diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/sherlock/music.cpp | 210 | ||||
-rw-r--r-- | engines/sherlock/music.h | 11 | ||||
-rw-r--r-- | engines/sherlock/scalpel/scalpel.cpp | 68 |
3 files changed, 204 insertions, 85 deletions
diff --git a/engines/sherlock/music.cpp b/engines/sherlock/music.cpp index c00be10463..8b1f173f3d 100644 --- a/engines/sherlock/music.cpp +++ b/engines/sherlock/music.cpp @@ -24,6 +24,8 @@ #include "sherlock/sherlock.h" #include "sherlock/music.h" #include "sherlock/scalpel/drivers/mididriver.h" +// for 3DO digital music +#include "audio/decoders/aiff.h" namespace Sherlock { @@ -190,16 +192,15 @@ bool MidiParser_SH::loadMusic(byte *data, uint32 size) { /*----------------------------------------------------------------*/ Music::Music(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) { + _midiDriver = NULL; + _midiParser = NULL; + _musicType = MT_NULL; _musicPlaying = false; - _musicOn = true; + _musicOn = false; if (_vm->getPlatform() == Common::kPlatform3DO) { - // 3DO - disable music - // TODO: Implement music support - _driver = NULL; - _midiParser = NULL; - _musicType = MT_NULL; - _musicOn = false; + // 3DO - uses digital samples for music + _musicOn = true; return; } @@ -211,18 +212,16 @@ Music::Music(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) { MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MT32); _musicType = MidiDriver::getMusicType(dev); - _driver = NULL; - switch (_musicType) { case MT_ADLIB: - _driver = MidiDriver_AdLib_create(); + _midiDriver = MidiDriver_AdLib_create(); break; case MT_MT32: - _driver = MidiDriver_MT32_create(); + _midiDriver = MidiDriver_MT32_create(); break; case MT_GM: if (ConfMan.getBool("native_mt32")) { - _driver = MidiDriver_MT32_create(); + _midiDriver = MidiDriver_MT32_create(); _musicType = MT_MT32; } break; @@ -233,16 +232,14 @@ Music::Music(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) { break; } - if (_driver) { - assert(_driver); - - int ret = _driver->open(); + if (_midiDriver) { + int ret = _midiDriver->open(); if (ret == 0) { // Reset is done inside our MIDI driver - _driver->setTimerCallback(_midiParser, &_midiParser->timerCallback); + _midiDriver->setTimerCallback(_midiParser, &_midiParser->timerCallback); } - _midiParser->setMidiDriver(_driver); - _midiParser->setTimerRate(_driver->getBaseTempo()); + _midiParser->setMidiDriver(_midiDriver); + _midiParser->setTimerRate(_midiDriver->getBaseTempo()); if (_musicType == MT_MT32) { // Upload patches @@ -259,12 +256,11 @@ Music::Music(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) { byte *MT32driverDataPtr = MT32driverData + 12; MT32driverDataSize -= 12; - MidiDriver_MT32_uploadPatches(_driver, MT32driverDataPtr, MT32driverDataSize); + MidiDriver_MT32_uploadPatches(_midiDriver, MT32driverDataPtr, MT32driverDataSize); delete[] MT32driverData; } - } else { - // no driver, bye bye music - _musicOn = false; + + _musicOn = true; } } @@ -274,9 +270,9 @@ Music::~Music() { _midiParser->stopPlaying(); delete _midiParser; } - if (_driver) { - _driver->close(); - delete _driver; + if (_midiDriver) { + _midiDriver->close(); + delete _midiDriver; } } @@ -321,66 +317,92 @@ void Music::syncMusicSettings() { } bool Music::playMusic(const Common::String &name) { - if (!_driver) - return false; if (!_musicOn) return false; debugC(kDebugLevelMusic, "Music: playMusic('%s')", name.c_str()); - Common::SeekableReadStream *stream = _vm->_res->load(name, "MUSIC.LIB"); - byte *data = new byte[stream->size()]; - int32 dataSize = stream->size(); - assert(data); + if (_vm->getPlatform() != Common::kPlatform3DO) { + // MIDI based + if (!_midiDriver) + return false; + + Common::SeekableReadStream *stream = _vm->_res->load(name, "MUSIC.LIB"); - stream->read(data, dataSize); - delete stream; + byte *data = new byte[stream->size()]; + int32 dataSize = stream->size(); + assert(data); - // for dumping the music tracks + stream->read(data, dataSize); + delete stream; + + // for dumping the music tracks #if 0 - Common::DumpFile outFile; - outFile.open(name + ".RAW"); - outFile.write(data, stream->size()); - outFile.flush(); - outFile.close(); + Common::DumpFile outFile; + outFile.open(name + ".RAW"); + outFile.write(data, stream->size()); + outFile.flush(); + outFile.close(); #endif - if (dataSize < 14) { - warning("Music: not enough data in music file"); - return false; - } + if (dataSize < 14) { + warning("Music: not enough data in music file"); + return false; + } - byte *dataPos = data; - if (memcmp(" ", dataPos, 12)) { - warning("Music: expected header not found in music file"); - return false; - } - dataPos += 12; - dataSize -= 12; + byte *dataPos = data; + if (memcmp(" ", dataPos, 12)) { + warning("Music: expected header not found in music file"); + return false; + } + dataPos += 12; + dataSize -= 12; - uint16 headerSize = READ_LE_UINT16(dataPos); - if (headerSize != 0x7F) { - warning("Music: header is not as expected"); - return false; - } + uint16 headerSize = READ_LE_UINT16(dataPos); + if (headerSize != 0x7F) { + warning("Music: header is not as expected"); + return false; + } - if (_driver) { switch (_musicType) { case MT_ADLIB: - MidiDriver_AdLib_newMusicData(_driver, dataPos, dataSize); + MidiDriver_AdLib_newMusicData(_midiDriver, dataPos, dataSize); break; case MT_MT32: - MidiDriver_MT32_newMusicData(_driver, dataPos, dataSize); + MidiDriver_MT32_newMusicData(_midiDriver, dataPos, dataSize); break; default: // should never happen break; } - } - _midiParser->loadMusic(dataPos, dataSize); + _midiParser->loadMusic(dataPos, dataSize); + + } else { + // 3DO: sample based + Audio::AudioStream *musicStream; + Common::String digitalMusicName = "music/" + name + "_MW22.aifc"; + + if (isPlaying()) { + _mixer->stopHandle(_digitalMusicHandle); + } + + Common::File *digitalMusicFile = new Common::File(); + if (!digitalMusicFile->open(digitalMusicName)) { + warning("playMusic: can not open 3DO music '%s'", digitalMusicName.c_str()); + return false; + } + + // Try to load the given file as AIFF/AIFC + musicStream = Audio::makeAIFFStream(digitalMusicFile, DisposeAfterUse::YES); + if (!musicStream) { + warning("playMusic: can not load 3DO music '%s'", digitalMusicName.c_str()); + return false; + } + _mixer->playStream(Audio::Mixer::kMusicSoundType, &_digitalMusicHandle, musicStream); + } return true; } @@ -388,6 +410,15 @@ void Music::stopMusic() { // TODO warning("TODO: Sound::stopMusic"); + if (_vm->getPlatform() != Common::kPlatform3DO) { + // TODO + } else { + // 3DO + if (isPlaying()) { + _mixer->stopHandle(_digitalMusicHandle); + } + } + _musicPlaying = false; } @@ -410,6 +441,27 @@ void Music::waitTimerRoland(uint time) { warning("TODO: Sound::waitTimerRoland"); } +bool Music::isPlaying() { + if (_vm->getPlatform() != Common::kPlatform3DO) { + // MIDI based + return _midiParser->isPlaying(); + } else { + // 3DO: sample based + return _mixer->isSoundHandleActive(_digitalMusicHandle); + } +} + +// Returns the current music position in milliseconds +uint32 Music::getCurrentPosition() { + if (_vm->getPlatform() != Common::kPlatform3DO) { + // MIDI based + return (_midiParser->getTick() * 1000) / 60; // translate tick to millisecond + } else { + // 3DO: sample based + return _mixer->getSoundElapsedTime(_digitalMusicHandle); + } +} + // This is used to wait for the music in certain situations like especially the intro // Note: the original game didn't do this, instead it just waited for certain amounts of time // We do this, so that the intro graphics + music work together even on faster/slower hardware. @@ -445,5 +497,39 @@ bool Music::waitUntilTick(uint32 tick, uint32 maxTick, uint32 additionalDelay, u } } -} // End of namespace Sherlock +// This is used to wait for the music in certain situations like especially the intro +// Note: the original game didn't do this, instead it just waited for certain amounts of time +// We do this, so that the intro graphics + music work together even on faster/slower hardware. +bool Music::waitUntilMSec(uint32 msecTarget, uint32 msecMax, uint32 additionalDelay, uint32 noMusicDelay) { + uint32 msecCurrent = 0; + + if (!isPlaying()) { + return _vm->_events->delay(noMusicDelay, true); + } + while (1) { + if (!isPlaying()) { // Music is not playing anymore -> we are done + if (additionalDelay > 0) { + if (!_vm->_events->delay(additionalDelay, true)) + return false; + } + return true; + } + + msecCurrent = getCurrentPosition(); + //warning("waitUntilMSec: %lx", msecCurrent); + + if ((!msecMax) || (msecCurrent <= msecMax)) { + if (msecCurrent >= msecTarget) { + if (additionalDelay > 0) { + if (!_vm->_events->delay(additionalDelay, true)) + return false; + } + return true; + } + } + if (!_vm->_events->delay(10, true)) + return false; + } +} +} // End of namespace Sherlock diff --git a/engines/sherlock/music.h b/engines/sherlock/music.h index b11a7691bd..f8cad3fd73 100644 --- a/engines/sherlock/music.h +++ b/engines/sherlock/music.h @@ -27,6 +27,9 @@ #include "audio/midiparser.h" //#include "audio/mididrv.h" #include "sherlock/scalpel/drivers/mididriver.h" +// for 3DO digital music +#include "audio/audiostream.h" +#include "audio/mixer.h" namespace Sherlock { @@ -58,7 +61,8 @@ private: SherlockEngine *_vm; Audio::Mixer *_mixer; MidiParser_SH *_midiParser; - MidiDriver *_driver; + MidiDriver *_midiDriver; + Audio::SoundHandle _digitalMusicHandle; public: bool _musicPlaying; @@ -105,7 +109,12 @@ public: void waitTimerRoland(uint time); + bool isPlaying(); + uint32 getCurrentPosition(); + bool waitUntilTick(uint32 tick, uint32 maxTick, uint32 additionalDelay, uint32 noMusicDelay); + + bool waitUntilMSec(uint32 msecTarget, uint32 maxMSec, uint32 additionalDelay, uint32 noMusicDelay); }; } // End of namespace Sherlock diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp index bf961dd13d..af06f45c64 100644 --- a/engines/sherlock/scalpel/scalpel.cpp +++ b/engines/sherlock/scalpel/scalpel.cpp @@ -531,6 +531,12 @@ bool ScalpelEngine::showOfficeCutscene() { bool ScalpelEngine::showCityCutscene3DO() { _animation->_soundLibraryFilename = "TITLE.SND"; + // Play intro music + _music->playMusic("prolog"); + + // rain.aiff seems to be playing in an endless loop until + // sherlock logo fades away TODO + bool finished = _animation->play3DO("26open1", true, 1, 255, 2); if (finished) { @@ -548,8 +554,8 @@ bool ScalpelEngine::showCityCutscene3DO() { ImageFile3DO titleImage_November("title2b.cel"); _screen->transBlitFromUnscaled3DO(titleImage_November[0]._frame, Common::Point(101, 100)); - finished = _events->delay(5000, true); + finished = _music->waitUntilMSec(14700, 0, 0, 5000); } if (finished) { @@ -562,8 +568,6 @@ bool ScalpelEngine::showCityCutscene3DO() { finished = _animation->play3DO("26open2", true, 1, 0, 2); if (finished) { - _screen->_backBuffer2.blitFrom(*_screen); - // "Sherlock Holmes" (title) ImageFile3DO titleImage_SherlockHolmesTitle("title1ab.cel"); @@ -578,14 +582,10 @@ bool ScalpelEngine::showCityCutscene3DO() { finished = _events->delay(3500, true); } // Title is supposed to get faded away after that - if (finished) { - // Restore screen - _screen->blitFrom(_screen->_backBuffer2); - } } if (finished) - finished = _events->delay(2000); + finished = _music->waitUntilMSec(33600, 0, 0, 2000); if (finished) { // TODO: fade to black @@ -598,44 +598,56 @@ bool ScalpelEngine::showCityCutscene3DO() { _screen->transBlitFromUnscaled3DO(titleImage_InTheAlley[0]._frame, Common::Point(72, 51)); // TODO: Supposed to get faded in and out - finished = _events->delay(2500, true); + finished = _music->waitUntilMSec(39900, 0, 0, 2500); // Fade out + _screen->clear(); } return finished; } bool ScalpelEngine::showAlleyCutscene3DO() { - bool finished = _animation->play3DO("27PRO1", true, 1, 3, 2); + bool finished = _music->waitUntilMSec(44000, 0, 0, 1000); + + if (finished) + finished = _animation->play3DO("27PRO1", true, 1, 3, 2); if (finished) { // Fade out... _screen->clear(); - finished = _events->delay(1000, true); + finished = _music->waitUntilMSec(66700, 0, 0, 1000); } if (finished) finished = _animation->play3DO("27PRO2", true, 1, 0, 2); if (finished) { + // Fade out + _screen->clear(); + + finished = _music->waitUntilMSec(76000, 0, 0, 1000); + } + + if (finished) { // Show screaming victim ImageFile3DO titleImage_ScreamingVictim("scream.cel"); + _screen->clear(); _screen->transBlitFromUnscaled3DO(titleImage_ScreamingVictim[0]._frame, Common::Point(0, 0)); // Play "scream.aiff" if (_sound->_voices) _sound->playSound("prologue/sounds/scream.aiff", WAIT_RETURN_IMMEDIATELY, 100); - finished = _events->delay(6000, true); + finished = _music->waitUntilMSec(81600, 0, 0, 6000); } if (finished) { // TODO: quick fade out _screen->clear(); - finished = _events->delay(2000, true); + finished = _music->waitUntilMSec(84400, 0, 0, 2000); } if (finished) @@ -653,22 +665,21 @@ bool ScalpelEngine::showAlleyCutscene3DO() { _screen->transBlitFromUnscaled3DO(titleImage_EarlyTheFollowingMorning[0]._frame, Common::Point(35, 51)); // TODO: Fade in - finished = _events->delay(3000, true); + finished = _music->waitUntilMSec(96700, 0, 0, 3000); } return finished; } bool ScalpelEngine::showStreetCutscene3DO() { - // wait a bit - bool finished = _events->delay(500); + bool finished = true; if (finished) { // fade out "Early the following morning..." _screen->clear(); // wait for music a bit - finished = _events->delay(1000, true); + finished = _music->waitUntilMSec(100300, 0, 0, 1000); } finished = _animation->play3DO("14KICK", true, 1, 3, 2); @@ -677,16 +688,25 @@ bool ScalpelEngine::showStreetCutscene3DO() { finished = _animation->play3DO("14NOTE", true, 1, 0, 3); // TODO: fade out + _screen->clear(); return finished; } bool ScalpelEngine::showOfficeCutscene3DO() { - bool finished = _animation->play3DO("COFF1", true, 1, 3, 3); + bool finished = true; + + finished = _music->waitUntilMSec(151000, 0, 0, 1000); + + if (finished) + _animation->play3DO("COFF1", true, 1, 3, 3); if (finished) finished = _animation->play3DO("COFF2", true, 1, 0, 3); + if (finished) + finished = _music->waitUntilMSec(182400, 0, 0, 1000); + if (finished) { // Show the note ImageFile3DO titleImage_CoffeeNote("note.cel"); @@ -699,13 +719,17 @@ bool ScalpelEngine::showOfficeCutscene3DO() { } else finished = _events->delay(19000); - if (finished) { - _events->clearEvents(); - finished = _events->delay(500); - } + if (finished) + finished = _music->waitUntilMSec(218800, 0, 0, 1000); + + // Fade out + _screen->clear(); } if (finished) + finished = _music->waitUntilMSec(222200, 0, 0, 1000); + + if (finished) finished = _animation->play3DO("COFF3", true, 1, 0, 3); if (finished) |