diff options
author | Max Horn | 2011-02-09 01:09:01 +0000 |
---|---|---|
committer | Max Horn | 2011-02-09 01:09:01 +0000 |
commit | 42ab839dd6c8a1570b232101eb97f4e54de57935 (patch) | |
tree | 3b763d8913a87482b793e0348c88b9a5f40eecc9 /sound/decoders | |
parent | 386203a3d6ce1abf457c9110d695408ec5f01b85 (diff) | |
download | scummvm-rg350-42ab839dd6c8a1570b232101eb97f4e54de57935.tar.gz scummvm-rg350-42ab839dd6c8a1570b232101eb97f4e54de57935.tar.bz2 scummvm-rg350-42ab839dd6c8a1570b232101eb97f4e54de57935.zip |
AUDIO: Rename sound/ dir to audio/
svn-id: r55850
Diffstat (limited to 'sound/decoders')
-rw-r--r-- | sound/decoders/adpcm.cpp | 851 | ||||
-rw-r--r-- | sound/decoders/adpcm.h | 90 | ||||
-rw-r--r-- | sound/decoders/aiff.cpp | 186 | ||||
-rw-r--r-- | sound/decoders/aiff.h | 71 | ||||
-rw-r--r-- | sound/decoders/flac.cpp | 745 | ||||
-rw-r--r-- | sound/decoders/flac.h | 75 | ||||
-rw-r--r-- | sound/decoders/iff_sound.cpp | 130 | ||||
-rw-r--r-- | sound/decoders/iff_sound.h | 47 | ||||
-rw-r--r-- | sound/decoders/mac_snd.cpp | 116 | ||||
-rw-r--r-- | sound/decoders/mac_snd.h | 58 | ||||
-rw-r--r-- | sound/decoders/mp3.cpp | 375 | ||||
-rw-r--r-- | sound/decoders/mp3.h | 76 | ||||
-rw-r--r-- | sound/decoders/raw.cpp | 356 | ||||
-rw-r--r-- | sound/decoders/raw.h | 153 | ||||
-rw-r--r-- | sound/decoders/vag.cpp | 150 | ||||
-rw-r--r-- | sound/decoders/vag.h | 60 | ||||
-rw-r--r-- | sound/decoders/voc.cpp | 403 | ||||
-rw-r--r-- | sound/decoders/voc.h | 107 | ||||
-rw-r--r-- | sound/decoders/vorbis.cpp | 262 | ||||
-rw-r--r-- | sound/decoders/vorbis.h | 75 | ||||
-rw-r--r-- | sound/decoders/wave.cpp | 194 | ||||
-rw-r--r-- | sound/decoders/wave.h | 84 |
22 files changed, 0 insertions, 4664 deletions
diff --git a/sound/decoders/adpcm.cpp b/sound/decoders/adpcm.cpp deleted file mode 100644 index 4b5e6a5b84..0000000000 --- a/sound/decoders/adpcm.cpp +++ /dev/null @@ -1,851 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/endian.h" - -#include "sound/decoders/adpcm.h" -#include "sound/audiostream.h" - - -namespace Audio { - -class ADPCMStream : public RewindableAudioStream { -protected: - Common::SeekableReadStream *_stream; - const DisposeAfterUse::Flag _disposeAfterUse; - const int32 _startpos; - const int32 _endpos; - const int _channels; - const uint32 _blockAlign; - uint32 _blockPos[2]; - const int _rate; - - struct { - // OKI/IMA - struct { - int32 last; - int32 stepIndex; - } ima_ch[2]; - } _status; - - virtual void reset(); - int16 stepAdjust(byte); - -public: - ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign); - ~ADPCMStream(); - - 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 rewind(); -}; - -// Routines to convert 12 bit linear samples to the -// Dialogic or Oki ADPCM coding format aka VOX. -// See also <http://www.comptek.ru/telephony/tnotes/tt1-13.html> -// -// IMA ADPCM support is based on -// <http://wiki.multimedia.cx/index.php?title=IMA_ADPCM> -// -// In addition, also MS IMA ADPCM is supported. See -// <http://wiki.multimedia.cx/index.php?title=Microsoft_IMA_ADPCM>. - -ADPCMStream::ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : _stream(stream), - _disposeAfterUse(disposeAfterUse), - _startpos(stream->pos()), - _endpos(_startpos + size), - _channels(channels), - _blockAlign(blockAlign), - _rate(rate) { - - reset(); -} - -ADPCMStream::~ADPCMStream() { - if (_disposeAfterUse == DisposeAfterUse::YES) - delete _stream; -} - -void ADPCMStream::reset() { - memset(&_status, 0, sizeof(_status)); - _blockPos[0] = _blockPos[1] = _blockAlign; // To make sure first header is read -} - -bool ADPCMStream::rewind() { - // TODO: Error checking. - reset(); - _stream->seek(_startpos); - return true; -} - - -#pragma mark - - - -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) {} - - virtual int readBuffer(int16 *buffer, const int numSamples); - -protected: - int16 decodeOKI(byte); -}; - -int Oki_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { - int samples; - byte data; - - assert(numSamples % 2 == 0); - - 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); - } - return samples; -} - -static const int16 okiStepSize[49] = { - 16, 17, 19, 21, 23, 25, 28, 31, - 34, 37, 41, 45, 50, 55, 60, 66, - 73, 80, 88, 97, 107, 118, 130, 143, - 157, 173, 190, 209, 230, 253, 279, 307, - 337, 371, 408, 449, 494, 544, 598, 658, - 724, 796, 876, 963, 1060, 1166, 1282, 1411, - 1552 -}; - -// Decode Linear to ADPCM -int16 Oki_ADPCMStream::decodeOKI(byte code) { - int16 diff, E, samp; - - E = (2 * (code & 0x7) + 1) * okiStepSize[_status.ima_ch[0].stepIndex] / 8; - diff = (code & 0x08) ? -E : E; - samp = _status.ima_ch[0].last + diff; - // Clip the values to +/- 2^11 (supposed to be 12 bits) - samp = CLIP<int16>(samp, -2048, 2047); - - _status.ima_ch[0].last = samp; - _status.ima_ch[0].stepIndex += stepAdjust(code); - _status.ima_ch[0].stepIndex = CLIP<int32>(_status.ima_ch[0].stepIndex, 0, ARRAYSIZE(okiStepSize) - 1); - - // * 16 effectively converts 12-bit input to 16-bit output - return samp * 16; -} - - -#pragma mark - - - -class Ima_ADPCMStream : public ADPCMStream { -protected: - int16 decodeIMA(byte code, int channel = 0); // Default to using the left channel/using one channel - -public: - Ima_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { - memset(&_status, 0, sizeof(_status)); - } - - virtual int readBuffer(int16 *buffer, const int numSamples); -}; - -int Ima_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { - int samples; - byte data; - - assert(numSamples % 2 == 0); - - 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); - } - return samples; -} - -#pragma mark - - - -class Apple_ADPCMStream : public Ima_ADPCMStream { -protected: - // Apple QuickTime IMA ADPCM - int32 _streamPos[2]; - int16 _buffer[2][2]; - uint8 _chunkPos[2]; - - void reset() { - Ima_ADPCMStream::reset(); - _chunkPos[0] = 0; - _chunkPos[1] = 0; - _streamPos[0] = 0; - _streamPos[1] = _blockAlign; - } - -public: - Apple_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { - _chunkPos[0] = 0; - _chunkPos[1] = 0; - _streamPos[0] = 0; - _streamPos[1] = _blockAlign; - } - - virtual int readBuffer(int16 *buffer, const int numSamples); - -}; - -int Apple_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { - // Need to write at least one samples per channel - assert((numSamples % _channels) == 0); - - // Current sample positions - int samples[2] = { 0, 0}; - - // Number of samples per channel - int chanSamples = numSamples / _channels; - - for (int i = 0; i < _channels; i++) { - _stream->seek(_streamPos[i]); - - while ((samples[i] < chanSamples) && - // Last byte read and a new one needed - !((_stream->eos() || (_stream->pos() >= _endpos)) && (_chunkPos[i] == 0))) { - - if (_blockPos[i] == _blockAlign) { - // 2 byte header per block - uint16 temp = _stream->readUint16BE(); - - // First 9 bits are the upper bits of the predictor - _status.ima_ch[i].last = (int16) (temp & 0xFF80); - // Lower 7 bits are the step index - _status.ima_ch[i].stepIndex = temp & 0x007F; - - // Clip the step index - _status.ima_ch[i].stepIndex = CLIP<int32>(_status.ima_ch[i].stepIndex, 0, 88); - - _blockPos[i] = 2; - } - - if (_chunkPos[i] == 0) { - // Decode data - byte data = _stream->readByte(); - _buffer[i][0] = decodeIMA(data & 0x0F, i); - _buffer[i][1] = decodeIMA(data >> 4, i); - } - - // The original is interleaved block-wise, we want it sample-wise - buffer[_channels * samples[i] + i] = _buffer[i][_chunkPos[i]]; - - if (++_chunkPos[i] > 1) { - // We're about to decode the next byte, so advance the block position - _chunkPos[i] = 0; - _blockPos[i]++; - } - - samples[i]++; - - if (_channels == 2) - if (_blockPos[i] == _blockAlign) - // We're at the end of the block. - // Since the channels are interleaved, skip the next block - _stream->skip(MIN<uint32>(_blockAlign, _endpos - _stream->pos())); - - _streamPos[i] = _stream->pos(); - } - } - - return samples[0] + samples[1]; -} - -#pragma mark - - - -class MSIma_ADPCMStream : public Ima_ADPCMStream { -public: - MSIma_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign, bool invertSamples = false) - : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign), _invertSamples(invertSamples) { - if (blockAlign == 0) - error("ADPCMStream(): blockAlign isn't specified for MS IMA ADPCM"); - } - - virtual int readBuffer(int16 *buffer, const int numSamples) { - if (_channels == 1) - return readBufferMSIMA1(buffer, numSamples); - else - return readBufferMSIMA2(buffer, numSamples); - } - - int readBufferMSIMA1(int16 *buffer, const int numSamples); - int readBufferMSIMA2(int16 *buffer, const int numSamples); - -private: - bool _invertSamples; // Some implementations invert the way samples are decoded -}; - -int MSIma_ADPCMStream::readBufferMSIMA1(int16 *buffer, const int numSamples) { - int samples = 0; - byte data; - - assert(numSamples % 2 == 0); - - while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) { - if (_blockPos[0] == _blockAlign) { - // read block header - _status.ima_ch[0].last = _stream->readSint16LE(); - _status.ima_ch[0].stepIndex = _stream->readSint16LE(); - _blockPos[0] = 4; - } - - for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2) { - data = _stream->readByte(); - _blockPos[0]++; - buffer[samples] = decodeIMA(_invertSamples ? (data >> 4) & 0x0f : data & 0x0f); - buffer[samples + 1] = decodeIMA(_invertSamples ? data & 0x0f : (data >> 4) & 0x0f); - } - } - return samples; -} - - -// Microsoft as usual tries to implement it differently. This method -// is used for stereo data. -int MSIma_ADPCMStream::readBufferMSIMA2(int16 *buffer, const int numSamples) { - int samples; - uint32 data; - int nibble; - byte k; - - // TODO: Currently this implementation only supports - // reading a multiple of 16 samples at once. We might - // consider changing that so it could read an arbitrary - // sample pair count. - assert(numSamples % 16 == 0); - - for (samples = 0; samples < numSamples && !_stream->eos() && _stream->pos() < _endpos;) { - for (int channel = 0; channel < 2; channel++) { - data = _stream->readUint32LE(); - - for (nibble = 0; nibble < 8; nibble++) { - k = ((data & 0xf0000000) >> 28); - buffer[samples + channel + nibble * 2] = decodeIMA(k); - data <<= 4; - } - } - samples += 16; - } - return samples; -} - - -#pragma mark - - - -static const int MSADPCMAdaptCoeff1[] = { - 256, 512, 0, 192, 240, 460, 392 -}; - -static const int MSADPCMAdaptCoeff2[] = { - 0, -256, 0, 64, 0, -208, -232 -}; - -static const int MSADPCMAdaptationTable[] = { - 230, 230, 230, 230, 307, 409, 512, 614, - 768, 614, 512, 409, 307, 230, 230, 230 -}; - - -class MS_ADPCMStream : public ADPCMStream { -protected: - struct ADPCMChannelStatus { - byte predictor; - int16 delta; - int16 coeff1; - int16 coeff2; - int16 sample1; - int16 sample2; - }; - - struct { - // MS ADPCM - ADPCMChannelStatus ch[2]; - } _status; - - void reset() { - ADPCMStream::reset(); - memset(&_status, 0, sizeof(_status)); - } - -public: - MS_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { - if (blockAlign == 0) - error("MS_ADPCMStream(): blockAlign isn't specified for MS ADPCM"); - memset(&_status, 0, sizeof(_status)); - } - - virtual int readBuffer(int16 *buffer, const int numSamples); - -protected: - int16 decodeMS(ADPCMChannelStatus *c, byte); -}; - -int16 MS_ADPCMStream::decodeMS(ADPCMChannelStatus *c, byte code) { - int32 predictor; - - predictor = (((c->sample1) * (c->coeff1)) + ((c->sample2) * (c->coeff2))) / 256; - predictor += (signed)((code & 0x08) ? (code - 0x10) : (code)) * c->delta; - - predictor = CLIP<int32>(predictor, -32768, 32767); - - c->sample2 = c->sample1; - c->sample1 = predictor; - c->delta = (MSADPCMAdaptationTable[(int)code] * c->delta) >> 8; - - if (c->delta < 16) - c->delta = 16; - - return (int16)predictor; -} - -int MS_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { - int samples; - byte data; - int i = 0; - - samples = 0; - - while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) { - if (_blockPos[0] == _blockAlign) { - // read block header - for (i = 0; i < _channels; i++) { - _status.ch[i].predictor = CLIP(_stream->readByte(), (byte)0, (byte)6); - _status.ch[i].coeff1 = MSADPCMAdaptCoeff1[_status.ch[i].predictor]; - _status.ch[i].coeff2 = MSADPCMAdaptCoeff2[_status.ch[i].predictor]; - } - - for (i = 0; i < _channels; i++) - _status.ch[i].delta = _stream->readSint16LE(); - - for (i = 0; i < _channels; i++) - _status.ch[i].sample1 = _stream->readSint16LE(); - - for (i = 0; i < _channels; i++) - buffer[samples++] = _status.ch[i].sample2 = _stream->readSint16LE(); - - for (i = 0; i < _channels; i++) - buffer[samples++] = _status.ch[i].sample1; - - _blockPos[0] = _channels * 7; - } - - for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2) { - data = _stream->readByte(); - _blockPos[0]++; - buffer[samples] = decodeMS(&_status.ch[0], (data >> 4) & 0x0f); - buffer[samples + 1] = decodeMS(&_status.ch[_channels - 1], data & 0x0f); - } - } - - return samples; -} - - - -#pragma mark - - - -class Tinsel_ADPCMStream : public ADPCMStream { -protected: - struct { - // Tinsel - double predictor; - double K0, K1; - double d0, d1; - } _status; - - void reset() { - ADPCMStream::reset(); - memset(&_status, 0, sizeof(_status)); - } - - int16 decodeTinsel(int16, double); - void readBufferTinselHeader(); - -public: - Tinsel_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { - - if (blockAlign == 0) - error("Tinsel_ADPCMStream(): blockAlign isn't specified"); - - if (channels != 1) - error("Tinsel_ADPCMStream(): Tinsel ADPCM only supports mono"); - - memset(&_status, 0, sizeof(_status)); - } - -}; - -static const double TinselFilterTable[4][2] = { - {0, 0 }, - {0.9375, 0}, - {1.796875, -0.8125}, - {1.53125, -0.859375} -}; - -void Tinsel_ADPCMStream::readBufferTinselHeader() { - uint8 start = _stream->readByte(); - uint8 filterVal = (start & 0xC0) >> 6; - - if ((start & 0x20) != 0) { - //Lower 6 bit are negative - - // Negate - start = ~(start | 0xC0) + 1; - - _status.predictor = 1 << start; - } else { - // Lower 6 bit are positive - - // Truncate - start &= 0x1F; - - _status.predictor = ((double) 1.0) / (1 << start); - } - - _status.K0 = TinselFilterTable[filterVal][0]; - _status.K1 = TinselFilterTable[filterVal][1]; -} - -int16 Tinsel_ADPCMStream::decodeTinsel(int16 code, double eVal) { - double sample; - - sample = (double) code; - sample *= eVal * _status.predictor; - sample += (_status.d0 * _status.K0) + (_status.d1 * _status.K1); - - _status.d1 = _status.d0; - _status.d0 = sample; - - return (int16) CLIP<double>(sample, -32768.0, 32767.0); -} - -class Tinsel4_ADPCMStream : public Tinsel_ADPCMStream { -public: - Tinsel4_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : Tinsel_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {} - - virtual int readBuffer(int16 *buffer, const int numSamples); -}; - -int Tinsel4_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { - int samples; - uint16 data; - const double eVal = 1.142822265; - - samples = 0; - - assert(numSamples % 2 == 0); - - while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) { - if (_blockPos[0] == _blockAlign) { - readBufferTinselHeader(); - _blockPos[0] = 0; - } - - for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2, _blockPos[0]++) { - // Read 1 byte = 8 bits = two 4 bit blocks - data = _stream->readByte(); - buffer[samples] = decodeTinsel((data << 8) & 0xF000, eVal); - buffer[samples+1] = decodeTinsel((data << 12) & 0xF000, eVal); - } - } - - return samples; -} - -class Tinsel6_ADPCMStream : public Tinsel_ADPCMStream { -protected: - uint8 _chunkPos; - uint16 _chunkData; - - void reset() { - ADPCMStream::reset(); - _chunkPos = 0; - _chunkData = 0; - } - -public: - Tinsel6_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : Tinsel_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { - _chunkPos = 0; - _chunkData = 0; - } - - virtual int readBuffer(int16 *buffer, const int numSamples); -}; - -int Tinsel6_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { - int samples; - const double eVal = 1.032226562; - - samples = 0; - - while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) { - if (_blockPos[0] == _blockAlign) { - readBufferTinselHeader(); - _blockPos[0] = 0; - _chunkPos = 0; - } - - for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples++, _chunkPos = (_chunkPos + 1) % 4) { - - switch (_chunkPos) { - case 0: - _chunkData = _stream->readByte(); - buffer[samples] = decodeTinsel((_chunkData << 8) & 0xFC00, eVal); - break; - case 1: - _chunkData = (_chunkData << 8) | (_stream->readByte()); - buffer[samples] = decodeTinsel((_chunkData << 6) & 0xFC00, eVal); - _blockPos[0]++; - break; - case 2: - _chunkData = (_chunkData << 8) | (_stream->readByte()); - buffer[samples] = decodeTinsel((_chunkData << 4) & 0xFC00, eVal); - _blockPos[0]++; - break; - case 3: - _chunkData = (_chunkData << 8); - buffer[samples] = decodeTinsel((_chunkData << 2) & 0xFC00, eVal); - _blockPos[0]++; - break; - } - - } - - } - - return samples; -} - -class Tinsel8_ADPCMStream : public Tinsel_ADPCMStream { -public: - Tinsel8_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : Tinsel_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {} - - virtual int readBuffer(int16 *buffer, const int numSamples); -}; - -int Tinsel8_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { - int samples; - byte data; - const double eVal = 1.007843258; - - samples = 0; - - while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) { - if (_blockPos[0] == _blockAlign) { - readBufferTinselHeader(); - _blockPos[0] = 0; - } - - for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples++, _blockPos[0]++) { - // Read 1 byte = 8 bits = one 8 bit block - data = _stream->readByte(); - buffer[samples] = decodeTinsel(data << 8, eVal); - } - } - - return samples; -} - - -#pragma mark - - -// Duck DK3 IMA ADPCM Decoder -// Based on FFmpeg's decoder and http://wiki.multimedia.cx/index.php?title=Duck_DK3_IMA_ADPCM - -class DK3_ADPCMStream : public Ima_ADPCMStream { -protected: - - void reset() { - Ima_ADPCMStream::reset(); - _topNibble = false; - } - -public: - DK3_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { - - // DK3 only works as a stereo stream - assert(channels == 2); - _topNibble = false; - } - - virtual int readBuffer(int16 *buffer, const int numSamples); - -private: - byte _nibble, _lastByte; - bool _topNibble; -}; - -#define DK3_READ_NIBBLE() \ -do { \ - if (_topNibble) { \ - _nibble = _lastByte >> 4; \ - _topNibble = false; \ - } else { \ - if (_stream->pos() >= _endpos) \ - break; \ - if ((_stream->pos() % _blockAlign) == 0) \ - continue; \ - _lastByte = _stream->readByte(); \ - _nibble = _lastByte & 0xf; \ - _topNibble = true; \ - } \ -} while (0) - - -int DK3_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { - int samples = 0; - - assert((numSamples % 4) == 0); - - while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) { - if ((_stream->pos() % _blockAlign) == 0) { - _stream->readUint16LE(); // Unknown - uint16 rate = _stream->readUint16LE(); // Copy of rate - _stream->skip(6); // Unknown - // Get predictor for both sum/diff channels - _status.ima_ch[0].last = _stream->readSint16LE(); - _status.ima_ch[1].last = _stream->readSint16LE(); - // Get index for both sum/diff channels - _status.ima_ch[0].stepIndex = _stream->readByte(); - _status.ima_ch[1].stepIndex = _stream->readByte(); - - if (_stream->eos()) - break; - - // Sanity check - assert(rate == getRate()); - } - - DK3_READ_NIBBLE(); - decodeIMA(_nibble, 0); - - DK3_READ_NIBBLE(); - decodeIMA(_nibble, 1); - - buffer[samples++] = _status.ima_ch[0].last + _status.ima_ch[1].last; - buffer[samples++] = _status.ima_ch[0].last - _status.ima_ch[1].last; - - DK3_READ_NIBBLE(); - decodeIMA(_nibble, 0); - - buffer[samples++] = _status.ima_ch[0].last + _status.ima_ch[1].last; - buffer[samples++] = _status.ima_ch[0].last - _status.ima_ch[1].last; - } - - return samples; -} - - -#pragma mark - - - -// adjust the step for use on the next sample. -int16 ADPCMStream::stepAdjust(byte code) { - static const int16 adjusts[] = {-1, -1, -1, -1, 2, 4, 6, 8}; - - return adjusts[code & 0x07]; -} - -static const uint16 imaStepTable[89] = { - 7, 8, 9, 10, 11, 12, 13, 14, - 16, 17, 19, 21, 23, 25, 28, 31, - 34, 37, 41, 45, 50, 55, 60, 66, - 73, 80, 88, 97, 107, 118, 130, 143, - 157, 173, 190, 209, 230, 253, 279, 307, - 337, 371, 408, 449, 494, 544, 598, 658, - 724, 796, 876, 963, 1060, 1166, 1282, 1411, - 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, - 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, - 7132, 7845, 8630, 9493,10442,11487,12635,13899, - 15289,16818,18500,20350,22385,24623,27086,29794, - 32767 -}; - -int16 Ima_ADPCMStream::decodeIMA(byte code, int channel) { - int32 E = (2 * (code & 0x7) + 1) * imaStepTable[_status.ima_ch[channel].stepIndex] / 8; - int32 diff = (code & 0x08) ? -E : E; - int32 samp = CLIP<int32>(_status.ima_ch[channel].last + diff, -32768, 32767); - - _status.ima_ch[channel].last = samp; - _status.ima_ch[channel].stepIndex += stepAdjust(code); - _status.ima_ch[channel].stepIndex = CLIP<int32>(_status.ima_ch[channel].stepIndex, 0, ARRAYSIZE(imaStepTable) - 1); - - return samp; -} - -RewindableAudioStream *makeADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, typesADPCM type, int rate, int channels, uint32 blockAlign) { - // If size is 0, report the entire size of the stream - if (!size) - size = stream->size(); - - switch (type) { - case kADPCMOki: - return new Oki_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); - case kADPCMMSIma: - return new MSIma_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); - case kADPCMMSImaLastExpress: - return new MSIma_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign, true); - case kADPCMMS: - return new MS_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); - case kADPCMTinsel4: - return new Tinsel4_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); - case kADPCMTinsel6: - return new Tinsel6_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); - case kADPCMTinsel8: - return new Tinsel8_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); - case kADPCMIma: - return new Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); - case kADPCMApple: - return new Apple_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); - case kADPCMDK3: - return new DK3_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); - default: - error("Unsupported ADPCM encoding"); - break; - } -} - -} // End of namespace Audio diff --git a/sound/decoders/adpcm.h b/sound/decoders/adpcm.h deleted file mode 100644 index 38ec870a27..0000000000 --- a/sound/decoders/adpcm.h +++ /dev/null @@ -1,90 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/** - * @file - * Sound decoder used in engines: - * - agos - * - lastexpress - * - mohawk - * - saga - * - scumm - * - tinsel - */ - -#ifndef SOUND_ADPCM_H -#define SOUND_ADPCM_H - -#include "common/scummsys.h" -#include "common/stream.h" - - -namespace Audio { - -class AudioStream; -class RewindableAudioStream; - -// There are several types of ADPCM encoding, only some are supported here -// For all the different encodings, refer to: -// http://wiki.multimedia.cx/index.php?title=Category:ADPCM_Audio_Codecs -// Usually, if the audio stream we're trying to play has the FourCC header -// string intact, it's easy to discern which encoding is used -enum typesADPCM { - kADPCMOki, // Dialogic/Oki ADPCM (aka VOX) - kADPCMMSIma, // Microsoft IMA ADPCM - kADPCMMSImaLastExpress, // Microsoft IMA ADPCM (with inverted samples) - kADPCMMS, // Microsoft ADPCM - kADPCMTinsel4, // 4-bit ADPCM used by the Tinsel engine - kADPCMTinsel6, // 6-bit ADPCM used by the Tinsel engine - kADPCMTinsel8, // 8-bit ADPCM used by the Tinsel engine - kADPCMIma, // Standard IMA ADPCM - kADPCMApple, // Apple QuickTime IMA ADPCM - kADPCMDK3 // Duck DK3 IMA ADPCM -}; - -/** - * Takes an input stream containing ADPCM compressed sound data and creates - * an RewindableAudioStream from that. - * - * @param stream the SeekableReadStream from which to read the ADPCM data - * @param disposeAfterUse whether to delete the stream after use - * @param size how many bytes to read from the stream (0 = all) - * @param type the compression type used - * @param rate the sampling rate - * @param channels the number of channels - * @param blockAlign block alignment ??? - * @return a new RewindableAudioStream, or NULL, if an error occurred - */ -RewindableAudioStream *makeADPCMStream( - Common::SeekableReadStream *stream, - DisposeAfterUse::Flag disposeAfterUse, - uint32 size, typesADPCM type, - int rate = 22050, - int channels = 2, - uint32 blockAlign = 0); - -} // End of namespace Audio - -#endif diff --git a/sound/decoders/aiff.cpp b/sound/decoders/aiff.cpp deleted file mode 100644 index ce8c6ad32c..0000000000 --- a/sound/decoders/aiff.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/* - * The code in this file is based on information found at - * http://www.borg.com/~jglatt/tech/aiff.htm - * - * We currently only implement uncompressed AIFF. If we ever need AIFF-C, SoX - * (http://sox.sourceforge.net) may be a good place to start from. - */ - -#include "common/endian.h" -#include "common/util.h" -#include "common/stream.h" - -#include "sound/decoders/aiff.h" -#include "sound/audiostream.h" -#include "sound/mixer.h" -#include "sound/decoders/raw.h" - -namespace Audio { - -uint32 readExtended(Common::SeekableReadStream &stream) { - // The sample rate is stored as an "80 bit IEEE Standard 754 floating - // point number (Standard Apple Numeric Environment [SANE] data type - // Extended). - - byte buf[10]; - uint32 mantissa; - uint32 last = 0; - byte exp; - - stream.read(buf, 10); - mantissa = READ_BE_UINT32(buf + 2); - exp = 30 - buf[1]; - - while (exp--) { - last = mantissa; - mantissa >>= 1; - } - - if (last & 0x00000001) - mantissa++; - - return mantissa; -} - -bool loadAIFFFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags) { - byte buf[4]; - - stream.read(buf, 4); - if (memcmp(buf, "FORM", 4) != 0) { - warning("loadAIFFFromStream: No 'FORM' header"); - return false; - } - - stream.readUint32BE(); - - // This could be AIFC, but we don't handle that case. - - stream.read(buf, 4); - if (memcmp(buf, "AIFF", 4) != 0) { - warning("loadAIFFFromStream: No 'AIFF' header"); - return false; - } - - // From here on, we only care about the COMM and SSND chunks, which are - // the only required chunks. - - bool foundCOMM = false; - bool foundSSND = false; - - uint16 numChannels = 0, bitsPerSample = 0; - uint32 numSampleFrames = 0, offset = 0, blockSize = 0, soundOffset = 0; - - while (!(foundCOMM && foundSSND) && !stream.err() && !stream.eos()) { - uint32 length, pos; - - stream.read(buf, 4); - length = stream.readUint32BE(); - pos = stream.pos(); - - if (memcmp(buf, "COMM", 4) == 0) { - foundCOMM = true; - numChannels = stream.readUint16BE(); - numSampleFrames = stream.readUint32BE(); - bitsPerSample = stream.readUint16BE(); - rate = readExtended(stream); - size = numSampleFrames * numChannels * (bitsPerSample / 8); - } else if (memcmp(buf, "SSND", 4) == 0) { - foundSSND = true; - offset = stream.readUint32BE(); - blockSize = stream.readUint32BE(); - soundOffset = stream.pos(); - } - - stream.seek(pos + length); - } - - if (!foundCOMM) { - warning("loadAIFFFromStream: Cound not find 'COMM' chunk"); - return false; - } - - if (!foundSSND) { - warning("loadAIFFFromStream: Cound not find 'SSND' chunk"); - return false; - } - - // We only implement a subset of the AIFF standard. - - if (numChannels < 1 || numChannels > 2) { - warning("loadAIFFFromStream: Only 1 or 2 channels are supported, not %d", numChannels); - return false; - } - - if (bitsPerSample != 8 && bitsPerSample != 16) { - warning("loadAIFFFromStream: Only 8 or 16 bits per sample are supported, not %d", bitsPerSample); - return false; - } - - if (offset != 0 || blockSize != 0) { - warning("loadAIFFFromStream: Block-aligned data is not supported"); - return false; - } - - // Samples are always signed, and big endian. - - flags = 0; - if (bitsPerSample == 16) - flags |= Audio::FLAG_16BITS; - if (numChannels == 2) - flags |= Audio::FLAG_STEREO; - - stream.seek(soundOffset); - - // Stream now points at the sample data - - return true; -} - -SeekableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, - DisposeAfterUse::Flag disposeAfterUse) { - int size, rate; - byte *data, flags; - - if (!loadAIFFFromStream(*stream, size, rate, flags)) { - if (disposeAfterUse == DisposeAfterUse::YES) - delete stream; - return 0; - } - - data = (byte *)malloc(size); - assert(data); - stream->read(data, size); - - if (disposeAfterUse == DisposeAfterUse::YES) - delete stream; - - // Since we allocated our own buffer for the data, we must specify DisposeAfterUse::YES. - return makeRawStream(data, size, rate, flags); -} - -} // End of namespace Audio diff --git a/sound/decoders/aiff.h b/sound/decoders/aiff.h deleted file mode 100644 index 06c56ecd38..0000000000 --- a/sound/decoders/aiff.h +++ /dev/null @@ -1,71 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/** - * @file - * Sound decoder used in engines: - * - saga - * - sci - * - sword1 - */ - -#ifndef SOUND_AIFF_H -#define SOUND_AIFF_H - -#include "common/scummsys.h" -#include "common/types.h" - -namespace Common { class SeekableReadStream; } - -namespace Audio { - -class SeekableAudioStream; - -/** - * Try to load an AIFF from the given seekable stream. Returns true if - * successful. In that case, the stream's seek position will be set to the - * start of the audio data, and size, rate and flags contain information - * necessary for playback. Currently this function only supports uncompressed - * raw PCM data as well as IMA ADPCM. - */ -extern bool loadAIFFFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags); - -/** - * Try to load an AIFF from the given seekable stream and create an AudioStream - * from that data. - * - * This function uses loadAIFFFromStream() internally. - * - * @param stream the SeekableReadStream from which to read the AIFF data - * @param disposeAfterUse whether to delete the stream after use - * @return a new SeekableAudioStream, or NULL, if an error occurred - */ -SeekableAudioStream *makeAIFFStream( - Common::SeekableReadStream *stream, - DisposeAfterUse::Flag disposeAfterUse); - -} // End of namespace Audio - -#endif diff --git a/sound/decoders/flac.cpp b/sound/decoders/flac.cpp deleted file mode 100644 index 080141f224..0000000000 --- a/sound/decoders/flac.cpp +++ /dev/null @@ -1,745 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -// Disable symbol overrides for FILE as that is used in FLAC headers -#define FORBIDDEN_SYMBOL_EXCEPTION_FILE - -#include "sound/decoders/flac.h" - -#ifdef USE_FLAC - -#include "common/debug.h" -#include "common/stream.h" -#include "common/util.h" - -#include "sound/audiostream.h" - -#define FLAC__NO_DLL // that MS-magic gave me headaches - just link the library you like -#include <FLAC/export.h> - - -// check if we have FLAC >= 1.1.3; LEGACY_FLAC code can be removed once FLAC-1.1.3 propagates everywhere -#if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT < 8 -#define LEGACY_FLAC -#else -#undef LEGACY_FLAC -#endif - - -#ifdef LEGACY_FLAC - -// Before FLAC 1.1.3, we needed to use the stream decoder API. -#include <FLAC/seekable_stream_decoder.h> -typedef uint FLAC_size_t; - -#else - -// With FLAC 1.1.3, the stream decoder API was merged into the regular -// stream API. In order to stay compatible with older FLAC versions, we -// simply add some typedefs and #ifdefs to map between the old and new API. -// We use the typedefs (instead of only #defines) in order to somewhat -// improve the readability of the code. - -#include <FLAC/stream_decoder.h> -typedef size_t FLAC_size_t; -// Add aliases for the old names -typedef FLAC__StreamDecoderState FLAC__SeekableStreamDecoderState; -typedef FLAC__StreamDecoderReadStatus FLAC__SeekableStreamDecoderReadStatus; -typedef FLAC__StreamDecoderSeekStatus FLAC__SeekableStreamDecoderSeekStatus; -typedef FLAC__StreamDecoderTellStatus FLAC__SeekableStreamDecoderTellStatus; -typedef FLAC__StreamDecoderLengthStatus FLAC__SeekableStreamDecoderLengthStatus; -typedef FLAC__StreamDecoder FLAC__SeekableStreamDecoder; - -#endif - - -namespace Audio { - -#pragma mark - -#pragma mark --- FLAC stream --- -#pragma mark - - -static const uint MAX_OUTPUT_CHANNELS = 2; - - -class FLACStream : public SeekableAudioStream { -protected: - Common::SeekableReadStream *_inStream; - bool _disposeAfterUse; - - ::FLAC__SeekableStreamDecoder *_decoder; - - /** Header of the stream */ - FLAC__StreamMetadata_StreamInfo _streaminfo; - - /** index + 1(!) of the last sample to be played */ - FLAC__uint64 _lastSample; - - /** total play time */ - Timestamp _length; - - /** true if the last sample was decoded from the FLAC-API - there might still be data in the buffer */ - bool _lastSampleWritten; - - typedef int16 SampleType; - enum { BUFTYPE_BITS = 16 }; - - enum { - // Maximal buffer size. According to the FLAC format specification, the block size is - // a 16 bit value (in fact it seems the maximal block size is 32768, but we play it safe). - BUFFER_SIZE = 65536 - }; - - struct { - SampleType bufData[BUFFER_SIZE]; - SampleType *bufReadPos; - uint bufFill; - } _sampleCache; - - SampleType *_outBuffer; - uint _requestedSamples; - - typedef void (*PFCONVERTBUFFERS)(SampleType*, const FLAC__int32*[], uint, const uint, const uint8); - PFCONVERTBUFFERS _methodConvertBuffers; - - -public: - FLACStream(Common::SeekableReadStream *inStream, bool dispose); - virtual ~FLACStream(); - - int readBuffer(int16 *buffer, const int numSamples); - - bool isStereo() const { return _streaminfo.channels >= 2; } - int getRate() const { return _streaminfo.sample_rate; } - bool endOfData() const { - // End of data is reached if there either is no valid stream data available, - // or if we reached the last sample and completely emptied the sample cache. - return _streaminfo.channels == 0 || (_lastSampleWritten && _sampleCache.bufFill == 0); - } - - bool seek(const Timestamp &where); - Timestamp getLength() const { return _length; } - - bool isStreamDecoderReady() const { return getStreamDecoderState() == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; } -protected: - uint getChannels() const { return MIN<uint>(_streaminfo.channels, MAX_OUTPUT_CHANNELS); } - - bool allocateBuffer(uint minSamples); - - inline FLAC__StreamDecoderState getStreamDecoderState() const; - - inline bool processSingleBlock(); - inline bool processUntilEndOfMetadata(); - bool seekAbsolute(FLAC__uint64 sample); - - inline ::FLAC__SeekableStreamDecoderReadStatus callbackRead(FLAC__byte buffer[], FLAC_size_t *bytes); - inline ::FLAC__SeekableStreamDecoderSeekStatus callbackSeek(FLAC__uint64 absoluteByteOffset); - inline ::FLAC__SeekableStreamDecoderTellStatus callbackTell(FLAC__uint64 *absoluteByteOffset); - inline ::FLAC__SeekableStreamDecoderLengthStatus callbackLength(FLAC__uint64 *streamLength); - inline bool callbackEOF(); - inline ::FLAC__StreamDecoderWriteStatus callbackWrite(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]); - inline void callbackMetadata(const ::FLAC__StreamMetadata *metadata); - inline void callbackError(::FLAC__StreamDecoderErrorStatus status); - -private: - static ::FLAC__SeekableStreamDecoderReadStatus callWrapRead(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], FLAC_size_t *bytes, void *clientData); - static ::FLAC__SeekableStreamDecoderSeekStatus callWrapSeek(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absoluteByteOffset, void *clientData); - static ::FLAC__SeekableStreamDecoderTellStatus callWrapTell(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absoluteByteOffset, void *clientData); - static ::FLAC__SeekableStreamDecoderLengthStatus callWrapLength(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *streamLength, void *clientData); - static FLAC__bool callWrapEOF(const ::FLAC__SeekableStreamDecoder *decoder, void *clientData); - static ::FLAC__StreamDecoderWriteStatus callWrapWrite(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData); - static void callWrapMetadata(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *clientData); - static void callWrapError(const ::FLAC__SeekableStreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *clientData); - - void setBestConvertBufferMethod(); - static void convertBuffersGeneric(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits); - static void convertBuffersStereoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits); - static void convertBuffersStereo8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits); - static void convertBuffersMonoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits); - static void convertBuffersMono8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits); -}; - -FLACStream::FLACStream(Common::SeekableReadStream *inStream, bool dispose) -#ifdef LEGACY_FLAC - : _decoder(::FLAC__seekable_stream_decoder_new()), -#else - : _decoder(::FLAC__stream_decoder_new()), -#endif - _inStream(inStream), - _disposeAfterUse(dispose), - _length(0, 1000), _lastSample(0), - _outBuffer(NULL), _requestedSamples(0), _lastSampleWritten(false), - _methodConvertBuffers(&FLACStream::convertBuffersGeneric) -{ - assert(_inStream); - memset(&_streaminfo, 0, sizeof(_streaminfo)); - - _sampleCache.bufReadPos = NULL; - _sampleCache.bufFill = 0; - - _methodConvertBuffers = &FLACStream::convertBuffersGeneric; - - bool success; -#ifdef LEGACY_FLAC - ::FLAC__seekable_stream_decoder_set_read_callback(_decoder, &FLACStream::callWrapRead); - ::FLAC__seekable_stream_decoder_set_seek_callback(_decoder, &FLACStream::callWrapSeek); - ::FLAC__seekable_stream_decoder_set_tell_callback(_decoder, &FLACStream::callWrapTell); - ::FLAC__seekable_stream_decoder_set_length_callback(_decoder, &FLACStream::callWrapLength); - ::FLAC__seekable_stream_decoder_set_eof_callback(_decoder, &FLACStream::callWrapEOF); - ::FLAC__seekable_stream_decoder_set_write_callback(_decoder, &FLACStream::callWrapWrite); - ::FLAC__seekable_stream_decoder_set_metadata_callback(_decoder, &FLACStream::callWrapMetadata); - ::FLAC__seekable_stream_decoder_set_error_callback(_decoder, &FLACStream::callWrapError); - ::FLAC__seekable_stream_decoder_set_client_data(_decoder, (void*)this); - - success = (::FLAC__seekable_stream_decoder_init(_decoder) == FLAC__SEEKABLE_STREAM_DECODER_OK); -#else - success = (::FLAC__stream_decoder_init_stream( - _decoder, - &FLACStream::callWrapRead, - &FLACStream::callWrapSeek, - &FLACStream::callWrapTell, - &FLACStream::callWrapLength, - &FLACStream::callWrapEOF, - &FLACStream::callWrapWrite, - &FLACStream::callWrapMetadata, - &FLACStream::callWrapError, - (void*)this - ) == FLAC__STREAM_DECODER_INIT_STATUS_OK); -#endif - if (success) { - if (processUntilEndOfMetadata() && _streaminfo.channels > 0) { - _lastSample = _streaminfo.total_samples + 1; - _length = Timestamp(0, _lastSample - 1, getRate()); - return; // no error occurred - } - } - - warning("FLACStream: could not create audio stream"); -} - -FLACStream::~FLACStream() { - if (_decoder != NULL) { -#ifdef LEGACY_FLAC - (void) ::FLAC__seekable_stream_decoder_finish(_decoder); - ::FLAC__seekable_stream_decoder_delete(_decoder); -#else - (void) ::FLAC__stream_decoder_finish(_decoder); - ::FLAC__stream_decoder_delete(_decoder); -#endif - } - if (_disposeAfterUse) - delete _inStream; -} - -inline FLAC__StreamDecoderState FLACStream::getStreamDecoderState() const { - assert(_decoder != NULL); -#ifdef LEGACY_FLAC - return ::FLAC__seekable_stream_decoder_get_stream_decoder_state(_decoder); -#else - return ::FLAC__stream_decoder_get_state(_decoder); -#endif -} - -inline bool FLACStream::processSingleBlock() { - assert(_decoder != NULL); -#ifdef LEGACY_FLAC - return 0 != ::FLAC__seekable_stream_decoder_process_single(_decoder); -#else - return 0 != ::FLAC__stream_decoder_process_single(_decoder); -#endif -} - -inline bool FLACStream::processUntilEndOfMetadata() { - assert(_decoder != NULL); -#ifdef LEGACY_FLAC - return 0 != ::FLAC__seekable_stream_decoder_process_until_end_of_metadata(_decoder); -#else - return 0 != ::FLAC__stream_decoder_process_until_end_of_metadata(_decoder); -#endif -} - -bool FLACStream::seekAbsolute(FLAC__uint64 sample) { - assert(_decoder != NULL); -#ifdef LEGACY_FLAC - const bool result = (0 != ::FLAC__seekable_stream_decoder_seek_absolute(_decoder, sample)); -#else - const bool result = (0 != ::FLAC__stream_decoder_seek_absolute(_decoder, sample)); -#endif - if (result) { - _lastSampleWritten = (_lastSample != 0 && sample >= _lastSample); // only set if we are SURE - } - return result; -} - -bool FLACStream::seek(const Timestamp &where) { - _sampleCache.bufFill = 0; - _sampleCache.bufReadPos = NULL; - // FLAC uses the sample pair number, thus we always use "false" for the isStereo parameter - // of the convertTimeToStreamPos helper. - return seekAbsolute((FLAC__uint64)convertTimeToStreamPos(where, getRate(), false).totalNumberOfFrames()); -} - -int FLACStream::readBuffer(int16 *buffer, const int numSamples) { - const uint numChannels = getChannels(); - - if (numChannels == 0) { - warning("FLACStream: Stream not successfully initialised, cant playback"); - return -1; // streaminfo wasnt read! - } - - assert(numSamples % numChannels == 0); // must be multiple of channels! - assert(buffer != NULL); - assert(_outBuffer == NULL); - assert(_requestedSamples == 0); - - _outBuffer = buffer; - _requestedSamples = numSamples; - - // If there is still data in our buffer from the last time around, - // copy that first. - if (_sampleCache.bufFill > 0) { - assert(_sampleCache.bufReadPos >= _sampleCache.bufData); - assert(_sampleCache.bufFill % numChannels == 0); - - const uint copySamples = MIN((uint)numSamples, _sampleCache.bufFill); - memcpy(buffer, _sampleCache.bufReadPos, copySamples*sizeof(buffer[0])); - - _outBuffer = buffer + copySamples; - _requestedSamples = numSamples - copySamples; - _sampleCache.bufReadPos += copySamples; - _sampleCache.bufFill -= copySamples; - } - - bool decoderOk = true; - - FLAC__StreamDecoderState state = getStreamDecoderState(); - - // Keep poking FLAC to process more samples until we completely satisfied the request - // respectively until we run out of data. - while (!_lastSampleWritten && _requestedSamples > 0 && state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) { - assert(_sampleCache.bufFill == 0); - assert(_requestedSamples % numChannels == 0); - processSingleBlock(); - state = getStreamDecoderState(); - - if (state == FLAC__STREAM_DECODER_END_OF_STREAM) - _lastSampleWritten = true; - } - - // Error handling - switch (state) { - case FLAC__STREAM_DECODER_END_OF_STREAM: - _lastSampleWritten = true; - break; - case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: - break; - default: - decoderOk = false; - warning("FLACStream: An error occurred while decoding. DecoderState is: %s", - FLAC__StreamDecoderStateString[getStreamDecoderState()]); - } - - // Compute how many samples we actually produced - const int samples = (int)(_outBuffer - buffer); - assert(samples % numChannels == 0); - - _outBuffer = NULL; // basically unnecessary, only for the purpose of the asserts - _requestedSamples = 0; // basically unnecessary, only for the purpose of the asserts - - return decoderOk ? samples : -1; -} - -inline ::FLAC__SeekableStreamDecoderReadStatus FLACStream::callbackRead(FLAC__byte buffer[], FLAC_size_t *bytes) { - if (*bytes == 0) { -#ifdef LEGACY_FLAC - return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; /* abort to avoid a deadlock */ -#else - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */ -#endif - } - - const uint32 bytesRead = _inStream->read(buffer, *bytes); - - if (bytesRead == 0) { -#ifdef LEGACY_FLAC - return _inStream->eos() ? FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK : FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; -#else - return _inStream->eos() ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_ABORT; -#endif - } - - *bytes = static_cast<uint>(bytesRead); -#ifdef LEGACY_FLAC - return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK; -#else - return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; -#endif -} - -void FLACStream::setBestConvertBufferMethod() { - PFCONVERTBUFFERS tempMethod = &FLACStream::convertBuffersGeneric; - - const uint numChannels = getChannels(); - const uint8 numBits = (uint8)_streaminfo.bits_per_sample; - - assert(numChannels >= 1); - assert(numBits >= 4 && numBits <=32); - - if (numChannels == 1) { - if (numBits == 8) - tempMethod = &FLACStream::convertBuffersMono8Bit; - if (numBits == BUFTYPE_BITS) - tempMethod = &FLACStream::convertBuffersMonoNS; - } else if (numChannels == 2) { - if (numBits == 8) - tempMethod = &FLACStream::convertBuffersStereo8Bit; - if (numBits == BUFTYPE_BITS) - tempMethod = &FLACStream::convertBuffersStereoNS; - } /* else ... */ - - _methodConvertBuffers = tempMethod; -} - -// 1 channel, no scaling -void FLACStream::convertBuffersMonoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) { - assert(numChannels == 1); - assert(numBits == BUFTYPE_BITS); - - FLAC__int32 const* inChannel1 = inChannels[0]; - - while (numSamples >= 4) { - bufDestination[0] = static_cast<SampleType>(inChannel1[0]); - bufDestination[1] = static_cast<SampleType>(inChannel1[1]); - bufDestination[2] = static_cast<SampleType>(inChannel1[2]); - bufDestination[3] = static_cast<SampleType>(inChannel1[3]); - bufDestination += 4; - inChannel1 += 4; - numSamples -= 4; - } - - for (; numSamples > 0; --numSamples) { - *bufDestination++ = static_cast<SampleType>(*inChannel1++); - } - - inChannels[0] = inChannel1; - assert(numSamples == 0); // dint copy too many samples -} - -// 1 channel, scaling from 8Bit -void FLACStream::convertBuffersMono8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) { - assert(numChannels == 1); - assert(numBits == 8); - assert(8 < BUFTYPE_BITS); - - FLAC__int32 const* inChannel1 = inChannels[0]; - - while (numSamples >= 4) { - bufDestination[0] = static_cast<SampleType>(inChannel1[0]) << (BUFTYPE_BITS - 8); - bufDestination[1] = static_cast<SampleType>(inChannel1[1]) << (BUFTYPE_BITS - 8); - bufDestination[2] = static_cast<SampleType>(inChannel1[2]) << (BUFTYPE_BITS - 8); - bufDestination[3] = static_cast<SampleType>(inChannel1[3]) << (BUFTYPE_BITS - 8); - bufDestination += 4; - inChannel1 += 4; - numSamples -= 4; - } - - for (; numSamples > 0; --numSamples) { - *bufDestination++ = static_cast<SampleType>(*inChannel1++) << (BUFTYPE_BITS - 8); - } - - inChannels[0] = inChannel1; - assert(numSamples == 0); // dint copy too many samples -} - -// 2 channels, no scaling -void FLACStream::convertBuffersStereoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) { - assert(numChannels == 2); - assert(numBits == BUFTYPE_BITS); - assert(numSamples % 2 == 0); // must be integral multiply of channels - - - FLAC__int32 const* inChannel1 = inChannels[0]; // Left Channel - FLAC__int32 const* inChannel2 = inChannels[1]; // Right Channel - - while (numSamples >= 2*2) { - bufDestination[0] = static_cast<SampleType>(inChannel1[0]); - bufDestination[1] = static_cast<SampleType>(inChannel2[0]); - bufDestination[2] = static_cast<SampleType>(inChannel1[1]); - bufDestination[3] = static_cast<SampleType>(inChannel2[1]); - bufDestination += 2 * 2; - inChannel1 += 2; - inChannel2 += 2; - numSamples -= 2 * 2; - } - - while (numSamples > 0) { - bufDestination[0] = static_cast<SampleType>(*inChannel1++); - bufDestination[1] = static_cast<SampleType>(*inChannel2++); - bufDestination += 2; - numSamples -= 2; - } - - inChannels[0] = inChannel1; - inChannels[1] = inChannel2; - assert(numSamples == 0); // dint copy too many samples -} - -// 2 channels, scaling from 8Bit -void FLACStream::convertBuffersStereo8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) { - assert(numChannels == 2); - assert(numBits == 8); - assert(numSamples % 2 == 0); // must be integral multiply of channels - assert(8 < BUFTYPE_BITS); - - FLAC__int32 const* inChannel1 = inChannels[0]; // Left Channel - FLAC__int32 const* inChannel2 = inChannels[1]; // Right Channel - - while (numSamples >= 2*2) { - bufDestination[0] = static_cast<SampleType>(inChannel1[0]) << (BUFTYPE_BITS - 8); - bufDestination[1] = static_cast<SampleType>(inChannel2[0]) << (BUFTYPE_BITS - 8); - bufDestination[2] = static_cast<SampleType>(inChannel1[1]) << (BUFTYPE_BITS - 8); - bufDestination[3] = static_cast<SampleType>(inChannel2[1]) << (BUFTYPE_BITS - 8); - bufDestination += 2 * 2; - inChannel1 += 2; - inChannel2 += 2; - numSamples -= 2 * 2; - } - - while (numSamples > 0) { - bufDestination[0] = static_cast<SampleType>(*inChannel1++) << (BUFTYPE_BITS - 8); - bufDestination[1] = static_cast<SampleType>(*inChannel2++) << (BUFTYPE_BITS - 8); - bufDestination += 2; - numSamples -= 2; - } - - inChannels[0] = inChannel1; - inChannels[1] = inChannel2; - assert(numSamples == 0); // dint copy too many samples -} - -// all Purpose-conversion - slowest of em all -void FLACStream::convertBuffersGeneric(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) { - assert(numSamples % numChannels == 0); // must be integral multiply of channels - - if (numBits < BUFTYPE_BITS) { - const uint8 kPower = (uint8)(BUFTYPE_BITS - numBits); - - for (; numSamples > 0; numSamples -= numChannels) { - for (uint i = 0; i < numChannels; ++i) - *bufDestination++ = static_cast<SampleType>(*(inChannels[i]++)) << kPower; - } - } else if (numBits > BUFTYPE_BITS) { - const uint8 kPower = (uint8)(numBits - BUFTYPE_BITS); - - for (; numSamples > 0; numSamples -= numChannels) { - for (uint i = 0; i < numChannels; ++i) - *bufDestination++ = static_cast<SampleType>(*(inChannels[i]++) >> kPower); - } - } else { - for (; numSamples > 0; numSamples -= numChannels) { - for (uint i = 0; i < numChannels; ++i) - *bufDestination++ = static_cast<SampleType>(*(inChannels[i]++)); - } - } - - assert(numSamples == 0); // dint copy too many samples -} - -inline ::FLAC__StreamDecoderWriteStatus FLACStream::callbackWrite(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) { - assert(frame->header.channels == _streaminfo.channels); - assert(frame->header.sample_rate == _streaminfo.sample_rate); - assert(frame->header.bits_per_sample == _streaminfo.bits_per_sample); - assert(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER || _streaminfo.min_blocksize == _streaminfo.max_blocksize); - - // We require that either the sample cache is empty, or that no samples were requested - assert(_sampleCache.bufFill == 0 || _requestedSamples == 0); - - uint numSamples = frame->header.blocksize; - const uint numChannels = getChannels(); - const uint8 numBits = (uint8)_streaminfo.bits_per_sample; - - assert(_requestedSamples % numChannels == 0); // must be integral multiply of channels - - const FLAC__uint64 firstSampleNumber = (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER) ? - frame->header.number.sample_number : (static_cast<FLAC__uint64>(frame->header.number.frame_number)) * _streaminfo.max_blocksize; - - // Check whether we are about to reach beyond the last sample we are supposed to play. - if (_lastSample != 0 && firstSampleNumber + numSamples >= _lastSample) { - numSamples = (uint)(firstSampleNumber >= _lastSample ? 0 : _lastSample - firstSampleNumber); - _lastSampleWritten = true; - } - - // The value in _requestedSamples counts raw samples, so if there are more than one - // channel, we have to multiply the number of available sample "pairs" by numChannels - numSamples *= numChannels; - - const FLAC__int32 *inChannels[MAX_OUTPUT_CHANNELS]; - for (uint i = 0; i < numChannels; ++i) - inChannels[i] = buffer[i]; - - // write the incoming samples directly into the buffer provided to us by the mixer - if (_requestedSamples > 0) { - assert(_requestedSamples % numChannels == 0); - assert(_outBuffer != NULL); - - // Copy & convert the available samples (limited both by how many we have available, and - // by how many are actually needed). - const uint copySamples = MIN(_requestedSamples, numSamples); - (*_methodConvertBuffers)(_outBuffer, inChannels, copySamples, numChannels, numBits); - - _requestedSamples -= copySamples; - numSamples -= copySamples; - _outBuffer += copySamples; - } - - // Write all remaining samples (i.e. those which didn't fit into the mixer buffer) - // into the sample cache. - if (_sampleCache.bufFill == 0) - _sampleCache.bufReadPos = _sampleCache.bufData; - const uint cacheSpace = (_sampleCache.bufData + BUFFER_SIZE) - (_sampleCache.bufReadPos + _sampleCache.bufFill); - assert(numSamples <= cacheSpace); - (*_methodConvertBuffers)(_sampleCache.bufReadPos + _sampleCache.bufFill, inChannels, numSamples, numChannels, numBits); - - _sampleCache.bufFill += numSamples; - - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; -} - -inline ::FLAC__SeekableStreamDecoderSeekStatus FLACStream::callbackSeek(FLAC__uint64 absoluteByteOffset) { - _inStream->seek(absoluteByteOffset, SEEK_SET); - const bool result = (absoluteByteOffset == (FLAC__uint64)_inStream->pos()); - -#ifdef LEGACY_FLAC - return result ? FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK : FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; -#else - return result ? FLAC__STREAM_DECODER_SEEK_STATUS_OK : FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; -#endif -} - -inline ::FLAC__SeekableStreamDecoderTellStatus FLACStream::callbackTell(FLAC__uint64 *absoluteByteOffset) { - *absoluteByteOffset = static_cast<FLAC__uint64>(_inStream->pos()); -#ifdef LEGACY_FLAC - return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK; -#else - return FLAC__STREAM_DECODER_TELL_STATUS_OK; -#endif -} - -inline ::FLAC__SeekableStreamDecoderLengthStatus FLACStream::callbackLength(FLAC__uint64 *streamLength) { - *streamLength = static_cast<FLAC__uint64>(_inStream->size()); -#ifdef LEGACY_FLAC - return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK; -#else - return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; -#endif -} - -inline bool FLACStream::callbackEOF() { - return _inStream->eos(); -} - - -inline void FLACStream::callbackMetadata(const ::FLAC__StreamMetadata *metadata) { - assert(_decoder != NULL); - assert(metadata->type == FLAC__METADATA_TYPE_STREAMINFO); // others arent really interesting - - _streaminfo = metadata->data.stream_info; - setBestConvertBufferMethod(); // should be set after getting stream-information. FLAC always parses the info first -} -inline void FLACStream::callbackError(::FLAC__StreamDecoderErrorStatus status) { - // some of these are non-critical-Errors - debug(1, "FLACStream: An error occurred while decoding. DecoderState is: %s", - FLAC__StreamDecoderErrorStatusString[status]); -} - -/* Static Callback Wrappers */ -::FLAC__SeekableStreamDecoderReadStatus FLACStream::callWrapRead(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], FLAC_size_t *bytes, void *clientData) { - FLACStream *instance = (FLACStream *)clientData; - assert(0 != instance); - return instance->callbackRead(buffer, bytes); -} - -::FLAC__SeekableStreamDecoderSeekStatus FLACStream::callWrapSeek(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absoluteByteOffset, void *clientData) { - FLACStream *instance = (FLACStream *)clientData; - assert(0 != instance); - return instance->callbackSeek(absoluteByteOffset); -} - -::FLAC__SeekableStreamDecoderTellStatus FLACStream::callWrapTell(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absoluteByteOffset, void *clientData) { - FLACStream *instance = (FLACStream *)clientData; - assert(0 != instance); - return instance->callbackTell(absoluteByteOffset); -} - -::FLAC__SeekableStreamDecoderLengthStatus FLACStream::callWrapLength(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *streamLength, void *clientData) { - FLACStream *instance = (FLACStream *)clientData; - assert(0 != instance); - return instance->callbackLength(streamLength); -} - -FLAC__bool FLACStream::callWrapEOF(const ::FLAC__SeekableStreamDecoder *decoder, void *clientData) { - FLACStream *instance = (FLACStream *)clientData; - assert(0 != instance); - return instance->callbackEOF(); -} - -::FLAC__StreamDecoderWriteStatus FLACStream::callWrapWrite(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData) { - FLACStream *instance = (FLACStream *)clientData; - assert(0 != instance); - return instance->callbackWrite(frame, buffer); -} - -void FLACStream::callWrapMetadata(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *clientData) { - FLACStream *instance = (FLACStream *)clientData; - assert(0 != instance); - instance->callbackMetadata(metadata); -} - -void FLACStream::callWrapError(const ::FLAC__SeekableStreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *clientData) { - FLACStream *instance = (FLACStream *)clientData; - assert(0 != instance); - instance->callbackError(status); -} - - -#pragma mark - -#pragma mark --- FLAC factory functions --- -#pragma mark - - -SeekableAudioStream *makeFLACStream( - Common::SeekableReadStream *stream, - DisposeAfterUse::Flag disposeAfterUse) { - SeekableAudioStream *s = new FLACStream(stream, disposeAfterUse); - if (s && s->endOfData()) { - delete s; - return 0; - } else { - return s; - } -} - -} // End of namespace Audio - -#endif // #ifdef USE_FLAC diff --git a/sound/decoders/flac.h b/sound/decoders/flac.h deleted file mode 100644 index 17f95ec1fb..0000000000 --- a/sound/decoders/flac.h +++ /dev/null @@ -1,75 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/** - * @file - * Sound decoder used in engines: - * - agos - * - draci - * - kyra - * - m4 - * - queen - * - saga - * - sci - * - scumm - * - sword1 - * - sword2 - * - touche - * - tucker - */ - -#ifndef SOUND_FLAC_H -#define SOUND_FLAC_H - -#include "common/scummsys.h" -#include "common/types.h" - -#ifdef USE_FLAC - -namespace Common { - class SeekableReadStream; -} - -namespace Audio { - -class AudioStream; -class SeekableAudioStream; - -/** - * Create a new SeekableAudioStream from the FLAC data in the given stream. - * Allows for seeking (which is why we require a SeekableReadStream). - * - * @param stream the SeekableReadStream from which to read the FLAC data - * @param disposeAfterUse whether to delete the stream after use - * @return a new SeekableAudioStream, or NULL, if an error occurred - */ -SeekableAudioStream *makeFLACStream( - Common::SeekableReadStream *stream, - DisposeAfterUse::Flag disposeAfterUse); - -} // End of namespace Audio - -#endif // #ifdef USE_FLAC -#endif // #ifndef SOUND_FLAC_H diff --git a/sound/decoders/iff_sound.cpp b/sound/decoders/iff_sound.cpp deleted file mode 100644 index 148de5b621..0000000000 --- a/sound/decoders/iff_sound.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "sound/decoders/iff_sound.h" -#include "sound/audiostream.h" -#include "sound/mixer.h" -#include "sound/decoders/raw.h" -#include "common/iff_container.h" -#include "common/func.h" - -namespace Audio { - -struct Voice8Header { - uint32 oneShotHiSamples; - uint32 repeatHiSamples; - uint32 samplesPerHiCycle; - uint16 samplesPerSec; - byte octaves; - byte compression; - uint32 volume; - - Voice8Header() { - memset(this, 0, sizeof(Voice8Header)); - } - - void load(Common::ReadStream &stream); -}; - -void Voice8Header::load(Common::ReadStream &stream) { - oneShotHiSamples = stream.readUint32BE(); - repeatHiSamples = stream.readUint32BE(); - samplesPerHiCycle = stream.readUint32BE(); - samplesPerSec = stream.readUint16BE(); - octaves = stream.readByte(); - compression = stream.readByte(); - volume = stream.readUint32BE(); -} - - - -struct A8SVXLoader { - Voice8Header _header; - int8 *_data; - uint32 _dataSize; - - void load(Common::ReadStream &input) { - Common::IFFParser parser(&input); - Common::Functor1Mem< Common::IFFChunk&, bool, A8SVXLoader > c(this, &A8SVXLoader::callback); - parser.parse(c); - } - - bool callback(Common::IFFChunk &chunk) { - switch (chunk._type) { - case ID_VHDR: - _header.load(*chunk._stream); - break; - - case ID_BODY: - _dataSize = chunk._size; - _data = (int8*)malloc(_dataSize); - assert(_data); - loadData(chunk._stream); - return true; - } - - return false; - } - - void loadData(Common::ReadStream *stream) { - switch (_header.compression) { - case 0: - stream->read(_data, _dataSize); - break; - - case 1: - // implement other formats here - error("compressed IFF audio is not supported"); - break; - } - - } -}; - - -AudioStream *make8SVXStream(Common::ReadStream &input, bool loop) { - A8SVXLoader loader; - loader.load(input); - - SeekableAudioStream *stream = Audio::makeRawStream((byte *)loader._data, loader._dataSize, loader._header.samplesPerSec, 0); - - uint32 loopStart = 0, loopEnd = 0; - if (loop) { - // the standard way to loop 8SVX audio implies use of the oneShotHiSamples and - // repeatHiSamples fields - loopStart = 0; - loopEnd = loader._header.oneShotHiSamples + loader._header.repeatHiSamples; - - if (loopStart != loopEnd) { - return new SubLoopingAudioStream(stream, 0, - Timestamp(0, loopStart, loader._header.samplesPerSec), - Timestamp(0, loopEnd, loader._header.samplesPerSec)); - } - } - - return stream; -} - -} diff --git a/sound/decoders/iff_sound.h b/sound/decoders/iff_sound.h deleted file mode 100644 index 4e53059380..0000000000 --- a/sound/decoders/iff_sound.h +++ /dev/null @@ -1,47 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/** - * @file - * Sound decoder used in engines: - * - parallaction - */ - -#ifndef SOUND_IFF_H -#define SOUND_IFF_H - -namespace Common { - class ReadStream; -} - -namespace Audio { - -class AudioStream; - -AudioStream *make8SVXStream(Common::ReadStream &stream, bool loop); - -} - -#endif diff --git a/sound/decoders/mac_snd.cpp b/sound/decoders/mac_snd.cpp deleted file mode 100644 index 48f6886bf4..0000000000 --- a/sound/decoders/mac_snd.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/* - * The code in this file is based on information found at - * http://developer.apple.com/legacy/mac/library/documentation/mac/Sound/Sound-60.html#HEADING60-15 - * - * We implement both type 1 and type 2 snd resources, but only those that are sampled - */ - -#include "common/util.h" -#include "common/stream.h" - -#include "sound/decoders/mac_snd.h" -#include "sound/audiostream.h" -#include "sound/decoders/raw.h" - -namespace Audio { - -SeekableAudioStream *makeMacSndStream(Common::SeekableReadStream *stream, - DisposeAfterUse::Flag disposeAfterUse) { - - uint16 sndType = stream->readUint16BE(); - - if (sndType == 1) { - // "normal" snd resources - if (stream->readUint16BE() != 1) { - warning("makeMacSndStream(): Unsupported data type count"); - return 0; - } - - if (stream->readUint16BE() != 5) { - // 5 == sampled - warning("makeMacSndStream(): Unsupported data type"); - return 0; - } - - stream->readUint32BE(); // initialization option - } else if (sndType == 2) { - // old HyperCard snd resources - stream->readUint16BE(); // reference count (unused) - } else { - warning("makeMacSndStream(): Unknown format type %d", sndType); - return 0; - } - - // We really should never get this as long as we have sampled data only - if (stream->readUint16BE() != 1) { - warning("makeMacSndStream(): Unsupported command count"); - return 0; - } - - uint16 command = stream->readUint16BE(); - - // 0x8050 - soundCmd (with dataOffsetFlag set): install a sampled sound as a voice - // 0x8051 - bufferCmd (with dataOffsetFlag set): play a sample sound - if (command != 0x8050 && command != 0x8051) { - warning("makeMacSndStream(): Unsupported command %04x", command); - return 0; - } - - stream->readUint16BE(); // 0 - uint32 soundHeaderOffset = stream->readUint32BE(); - - stream->seek(soundHeaderOffset); - - uint32 soundDataOffset = stream->readUint32BE(); - uint32 size = stream->readUint32BE(); - uint16 rate = stream->readUint32BE() >> 16; // Really fixed point, but we only support integer rates - stream->readUint32BE(); // loop start - stream->readUint32BE(); // loop end - byte encoding = stream->readByte(); - stream->readByte(); // base frequency - - if (encoding != 0) { - // 0 == PCM - warning("makeMacSndStream(): Unsupported compression %d", encoding); - return 0; - } - - stream->skip(soundDataOffset); - - byte *data = (byte *)malloc(size); - assert(data); - stream->read(data, size); - - if (disposeAfterUse == DisposeAfterUse::YES) - delete stream; - - // Since we allocated our own buffer for the data, we must specify DisposeAfterUse::YES. - return makeRawStream(data, size, rate, Audio::FLAG_UNSIGNED); -} - -} // End of namespace Audio diff --git a/sound/decoders/mac_snd.h b/sound/decoders/mac_snd.h deleted file mode 100644 index 198a61333e..0000000000 --- a/sound/decoders/mac_snd.h +++ /dev/null @@ -1,58 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/** - * @file - * Sound decoder used in engines: - * - sci - */ - -#ifndef SOUND_MAC_SND_H -#define SOUND_MAC_SND_H - -#include "common/scummsys.h" -#include "common/types.h" - -namespace Common { class SeekableReadStream; } - -namespace Audio { - -class SeekableAudioStream; - -/** - * Try to load a Mac snd resource from the given seekable stream and create a SeekableAudioStream - * from that data. - * - * @param stream the SeekableReadStream from which to read the snd data - * @param disposeAfterUse whether to delete the stream after use - * @return a new SeekableAudioStream, or NULL, if an error occurred - */ -SeekableAudioStream *makeMacSndStream( - Common::SeekableReadStream *stream, - DisposeAfterUse::Flag disposeAfterUse); - -} // End of namespace Audio - -#endif diff --git a/sound/decoders/mp3.cpp b/sound/decoders/mp3.cpp deleted file mode 100644 index e06b82a9e2..0000000000 --- a/sound/decoders/mp3.cpp +++ /dev/null @@ -1,375 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "sound/decoders/mp3.h" - -#ifdef USE_MAD - -#include "common/debug.h" -#include "common/stream.h" -#include "common/util.h" - -#include "sound/audiostream.h" - -#include <mad.h> - -#if defined(__PSP__) - #include "backends/platform/psp/mp3.h" -#endif -namespace Audio { - - -#pragma mark - -#pragma mark --- MP3 (MAD) stream --- -#pragma mark - - - -class MP3Stream : public SeekableAudioStream { -protected: - enum State { - MP3_STATE_INIT, // Need to init the decoder - MP3_STATE_READY, // ready for processing data - MP3_STATE_EOS // end of data reached (may need to loop) - }; - - Common::SeekableReadStream *_inStream; - DisposeAfterUse::Flag _disposeAfterUse; - - uint _posInFrame; - State _state; - - Timestamp _length; - mad_timer_t _totalTime; - - mad_stream _stream; - mad_frame _frame; - mad_synth _synth; - - enum { - BUFFER_SIZE = 5 * 8192 - }; - - // This buffer contains a slab of input data - byte _buf[BUFFER_SIZE + MAD_BUFFER_GUARD]; - -public: - MP3Stream(Common::SeekableReadStream *inStream, - DisposeAfterUse::Flag dispose); - ~MP3Stream(); - - int readBuffer(int16 *buffer, const int numSamples); - - bool endOfData() const { return _state == MP3_STATE_EOS; } - bool isStereo() const { return MAD_NCHANNELS(&_frame.header) == 2; } - int getRate() const { return _frame.header.samplerate; } - - bool seek(const Timestamp &where); - Timestamp getLength() const { return _length; } -protected: - void decodeMP3Data(); - void readMP3Data(); - - void initStream(); - void readHeader(); - void deinitStream(); -}; - -MP3Stream::MP3Stream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose) : - _inStream(inStream), - _disposeAfterUse(dispose), - _posInFrame(0), - _state(MP3_STATE_INIT), - _length(0, 1000), - _totalTime(mad_timer_zero) { - - // The MAD_BUFFER_GUARD must always contain zeros (the reason - // for this is that the Layer III Huffman decoder of libMAD - // may read a few bytes beyond the end of the input buffer). - memset(_buf + BUFFER_SIZE, 0, MAD_BUFFER_GUARD); - - // Calculate the length of the stream - initStream(); - - while (_state != MP3_STATE_EOS) - readHeader(); - - // To rule out any invalid sample rate to be encountered here, say in case the - // MP3 stream is invalid, we just check the MAD error code here. - // We need to assure this, since else we might trigger an assertion in Timestamp - // (When getRate() returns 0 or a negative number to be precise). - // Note that we allow "MAD_ERROR_BUFLEN" as error code here, since according - // to mad.h it is also set on EOF. - if ((_stream.error == MAD_ERROR_NONE || _stream.error == MAD_ERROR_BUFLEN) && getRate() > 0) - _length = Timestamp(mad_timer_count(_totalTime, MAD_UNITS_MILLISECONDS), getRate()); - - deinitStream(); - - // Reinit stream - _state = MP3_STATE_INIT; - - // Decode the first chunk of data. This is necessary so that _frame - // is setup and isStereo() and getRate() return correct results. - decodeMP3Data(); -} - -MP3Stream::~MP3Stream() { - deinitStream(); - - if (_disposeAfterUse == DisposeAfterUse::YES) - delete _inStream; -} - -void MP3Stream::decodeMP3Data() { - do { - if (_state == MP3_STATE_INIT) - initStream(); - - if (_state == MP3_STATE_EOS) - return; - - // If necessary, load more data into the stream decoder - if (_stream.error == MAD_ERROR_BUFLEN) - readMP3Data(); - - while (_state == MP3_STATE_READY) { - _stream.error = MAD_ERROR_NONE; - - // Decode the next frame - if (mad_frame_decode(&_frame, &_stream) == -1) { - if (_stream.error == MAD_ERROR_BUFLEN) { - break; // Read more data - } else if (MAD_RECOVERABLE(_stream.error)) { - // Note: we will occasionally see MAD_ERROR_BADDATAPTR errors here. - // These are normal and expected (caused by our frame skipping (i.e. "seeking") - // code above). - debug(6, "MP3Stream: Recoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream)); - continue; - } else { - warning("MP3Stream: Unrecoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream)); - break; - } - } - - // Synthesize PCM data - mad_synth_frame(&_synth, &_frame); - _posInFrame = 0; - break; - } - } while (_state != MP3_STATE_EOS && _stream.error == MAD_ERROR_BUFLEN); - - if (_stream.error != MAD_ERROR_NONE) - _state = MP3_STATE_EOS; -} - -void MP3Stream::readMP3Data() { - uint32 remaining = 0; - - // Give up immediately if we already used up all data in the stream - if (_inStream->eos()) { - _state = MP3_STATE_EOS; - return; - } - - if (_stream.next_frame) { - // If there is still data in the MAD stream, we need to preserve it. - // Note that we use memmove, as we are reusing the same buffer, - // and hence the data regions we copy from and to may overlap. - remaining = _stream.bufend - _stream.next_frame; - assert(remaining < BUFFER_SIZE); // Paranoia check - memmove(_buf, _stream.next_frame, remaining); - } - - // Try to read the next block - uint32 size = _inStream->read(_buf + remaining, BUFFER_SIZE - remaining); - if (size <= 0) { - _state = MP3_STATE_EOS; - return; - } - - // Feed the data we just read into the stream decoder - _stream.error = MAD_ERROR_NONE; - mad_stream_buffer(&_stream, _buf, size + remaining); -} - -bool MP3Stream::seek(const Timestamp &where) { - if (where == _length) { - _state = MP3_STATE_EOS; - return true; - } else if (where > _length) { - return false; - } - - const uint32 time = where.msecs(); - - mad_timer_t destination; - mad_timer_set(&destination, time / 1000, time % 1000, 1000); - - if (_state != MP3_STATE_READY || mad_timer_compare(destination, _totalTime) < 0) - initStream(); - - while (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS) - readHeader(); - - decodeMP3Data(); - - return (_state != MP3_STATE_EOS); -} - -void MP3Stream::initStream() { - if (_state != MP3_STATE_INIT) - deinitStream(); - - // Init MAD - mad_stream_init(&_stream); - mad_frame_init(&_frame); - mad_synth_init(&_synth); - - // Reset the stream data - _inStream->seek(0, SEEK_SET); - _totalTime = mad_timer_zero; - _posInFrame = 0; - - // Update state - _state = MP3_STATE_READY; - - // Read the first few sample bytes - readMP3Data(); -} - -void MP3Stream::readHeader() { - if (_state != MP3_STATE_READY) - return; - - // If necessary, load more data into the stream decoder - if (_stream.error == MAD_ERROR_BUFLEN) - readMP3Data(); - - while (_state != MP3_STATE_EOS) { - _stream.error = MAD_ERROR_NONE; - - // Decode the next header. Note: mad_frame_decode would do this for us, too. - // However, for seeking we don't want to decode the full frame (else it would - // be far too slow). Hence we perform this explicitly in a separate step. - if (mad_header_decode(&_frame.header, &_stream) == -1) { - if (_stream.error == MAD_ERROR_BUFLEN) { - readMP3Data(); // Read more data - continue; - } else if (MAD_RECOVERABLE(_stream.error)) { - debug(6, "MP3Stream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream)); - continue; - } else { - warning("MP3Stream: Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream)); - break; - } - } - - // Sum up the total playback time so far - mad_timer_add(&_totalTime, _frame.header.duration); - break; - } - - if (_stream.error != MAD_ERROR_NONE) - _state = MP3_STATE_EOS; -} - -void MP3Stream::deinitStream() { - if (_state == MP3_STATE_INIT) - return; - - // Deinit MAD - mad_synth_finish(&_synth); - mad_frame_finish(&_frame); - mad_stream_finish(&_stream); - - _state = MP3_STATE_EOS; -} - -static inline int scale_sample(mad_fixed_t sample) { - // round - sample += (1L << (MAD_F_FRACBITS - 16)); - - // clip - if (sample > MAD_F_ONE - 1) - sample = MAD_F_ONE - 1; - else if (sample < -MAD_F_ONE) - sample = -MAD_F_ONE; - - // quantize and scale to not saturate when mixing a lot of channels - return sample >> (MAD_F_FRACBITS + 1 - 16); -} - -int MP3Stream::readBuffer(int16 *buffer, const int numSamples) { - int samples = 0; - // Keep going as long as we have input available - while (samples < numSamples && _state != MP3_STATE_EOS) { - const int len = MIN(numSamples, samples + (int)(_synth.pcm.length - _posInFrame) * MAD_NCHANNELS(&_frame.header)); - while (samples < len) { - *buffer++ = (int16)scale_sample(_synth.pcm.samples[0][_posInFrame]); - samples++; - if (MAD_NCHANNELS(&_frame.header) == 2) { - *buffer++ = (int16)scale_sample(_synth.pcm.samples[1][_posInFrame]); - samples++; - } - _posInFrame++; - } - if (_posInFrame >= _synth.pcm.length) { - // We used up all PCM data in the current frame -- read & decode more - decodeMP3Data(); - } - } - return samples; -} - - -#pragma mark - -#pragma mark --- MP3 factory functions --- -#pragma mark - - -SeekableAudioStream *makeMP3Stream( - Common::SeekableReadStream *stream, - DisposeAfterUse::Flag disposeAfterUse) { - -#if defined(__PSP__) - SeekableAudioStream *s = 0; - - if (Mp3PspStream::isOkToCreateStream()) - s = new Mp3PspStream(stream, disposeAfterUse); - - if (!s) // go to regular MAD mp3 stream if ME fails - s = new MP3Stream(stream, disposeAfterUse); -#else - SeekableAudioStream *s = new MP3Stream(stream, disposeAfterUse); -#endif - if (s && s->endOfData()) { - delete s; - return 0; - } else { - return s; - } -} - -} // End of namespace Audio - -#endif // #ifdef USE_MAD diff --git a/sound/decoders/mp3.h b/sound/decoders/mp3.h deleted file mode 100644 index 72bc6e1b3e..0000000000 --- a/sound/decoders/mp3.h +++ /dev/null @@ -1,76 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/** - * @file - * Sound decoder used in engines: - * - agos - * - draci - * - kyra - * - m4 - * - mohawk - * - queen - * - saga - * - sci - * - scumm - * - sword1 - * - sword2 - * - touche - * - tucker - */ - -#ifndef SOUND_MP3_H -#define SOUND_MP3_H - -#include "common/scummsys.h" -#include "common/types.h" - -#ifdef USE_MAD - -namespace Common { - class SeekableReadStream; -} - -namespace Audio { - -class AudioStream; -class SeekableAudioStream; - -/** - * Create a new SeekableAudioStream from the MP3 data in the given stream. - * Allows for seeking (which is why we require a SeekableReadStream). - * - * @param stream the SeekableReadStream from which to read the MP3 data - * @param disposeAfterUse whether to delete the stream after use - * @return a new SeekableAudioStream, or NULL, if an error occurred - */ -SeekableAudioStream *makeMP3Stream( - Common::SeekableReadStream *stream, - DisposeAfterUse::Flag disposeAfterUse); - -} // End of namespace Audio - -#endif // #ifdef USE_MAD -#endif // #ifndef SOUND_MP3_H diff --git a/sound/decoders/raw.cpp b/sound/decoders/raw.cpp deleted file mode 100644 index aedddbf6c4..0000000000 --- a/sound/decoders/raw.cpp +++ /dev/null @@ -1,356 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/endian.h" -#include "common/memstream.h" - -#include "sound/audiostream.h" -#include "sound/mixer.h" -#include "sound/decoders/raw.h" - -namespace Audio { - -// This used to be an inline template function, but -// buggy template function handling in MSVC6 forced -// us to go with the macro approach. So far this is -// the only template function that MSVC6 seemed to -// compile incorrectly. Knock on wood. -#define READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, ptr, isLE) \ - ((is16Bit ? (isLE ? READ_LE_UINT16(ptr) : READ_BE_UINT16(ptr)) : (*ptr << 8)) ^ (isUnsigned ? 0x8000 : 0)) - - -#pragma mark - -#pragma mark --- RawStream --- -#pragma mark - - -/** - * This is a stream, which allows for playing raw PCM data from a stream. - * It also features playback of multiple blocks from a given stream. - */ -template<bool is16Bit, bool isUnsigned, bool isLE> -class RawStream : public SeekableAudioStream { -public: - RawStream(int rate, bool stereo, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream, const RawStreamBlockList &blocks) - : _rate(rate), _isStereo(stereo), _playtime(0, rate), _stream(stream), _disposeAfterUse(disposeStream), _blocks(blocks), _curBlock(_blocks.begin()), _blockLeft(0), _buffer(0) { - - assert(_blocks.size() > 0); - - // Setup our buffer for readBuffer - _buffer = new byte[kSampleBufferLength * (is16Bit ? 2 : 1)]; - assert(_buffer); - - // Set current buffer state, playing first block - _stream->seek(_curBlock->pos, SEEK_SET); - - // In case of an error we will stop (or rather - // not start) stream playback. - if (_stream->err()) { - _blockLeft = 0; - _curBlock = _blocks.end(); - } else { - _blockLeft = _curBlock->len; - } - - // Add up length of all blocks in order to caluclate total play time - int32 len = 0; - for (RawStreamBlockList::const_iterator i = _blocks.begin(); i != _blocks.end(); ++i) { - assert(i->len % (_isStereo ? 2 : 1) == 0); - len += i->len; - } - - _playtime = Timestamp(0, len / (_isStereo ? 2 : 1), rate); - } - - ~RawStream() { - if (_disposeAfterUse == DisposeAfterUse::YES) - delete _stream; - - delete[] _buffer; - } - - int readBuffer(int16 *buffer, const int numSamples); - - bool isStereo() const { return _isStereo; } - bool endOfData() const { return (_curBlock == _blocks.end()) && (_blockLeft == 0); } - - int getRate() const { return _rate; } - Timestamp getLength() const { return _playtime; } - - bool seek(const Timestamp &where); -private: - const int _rate; ///< Sample rate of stream - const bool _isStereo; ///< Whether this is an stereo stream - Timestamp _playtime; ///< Calculated total play time - Common::SeekableReadStream *_stream; ///< Stream to read data from - const DisposeAfterUse::Flag _disposeAfterUse; ///< Indicates whether the stream object should be deleted when this RawStream is destructed - const RawStreamBlockList _blocks; ///< Audio block list - - RawStreamBlockList::const_iterator _curBlock; ///< Current audio block number - int32 _blockLeft; ///< How many bytes are still left in the current block - - /** - * Advance one block in the stream in case - * the current one is empty. - */ - void updateBlockIfNeeded(); - - byte *_buffer; ///< Buffer used in readBuffer - enum { - /** - * How many samples we can buffer at once. - * - * TODO: Check whether this size suffices - * for systems with slow disk I/O. - */ - kSampleBufferLength = 2048 - }; - - /** - * Fill the temporary sample buffer used in readBuffer. - * - * @param maxSamples Maximum samples to read. - * @return actual count of samples read. - */ - int fillBuffer(int maxSamples); -}; - -template<bool is16Bit, bool isUnsigned, bool isLE> -int RawStream<is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) { - int samplesLeft = numSamples; - - while (samplesLeft > 0) { - // Try to read up to "samplesLeft" samples. - int len = fillBuffer(samplesLeft); - - // In case we were not able to read any samples - // we will stop reading here. - if (!len) - break; - - // Adjust the samples left to read. - samplesLeft -= len; - - // Copy the data to the caller's buffer. - const byte *src = _buffer; - while (len-- > 0) { - *buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, src, isLE); - src += (is16Bit ? 2 : 1); - } - } - - return numSamples - samplesLeft; -} - -template<bool is16Bit, bool isUnsigned, bool isLE> -int RawStream<is16Bit, isUnsigned, isLE>::fillBuffer(int maxSamples) { - int bufferedSamples = 0; - byte *dst = _buffer; - - // We can only read up to "kSampleBufferLength" samples - // so we take this into consideration, when trying to - // read up to maxSamples. - maxSamples = MIN<int>(kSampleBufferLength, maxSamples); - - // We will only read up to maxSamples - while (maxSamples > 0 && !endOfData()) { - // Calculate how many samples we can safely read - // from the current block. - const int len = MIN<int>(maxSamples, _blockLeft); - - // Try to read all the sample data and update the - // destination pointer. - const int bytesRead = _stream->read(dst, len * (is16Bit ? 2 : 1)); - dst += bytesRead; - - // Calculate how many samples we actually read. - const int samplesRead = bytesRead / (is16Bit ? 2 : 1); - - // Update all status variables - bufferedSamples += samplesRead; - maxSamples -= samplesRead; - _blockLeft -= samplesRead; - - // In case of an error we will stop - // stream playback. - if (_stream->err()) { - _blockLeft = 0; - _curBlock = _blocks.end(); - } - - // Advance to the next block in case the current - // one is already finished. - updateBlockIfNeeded(); - } - - return bufferedSamples; -} - -template<bool is16Bit, bool isUnsigned, bool isLE> -void RawStream<is16Bit, isUnsigned, isLE>::updateBlockIfNeeded() { - // Have we now finished this block? If so, read the next block - if (_blockLeft == 0 && _curBlock != _blocks.end()) { - // Next block - ++_curBlock; - - // Check whether we reached the end of the stream - // yet. In case we did not do this, we will just - // setup the next block as new block. - if (_curBlock != _blocks.end()) { - _stream->seek(_curBlock->pos, SEEK_SET); - - // In case of an error we will stop - // stream playback. - if (_stream->err()) { - _blockLeft = 0; - _curBlock = _blocks.end(); - } else { - _blockLeft = _curBlock->len; - } - } - } -} - -template<bool is16Bit, bool isUnsigned, bool isLE> -bool RawStream<is16Bit, isUnsigned, isLE>::seek(const Timestamp &where) { - _blockLeft = 0; - _curBlock = _blocks.end(); - - if (where > _playtime) - return false; - - const uint32 seekSample = convertTimeToStreamPos(where, getRate(), isStereo()).totalNumberOfFrames(); - uint32 curSample = 0; - - // Search for the disk block in which the specific sample is placed - for (_curBlock = _blocks.begin(); _curBlock != _blocks.end(); ++_curBlock) { - uint32 nextBlockSample = curSample + _curBlock->len; - - if (nextBlockSample > seekSample) - break; - - curSample = nextBlockSample; - } - - if (_curBlock == _blocks.end()) { - return ((seekSample - curSample) == 0); - } else { - const uint32 offset = seekSample - curSample; - - _stream->seek(_curBlock->pos + offset * (is16Bit ? 2 : 1), SEEK_SET); - - // In case of an error we will stop - // stream playback. - if (_stream->err()) { - _blockLeft = 0; - _curBlock = _blocks.end(); - } else { - _blockLeft = _curBlock->len - offset; - } - - return true; - } -} - -#pragma mark - -#pragma mark --- Raw stream factories --- -#pragma mark - - -/* In the following, we use preprocessor / macro tricks to simplify the code - * which instantiates the input streams. We used to use template functions for - * this, but MSVC6 / EVC 3-4 (used for WinCE builds) are extremely buggy when it - * comes to this feature of C++... so as a compromise we use macros to cut down - * on the (source) code duplication a bit. - * So while normally macro tricks are said to make maintenance harder, in this - * particular case it should actually help it :-) - */ - -#define MAKE_RAW_STREAM(UNSIGNED) \ - if (is16Bit) { \ - if (isLE) \ - return new RawStream<true, UNSIGNED, true>(rate, isStereo, disposeAfterUse, stream, blockList); \ - else \ - return new RawStream<true, UNSIGNED, false>(rate, isStereo, disposeAfterUse, stream, blockList); \ - } else \ - return new RawStream<false, UNSIGNED, false>(rate, isStereo, disposeAfterUse, stream, blockList) - -SeekableAudioStream *makeRawStream(Common::SeekableReadStream *stream, - const RawStreamBlockList &blockList, - int rate, - byte flags, - DisposeAfterUse::Flag disposeAfterUse) { - const bool isStereo = (flags & Audio::FLAG_STEREO) != 0; - const bool is16Bit = (flags & Audio::FLAG_16BITS) != 0; - const bool isUnsigned = (flags & Audio::FLAG_UNSIGNED) != 0; - const bool isLE = (flags & Audio::FLAG_LITTLE_ENDIAN) != 0; - - if (blockList.empty()) { - warning("Empty block list passed to makeRawStream"); - if (disposeAfterUse == DisposeAfterUse::YES) - delete stream; - return 0; - } - - if (isUnsigned) { - MAKE_RAW_STREAM(true); - } else { - MAKE_RAW_STREAM(false); - } -} - -SeekableAudioStream *makeRawStream(Common::SeekableReadStream *stream, - int rate, byte flags, - DisposeAfterUse::Flag disposeAfterUse) { - RawStreamBlockList blocks; - RawStreamBlock block; - block.pos = 0; - - const bool isStereo = (flags & Audio::FLAG_STEREO) != 0; - const bool is16Bit = (flags & Audio::FLAG_16BITS) != 0; - - assert(stream->size() % ((is16Bit ? 2 : 1) * (isStereo ? 2 : 1)) == 0); - - block.len = stream->size() / (is16Bit ? 2 : 1); - blocks.push_back(block); - - return makeRawStream(stream, blocks, rate, flags, disposeAfterUse); -} - -SeekableAudioStream *makeRawStream(const byte *buffer, uint32 size, - int rate, byte flags, - DisposeAfterUse::Flag disposeAfterUse) { - return makeRawStream(new Common::MemoryReadStream(buffer, size, disposeAfterUse), rate, flags, DisposeAfterUse::YES); -} - -SeekableAudioStream *makeRawDiskStream_OLD(Common::SeekableReadStream *stream, RawStreamBlock *block, int numBlocks, - int rate, byte flags, DisposeAfterUse::Flag disposeStream) { - assert(numBlocks > 0); - RawStreamBlockList blocks; - for (int i = 0; i < numBlocks; ++i) - blocks.push_back(block[i]); - - return makeRawStream(stream, blocks, rate, flags, disposeStream); -} - -} // End of namespace Audio diff --git a/sound/decoders/raw.h b/sound/decoders/raw.h deleted file mode 100644 index 3e9426012c..0000000000 --- a/sound/decoders/raw.h +++ /dev/null @@ -1,153 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#ifndef SOUND_RAW_H -#define SOUND_RAW_H - -#include "common/scummsys.h" -#include "common/types.h" - -#include "common/list.h" - - -namespace Common { class SeekableReadStream; } - - -namespace Audio { - -class AudioStream; -class SeekableAudioStream; - -/** - * Various flags which can be bit-ORed and then passed to - * makeRawStream and some other AudioStream factories - * to control their behavior. - * - * Engine authors are advised not to rely on a certain value or - * order of these flags (in particular, do not store them verbatim - * in savestates). - */ -enum RawFlags { - /** unsigned samples (default: signed) */ - FLAG_UNSIGNED = 1 << 0, - - /** sound is 16 bits wide (default: 8bit) */ - FLAG_16BITS = 1 << 1, - - /** samples are little endian (default: big endian) */ - FLAG_LITTLE_ENDIAN = 1 << 2, - - /** sound is in stereo (default: mono) */ - FLAG_STEREO = 1 << 3 -}; - - -/** - * Struct used to define the audio data to be played by a RawStream. - */ -struct RawStreamBlock { - int32 pos; ///< Position in stream of the block (in bytes of course!) - int32 len; ///< Length of the block (in raw samples, not sample pairs!) -}; - -/** - * List containing all blocks of a raw stream. - * @see RawStreamBlock - */ -typedef Common::List<RawStreamBlock> RawStreamBlockList; - -/** - * Creates an audio stream, which plays from the given buffer. - * - * @param buffer Buffer to play from. - * @param size Size of the buffer in bytes. - * @param rate Rate of the sound data. - * @param flags Audio flags combination. - * @see RawFlags - * @param disposeAfterUse Whether to free the buffer after use (with free!). - * @return The new SeekableAudioStream (or 0 on failure). - */ -SeekableAudioStream *makeRawStream(const byte *buffer, uint32 size, - int rate, byte flags, - DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); - -/** - * Creates an audio stream, which plays from the given stream. - * - * @param stream Stream object to play from. - * @param rate Rate of the sound data. - * @param flags Audio flags combination. - * @see RawFlags - * @param disposeAfterUse Whether to delete the stream after use. - * @return The new SeekableAudioStream (or 0 on failure). - */ -SeekableAudioStream *makeRawStream(Common::SeekableReadStream *stream, - int rate, byte flags, - DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); - -/** - * Creates an audio stream, which plays from the given stream. - * - * @param stream Stream object to play from. - * @param blockList List of blocks to play. - * @see RawDiskStreamAudioBlock - * @see RawStreamBlockList - * @param rate Rate of the sound data. - * @param flags Audio flags combination. - * @see RawFlags - * @param disposeAfterUse Whether to delete the stream after use. - * @return The new SeekableAudioStream (or 0 on failure). - */ -SeekableAudioStream *makeRawStream(Common::SeekableReadStream *stream, - const RawStreamBlockList &blockList, - int rate, - byte flags, - DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); - -/** - * NOTE: - * This API is considered deprecated. - * - * Creates a audio stream, which plays from given stream. - * - * @param stream Stream to play from - * @param block Pointer to an RawStreamBlock array - * @see RawStreamBlock - * @param numBlocks Number of blocks. - * @param rate The rate - * @param flags Flags combination. - * @see RawFlags - * @param disposeStream Whether the "stream" object should be destroyed after playback. - * @return The new SeekableAudioStream (or 0 on failure). - */ -SeekableAudioStream *makeRawDiskStream_OLD(Common::SeekableReadStream *stream, - RawStreamBlock *block, int numBlocks, - int rate, byte flags, - DisposeAfterUse::Flag disposeStream); - - -} // End of namespace Audio - -#endif diff --git a/sound/decoders/vag.cpp b/sound/decoders/vag.cpp deleted file mode 100644 index d3f0811f2b..0000000000 --- a/sound/decoders/vag.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "sound/decoders/vag.h" -#include "sound/audiostream.h" -#include "common/stream.h" - -namespace Audio { - -class VagStream : public Audio::RewindableAudioStream { -public: - VagStream(Common::SeekableReadStream *stream, int rate); - ~VagStream(); - - bool isStereo() const { return false; } - bool endOfData() const { return _stream->pos() == _stream->size(); } - int getRate() const { return _rate; } - int readBuffer(int16 *buffer, const int numSamples); - - bool rewind(); -private: - Common::SeekableReadStream *_stream; - - byte _predictor; - double _samples[28]; - byte _samplesRemaining; - int _rate; - double _s1, _s2; -}; - -VagStream::VagStream(Common::SeekableReadStream *stream, int rate) : _stream(stream) { - _samplesRemaining = 0; - _predictor = 0; - _s1 = _s2 = 0.0; - _rate = rate; -} - - -VagStream::~VagStream() { - delete _stream; -} - -static const double s_vagDataTable[5][2] = - { - { 0.0, 0.0 }, - { 60.0 / 64.0, 0.0 }, - { 115.0 / 64.0, -52.0 / 64.0 }, - { 98.0 / 64.0, -55.0 / 64.0 }, - { 122.0 / 64.0, -60.0 / 64.0 } - }; - -int VagStream::readBuffer(int16 *buffer, const int numSamples) { - int32 samplesDecoded = 0; - - if (_samplesRemaining) { - byte i = 0; - - for (i = 28 - _samplesRemaining; i < 28 && samplesDecoded < numSamples; i++) { - _samples[i] = _samples[i] + _s1 * s_vagDataTable[_predictor][0] + _s2 * s_vagDataTable[_predictor][1]; - _s2 = _s1; - _s1 = _samples[i]; - int16 d = (int) (_samples[i] + 0.5); - buffer[samplesDecoded] = d; - samplesDecoded++; - } - -#if 0 - assert(i == 28); // We're screwed if this fails :P -#endif - // This might mean the file is corrupted, or that the stream has - // been closed. - if (i != 28) return 0; - - _samplesRemaining = 0; - } - - while (samplesDecoded < numSamples) { - byte i = 0; - - _predictor = _stream->readByte(); - byte shift = _predictor & 0xf; - _predictor >>= 4; - - if (_stream->readByte() == 7) - return samplesDecoded; - - for (i = 0; i < 28; i += 2) { - byte d = _stream->readByte(); - int16 s = (d & 0xf) << 12; - if (s & 0x8000) - s |= 0xffff0000; - _samples[i] = (double)(s >> shift); - s = (d & 0xf0) << 8; - if (s & 0x8000) - s |= 0xffff0000; - _samples[i + 1] = (double)(s >> shift); - } - - for (i = 0; i < 28 && samplesDecoded < numSamples; i++) { - _samples[i] = _samples[i] + _s1 * s_vagDataTable[_predictor][0] + _s2 * s_vagDataTable[_predictor][1]; - _s2 = _s1; - _s1 = _samples[i]; - int16 d = (int) (_samples[i] + 0.5); - buffer[samplesDecoded] = d; - samplesDecoded++; - } - - if (i != 27) - _samplesRemaining = 28 - i; - } - - return samplesDecoded; -} - -bool VagStream::rewind() { - _stream->seek(0); - _samplesRemaining = 0; - _predictor = 0; - _s1 = _s2 = 0.0; - - return true; -} - -RewindableAudioStream *makeVagStream(Common::SeekableReadStream *stream, int rate) { - return new VagStream(stream, rate); -} - -} diff --git a/sound/decoders/vag.h b/sound/decoders/vag.h deleted file mode 100644 index cdf91a8ea1..0000000000 --- a/sound/decoders/vag.h +++ /dev/null @@ -1,60 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/** - * @file - * Sound decoder used in engines: - * - sword1 (PSX port of the game) - * - sword2 (PSX port of the game) - * - tinsel (PSX port of the game) - */ - -#ifndef SOUND_VAG_H -#define SOUND_VAG_H - -namespace Common { - class SeekableReadStream; -} - -namespace Audio { - -class AudioStream; -class RewindableAudioStream; - -/** - * Takes an input stream containing Vag sound data and creates - * an RewindableAudioStream from that. - * - * @param stream the SeekableReadStream from which to read the ADPCM data - * @param rate the sampling rate - * @return a new RewindableAudioStream, or NULL, if an error occurred - */ -RewindableAudioStream *makeVagStream( - Common::SeekableReadStream *stream, - int rate = 11025); - -} // End of namespace Sword1 - -#endif diff --git a/sound/decoders/voc.cpp b/sound/decoders/voc.cpp deleted file mode 100644 index e9af7ece3f..0000000000 --- a/sound/decoders/voc.cpp +++ /dev/null @@ -1,403 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/debug.h" -#include "common/endian.h" -#include "common/util.h" -#include "common/stream.h" - -#include "sound/audiostream.h" -#include "sound/mixer.h" -#include "sound/decoders/raw.h" -#include "sound/decoders/voc.h" - - -namespace Audio { - -int getSampleRateFromVOCRate(int vocSR) { - if (vocSR == 0xa5 || vocSR == 0xa6) { - return 11025; - } else if (vocSR == 0xd2 || vocSR == 0xd3) { - return 22050; - } else { - int sr = 1000000L / (256L - vocSR); - // inexact sampling rates occur e.g. in the kitchen in Monkey Island, - // very easy to reach right from the start of the game. - //warning("inexact sample rate used: %i (0x%x)", sr, vocSR); - return sr; - } -} - -static byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate, int &loops, int &begin_loop, int &end_loop) { - VocFileHeader fileHeader; - - debug(2, "loadVOCFromStream"); - - if (stream.read(&fileHeader, 8) != 8) - goto invalid; - - if (!memcmp(&fileHeader, "VTLK", 4)) { - if (stream.read(&fileHeader, sizeof(VocFileHeader)) != sizeof(VocFileHeader)) - goto invalid; - } else if (!memcmp(&fileHeader, "Creative", 8)) { - if (stream.read(((byte *)&fileHeader) + 8, sizeof(VocFileHeader) - 8) != sizeof(VocFileHeader) - 8) - goto invalid; - } else { - invalid:; - warning("loadVOCFromStream: Invalid header"); - return NULL; - } - - if (memcmp(fileHeader.desc, "Creative Voice File", 19) != 0) - error("loadVOCFromStream: Invalid header"); - if (fileHeader.desc[19] != 0x1A) - debug(3, "loadVOCFromStream: Partially invalid header"); - - int32 offset = FROM_LE_16(fileHeader.datablock_offset); - int16 version = FROM_LE_16(fileHeader.version); - int16 code = FROM_LE_16(fileHeader.id); - assert(offset == sizeof(VocFileHeader)); - // 0x100 is an invalid VOC version used by German version of DOTT (Disk) and - // French version of Simon the Sorcerer 2 (CD) - assert(version == 0x010A || version == 0x0114 || version == 0x0100); - assert(code == ~version + 0x1234); - - int len; - byte *ret_sound = 0; - size = 0; - begin_loop = 0; - end_loop = 0; - - while ((code = stream.readByte())) { - len = stream.readByte(); - len |= stream.readByte() << 8; - len |= stream.readByte() << 16; - - debug(2, "Block code %d, len %d", code, len); - - switch (code) { - case 1: - case 9: { - int packing; - if (code == 1) { - int time_constant = stream.readByte(); - packing = stream.readByte(); - len -= 2; - rate = getSampleRateFromVOCRate(time_constant); - } else { - rate = stream.readUint32LE(); - int bits = stream.readByte(); - int channels = stream.readByte(); - if (bits != 8 || channels != 1) { - warning("Unsupported VOC file format (%d bits per sample, %d channels)", bits, channels); - break; - } - packing = stream.readUint16LE(); - stream.readUint32LE(); - len -= 12; - } - debug(9, "VOC Data Block: %d, %d, %d", rate, packing, len); - if (packing == 0) { - if (size) { - ret_sound = (byte *)realloc(ret_sound, size + len); - } else { - ret_sound = (byte *)malloc(len); - } - stream.read(ret_sound + size, len); - size += len; - begin_loop = size; - end_loop = size; - } else { - warning("VOC file packing %d unsupported", packing); - } - } break; - case 3: // silence - // occur with a few Igor sounds, voc file starts with a silence block with a - // frequency different from the data block. Just ignore fow now (implementing - // it wouldn't make a big difference anyway...) - assert(len == 3); - stream.readUint16LE(); - stream.readByte(); - break; - case 6: // begin of loop - assert(len == 2); - loops = stream.readUint16LE(); - break; - case 7: // end of loop - assert(len == 0); - break; - case 8: { // "Extended" - // This occures in the LoL Intro demo. - // This block overwrites the next parameters of a block 1 "Sound data". - // To assure we never get any bad data here, we will assert in case - // this tries to define a stereo sound block or tries to use something - // different than 8bit unsigned sound data. - // TODO: Actually we would need to check the frequency divisor (the - // first word) here too. It is used in the following equation: - // sampleRate = 256000000/(channels * (65536 - frequencyDivisor)) - assert(len == 4); - stream.readUint16LE(); - uint8 codec = stream.readByte(); - uint8 channels = stream.readByte() + 1; - assert(codec == 0 && channels == 1); - } break; - default: - warning("Unhandled code %d in VOC file (len %d)", code, len); - return ret_sound; - } - } - debug(4, "VOC Data Size : %d", size); - return ret_sound; -} - -byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate) { - int loops, begin_loop, end_loop; - return loadVOCFromStream(stream, size, rate, loops, begin_loop, end_loop); -} - - -#ifdef STREAM_AUDIO_FROM_DISK - -int parseVOCFormat(Common::SeekableReadStream& stream, RawStreamBlock* block, int &rate, int &loops, int &begin_loop, int &end_loop) { - VocFileHeader fileHeader; - int currentBlock = 0; - int size = 0; - - debug(2, "parseVOCFormat"); - - if (stream.read(&fileHeader, 8) != 8) - goto invalid; - - if (!memcmp(&fileHeader, "VTLK", 4)) { - if (stream.read(&fileHeader, sizeof(VocFileHeader)) != sizeof(VocFileHeader)) - goto invalid; - } else if (!memcmp(&fileHeader, "Creative", 8)) { - if (stream.read(((byte *)&fileHeader) + 8, sizeof(VocFileHeader) - 8) != sizeof(VocFileHeader) - 8) - goto invalid; - } else { - invalid:; - warning("loadVOCFromStream: Invalid header"); - return 0; - } - - if (memcmp(fileHeader.desc, "Creative Voice File", 19) != 0) - error("loadVOCFromStream: Invalid header"); - if (fileHeader.desc[19] != 0x1A) - debug(3, "loadVOCFromStream: Partially invalid header"); - - int32 offset = FROM_LE_16(fileHeader.datablock_offset); - int16 version = FROM_LE_16(fileHeader.version); - int16 code = FROM_LE_16(fileHeader.id); - assert(offset == sizeof(VocFileHeader)); - // 0x100 is an invalid VOC version used by German version of DOTT (Disk) and - // French version of Simon the Sorcerer 2 (CD) - assert(version == 0x010A || version == 0x0114 || version == 0x0100); - assert(code == ~version + 0x1234); - - int len; - size = 0; - begin_loop = 0; - end_loop = 0; - - while ((code = stream.readByte())) { - len = stream.readByte(); - len |= stream.readByte() << 8; - len |= stream.readByte() << 16; - - debug(2, "Block code %d, len %d", code, len); - - switch (code) { - case 1: - case 9: { - int packing; - if (code == 1) { - int time_constant = stream.readByte(); - packing = stream.readByte(); - len -= 2; - rate = getSampleRateFromVOCRate(time_constant); - } else { - rate = stream.readUint32LE(); - int bits = stream.readByte(); - int channels = stream.readByte(); - if (bits != 8 || channels != 1) { - warning("Unsupported VOC file format (%d bits per sample, %d channels)", bits, channels); - break; - } - packing = stream.readUint16LE(); - stream.readUint32LE(); - len -= 12; - } - debug(9, "VOC Data Block: %d, %d, %d", rate, packing, len); - if (packing == 0) { - - // Found a data block - so add it to the block list - block[currentBlock].pos = stream.pos(); - block[currentBlock].len = len; - currentBlock++; - - stream.seek(len, SEEK_CUR); - - size += len; - begin_loop = size; - end_loop = size; - } else { - warning("VOC file packing %d unsupported", packing); - } - } break; - case 3: // silence - // occur with a few Igor sounds, voc file starts with a silence block with a - // frequency different from the data block. Just ignore fow now (implementing - // it wouldn't make a big difference anyway...) - assert(len == 3); - stream.readUint16LE(); - stream.readByte(); - break; - case 6: // begin of loop - assert(len == 2); - loops = stream.readUint16LE(); - break; - case 7: // end of loop - assert(len == 0); - break; - case 8: // "Extended" - // This occures in the LoL Intro demo. This block can usually be used to create stereo - // sound, but the LoL intro has only an empty block, thus this dummy implementation will - // work. - assert(len == 4); - stream.readUint16LE(); - stream.readByte(); - stream.readByte(); - break; - default: - warning("Unhandled code %d in VOC file (len %d)", code, len); - return 0; - } - } - debug(4, "VOC Data Size : %d", size); - return currentBlock; -} - -AudioStream *makeVOCDiskStream(Common::SeekableReadStream *stream, byte flags, DisposeAfterUse::Flag disposeAfterUse) { - const int MAX_AUDIO_BLOCKS = 256; - - RawStreamBlock *block = new RawStreamBlock[MAX_AUDIO_BLOCKS]; - int rate, loops, begin_loop, end_loop; - - int numBlocks = parseVOCFormat(*stream, block, rate, loops, begin_loop, end_loop); - - AudioStream *audioStream = 0; - - // Create an audiostream from the data. Note the numBlocks may be 0, - // e.g. when invalid data is encountered. See bug #2890038. - if (numBlocks) - audioStream = makeRawDiskStream_OLD(stream, block, numBlocks, rate, flags, disposeAfterUse/*, begin_loop, end_loop*/); - - delete[] block; - - return audioStream; -} - -SeekableAudioStream *makeVOCDiskStreamNoLoop(Common::SeekableReadStream *stream, byte flags, DisposeAfterUse::Flag disposeAfterUse) { - const int MAX_AUDIO_BLOCKS = 256; - - RawStreamBlock *block = new RawStreamBlock[MAX_AUDIO_BLOCKS]; - int rate, loops, begin_loop, end_loop; - - int numBlocks = parseVOCFormat(*stream, block, rate, loops, begin_loop, end_loop); - - SeekableAudioStream *audioStream = 0; - - // Create an audiostream from the data. Note the numBlocks may be 0, - // e.g. when invalid data is encountered. See bug #2890038. - if (numBlocks) - audioStream = makeRawDiskStream_OLD(stream, block, numBlocks, rate, flags, disposeAfterUse); - - delete[] block; - - return audioStream; -} - -#endif - - -AudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flags, uint loopStart, uint loopEnd, DisposeAfterUse::Flag disposeAfterUse) { -#ifdef STREAM_AUDIO_FROM_DISK - return makeVOCDiskStream(stream, flags, disposeAfterUse); -#else - int size, rate; - - byte *data = loadVOCFromStream(*stream, size, rate); - - if (!data) { - if (disposeAfterUse == DisposeAfterUse::YES) - delete stream; - return 0; - } - - SeekableAudioStream *s = Audio::makeRawStream(data, size, rate, flags); - - if (loopStart != loopEnd) { - const bool isStereo = (flags & Audio::FLAG_STEREO) != 0; - const bool is16Bit = (flags & Audio::FLAG_16BITS) != 0; - - if (loopEnd == 0) - loopEnd = size; - assert(loopStart <= loopEnd); - assert(loopEnd <= (uint)size); - - // Verify the buffer sizes are sane - if (is16Bit && isStereo) - assert((loopStart & 3) == 0 && (loopEnd & 3) == 0); - else if (is16Bit || isStereo) - assert((loopStart & 1) == 0 && (loopEnd & 1) == 0); - - const uint32 extRate = s->getRate() * (is16Bit ? 2 : 1) * (isStereo ? 2 : 1); - - return new SubLoopingAudioStream(s, 0, Timestamp(0, loopStart, extRate), Timestamp(0, loopEnd, extRate)); - } else { - return s; - } -#endif -} - -SeekableAudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flags, DisposeAfterUse::Flag disposeAfterUse) { -#ifdef STREAM_AUDIO_FROM_DISK - return makeVOCDiskStreamNoLoop(stream, flags, disposeAfterUse); -#else - int size, rate; - - byte *data = loadVOCFromStream(*stream, size, rate); - - if (!data) { - if (disposeAfterUse == DisposeAfterUse::YES) - delete stream; - return 0; - } - - return makeRawStream(data, size, rate, flags); -#endif -} - -} // End of namespace Audio diff --git a/sound/decoders/voc.h b/sound/decoders/voc.h deleted file mode 100644 index 82cc261f2c..0000000000 --- a/sound/decoders/voc.h +++ /dev/null @@ -1,107 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/** - * @file - * Sound decoder used in engines: - * - agos - * - drascula - * - kyra - * - made - * - saga - * - scumm - * - touche - */ - -#ifndef SOUND_VOC_H -#define SOUND_VOC_H - -#include "common/scummsys.h" -#include "common/types.h" - -namespace Common { class ReadStream; } -namespace Common { class SeekableReadStream; } - -namespace Audio { - -class AudioStream; -class SeekableAudioStream; - - -#include "common/pack-start.h" // START STRUCT PACKING - -struct VocFileHeader { - uint8 desc[20]; - uint16 datablock_offset; - uint16 version; - uint16 id; -} PACKED_STRUCT; - -struct VocBlockHeader { - uint8 blocktype; - uint8 size[3]; - uint8 sr; - uint8 pack; -} PACKED_STRUCT; - -#include "common/pack-end.h" // END STRUCT PACKING - -/** - * Take a sample rate parameter as it occurs in a VOC sound header, and - * return the corresponding sample frequency. - * - * This method has special cases for the standard rates of 11025 and 22050 kHz, - * which due to limitations of the format, cannot be encoded exactly in a VOC - * file. As a consequence, many game files have sound data sampled with those - * rates, but the VOC marks them incorrectly as 11111 or 22222 kHz. This code - * works around that and "unrounds" the sampling rates. - */ -extern int getSampleRateFromVOCRate(int vocSR); - -/** - * Try to load a VOC from the given stream. Returns a pointer to memory - * containing the PCM sample data (allocated with malloc). It is the callers - * responsibility to dellocate that data again later on! Currently this - * function only supports uncompressed raw PCM data. - */ -extern byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate); - -/** - * Try to load a VOC from the given seekable stream and create an AudioStream - * from that data. Currently this function only supports uncompressed raw PCM - * data. Optionally supports (infinite) looping of a portion of the data. - * - * This function uses loadVOCFromStream() internally. - */ -AudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flags = 0, uint loopStart = 0, uint loopEnd = 0, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::NO); - -/** - * This does not use any of the looping features of VOC files! - */ -SeekableAudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flags, DisposeAfterUse::Flag disposeAfterUse); - -} // End of namespace Audio - -#endif diff --git a/sound/decoders/vorbis.cpp b/sound/decoders/vorbis.cpp deleted file mode 100644 index 425eb6b751..0000000000 --- a/sound/decoders/vorbis.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -// Disable symbol overrides for FILE and fseek as those are used in the -// Vorbis headers. -#define FORBIDDEN_SYMBOL_EXCEPTION_FILE -#define FORBIDDEN_SYMBOL_EXCEPTION_fseek - -#include "sound/decoders/vorbis.h" - -#ifdef USE_VORBIS - -#include "common/debug.h" -#include "common/stream.h" -#include "common/util.h" - -#include "sound/audiostream.h" - -#ifdef USE_TREMOR -#if defined(__GP32__) // custom libtremor locations -#include <ivorbisfile.h> -#else -#include <tremor/ivorbisfile.h> -#endif -#else -#include <vorbis/vorbisfile.h> -#endif - - -namespace Audio { - -// These are wrapper functions to allow using a SeekableReadStream object to -// provide data to the OggVorbis_File object. - -static size_t read_stream_wrap(void *ptr, size_t size, size_t nmemb, void *datasource) { - Common::SeekableReadStream *stream = (Common::SeekableReadStream *)datasource; - - uint32 result = stream->read(ptr, size * nmemb); - - return result / size; -} - -static int seek_stream_wrap(void *datasource, ogg_int64_t offset, int whence) { - Common::SeekableReadStream *stream = (Common::SeekableReadStream *)datasource; - stream->seek((int32)offset, whence); - return stream->pos(); -} - -static int close_stream_wrap(void *datasource) { - // Do nothing -- we leave it up to the VorbisStream to free memory as appropriate. - return 0; -} - -static long tell_stream_wrap(void *datasource) { - Common::SeekableReadStream *stream = (Common::SeekableReadStream *)datasource; - return stream->pos(); -} - -static ov_callbacks g_stream_wrap = { - read_stream_wrap, seek_stream_wrap, close_stream_wrap, tell_stream_wrap -}; - - - -#pragma mark - -#pragma mark --- Ogg Vorbis stream --- -#pragma mark - - - -class VorbisStream : public SeekableAudioStream { -protected: - Common::SeekableReadStream *_inStream; - DisposeAfterUse::Flag _disposeAfterUse; - - bool _isStereo; - int _rate; - - Timestamp _length; - - OggVorbis_File _ovFile; - - int16 _buffer[4096]; - const int16 *_bufferEnd; - const int16 *_pos; - -public: - // startTime / duration are in milliseconds - VorbisStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose); - ~VorbisStream(); - - int readBuffer(int16 *buffer, const int numSamples); - - bool endOfData() const { return _pos >= _bufferEnd; } - bool isStereo() const { return _isStereo; } - int getRate() const { return _rate; } - - bool seek(const Timestamp &where); - Timestamp getLength() const { return _length; } -protected: - bool refill(); -}; - -VorbisStream::VorbisStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose) : - _inStream(inStream), - _disposeAfterUse(dispose), - _length(0, 1000), - _bufferEnd(_buffer + ARRAYSIZE(_buffer)) { - - int res = ov_open_callbacks(inStream, &_ovFile, NULL, 0, g_stream_wrap); - if (res < 0) { - warning("Could not create Vorbis stream (%d)", res); - _pos = _bufferEnd; - return; - } - - // Read in initial data - if (!refill()) - return; - - // Setup some header information - _isStereo = ov_info(&_ovFile, -1)->channels >= 2; - _rate = ov_info(&_ovFile, -1)->rate; - -#ifdef USE_TREMOR - _length = Timestamp(ov_time_total(&_ovFile, -1), getRate()); -#else - _length = Timestamp(uint32(ov_time_total(&_ovFile, -1) * 1000.0), getRate()); -#endif -} - -VorbisStream::~VorbisStream() { - ov_clear(&_ovFile); - if (_disposeAfterUse == DisposeAfterUse::YES) - delete _inStream; -} - -int VorbisStream::readBuffer(int16 *buffer, const int numSamples) { - int samples = 0; - while (samples < numSamples && _pos < _bufferEnd) { - const int len = MIN(numSamples - samples, (int)(_bufferEnd - _pos)); - memcpy(buffer, _pos, len * 2); - buffer += len; - _pos += len; - samples += len; - if (_pos >= _bufferEnd) { - if (!refill()) - break; - } - } - return samples; -} - -bool VorbisStream::seek(const Timestamp &where) { - // Vorbisfile uses the sample pair number, thus we always use "false" for the isStereo parameter - // of the convertTimeToStreamPos helper. - int res = ov_pcm_seek(&_ovFile, convertTimeToStreamPos(where, getRate(), false).totalNumberOfFrames()); - if (res) { - warning("Error seeking in Vorbis stream (%d)", res); - _pos = _bufferEnd; - return false; - } - - return refill(); -} - -bool VorbisStream::refill() { - // Read the samples - uint len_left = sizeof(_buffer); - char *read_pos = (char *)_buffer; - - while (len_left > 0) { - long result; - -#ifdef USE_TREMOR - // Tremor ov_read() always returns data as signed 16 bit interleaved PCM - // in host byte order. As such, it does not take arguments to request - // specific signedness, byte order or bit depth as in Vorbisfile. - result = ov_read(&_ovFile, read_pos, len_left, - NULL); -#else -#ifdef SCUMM_BIG_ENDIAN - result = ov_read(&_ovFile, read_pos, len_left, - 1, - 2, // 16 bit - 1, // signed - NULL); -#else - result = ov_read(&_ovFile, read_pos, len_left, - 0, - 2, // 16 bit - 1, // signed - NULL); -#endif -#endif - if (result == OV_HOLE) { - // Possibly recoverable, just warn about it - warning("Corrupted data in Vorbis file"); - } else if (result == 0) { - //warning("End of file while reading from Vorbis file"); - //_pos = _bufferEnd; - //return false; - break; - } else if (result < 0) { - warning("Error reading from Vorbis stream (%d)", int(result)); - _pos = _bufferEnd; - // Don't delete it yet, that causes problems in - // the CD player emulation code. - return false; - } else { - len_left -= result; - read_pos += result; - } - } - - _pos = _buffer; - _bufferEnd = (int16 *)read_pos; - - return true; -} - - -#pragma mark - -#pragma mark --- Ogg Vorbis factory functions --- -#pragma mark - - -SeekableAudioStream *makeVorbisStream( - Common::SeekableReadStream *stream, - DisposeAfterUse::Flag disposeAfterUse) { - SeekableAudioStream *s = new VorbisStream(stream, disposeAfterUse); - if (s && s->endOfData()) { - delete s; - return 0; - } else { - return s; - } -} - -} // End of namespace Audio - -#endif // #ifdef USE_VORBIS diff --git a/sound/decoders/vorbis.h b/sound/decoders/vorbis.h deleted file mode 100644 index 7cc395cccb..0000000000 --- a/sound/decoders/vorbis.h +++ /dev/null @@ -1,75 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/** - * @file - * Sound decoder used in engines: - * - agos - * - draci - * - kyra - * - m4 - * - queen - * - saga - * - sci - * - scumm - * - sword1 - * - sword2 - * - touche - * - tucker - */ - -#ifndef SOUND_VORBIS_H -#define SOUND_VORBIS_H - -#include "common/scummsys.h" -#include "common/types.h" - -#ifdef USE_VORBIS - -namespace Common { - class SeekableReadStream; -} - -namespace Audio { - -class AudioStream; -class SeekableAudioStream; - -/** - * Create a new SeekableAudioStream from the Ogg Vorbis data in the given stream. - * Allows for seeking (which is why we require a SeekableReadStream). - * - * @param stream the SeekableReadStream from which to read the Ogg Vorbis data - * @param disposeAfterUse whether to delete the stream after use - * @return a new SeekableAudioStream, or NULL, if an error occurred - */ -SeekableAudioStream *makeVorbisStream( - Common::SeekableReadStream *stream, - DisposeAfterUse::Flag disposeAfterUse); - -} // End of namespace Audio - -#endif // #ifdef USE_VORBIS -#endif // #ifndef SOUND_VORBIS_H diff --git a/sound/decoders/wave.cpp b/sound/decoders/wave.cpp deleted file mode 100644 index fcaace5301..0000000000 --- a/sound/decoders/wave.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/debug.h" -#include "common/util.h" -#include "common/stream.h" - -#include "sound/audiostream.h" -#include "sound/mixer.h" -#include "sound/decoders/wave.h" -#include "sound/decoders/adpcm.h" -#include "sound/decoders/raw.h" - -namespace Audio { - -bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags, uint16 *wavType, int *blockAlign_) { - const int32 initialPos = stream.pos(); - byte buf[4+1]; - - buf[4] = 0; - - stream.read(buf, 4); - if (memcmp(buf, "RIFF", 4) != 0) { - warning("getWavInfo: No 'RIFF' header"); - return false; - } - - int32 wavLength = stream.readUint32LE(); - - stream.read(buf, 4); - if (memcmp(buf, "WAVE", 4) != 0) { - warning("getWavInfo: No 'WAVE' header"); - return false; - } - - stream.read(buf, 4); - if (memcmp(buf, "fmt ", 4) != 0) { - warning("getWavInfo: No 'fmt' header"); - return false; - } - - uint32 fmtLength = stream.readUint32LE(); - if (fmtLength < 16) { - // A valid fmt chunk always contains at least 16 bytes - warning("getWavInfo: 'fmt' header is too short"); - return false; - } - - // Next comes the "type" field of the fmt header. Some typical - // values for it: - // 1 -> uncompressed PCM - // 17 -> IMA ADPCM compressed WAVE - // See <http://www.saettler.com/RIFFNEW/RIFFNEW.htm> for a more complete - // list of common WAVE compression formats... - uint16 type = stream.readUint16LE(); // == 1 for PCM data - uint16 numChannels = stream.readUint16LE(); // 1 for mono, 2 for stereo - uint32 samplesPerSec = stream.readUint32LE(); // in Hz - uint32 avgBytesPerSec = stream.readUint32LE(); // == SampleRate * NumChannels * BitsPerSample/8 - - uint16 blockAlign = stream.readUint16LE(); // == NumChannels * BitsPerSample/8 - uint16 bitsPerSample = stream.readUint16LE(); // 8, 16 ... - // 8 bit data is unsigned, 16 bit data signed - - - if (wavType != 0) - *wavType = type; - - if (blockAlign_ != 0) - *blockAlign_ = blockAlign; -#if 0 - debug("WAVE information:"); - debug(" total size: %d", wavLength); - debug(" fmt size: %d", fmtLength); - debug(" type: %d", type); - debug(" numChannels: %d", numChannels); - debug(" samplesPerSec: %d", samplesPerSec); - debug(" avgBytesPerSec: %d", avgBytesPerSec); - debug(" blockAlign: %d", blockAlign); - debug(" bitsPerSample: %d", bitsPerSample); -#endif - - if (type != 1 && type != 2 && type != 17) { - warning("getWavInfo: only PCM, MS ADPCM or IMA ADPCM data is supported (type %d)", type); - return false; - } - - if (blockAlign != numChannels * bitsPerSample / 8 && type != 2) { - debug(0, "getWavInfo: blockAlign is invalid"); - } - - if (avgBytesPerSec != samplesPerSec * blockAlign && type != 2) { - debug(0, "getWavInfo: avgBytesPerSec is invalid"); - } - - // Prepare the return values. - rate = samplesPerSec; - - flags = 0; - if (bitsPerSample == 8) // 8 bit data is unsigned - flags |= Audio::FLAG_UNSIGNED; - else if (bitsPerSample == 16) // 16 bit data is signed little endian - flags |= (Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN); - else if (bitsPerSample == 4 && (type == 2 || type == 17)) - flags |= Audio::FLAG_16BITS; - else { - warning("getWavInfo: unsupported bitsPerSample %d", bitsPerSample); - return false; - } - - if (numChannels == 2) - flags |= Audio::FLAG_STEREO; - else if (numChannels != 1) { - warning("getWavInfo: unsupported number of channels %d", numChannels); - return false; - } - - // It's almost certainly a WAV file, but we still need to find its - // 'data' chunk. - - // Skip over the rest of the fmt chunk. - int offset = fmtLength - 16; - - do { - stream.seek(offset, SEEK_CUR); - if (stream.pos() >= initialPos + wavLength + 8) { - warning("getWavInfo: Can't find 'data' chunk"); - return false; - } - stream.read(buf, 4); - offset = stream.readUint32LE(); - -#if 0 - debug(" found a '%s' tag of size %d", buf, offset); -#endif - } while (memcmp(buf, "data", 4) != 0); - - // Stream now points at 'offset' bytes of sample data... - size = offset; - - return true; -} - -RewindableAudioStream *makeWAVStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) { - int size, rate; - byte flags; - uint16 type; - int blockAlign; - - if (!loadWAVFromStream(*stream, size, rate, flags, &type, &blockAlign)) { - if (disposeAfterUse == DisposeAfterUse::YES) - delete stream; - return 0; - } - - if (type == 17) // MS IMA ADPCM - return makeADPCMStream(stream, disposeAfterUse, size, Audio::kADPCMMSIma, rate, (flags & Audio::FLAG_STEREO) ? 2 : 1, blockAlign); - else if (type == 2) // MS ADPCM - return makeADPCMStream(stream, disposeAfterUse, size, Audio::kADPCMMS, rate, (flags & Audio::FLAG_STEREO) ? 2 : 1, blockAlign); - - // Raw PCM. Just read everything at once. - // TODO: More elegant would be to wrap the stream. - byte *data = (byte *)malloc(size); - assert(data); - stream->read(data, size); - - if (disposeAfterUse == DisposeAfterUse::YES) - delete stream; - - return makeRawStream(data, size, rate, flags); -} - -} // End of namespace Audio diff --git a/sound/decoders/wave.h b/sound/decoders/wave.h deleted file mode 100644 index 2bdbe8f0b6..0000000000 --- a/sound/decoders/wave.h +++ /dev/null @@ -1,84 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/** - * @file - * Sound decoder used in engines: - * - agos - * - gob - * - mohawk - * - saga - * - sci - * - scumm - * - sword1 - * - sword2 - * - tucker - */ - -#ifndef SOUND_WAVE_H -#define SOUND_WAVE_H - -#include "common/scummsys.h" -#include "common/types.h" - -namespace Common { class SeekableReadStream; } - -namespace Audio { - -class RewindableAudioStream; - -/** - * Try to load a WAVE from the given seekable stream. Returns true if - * successful. In that case, the stream's seek position will be set to the - * start of the audio data, and size, rate and flags contain information - * necessary for playback. Currently this function supports uncompressed - * raw PCM data, MS IMA ADPCM and MS ADPCM (uses makeADPCMStream internally). - */ -extern bool loadWAVFromStream( - Common::SeekableReadStream &stream, - int &size, - int &rate, - byte &flags, - uint16 *wavType = 0, - int *blockAlign = 0); - -/** - * Try to load a WAVE from the given seekable stream and create an AudioStream - * from that data. Currently this function supports uncompressed - * raw PCM data, MS IMA ADPCM and MS ADPCM (uses makeADPCMStream internally). - * - * This function uses loadWAVFromStream() internally. - * - * @param stream the SeekableReadStream from which to read the WAVE data - * @param disposeAfterUse whether to delete the stream after use - * @return a new RewindableAudioStream, or NULL, if an error occurred - */ -RewindableAudioStream *makeWAVStream( - Common::SeekableReadStream *stream, - DisposeAfterUse::Flag disposeAfterUse); - -} // End of namespace Audio - -#endif |