o Fixed ADPCM decoder length bug

o Plugged IMA ADPCM into SCUMM engine so latter HE titles now have speech
  though it is somewhat noisy don't know why as decoder is based on ADPCM
   reference implementation.

svn-id: r17904
This commit is contained in:
Eugene Sandulenko 2005-05-03 22:12:23 +00:00
parent a71d60686c
commit 575e94602c
5 changed files with 34 additions and 22 deletions

View File

@ -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;

View File

@ -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);

View File

@ -32,6 +32,6 @@ enum typesADPCM {
kADPCMIma
};
AudioStream *makeADPCMStream(Common::SeekableReadStream &stream, typesADPCM type);
AudioStream *makeADPCMStream(Common::SeekableReadStream &stream, uint32 size, typesADPCM type);
#endif

View File

@ -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);

View File

@ -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);