From 0d3750a768c8f9457530344fa6871b98dd20276b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 11 May 2015 01:04:04 +0200 Subject: SHERLOCK: Add preliminar sound support --- engines/sherlock/sherlock.cpp | 2 +- engines/sherlock/sound.cpp | 112 ++++++++++++++++++++++++++++++++++++++++-- engines/sherlock/sound.h | 13 ++++- 3 files changed, 119 insertions(+), 8 deletions(-) (limited to 'engines/sherlock') diff --git a/engines/sherlock/sherlock.cpp b/engines/sherlock/sherlock.cpp index 6bfc7ea7d4..2a5d9ec627 100644 --- a/engines/sherlock/sherlock.cpp +++ b/engines/sherlock/sherlock.cpp @@ -89,7 +89,7 @@ void SherlockEngine::initialize() { _saves = new SaveManager(this, _targetName); _scene = new Scene(this); _screen = new Screen(this); - _sound = new Sound(this); + _sound = new Sound(this, _mixer); _talk = new Talk(this); _ui = new UserInterface(this); diff --git a/engines/sherlock/sound.cpp b/engines/sherlock/sound.cpp index 24147a0ab9..51563d17a6 100644 --- a/engines/sherlock/sound.cpp +++ b/engines/sherlock/sound.cpp @@ -23,10 +23,14 @@ #include "sherlock/sherlock.h" #include "sherlock/sound.h" #include "common/config-manager.h" +#include "audio/audiostream.h" +#include "common/algorithm.h" +#include "audio/mixer.h" +#include "audio/decoders/raw.h" namespace Sherlock { -Sound::Sound(SherlockEngine *vm): _vm(vm) { +Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer): _vm(vm), _mixer(mixer) { _digitized = false; _music = false; _voices = 0; @@ -38,6 +42,9 @@ Sound::Sound(SherlockEngine *vm): _vm(vm) { _soundOn = true; _musicOn = true; _speechOn = true; + + _vm->_res->addToCache("MUSIC.LIB"); + _vm->_res->addToCache("SND.SND"); } /** @@ -54,10 +61,91 @@ void Sound::loadSound(const Common::String &name, int priority) { warning("TODO: Sound::loadSound"); } +char Sound::decodeSample(char sample, byte& prediction, int& step) { + char diff = ((sample & 0x07) << step); + + if (sample & 0x08) { + if (prediction > diff) + prediction = prediction - ((sample & 0x07) << step); + else + prediction = 0; + } else { + if (prediction < 0xff - diff) + prediction = prediction + ((sample&0x07) << step); + else + prediction = 0xff; + } + + + if ((sample & 0x07) >= 5 && step < 3) { + step ++; + } else if ((sample & 0x07) == 0 && step > 0) { + step --; + } + + return prediction; +} + bool Sound::playSound(const Common::String &name, WaitType waitType) { - // TODO - warning("TODO: Sound::playSound"); - return true; + _mixer->stopHandle(_effectsHandle); + + Common::String filename = name; + if (!filename.contains('.')) + filename += ".SND"; + Common::SeekableReadStream *stream = _vm->_res->load(filename, "TITLE.SND"); + + stream->skip(2); + int size = stream->readUint32BE(); + int rate = stream->readUint16BE(); + byte *data = (byte *)malloc(size); + byte *ptr = data; + stream->read(ptr, size); + + byte *decoded = (byte *)malloc((size - 1) * 2); + + // +127 to eliminate the pop when the sound starts (signed vs unsignded PCM). Still does not help with the pop at the end + byte prediction = (ptr[0] & 0x0f) + 127; + int step = 0; + int counter = 0; + + for(int i = 1; i < size; i++) { + decoded[counter++] = decodeSample((ptr[i]>>4)&0x0f, prediction, step); + decoded[counter++] = decodeSample((ptr[i]>>0)&0x0f, prediction, step); + } + + free(data); + + Audio::AudioStream *audioStream = Audio::makeRawStream(decoded, (size - 2) * 2, rate, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES); + _mixer->playStream(Audio::Mixer::kPlainSoundType, &_effectsHandle, audioStream, -1, Audio::Mixer::kMaxChannelVolume); + _soundPlaying = true; + + if (waitType == WAIT_RETURN_IMMEDIATELY) { + _diskSoundPlaying = true; + return true; + } + + bool retval = true; + do { + _vm->_events->pollEvents(); + g_system->delayMillis(10); + if ((waitType == WAIT_KBD_OR_FINISH) && _vm->_events->kbHit()) { + retval = false; + break; + } + } while (!_vm->shouldQuit() && _mixer->isSoundHandleActive(_effectsHandle)); + + _soundPlaying = false; + _mixer->stopHandle(_effectsHandle); + +#if 0 + // Debug : used to dump files + Common::DumpFile outFile; + outFile.open(filename); + outFile.write(decoded, (size - 2) * 2); + outFile.flush(); + outFile.close(); +#endif + return retval; } void Sound::cacheSound(const Common::String &name, int index) { @@ -92,7 +180,21 @@ void Sound::stopSound() { void Sound::playMusic(const Common::String &name) { // TODO - warning("TODO: Sound::playMusic"); + warning("Sound::playMusic %s", name.c_str()); + Common::SeekableReadStream *stream = _vm->_res->load(name, "MUSIC.LIB"); + + byte *data = new byte[stream->size()]; + byte *ptr = data; + stream->read(ptr, stream->size()); + Common::DumpFile outFile; + outFile.open(name + ".RAW"); + outFile.write(data, stream->size()); + outFile.flush(); + outFile.close(); + delete[] data; + + stopMusic(); + startSong(); } void Sound::stopMusic() { diff --git a/engines/sherlock/sound.h b/engines/sherlock/sound.h index 56cd4ed0a8..213a6f7a1e 100644 --- a/engines/sherlock/sound.h +++ b/engines/sherlock/sound.h @@ -25,6 +25,11 @@ #include "common/scummsys.h" #include "common/str.h" +#include "audio/audiostream.h" +#include "audio/mixer.h" +#include "access/files.h" +#include "audio/midiplayer.h" +#include "audio/midiparser.h" namespace Sherlock { @@ -37,6 +42,10 @@ enum WaitType { class Sound { private: SherlockEngine *_vm; + Audio::Mixer *_mixer; + Audio::SoundHandle _effectsHandle; + + char decodeSample(char sample, byte& prediction, int& step); public: bool _digitized; bool _music; @@ -50,7 +59,7 @@ public: bool *_soundIsOn; byte *_digiBuf; public: - Sound(SherlockEngine *vm); + Sound(SherlockEngine *vm, Audio::Mixer *mixer); void syncSoundSettings(); void loadSound(const Common::String &name, int priority); @@ -64,7 +73,7 @@ public: int loadSong(int songNumber); void startSong(); void freeSong(); - + void playMusic(const Common::String &name); void stopMusic(); void stopSndFuncPtr(int v1, int v2); -- cgit v1.2.3