diff options
Diffstat (limited to 'audio')
27 files changed, 565 insertions, 1091 deletions
diff --git a/audio/audiostream.cpp b/audio/audiostream.cpp index 1c5c435359..2d65d4afef 100644 --- a/audio/audiostream.cpp +++ b/audio/audiostream.cpp @@ -386,4 +386,42 @@ Timestamp convertTimeToStreamPos(const Timestamp &where, int rate, bool isStereo return Timestamp(result.secs(), result.numberOfFrames(), result.framerate()); } +/** + * An AudioStream wrapper that cuts off the amount of samples read after a + * given time length is reached. + */ +class LimitingAudioStream : public AudioStream { +public: + LimitingAudioStream(AudioStream *parentStream, const Audio::Timestamp &length, DisposeAfterUse::Flag disposeAfterUse) : + _parentStream(parentStream), _samplesRead(0), _disposeAfterUse(disposeAfterUse), + _totalSamples(length.convertToFramerate(getRate()).totalNumberOfFrames() * getChannels()) {} + + ~LimitingAudioStream() { + if (_disposeAfterUse == DisposeAfterUse::YES) + delete _parentStream; + } + + int readBuffer(int16 *buffer, const int numSamples) { + // Cap us off so we don't read past _totalSamples + int samplesRead = _parentStream->readBuffer(buffer, MIN<int>(numSamples, _totalSamples - _samplesRead)); + _samplesRead += samplesRead; + return samplesRead; + } + + bool endOfData() const { return _parentStream->endOfData() || _samplesRead >= _totalSamples; } + bool isStereo() const { return _parentStream->isStereo(); } + int getRate() const { return _parentStream->getRate(); } + +private: + int getChannels() const { return isStereo() ? 2 : 1; } + + AudioStream *_parentStream; + DisposeAfterUse::Flag _disposeAfterUse; + uint32 _totalSamples, _samplesRead; +}; + +AudioStream *makeLimitingAudioStream(AudioStream *parentStream, const Timestamp &length, DisposeAfterUse::Flag disposeAfterUse) { + return new LimitingAudioStream(parentStream, length, disposeAfterUse); +} + } // End of namespace Audio diff --git a/audio/audiostream.h b/audio/audiostream.h index 801f13d9d9..d6d4a16280 100644 --- a/audio/audiostream.h +++ b/audio/audiostream.h @@ -356,6 +356,16 @@ QueuingAudioStream *makeQueuingAudioStream(int rate, bool stereo); */ Timestamp convertTimeToStreamPos(const Timestamp &where, int rate, bool isStereo); +/** + * Factory function for an AudioStream wrapper that cuts off the amount of samples read after a + * given time length is reached. + * + * @param parentStream The stream to limit + * @param length The time length to limit the stream to + * @param disposeAfterUse Whether the parent stream object should be destroyed on destruction of the returned stream + */ +AudioStream *makeLimitingAudioStream(AudioStream *parentStream, const Timestamp &length, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); + } // End of namespace Audio #endif diff --git a/audio/decoders/adpcm.cpp b/audio/decoders/adpcm.cpp index 535652a0b3..2fe509e1f3 100644 --- a/audio/decoders/adpcm.cpp +++ b/audio/decoders/adpcm.cpp @@ -71,13 +71,19 @@ int Oki_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { int samples; byte data; - assert(numSamples % 2 == 0); + for (samples = 0; samples < numSamples && !endOfData(); samples++) { + if (_decodedSampleCount == 0) { + data = _stream->readByte(); + _decodedSamples[0] = decodeOKI((data >> 4) & 0x0f); + _decodedSamples[1] = decodeOKI((data >> 0) & 0x0f); + _decodedSampleCount = 2; + } - for (samples = 0; samples < numSamples && !_stream->eos() && _stream->pos() < _endpos; samples += 2) { - data = _stream->readByte(); - buffer[samples] = decodeOKI((data >> 4) & 0x0f); - buffer[samples + 1] = decodeOKI(data & 0x0f); + // (1 - (count - 1)) ensures that _decodedSamples acts as a FIFO of depth 2 + buffer[samples] = _decodedSamples[1 - (_decodedSampleCount - 1)]; + _decodedSampleCount--; } + return samples; } @@ -117,13 +123,19 @@ int DVI_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { int samples; byte data; - assert(numSamples % 2 == 0); + for (samples = 0; samples < numSamples && !endOfData(); samples++) { + if (_decodedSampleCount == 0) { + data = _stream->readByte(); + _decodedSamples[0] = decodeIMA((data >> 4) & 0x0f, 0); + _decodedSamples[1] = decodeIMA((data >> 0) & 0x0f, _channels == 2 ? 1 : 0); + _decodedSampleCount = 2; + } - for (samples = 0; samples < numSamples && !_stream->eos() && _stream->pos() < _endpos; samples += 2) { - data = _stream->readByte(); - buffer[samples] = decodeIMA((data >> 4) & 0x0f); - buffer[samples + 1] = decodeIMA(data & 0x0f, _channels == 2 ? 1 : 0); + // (1 - (count - 1)) ensures that _decodedSamples acts as a FIFO of depth 2 + buffer[samples] = _decodedSamples[1 - (_decodedSampleCount - 1)]; + _decodedSampleCount--; } + return samples; } diff --git a/audio/decoders/adpcm_intern.h b/audio/decoders/adpcm_intern.h index 31747aabaf..3b8d8c74d0 100644 --- a/audio/decoders/adpcm_intern.h +++ b/audio/decoders/adpcm_intern.h @@ -37,7 +37,6 @@ #include "common/stream.h" #include "common/textconsole.h" - namespace Audio { class ADPCMStream : public RewindableAudioStream { @@ -64,12 +63,11 @@ public: ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign); virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos); } - virtual bool isStereo() const { return _channels == 2; } - virtual int getRate() const { return _rate; } + virtual bool isStereo() const { return _channels == 2; } + virtual int getRate() const { return _rate; } virtual bool rewind(); - /** * This table is used by some ADPCM variants (IMA and OKI) to adjust the * step for use on the next sample. @@ -83,12 +81,18 @@ public: class Oki_ADPCMStream : public ADPCMStream { public: Oki_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {} + : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { _decodedSampleCount = 0; } + + virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos) && (_decodedSampleCount == 0); } virtual int readBuffer(int16 *buffer, const int numSamples); protected: int16 decodeOKI(byte); + +private: + uint8 _decodedSampleCount; + int16 _decodedSamples[2]; }; class Ima_ADPCMStream : public ADPCMStream { @@ -108,9 +112,15 @@ public: class DVI_ADPCMStream : public Ima_ADPCMStream { public: DVI_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {} + : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { _decodedSampleCount = 0; } + + virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos) && (_decodedSampleCount == 0); } virtual int readBuffer(int16 *buffer, const int numSamples); + +private: + uint8 _decodedSampleCount; + int16 _decodedSamples[2]; }; class Apple_ADPCMStream : public Ima_ADPCMStream { diff --git a/audio/decoders/aiff.h b/audio/decoders/aiff.h index 59664bb85a..afcdb6ae6c 100644 --- a/audio/decoders/aiff.h +++ b/audio/decoders/aiff.h @@ -23,6 +23,7 @@ /** * @file * Sound decoder used in engines: + * - pegasus * - saga * - sci * - sword1 diff --git a/audio/decoders/qdm2.cpp b/audio/decoders/qdm2.cpp index 2de7a68dd9..732de311aa 100644 --- a/audio/decoders/qdm2.cpp +++ b/audio/decoders/qdm2.cpp @@ -35,7 +35,10 @@ #include "common/array.h" #include "common/debug.h" #include "common/math.h" +#include "common/rdft.h" #include "common/stream.h" +#include "common/memstream.h" +#include "common/bitstream.h" #include "common/textconsole.h" namespace Audio { @@ -50,14 +53,6 @@ enum { typedef int8 sb_int8_array[2][30][64]; -/* bit input */ -/* buffer, buffer_end and size_in_bits must be present and used by every reader */ -struct GetBitContext { - const uint8 *buffer, *bufferEnd; - int index; - int sizeInBits; -}; - struct QDM2SubPacket { int type; unsigned int size; @@ -106,53 +101,6 @@ struct QDM2FFT { } PACKED_STRUCT; #include "common/pack-end.h" -enum RDFTransformType { - RDFT, - IRDFT, - RIDFT, - IRIDFT -}; - -struct FFTComplex { - float re, im; -}; - -struct FFTContext { - int nbits; - int inverse; - uint16 *revtab; - FFTComplex *exptab; - FFTComplex *tmpBuf; - int mdctSize; // size of MDCT (i.e. number of input data * 2) - int mdctBits; // n = 2^nbits - // pre/post rotation tables - float *tcos; - float *tsin; - void (*fftPermute)(struct FFTContext *s, FFTComplex *z); - void (*fftCalc)(struct FFTContext *s, FFTComplex *z); - void (*imdctCalc)(struct FFTContext *s, float *output, const float *input); - void (*imdctHalf)(struct FFTContext *s, float *output, const float *input); - void (*mdctCalc)(struct FFTContext *s, float *output, const float *input); - int splitRadix; - int permutation; -}; - -enum { - FF_MDCT_PERM_NONE = 0, - FF_MDCT_PERM_INTERLEAVE = 1 -}; - -struct RDFTContext { - int nbits; - int inverse; - int signConvention; - - // pre/post rotation tables - float *tcos; - float *tsin; - FFTContext fft; -}; - class QDM2Stream : public Codec { public: QDM2Stream(Common::SeekableReadStream *extraData, DisposeAfterUse::Flag disposeExtraData); @@ -196,7 +144,7 @@ private: int _fftCoefsMinIndex[5]; int _fftCoefsMaxIndex[5]; int _fftLevelExp[6]; - RDFTContext _rdftCtx; + Common::RDFT *_rdft; QDM2FFT _fft; // I/O data @@ -265,9 +213,9 @@ private: void fill_coding_method_array(sb_int8_array tone_level_idx, sb_int8_array tone_level_idx_temp, sb_int8_array coding_method, int nb_channels, int c, int superblocktype_2_3, int cm_table_select); - void synthfilt_build_sb_samples(GetBitContext *gb, int length, int sb_min, int sb_max); - void init_quantized_coeffs_elem0(int8 *quantized_coeffs, GetBitContext *gb, int length); - void init_tone_level_dequantization(GetBitContext *gb, int length); + void synthfilt_build_sb_samples(Common::BitStream *gb, int length, int sb_min, int sb_max); + void init_quantized_coeffs_elem0(int8 *quantized_coeffs, Common::BitStream *gb, int length); + void init_tone_level_dequantization(Common::BitStream *gb, int length); void process_subpacket_9(QDM2SubPNode *node); void process_subpacket_10(QDM2SubPNode *node, int length); void process_subpacket_11(QDM2SubPNode *node, int length); @@ -276,7 +224,7 @@ private: void qdm2_decode_super_block(void); void qdm2_fft_init_coefficient(int sub_packet, int offset, int duration, int channel, int exp, int phase); - void qdm2_fft_decode_tones(int duration, GetBitContext *gb, int b); + void qdm2_fft_decode_tones(int duration, Common::BitStream *gb, int b); void qdm2_decode_fft_packets(void); void qdm2_fft_generate_tone(FFTTone *tone); void qdm2_fft_tone_synthesizer(uint8 sub_packet); @@ -308,560 +256,6 @@ typedef signed long long int int64_t; #define SB_DITHERING_NOISE(sb, noiseIdx) (_noiseTable[(noiseIdx)++] * sb_noise_attenuation[(sb)]) -static inline void initGetBits(GetBitContext *s, const uint8 *buffer, int bitSize) { - int bufferSize = (bitSize + 7) >> 3; - - if (bufferSize < 0 || bitSize < 0) { - bufferSize = bitSize = 0; - buffer = NULL; - } - - s->buffer = buffer; - s->sizeInBits = bitSize; - s->bufferEnd = buffer + bufferSize; - s->index = 0; -} - -static inline int getBitsCount(GetBitContext *s) { - return s->index; -} - -static inline unsigned int getBits1(GetBitContext *s) { - int index; - uint8 result; - - index = s->index; - result = s->buffer[index >> 3]; - - result >>= (index & 0x07); - result &= 1; - index++; - s->index = index; - - return result; -} - -static inline unsigned int getBits(GetBitContext *s, int n) { - int tmp, reCache, reIndex; - - reIndex = s->index; - - reCache = READ_LE_UINT32((const uint8 *)s->buffer + (reIndex >> 3)) >> (reIndex & 0x07); - - tmp = (reCache) & ((uint32)0xffffffff >> (32 - n)); - - s->index = reIndex + n; - - return tmp; -} - -static inline void skipBits(GetBitContext *s, int n) { - s->index += n; -} - -#define BITS_LEFT(length, gb) ((length) - getBitsCount((gb))) - -static int splitRadixPermutation(int i, int n, int inverse) { - if (n <= 2) - return i & 1; - - int m = n >> 1; - - if(!(i & m)) - return splitRadixPermutation(i, m, inverse) * 2; - - m >>= 1; - - if (inverse == !(i & m)) - return splitRadixPermutation(i, m, inverse) * 4 + 1; - - return splitRadixPermutation(i, m, inverse) * 4 - 1; -} - -// sin(2*pi*x/n) for 0<=x<n/4, followed by n/2<=x<3n/4 -float ff_sin_16[8]; -float ff_sin_32[16]; -float ff_sin_64[32]; -float ff_sin_128[64]; -float ff_sin_256[128]; -float ff_sin_512[256]; -float ff_sin_1024[512]; -float ff_sin_2048[1024]; -float ff_sin_4096[2048]; -float ff_sin_8192[4096]; -float ff_sin_16384[8192]; -float ff_sin_32768[16384]; -float ff_sin_65536[32768]; - -float *ff_sin_tabs[] = { - NULL, NULL, NULL, NULL, - ff_sin_16, ff_sin_32, ff_sin_64, ff_sin_128, ff_sin_256, ff_sin_512, ff_sin_1024, - ff_sin_2048, ff_sin_4096, ff_sin_8192, ff_sin_16384, ff_sin_32768, ff_sin_65536, -}; - -// cos(2*pi*x/n) for 0<=x<=n/4, followed by its reverse -float ff_cos_16[8]; -float ff_cos_32[16]; -float ff_cos_64[32]; -float ff_cos_128[64]; -float ff_cos_256[128]; -float ff_cos_512[256]; -float ff_cos_1024[512]; -float ff_cos_2048[1024]; -float ff_cos_4096[2048]; -float ff_cos_8192[4096]; -float ff_cos_16384[8192]; -float ff_cos_32768[16384]; -float ff_cos_65536[32768]; - -float *ff_cos_tabs[] = { - NULL, NULL, NULL, NULL, - ff_cos_16, ff_cos_32, ff_cos_64, ff_cos_128, ff_cos_256, ff_cos_512, ff_cos_1024, - ff_cos_2048, ff_cos_4096, ff_cos_8192, ff_cos_16384, ff_cos_32768, ff_cos_65536, -}; - -void initCosineTables(int index) { - int m = 1 << index; - double freq = 2 * M_PI / m; - float *tab = ff_cos_tabs[index]; - - for (int i = 0; i <= m / 4; i++) - tab[i] = cos(i * freq); - - for (int i = 1; i < m / 4; i++) - tab[m / 2 - i] = tab[i]; -} - -void fftPermute(FFTContext *s, FFTComplex *z) { - const uint16 *revtab = s->revtab; - int np = 1 << s->nbits; - - if (s->tmpBuf) { - // TODO: handle split-radix permute in a more optimal way, probably in-place - for (int j = 0; j < np; j++) - s->tmpBuf[revtab[j]] = z[j]; - memcpy(z, s->tmpBuf, np * sizeof(FFTComplex)); - return; - } - - // reverse - for (int j = 0; j < np; j++) { - int k = revtab[j]; - if (k < j) { - FFTComplex tmp = z[k]; - z[k] = z[j]; - z[j] = tmp; - } - } -} - -#define DECL_FFT(n,n2,n4) \ -static void fft##n(FFTComplex *z) { \ - fft##n2(z); \ - fft##n4(z + n4 * 2); \ - fft##n4(z + n4 * 3); \ - pass(z, ff_cos_##n, n4 / 2); \ -} - -#ifndef M_SQRT1_2 -#define M_SQRT1_2 7.0710678118654752440E-1 -#endif - -#define sqrthalf (float)M_SQRT1_2 - -#define BF(x,y,a,b) { \ - x = a - b; \ - y = a + b; \ -} - -#define BUTTERFLIES(a0, a1, a2, a3) { \ - BF(t3, t5, t5, t1); \ - BF(a2.re, a0.re, a0.re, t5); \ - BF(a3.im, a1.im, a1.im, t3); \ - BF(t4, t6, t2, t6); \ - BF(a3.re, a1.re, a1.re, t4); \ - BF(a2.im, a0.im, a0.im, t6); \ -} - -// force loading all the inputs before storing any. -// this is slightly slower for small data, but avoids store->load aliasing -// for addresses separated by large powers of 2. -#define BUTTERFLIES_BIG(a0, a1, a2, a3) { \ - float r0 = a0.re, i0 = a0.im, r1 = a1.re, i1 = a1.im; \ - BF(t3, t5, t5, t1); \ - BF(a2.re, a0.re, r0, t5); \ - BF(a3.im, a1.im, i1, t3); \ - BF(t4, t6, t2, t6); \ - BF(a3.re, a1.re, r1, t4); \ - BF(a2.im, a0.im, i0, t6); \ -} - -#define TRANSFORM(a0, a1, a2, a3, wre, wim) { \ - t1 = a2.re * wre + a2.im * wim; \ - t2 = a2.im * wre - a2.re * wim; \ - t5 = a3.re * wre - a3.im * wim; \ - t6 = a3.im * wre + a3.re * wim; \ - BUTTERFLIES(a0, a1, a2, a3) \ -} - -#define TRANSFORM_ZERO(a0, a1, a2, a3) { \ - t1 = a2.re; \ - t2 = a2.im; \ - t5 = a3.re; \ - t6 = a3.im; \ - BUTTERFLIES(a0, a1, a2, a3) \ -} - -// z[0...8n-1], w[1...2n-1] -#define PASS(name) \ -static void name(FFTComplex *z, const float *wre, unsigned int n) { \ - float t1, t2, t3, t4, t5, t6; \ - int o1 = 2 * n; \ - int o2 = 4 * n; \ - int o3 = 6 * n; \ - const float *wim = wre + o1; \ - n--; \ - \ - TRANSFORM_ZERO(z[0], z[o1], z[o2], z[o3]); \ - TRANSFORM(z[1], z[o1 + 1], z[o2 + 1], z[o3 + 1], wre[1], wim[-1]); \ - \ - do { \ - z += 2; \ - wre += 2; \ - wim -= 2; \ - TRANSFORM(z[0], z[o1], z[o2], z[o3], wre[0], wim[0]); \ - TRANSFORM(z[1], z[o1 + 1],z[o2 + 1], z[o3 + 1], wre[1], wim[-1]); \ - } while(--n); \ -} - -PASS(pass) -#undef BUTTERFLIES -#define BUTTERFLIES BUTTERFLIES_BIG -PASS(pass_big) - -static void fft4(FFTComplex *z) { - float t1, t2, t3, t4, t5, t6, t7, t8; - - BF(t3, t1, z[0].re, z[1].re); - BF(t8, t6, z[3].re, z[2].re); - BF(z[2].re, z[0].re, t1, t6); - BF(t4, t2, z[0].im, z[1].im); - BF(t7, t5, z[2].im, z[3].im); - BF(z[3].im, z[1].im, t4, t8); - BF(z[3].re, z[1].re, t3, t7); - BF(z[2].im, z[0].im, t2, t5); -} - -static void fft8(FFTComplex *z) { - float t1, t2, t3, t4, t5, t6, t7, t8; - - fft4(z); - - BF(t1, z[5].re, z[4].re, -z[5].re); - BF(t2, z[5].im, z[4].im, -z[5].im); - BF(t3, z[7].re, z[6].re, -z[7].re); - BF(t4, z[7].im, z[6].im, -z[7].im); - BF(t8, t1, t3, t1); - BF(t7, t2, t2, t4); - BF(z[4].re, z[0].re, z[0].re, t1); - BF(z[4].im, z[0].im, z[0].im, t2); - BF(z[6].re, z[2].re, z[2].re, t7); - BF(z[6].im, z[2].im, z[2].im, t8); - - TRANSFORM(z[1], z[3], z[5], z[7], sqrthalf, sqrthalf); -} - -#undef BF - -DECL_FFT(16,8,4) -DECL_FFT(32,16,8) -DECL_FFT(64,32,16) -DECL_FFT(128,64,32) -DECL_FFT(256,128,64) -DECL_FFT(512,256,128) -#define pass pass_big -DECL_FFT(1024,512,256) -DECL_FFT(2048,1024,512) -DECL_FFT(4096,2048,1024) -DECL_FFT(8192,4096,2048) -DECL_FFT(16384,8192,4096) -DECL_FFT(32768,16384,8192) -DECL_FFT(65536,32768,16384) - -void fftCalc(FFTContext *s, FFTComplex *z) { - static void (* const fftDispatch[])(FFTComplex *) = { - fft4, fft8, fft16, fft32, fft64, fft128, fft256, fft512, fft1024, - fft2048, fft4096, fft8192, fft16384, fft32768, fft65536, - }; - - fftDispatch[s->nbits - 2](z); -} - -// complex multiplication: p = a * b -#define CMUL(pre, pim, are, aim, bre, bim) \ -{\ - float _are = (are); \ - float _aim = (aim); \ - float _bre = (bre); \ - float _bim = (bim); \ - (pre) = _are * _bre - _aim * _bim; \ - (pim) = _are * _bim + _aim * _bre; \ -} - -/** - * Compute the middle half of the inverse MDCT of size N = 2^nbits, - * thus excluding the parts that can be derived by symmetry - * @param output N/2 samples - * @param input N/2 samples - */ -void imdctHalfC(FFTContext *s, float *output, const float *input) { - const uint16 *revtab = s->revtab; - const float *tcos = s->tcos; - const float *tsin = s->tsin; - FFTComplex *z = (FFTComplex *)output; - - int n = 1 << s->mdctBits; - int n2 = n >> 1; - int n4 = n >> 2; - int n8 = n >> 3; - - // pre rotation - const float *in1 = input; - const float *in2 = input + n2 - 1; - for (int k = 0; k < n4; k++) { - int j = revtab[k]; - CMUL(z[j].re, z[j].im, *in2, *in1, tcos[k], tsin[k]); - in1 += 2; - in2 -= 2; - } - - fftCalc(s, z); - - // post rotation + reordering - for (int k = 0; k < n8; k++) { - float r0, i0, r1, i1; - CMUL(r0, i1, z[n8 - k - 1].im, z[n8 - k - 1].re, tsin[n8 - k - 1], tcos[n8 - k - 1]); - CMUL(r1, i0, z[n8 + k].im, z[n8 + k].re, tsin[n8 + k], tcos[n8 + k]); - z[n8 - k - 1].re = r0; - z[n8 - k - 1].im = i0; - z[n8 + k].re = r1; - z[n8 + k].im = i1; - } -} - -/** - * Compute inverse MDCT of size N = 2^nbits - * @param output N samples - * @param input N/2 samples - */ -void imdctCalcC(FFTContext *s, float *output, const float *input) { - int n = 1 << s->mdctBits; - int n2 = n >> 1; - int n4 = n >> 2; - - imdctHalfC(s, output + n4, input); - - for (int k = 0; k < n4; k++) { - output[k] = -output[n2 - k - 1]; - output[n - k - 1] = output[n2 + k]; - } -} - -/** - * Compute MDCT of size N = 2^nbits - * @param input N samples - * @param out N/2 samples - */ -void mdctCalcC(FFTContext *s, float *out, const float *input) { - const uint16 *revtab = s->revtab; - const float *tcos = s->tcos; - const float *tsin = s->tsin; - FFTComplex *x = (FFTComplex *)out; - - int n = 1 << s->mdctBits; - int n2 = n >> 1; - int n4 = n >> 2; - int n8 = n >> 3; - int n3 = 3 * n4; - - // pre rotation - for (int i = 0; i < n8; i++) { - float re = -input[2 * i + 3 * n4] - input[n3 - 1 - 2 * i]; - float im = -input[n4 + 2 * i] + input[n4 - 1 - 2 * i]; - int j = revtab[i]; - CMUL(x[j].re, x[j].im, re, im, -tcos[i], tsin[i]); - - re = input[2 * i] - input[n2 - 1 - 2 * i]; - im = -(input[n2 + 2 * i] + input[n - 1 - 2 * i]); - j = revtab[n8 + i]; - CMUL(x[j].re, x[j].im, re, im, -tcos[n8 + i], tsin[n8 + i]); - } - - fftCalc(s, x); - - // post rotation - for (int i = 0; i < n8; i++) { - float r0, i0, r1, i1; - CMUL(i1, r0, x[n8 - i - 1].re, x[n8 - i - 1].im, -tsin[n8 - i - 1], -tcos[n8 - i - 1]); - CMUL(i0, r1, x[n8 + i].re, x[n8 + i].im, -tsin[n8 + i], -tcos[n8 + i]); - x[n8 - i - 1].re = r0; - x[n8 - i - 1].im = i0; - x[n8 + i].re = r1; - x[n8 + i].im = i1; - } -} - -int fftInit(FFTContext *s, int nbits, int inverse) { - int i, j, m, n; - float alpha, c1, s1, s2; - - if (nbits < 2 || nbits > 16) - goto fail; - - s->nbits = nbits; - n = 1 << nbits; - s->tmpBuf = NULL; - - s->exptab = (FFTComplex *)malloc((n / 2) * sizeof(FFTComplex)); - if (!s->exptab) - goto fail; - - s->revtab = (uint16 *)malloc(n * sizeof(uint16)); - if (!s->revtab) - goto fail; - s->inverse = inverse; - - s2 = inverse ? 1.0 : -1.0; - - s->fftPermute = fftPermute; - s->fftCalc = fftCalc; - s->imdctCalc = imdctCalcC; - s->imdctHalf = imdctHalfC; - s->mdctCalc = mdctCalcC; - s->splitRadix = 1; - - if (s->splitRadix) { - for (j = 4; j <= nbits; j++) - initCosineTables(j); - - for (i = 0; i < n; i++) - s->revtab[-splitRadixPermutation(i, n, s->inverse) & (n - 1)] = i; - - s->tmpBuf = (FFTComplex *)malloc(n * sizeof(FFTComplex)); - } else { - for (i = 0; i < n / 2; i++) { - alpha = 2 * M_PI * (float)i / (float)n; - c1 = cos(alpha); - s1 = sin(alpha) * s2; - s->exptab[i].re = c1; - s->exptab[i].im = s1; - } - - //int np = 1 << nbits; - //int nblocks = np >> 3; - //int np2 = np >> 1; - - // compute bit reverse table - for (i = 0; i < n; i++) { - m = 0; - - for (j = 0; j < nbits; j++) - m |= ((i >> j) & 1) << (nbits - j - 1); - - s->revtab[i] = m; - } - } - - return 0; - - fail: - free(&s->revtab); - free(&s->exptab); - free(&s->tmpBuf); - return -1; -} - -/** - * Sets up a real FFT. - * @param nbits log2 of the length of the input array - * @param trans the type of transform - */ -int rdftInit(RDFTContext *s, int nbits, RDFTransformType trans) { - int n = 1 << nbits; - const double theta = (trans == RDFT || trans == IRIDFT ? -1 : 1) * 2 * M_PI / n; - - s->nbits = nbits; - s->inverse = trans == IRDFT || trans == IRIDFT; - s->signConvention = trans == RIDFT || trans == IRIDFT ? 1 : -1; - - if (nbits < 4 || nbits > 16) - return -1; - - if (fftInit(&s->fft, nbits - 1, trans == IRDFT || trans == RIDFT) < 0) - return -1; - - initCosineTables(nbits); - s->tcos = ff_cos_tabs[nbits]; - s->tsin = ff_sin_tabs[nbits] + (trans == RDFT || trans == IRIDFT) * (n >> 2); - - for (int i = 0; i < n >> 2; i++) - s->tsin[i] = sin(i*theta); - - return 0; -} - -/** Map one real FFT into two parallel real even and odd FFTs. Then interleave - * the two real FFTs into one complex FFT. Unmangle the results. - * ref: http://www.engineeringproductivitytools.com/stuff/T0001/PT10.HTM - */ -void rdftCalc(RDFTContext *s, float *data) { - FFTComplex ev, od; - - const int n = 1 << s->nbits; - const float k1 = 0.5; - const float k2 = 0.5 - s->inverse; - const float *tcos = s->tcos; - const float *tsin = s->tsin; - - if (!s->inverse) { - fftPermute(&s->fft, (FFTComplex *)data); - fftCalc(&s->fft, (FFTComplex *)data); - } - - // i=0 is a special case because of packing, the DC term is real, so we - // are going to throw the N/2 term (also real) in with it. - ev.re = data[0]; - data[0] = ev.re + data[1]; - data[1] = ev.re - data[1]; - - int i; - - for (i = 1; i < n >> 2; i++) { - int i1 = i * 2; - int i2 = n - i1; - - // Separate even and odd FFTs - ev.re = k1 * (data[i1] + data[i2]); - od.im = -k2 * (data[i1] - data[i2]); - ev.im = k1 * (data[i1 + 1] - data[i2 + 1]); - od.re = k2 * (data[i1 + 1] + data[i2 + 1]); - - // Apply twiddle factors to the odd FFT and add to the even FFT - data[i1] = ev.re + od.re * tcos[i] - od.im * tsin[i]; - data[i1 + 1] = ev.im + od.im * tcos[i] + od.re * tsin[i]; - data[i2] = ev.re - od.re * tcos[i] + od.im * tsin[i]; - data[i2 + 1] = -ev.im + od.im * tcos[i] + od.re * tsin[i]; - } - - data[i * 2 + 1] = s->signConvention * data[i * 2 + 1]; - if (s->inverse) { - data[0] *= k1; - data[1] *= k1; - fftPermute(&s->fft, (FFTComplex *)data); - fftCalc(&s->fft, (FFTComplex *)data); - } -} - // half mpeg encoding window (full precision) const int32 ff_mpa_enwindow[257] = { 0, -1, -1, -1, -1, -1, -1, -2, @@ -1283,43 +677,27 @@ void ff_mpa_synth_filter(int16 *synth_buf_ptr, int *synth_buf_offset, * read the longest vlc code * = (max_vlc_length + bits - 1) / bits */ -static int getVlc2(GetBitContext *s, int16 (*table)[2], int bits, int maxDepth) { - int reIndex; - int reCache; - int index; - int code; - int n; - - reIndex = s->index; - reCache = READ_LE_UINT32(s->buffer + (reIndex >> 3)) >> (reIndex & 0x07); - index = reCache & (0xffffffff >> (32 - bits)); - code = table[index][0]; - n = table[index][1]; - - if (maxDepth > 1 && n < 0){ - reIndex += bits; - reCache = READ_LE_UINT32(s->buffer + (reIndex >> 3)) >> (reIndex & 0x07); +static int getVlc2(Common::BitStream *s, int16 (*table)[2], int bits, int maxDepth) { + int index = s->peekBits(bits); + int code = table[index][0]; + int n = table[index][1]; + if (maxDepth > 1 && n < 0) { + s->skip(bits); int nbBits = -n; - - index = (reCache & (0xffffffff >> (32 - nbBits))) + code; + index = s->peekBits(-n) + code; code = table[index][0]; n = table[index][1]; - if(maxDepth > 2 && n < 0) { - reIndex += nbBits; - reCache = READ_LE_UINT32(s->buffer + (reIndex >> 3)) >> (reIndex & 0x07); - - nbBits = -n; - - index = (reCache & (0xffffffff >> (32 - nbBits))) + code; + if (maxDepth > 2 && n < 0) { + s->skip(nbBits); + index = s->getBits(-n) + code; code = table[index][0]; n = table[index][1]; } } - reCache >>= n; - s->index = reIndex + n; + s->skip(n); return code; } @@ -1483,9 +861,9 @@ void initVlcSparse(VLC *vlc, int nb_bits, int nb_codes, const void *symbols, int symbols_wrap, int symbols_size) { vlc->bits = nb_bits; - if(vlc->table_size && vlc->table_size == vlc->table_allocated) { + if (vlc->table_size && vlc->table_size == vlc->table_allocated) { return; - } else if(vlc->table_size) { + } else if (vlc->table_size) { error("called on a partially initialized table"); } @@ -1830,7 +1208,7 @@ QDM2Stream::QDM2Stream(Common::SeekableReadStream *extraData, DisposeAfterUse::F if (_fftOrder < 7 || _fftOrder > 9) error("QDM2Stream::QDM2Stream() Unsupported fft_order: %d", _fftOrder); - rdftInit(&_rdftCtx, _fftOrder, IRDFT); + _rdft = new Common::RDFT(_fftOrder, Common::RDFT::IDFT_C2R); initVlc(); ff_mpa_synth_init(ff_mpa_synth_window); @@ -1845,29 +1223,30 @@ QDM2Stream::QDM2Stream(Common::SeekableReadStream *extraData, DisposeAfterUse::F } QDM2Stream::~QDM2Stream() { + delete _rdft; delete[] _compressedData; } -static int qdm2_get_vlc(GetBitContext *gb, VLC *vlc, int flag, int depth) { +static int qdm2_get_vlc(Common::BitStream *gb, VLC *vlc, int flag, int depth) { int value = getVlc2(gb, vlc->table, vlc->bits, depth); // stage-2, 3 bits exponent escape sequence if (value-- == 0) - value = getBits(gb, getBits (gb, 3) + 1); + value = gb->getBits(gb->getBits(3) + 1); // stage-3, optional if (flag) { int tmp = vlc_stage3_values[value]; if ((value & ~3) > 0) - tmp += getBits(gb, (value >> 2)); + tmp += gb->getBits(value >> 2); value = tmp; } return value; } -static int qdm2_get_se_vlc(VLC *vlc, GetBitContext *gb, int depth) +static int qdm2_get_se_vlc(VLC *vlc, Common::BitStream *gb, int depth) { int value = qdm2_get_vlc(gb, vlc, 0, depth); @@ -1893,35 +1272,6 @@ static uint16 qdm2_packet_checksum(const uint8 *data, int length, int value) { } /** - * Fills a QDM2SubPacket structure with packet type, size, and data pointer. - * - * @param gb bitreader context - * @param sub_packet packet under analysis - */ -static void qdm2_decode_sub_packet_header(GetBitContext *gb, QDM2SubPacket *sub_packet) -{ - sub_packet->type = getBits (gb, 8); - - if (sub_packet->type == 0) { - sub_packet->size = 0; - sub_packet->data = NULL; - } else { - sub_packet->size = getBits (gb, 8); - - if (sub_packet->type & 0x80) { - sub_packet->size <<= 8; - sub_packet->size |= getBits (gb, 8); - sub_packet->type &= 0x7f; - } - - if (sub_packet->type == 0x7f) - sub_packet->type |= (getBits (gb, 8) << 8); - - sub_packet->data = &gb->buffer[getBitsCount(gb) / 8]; // FIXME: this depends on bitreader internal data - } -} - -/** * Return node pointer to first packet of requested type in list. * * @param list list of subpackets to be scanned @@ -2003,7 +1353,7 @@ void QDM2Stream::fix_coding_method_array(int sb, int channels, sb_int8_array cod for (ch = 0; ch < channels; ch++) { for (j = 0; j < 64; ) { - if((coding_method[ch][sb][j] - 8) > 22) { + if ((coding_method[ch][sb][j] - 8) > 22) { run = 1; case_val = 8; } else { @@ -2256,7 +1606,7 @@ void QDM2Stream::fill_coding_method_array(sb_int8_array tone_level_idx, sb_int8_ * @param sb_min lower subband processed (sb_min included) * @param sb_max higher subband processed (sb_max excluded) */ -void QDM2Stream::synthfilt_build_sb_samples(GetBitContext *gb, int length, int sb_min, int sb_max) { +void QDM2Stream::synthfilt_build_sb_samples(Common::BitStream *gb, int length, int sb_min, int sb_max) { int sb, j, k, n, ch, run, channels; int joined_stereo, zero_encoding, chs; int type34_first; @@ -2282,12 +1632,12 @@ void QDM2Stream::synthfilt_build_sb_samples(GetBitContext *gb, int length, int s else if (sb >= 24) joined_stereo = 1; else - joined_stereo = (BITS_LEFT(length,gb) >= 1) ? getBits1 (gb) : 0; + joined_stereo = ((length - gb->pos()) >= 1) ? gb->getBit() : 0; if (joined_stereo) { - if (BITS_LEFT(length,gb) >= 16) + if ((length - gb->pos()) >= 16) for (j = 0; j < 16; j++) - sign_bits[j] = getBits1(gb); + sign_bits[j] = gb->getBit(); for (j = 0; j < 64; j++) if (_codingMethod[1][sb][j] > _codingMethod[0][sb][j]) @@ -2298,22 +1648,22 @@ void QDM2Stream::synthfilt_build_sb_samples(GetBitContext *gb, int length, int s } for (ch = 0; ch < channels; ch++) { - zero_encoding = (BITS_LEFT(length,gb) >= 1) ? getBits1(gb) : 0; + zero_encoding = ((length - gb->pos()) >= 1) ? gb->getBit() : 0; type34_predictor = 0.0; type34_first = 1; for (j = 0; j < 128; ) { switch (_codingMethod[ch][sb][j / 2]) { case 8: - if (BITS_LEFT(length,gb) >= 10) { + if ((length - gb->pos()) >= 10) { if (zero_encoding) { for (k = 0; k < 5; k++) { if ((j + 2 * k) >= 128) break; - samples[2 * k] = getBits1(gb) ? dequant_1bit[joined_stereo][2 * getBits1(gb)] : 0; + samples[2 * k] = gb->getBit() ? dequant_1bit[joined_stereo][2 * gb->getBit()] : 0; } } else { - n = getBits(gb, 8); + n = gb->getBits(8); for (k = 0; k < 5; k++) samples[2 * k] = dequant_1bit[joined_stereo][_randomDequantIndex[n][k]]; } @@ -2327,10 +1677,10 @@ void QDM2Stream::synthfilt_build_sb_samples(GetBitContext *gb, int length, int s break; case 10: - if (BITS_LEFT(length,gb) >= 1) { + if ((length - gb->pos()) >= 1) { double f = 0.81; - if (getBits1(gb)) + if (gb->getBit()) f = -f; f -= _noiseSamples[((sb + 1) * (j +5 * ch + 1)) & 127] * 9.0 / 40.0; samples[0] = f; @@ -2341,15 +1691,15 @@ void QDM2Stream::synthfilt_build_sb_samples(GetBitContext *gb, int length, int s break; case 16: - if (BITS_LEFT(length,gb) >= 10) { + if ((length - gb->pos()) >= 10) { if (zero_encoding) { for (k = 0; k < 5; k++) { if ((j + k) >= 128) break; - samples[k] = (getBits1(gb) == 0) ? 0 : dequant_1bit[joined_stereo][2 * getBits1(gb)]; + samples[k] = (gb->getBit() == 0) ? 0 : dequant_1bit[joined_stereo][2 * gb->getBit()]; } } else { - n = getBits (gb, 8); + n = gb->getBits(8); for (k = 0; k < 5; k++) samples[k] = dequant_1bit[joined_stereo][_randomDequantIndex[n][k]]; } @@ -2361,8 +1711,8 @@ void QDM2Stream::synthfilt_build_sb_samples(GetBitContext *gb, int length, int s break; case 24: - if (BITS_LEFT(length,gb) >= 7) { - n = getBits(gb, 7); + if ((length - gb->pos()) >= 7) { + n = gb->getBits(7); for (k = 0; k < 3; k++) samples[k] = (_randomDequantType24[n][k] - 2.0) * 0.5; } else { @@ -2373,7 +1723,7 @@ void QDM2Stream::synthfilt_build_sb_samples(GetBitContext *gb, int length, int s break; case 30: - if (BITS_LEFT(length,gb) >= 4) + if ((length - gb->pos()) >= 4) samples[0] = type30_dequant[qdm2_get_vlc(gb, &_vlcTabType30, 0, 1)]; else samples[0] = SB_DITHERING_NOISE(sb, _noiseIdx); @@ -2382,10 +1732,10 @@ void QDM2Stream::synthfilt_build_sb_samples(GetBitContext *gb, int length, int s break; case 34: - if (BITS_LEFT(length,gb) >= 7) { + if ((length - gb->pos()) >= 7) { if (type34_first) { - type34_div = (float)(1 << getBits(gb, 2)); - samples[0] = ((float)getBits(gb, 5) - 16.0) / 15.0; + type34_div = (float)(1 << gb->getBits(2)); + samples[0] = ((float)gb->getBits(5) - 16.0) / 15.0; type34_predictor = samples[0]; type34_first = 0; } else { @@ -2436,21 +1786,21 @@ void QDM2Stream::synthfilt_build_sb_samples(GetBitContext *gb, int length, int s * @param gb bitreader context * @param length packet length in bits */ -void QDM2Stream::init_quantized_coeffs_elem0(int8 *quantized_coeffs, GetBitContext *gb, int length) { +void QDM2Stream::init_quantized_coeffs_elem0(int8 *quantized_coeffs, Common::BitStream *gb, int length) { int i, k, run, level, diff; - if (BITS_LEFT(length,gb) < 16) + if ((length - gb->pos()) < 16) return; level = qdm2_get_vlc(gb, &_vlcTabLevel, 0, 2); quantized_coeffs[0] = level; for (i = 0; i < 7; ) { - if (BITS_LEFT(length,gb) < 16) + if ((length - gb->pos()) < 16) break; run = qdm2_get_vlc(gb, &_vlcTabRun, 0, 1) + 1; - if (BITS_LEFT(length,gb) < 16) + if ((length - gb->pos()) < 16) break; diff = qdm2_get_se_vlc(&_vlcTabDiff, gb, 2); @@ -2470,13 +1820,13 @@ void QDM2Stream::init_quantized_coeffs_elem0(int8 *quantized_coeffs, GetBitConte * @param gb bitreader context * @param length packet length in bits */ -void QDM2Stream::init_tone_level_dequantization(GetBitContext *gb, int length) { +void QDM2Stream::init_tone_level_dequantization(Common::BitStream *gb, int length) { int sb, j, k, n, ch; for (ch = 0; ch < _channels; ch++) { init_quantized_coeffs_elem0(_quantizedCoeffs[ch][0], gb, length); - if (BITS_LEFT(length,gb) < 16) { + if ((length - gb->pos()) < 16) { memset(_quantizedCoeffs[ch][0], 0, 8); break; } @@ -2487,11 +1837,11 @@ void QDM2Stream::init_tone_level_dequantization(GetBitContext *gb, int length) { for (sb = 0; sb < n; sb++) for (ch = 0; ch < _channels; ch++) for (j = 0; j < 8; j++) { - if (BITS_LEFT(length,gb) < 1) + if ((length - gb->pos()) < 1) break; - if (getBits1(gb)) { + if (gb->getBit()) { for (k=0; k < 8; k++) { - if (BITS_LEFT(length,gb) < 16) + if ((length - gb->pos()) < 16) break; _toneLevelIdxHi1[ch][sb][j][k] = qdm2_get_vlc(gb, &_vlcTabToneLevelIdxHi1, 0, 2); } @@ -2505,7 +1855,7 @@ void QDM2Stream::init_tone_level_dequantization(GetBitContext *gb, int length) { for (sb = 0; sb < n; sb++) for (ch = 0; ch < _channels; ch++) { - if (BITS_LEFT(length,gb) < 16) + if ((length - gb->pos()) < 16) break; _toneLevelIdxHi2[ch][sb] = qdm2_get_vlc(gb, &_vlcTabToneLevelIdxHi2, 0, 2); if (sb > 19) @@ -2520,7 +1870,7 @@ void QDM2Stream::init_tone_level_dequantization(GetBitContext *gb, int length) { for (sb = 0; sb < n; sb++) { for (ch = 0; ch < _channels; ch++) { for (j = 0; j < 8; j++) { - if (BITS_LEFT(length,gb) < 16) + if ((length - gb->pos()) < 16) break; _toneLevelIdxMid[ch][sb][j] = qdm2_get_vlc(gb, &_vlcTabToneLevelIdxMid, 0, 2) - 32; } @@ -2534,10 +1884,10 @@ void QDM2Stream::init_tone_level_dequantization(GetBitContext *gb, int length) { * @param node pointer to node with packet */ void QDM2Stream::process_subpacket_9(QDM2SubPNode *node) { - GetBitContext gb; int i, j, k, n, ch, run, level, diff; - initGetBits(&gb, node->packet->data, node->packet->size*8); + Common::MemoryReadStream d(node->packet->data, node->packet->size*8); + Common::BitStream32LELSB gb(&d); n = coeff_per_sb_for_avg[_coeffPerSbSelect][QDM2_SB_USED(_subSampling) - 1] + 1; // same as averagesomething function @@ -2570,9 +1920,8 @@ void QDM2Stream::process_subpacket_9(QDM2SubPNode *node) { * @param length packet length in bits */ void QDM2Stream::process_subpacket_10(QDM2SubPNode *node, int length) { - GetBitContext gb; - - initGetBits(&gb, ((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8)); + Common::MemoryReadStream d(((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8)); + Common::BitStream32LELSB gb(&d); if (length != 0) { init_tone_level_dequantization(&gb, length); @@ -2589,11 +1938,11 @@ void QDM2Stream::process_subpacket_10(QDM2SubPNode *node, int length) { * @param length packet length in bit */ void QDM2Stream::process_subpacket_11(QDM2SubPNode *node, int length) { - GetBitContext gb; + Common::MemoryReadStream d(((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8)); + Common::BitStream32LELSB gb(&d); - initGetBits(&gb, ((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8)); if (length >= 32) { - int c = getBits (&gb, 13); + int c = gb.getBits(13); if (c > 3) fill_coding_method_array(_toneLevelIdx, _toneLevelIdxTemp, _codingMethod, @@ -2610,9 +1959,9 @@ void QDM2Stream::process_subpacket_11(QDM2SubPNode *node, int length) { * @param length packet length in bits */ void QDM2Stream::process_subpacket_12(QDM2SubPNode *node, int length) { - GetBitContext gb; + Common::MemoryReadStream d(((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8)); + Common::BitStream32LELSB gb(&d); - initGetBits(&gb, ((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8)); synthfilt_build_sb_samples(&gb, length, 8, QDM2_SB_USED(_subSampling)); } @@ -2652,7 +2001,6 @@ void QDM2Stream::process_synthesis_subpackets(QDM2SubPNode *list) { * */ void QDM2Stream::qdm2_decode_super_block(void) { - GetBitContext gb; struct QDM2SubPacket header, *packet; int i, packet_bytes, sub_packet_size, subPacketsD; unsigned int next_index = 0; @@ -2666,8 +2014,28 @@ void QDM2Stream::qdm2_decode_super_block(void) { average_quantized_coeffs(); // average elements in quantized_coeffs[max_ch][10][8] - initGetBits(&gb, _compressedData, _packetSize*8); - qdm2_decode_sub_packet_header(&gb, &header); + Common::MemoryReadStream *d = new Common::MemoryReadStream(_compressedData, _packetSize*8); + Common::BitStream *gb = new Common::BitStream32LELSB(d); + //qdm2_decode_sub_packet_header + header.type = gb->getBits(8); + + if (header.type == 0) { + header.size = 0; + header.data = NULL; + } else { + header.size = gb->getBits(8); + + if (header.type & 0x80) { + header.size <<= 8; + header.size |= gb->getBits(8); + header.type &= 0x7f; + } + + if (header.type == 0x7f) + header.type |= (gb->getBits(8) << 8); + + header.data = &_compressedData[gb->pos() / 8]; + } if (header.type < 2 || header.type >= 8) { _hasErrors = true; @@ -2676,12 +2044,15 @@ void QDM2Stream::qdm2_decode_super_block(void) { } _superblocktype_2_3 = (header.type == 2 || header.type == 3); - packet_bytes = (_packetSize - getBitsCount(&gb) / 8); + packet_bytes = (_packetSize - gb->pos() / 8); - initGetBits(&gb, header.data, header.size*8); + delete gb; + delete d; + d = new Common::MemoryReadStream(header.data, header.size*8); + gb = new Common::BitStream32LELSB(d); if (header.type == 2 || header.type == 4 || header.type == 5) { - int csum = 257 * getBits(&gb, 8) + 2 * getBits(&gb, 8); + int csum = 257 * gb->getBits(8) + 2 * gb->getBits(8); csum = qdm2_packet_checksum(_compressedData, _packetSize, csum); @@ -2708,8 +2079,11 @@ void QDM2Stream::qdm2_decode_super_block(void) { _subPacketListA[i - 1].next = &_subPacketListA[i]; // seek to next block - initGetBits(&gb, header.data, header.size*8); - skipBits(&gb, next_index*8); + delete gb; + delete d; + d = new Common::MemoryReadStream(header.data, header.size*8); + gb = new Common::BitStream32LELSB(d); + gb->skip(next_index*8); if (next_index >= header.size) break; @@ -2717,8 +2091,28 @@ void QDM2Stream::qdm2_decode_super_block(void) { // decode subpacket packet = &_subPackets[i]; - qdm2_decode_sub_packet_header(&gb, packet); - next_index = packet->size + getBitsCount(&gb) / 8; + //qdm2_decode_sub_packet_header + packet->type = gb->getBits(8); + + if (packet->type == 0) { + packet->size = 0; + packet->data = NULL; + } else { + packet->size = gb->getBits(8); + + if (packet->type & 0x80) { + packet->size <<= 8; + packet->size |= gb->getBits(8); + packet->type &= 0x7f; + } + + if (packet->type == 0x7f) + packet->type |= (gb->getBits(8) << 8); + + packet->data = &header.data[gb->pos() / 8]; + } + + next_index = packet->size + gb->pos() / 8; sub_packet_size = ((packet->size > 0xff) ? 1 : 0) + packet->size + 2; if (packet->type == 0) @@ -2738,18 +2132,22 @@ void QDM2Stream::qdm2_decode_super_block(void) { // add subpacket to related list if (packet->type == 8) { error("Unsupported packet type 8"); + delete gb; + delete d; return; } else if (packet->type >= 9 && packet->type <= 12) { // packets for MPEG Audio like Synthesis Filter QDM2_LIST_ADD(_subPacketListD, subPacketsD, packet); } else if (packet->type == 13) { for (j = 0; j < 6; j++) - _fftLevelExp[j] = getBits(&gb, 6); + _fftLevelExp[j] = gb->getBits(6); } else if (packet->type == 14) { for (j = 0; j < 6; j++) - _fftLevelExp[j] = qdm2_get_vlc(&gb, &_fftLevelExpVlc, 0, 2); + _fftLevelExp[j] = qdm2_get_vlc(gb, &_fftLevelExpVlc, 0, 2); } else if (packet->type == 15) { error("Unsupported packet type 15"); + delete gb; + delete d; return; } else if (packet->type >= 16 && packet->type < 48 && !fft_subpackets[packet->type - 16]) { // packets for FFT @@ -2767,6 +2165,8 @@ void QDM2Stream::qdm2_decode_super_block(void) { process_subpacket_12(NULL, 0); } // **************************************************************** + delete gb; + delete d; } void QDM2Stream::qdm2_fft_init_coefficient(int sub_packet, int offset, int duration, @@ -2782,7 +2182,7 @@ void QDM2Stream::qdm2_fft_init_coefficient(int sub_packet, int offset, int durat _fftCoefsIndex++; } -void QDM2Stream::qdm2_fft_decode_tones(int duration, GetBitContext *gb, int b) { +void QDM2Stream::qdm2_fft_decode_tones(int duration, Common::BitStream *gb, int b) { int channel, stereo, phase, exp; int local_int_4, local_int_8, stereo_phase, local_int_10; int local_int_14, stereo_exp, local_int_20, local_int_28; @@ -2823,8 +2223,8 @@ void QDM2Stream::qdm2_fft_decode_tones(int duration, GetBitContext *gb, int b) { local_int_14 = (offset >> local_int_8); if (_channels > 1) { - channel = getBits1(gb); - stereo = getBits1(gb); + channel = gb->getBit(); + stereo = gb->getBit(); } else { channel = 0; stereo = 0; @@ -2834,7 +2234,7 @@ void QDM2Stream::qdm2_fft_decode_tones(int duration, GetBitContext *gb, int b) { exp += _fftLevelExp[fft_level_index_table[local_int_14]]; exp = (exp < 0) ? 0 : exp; - phase = getBits(gb, 3); + phase = gb->getBits(3); stereo_exp = 0; stereo_phase = 0; @@ -2859,7 +2259,6 @@ void QDM2Stream::qdm2_fft_decode_tones(int duration, GetBitContext *gb, int b) { void QDM2Stream::qdm2_decode_fft_packets(void) { int i, j, min, max, value, type, unknown_flag; - GetBitContext gb; if (_subPacketListB[0].packet == NULL) return; @@ -2892,7 +2291,8 @@ void QDM2Stream::qdm2_decode_fft_packets(void) { return; // decode FFT tones - initGetBits(&gb, packet->data, packet->size*8); + Common::MemoryReadStream d(packet->data, packet->size*8); + Common::BitStream32LELSB gb(&d); if (packet->type >= 32 && packet->type < 48 && !fft_subpackets[packet->type - 16]) unknown_flag = 1; @@ -2913,7 +2313,7 @@ void QDM2Stream::qdm2_decode_fft_packets(void) { } } else if (type == 46) { for (j=0; j < 6; j++) - _fftLevelExp[j] = getBits(&gb, 6); + _fftLevelExp[j] = gb.getBits(6); for (j=0; j < 4; j++) { qdm2_fft_decode_tones(j, &gb, unknown_flag); } @@ -3045,15 +2445,13 @@ void QDM2Stream::qdm2_fft_tone_synthesizer(uint8 sub_packet) { } void QDM2Stream::qdm2_calculate_fft(int channel) { - int i; - _fft.complex[channel][0].re *= 2.0f; _fft.complex[channel][0].im = 0.0f; - rdftCalc(&_rdftCtx, (float *)_fft.complex[channel]); + _rdft->calc((float *)_fft.complex[channel]); // add samples to output buffer - for (i = 0; i < ((_fftFrameSize + 15) & ~15); i++) + for (int i = 0; i < ((_fftFrameSize + 15) & ~15); i++) _outputBuffer[_channels * i + channel] += ((float *) _fft.complex[channel])[i]; } diff --git a/audio/decoders/quicktime.cpp b/audio/decoders/quicktime.cpp index 762e86959d..0588650ec6 100644 --- a/audio/decoders/quicktime.cpp +++ b/audio/decoders/quicktime.cpp @@ -62,38 +62,42 @@ private: }; /** - * An AudioStream wrapper that cuts off the amount of samples read after a - * given time length is reached. + * An AudioStream wrapper that forces audio to be played in mono. + * It currently just ignores the right channel if stereo. */ -class LimitingAudioStream : public AudioStream { +class ForcedMonoAudioStream : public AudioStream { public: - LimitingAudioStream(AudioStream *parentStream, const Audio::Timestamp &length, - DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES) : - _parentStream(parentStream), _samplesRead(0), _disposeAfterUse(disposeAfterUse), - _totalSamples(length.convertToFramerate(getRate()).totalNumberOfFrames() * getChannels()) {} + ForcedMonoAudioStream(AudioStream *parentStream, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES) : + _parentStream(parentStream), _disposeAfterUse(disposeAfterUse) {} - ~LimitingAudioStream() { + ~ForcedMonoAudioStream() { if (_disposeAfterUse == DisposeAfterUse::YES) - delete _parentStream; + delete _parentStream; } int readBuffer(int16 *buffer, const int numSamples) { - // Cap us off so we don't read past _totalSamples - int samplesRead = _parentStream->readBuffer(buffer, MIN<int>(numSamples, _totalSamples - _samplesRead)); - _samplesRead += samplesRead; - return samplesRead; + if (!_parentStream->isStereo()) + return _parentStream->readBuffer(buffer, numSamples); + + int16 temp[2]; + int samples = 0; + + while (samples < numSamples && !endOfData()) { + _parentStream->readBuffer(temp, 2); + *buffer++ = temp[0]; + samples++; + } + + return samples; } - bool endOfData() const { return _parentStream->endOfData() || _samplesRead >= _totalSamples; } - bool isStereo() const { return _parentStream->isStereo(); } + bool endOfData() const { return _parentStream->endOfData(); } + bool isStereo() const { return false; } int getRate() const { return _parentStream->getRate(); } private: - int getChannels() const { return isStereo() ? 2 : 1; } - AudioStream *_parentStream; DisposeAfterUse::Flag _disposeAfterUse; - uint32 _totalSamples, _samplesRead; }; QuickTimeAudioDecoder::QuickTimeAudioDecoder() : Common::QuickTimeParser() { @@ -191,7 +195,7 @@ QuickTimeAudioDecoder::QuickTimeAudioTrack::QuickTimeAudioTrack(QuickTimeAudioDe if (entry->getCodecTag() == MKTAG('r', 'a', 'w', ' ') || entry->getCodecTag() == MKTAG('t', 'w', 'o', 's')) _parentTrack->sampleSize = (entry->_bitsPerSample / 8) * entry->_channels; - + // Initialize our edit parser too _curEdit = 0; enterNewEdit(Timestamp()); @@ -224,7 +228,7 @@ void QuickTimeAudioDecoder::QuickTimeAudioTrack::queueAudio(const Timestamp &len _skipSamples = Timestamp(); } - queueStream(new LimitingAudioStream(new SilentAudioStream(getRate(), isStereo()), editLength), editLength); + queueStream(makeLimitingAudioStream(new SilentAudioStream(getRate(), isStereo()), editLength), editLength); _curEdit++; enterNewEdit(nextEditTime); } else { @@ -250,7 +254,7 @@ void QuickTimeAudioDecoder::QuickTimeAudioTrack::queueAudio(const Timestamp &len // we move on to the next edit if (trackPosition >= nextEditTime || _curChunk >= _parentTrack->chunkCount) { chunkLength = nextEditTime.convertToFramerate(getRate()) - getCurrentTrackTime(); - stream = new LimitingAudioStream(stream, chunkLength); + stream = makeLimitingAudioStream(stream, chunkLength); _curEdit++; enterNewEdit(nextEditTime); @@ -299,7 +303,7 @@ bool QuickTimeAudioDecoder::QuickTimeAudioTrack::seek(const Timestamp &where) { _queue = createStream(); _samplesQueued = 0; - if (where > getLength()) { + if (where >= getLength()) { // We're done _curEdit = _parentTrack->editCount; return true; @@ -391,9 +395,9 @@ AudioStream *QuickTimeAudioDecoder::QuickTimeAudioTrack::readAudioChunk(uint chu } void QuickTimeAudioDecoder::QuickTimeAudioTrack::skipSamples(const Timestamp &length, AudioStream *stream) { - uint32 sampleCount = length.convertToFramerate(getRate()).totalNumberOfFrames(); + int32 sampleCount = length.convertToFramerate(getRate()).totalNumberOfFrames(); - if (sampleCount == 0) + if (sampleCount <= 0) return; if (isStereo()) @@ -410,7 +414,7 @@ void QuickTimeAudioDecoder::QuickTimeAudioTrack::skipSamples(const Timestamp &le } void QuickTimeAudioDecoder::QuickTimeAudioTrack::findEdit(const Timestamp &position) { - for (_curEdit = 0; _curEdit < _parentTrack->editCount && position < Timestamp(0, _parentTrack->editList[_curEdit].timeOffset, _decoder->_timeScale); _curEdit++) + for (_curEdit = 0; _curEdit < _parentTrack->editCount - 1 && position > Timestamp(0, _parentTrack->editList[_curEdit].timeOffset, _decoder->_timeScale); _curEdit++) ; enterNewEdit(position); @@ -422,7 +426,7 @@ void QuickTimeAudioDecoder::QuickTimeAudioTrack::enterNewEdit(const Timestamp &p // If we're at the end of the edit list, there's nothing else for us to do here if (allDataRead()) return; - + // For an empty edit, we may need to adjust the start time if (_parentTrack->editList[_curEdit].mediaTime == -1) { // Just invalidate the current media position (and make sure the scale @@ -495,7 +499,13 @@ void QuickTimeAudioDecoder::QuickTimeAudioTrack::enterNewEdit(const Timestamp &p } void QuickTimeAudioDecoder::QuickTimeAudioTrack::queueStream(AudioStream *stream, const Timestamp &length) { - _queue->queueAudioStream(stream, DisposeAfterUse::YES); + // If the samples are stereo and the container is mono, force the samples + // to be mono. + if (stream->isStereo() && !isStereo()) + _queue->queueAudioStream(new ForcedMonoAudioStream(stream, DisposeAfterUse::YES), DisposeAfterUse::YES); + else + _queue->queueAudioStream(stream, DisposeAfterUse::YES); + _samplesQueued += length.convertToFramerate(getRate()).totalNumberOfFrames(); } diff --git a/audio/decoders/quicktime.h b/audio/decoders/quicktime.h index 4dd1a57710..4c0b93488e 100644 --- a/audio/decoders/quicktime.h +++ b/audio/decoders/quicktime.h @@ -25,6 +25,7 @@ * Sound decoder used in engines: * - groovie * - mohawk + * - pegasus * - sci */ diff --git a/audio/decoders/quicktime_intern.h b/audio/decoders/quicktime_intern.h index efc97cbd13..f1ab037d89 100644 --- a/audio/decoders/quicktime_intern.h +++ b/audio/decoders/quicktime_intern.h @@ -88,7 +88,7 @@ protected: private: QuickTimeAudioDecoder *_decoder; - Track *_parentTrack; + Track *_parentTrack; QueuingAudioStream *_queue; uint _curChunk; Timestamp _curMediaPos, _skipSamples; @@ -115,7 +115,7 @@ protected: ~AudioSampleDesc(); bool isAudioCodecSupported() const; - + AudioStream *createAudioStream(Common::SeekableReadStream *stream) const; void initCodec(); diff --git a/audio/decoders/voc.cpp b/audio/decoders/voc.cpp index f0b5b2777d..fa330c6f2c 100644 --- a/audio/decoders/voc.cpp +++ b/audio/decoders/voc.cpp @@ -321,9 +321,14 @@ void VocStream::preProcess() { // In case we hit a "Terminator" block we also break here. if (_stream->eos() || block.code == 0) break; - // We also allow 128 as terminator, since Simon 1 Amiga CD32 uses it. - if (block.code == 128) { - debug(3, "VocStream::preProcess: Caught 128 as terminator"); + // We will allow invalid block numbers as terminators. This is needed, + // since some games ship broken VOC files. The following occasions are + // known: + // - 128 is used as terminator in Simon 1 Amiga CD32 + // - Full Throttle contains a VOC file with an incorrect block length + // resulting in a sample (127) to be read as block code. + if (block.code > 9) { + warning("VocStream::preProcess: Caught %d as terminator", block.code); break; } @@ -482,7 +487,8 @@ void VocStream::preProcess() { default: warning("Unhandled code %d in VOC file (len %d)", block.code, block.length); - return; + // Skip the whole block and try to use the next one. + skip = block.length; } // Premature end of stream => error! diff --git a/audio/mididrv.cpp b/audio/mididrv.cpp index 0518915e81..dea07a739b 100644 --- a/audio/mididrv.cpp +++ b/audio/mididrv.cpp @@ -240,7 +240,7 @@ MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) { devStr = ConfMan.hasKey("gm_device") ? ConfMan.get("gm_device") : Common::String("null"); else devStr = "auto"; - + // Default to Null device here, since we also register a default null setting for // the MT32 or GM device in the config manager. hdl = getDeviceHandle(devStr.empty() ? Common::String("null") : devStr); diff --git a/audio/midiparser.cpp b/audio/midiparser.cpp index 943a6067a4..eec32c05d1 100644 --- a/audio/midiparser.cpp +++ b/audio/midiparser.cpp @@ -32,24 +32,24 @@ ////////////////////////////////////////////////// MidiParser::MidiParser() : -_hanging_notes_count(0), +_hangingNotesCount(0), _driver(0), -_timer_rate(0x4A0000), +_timerRate(0x4A0000), _ppqn(96), _tempo(500000), -_psec_per_tick(5208), // 500000 / 96 +_psecPerTick(5208), // 500000 / 96 _autoLoop(false), _smartJump(false), _centerPitchWheelOnUnload(false), _sendSustainOffOnNotesOff(false), -_num_tracks(0), -_active_track(255), -_abort_parse(0) { - memset(_active_notes, 0, sizeof(_active_notes)); - _next_event.start = NULL; - _next_event.delta = 0; - _next_event.event = 0; - _next_event.length = 0; +_numTracks(0), +_activeTrack(255), +_abortParse(0) { + memset(_activeNotes, 0, sizeof(_activeNotes)); + _nextEvent.start = NULL; + _nextEvent.delta = 0; + _nextEvent.event = 0; + _nextEvent.length = 0; } void MidiParser::property(int prop, int value) { @@ -76,7 +76,7 @@ void MidiParser::sendToDriver(uint32 b) { void MidiParser::setTempo(uint32 tempo) { _tempo = tempo; if (_ppqn) - _psec_per_tick = (tempo + (_ppqn >> 2)) / _ppqn; + _psecPerTick = (tempo + (_ppqn >> 2)) / _ppqn; } // This is the conventional (i.e. SMF) variable length quantity @@ -100,44 +100,44 @@ void MidiParser::activeNote(byte channel, byte note, bool active) { return; if (active) - _active_notes[note] |= (1 << channel); + _activeNotes[note] |= (1 << channel); else - _active_notes[note] &= ~(1 << channel); + _activeNotes[note] &= ~(1 << channel); // See if there are hanging notes that we can cancel - NoteTimer *ptr = _hanging_notes; + NoteTimer *ptr = _hangingNotes; int i; - for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) { - if (ptr->channel == channel && ptr->note == note && ptr->time_left) { - ptr->time_left = 0; - --_hanging_notes_count; + for (i = ARRAYSIZE(_hangingNotes); i; --i, ++ptr) { + if (ptr->channel == channel && ptr->note == note && ptr->timeLeft) { + ptr->timeLeft = 0; + --_hangingNotesCount; break; } } } -void MidiParser::hangingNote(byte channel, byte note, uint32 time_left, bool recycle) { +void MidiParser::hangingNote(byte channel, byte note, uint32 timeLeft, bool recycle) { NoteTimer *best = 0; - NoteTimer *ptr = _hanging_notes; + NoteTimer *ptr = _hangingNotes; int i; - if (_hanging_notes_count >= ARRAYSIZE(_hanging_notes)) { + if (_hangingNotesCount >= ARRAYSIZE(_hangingNotes)) { warning("MidiParser::hangingNote(): Exceeded polyphony"); return; } - for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) { + for (i = ARRAYSIZE(_hangingNotes); i; --i, ++ptr) { if (ptr->channel == channel && ptr->note == note) { - if (ptr->time_left && ptr->time_left < time_left && recycle) + if (ptr->timeLeft && ptr->timeLeft < timeLeft && recycle) return; best = ptr; - if (ptr->time_left) { + if (ptr->timeLeft) { if (recycle) sendToDriver(0x80 | channel, note, 0); - --_hanging_notes_count; + --_hangingNotesCount; } break; - } else if (!best && ptr->time_left == 0) { + } else if (!best && ptr->timeLeft == 0) { best = ptr; } } @@ -146,14 +146,14 @@ void MidiParser::hangingNote(byte channel, byte note, uint32 time_left, bool rec // length, if the note should be turned on and off in // the same iteration. For now just set it to 1 and // we'll turn it off in the next cycle. - if (!time_left || time_left & 0x80000000) - time_left = 1; + if (!timeLeft || timeLeft & 0x80000000) + timeLeft = 1; if (best) { best->channel = channel; best->note = note; - best->time_left = time_left; - ++_hanging_notes_count; + best->timeLeft = timeLeft; + ++_hangingNotesCount; } else { // We checked this up top. We should never get here! warning("MidiParser::hangingNote(): Internal error"); @@ -161,45 +161,45 @@ void MidiParser::hangingNote(byte channel, byte note, uint32 time_left, bool rec } void MidiParser::onTimer() { - uint32 end_time; - uint32 event_time; + uint32 endTime; + uint32 eventTime; - if (!_position._play_pos || !_driver) + if (!_position._playPos || !_driver) return; - _abort_parse = false; - end_time = _position._play_time + _timer_rate; + _abortParse = false; + endTime = _position._playTime + _timerRate; // Scan our hanging notes for any // that should be turned off. - if (_hanging_notes_count) { - NoteTimer *ptr = &_hanging_notes[0]; + if (_hangingNotesCount) { + NoteTimer *ptr = &_hangingNotes[0]; int i; - for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) { - if (ptr->time_left) { - if (ptr->time_left <= _timer_rate) { + for (i = ARRAYSIZE(_hangingNotes); i; --i, ++ptr) { + if (ptr->timeLeft) { + if (ptr->timeLeft <= _timerRate) { sendToDriver(0x80 | ptr->channel, ptr->note, 0); - ptr->time_left = 0; - --_hanging_notes_count; + ptr->timeLeft = 0; + --_hangingNotesCount; } else { - ptr->time_left -= _timer_rate; + ptr->timeLeft -= _timerRate; } } } } - while (!_abort_parse) { - EventInfo &info = _next_event; + while (!_abortParse) { + EventInfo &info = _nextEvent; - event_time = _position._last_event_time + info.delta * _psec_per_tick; - if (event_time > end_time) + eventTime = _position._lastEventTime + info.delta * _psecPerTick; + if (eventTime > endTime) break; // Process the next info. - _position._last_event_tick += info.delta; + _position._lastEventTick += info.delta; if (info.event < 0x80) { warning("Bad command or running status %02X", info.event); - _position._play_pos = 0; + _position._playPos = 0; return; } @@ -217,7 +217,7 @@ void MidiParser::onTimer() { // as well as sending it to the output device. if (_autoLoop) { jumpToTick(0); - parseNextEvent(_next_event); + parseNextEvent(_nextEvent); } else { stopPlaying(); _driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length); @@ -234,7 +234,7 @@ void MidiParser::onTimer() { activeNote(info.channel(), info.basic.param1, false); } else if (info.command() == 0x9) { if (info.length > 0) - hangingNote(info.channel(), info.basic.param1, info.length * _psec_per_tick - (end_time - event_time)); + hangingNote(info.channel(), info.basic.param1, info.length * _psecPerTick - (endTime - eventTime)); else activeNote(info.channel(), info.basic.param1, true); } @@ -242,15 +242,15 @@ void MidiParser::onTimer() { } - if (!_abort_parse) { - _position._last_event_time = event_time; - parseNextEvent(_next_event); + if (!_abortParse) { + _position._lastEventTime = eventTime; + parseNextEvent(_nextEvent); } } - if (!_abort_parse) { - _position._play_time = end_time; - _position._play_tick = (_position._play_time - _position._last_event_time) / _psec_per_tick + _position._last_event_tick; + if (!_abortParse) { + _position._playTime = endTime; + _position._playTick = (_position._playTime - _position._lastEventTime) / _psecPerTick + _position._lastEventTick; } } @@ -263,20 +263,20 @@ void MidiParser::allNotesOff() { // Turn off all active notes for (i = 0; i < 128; ++i) { for (j = 0; j < 16; ++j) { - if (_active_notes[i] & (1 << j)) { + if (_activeNotes[i] & (1 << j)) { sendToDriver(0x80 | j, i, 0); } } } // Turn off all hanging notes - for (i = 0; i < ARRAYSIZE(_hanging_notes); i++) { - if (_hanging_notes[i].time_left) { - sendToDriver(0x80 | _hanging_notes[i].channel, _hanging_notes[i].note, 0); - _hanging_notes[i].time_left = 0; + for (i = 0; i < ARRAYSIZE(_hangingNotes); i++) { + if (_hangingNotes[i].timeLeft) { + sendToDriver(0x80 | _hangingNotes[i].channel, _hangingNotes[i].note, 0); + _hangingNotes[i].timeLeft = 0; } } - _hanging_notes_count = 0; + _hangingNotesCount = 0; // To be sure, send an "All Note Off" event (but not all MIDI devices // support this...). @@ -287,7 +287,7 @@ void MidiParser::allNotesOff() { sendToDriver(0xB0 | i, 0x40, 0); // Also send a sustain off event (bug #3116608) } - memset(_active_notes, 0, sizeof(_active_notes)); + memset(_activeNotes, 0, sizeof(_activeNotes)); } void MidiParser::resetTracking() { @@ -295,7 +295,7 @@ void MidiParser::resetTracking() { } bool MidiParser::setTrack(int track) { - if (track < 0 || track >= _num_tracks) + if (track < 0 || track >= _numTracks) return false; // We allow restarting the track via setTrack when // it isn't playing anymore. This allows us to reuse @@ -308,7 +308,7 @@ bool MidiParser::setTrack(int track) { // TODO: Check if any engine has problem with this // handling, if so we need to find a better way to handle // track restarts. (KYRA relies on this working) - else if (track == _active_track && isPlaying()) + else if (track == _activeTrack && isPlaying()) return true; if (_smartJump) @@ -317,10 +317,10 @@ bool MidiParser::setTrack(int track) { allNotesOff(); resetTracking(); - memset(_active_notes, 0, sizeof(_active_notes)); - _active_track = track; - _position._play_pos = _tracks[track]; - parseNextEvent(_next_event); + memset(_activeNotes, 0, sizeof(_activeNotes)); + _activeTrack = track; + _position._playPos = _tracks[track]; + parseNextEvent(_nextEvent); return true; } @@ -332,29 +332,29 @@ void MidiParser::stopPlaying() { void MidiParser::hangAllActiveNotes() { // Search for note off events until we have // accounted for every active note. - uint16 temp_active[128]; - memcpy(temp_active, _active_notes, sizeof (temp_active)); + uint16 tempActive[128]; + memcpy(tempActive, _activeNotes, sizeof (tempActive)); - uint32 advance_tick = _position._last_event_tick; + uint32 advanceTick = _position._lastEventTick; while (true) { int i; for (i = 0; i < 128; ++i) - if (temp_active[i] != 0) + if (tempActive[i] != 0) break; if (i == 128) break; - parseNextEvent(_next_event); - advance_tick += _next_event.delta; - if (_next_event.command() == 0x8) { - if (temp_active[_next_event.basic.param1] & (1 << _next_event.channel())) { - hangingNote(_next_event.channel(), _next_event.basic.param1, (advance_tick - _position._last_event_tick) * _psec_per_tick, false); - temp_active[_next_event.basic.param1] &= ~(1 << _next_event.channel()); + parseNextEvent(_nextEvent); + advanceTick += _nextEvent.delta; + if (_nextEvent.command() == 0x8) { + if (tempActive[_nextEvent.basic.param1] & (1 << _nextEvent.channel())) { + hangingNote(_nextEvent.channel(), _nextEvent.basic.param1, (advanceTick - _position._lastEventTick) * _psecPerTick, false); + tempActive[_nextEvent.basic.param1] &= ~(1 << _nextEvent.channel()); } - } else if (_next_event.event == 0xFF && _next_event.ext.type == 0x2F) { + } else if (_nextEvent.event == 0xFF && _nextEvent.ext.type == 0x2F) { // warning("MidiParser::hangAllActiveNotes(): Hit End of Track with active notes left"); for (i = 0; i < 128; ++i) { for (int j = 0; j < 16; ++j) { - if (temp_active[i] & (1 << j)) { + if (tempActive[i] & (1 << j)) { activeNote(j, i, false); sendToDriver(0x80 | j, i, 0); } @@ -366,33 +366,33 @@ void MidiParser::hangAllActiveNotes() { } bool MidiParser::jumpToTick(uint32 tick, bool fireEvents, bool stopNotes, bool dontSendNoteOn) { - if (_active_track >= _num_tracks) + if (_activeTrack >= _numTracks) return false; Tracker currentPos(_position); - EventInfo currentEvent(_next_event); + EventInfo currentEvent(_nextEvent); resetTracking(); - _position._play_pos = _tracks[_active_track]; - parseNextEvent(_next_event); + _position._playPos = _tracks[_activeTrack]; + parseNextEvent(_nextEvent); if (tick > 0) { while (true) { - EventInfo &info = _next_event; - if (_position._last_event_tick + info.delta >= tick) { - _position._play_time += (tick - _position._last_event_tick) * _psec_per_tick; - _position._play_tick = tick; + EventInfo &info = _nextEvent; + if (_position._lastEventTick + info.delta >= tick) { + _position._playTime += (tick - _position._lastEventTick) * _psecPerTick; + _position._playTick = tick; break; } - _position._last_event_tick += info.delta; - _position._last_event_time += info.delta * _psec_per_tick; - _position._play_tick = _position._last_event_tick; - _position._play_time = _position._last_event_time; + _position._lastEventTick += info.delta; + _position._lastEventTime += info.delta * _psecPerTick; + _position._playTick = _position._lastEventTick; + _position._playTime = _position._lastEventTime; if (info.event == 0xFF) { if (info.ext.type == 0x2F) { // End of track _position = currentPos; - _next_event = currentEvent; + _nextEvent = currentEvent; return false; } else { if (info.ext.type == 0x51 && info.length >= 3) // Tempo @@ -419,36 +419,36 @@ bool MidiParser::jumpToTick(uint32 tick, bool fireEvents, bool stopNotes, bool d } } - parseNextEvent(_next_event); + parseNextEvent(_nextEvent); } } if (stopNotes) { - if (!_smartJump || !currentPos._play_pos) { + if (!_smartJump || !currentPos._playPos) { allNotesOff(); } else { - EventInfo targetEvent(_next_event); + EventInfo targetEvent(_nextEvent); Tracker targetPosition(_position); _position = currentPos; - _next_event = currentEvent; + _nextEvent = currentEvent; hangAllActiveNotes(); - _next_event = targetEvent; + _nextEvent = targetEvent; _position = targetPosition; } } - _abort_parse = true; + _abortParse = true; return true; } void MidiParser::unloadMusic() { resetTracking(); allNotesOff(); - _num_tracks = 0; - _active_track = 255; - _abort_parse = true; + _numTracks = 0; + _activeTrack = 255; + _abortParse = true; if (_centerPitchWheelOnUnload) { // Center the pitch wheels in preparation for the next piece of diff --git a/audio/midiparser.h b/audio/midiparser.h index c935969e72..a4dbf174e1 100644 --- a/audio/midiparser.h +++ b/audio/midiparser.h @@ -49,33 +49,33 @@ class MidiDriver_BASE; * each Tracker location. */ struct Tracker { - byte * _play_pos; ///< A pointer to the next event to be parsed - uint32 _play_time; ///< Current time in microseconds; may be in between event times - uint32 _play_tick; ///< Current MIDI tick; may be in between event ticks - uint32 _last_event_time; ///< The time, in microseconds, of the last event that was parsed - uint32 _last_event_tick; ///< The tick at which the last parsed event occurs - byte _running_status; ///< Cached MIDI command, for MIDI streams that rely on implied event codes + byte * _playPos; ///< A pointer to the next event to be parsed + uint32 _playTime; ///< Current time in microseconds; may be in between event times + uint32 _playTick; ///< Current MIDI tick; may be in between event ticks + uint32 _lastEventTime; ///< The time, in microseconds, of the last event that was parsed + uint32 _lastEventTick; ///< The tick at which the last parsed event occurs + byte _runningStatus; ///< Cached MIDI command, for MIDI streams that rely on implied event codes Tracker() { clear(); } /// Copy constructor for each duplication of Tracker information. Tracker(const Tracker ©) : - _play_pos(copy._play_pos), - _play_time(copy._play_time), - _play_tick(copy._play_tick), - _last_event_time(copy._last_event_time), - _last_event_tick(copy._last_event_tick), - _running_status(copy._running_status) + _playPos(copy._playPos), + _playTime(copy._playTime), + _playTick(copy._playTick), + _lastEventTime(copy._lastEventTime), + _lastEventTick(copy._lastEventTick), + _runningStatus(copy._runningStatus) { } /// Clears all data; used by the constructor for initialization. void clear() { - _play_pos = 0; - _play_time = 0; - _play_tick = 0; - _last_event_time = 0; - _last_event_tick = 0; - _running_status = 0; + _playPos = 0; + _playTime = 0; + _playTick = 0; + _lastEventTime = 0; + _lastEventTick = 0; + _runningStatus = 0; } }; @@ -119,8 +119,8 @@ struct EventInfo { struct NoteTimer { byte channel; ///< The MIDI channel on which the note was played byte note; ///< The note number for the active note - uint32 time_left; ///< The time, in microseconds, remaining before the note should be turned off - NoteTimer() : channel(0), note(0), time_left(0) {} + uint32 timeLeft; ///< The time, in microseconds, remaining before the note should be turned off + NoteTimer() : channel(0), note(0), timeLeft(0) {} }; @@ -264,29 +264,29 @@ struct NoteTimer { */ class MidiParser { protected: - uint16 _active_notes[128]; ///< Each uint16 is a bit mask for channels that have that note on. - NoteTimer _hanging_notes[32]; ///< Maintains expiration info for up to 32 notes. + uint16 _activeNotes[128]; ///< Each uint16 is a bit mask for channels that have that note on. + NoteTimer _hangingNotes[32]; ///< Maintains expiration info for up to 32 notes. ///< Used for "Smart Jump" and MIDI formats that do not include explicit Note Off events. - byte _hanging_notes_count; ///< Count of hanging notes, used to optimize expiration. + byte _hangingNotesCount; ///< Count of hanging notes, used to optimize expiration. MidiDriver_BASE *_driver; ///< The device to which all events will be transmitted. - uint32 _timer_rate; ///< The time in microseconds between onTimer() calls. Obtained from the MidiDriver. + uint32 _timerRate; ///< The time in microseconds between onTimer() calls. Obtained from the MidiDriver. uint32 _ppqn; ///< Pulses Per Quarter Note. (We refer to "pulses" as "ticks".) uint32 _tempo; ///< Microseconds per quarter note. - uint32 _psec_per_tick; ///< Microseconds per tick (_tempo / _ppqn). + uint32 _psecPerTick; ///< Microseconds per tick (_tempo / _ppqn). bool _autoLoop; ///< For lightweight clients that don't provide their own flow control. bool _smartJump; ///< Support smart expiration of hanging notes when jumping bool _centerPitchWheelOnUnload; ///< Center the pitch wheels when unloading a song bool _sendSustainOffOnNotesOff; ///< Send a sustain off on a notes off event, stopping hanging notes byte *_tracks[120]; ///< Multi-track MIDI formats are supported, up to 120 tracks. - byte _num_tracks; ///< Count of total tracks for multi-track MIDI formats. 1 for single-track formats. - byte _active_track; ///< Keeps track of the currently active track, in multi-track formats. + byte _numTracks; ///< Count of total tracks for multi-track MIDI formats. 1 for single-track formats. + byte _activeTrack; ///< Keeps track of the currently active track, in multi-track formats. Tracker _position; ///< The current time/position in the active track. - EventInfo _next_event; ///< The next event to transmit. Events are preparsed + EventInfo _nextEvent; ///< The next event to transmit. Events are preparsed ///< so each event is parsed only once; this permits ///< simulated events in certain formats. - bool _abort_parse; ///< If a jump or other operation interrupts parsing, flag to abort. + bool _abortParse; ///< If a jump or other operation interrupts parsing, flag to abort. protected: static uint32 readVLQ(byte * &data); @@ -295,7 +295,7 @@ protected: virtual void parseNextEvent(EventInfo &info) = 0; void activeNote(byte channel, byte note, bool active); - void hangingNote(byte channel, byte note, uint32 ticks_left, bool recycle = true); + void hangingNote(byte channel, byte note, uint32 ticksLeft, bool recycle = true); void hangAllActiveNotes(); virtual void sendToDriver(uint32 b); @@ -377,18 +377,18 @@ public: virtual void property(int prop, int value); void setMidiDriver(MidiDriver_BASE *driver) { _driver = driver; } - void setTimerRate(uint32 rate) { _timer_rate = rate; } + void setTimerRate(uint32 rate) { _timerRate = rate; } void setTempo(uint32 tempo); void onTimer(); - bool isPlaying() const { return (_position._play_pos != 0); } + bool isPlaying() const { return (_position._playPos != 0); } void stopPlaying(); bool setTrack(int track); bool jumpToTick(uint32 tick, bool fireEvents = false, bool stopNotes = true, bool dontSendNoteOn = false); uint32 getPPQN() { return _ppqn; } - virtual uint32 getTick() { return _position._play_tick; } + virtual uint32 getTick() { return _position._playTick; } static void defaultXMidiCallback(byte eventData, void *refCon); diff --git a/audio/midiparser_smf.cpp b/audio/midiparser_smf.cpp index e883471b54..4b0913cbfe 100644 --- a/audio/midiparser_smf.cpp +++ b/audio/midiparser_smf.cpp @@ -45,8 +45,8 @@ public: }; -static const byte command_lengths[8] = { 3, 3, 3, 3, 2, 2, 3, 0 }; -static const byte special_lengths[16] = { 0, 2, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }; +static const byte commandLengths[8] = { 3, 3, 3, 3, 2, 2, 3, 0 }; +static const byte specialLengths[16] = { 0, 2, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }; MidiParser_SMF::~MidiParser_SMF() { free(_buffer); @@ -62,8 +62,8 @@ void MidiParser_SMF::property(int prop, int value) { } void MidiParser_SMF::parseNextEvent(EventInfo &info) { - info.start = _position._play_pos; - info.delta = readVLQ(_position._play_pos); + info.start = _position._playPos; + info.delta = readVLQ(_position._playPos); // Process the next info. If mpMalformedPitchBends // was set, we must skip over any pitch bend events @@ -71,19 +71,19 @@ void MidiParser_SMF::parseNextEvent(EventInfo &info) { // real pitch bend events, they're just two-byte // prefixes before the real info. do { - if ((_position._play_pos[0] & 0xF0) >= 0x80) - info.event = *(_position._play_pos++); + if ((_position._playPos[0] & 0xF0) >= 0x80) + info.event = *(_position._playPos++); else - info.event = _position._running_status; - } while (_malformedPitchBends && (info.event & 0xF0) == 0xE0 && _position._play_pos++); + info.event = _position._runningStatus; + } while (_malformedPitchBends && (info.event & 0xF0) == 0xE0 && _position._playPos++); if (info.event < 0x80) return; - _position._running_status = info.event; + _position._runningStatus = info.event; switch (info.command()) { case 0x9: // Note On - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = *(_position._play_pos++); + info.basic.param1 = *(_position._playPos++); + info.basic.param2 = *(_position._playPos++); if (info.basic.param2 == 0) info.event = info.channel() | 0x80; info.length = 0; @@ -91,7 +91,7 @@ void MidiParser_SMF::parseNextEvent(EventInfo &info) { case 0xC: case 0xD: - info.basic.param1 = *(_position._play_pos++); + info.basic.param1 = *(_position._playPos++); info.basic.param2 = 0; break; @@ -99,20 +99,20 @@ void MidiParser_SMF::parseNextEvent(EventInfo &info) { case 0xA: case 0xB: case 0xE: - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = *(_position._play_pos++); + info.basic.param1 = *(_position._playPos++); + info.basic.param2 = *(_position._playPos++); info.length = 0; break; case 0xF: // System Common, Meta or SysEx event switch (info.event & 0x0F) { case 0x2: // Song Position Pointer - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = *(_position._play_pos++); + info.basic.param1 = *(_position._playPos++); + info.basic.param2 = *(_position._playPos++); break; case 0x3: // Song Select - info.basic.param1 = *(_position._play_pos++); + info.basic.param1 = *(_position._playPos++); info.basic.param2 = 0; break; @@ -126,16 +126,16 @@ void MidiParser_SMF::parseNextEvent(EventInfo &info) { break; case 0x0: // SysEx - info.length = readVLQ(_position._play_pos); - info.ext.data = _position._play_pos; - _position._play_pos += info.length; + info.length = readVLQ(_position._playPos); + info.ext.data = _position._playPos; + _position._playPos += info.length; break; case 0xF: // META event - info.ext.type = *(_position._play_pos++); - info.length = readVLQ(_position._play_pos); - info.ext.data = _position._play_pos; - _position._play_pos += info.length; + info.ext.type = *(_position._playPos++); + info.length = readVLQ(_position._playPos); + info.ext.data = _position._playPos; + _position._playPos += info.length; break; default: @@ -146,8 +146,8 @@ void MidiParser_SMF::parseNextEvent(EventInfo &info) { bool MidiParser_SMF::loadMusic(byte *data, uint32 size) { uint32 len; - byte midi_type; - uint32 total_size; + byte midiType; + uint32 totalSize; bool isGMF; unloadMusic(); @@ -171,10 +171,10 @@ bool MidiParser_SMF::loadMusic(byte *data, uint32 size) { // Verify that this MIDI either is a Type 2 // or has only 1 track. We do not support // multitrack Type 1 files. - _num_tracks = pos[2] << 8 | pos[3]; - midi_type = pos[1]; - if (midi_type > 2 /*|| (midi_type < 2 && _num_tracks > 1)*/) { - warning("No support for a Type %d MIDI with %d tracks", (int)midi_type, (int)_num_tracks); + _numTracks = pos[2] << 8 | pos[3]; + midiType = pos[1]; + if (midiType > 2 /*|| (midiType < 2 && _numTracks > 1)*/) { + warning("No support for a Type %d MIDI with %d tracks", (int)midiType, (int)_numTracks); return false; } _ppqn = pos[4] << 8 | pos[5]; @@ -183,8 +183,8 @@ bool MidiParser_SMF::loadMusic(byte *data, uint32 size) { // Older GMD/MUS file with no header info. // Assume 1 track, 192 PPQN, and no MTrk headers. isGMF = true; - midi_type = 0; - _num_tracks = 1; + midiType = 0; + _numTracks = 1; _ppqn = 192; pos += 7; // 'GMD\x1' + 3 bytes of useless (translate: unknown) information } else { @@ -193,14 +193,14 @@ bool MidiParser_SMF::loadMusic(byte *data, uint32 size) { } // Now we identify and store the location for each track. - if (_num_tracks > ARRAYSIZE(_tracks)) { - warning("Can only handle %d tracks but was handed %d", (int)ARRAYSIZE(_tracks), (int)_num_tracks); + if (_numTracks > ARRAYSIZE(_tracks)) { + warning("Can only handle %d tracks but was handed %d", (int)ARRAYSIZE(_tracks), (int)_numTracks); return false; } - total_size = 0; - int tracks_read = 0; - while (tracks_read < _num_tracks) { + totalSize = 0; + int tracksRead = 0; + while (tracksRead < _numTracks) { if (memcmp(pos, "MTrk", 4) && !isGMF) { warning("Position: %p ('%c')", pos, *pos); warning("Hit invalid block '%c%c%c%c' while scanning for track locations", pos[0], pos[1], pos[2], pos[3]); @@ -208,11 +208,11 @@ bool MidiParser_SMF::loadMusic(byte *data, uint32 size) { } // If needed, skip the MTrk and length bytes - _tracks[tracks_read] = pos + (isGMF ? 0 : 8); + _tracks[tracksRead] = pos + (isGMF ? 0 : 8); if (!isGMF) { pos += 4; len = read4high(pos); - total_size += len; + totalSize += len; pos += len; } else { // An SMF End of Track meta event must be placed @@ -222,7 +222,7 @@ bool MidiParser_SMF::loadMusic(byte *data, uint32 size) { data[size++] = 0x00; data[size++] = 0x00; } - ++tracks_read; + ++tracksRead; } // If this is a Type 1 MIDI, we need to now compress @@ -230,13 +230,13 @@ bool MidiParser_SMF::loadMusic(byte *data, uint32 size) { free(_buffer); _buffer = 0; - if (midi_type == 1) { + if (midiType == 1) { // FIXME: Doubled the buffer size to prevent crashes with the // Inherit the Earth MIDIs. Jamieson630 said something about a // better fix, but this will have to do in the meantime. _buffer = (byte *)malloc(size * 2); compressToType0(); - _num_tracks = 1; + _numTracks = 1; _tracks[0] = _buffer; } @@ -253,48 +253,48 @@ void MidiParser_SMF::compressToType0() { // We assume that _buffer has been allocated // to sufficient size for this operation. - // using 0xFF since it could write track_pos[0 to _num_tracks] here + // using 0xFF since it could write trackPos[0 to _numTracks] here // this would cause some illegal writes and could lead to segfaults // (it crashed for some midis for me, they're not used in any game // scummvm supports though). *Maybe* handle this in another way, // it's at the moment only to be sure, that nothing goes wrong. - byte *track_pos[0xFF]; - byte running_status[0xFF]; - uint32 track_timer[0xFF]; + byte *trackPos[0xFF]; + byte runningStatus[0xFF]; + uint32 trackTimer[0xFF]; uint32 delta; int i; - for (i = 0; i < _num_tracks; ++i) { - running_status[i] = 0; - track_pos[i] = _tracks[i]; - track_timer[i] = readVLQ(track_pos[i]); - running_status[i] = 0; + for (i = 0; i < _numTracks; ++i) { + runningStatus[i] = 0; + trackPos[i] = _tracks[i]; + trackTimer[i] = readVLQ(trackPos[i]); + runningStatus[i] = 0; } - int best_i; + int bestTrack; uint32 length; byte *output = _buffer; byte *pos, *pos2; byte event; - uint32 copy_bytes; + uint32 copyBytes; bool write; - byte active_tracks = (byte)_num_tracks; + byte activeTracks = (byte)_numTracks; - while (active_tracks) { + while (activeTracks) { write = true; - best_i = 255; - for (i = 0; i < _num_tracks; ++i) { - if (track_pos[i] && (best_i == 255 || track_timer[i] < track_timer[best_i])) - best_i = i; + bestTrack = 255; + for (i = 0; i < _numTracks; ++i) { + if (trackPos[i] && (bestTrack == 255 || trackTimer[i] < trackTimer[bestTrack])) + bestTrack = i; } - if (best_i == 255) { + if (bestTrack == 255) { warning("Premature end of tracks"); break; } // Initial VLQ delta computation delta = 0; - length = track_timer[best_i]; + length = trackTimer[bestTrack]; for (i = 0; length; ++i) { delta = (delta << 8) | (length & 0x7F) | (i ? 0x80 : 0); length >>= 7; @@ -302,55 +302,55 @@ void MidiParser_SMF::compressToType0() { // Process MIDI event. bool implicitEvent = false; - copy_bytes = 0; - pos = track_pos[best_i]; + copyBytes = 0; + pos = trackPos[bestTrack]; do { event = *(pos++); if (event < 0x80) { - event = running_status[best_i]; + event = runningStatus[bestTrack]; implicitEvent = true; } } while (_malformedPitchBends && (event & 0xF0) == 0xE0 && pos++); - running_status[best_i] = event; + runningStatus[bestTrack] = event; - if (command_lengths[(event >> 4) - 8] > 0) { - copy_bytes = command_lengths[(event >> 4) - 8]; - } else if (special_lengths[(event & 0x0F)] > 0) { - copy_bytes = special_lengths[(event & 0x0F)]; + if (commandLengths[(event >> 4) - 8] > 0) { + copyBytes = commandLengths[(event >> 4) - 8]; + } else if (specialLengths[(event & 0x0F)] > 0) { + copyBytes = specialLengths[(event & 0x0F)]; } else if (event == 0xF0) { // SysEx pos2 = pos; length = readVLQ(pos); - copy_bytes = 1 + (pos - pos2) + length; + copyBytes = 1 + (pos - pos2) + length; } else if (event == 0xFF) { // META event = *(pos++); - if (event == 0x2F && active_tracks > 1) { - track_pos[best_i] = 0; + if (event == 0x2F && activeTracks > 1) { + trackPos[bestTrack] = 0; write = false; } else { pos2 = pos; length = readVLQ(pos); - copy_bytes = 2 + (pos - pos2) + length; + copyBytes = 2 + (pos - pos2) + length; } if (event == 0x2F) - --active_tracks; + --activeTracks; } else { warning("Bad MIDI command %02X", (int)event); - track_pos[best_i] = 0; + trackPos[bestTrack] = 0; } // Update all tracks' deltas if (write) { - for (i = 0; i < _num_tracks; ++i) { - if (track_pos[i] && i != best_i) - track_timer[i] -= track_timer[best_i]; + for (i = 0; i < _numTracks; ++i) { + if (trackPos[i] && i != bestTrack) + trackTimer[i] -= trackTimer[bestTrack]; } } - if (track_pos[best_i]) { + if (trackPos[bestTrack]) { if (write) { - track_timer[best_i] = 0; + trackTimer[bestTrack] = 0; // Write VLQ delta while (delta & 0x80) { @@ -361,17 +361,17 @@ void MidiParser_SMF::compressToType0() { // Write MIDI data if (!implicitEvent) - ++track_pos[best_i]; - --copy_bytes; - *output++ = running_status[best_i]; - memcpy(output, track_pos[best_i], copy_bytes); - output += copy_bytes; + ++trackPos[bestTrack]; + --copyBytes; + *output++ = runningStatus[bestTrack]; + memcpy(output, trackPos[bestTrack], copyBytes); + output += copyBytes; } // Fetch new VLQ delta for winning track - track_pos[best_i] += copy_bytes; - if (active_tracks) - track_timer[best_i] += readVLQ(track_pos[best_i]); + trackPos[bestTrack] += copyBytes; + if (activeTracks) + trackTimer[bestTrack] += readVLQ(trackPos[bestTrack]); } } diff --git a/audio/midiparser_xmidi.cpp b/audio/midiparser_xmidi.cpp index 85491faaf8..11690b0214 100644 --- a/audio/midiparser_xmidi.cpp +++ b/audio/midiparser_xmidi.cpp @@ -32,9 +32,6 @@ */ class MidiParser_XMIDI : public MidiParser { protected: - NoteTimer _notes_cache[32]; - uint32 _inserted_delta; // Track simulated deltas for note-off events - struct Loop { byte *pos; byte repeat; @@ -48,11 +45,10 @@ protected: protected: uint32 readVLQ2(byte * &data); - void resetTracking(); void parseNextEvent(EventInfo &info); public: - MidiParser_XMIDI(XMidiCallbackProc proc, void *data) : _inserted_delta(0), _callbackProc(proc), _callbackData(data) {} + MidiParser_XMIDI(XMidiCallbackProc proc, void *data) : _callbackProc(proc), _callbackData(data) {} ~MidiParser_XMIDI() { } bool loadMusic(byte *data, uint32 size); @@ -69,17 +65,16 @@ uint32 MidiParser_XMIDI::readVLQ2(byte * &pos) { } void MidiParser_XMIDI::parseNextEvent(EventInfo &info) { - info.start = _position._play_pos; - info.delta = readVLQ2(_position._play_pos) - _inserted_delta; + info.start = _position._playPos; + info.delta = readVLQ2(_position._playPos); // Process the next event. - _inserted_delta = 0; - info.event = *(_position._play_pos++); + info.event = *(_position._playPos++); switch (info.event >> 4) { case 0x9: // Note On - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = *(_position._play_pos++); - info.length = readVLQ(_position._play_pos); + info.basic.param1 = *(_position._playPos++); + info.basic.param2 = *(_position._playPos++); + info.length = readVLQ(_position._playPos); if (info.basic.param2 == 0) { info.event = info.channel() | 0x80; info.length = 0; @@ -88,20 +83,20 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) { case 0xC: case 0xD: - info.basic.param1 = *(_position._play_pos++); + info.basic.param1 = *(_position._playPos++); info.basic.param2 = 0; break; case 0x8: case 0xA: case 0xE: - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = *(_position._play_pos++); + info.basic.param1 = *(_position._playPos++); + info.basic.param2 = *(_position._playPos++); break; case 0xB: - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = *(_position._play_pos++); + info.basic.param1 = *(_position._playPos++); + info.basic.param2 = *(_position._playPos++); // This isn't a full XMIDI implementation, but it should // hopefully be "good enough" for most things. @@ -109,7 +104,7 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) { switch (info.basic.param1) { // Simplified XMIDI looping. case 0x74: { // XMIDI_CONTROLLER_FOR_LOOP - byte *pos = _position._play_pos; + byte *pos = _position._playPos; if (_loopCount < ARRAYSIZE(_loop) - 1) _loopCount++; else @@ -131,9 +126,9 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) { if (--_loop[_loopCount].repeat == 0) _loopCount--; else - _position._play_pos = _loop[_loopCount].pos; + _position._playPos = _loop[_loopCount].pos; } else { - _position._play_pos = _loop[_loopCount].pos; + _position._playPos = _loop[_loopCount].pos; } } } @@ -169,12 +164,12 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) { case 0xF: // Meta or SysEx event switch (info.event & 0x0F) { case 0x2: // Song Position Pointer - info.basic.param1 = *(_position._play_pos++); - info.basic.param2 = *(_position._play_pos++); + info.basic.param1 = *(_position._playPos++); + info.basic.param2 = *(_position._playPos++); break; case 0x3: // Song Select - info.basic.param1 = *(_position._play_pos++); + info.basic.param1 = *(_position._playPos++); info.basic.param2 = 0; break; @@ -188,16 +183,16 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) { break; case 0x0: // SysEx - info.length = readVLQ(_position._play_pos); - info.ext.data = _position._play_pos; - _position._play_pos += info.length; + info.length = readVLQ(_position._playPos); + info.ext.data = _position._playPos; + _position._playPos += info.length; break; case 0xF: // META event - info.ext.type = *(_position._play_pos++); - info.length = readVLQ(_position._play_pos); - info.ext.data = _position._play_pos; - _position._play_pos += info.length; + info.ext.type = *(_position._playPos++); + info.length = readVLQ(_position._playPos); + info.ext.data = _position._playPos; + _position._playPos += info.length; if (info.ext.type == 0x51 && info.length == 3) { // Tempo event. We want to make these constant 500,000. info.ext.data[0] = 0x07; @@ -216,7 +211,7 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) { uint32 i = 0; byte *start; uint32 len; - uint32 chunk_len; + uint32 chunkLen; char buf[32]; _loopCount = -1; @@ -235,7 +230,7 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) { if (!memcmp(pos, "XMID", 4)) { warning("XMIDI doesn't have XDIR"); pos += 4; - _num_tracks = 1; + _numTracks = 1; } else if (memcmp(pos, "XDIR", 4)) { // Not an XMIDI that we recognize warning("Expected 'XDIR' but found '%c%c%c%c'", pos[0], pos[1], pos[2], pos[3]); @@ -243,7 +238,7 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) { } else { // Seems Valid pos += 4; - _num_tracks = 0; + _numTracks = 0; for (i = 4; i < len; i++) { // Read 4 bytes of type @@ -251,34 +246,34 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) { pos += 4; // Read length of chunk - chunk_len = read4high(pos); + chunkLen = read4high(pos); // Add eight bytes i += 8; if (memcmp(buf, "INFO", 4) == 0) { // Must be at least 2 bytes long - if (chunk_len < 2) { - warning("Invalid chunk length %d for 'INFO' block", (int)chunk_len); + if (chunkLen < 2) { + warning("Invalid chunk length %d for 'INFO' block", (int)chunkLen); return false; } - _num_tracks = (byte)read2low(pos); + _numTracks = (byte)read2low(pos); - if (chunk_len > 2) { - warning("Chunk length %d is greater than 2", (int)chunk_len); - //pos += chunk_len - 2; + if (chunkLen > 2) { + warning("Chunk length %d is greater than 2", (int)chunkLen); + //pos += chunkLen - 2; } break; } // Must align - pos += (chunk_len + 1) & ~1; - i += (chunk_len + 1) & ~1; + pos += (chunkLen + 1) & ~1; + i += (chunkLen + 1) & ~1; } // Didn't get to fill the header - if (_num_tracks == 0) { + if (_numTracks == 0) { warning("Didn't find a valid track count"); return false; } @@ -308,13 +303,13 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) { // Ok it's an XMIDI. // We're going to identify and store the location for each track. - if (_num_tracks > ARRAYSIZE(_tracks)) { - warning("Can only handle %d tracks but was handed %d", (int)ARRAYSIZE(_tracks), (int)_num_tracks); + if (_numTracks > ARRAYSIZE(_tracks)) { + warning("Can only handle %d tracks but was handed %d", (int)ARRAYSIZE(_tracks), (int)_numTracks); return false; } - int tracks_read = 0; - while (tracks_read < _num_tracks) { + int tracksRead = 0; + while (tracksRead < _numTracks) { if (!memcmp(pos, "FORM", 4)) { // Skip this plus the 4 bytes after it. pos += 8; @@ -330,11 +325,11 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) { pos += (len + 1) & ~1; } else if (!memcmp(pos, "EVNT", 4)) { // Ahh! What we're looking for at last. - _tracks[tracks_read] = pos + 8; // Skip the EVNT and length bytes + _tracks[tracksRead] = pos + 8; // Skip the EVNT and length bytes pos += 4; len = read4high(pos); pos += (len + 1) & ~1; - ++tracks_read; + ++tracksRead; } else { warning("Hit invalid block '%c%c%c%c' while scanning for track locations", pos[0], pos[1], pos[2], pos[3]); return false; @@ -349,7 +344,6 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) { _ppqn = 60; resetTracking(); setTempo(500000); - _inserted_delta = 0; setTrack(0); return true; } @@ -357,11 +351,6 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) { return false; } -void MidiParser_XMIDI::resetTracking() { - MidiParser::resetTracking(); - _inserted_delta = 0; -} - void MidiParser::defaultXMidiCallback(byte eventData, void *data) { warning("MidiParser: defaultXMidiCallback(%d)", eventData); } diff --git a/audio/mixer.h b/audio/mixer.h index e38e052bef..a0060f2e1a 100644 --- a/audio/mixer.h +++ b/audio/mixer.h @@ -97,7 +97,7 @@ public: * @param stream the actual AudioStream to be played * @param id a unique id assigned to this stream * @param volume the volume with which to play the sound, ranging from 0 to 255 - * @param balance the balance with which to play the sound, ranging from -128 to 127 + * @param balance the balance with which to play the sound, ranging from -127 to 127 (full left to full right), 0 is balanced, -128 is invalid * @param autofreeStream a flag indicating whether the stream should be * freed after playback finished * @param permanent a flag indicating whether a plain stopAll call should diff --git a/audio/mods/maxtrax.h b/audio/mods/maxtrax.h index c45a21a255..ffb176c241 100644 --- a/audio/mods/maxtrax.h +++ b/audio/mods/maxtrax.h @@ -20,11 +20,8 @@ * */ -// see if all engines using this class are DISABLED -#if !defined(ENABLE_KYRA) - -// normal Header Guard -#elif !defined(AUDIO_MODS_MAXTRAX_H) +// Only compiled if Kyra is built-in or we're building for dynamic modules +#if !defined(AUDIO_MODS_MAXTRAX_H) && (defined(ENABLE_KYRA) || defined(DYNAMIC_MODULES)) #define AUDIO_MODS_MAXTRAX_H // #define MAXTRAX_HAS_MODULATION diff --git a/audio/mods/protracker.cpp b/audio/mods/protracker.cpp index 084b0edf9a..1e18d5adf8 100644 --- a/audio/mods/protracker.cpp +++ b/audio/mods/protracker.cpp @@ -61,6 +61,7 @@ private: struct { byte sample; + byte lastSample; uint16 period; Offset offset; @@ -184,6 +185,7 @@ void ProtrackerStream::updateRow() { _track[track].vibratoPos = 0; } _track[track].sample = note.sample; + _track[track].lastSample = note.sample; _track[track].finetune = _module.sample[note.sample - 1].finetune; _track[track].vol = _module.sample[note.sample - 1].vol; } @@ -194,7 +196,9 @@ void ProtrackerStream::updateRow() { _track[track].period = _module.noteToPeriod(note.note, _track[track].finetune); else _track[track].period = note.period; + _track[track].offset = Offset(0); + _track[track].sample = _track[track].lastSample; } } diff --git a/audio/mods/protracker.h b/audio/mods/protracker.h index d52322f07e..5f47c4453b 100644 --- a/audio/mods/protracker.h +++ b/audio/mods/protracker.h @@ -25,6 +25,7 @@ * Sound decoder used in engines: * - agos * - parallaction + * - gob */ #ifndef AUDIO_MODS_PROTRACKER_H diff --git a/audio/mods/tfmx.h b/audio/mods/tfmx.h index 4174fbfb27..ebe1172278 100644 --- a/audio/mods/tfmx.h +++ b/audio/mods/tfmx.h @@ -20,11 +20,8 @@ * */ -// see if all engines using this class are DISABLED -#if !defined(ENABLE_SCUMM) - -// normal Header Guard -#elif !defined(AUDIO_MODS_TFMX_H) +// Only compiled if SCUMM is built-in or we're building for dynamic modules +#if !defined(AUDIO_MODS_TFMX_H) && (defined(ENABLE_SCUMM) || defined(DYNAMIC_MODULES)) #define AUDIO_MODS_TFMX_H #include "audio/mods/paula.h" diff --git a/audio/softsynth/mt32/Part.cpp b/audio/softsynth/mt32/Part.cpp index c9bd86b54a..75912f38a8 100644 --- a/audio/softsynth/mt32/Part.cpp +++ b/audio/softsynth/mt32/Part.cpp @@ -411,7 +411,7 @@ void RhythmPart::noteOn(unsigned int midiKey, unsigned int velocity) { // According to info from Mok, keyShift does not appear to affect anything on rhythm part on LAPC-I, but may do on MT-32 - needs investigation synth->printDebug(" Patch: (timbreGroup %u), (timbreNum %u), (keyShift %u), fineTune %u, benderRange %u, assignMode %u, (reverbSwitch %u)", patchTemp->patch.timbreGroup, patchTemp->patch.timbreNum, patchTemp->patch.keyShift, patchTemp->patch.fineTune, patchTemp->patch.benderRange, patchTemp->patch.assignMode, patchTemp->patch.reverbSwitch); synth->printDebug(" PatchTemp: outputLevel %u, (panpot %u)", patchTemp->outputLevel, patchTemp->panpot); - synth->printDebug(" RhythmTemp: timbre %u, outputLevel %u, panpot %u, reverbSwitch %u", rhythmTemp[drumNum].timbre, rhythmTemp[drumNum].outputLevel, rhythmTemp[drumNum].panpot, rhythmTemp[drumNum].reverbSwitch); + synth->printDebug(" RhythmTemp: timbre %u, outputLevel %u, panpot %u, reverbSwitch %u", rhythmTemp[drumNum].timbre, rhythmTemp[drumNum].outputLevel, rhythmTemp[drumNum].panpot, rhythmTemp[drumNum].reverbSwitch); #endif #endif playPoly(drumCache[drumNum], &rhythmTemp[drumNum], midiKey, key, velocity); diff --git a/audio/softsynth/mt32/Partial.h b/audio/softsynth/mt32/Partial.h index 95218c858c..5e250769ec 100644 --- a/audio/softsynth/mt32/Partial.h +++ b/audio/softsynth/mt32/Partial.h @@ -37,7 +37,7 @@ private: const int debugPartialNum; // Only used for debugging // Number of the sample currently being rendered by generateSamples(), or 0 if no run is in progress // This is only kept available for debugging purposes. - unsigned long sampleNum; + unsigned long sampleNum; int ownerPart; // -1 if unassigned int mixType; diff --git a/audio/softsynth/mt32/PartialManager.cpp b/audio/softsynth/mt32/PartialManager.cpp index 42a3eaa179..0a6be826d6 100644 --- a/audio/softsynth/mt32/PartialManager.cpp +++ b/audio/softsynth/mt32/PartialManager.cpp @@ -148,7 +148,7 @@ bool PartialManager::abortFirstPolyPreferHeldWhereReserveExceeded(int minPart) { bool PartialManager::freePartials(unsigned int needed, int partNum) { // CONFIRMED: Barring bugs, this matches the real LAPC-I according to information from Mok. - // BUG: There's a bug in the LAPC-I implementation: + // BUG: There's a bug in the LAPC-I implementation: // When allocating for rhythm part, or when allocating for a part that is using fewer partials than it has reserved, // held and playing polys on the rhythm part can potentially be aborted before releasing polys on the rhythm part. // This bug isn't present on MT-32. diff --git a/audio/softsynth/mt32/Synth.cpp b/audio/softsynth/mt32/Synth.cpp index 0861053b5c..7a1b5c2275 100644 --- a/audio/softsynth/mt32/Synth.cpp +++ b/audio/softsynth/mt32/Synth.cpp @@ -1156,7 +1156,7 @@ void Synth::writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u le DT(partial[x].tva.envLevel[0]); \ DT(partial[x].tva.envLevel[1]); \ DT(partial[x].tva.envLevel[2]); \ - DT(partial[x].tva.envLevel[3]); + DT(partial[x].tva.envLevel[3]); DTP(0); DTP(1); diff --git a/audio/softsynth/mt32/TVA.cpp b/audio/softsynth/mt32/TVA.cpp index c3be6db591..f3e3f7bbc7 100644 --- a/audio/softsynth/mt32/TVA.cpp +++ b/audio/softsynth/mt32/TVA.cpp @@ -274,7 +274,7 @@ void TVA::nextPhase() { } int newTarget; - int newIncrement; + int newIncrement = 0; int envPointIndex = phase; if (!allLevelsZeroFromNowOn) { diff --git a/audio/softsynth/mt32/TVF.cpp b/audio/softsynth/mt32/TVF.cpp index 58f72e5a9b..80b592ea67 100644 --- a/audio/softsynth/mt32/TVF.cpp +++ b/audio/softsynth/mt32/TVF.cpp @@ -64,11 +64,11 @@ static int calcBaseCutoff(const TimbreParam::PartialParam *partialParam, Bit32u int biasPoint = partialParam->tvf.biasPoint; if ((biasPoint & 0x40) == 0) { // biasPoint range here: 0 to 63 - int bias = biasPoint + 33 - key; // bias range here: -75 to 84 + int bias = biasPoint + 33 - key; // bias range here: -75 to 84 if (bias > 0) { bias = -bias; // bias range here: -1 to -84 baseCutoff += bias * biasLevelToBiasMult[partialParam->tvf.biasLevel]; // Calculation range: -7140 to 7140 - // baseCutoff range now: -10164 to 10164 + // baseCutoff range now: -10164 to 10164 } } else { // biasPoint range here: 64 to 127 diff --git a/audio/softsynth/mt32/freeverb.cpp b/audio/softsynth/mt32/freeverb.cpp index de8f2632cb..181b878596 100644 --- a/audio/softsynth/mt32/freeverb.cpp +++ b/audio/softsynth/mt32/freeverb.cpp @@ -202,7 +202,7 @@ void revmodel::process(const float *inputL, const float *inputR, float *outputL, // Calculate output REPLACING anything already there *outputL = outL*wet1 + outR*wet2; *outputR = outR*wet1 + outL*wet2; - + inputL++; inputR++; outputL++; |