aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Haisch2008-04-23 23:22:02 +0000
committerBenjamin Haisch2008-04-23 23:22:02 +0000
commitefeb8a319370bc913dc93f21b77aedeaa3777b7d (patch)
treec6d7898fa4a26a6d6f340e86d4ec1a840923afbe
parent6562a7cd8abae364b1ca481e4cbdab8f422feaf9 (diff)
downloadscummvm-rg350-efeb8a319370bc913dc93f21b77aedeaa3777b7d.tar.gz
scummvm-rg350-efeb8a319370bc913dc93f21b77aedeaa3777b7d.tar.bz2
scummvm-rg350-efeb8a319370bc913dc93f21b77aedeaa3777b7d.zip
Added (early) midi player code.
Added "screen flash" effect. Implemented opcodes: - o1_PLAYMUS - o1_STOPMUS - o1_ISMUS - o1_FLASH - o1_LOADSND - o1_LOADMUS svn-id: r31682
-rw-r--r--engines/made/made.cpp20
-rw-r--r--engines/made/made.h5
-rw-r--r--engines/made/module.mk1
-rw-r--r--engines/made/music.cpp274
-rw-r--r--engines/made/music.h150
-rw-r--r--engines/made/resource.cpp20
-rw-r--r--engines/made/resource.h16
-rw-r--r--engines/made/screen.cpp16
-rw-r--r--engines/made/screen.h3
-rw-r--r--engines/made/scriptfuncs.cpp24
10 files changed, 525 insertions, 4 deletions
diff --git a/engines/made/made.cpp b/engines/made/made.cpp
index 2d04e8272e..51da50f7d3 100644
--- a/engines/made/made.cpp
+++ b/engines/made/made.cpp
@@ -44,6 +44,7 @@
#include "made/screen.h"
#include "made/script.h"
#include "made/sound.h"
+#include "made/music.h"
#include "made/redreader.h"
namespace Made {
@@ -88,6 +89,24 @@ MadeEngine::MadeEngine(OSystem *syst, const MadeGameDescription *gameDesc) : Eng
_dat = new GameDatabase();
_script = new ScriptInterpreter(this);
+ 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 *driver = MidiDriver::createMidi(midiDriver);
+ if (native_mt32)
+ driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+
+ _music = new Music(driver, _musicVolume);
+ _music->setNativeMT32(native_mt32);
+ _music->setAdlib(adlib);
+
+ _musicVolume = ConfMan.getInt("music_volume");
+
+ if (!_musicVolume) {
+ debug(1, "Music disabled.");
+ }
+
}
MadeEngine::~MadeEngine() {
@@ -97,6 +116,7 @@ MadeEngine::~MadeEngine() {
delete _screen;
delete _dat;
delete _script;
+ delete _music;
}
int MadeEngine::init() {
diff --git a/engines/made/made.h b/engines/made/made.h
index d897509d31..8cf26c0d81 100644
--- a/engines/made/made.h
+++ b/engines/made/made.h
@@ -61,6 +61,7 @@ class PmvPlayer;
class Screen;
class ScriptInterpreter;
class GameDatabase;
+class Music;
class MadeEngine : public ::Engine {
int _gameId;
@@ -93,10 +94,12 @@ public:
Screen *_screen;
GameDatabase *_dat;
ScriptInterpreter *_script;
+ Music *_music;
int _eventMouseX, _eventMouseY;
- int _soundRate;
uint16 _eventKey;
+ int _soundRate;
+ int _musicVolume;
int32 _timers[50];
int16 getTimer(int16 timerNum);
diff --git a/engines/made/module.mk b/engines/made/module.mk
index 1f4cf73cb8..9963f19660 100644
--- a/engines/made/module.mk
+++ b/engines/made/module.mk
@@ -5,6 +5,7 @@ MODULE_OBJS = \
detection.o \
graphics.o \
made.o \
+ music.o \
pmvplayer.o \
redreader.o \
resource.o \
diff --git a/engines/made/music.cpp b/engines/made/music.cpp
new file mode 100644
index 0000000000..8394e78b24
--- /dev/null
+++ b/engines/made/music.cpp
@@ -0,0 +1,274 @@
+/* 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$
+ * $Id$
+ *
+ */
+
+// 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 "made/music.h"
+
+namespace Made {
+
+MusicPlayer::MusicPlayer(MidiDriver *driver) : _parser(0), _driver(driver), _looping(false), _isPlaying(false), _passThrough(false), _isGM(false) {
+ memset(_channel, 0, sizeof(_channel));
+ _masterVolume = 0;
+ this->open();
+}
+
+MusicPlayer::~MusicPlayer() {
+ _driver->setTimerCallback(NULL, NULL);
+ stopMusic();
+ this->close();
+}
+
+void MusicPlayer::setVolume(int volume) {
+ volume = CLIP(volume, 0, 255);
+
+ if (_masterVolume == volume)
+ return;
+
+ _masterVolume = volume;
+
+ 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() {
+ stopMusic();
+ 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
+ stopMusic();
+ 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::playMusic() {
+ _isPlaying = true;
+}
+
+void MusicPlayer::stopMusic() {
+ Common::StackLock lock(_mutex);
+
+ _isPlaying = false;
+ if (_parser) {
+ _parser->unloadMusic();
+ _parser = NULL;
+ }
+}
+
+Music::Music(MidiDriver *driver, int enabled) : _enabled(enabled), _adlib(false) {
+ _player = new MusicPlayer(driver);
+ _currentVolume = 0;
+
+ xmidiParser = MidiParser::createParser_XMIDI();
+
+ _songTableLen = 0;
+ _songTable = 0;
+
+ _midiMusicData = NULL;
+}
+
+Music::~Music() {
+ delete _player;
+ xmidiParser->setMidiDriver(NULL);
+ delete xmidiParser;
+
+ free(_songTable);
+ if (_midiMusicData)
+ delete[] _midiMusicData;
+}
+
+void Music::setVolume(int volume, int time) {
+ _targetVolume = volume * 2; // ScummVM has different volume scale
+ _currentVolumePercent = 0;
+
+ if (volume == -1) // Set Full volume
+ volume = 255;
+
+ if (time == 1) {
+ _player->setVolume(volume);
+ _currentVolume = volume;
+ return;
+ }
+
+}
+
+bool Music::isPlaying() {
+ return _player->isPlaying();
+}
+
+void Music::play(XmidiResource *midiResource, MusicFlags flags) {
+ MidiParser *parser;
+ byte *resourceData;
+ size_t resourceSize;
+
+ debug(2, "Music::play %d", flags);
+
+ if (!_enabled) {
+ return;
+ }
+
+ if (isPlaying()) {
+ return;
+ }
+
+ _player->stopMusic();
+
+ /*
+ if (!_vm->_musicVolume) {
+ return;
+ }
+ */
+
+ if (flags == MUSIC_DEFAULT) {
+ flags = MUSIC_NORMAL;
+ }
+
+ // Load MIDI/XMI resource data
+
+ _player->setGM(true);
+
+ resourceSize = midiResource->getSize();
+ resourceData = new byte[resourceSize];
+ memcpy(resourceData, midiResource->getData(), resourceSize);
+
+ if (resourceSize < 4) {
+ error("Music::play() wrong music resource size");
+ }
+
+ if (xmidiParser->loadMusic(resourceData, resourceSize)) {
+ //_player->setGM(false);
+ parser = xmidiParser;
+ }
+
+ parser->setTrack(0);
+ parser->setMidiDriver(_player);
+ parser->setTimerRate(_player->getBaseTempo());
+ parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+
+ _player->_parser = parser;
+ //setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25);
+ setVolume(255);
+
+ if (flags & MUSIC_LOOP)
+ _player->setLoop(true);
+ else
+ _player->setLoop(false);
+
+ _player->playMusic();
+ if (_midiMusicData)
+ delete[] _midiMusicData;
+ _midiMusicData = resourceData;
+}
+
+void Music::pause(void) {
+ _player->setVolume(-1);
+ _player->setPlaying(false);
+}
+
+void Music::resume(void) {
+ //_player->setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25);
+ setVolume(255);
+ _player->setPlaying(true);
+}
+
+void Music::stop(void) {
+ _player->stopMusic();
+}
+
+} // End of namespace Made
diff --git a/engines/made/music.h b/engines/made/music.h
new file mode 100644
index 0000000000..1403a7c0a1
--- /dev/null
+++ b/engines/made/music.h
@@ -0,0 +1,150 @@
+/* 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$
+ * $Id$
+ *
+ */
+
+// Music class
+
+#ifndef MADE_MUSIC_H
+#define MADE_MUSIC_H
+
+#include "sound/audiocd.h"
+#include "sound/mididrv.h"
+#include "sound/midiparser.h"
+#include "sound/mp3.h"
+#include "sound/vorbis.h"
+#include "sound/flac.h"
+#include "common/mutex.h"
+
+#include "made/resource.h"
+
+namespace Made {
+
+enum MusicFlags {
+ MUSIC_NORMAL = 0,
+ MUSIC_LOOP = 0x0001,
+ MUSIC_DEFAULT = 0xffff
+};
+
+class MusicPlayer : public MidiDriver {
+public:
+ MusicPlayer(MidiDriver *driver);
+ ~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 playMusic();
+ void stopMusic();
+ 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;
+ byte _channelVolume[16];
+ bool _nativeMT32;
+ bool _isGM;
+ bool _passThrough;
+
+ bool _isPlaying;
+ bool _looping;
+ bool _randomLoop;
+ byte _masterVolume;
+
+ byte *_musicData;
+ uint16 *_buf;
+ size_t _musicDataSize;
+};
+
+class Music {
+public:
+
+ Music(MidiDriver *driver, int enabled);
+ ~Music(void);
+ void setNativeMT32(bool b) { _player->setNativeMT32(b); }
+ bool hasNativeMT32() { return _player->hasNativeMT32(); }
+ void setAdlib(bool b) { _adlib = b; }
+ bool hasAdlib() { return _adlib; }
+ void setPassThrough(bool b) { _player->setPassThrough(b); }
+ bool isPlaying(void);
+
+ void play(XmidiResource *midiResource, MusicFlags flags = MUSIC_DEFAULT);
+ void pause(void);
+ void resume(void);
+ void stop(void);
+
+ void setVolume(int volume, int time = 1);
+ int getVolume() { return _currentVolume; }
+
+ int32 *_songTable;
+ int _songTableLen;
+
+private:
+
+ MusicPlayer *_player;
+ uint32 _trackNumber;
+
+ int _enabled;
+ bool _adlib;
+
+ int _targetVolume;
+ int _currentVolume;
+ int _currentVolumePercent;
+
+ MidiParser *xmidiParser;
+
+ byte *_midiMusicData;
+
+};
+
+} // End of namespace Made
+
+#endif
diff --git a/engines/made/resource.cpp b/engines/made/resource.cpp
index cb7cf6e7f5..4450d86c31 100644
--- a/engines/made/resource.cpp
+++ b/engines/made/resource.cpp
@@ -205,6 +205,22 @@ const char *MenuResource::getString(uint index) const {
return NULL;
}
+/* XmidiResource */
+
+XmidiResource::XmidiResource() : _data(NULL), _size(0) {
+}
+
+XmidiResource::~XmidiResource() {
+ if (_data)
+ delete[] _data;
+}
+
+void XmidiResource::load(byte *source, int size) {
+ _data = new byte[size];
+ _size = size;
+ memcpy(_data, source, size);
+}
+
/* ProjectReader */
ProjectReader::ProjectReader() {
@@ -269,6 +285,10 @@ MenuResource *ProjectReader::getMenu(int index) {
return createResource<MenuResource>(kResMENU, index);
}
+XmidiResource *ProjectReader::getXmidi(int index) {
+ return createResource<XmidiResource>(kResXMID, index);
+}
+
void ProjectReader::loadIndex(ResourceSlots *slots) {
_fd->readUint32LE(); // skip INDX
_fd->readUint32LE(); // skip index size
diff --git a/engines/made/resource.h b/engines/made/resource.h
index e2f305dc79..5350ed5242 100644
--- a/engines/made/resource.h
+++ b/engines/made/resource.h
@@ -44,7 +44,8 @@ enum ResourceType {
kResFLEX = MKID_BE('FLEX'),
kResSNDS = MKID_BE('SNDS'),
kResANIM = MKID_BE('ANIM'),
- kResMENU = MKID_BE('MENU')
+ kResMENU = MKID_BE('MENU'),
+ kResXMID = MKID_BE('XMID')
};
struct ResourceSlot;
@@ -110,6 +111,18 @@ protected:
Common::Array<Common::String> _strings;
};
+class XmidiResource : public Resource {
+public:
+ XmidiResource();
+ ~XmidiResource();
+ void load(byte *source, int size);
+ byte *getData() const { return _data; }
+ int getSize() const { return _size; }
+protected:
+ byte *_data;
+ int _size;
+};
+
struct ResourceSlot {
uint32 offs;
uint32 size;
@@ -133,6 +146,7 @@ public:
AnimationResource *getAnimation(int index);
SoundResource *getSound(int index);
MenuResource *getMenu(int index);
+ XmidiResource *getXmidi(int index);
void freeResource(Resource *resource);
diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp
index e63854db64..ede49e25f4 100644
--- a/engines/made/screen.cpp
+++ b/engines/made/screen.cpp
@@ -472,4 +472,20 @@ void Screen::show() {
}
+void Screen::flash(int flashCount) {
+ int palSize = _paletteColorCount * 3;
+ if (flashCount < 1)
+ flashCount = 1;
+ for (int i = 0; i < palSize; i++)
+ _fxPalette[i] = CLIP<byte>(255 - _palette[i], 0, 255);
+ while (flashCount--) {
+ setRGBPalette(_fxPalette, 0, _paletteColorCount);
+ _vm->_system->updateScreen();
+ _vm->_system->delayMillis(30);
+ setRGBPalette(_palette, 0, _paletteColorCount);
+ _vm->_system->updateScreen();
+ _vm->_system->delayMillis(30);
+ }
+}
+
} // End of namespace Made
diff --git a/engines/made/screen.h b/engines/made/screen.h
index eb072477a3..fa58dde88d 100644
--- a/engines/made/screen.h
+++ b/engines/made/screen.h
@@ -102,6 +102,7 @@ public:
uint16 placeText(uint16 channelIndex, uint16 textObjectIndex, int16 x, int16 y, uint16 fontNum, int16 textColor, int16 outlineColor);
void show();
+ void flash(int count);
byte _screenPalette[256 * 4];
@@ -111,7 +112,7 @@ protected:
bool _screenLock;
bool _paletteLock;
- byte _palette[768], _newPalette[768];
+ byte _palette[768], _newPalette[768], _fxPalette[768];
int _paletteColorCount, _oldPaletteColorCount;
bool _paletteInitialized, _needPalette;
diff --git a/engines/made/scriptfuncs.cpp b/engines/made/scriptfuncs.cpp
index 5c5995f593..cd3d3daf1a 100644
--- a/engines/made/scriptfuncs.cpp
+++ b/engines/made/scriptfuncs.cpp
@@ -36,6 +36,7 @@
#include "made/script.h"
#include "made/pmvplayer.h"
#include "made/scriptfuncs.h"
+#include "made/music.h"
namespace Made {
@@ -288,15 +289,25 @@ int16 ScriptFunctionsRtz::o1_PLAYSND(int16 argc, int16 *argv) {
}
int16 ScriptFunctionsRtz::o1_PLAYMUS(int16 argc, int16 *argv) {
+ int16 musicId = argv[0];
+ if (musicId > 0) {
+ XmidiResource *xmidi = _vm->_res->getXmidi(musicId);
+ _vm->_music->play(xmidi);
+ _vm->_res->freeResource(xmidi);
+ }
return 0;
}
int16 ScriptFunctionsRtz::o1_STOPMUS(int16 argc, int16 *argv) {
+ _vm->_music->stop();
return 0;
}
int16 ScriptFunctionsRtz::o1_ISMUS(int16 argc, int16 *argv) {
- return 0;
+ if (_vm->_music->isPlaying())
+ return 1;
+ else
+ return 0;
}
int16 ScriptFunctionsRtz::o1_TEXTPOS(int16 argc, int16 *argv) {
@@ -304,6 +315,7 @@ int16 ScriptFunctionsRtz::o1_TEXTPOS(int16 argc, int16 *argv) {
}
int16 ScriptFunctionsRtz::o1_FLASH(int16 argc, int16 *argv) {
+ _vm->_screen->flash(argv[0]);
return 0;
}
@@ -536,10 +548,20 @@ int16 ScriptFunctionsRtz::o1_PLAYMOVIE(int16 argc, int16 *argv) {
}
int16 ScriptFunctionsRtz::o1_LOADSND(int16 argc, int16 *argv) {
+ SoundResource *sound = _vm->_res->getSound(argv[0]);
+ if (sound) {
+ _vm->_res->freeResource(sound);
+ return 1;
+ }
return 0;
}
int16 ScriptFunctionsRtz::o1_LOADMUS(int16 argc, int16 *argv) {
+ XmidiResource *xmidi = _vm->_res->getXmidi(argv[0]);
+ if (xmidi) {
+ _vm->_res->freeResource(xmidi);
+ return 1;
+ }
return 0;
}