aboutsummaryrefslogtreecommitdiff
path: root/saga/sound.cpp
diff options
context:
space:
mode:
authorEugene Sandulenko2004-11-15 03:03:48 +0000
committerEugene Sandulenko2004-11-15 03:03:48 +0000
commit4295a17c2323d025aad8ccd7084a8c3bdedfcaa6 (patch)
tree41382d001ca51502103e788f1beabc511661186f /saga/sound.cpp
parent183a11153e680a1b6cd399da09deff7a690304dc (diff)
downloadscummvm-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.cpp118
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;