/* Audio File Library Copyright (C) 2010-2013, Michael Pruett Copyright (C) 2001, Silicon Graphics, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* This module implements IMA ADPCM compression. */ #include "config.h" #include "IMA.h" #include #include #include "BlockCodec.h" #include "Compiler.h" #include "File.h" #include "Track.h" #include "afinternal.h" #include "byteorder.h" #include "util.h" #include "../pcm.h" struct adpcmState { int previousValue; // previous output value int index; // index into step table adpcmState() { previousValue = 0; index = 0; } }; class IMA : public BlockCodec { public: static IMA *createDecompress(Track *track, File *fh, bool canSeek, bool headerless, AFframecount *chunkFrames); static IMA *createCompress(Track *track, File *fh, bool canSeek, bool headerless, AFframecount *chunkFrames); virtual ~IMA(); virtual const char *name() const OVERRIDE { return mode() == Compress ? "ima_adpcm_compress" : "ima_adpcm_decompress"; } virtual void describe() OVERRIDE; private: int m_imaType; adpcmState *m_adpcmState; IMA(Mode, Track *, File *fh, bool canSeek); int decodeBlock(const uint8_t *encoded, int16_t *decoded) OVERRIDE; int decodeBlockWAVE(const uint8_t *encoded, int16_t *decoded); int decodeBlockQT(const uint8_t *encoded, int16_t *decoded); int encodeBlock(const int16_t *input, uint8_t *output) OVERRIDE; int encodeBlockWAVE(const int16_t *input, uint8_t *output); int encodeBlockQT(const int16_t *input, uint8_t *output); }; IMA::IMA(Mode mode, Track *track, File *fh, bool canSeek) : BlockCodec(mode, track, fh, canSeek), m_imaType(0) { AUpvlist pv = (AUpvlist) track->f.compressionParams; m_framesPerPacket = track->f.framesPerPacket; m_bytesPerPacket = track->f.bytesPerPacket; long l; if (_af_pv_getlong(pv, _AF_IMA_ADPCM_TYPE, &l)) m_imaType = l; m_adpcmState = new adpcmState[track->f.channelCount]; } IMA::~IMA() { delete [] m_adpcmState; } int IMA::decodeBlock(const uint8_t *encoded, int16_t *decoded) { if (m_imaType == _AF_IMA_ADPCM_TYPE_WAVE) return decodeBlockWAVE(encoded, decoded); else if (m_imaType == _AF_IMA_ADPCM_TYPE_QT) return decodeBlockQT(encoded, decoded); return 0; } static const int8_t indexTable[16] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8, }; static const int16_t stepTable[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; static inline int clamp(int x, int low, int high) { if (x < low) return low; if (x > high) return high; return x; } static inline int16_t decodeSample(adpcmState &state, uint8_t code) { int step = stepTable[state.index]; int diff = step >> 3; if (code & 4) diff += step; if (code & 2) diff += step>>1; if (code & 1) diff += step>>2; int predictor = state.previousValue; if (code & 8) predictor -= diff; else predictor += diff; state.previousValue = clamp(predictor, MIN_INT16, MAX_INT16); state.index = clamp(state.index + indexTable[code], 0, 88); return state.previousValue; } int IMA::decodeBlockWAVE(const uint8_t *encoded, int16_t *decoded) { int channelCount = m_track->f.channelCount; for (int c=0; c> 4); output += channelCount; encoded++; } } decoded += channelCount * 8; } return m_framesPerPacket * channelCount * sizeof (int16_t); } int IMA::decodeBlockQT(const uint8_t *encoded, int16_t *decoded) { int channelCount = m_track->f.channelCount; for (int c=0; c> 4); encoded++; } } return m_framesPerPacket * channelCount * sizeof (int16_t); } int IMA::encodeBlock(const int16_t *input, uint8_t *output) { if (m_imaType == _AF_IMA_ADPCM_TYPE_WAVE) return encodeBlockWAVE(input, output); else if (m_imaType == _AF_IMA_ADPCM_TYPE_QT) return encodeBlockQT(input, output); return 0; } static inline uint8_t encodeSample(adpcmState &state, int16_t sample) { int step = stepTable[state.index]; int diff = sample - state.previousValue; int vpdiff = step >> 3; uint8_t code = 0; if (diff < 0) { code = 8; diff = -diff; } if (diff >= step) { code |= 4; diff -= step; vpdiff += step; } step >>= 1; if (diff >= step) { code |= 2; diff -= step; vpdiff += step; } step >>= 1; if (diff >= step) { code |= 1; vpdiff += step; } if (code & 8) vpdiff = -vpdiff; state.previousValue = clamp(state.previousValue + vpdiff, MIN_INT16, MAX_INT16); state.index = clamp(state.index + indexTable[code], 0, 88); return code & 0xf; } int IMA::encodeBlockWAVE(const int16_t *input, uint8_t *output) { int channelCount = m_track->f.channelCount; for (int c=0; c> 8; output[2] = m_adpcmState[c].index; output[3] = 0; output += 4; } for (int n=0; nf.channelCount; for (int c=0; c> 8) & 0xff; output[1] = (state.previousValue & 0x80) | (state.index & 0x7f); output += 2; for (int n=0; nchannelCount != 1 && f->channelCount != 2) { _af_error(AF_BAD_COMPRESSION, "IMA ADPCM compression requires 1 or 2 channels"); return false; } if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP || f->sampleWidth != 16) { _af_error(AF_BAD_COMPRESSION, "IMA ADPCM compression requires 16-bit signed integer format"); return false; } if (f->byteOrder != _AF_BYTEORDER_NATIVE) { _af_error(AF_BAD_COMPRESSION, "IMA ADPCM compression requires native byte order"); return false; } return true; } void IMA::describe() { m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE; m_outChunk->f.compressionType = AF_COMPRESSION_NONE; m_outChunk->f.compressionParams = AU_NULL_PVLIST; } IMA *IMA::createDecompress(Track *track, File *fh, bool canSeek, bool headerless, AFframecount *chunkFrames) { assert(fh->tell() == track->fpos_first_frame); IMA *ima = new IMA(Decompress, track, fh, canSeek); if (!ima->m_imaType) { _af_error(AF_BAD_CODEC_CONFIG, "IMA type not set"); delete ima; return NULL; } *chunkFrames = ima->m_framesPerPacket; return ima; } IMA *IMA::createCompress(Track *track, File *fh, bool canSeek, bool headerless, AFframecount *chunkFrames) { assert(fh->tell() == track->fpos_first_frame); IMA *ima = new IMA(Compress, track, fh, canSeek); if (!ima->m_imaType) { _af_error(AF_BAD_CODEC_CONFIG, "IMA type not set"); delete ima; return NULL; } *chunkFrames = ima->m_framesPerPacket; return ima; } FileModule *_af_ima_adpcm_init_decompress(Track *track, File *fh, bool canSeek, bool headerless, AFframecount *chunkFrames) { return IMA::createDecompress(track, fh, canSeek, headerless, chunkFrames); } FileModule *_af_ima_adpcm_init_compress(Track *track, File *fh, bool canSeek, bool headerless, AFframecount *chunkFrames) { return IMA::createCompress(track, fh, canSeek, headerless, chunkFrames); }