aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--saga/sound.cpp2
-rw-r--r--sound/adpcm.cpp29
-rw-r--r--sound/adpcm.h2
-rw-r--r--sound/wave.cpp21
-rw-r--r--sound/wave.h2
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);