aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/draci/draci.cpp18
-rw-r--r--engines/draci/draci.h4
-rw-r--r--engines/draci/game.cpp6
-rw-r--r--engines/draci/module.mk1
-rw-r--r--engines/draci/music.cpp213
-rw-r--r--engines/draci/music.h101
6 files changed, 343 insertions, 0 deletions
diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp
index 4c52398737..19732e7687 100644
--- a/engines/draci/draci.cpp
+++ b/engines/draci/draci.cpp
@@ -61,6 +61,7 @@ const char *initPath = "INIT.DFW";
const char *stringsPath = "RETEZCE.DFW";
const char *soundsPath = "CD2.SAM";
const char *dubbingPath = "CD.SAM";
+const char *musicPathMask = "HUDBA%d.MID";
const uint kSoundsFrequency = 13000;
const uint kDubbingFrequency = 22000;
@@ -117,6 +118,18 @@ int DraciEngine::init() {
_dubbingArchive = new SoundArchive(dubbingPath, kDubbingFrequency);
_sound = new Sound(_mixer);
+ int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI);
+ bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));
+ //bool adlib = (midiDriver == MD_ADLIB);
+
+ _midiDriver = MidiDriver::createMidi(midiDriver);
+ if (native_mt32)
+ _midiDriver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+
+ _music = new MusicPlayer(_midiDriver, musicPathMask);
+ _music->setNativeMT32(native_mt32);
+ //_music->setAdlib(adlib);
+
// Load the game's fonts
_smallFont = new Font(kFontSmall);
_bigFont = new Font(kFontBig);
@@ -303,6 +316,8 @@ DraciEngine::~DraciEngine() {
delete _soundsArchive;
delete _dubbingArchive;
delete _sound;
+ delete _music;
+ delete _midiDriver;
// Remove all of our debug levels here
Common::clearAllDebugChannels();
@@ -332,10 +347,12 @@ void DraciEngine::pauseEngineIntern(bool pause) {
_anims->pauseAnimations();
_sound->pauseSound();
_sound->pauseVoice();
+ _music->pause();
} else {
_anims->unpauseAnimations();
_sound->resumeSound();
_sound->resumeVoice();
+ _music->resume();
// Adjust engine start time
const int delta = _system->getMillis() - _pauseStartTime;
@@ -349,6 +366,7 @@ void DraciEngine::syncSoundSettings() {
Engine::syncSoundSettings();
_sound->setVolume();
+ _music->setVolume(ConfMan.getInt("music_volume"));
}
const char *DraciEngine::getSavegameFile(int saveGameIdx) {
diff --git a/engines/draci/draci.h b/engines/draci/draci.h
index 6ef339de33..8de37ac312 100644
--- a/engines/draci/draci.h
+++ b/engines/draci/draci.h
@@ -29,6 +29,7 @@
#include "common/system.h"
#include "engines/engine.h"
#include "engines/advancedDetector.h"
+#include "sound/mididrv.h"
#include "draci/game.h"
#include "draci/mouse.h"
@@ -38,6 +39,7 @@
#include "draci/barchive.h"
#include "draci/animation.h"
#include "draci/sound.h"
+#include "draci/music.h"
namespace Draci {
@@ -67,6 +69,8 @@ public:
Script *_script;
AnimationManager *_anims;
Sound *_sound;
+ MusicPlayer *_music;
+ MidiDriver *_midiDriver;
Font *_smallFont;
Font *_bigFont;
diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp
index 1694d81cf0..773f97ce64 100644
--- a/engines/draci/game.cpp
+++ b/engines/draci/game.cpp
@@ -1123,6 +1123,12 @@ void Game::loadRoom(int roomNum) {
Animation *map = _vm->_anims->addAnimation(kWalkingMapOverlay, 255, false);
map->addFrame(ov, NULL);
+
+ if (_currentRoom._music) {
+ _vm->_music->playSMF(_currentRoom._music, true);
+ } else {
+ _vm->_music->stop();
+ }
}
int Game::loadAnimation(uint animNum, uint z) {
diff --git a/engines/draci/module.mk b/engines/draci/module.mk
index 1810ddff2f..2005c0b095 100644
--- a/engines/draci/module.mk
+++ b/engines/draci/module.mk
@@ -8,6 +8,7 @@ MODULE_OBJS := \
font.o \
saveload.o \
sound.o \
+ music.o \
sprite.o \
screen.o \
surface.o \
diff --git a/engines/draci/music.cpp b/engines/draci/music.cpp
new file mode 100644
index 0000000000..b63c171974
--- /dev/null
+++ b/engines/draci/music.cpp
@@ -0,0 +1,213 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/engines/made/music.cpp $
+ * $Id: music.cpp 35843 2009-01-13 10:11:52Z thebluegr $
+ *
+ */
+
+// FIXME: This code is taken from SAGA and needs more work (e.g. setVolume).
+
+// MIDI and digital music class
+
+#include "sound/audiostream.h"
+#include "sound/mididrv.h"
+#include "sound/midiparser.h"
+#include "common/config-manager.h"
+#include "common/file.h"
+
+#include "draci/draci.h"
+#include "draci/music.h"
+
+namespace Draci {
+
+MusicPlayer::MusicPlayer(MidiDriver *driver, const char *pathMask) : _parser(0), _driver(driver), _pathMask(pathMask), _looping(false), _isPlaying(false), _passThrough(false), _isGM(false) {
+ memset(_channel, 0, sizeof(_channel));
+ _masterVolume = 0;
+ this->open();
+ _smfParser = MidiParser::createParser_SMF();
+ _midiMusicData = NULL;
+}
+
+MusicPlayer::~MusicPlayer() {
+ _driver->setTimerCallback(NULL, NULL);
+ stop();
+ this->close();
+ _smfParser->setMidiDriver(NULL);
+ delete _smfParser;
+ delete _midiMusicData;
+}
+
+void MusicPlayer::setVolume(int volume) {
+ volume = CLIP(volume, 0, 255);
+
+ if (_masterVolume == volume)
+ return;
+
+ _masterVolume = volume;
+
+ Common::StackLock lock(_mutex);
+
+ for (int i = 0; i < 16; ++i) {
+ if (_channel[i]) {
+ _channel[i]->volume(_channelVolume[i] * _masterVolume / 255);
+ }
+ }
+}
+
+int MusicPlayer::open() {
+ // Don't ever call open without first setting the output driver!
+ if (!_driver)
+ return 255;
+
+ int ret = _driver->open();
+ if (ret)
+ return ret;
+
+ _driver->setTimerCallback(this, &onTimer);
+ return 0;
+}
+
+void MusicPlayer::close() {
+ stop();
+ if (_driver)
+ _driver->close();
+ _driver = 0;
+}
+
+void MusicPlayer::send(uint32 b) {
+ if (_passThrough) {
+ _driver->send(b);
+ return;
+ }
+
+ byte channel = (byte)(b & 0x0F);
+ if ((b & 0xFFF0) == 0x07B0) {
+ // Adjust volume changes by master volume
+ byte volume = (byte)((b >> 16) & 0x7F);
+ _channelVolume[channel] = volume;
+ volume = volume * _masterVolume / 255;
+ b = (b & 0xFF00FFFF) | (volume << 16);
+ } else if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) {
+ b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
+ }
+ else if ((b & 0xFFF0) == 0x007BB0) {
+ //Only respond to All Notes Off if this channel
+ //has currently been allocated
+ if (_channel[b & 0x0F])
+ return;
+ }
+
+ if (!_channel[channel])
+ _channel[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
+
+ if (_channel[channel])
+ _channel[channel]->send(b);
+}
+
+void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) {
+
+ switch (type) {
+ case 0x2F: // End of Track
+ if (_looping)
+ _parser->jumpToTick(0);
+ else
+ stop();
+ break;
+ default:
+ //warning("Unhandled meta event: %02x", type);
+ break;
+ }
+}
+
+void MusicPlayer::onTimer(void *refCon) {
+ MusicPlayer *music = (MusicPlayer *)refCon;
+ Common::StackLock lock(music->_mutex);
+
+ if (music->_isPlaying)
+ music->_parser->onTimer();
+}
+
+void MusicPlayer::playSMF(int track, bool loop) {
+ if (_isPlaying && track == _track)
+ return;
+
+ stop();
+
+ _isGM = true;
+
+ debugC(2, kDraciSoundDebugLevel, "Playing track %d", track);
+
+ // Load MIDI resource data
+ Common::File musicFile;
+ char musicFileName[40];
+ sprintf(musicFileName, _pathMask.c_str(), track);
+ musicFile.open(musicFileName);
+ int midiMusicSize = musicFile.size();
+ delete _midiMusicData;
+ _midiMusicData = new byte[midiMusicSize];
+ musicFile.read(_midiMusicData, midiMusicSize);
+ musicFile.close();
+
+ if (_smfParser->loadMusic(_midiMusicData, midiMusicSize)) {
+ MidiParser *parser = _smfParser;
+ parser->setTrack(0);
+ parser->setMidiDriver(this);
+ parser->setTimerRate(getBaseTempo());
+ parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+
+ _parser = parser;
+
+ setVolume(127);
+
+ _looping = loop;
+ _isPlaying = true;
+ _track = track;
+ }
+}
+
+void MusicPlayer::stop() {
+ Common::StackLock lock(_mutex);
+
+ _isPlaying = false;
+ if (_parser) {
+ _parser->unloadMusic();
+ _parser = NULL;
+ }
+}
+
+void MusicPlayer::pause() {
+ setVolume(-1);
+ _isPlaying = false;
+}
+
+void MusicPlayer::resume() {
+ setVolume(127);
+ _isPlaying = true;
+}
+
+// TODO:
+// - volume support
+// - bindings to GPL2 scripting
+// - load cmf.ins
+// - enable Adlib
+// - resuming after load
+
+} // End of namespace Draci
diff --git a/engines/draci/music.h b/engines/draci/music.h
new file mode 100644
index 0000000000..bd8ffe6301
--- /dev/null
+++ b/engines/draci/music.h
@@ -0,0 +1,101 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/engines/made/music.h $
+ * $Id: music.h 31873 2008-05-05 12:51:50Z john_doe $
+ *
+ */
+
+// Music class
+
+#ifndef DRACI_MUSIC_H
+#define DRACI_MUSIC_H
+
+#include "sound/mididrv.h"
+#include "sound/midiparser.h"
+#include "common/mutex.h"
+
+namespace Draci {
+
+// Taken from MADE, which took it from SAGA.
+
+class MusicPlayer : public MidiDriver {
+public:
+ MusicPlayer(MidiDriver *driver, const char *pathMask);
+ ~MusicPlayer();
+
+ bool isPlaying() { return _isPlaying; }
+ void setPlaying(bool playing) { _isPlaying = playing; }
+
+ void setVolume(int volume);
+ int getVolume() { return _masterVolume; }
+
+ void setNativeMT32(bool b) { _nativeMT32 = b; }
+ bool hasNativeMT32() { return _nativeMT32; }
+ void playSMF(int track, bool loop);
+ void stop();
+ void pause();
+ void resume();
+ void setLoop(bool loop) { _looping = loop; }
+ void setPassThrough(bool b) { _passThrough = b; }
+
+ void setGM(bool isGM) { _isGM = isGM; }
+
+ //MidiDriver interface implementation
+ int open();
+ void close();
+ void send(uint32 b);
+
+ void metaEvent(byte type, byte *data, uint16 length);
+
+ void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { }
+ uint32 getBaseTempo(void) { return _driver ? _driver->getBaseTempo() : 0; }
+
+ //Channel allocation functions
+ MidiChannel *allocateChannel() { return 0; }
+ MidiChannel *getPercussionChannel() { return 0; }
+
+ MidiParser *_parser;
+ Common::Mutex _mutex;
+
+protected:
+
+ static void onTimer(void *data);
+
+ MidiChannel *_channel[16];
+ MidiDriver *_driver;
+ MidiParser *_smfParser;
+ Common::String _pathMask;
+ byte _channelVolume[16];
+ bool _nativeMT32;
+ bool _isGM;
+ bool _passThrough;
+
+ bool _isPlaying;
+ bool _looping;
+ byte _masterVolume;
+ int _track;
+
+ byte *_midiMusicData;
+};
+
+} // End of namespace Draci
+
+#endif