aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/illusions/dictionary.h4
-rw-r--r--engines/illusions/duckman/illusions_duckman.cpp12
-rw-r--r--engines/illusions/duckman/illusions_duckman.h1
-rw-r--r--engines/illusions/duckman/scriptopcodes_duckman.cpp2
-rw-r--r--engines/illusions/illusions.h1
-rw-r--r--engines/illusions/pathfinder.cpp15
-rw-r--r--engines/illusions/pathfinder.h1
-rw-r--r--engines/illusions/resources/backgroundresource.cpp5
-rw-r--r--engines/illusions/resources/midiresource.cpp64
-rw-r--r--engines/illusions/resources/midiresource.h27
-rw-r--r--engines/illusions/sound.cpp183
-rw-r--r--engines/illusions/sound.h42
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);
};