Browse Source

Extend WavImporter to support more formats, be more flexible, and give better errors

pull/176/head
Alice 10 years ago committed by Vladimír Vondruš
parent
commit
1897e36b19
  1. 27
      src/Magnum/Audio/Buffer.cpp
  2. 118
      src/Magnum/Audio/Buffer.h
  3. 3
      src/Magnum/Audio/Context.cpp
  4. 3
      src/Magnum/Audio/Extensions.h
  5. 34
      src/MagnumExternal/OpenAL/extensions.h
  6. 18
      src/MagnumPlugins/WavAudioImporter/Test/CMakeLists.txt
  7. 123
      src/MagnumPlugins/WavAudioImporter/Test/WavImporterTest.cpp
  8. BIN
      src/MagnumPlugins/WavAudioImporter/Test/mono32f.wav
  9. BIN
      src/MagnumPlugins/WavAudioImporter/Test/mono8.wav
  10. BIN
      src/MagnumPlugins/WavAudioImporter/Test/mono8ALaw.wav
  11. BIN
      src/MagnumPlugins/WavAudioImporter/Test/mono8MuLaw.wav
  12. BIN
      src/MagnumPlugins/WavAudioImporter/Test/mono8junk.wav
  13. BIN
      src/MagnumPlugins/WavAudioImporter/Test/stereo16.wav
  14. BIN
      src/MagnumPlugins/WavAudioImporter/Test/stereo32f.wav
  15. BIN
      src/MagnumPlugins/WavAudioImporter/Test/stereo64f.wav
  16. BIN
      src/MagnumPlugins/WavAudioImporter/Test/stereo8ALaw.wav
  17. BIN
      src/MagnumPlugins/WavAudioImporter/Test/stereo8MuLaw.wav
  18. BIN
      src/MagnumPlugins/WavAudioImporter/Test/surround616.wav
  19. 26
      src/MagnumPlugins/WavAudioImporter/WavHeader.h
  20. 183
      src/MagnumPlugins/WavAudioImporter/WavImporter.cpp

27
src/Magnum/Audio/Buffer.cpp

@ -38,10 +38,37 @@ Debug& operator<<(Debug& debug, const Buffer::Format value) {
_c(Stereo8)
_c(Stereo16)
_c(MonoALaw)
_c(StereoALaw)
_c(MonoMuLaw)
_c(StereoMuLaw)
_c(MonoFloat)
_c(StereoFloat)
_c(MonoDouble)
_c(StereoDouble)
_c(Quad8)
_c(Quad16)
_c(Quad32)
_c(Rear8)
_c(Rear16)
_c(Rear32)
_c(Surround51Channel8)
_c(Surround51Channel16)
_c(Surround51Channel32)
_c(Surround61Channel8)
_c(Surround61Channel16)
_c(Surround61Channel32)
_c(Surround71Channel8)
_c(Surround71Channel16)
_c(Surround71Channel32)
#undef _c
/* LCOV_EXCL_STOP */
}

118
src/Magnum/Audio/Buffer.h

@ -57,6 +57,34 @@ class Buffer {
Stereo8 = AL_FORMAT_STEREO8, /**< 8-bit interleaved unsigned stereo */
Stereo16 = AL_FORMAT_STEREO16, /**< 16-bit interleaved signed stereo */
/**
* @brief 8-bit unsigned mono A-Law Compressed Sound Format
*
* @requires_al_extension Extension @al_extension{EXT,ALAW}
*/
MonoALaw = AL_FORMAT_MONO_ALAW_EXT,
/**
* @brief 16-bit signed stereo A-Law Compressed Sound Format
*
* @requires_al_extension Extension @al_extension{EXT,ALAW}
*/
StereoALaw = AL_FORMAT_STEREO_ALAW_EXT,
/**
* @brief 8-bit unsigned mono Mu-Law Compressed Sound Format
*
* @requires_al_extension Extension @al_extension{EXT,MULAW}
*/
MonoMuLaw = AL_FORMAT_MONO_MULAW_EXT,
/**
* @brief 16-bit signed Mu-Law Compressed Sound Format
*
* @requires_al_extension Extension @al_extension{EXT,MULAW}
*/
StereoMuLaw = AL_FORMAT_STEREO_MULAW_EXT,
/**
* @brief 32-bit floating-point mono
*
@ -83,7 +111,95 @@ class Buffer {
*
* @requires_al_extension Extension @al_extension{EXT,double}
*/
StereoDouble = AL_FORMAT_STEREO_DOUBLE_EXT
StereoDouble = AL_FORMAT_STEREO_DOUBLE_EXT,
/**
* @brief 8-bit unsigned quadrophonic
*
* @requires_al_extension Extension @al_extension{EXT,MCFORMATS}
*/
Quad8 = AL_FORMAT_QUAD8,
/**
* @brief 16-bit signed quadrophonic
*
* @requires_al_extension Extension @al_extension{EXT,MCFORMATS}
*/
Quad16 = AL_FORMAT_QUAD16,
/**
* @brief 32-bit interleaved floating-point quadrophonic
*
* @requires_al_extension Extension @al_extension{EXT,MCFORMATS}
*/
Quad32 = AL_FORMAT_QUAD32,
Rear8 = AL_FORMAT_REAR8,
Rear16 = AL_FORMAT_REAR16,
Rear32 = AL_FORMAT_REAR32,
/**
* @brief 8-bit unsigned 5.1 surround
*
* @requires_al_extension Extension @al_extension{EXT,MCFORMATS}
*/
Surround51Channel8 = AL_FORMAT_51CHN8,
/**
* @brief 16-bit signed 5.1 surround
*
* @requires_al_extension Extension @al_extension{EXT,MCFORMATS}
*/
Surround51Channel16 = AL_FORMAT_51CHN16,
/**
* @brief 32-bit interleaved floating-point 5.1 surround
*
* @requires_al_extension Extension @al_extension{EXT,MCFORMATS}
*/
Surround51Channel32 = AL_FORMAT_51CHN32,
/**
* @brief 8-bit unsigned 6.1 surround
*
* @requires_al_extension Extension @al_extension{EXT,MCFORMATS}
*/
Surround61Channel8 = AL_FORMAT_61CHN8,
/**
* @brief 16-bit signed 6.1 surround
*
* @requires_al_extension Extension @al_extension{EXT,MCFORMATS}
*/
Surround61Channel16 = AL_FORMAT_61CHN16,
/**
* @brief 32-bit interleaved floating-point 6.1 surround
*
* @requires_al_extension Extension @al_extension{EXT,MCFORMATS}
*/
Surround61Channel32 = AL_FORMAT_61CHN32,
/**
* @brief 8-bit unsigned 7.1 surround
*
* @requires_al_extension Extension @al_extension{EXT,MCFORMATS}
*/
Surround71Channel8 = AL_FORMAT_71CHN8,
/**
* @brief 16-bit signed 7.1 surround
*
* @requires_al_extension Extension @al_extension{EXT,MCFORMATS}
*/
Surround71Channel16 = AL_FORMAT_71CHN16,
/**
* @brief 32-bit interleaved floating-point 7.1 surround
*
* @requires_al_extension Extension @al_extension{EXT,MCFORMATS}
*/
Surround71Channel32 = AL_FORMAT_71CHN32
};
/**

3
src/Magnum/Audio/Context.cpp

@ -44,6 +44,9 @@ const std::vector<Extension>& Extension::extensions() {
static const std::vector<Extension> extensions{
_extension(AL,EXT,FLOAT32),
_extension(AL,EXT,DOUBLE),
_extension(AL,EXT,ALAW),
_extension(AL,EXT,MULAW),
_extension(AL,EXT,MCFORMATS),
_extension(ALC,EXT,ENUMERATION),
_extension(ALC,SOFTX,HRTF),
_extension(ALC,SOFT,HRTF)

3
src/Magnum/Audio/Extensions.h

@ -79,6 +79,9 @@ namespace AL {
namespace EXT {
_extension(AL,EXT,FLOAT32) // #???
_extension(AL,EXT,DOUBLE) // #???
_extension(AL,EXT,ALAW) // #???
_extension(AL,EXT,MULAW) // #???
_extension(AL,EXT,MCFORMATS) // #???
}
} namespace ALC {
namespace EXT {

34
src/MagnumExternal/OpenAL/extensions.h vendored

@ -52,6 +52,40 @@ extern "C" {
#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013
#endif
/* AL_EXT_MULAW */
#ifndef AL_EXT_MULAW
#define AL_EXT_MULAW 1
#define AL_FORMAT_MONO_MULAW_EXT 0x10014
#define AL_FORMAT_STEREO_MULAW_EXT 0x10015
#endif
/* AL_EXT_ALAW */
#ifndef AL_EXT_ALAW
#define AL_EXT_ALAW 1
#define AL_FORMAT_MONO_ALAW_EXT 0x10016
#define AL_FORMAT_STEREO_ALAW_EXT 0x10017
#endif
/* AL_EXT_MCFORMATS */
#ifndef AL_EXT_MCFORMATS
#define AL_EXT_MCFORMATS 1
#define AL_FORMAT_QUAD8 0x1204
#define AL_FORMAT_QUAD16 0x1205
#define AL_FORMAT_QUAD32 0x1206
#define AL_FORMAT_REAR8 0x1207
#define AL_FORMAT_REAR16 0x1208
#define AL_FORMAT_REAR32 0x1209
#define AL_FORMAT_51CHN8 0x120A
#define AL_FORMAT_51CHN16 0x120B
#define AL_FORMAT_51CHN32 0x120C
#define AL_FORMAT_61CHN8 0x120D
#define AL_FORMAT_61CHN16 0x120E
#define AL_FORMAT_61CHN32 0x120F
#define AL_FORMAT_71CHN8 0x1210
#define AL_FORMAT_71CHN16 0x1211
#define AL_FORMAT_71CHN32 0x1212
#endif
/* ALC_SOFTX_HRTF */
#ifndef ALC_SOFTX_HRTF
#define ALC_SOFTX_HRTF 1

18
src/MagnumPlugins/WavAudioImporter/Test/CMakeLists.txt

@ -36,8 +36,26 @@ corrade_add_test(WavAudioImporterTest WavImporterTest.cpp LIBRARIES MagnumWavAud
target_include_directories(WavAudioImporterTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
if(CORRADE_TARGET_EMSCRIPTEN)
emscripten_embed_file(WavAudioImporterTest mono8.wav "/mono8.wav")
emscripten_embed_file(WavAudioImporterTest mono8.wav "/mono8junk.wav")
emscripten_embed_file(WavAudioImporterTest mono8ALaw.wav "/mono8ALaw.wav")
emscripten_embed_file(WavAudioImporterTest mono8MuLaw.wav "/mono8MuLaw.wav")
emscripten_embed_file(WavAudioImporterTest mono16.wav "/mono16.wav")
emscripten_embed_file(WavAudioImporterTest stereo8.wav "/stereo8.wav")
emscripten_embed_file(WavAudioImporterTest stereo8ALaw.wav "/stereo8ALaw.wav")
emscripten_embed_file(WavAudioImporterTest stereo8MuLaw.wav "/stereo8MuLaw.wav")
emscripten_embed_file(WavAudioImporterTest stereo16.wav "/stereo16.wav")
emscripten_embed_file(WavAudioImporterTest mono32f.wav "/mono32f.wav")
emscripten_embed_file(WavAudioImporterTest stereo32f.wav "/stereo32f.wav")
emscripten_embed_file(WavAudioImporterTest stereo64f.wav "/stereo64f.wav")
emscripten_embed_file(WavAudioImporterTest surround616.wav "/surround616.wav")
emscripten_embed_file(WavAudioImporterTest unsupportedChannelCount.wav "/unsupportedChannelCount.wav")
emscripten_embed_file(WavAudioImporterTest unsupportedFormat.wav "/unsupportedFormat.wav")
emscripten_embed_file(WavAudioImporterTest wrongSignature.wav "/wrongSignature.wav")

123
src/MagnumPlugins/WavAudioImporter/Test/WavImporterTest.cpp

@ -43,17 +43,45 @@ class WavImporterTest: public TestSuite::Tester {
void wrongSignature();
void unsupportedFormat();
void unsupportedChannelCount();
void mono8();
void mono8junk();
void mono8ALaw();
void mono8MuLaw();
void mono16();
void stereo8();
void stereo8ALaw();
void stereo8MuLaw();
void stereo16();
void mono32f();
void stereo32f();
void stereo64f();
void surround616();
};
WavImporterTest::WavImporterTest() {
addTests({&WavImporterTest::wrongSize,
addTests({
&WavImporterTest::wrongSize,
&WavImporterTest::wrongSignature,
&WavImporterTest::unsupportedFormat,
&WavImporterTest::unsupportedChannelCount,
&WavImporterTest::mono8,
&WavImporterTest::mono8junk,
&WavImporterTest::mono8ALaw,
&WavImporterTest::mono8MuLaw,
&WavImporterTest::mono16,
&WavImporterTest::stereo8});
&WavImporterTest::stereo8,
&WavImporterTest::stereo8ALaw,
&WavImporterTest::stereo8MuLaw,
&WavImporterTest::stereo16,
&WavImporterTest::mono32f,
&WavImporterTest::stereo32f,
&WavImporterTest::stereo64f,
&WavImporterTest::surround616});
}
void WavImporterTest::wrongSize() {
@ -92,6 +120,38 @@ void WavImporterTest::unsupportedChannelCount() {
CORRADE_COMPARE(out.str(), "Audio::WavImporter::openData(): unsupported channel count 6 with 8 bits per sample\n");
}
void WavImporterTest::mono8() {
WavImporter importer;
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "mono8.wav")));
CORRADE_COMPARE(importer.format(), Buffer::Format::Mono8);
CORRADE_COMPARE(importer.frequency(), 22050);
}
void WavImporterTest::mono8junk() {
WavImporter importer;
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "mono8junk.wav")));
CORRADE_COMPARE(importer.format(), Buffer::Format::Mono8);
CORRADE_COMPARE(importer.frequency(), 22050);
}
void WavImporterTest::mono8ALaw() {
WavImporter importer;
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "mono8ALaw.wav")));
CORRADE_COMPARE(importer.format(), Buffer::Format::MonoALaw);
CORRADE_COMPARE(importer.frequency(), 8000);
}
void WavImporterTest::mono8MuLaw() {
WavImporter importer;
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "mono8MuLaw.wav")));
CORRADE_COMPARE(importer.format(), Buffer::Format::MonoMuLaw);
CORRADE_COMPARE(importer.frequency(), 8000);
}
void WavImporterTest::mono16() {
WavImporter importer;
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "mono16.wav")));
@ -114,6 +174,65 @@ void WavImporterTest::stereo8() {
TestSuite::Compare::Container);
}
void WavImporterTest::stereo8ALaw() {
WavImporter importer;
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "stereo8ALaw.wav")));
CORRADE_COMPARE(importer.format(), Buffer::Format::StereoALaw);
CORRADE_COMPARE(importer.frequency(), 8000);
}
void WavImporterTest::stereo8MuLaw() {
WavImporter importer;
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "stereo8MuLaw.wav")));
CORRADE_COMPARE(importer.format(), Buffer::Format::StereoMuLaw);
CORRADE_COMPARE(importer.frequency(), 8000);
}
void WavImporterTest::stereo16() {
WavImporter importer;
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "stereo16.wav")));
CORRADE_COMPARE(importer.format(), Buffer::Format::Stereo16);
CORRADE_COMPARE(importer.frequency(), 44100);
}
void WavImporterTest::mono32f() {
WavImporter importer;
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "mono32f.wav")));
CORRADE_COMPARE(importer.format(), Buffer::Format::MonoFloat);
CORRADE_COMPARE(importer.frequency(), 48000);
}
void WavImporterTest::stereo32f() {
WavImporter importer;
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "stereo32f.wav")));
CORRADE_COMPARE(importer.format(), Buffer::Format::StereoFloat);
CORRADE_COMPARE(importer.frequency(), 44100);
}
void WavImporterTest::stereo64f() {
WavImporter importer;
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "stereo64f.wav")));
CORRADE_COMPARE(importer.format(), Buffer::Format::StereoDouble);
CORRADE_COMPARE(importer.frequency(), 8000);
}
void WavImporterTest::surround616() {
std::ostringstream out;
Error redirectError{&out};
WavImporter importer;
CORRADE_VERIFY(!importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "surround616.wav")));
CORRADE_COMPARE(out.str(), "Audio::WavImporter::openData(): unsupported audio format: extensible not implememented 65534\n");
}
}}}
CORRADE_TEST_MAIN(Magnum::Audio::Test::WavImporterTest)

BIN
src/MagnumPlugins/WavAudioImporter/Test/mono32f.wav

Binary file not shown.

BIN
src/MagnumPlugins/WavAudioImporter/Test/mono8.wav

Binary file not shown.

BIN
src/MagnumPlugins/WavAudioImporter/Test/mono8ALaw.wav

Binary file not shown.

BIN
src/MagnumPlugins/WavAudioImporter/Test/mono8MuLaw.wav

Binary file not shown.

BIN
src/MagnumPlugins/WavAudioImporter/Test/mono8junk.wav

Binary file not shown.

BIN
src/MagnumPlugins/WavAudioImporter/Test/stereo16.wav

Binary file not shown.

BIN
src/MagnumPlugins/WavAudioImporter/Test/stereo32f.wav

Binary file not shown.

BIN
src/MagnumPlugins/WavAudioImporter/Test/stereo64f.wav

Binary file not shown.

BIN
src/MagnumPlugins/WavAudioImporter/Test/stereo8ALaw.wav

Binary file not shown.

BIN
src/MagnumPlugins/WavAudioImporter/Test/stereo8MuLaw.wav

Binary file not shown.

BIN
src/MagnumPlugins/WavAudioImporter/Test/surround616.wav

Binary file not shown.

26
src/MagnumPlugins/WavAudioImporter/WavHeader.h

@ -33,28 +33,36 @@
namespace Magnum { namespace Audio {
#pragma pack(1)
/** @brief RIFF chunk */
struct RiffChunk {
char chunkId[4]; /**< @brief chunk name (4 characters) */
UnsignedInt chunkSize; /**< @brief size of chunk (does not include chunk header) */
};
#pragma pack()
#pragma pack(1)
/** @brief WAV file header */
struct WavHeader {
char chunkId[4]; /**< @brief `RIFF` characters */
UnsignedInt chunkSize; /**< @brief Size of the rest of the file */
struct WavHeaderChunk {
RiffChunk chunk; /**< @brief Starting RIFF chunk */
char format[4]; /**< @brief `WAVE` characters */
};
#pragma pack()
char subChunk1Id[4]; /**< @brief `fmt ` characters */
UnsignedInt subChunk1Size; /**< @brief 16 for PCM */
#pragma pack(1)
/** @brief WAV 'fmt' header */
struct WavFormatChunk {
RiffChunk chunk; /**< @brief Starting RIFF chunk */
UnsignedShort audioFormat; /**< @brief 1 = PCM */
UnsignedShort numChannels; /**< @brief 1 = Mono, 2 = Stereo */
UnsignedInt sampleRate; /**< @brief Sample rate in Hz */
UnsignedInt byteRate; /**< @brief Bytes per second */
UnsignedShort blockAlign; /**< @brief Bytes per sample (all channels) */
UnsignedShort bitsPerSample; /**< @brief Bits per sample (one channel) */
char subChunk2Id[4]; /**< @brief `data` characters */
UnsignedInt subChunk2Size; /**< @brief Size of the following data */
};
#pragma pack()
static_assert(sizeof(WavHeader) == 44, "WavHeader size is not 44 bytes");
static_assert(sizeof(WavHeaderChunk) + sizeof(WavFormatChunk) + sizeof(RiffChunk) == 44, "WavHeader size is not 44 bytes");
}}

183
src/MagnumPlugins/WavAudioImporter/WavImporter.cpp

@ -31,6 +31,12 @@
#include "MagnumPlugins/WavAudioImporter/WavHeader.h"
#define WAVE_FORMAT_PCM 0x0001
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
#define WAVE_FORMAT_ALAW 0x0006
#define WAVE_FORMAT_MULAW 0x0007
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
namespace Magnum { namespace Audio {
WavImporter::WavImporter() = default;
@ -43,74 +49,173 @@ bool WavImporter::doIsOpened() const { return _data; }
void WavImporter::doOpenData(Containers::ArrayView<const char> data) {
/* Check file size */
if(data.size() < sizeof(WavHeader)) {
if(data.size() < sizeof(WavHeaderChunk) + sizeof(WavFormatChunk) + sizeof(RiffChunk)) {
Error() << "Audio::WavImporter::openData(): the file is too short:" << data.size() << "bytes";
return;
}
/* Get header contents and fix endianness */
WavHeader header(*reinterpret_cast<const WavHeader*>(data.begin()));
Utility::Endianness::littleEndianInPlace(header.chunkSize,
header.subChunk1Size, header.audioFormat, header.numChannels,
header.sampleRate, header.byteRate, header.blockAlign,
header.bitsPerSample, header.subChunk2Size);
/* Check file signature */
if(std::strncmp(header.chunkId, "RIFF", 4) != 0 ||
std::strncmp(header.format, "WAVE", 4) != 0 ||
std::strncmp(header.subChunk1Id, "fmt ", 4) != 0 ||
std::strncmp(header.subChunk2Id, "data", 4) != 0) {
/* Get the RIFF/WAV header */
WavHeaderChunk header(*reinterpret_cast<const WavHeaderChunk*>(data.begin()));
/* Check RIFF/WAV file signature */
if(std::strncmp(header.chunk.chunkId, "RIFF", 4) != 0 ||
std::strncmp(header.format, "WAVE", 4) != 0) {
Error() << "Audio::WavImporter::openData(): the file signature is invalid";
return;
}
Utility::Endianness::littleEndianInPlace(header.chunk.chunkSize);
/* Check file size */
if(header.chunkSize + 8 != data.size()) {
if(header.chunk.chunkSize < 36 || header.chunk.chunkSize + 8 != data.size()) {
Error() << "Audio::WavImporter::openData(): the file has improper size, expected"
<< header.chunkSize + 8 << "but got" << data.size();
<< header.chunk.chunkSize + 8 << "but got" << data.size();
return;
}
const RiffChunk* dataChunk = nullptr;
const WavFormatChunk* formatChunk = nullptr;
UnsignedInt dataChunkSize = 0;
const UnsignedInt headerSize = sizeof(WavHeaderChunk);
UnsignedInt offset = 0;
/* Skip any chunks that aren't the format or data chunk */
while(headerSize + offset <= header.chunk.chunkSize) {
const RiffChunk* currChunk = reinterpret_cast<const RiffChunk*>(data.begin() + headerSize + offset);
offset += Utility::Endianness::littleEndian(currChunk->chunkSize) + sizeof(RiffChunk);
if(std::strncmp(currChunk->chunkId, "fmt ", 4) == 0) {
if(formatChunk != nullptr) {
Error() << "Audio::WavImporter::openData(): the file contains too many format chunks";
return;
}
formatChunk = reinterpret_cast<const WavFormatChunk*>(currChunk);
} else if(std::strncmp(currChunk->chunkId, "data", 4) == 0) {
if(dataChunk != nullptr) {
Error() << "Audio::WavImporter::openData(): the file contains too many data chunks";
return;
}
dataChunk = currChunk;
dataChunkSize = Utility::Endianness::littleEndian(currChunk->chunkSize);
break;
}
}
/* Make sure we actually got a format chunk */
if(formatChunk == nullptr) {
Error() << "Audio::WavImporter::openData(): the file contains no format chunk";
return;
}
/* Make sure we actually got a data chunk */
if(dataChunk == nullptr) {
Error() << "Audio::WavImporter::openData(): the file contains no data chunk";
return;
}
/* Fix endianness on Format chunk */
Utility::Endianness::littleEndianInPlace(
formatChunk->chunk.chunkSize, formatChunk->audioFormat, formatChunk->numChannels,
formatChunk->sampleRate, formatChunk->byteRate, formatChunk->blockAlign,
formatChunk->bitsPerSample);
/* Check PCM format */
if(header.audioFormat != 1) {
Error() << "Audio::WavImporter::openData(): unsupported audio format" << header.audioFormat;
if(formatChunk->audioFormat == WAVE_FORMAT_PCM) {
/* Decide about format */
if(formatChunk->numChannels == 1 && formatChunk->bitsPerSample == 8)
_format = Buffer::Format::Mono8;
else if(formatChunk->numChannels == 1 && formatChunk->bitsPerSample == 16)
_format = Buffer::Format::Mono16;
else if(formatChunk->numChannels == 2 && formatChunk->bitsPerSample == 8)
_format = Buffer::Format::Stereo8;
else if(formatChunk->numChannels == 2 && formatChunk->bitsPerSample == 16)
_format = Buffer::Format::Stereo16;
else {
Error() << "Audio::WavImporter::openData(): unsupported channel count"
<< formatChunk->numChannels << "with" << formatChunk->bitsPerSample
<< "bits per sample";
return;
}
/* Check IEEE Float format */
} else if(formatChunk->audioFormat == WAVE_FORMAT_IEEE_FLOAT) {
if(formatChunk->numChannels == 1 && formatChunk->bitsPerSample == 32)
_format = Buffer::Format::MonoFloat;
else if(formatChunk->numChannels == 2 && formatChunk->bitsPerSample == 32)
_format = Buffer::Format::StereoFloat;
else if(formatChunk->numChannels == 1 && formatChunk->bitsPerSample == 64)
_format = Buffer::Format::MonoDouble;
else if(formatChunk->numChannels == 2 && formatChunk->bitsPerSample == 64)
_format = Buffer::Format::StereoDouble;
else {
Error() << "Audio::WavImporter::openData(): unsupported channel count"
<< formatChunk->numChannels << "with" << formatChunk->bitsPerSample
<< "bits per sample";
return;
}
/* Check ALAW format */
} else if(formatChunk->audioFormat == WAVE_FORMAT_ALAW) {
if(formatChunk->numChannels == 1)
_format = Buffer::Format::MonoALaw;
else if(formatChunk->numChannels == 2)
_format = Buffer::Format::StereoALaw;
else {
Error() << "Audio::WavImporter::openData(): unsupported channel count"
<< formatChunk->numChannels << "with" << formatChunk->bitsPerSample
<< "bits per sample";
return;
}
/* Check MULAW format */
} else if(formatChunk->audioFormat == WAVE_FORMAT_MULAW) {
if(formatChunk->numChannels == 1)
_format = Buffer::Format::MonoMuLaw;
else if(formatChunk->numChannels == 2)
_format = Buffer::Format::StereoMuLaw;
else {
Error() << "Audio::WavImporter::openData(): unsupported channel count"
<< formatChunk->numChannels << "with" << formatChunk->bitsPerSample
<< "bits per sample";
return;
}
/* We do not currently support EXTENSIBLE formats */
} else if(formatChunk->audioFormat == WAVE_FORMAT_EXTENSIBLE) {
Error() << "Audio::WavImporter::openData(): unsupported audio format: extensible not implememented" << formatChunk->audioFormat;
return;
/* Unknown format */
} else {
Error() << "Audio::WavImporter::openData(): unsupported audio format" << formatChunk->audioFormat;
return;
}
/* Verify more things */
if(header.subChunk1Size != 16 ||
header.subChunk2Size + 44 != data.size() ||
header.blockAlign != header.numChannels*header.bitsPerSample/8 ||
header.byteRate != header.sampleRate*header.blockAlign) {
Error() << "Audio::WavImporter::openData(): the file is corrupted";
/* Size sanity checks */
if(headerSize + offset > data.size()) {
Error() << "Audio::WavImporter::openData(): file size doesn't match computed size";
return;
}
/* Decide about format */
if(header.numChannels == 1 && header.bitsPerSample == 8)
_format = Buffer::Format::Mono8;
else if(header.numChannels == 1 && header.bitsPerSample == 16)
_format = Buffer::Format::Mono16;
else if(header.numChannels == 2 && header.bitsPerSample == 8)
_format = Buffer::Format::Stereo8;
else if(header.numChannels == 2 && header.bitsPerSample == 16)
_format = Buffer::Format::Stereo16;
else {
Error() << "Audio::WavImporter::openData(): unsupported channel count"
<< header.numChannels << "with" << header.bitsPerSample
<< "bits per sample";
/* Format sanity checks */
if(formatChunk->blockAlign != formatChunk->numChannels * formatChunk->bitsPerSample / 8 ||
formatChunk->byteRate != formatChunk->sampleRate * formatChunk->blockAlign) {
Error() << "Audio::WavImporter::openData(): the file is corrupted";
return;
}
/* Save frequency */
_frequency = header.sampleRate;
_frequency = formatChunk->sampleRate;
/** @todo Convert the data from little endian too */
CORRADE_INTERNAL_ASSERT(!Utility::Endianness::isBigEndian());
/* Copy the data */
_data = Containers::Array<char>(header.subChunk2Size);
std::copy(data.begin()+sizeof(WavHeader), data.end(), _data.begin());
const char* dataChunkPtr = reinterpret_cast<const char*>(dataChunk + 1);
_data = Containers::Array<char>(dataChunkSize);
std::copy(dataChunkPtr, dataChunkPtr+dataChunkSize, _data.begin());
return;
}

Loading…
Cancel
Save