diff options
author | Eugene Sandulenko | 2004-11-15 03:03:48 +0000 |
---|---|---|
committer | Eugene Sandulenko | 2004-11-15 03:03:48 +0000 |
commit | 4295a17c2323d025aad8ccd7084a8c3bdedfcaa6 (patch) | |
tree | 41382d001ca51502103e788f1beabc511661186f /saga/sound.cpp | |
parent | 183a11153e680a1b6cd399da09deff7a690304dc (diff) | |
download | scummvm-rg350-4295a17c2323d025aad8ccd7084a8c3bdedfcaa6.tar.gz scummvm-rg350-4295a17c2323d025aad8ccd7084a8c3bdedfcaa6.tar.bz2 scummvm-rg350-4295a17c2323d025aad8ccd7084a8c3bdedfcaa6.zip |
o Make GAME_GetFileContext() more object-like
o Font::loadFont() now normally survives zero-length fonts as used in demos
o Removed unused SndRes::ITEVOC_Resample()
o Fixed playing of voice #4 on old DOS targets
o Implemented playing voices in VOX (Oki ADPCM) format
o Support of Win32 and Linux demos. There was old-style Win32 demo, which
is not supported yet, same is with DOS demo.
svn-id: r15814
Diffstat (limited to 'saga/sound.cpp')
-rw-r--r-- | saga/sound.cpp | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/saga/sound.cpp b/saga/sound.cpp index a6859134ae..e63f675ca0 100644 --- a/saga/sound.cpp +++ b/saga/sound.cpp @@ -25,9 +25,118 @@ #include "saga/sound.h" #include "saga/game_mod.h" +#include "sound/audiostream.h" #include "sound/mixer.h" namespace Saga { +#define BUFFER_SIZE 4096 + +// Routines to convert 12 bit linear samples to the +// Dialogic or Oki ADPCM coding format. +class VOXInputStream : public AudioStream { +private: + const byte *_buf; + uint32 _pos; + uint32 _inputLen; + bool _evenPos; + + struct adpcmStatus { + int16 last; + int16 stepIndex; + } _status; + + int16 stepAdjust(byte); + int16 adpcmDecode(byte); + +public: + VOXInputStream(const byte *input, int inputLen); + ~VOXInputStream() {}; + + int readBuffer(int16 *buffer, const int numSamples); + + bool endOfData() const { return _pos >= _inputLen; } + bool isStereo() const { return false; } + int getRate() const { return 22050; } +}; + + +VOXInputStream::VOXInputStream(const byte *input, int inputLen) + : _buf(input), _pos(0), _inputLen(inputLen), _evenPos(true) { + + _status.last = 0; + _status.stepIndex = 0; +} + +int VOXInputStream::readBuffer(int16 *buffer, const int numSamples) { + int samples = 0; + + while (samples < numSamples && !endOfData()) { + const int len = MIN(numSamples - samples, (int) (_inputLen - _pos)); + + // * 16 effectively converts 12-bit input to 16-bit output + for (int i = 0; i < len; i++) { + if (_evenPos) + buffer[i] = adpcmDecode((_buf[_pos] >> 4) & 0x0f) * 16; + else { + buffer[i] = adpcmDecode(_buf[_pos] & 0x0f) * 16; + _pos++; + } + _evenPos = !_evenPos; + } + + samples += len; + } + return samples; +} + +// adjust the step for use on the next sample. +int16 VOXInputStream::stepAdjust(byte code) { + static int16 adjusts[] = {-1, -1, -1, -1, 2, 4, 6, 8}; + + return adjusts[code & 0x07]; +} + +static int16 stepSize[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, 1408, 1552 }; + +// Decode Linear to ADPCM +int16 VOXInputStream::adpcmDecode(byte code) { + int16 diff, E, SS, samp; + + SS = stepSize[_status.stepIndex]; + E = SS/8; + if (code & 0x01) + E += SS/4; + if (code & 0x02) + E += SS/2; + if (code & 0x04) + E += SS; + diff = (code & 0x08) ? -E : E; + samp = _status.last + diff; + + // Clip the values to +/- 2^11 (supposed to be 12 bits) + if(samp > 2048) + samp = 2048; + if(samp < -2048) + samp = -2048; + + _status.last = samp; + _status.stepIndex += stepAdjust(code); + if(_status.stepIndex < 0) + _status.stepIndex = 0; + if(_status.stepIndex > 48) + _status.stepIndex = 48; + + return samp; +} + +AudioStream *makeVOXStream(const byte *input, int size) { + AudioStream *audioStream = new VOXInputStream(input, size); + + return audioStream; +} Sound::Sound(SagaEngine *vm, SoundMixer *mixer, int enabled) : _vm(vm), _mixer(mixer), _enabled(enabled) { @@ -119,6 +228,15 @@ int Sound::playVoice(SOUNDBUFFER *buf) { return playSoundBuffer(&_voiceHandle, buf, 255, false); } +int Sound::playVoxVoice(SOUNDBUFFER *buf) { + AudioStream *audioStream; + + audioStream = makeVOXStream(buf->s_buf, buf->s_buf_len); + _mixer->playInputStream(&_voiceHandle, audioStream, false); + + return SUCCESS; +} + int Sound::pauseVoice() { if (!_soundInitialized) { return FAILURE; |