modify wave decoder to handle ima adpcm files

adpcm
Dimitri Diakopoulos 10 years ago
parent 4b82d31b50
commit f3e03876a0

@ -33,12 +33,14 @@ namespace nqr
enum WaveFormatCode enum WaveFormatCode
{ {
FORMAT_UNKNOWN = 0x0, // Unknown Wave Format FORMAT_UNKNOWN = 0x0, // Unknown Wave Format
FORMAT_PCM = 0x1, // PCM Format FORMAT_PCM = 0x1, // PCM Format
FORMAT_IEEE = 0x3, // IEEE float/double FORMAT_ADPCM = 0x2, // Microsoft ADPCM Format
FORMAT_ALAW = 0x6, // 8-bit ITU-T G.711 A-law FORMAT_IEEE = 0x3, // IEEE float/double
FORMAT_MULAW = 0x7, // 8-bit ITU-T G.711 µ-law FORMAT_ALAW = 0x6, // 8-bit ITU-T G.711 A-law
FORMAT_EXT = 0xFFFE // Set via subformat FORMAT_MULAW = 0x7, // 8-bit ITU-T G.711 µ-law
FORMAT_IMA_ADPCM = 0x11, // IMA ADPCM Format
FORMAT_EXT = 0xFFFE // Set via subformat
}; };
struct RiffChunkHeader struct RiffChunkHeader

@ -25,6 +25,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "WavDecoder.h" #include "WavDecoder.h"
#include "RiffUtils.h" #include "RiffUtils.h"
#include "IMA4Util.h"
using namespace nqr; using namespace nqr;
@ -84,7 +85,7 @@ int WavDecoder::LoadFromBuffer(AudioData * data, const std::vector<uint8_t> & me
if (WaveChunkInfo.offset == 0) throw std::runtime_error("couldn't find fmt chunk"); if (WaveChunkInfo.offset == 0) throw std::runtime_error("couldn't find fmt chunk");
assert(WaveChunkInfo.size == 16 || WaveChunkInfo.size == 18 || WaveChunkInfo.size == 40); assert(WaveChunkInfo.size == 16 || WaveChunkInfo.size == 18 || WaveChunkInfo.size == 20 || WaveChunkInfo.size == 40);
WaveChunkHeader wavHeader = {}; WaveChunkHeader wavHeader = {};
memcpy(&wavHeader, memory.data() + WaveChunkInfo.offset, sizeof(WaveChunkHeader)); memcpy(&wavHeader, memory.data() + WaveChunkInfo.offset, sizeof(WaveChunkHeader));
@ -98,18 +99,33 @@ int WavDecoder::LoadFromBuffer(AudioData * data, const std::vector<uint8_t> & me
data->sampleRate = wavHeader.sample_rate; data->sampleRate = wavHeader.sample_rate;
data->frameSize = wavHeader.frame_size; data->frameSize = wavHeader.frame_size;
//std::cout << wavHeader << std::endl; auto bit_depth = wavHeader.bit_depth;
switch (bit_depth)
{
case 4: data->sourceFormat = PCMFormat::PCM_16; break; // for IMA ADPCM
case 8: data->sourceFormat = PCMFormat::PCM_U8; break;
case 16: data->sourceFormat = PCMFormat::PCM_16; break;
case 24: data->sourceFormat = PCMFormat::PCM_24; break;
case 32: data->sourceFormat = (wavHeader.format == WaveFormatCode::FORMAT_IEEE) ? PCMFormat::PCM_FLT : PCMFormat::PCM_32; break;
case 64: data->sourceFormat = (wavHeader.format == WaveFormatCode::FORMAT_IEEE) ? PCMFormat::PCM_DBL : PCMFormat::PCM_64; break;
}
std::cout << wavHeader << std::endl;
bool scanForFact = false; bool scanForFact = false;
bool grabExtensibleData = false; bool grabExtensibleData = false;
bool adpcmEncoded = false;
if (wavHeader.format == WaveFormatCode::FORMAT_PCM) if (wavHeader.format == WaveFormatCode::FORMAT_PCM)
{ {
//std::cout << "[format id] pcm" << std::endl;
} }
else if (wavHeader.format == WaveFormatCode::FORMAT_IEEE) else if (wavHeader.format == WaveFormatCode::FORMAT_IEEE)
{ {
//std::cout << "[format id] ieee" << std::endl; scanForFact = true;
}
else if (wavHeader.format == WaveFormatCode::FORMAT_IMA_ADPCM)
{
adpcmEncoded = true;
scanForFact = true; scanForFact = true;
} }
else if (wavHeader.format == WaveFormatCode::FORMAT_EXT) else if (wavHeader.format == WaveFormatCode::FORMAT_EXT)
@ -128,15 +144,12 @@ int WavDecoder::LoadFromBuffer(AudioData * data, const std::vector<uint8_t> & me
// Read Additional Chunks // // Read Additional Chunks //
//////////////////////////// ////////////////////////////
FactChunk factChunk;
if (scanForFact) if (scanForFact)
{ {
auto FactChunkInfo = ScanForChunk(memory, GenerateChunkCode('f', 'a', 'c', 't')); auto FactChunkInfo = ScanForChunk(memory, GenerateChunkCode('f', 'a', 'c', 't'));
FactChunk factChunk = {};
if (FactChunkInfo.size) if (FactChunkInfo.size)
{
memcpy(&factChunk, memory.data() + FactChunkInfo.offset, sizeof(FactChunk)); memcpy(&factChunk, memory.data() + FactChunkInfo.offset, sizeof(FactChunk));
}
} }
if (grabExtensibleData) if (grabExtensibleData)
@ -171,24 +184,42 @@ int WavDecoder::LoadFromBuffer(AudioData * data, const std::vector<uint8_t> & me
throw std::runtime_error("couldn't find data chunk"); throw std::runtime_error("couldn't find data chunk");
DataChunkInfo.offset += 2 * sizeof(uint32_t); // ignore the header and size fields DataChunkInfo.offset += 2 * sizeof(uint32_t); // ignore the header and size fields
data->lengthSeconds = ((float) DataChunkInfo.size / (float) wavHeader.sample_rate) / wavHeader.frame_size;
auto bit_depth = wavHeader.bit_depth;
size_t totalSamples = (DataChunkInfo.size / wavHeader.frame_size) * wavHeader.channel_count;
data->samples.resize(totalSamples);
switch (bit_depth) if (adpcmEncoded)
{ {
case 8: data->sourceFormat = PCMFormat::PCM_U8; break; ADPCMState s;
case 16: data->sourceFormat = PCMFormat::PCM_16; break; s.nBlockAlign = wavHeader.frame_size;
case 24: data->sourceFormat = PCMFormat::PCM_24; break; s.firstDataBlockByte = 0;
case 32: data->sourceFormat = (wavHeader.format == WaveFormatCode::FORMAT_IEEE) ? PCMFormat::PCM_FLT : PCMFormat::PCM_32; break; s.dataSize = DataChunkInfo.size;
case 64: data->sourceFormat = (wavHeader.format == WaveFormatCode::FORMAT_IEEE) ? PCMFormat::PCM_DBL : PCMFormat::PCM_64; break; s.currentByte = 0;
s.currentDatablock = const_cast<uint8_t*>(memory.data() + DataChunkInfo.offset);
// An encoded sample is 4 bits that expands to 16
size_t totalSamples = factChunk.sample_length * 4;
std::vector<int16_t> adpcm_pcm16(totalSamples, 0);
uint32_t frameOffset = 0;
unsigned numFrames = DataChunkInfo.size / s.nBlockAlign;
for (int i = 0; i < numFrames; ++i)
{
decode_ima_adpcm(s, adpcm_pcm16.data() + frameOffset, wavHeader.channel_count);
s.currentDatablock += s.nBlockAlign;
frameOffset += (wavHeader.channel_count * s.nBlockAlign);
}
data->lengthSeconds = ((float) totalSamples / (float) wavHeader.sample_rate) / wavHeader.channel_count;
data->samples.resize(totalSamples);
ConvertToFloat32(data->samples.data(), adpcm_pcm16.data(), totalSamples, data->sourceFormat);
}
else
{
data->lengthSeconds = ((float) DataChunkInfo.size / (float) wavHeader.sample_rate) / wavHeader.frame_size;
size_t totalSamples = (DataChunkInfo.size / wavHeader.frame_size) * wavHeader.channel_count;
data->samples.resize(totalSamples);
ConvertToFloat32(data->samples.data(), memory.data() + DataChunkInfo.offset, totalSamples, data->sourceFormat);
} }
ConvertToFloat32(data->samples.data(), memory.data() + DataChunkInfo.offset, totalSamples, data->sourceFormat);
return IOError::NoError; return IOError::NoError;
} }

Loading…
Cancel
Save