aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorMartin Kiewitz2015-06-08 20:09:29 +0200
committerMartin Kiewitz2015-06-08 20:09:29 +0200
commit0d090495627453ae5d1e71f4fe11d888ab04d5fe (patch)
tree856223047218cf73d39e88dea620e3c8fe82bb24 /engines
parent55551cfbd510a8e56562faddc4bb4768e3b72d0a (diff)
downloadscummvm-rg350-0d090495627453ae5d1e71f4fe11d888ab04d5fe.tar.gz
scummvm-rg350-0d090495627453ae5d1e71f4fe11d888ab04d5fe.tar.bz2
scummvm-rg350-0d090495627453ae5d1e71f4fe11d888ab04d5fe.zip
SHERLOCK: add music + sync to 3DO intro
Diffstat (limited to 'engines')
-rw-r--r--engines/sherlock/music.cpp210
-rw-r--r--engines/sherlock/music.h11
-rw-r--r--engines/sherlock/scalpel/scalpel.cpp68
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)