diff options
-rw-r--r-- | saga/sound.cpp | 2 | ||||
-rw-r--r-- | sound/adpcm.cpp | 29 | ||||
-rw-r--r-- | sound/adpcm.h | 2 | ||||
-rw-r--r-- | sound/wave.cpp | 21 | ||||
-rw-r--r-- | sound/wave.h | 2 |
5 files changed, 34 insertions, 22 deletions
diff --git a/saga/sound.cpp b/saga/sound.cpp index 9c2400fb65..2ba533d26a 100644 --- a/saga/sound.cpp +++ b/saga/sound.cpp @@ -119,7 +119,7 @@ int Sound::playVoxVoice(SOUNDBUFFER *buf) { _voxStream = new Common::MemoryReadStream(buf->s_buf, buf->s_buf_len); - audioStream = makeADPCMStream(*_voxStream, kADPCMOki); + audioStream = makeADPCMStream(*_voxStream, buf->s_buf_len, kADPCMOki); _mixer->playInputStream(SoundMixer::kSFXSoundType, &_voiceHandle, audioStream); return SUCCESS; diff --git a/sound/adpcm.cpp b/sound/adpcm.cpp index 18f600ed23..9df92fa680 100644 --- a/sound/adpcm.cpp +++ b/sound/adpcm.cpp @@ -33,6 +33,7 @@ private: bool _evenPos; Common::SeekableReadStream *_stream; typesADPCM _type; + uint32 _endpos; struct adpcmStatus { int16 last; @@ -47,22 +48,23 @@ private: int readIMABuffer(int16 *buffer, const int numSamples); public: - ADPCMInputStream(Common::SeekableReadStream *stream, typesADPCM type); + ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size, typesADPCM type); ~ADPCMInputStream() {}; int readBuffer(int16 *buffer, const int numSamples); - bool endOfData() const { return _stream->eos(); } + bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos); } bool isStereo() const { return false; } int getRate() const { return 22050; } }; -ADPCMInputStream::ADPCMInputStream(Common::SeekableReadStream *stream, typesADPCM type) +ADPCMInputStream::ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size, typesADPCM type) : _stream(stream), _evenPos(true), _type(type) { _status.last = 0; _status.stepIndex = 0; + _endpos = stream->pos() + size; } int ADPCMInputStream::readBuffer(int16 *buffer, const int numSamples) { @@ -83,7 +85,7 @@ int ADPCMInputStream::readBuffer(int16 *buffer, const int numSamples) { int ADPCMInputStream::readOkiBuffer(int16 *buffer, const int numSamples) { int samples; - for (samples = 0; samples < numSamples && !_stream->eos(); samples++) { + for (samples = 0; samples < numSamples && !_stream->eos() && _stream->pos() < _endpos; samples++) { // * 16 effectively converts 12-bit input to 16-bit output if (_evenPos) { buffer[samples] = okiADPCMDecode((_stream->readByte() >> 4) & 0x0f) * 16; @@ -100,7 +102,7 @@ int ADPCMInputStream::readOkiBuffer(int16 *buffer, const int numSamples) { int ADPCMInputStream::readIMABuffer(int16 *buffer, const int numSamples) { int samples; - for (samples = 0; samples < numSamples && !_stream->eos(); samples++) { + for (samples = 0; samples < numSamples && !_stream->eos() && _stream->pos() < _endpos; samples++) { if (_evenPos) { buffer[samples] = imaADPCMDecode((_stream->readByte() >> 4) & 0x0f); // Rewind back so we will reget byte later @@ -161,8 +163,8 @@ int16 ADPCMInputStream::okiADPCMDecode(byte code) { return samp; } -AudioStream *makeADPCMStream(Common::SeekableReadStream &stream, typesADPCM type) { - AudioStream *audioStream = new ADPCMInputStream(&stream, type); +AudioStream *makeADPCMStream(Common::SeekableReadStream &stream, uint32 size, typesADPCM type) { + AudioStream *audioStream = new ADPCMInputStream(&stream, size, type); return audioStream; } @@ -183,12 +185,10 @@ static const uint16 imaStepTable[89] = { 32767 }; - int16 ADPCMInputStream::imaADPCMDecode(byte code) { - int diff, E, SS, samp; + int32 diff, E, SS, samp; SS = imaStepTable[_status.stepIndex]; - E = SS/8; if (code & 0x01) E += SS/4; @@ -196,13 +196,14 @@ int16 ADPCMInputStream::imaADPCMDecode(byte code) { E += SS/2; if (code & 0x04) E += SS; + diff = (code & 0x08) ? -E : E; samp = _status.last + diff; - if(samp < -0x8000) - samp = -0x8000; - else if(samp > 0x7fff) - samp = 0x7fff; + if(samp < -32768) + samp = -32768; + else if(samp > 32767) + samp = 32767; _status.last = samp; _status.stepIndex += stepAdjust(code); diff --git a/sound/adpcm.h b/sound/adpcm.h index e5c51f36aa..cd240f8829 100644 --- a/sound/adpcm.h +++ b/sound/adpcm.h @@ -32,6 +32,6 @@ enum typesADPCM { kADPCMIma }; -AudioStream *makeADPCMStream(Common::SeekableReadStream &stream, typesADPCM type); +AudioStream *makeADPCMStream(Common::SeekableReadStream &stream, uint32 size, typesADPCM type); #endif diff --git a/sound/wave.cpp b/sound/wave.cpp index e3e5fc2daf..1e0274b605 100644 --- a/sound/wave.cpp +++ b/sound/wave.cpp @@ -26,8 +26,9 @@ #include "sound/audiostream.h" #include "sound/mixer.h" #include "sound/wave.h" +#include "sound/adpcm.h" -bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags) { +bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags, uint16 *wavType) { const uint32 initialPos = stream.pos(); byte buf[4+1]; @@ -62,7 +63,8 @@ bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, // Next comes the "type" field of the fmt header. Some typical // values for it: - // 1 -> uncompressed PCM + // 1 -> uncompressed PCM + // 17 -> IMA ADPCM compressed WAVE // See <http://www.sonicspot.com/guide/wavefiles.html> for a more complete // list of common WAVE compression formats... uint16 type = stream.readUint16LE(); // == 1 for PCM data @@ -74,6 +76,9 @@ bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, uint16 bitsPerSample = stream.readUint16LE(); // 8, 16 ... // 8 bit data is unsigned, 16 bit data signed + + if (wavType != 0) + *wavType = type; #if 0 printf("WAVE information:\n"); printf(" total size: %d\n", wavLength); @@ -86,8 +91,8 @@ bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, printf(" bitsPerSample: %d\n", bitsPerSample); #endif - if (type != 1) { - warning("getWavInfo: only PCM data is supported (type %d)", type); + if (type != 1 && type != 17) { + warning("getWavInfo: only PCM or IMA ADPCM data is supported (type %d)", type); return false; } @@ -107,6 +112,8 @@ bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, flags |= SoundMixer::FLAG_UNSIGNED; else if (bitsPerSample == 16) // 16 bit data is signed little endian flags |= (SoundMixer::FLAG_16BITS | SoundMixer::FLAG_LITTLE_ENDIAN); + else if (bitsPerSample == 4 && type == 17) // IDA ADPCM compressed. We decompress it + flags |= (SoundMixer::FLAG_16BITS | SoundMixer::FLAG_LITTLE_ENDIAN); else { warning("getWavInfo: unsupported bitsPerSample %d", bitsPerSample); return false; @@ -148,10 +155,14 @@ bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, AudioStream *makeWAVStream(Common::SeekableReadStream &stream) { int size, rate; byte flags; + uint16 type; - if (!loadWAVFromStream(stream, size, rate, flags)) + if (!loadWAVFromStream(stream, size, rate, flags, &type)) return 0; + if (type == 17) // IMA ADPCM + return makeADPCMStream(stream, size, kADPCMIma); + byte *data = (byte *)malloc(size); assert(data); stream.read(data, size); diff --git a/sound/wave.h b/sound/wave.h index 8aa4e42384..c28ca7222b 100644 --- a/sound/wave.h +++ b/sound/wave.h @@ -34,7 +34,7 @@ namespace Common { class SeekableReadStream; } * all information about the data necessary for playback. * Currently this only support uncompressed raw PCM data. */ -extern bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags); +extern bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags, uint16 *wavType = 0); AudioStream *makeWAVStream(Common::SeekableReadStream &stream); |