diff options
-rw-r--r-- | engines/illusions/dictionary.h | 4 | ||||
-rw-r--r-- | engines/illusions/duckman/illusions_duckman.cpp | 12 | ||||
-rw-r--r-- | engines/illusions/duckman/illusions_duckman.h | 1 | ||||
-rw-r--r-- | engines/illusions/duckman/scriptopcodes_duckman.cpp | 2 | ||||
-rw-r--r-- | engines/illusions/illusions.h | 1 | ||||
-rw-r--r-- | engines/illusions/pathfinder.cpp | 15 | ||||
-rw-r--r-- | engines/illusions/pathfinder.h | 1 | ||||
-rw-r--r-- | engines/illusions/resources/backgroundresource.cpp | 5 | ||||
-rw-r--r-- | engines/illusions/resources/midiresource.cpp | 64 | ||||
-rw-r--r-- | engines/illusions/resources/midiresource.h | 27 | ||||
-rw-r--r-- | engines/illusions/sound.cpp | 183 | ||||
-rw-r--r-- | engines/illusions/sound.h | 42 |
12 files changed, 279 insertions, 78 deletions
diff --git a/engines/illusions/dictionary.h b/engines/illusions/dictionary.h index c0d60a9bb7..d5c2d66242 100644 --- a/engines/illusions/dictionary.h +++ b/engines/illusions/dictionary.h @@ -67,8 +67,10 @@ public: if (it != _map.end()) { list = it->_value; list->pop_back(); - if (list->empty()) + if (list->empty()) { _map.erase(id); + delete list; + } } } diff --git a/engines/illusions/duckman/illusions_duckman.cpp b/engines/illusions/duckman/illusions_duckman.cpp index c30b8ce318..9eae7a5514 100644 --- a/engines/illusions/duckman/illusions_duckman.cpp +++ b/engines/illusions/duckman/illusions_duckman.cpp @@ -390,6 +390,18 @@ void IllusionsEngine_Duckman::updateFader() { } } +void IllusionsEngine_Duckman::clearFader() { + _fader->_active = false; + _fader->_currValue = 255; + _fader->_minValue = 255; + _fader->_maxValue = 255; + _fader->_firstIndex = 1; + _fader->_lastIndex = 256; + _fader->_startTime = 0; + _fader->_duration = 0; + _fader->_notifyThreadId = 0; +} + void IllusionsEngine_Duckman::pauseFader() { _fader->_paused = true; _fader->_startTime = getCurrentTime() - _fader->_startTime; diff --git a/engines/illusions/duckman/illusions_duckman.h b/engines/illusions/duckman/illusions_duckman.h index feacd50cc1..46bf15e3d8 100644 --- a/engines/illusions/duckman/illusions_duckman.h +++ b/engines/illusions/duckman/illusions_duckman.h @@ -113,6 +113,7 @@ public: void startFader(int duration, int minValue, int maxValue, int firstIndex, int lastIndex, uint32 threadId); void updateFader(); + void clearFader(); void pauseFader(); void unpauseFader(); diff --git a/engines/illusions/duckman/scriptopcodes_duckman.cpp b/engines/illusions/duckman/scriptopcodes_duckman.cpp index e6f286ca9c..8764f9277f 100644 --- a/engines/illusions/duckman/scriptopcodes_duckman.cpp +++ b/engines/illusions/duckman/scriptopcodes_duckman.cpp @@ -640,7 +640,7 @@ void ScriptOpcodes_Duckman::opStopMidiMusic(ScriptThread *scriptThread, OpCall & void ScriptOpcodes_Duckman::opFadeMidiMusic(ScriptThread *scriptThread, OpCall &opCall) { ARG_INT16(duration); ARG_INT16(finalVolume); - _vm->_soundMan->fadeMidiMusic(finalVolume, duration); + //FIXME _vm->_soundMan->fadeMidiMusic(finalVolume, duration); } void ScriptOpcodes_Duckman::opAddMenuChoice(ScriptThread *scriptThread, OpCall &opCall) { diff --git a/engines/illusions/illusions.h b/engines/illusions/illusions.h index 68557926f1..438ab04e34 100644 --- a/engines/illusions/illusions.h +++ b/engines/illusions/illusions.h @@ -173,6 +173,7 @@ public: bool isSoundActive(); virtual void updateFader() {}; + virtual void clearFader() {}; virtual void pauseFader() {}; virtual void unpauseFader() {}; diff --git a/engines/illusions/pathfinder.cpp b/engines/illusions/pathfinder.cpp index f021b2d5c5..2f723563e9 100644 --- a/engines/illusions/pathfinder.cpp +++ b/engines/illusions/pathfinder.cpp @@ -73,7 +73,7 @@ PointArray *PathFinder::findPathInternal(Common::Point sourcePt, Common::Point d } free(_pathBytes); - // TODO postProcess(sourcePt, foundPath); + postProcess(sourcePt, foundPath); } else { foundPath->push_back(destPt); @@ -81,6 +81,19 @@ PointArray *PathFinder::findPathInternal(Common::Point sourcePt, Common::Point d return foundPath; } +void PathFinder::postProcess(Common::Point sourcePt, PointArray *foundPath) { + // For each three points A, B and C, removes B if the line between A and C is not blocked + for (uint index = 0; index + 2 < foundPath->size(); ++index) { + PathLine line; + line.p0 = index == 0 ? sourcePt : (*foundPath)[index - 1]; + line.p1 = (*foundPath)[index + 1]; + if (!isLineBlocked(line)) { + debug("remove point"); + foundPath->remove_at(index); + } + } +} + bool PathFinder::isLineBlocked(PathLine &line) { for (uint i = 0; i < _walkRects->size(); ++i) { if (calcLineStatus(line, (*_walkRects)[i], 0) != 3) diff --git a/engines/illusions/pathfinder.h b/engines/illusions/pathfinder.h index 2b56b2df67..2f8d1b7e85 100644 --- a/engines/illusions/pathfinder.h +++ b/engines/illusions/pathfinder.h @@ -48,6 +48,7 @@ protected: WidthHeight _bgDimensions; byte *_pathBytes; PointArray *findPathInternal(Common::Point sourcePt, Common::Point destPt); + void postProcess(Common::Point sourcePt, PointArray *foundPath); bool isLineBlocked(PathLine &line); int calcLineDistance(PathLine &line); bool findClosestPt(Common::Point &sourcePt, Common::Point &closestPt, Common::Point &destPt); diff --git a/engines/illusions/resources/backgroundresource.cpp b/engines/illusions/resources/backgroundresource.cpp index 2a37bba4a8..933ba25e7e 100644 --- a/engines/illusions/resources/backgroundresource.cpp +++ b/engines/illusions/resources/backgroundresource.cpp @@ -402,7 +402,8 @@ void BackgroundInstance::load(Resource *resource) { registerResources(); - // TODO camera_fadeClear(); + _vm->clearFader(); + int index = _bgRes->findMasterBgIndex(); _vm->_camera->set(_bgRes->_bgInfos[index - 1]._panPoint, _bgRes->_bgInfos[index - 1]._surfInfo._dimensions); @@ -442,7 +443,7 @@ void BackgroundInstance::unpause() { _vm->_screenPalette->setPalette(_savedPalette, 1, 256); delete[] _savedPalette; _savedPalette = 0; - // TODO _vm->_screen->_fadeClear(); + _vm->clearFader(); _vm->_camera->setActiveState(_savedCameraState); _vm->_backgroundInstances->refreshPan(); } diff --git a/engines/illusions/resources/midiresource.cpp b/engines/illusions/resources/midiresource.cpp index 5e6e85a4ee..060565b02a 100644 --- a/engines/illusions/resources/midiresource.cpp +++ b/engines/illusions/resources/midiresource.cpp @@ -29,13 +29,71 @@ namespace Illusions { void MidiGroupResourceLoader::load(Resource *resource) { debug(1, "MidiGroupResourceLoader::load() Loading midi group %08X...", resource->_resId); + MidiGroupInstance *midiGroupInstance = new MidiGroupInstance(_vm); + midiGroupInstance->load(resource); + resource->_instance = midiGroupInstance; +} - // TODO +bool MidiGroupResourceLoader::isFlag(int flag) { + return + flag == kRlfLoadFile/* || + flag == kRlfFreeDataAfterLoad*/; +} +// MidiMusic + +void MidiMusic::load(Common::SeekableReadStream &stream) { + _musicId = stream.readUint32LE(); + _looping = stream.readUint16LE() != 0; + stream.skip(2 + 32 + 4); // Skip unused/unknown values + debug(1, "MidiMusic::load() _musicId: %08X; _looping: %d", _musicId, _looping); } -bool MidiGroupResourceLoader::isFlag(int flag) { - return false; +// MidiGroupResource + +MidiGroupResource::MidiGroupResource() + : _midiMusicCount(0), _midiMusic(0) { +} + +MidiGroupResource::~MidiGroupResource() { + delete[] _midiMusic; +} + +void MidiGroupResource::load(byte *data, uint32 dataSize) { + Common::MemoryReadStream stream(data, dataSize, DisposeAfterUse::NO); + + stream.skip(4); + _midiMusicCount = stream.readUint16LE(); + stream.skip(2); + uint32 midiMusicOffs = stream.readUint32LE(); + debug("_midiMusicCount: %d; midiMusicOffs: %08X", _midiMusicCount, midiMusicOffs); + _midiMusic = new MidiMusic[_midiMusicCount]; + stream.seek(midiMusicOffs); + for (uint i = 0; i < _midiMusicCount; ++i) + _midiMusic[i].load(stream); + +} + +// MidiGroupInstance + +MidiGroupInstance::MidiGroupInstance(IllusionsEngine *vm) + : _vm(vm), _midiGroupResource(0) { +} + +void MidiGroupInstance::load(Resource *resource) { + _midiGroupResource = new MidiGroupResource(); + _midiGroupResource->load(resource->_data, resource->_dataSize); + for (uint i = 0; i < _midiGroupResource->_midiMusicCount; ++i) { + // TODO + // SoundEffect *soundEffect = &_soundGroupResource->_soundEffects[i]; + // _vm->_soundMan->loadSound(soundEffect->_soundEffectId, resource->_resId, soundEffect->_looping); + } + _resId = resource->_resId; +} + +void MidiGroupInstance::unload() { + // _vm->_soundMan->unloadSounds(_resId); + delete _midiGroupResource; } } // End of namespace Illusions diff --git a/engines/illusions/resources/midiresource.h b/engines/illusions/resources/midiresource.h index 1cd3f806ef..fee4486fb8 100644 --- a/engines/illusions/resources/midiresource.h +++ b/engines/illusions/resources/midiresource.h @@ -40,6 +40,33 @@ protected: IllusionsEngine *_vm; }; +struct MidiMusic { + uint32 _musicId; + bool _looping; + void load(Common::SeekableReadStream &stream); +}; + +class MidiGroupResource { +public: + MidiGroupResource(); + ~MidiGroupResource(); + void load(byte *data, uint32 dataSize); +public: + uint _midiMusicCount; + MidiMusic *_midiMusic; +}; + +class MidiGroupInstance : public ResourceInstance { +public: + MidiGroupInstance(IllusionsEngine *vm); + virtual void load(Resource *resource); + virtual void unload(); +public: + IllusionsEngine *_vm; + MidiGroupResource *_midiGroupResource; + uint32 _resId; +}; + } // End of namespace Illusions #endif // ILLUSIONS_SOUNDRESOURCE_H diff --git a/engines/illusions/sound.cpp b/engines/illusions/sound.cpp index d976069beb..1e8ca49f88 100644 --- a/engines/illusions/sound.cpp +++ b/engines/illusions/sound.cpp @@ -23,6 +23,7 @@ #include "common/config-manager.h" #include "illusions/illusions.h" #include "illusions/sound.h" +#include "audio/mididrv.h" #include "audio/midiparser.h" namespace Illusions { @@ -76,68 +77,125 @@ bool MusicPlayer::isPlaying() { // MidiPlayer -MidiPlayer::MidiPlayer() { - MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM); - _driver = MidiDriver::createMidi(dev); - assert(_driver); - _paused = false; +MidiPlayer::MidiPlayer() + : _isIdle(true), _isPlaying(false), _isCurrentlyPlaying(false), _isLooped(false), + _loopedMusicId(0), _queuedMusicId(0), _loadedMusicId(0), + _data(0), _dataSize(0) { + _data = 0; + _dataSize = 0; + _isGM = false; + + MidiPlayer::createDriver(); int ret = _driver->open(); if (ret == 0) { - _driver->sendGMReset(); + if (_nativeMT32) + _driver->sendMT32Reset(); + else + _driver->sendGMReset(); _driver->setTimerCallback(this, &timerCallback); } } -void MidiPlayer::play(const Common::String &filename) { - Common::StackLock lock(_mutex); +MidiPlayer::~MidiPlayer() { + sysMidiStop(); +} - stop(); +bool MidiPlayer::play(uint32 musicId) { + debug("MidiPlayer::play(%08X)", musicId); + bool isMusicLooping = true; // TODO Use actual flag - Common::File *fd = new Common::File(); - if (!fd->open(filename)) { - delete fd; - error("MidiPlayer::play() Could not load %s", filename.c_str()); - } + if (!_isIdle) + return false; - uint32 size = (uint32)fd->size(); - _midiData = (uint8 *)malloc(size); + if (_isPlaying) { + if (isMusicLooping) { + _loopedMusicId = musicId; + } else { + _queuedMusicId = musicId; + _isIdle = false; + } + return true; + } - if (_midiData) { - fd->read(_midiData, size); + if (_isCurrentlyPlaying && _loopedMusicId == musicId) + return true; - syncVolume(); // FIXME: syncVolume calls setVolume which in turn also locks the mutex! ugh + sysMidiStop(); - _parser = MidiParser::createParser_SMF(); - _parser->loadMusic(_midiData, size); - _parser->setTrack(0); - _parser->setMidiDriver(this); - _parser->setTimerRate(_driver->getBaseTempo()); - _isLooping = true; + _isLooped = isMusicLooping; + if (_isLooped) { + _loopedMusicId = musicId; + } else { _isPlaying = true; } - fd->close(); - delete fd; + + sysMidiPlay(musicId); + + _isCurrentlyPlaying = true; + + return true; } -void MidiPlayer::pause(bool p) { - _paused = p; +void MidiPlayer::stop() { + sysMidiStop(); + _isIdle = true; + _isPlaying = false; + _isCurrentlyPlaying = false; + _loopedMusicId = 0; + _queuedMusicId = 0; +} - for (int i = 0; i < kNumChannels; ++i) { - if (_channelsTable[i]) { - _channelsTable[i]->volume(_paused ? 0 : _channelsVolume[i] * _masterVolume / 255); - } +void MidiPlayer::sysMidiPlay(uint32 musicId) { + Common::StackLock lock(_mutex); + + Common::String filename = Common::String::format("%08x.mid", musicId); + debug(0, "MidiPlayer::sysMidiPlay() %s", filename.c_str()); + + Common::File fd; + if (!fd.open(filename)) { + error("MidiPlayer::sysMidiPlay() Could not open %s", filename.c_str()); + } + + _dataSize = fd.size(); + _data = new byte[_dataSize]; + fd.read(_data, _dataSize); + + _isGM = true; + _loadedMusicId = musicId; + + MidiParser *parser = MidiParser::createParser_SMF(); + if (parser->loadMusic(_data, _dataSize)) { + parser->setTrack(0); + parser->setMidiDriver(this); + parser->setTimerRate(_driver->getBaseTempo()); + parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1); + + _parser = parser; + + syncVolume(); + + Audio::MidiPlayer::_isLooping = _isLooped; + Audio::MidiPlayer::_isPlaying = true; } } -void MidiPlayer::onTimer() { - Common::StackLock lock(_mutex); +void MidiPlayer::sysMidiStop() { + Audio::MidiPlayer::stop(); + delete[] _data; + _data = 0; + _dataSize = 0; + _loadedMusicId = 0; +} - if (!_paused && _isPlaying && _parser) { - _parser->onTimer(); +void MidiPlayer::send(uint32 b) { + if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) { + b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8; } + + Audio::MidiPlayer::send(b); } void MidiPlayer::sendToChannel(byte channel, uint32 b) { @@ -153,9 +211,20 @@ void MidiPlayer::sendToChannel(byte channel, uint32 b) { _channelsTable[channel]->send(b); } -void MidiPlayer::fade(int16 finalVolume, int16 duration) { - //TODO fade here. - debug(0, "Fade midi. finalVolume: %d, duration: %d", finalVolume, duration); +void MidiPlayer::endOfTrack() { + uint32 nextMusicId = _queuedMusicId; + if (nextMusicId == 0) + nextMusicId = _loopedMusicId; + + if (_isLooped && _loadedMusicId == nextMusicId) { + Audio::MidiPlayer::endOfTrack(); + return; + } + + sysMidiStop(); + _queuedMusicId = 0; + _isIdle = true; + play(nextMusicId); } // VoicePlayer @@ -279,6 +348,7 @@ SoundMan::~SoundMan() { } void SoundMan::update() { + updateMidi(); // TODO voc_testCued(); if (_musicNotifyThreadId && !_musicPlayer->isPlaying()) _vm->notifyThreadId(_musicNotifyThreadId); @@ -294,6 +364,20 @@ void SoundMan::stopMusic() { _musicPlayer->stop(); } +void SoundMan::playMidiMusic(uint32 musicId) { + if (!_midiPlayer->play(musicId)) { + _midiMusicQueue.push_back(musicId); + } +} + +void SoundMan::stopMidiMusic() { + _midiPlayer->stop(); +} + +void SoundMan::clearMidiMusicQueue() { + _midiMusicQueue.clear(); +} + bool SoundMan::cueVoice(const char *voiceName) { return _voicePlayer->cue(voiceName); } @@ -363,17 +447,13 @@ Sound *SoundMan::getSound(uint32 soundEffectId) { return 0; } -void SoundMan::playMidiMusic(uint32 musicId) { - Common::String filename = Common::String::format("%08x.MID", musicId); - _midiPlayer->play(filename); -} - -void SoundMan::stopMidiMusic() { - _midiPlayer->stop(); -} - -void SoundMan::fadeMidiMusic(int16 finalVolume, int16 duration) { - _midiPlayer->fade(finalVolume, duration); +void SoundMan::updateMidi() { + if (_midiPlayer->isIdle() & !_midiMusicQueue.empty()) { + uint32 musicId = _midiMusicQueue.front(); + _midiMusicQueue.remove_at(0); + _midiPlayer->play(musicId); + } + // TODO Update music volume fading } void SoundMan::setMusicVolume(uint16 volume) { @@ -408,5 +488,4 @@ uint16 SoundMan::getSfxVolume() { uint16 SoundMan::getSpeechVolume() { return (uint16)ConfMan.getInt("speech_volume"); } - } // End of namespace Illusions diff --git a/engines/illusions/sound.h b/engines/illusions/sound.h index f6a96d5aaa..8d5f21eed9 100644 --- a/engines/illusions/sound.h +++ b/engines/illusions/sound.h @@ -25,9 +25,10 @@ #include "illusions/graphics.h" #include "audio/audiostream.h" +#include "audio/decoders/wave.h" #include "audio/midiplayer.h" #include "audio/mixer.h" -#include "audio/decoders/wave.h" +#include "common/array.h" #include "common/list.h" namespace Illusions { @@ -50,23 +51,26 @@ protected: class MidiPlayer : public Audio::MidiPlayer { public: MidiPlayer(); - - void pause(bool p); - void play(const Common::String &filename); - void fade(int16 finalVolume, int16 duration); - - // The following line prevents compiler warnings about hiding the pause() - // method from the parent class. - // FIXME: Maybe the pause(bool p) method should be removed and the - // pause/resume methods of the parent class be used instead? - virtual void pause() { Audio::MidiPlayer::pause(); } - - // Overload Audio::MidiPlayer method + ~MidiPlayer(); + bool play(uint32 musicId); + void stop(); + bool isIdle() const { return _isIdle; } +protected: + bool _isIdle; + bool _isPlaying; + bool _isCurrentlyPlaying; + bool _isLooped; + uint32 _loopedMusicId; + uint32 _queuedMusicId; + uint32 _loadedMusicId; + byte *_data; + uint _dataSize; + bool _isGM; + void sysMidiPlay(uint32 musicId); + void sysMidiStop(); + virtual void send(uint32 b); virtual void sendToChannel(byte channel, uint32 b); - virtual void onTimer(); - -private: - bool _paused; + virtual void endOfTrack(); }; class VoicePlayer { @@ -116,7 +120,7 @@ public: void playMidiMusic(uint32 musicId); void stopMidiMusic(); - void fadeMidiMusic(int16 finalVolume, int16 duration); + void clearMidiMusicQueue(); uint16 getMusicVolume(); uint16 getSfxVolume(); @@ -149,7 +153,9 @@ protected: MidiPlayer *_midiPlayer; VoicePlayer *_voicePlayer; SoundList _sounds; + Common::Array<uint32> _midiMusicQueue; Sound *getSound(uint32 soundEffectId); + void updateMidi(); uint16 calcAdjustedVolume(const Common::String &volumeConfigKey, uint16 volume); }; |