diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/made/made.cpp | 20 | ||||
-rw-r--r-- | engines/made/made.h | 5 | ||||
-rw-r--r-- | engines/made/module.mk | 1 | ||||
-rw-r--r-- | engines/made/music.cpp | 274 | ||||
-rw-r--r-- | engines/made/music.h | 150 | ||||
-rw-r--r-- | engines/made/resource.cpp | 20 | ||||
-rw-r--r-- | engines/made/resource.h | 16 | ||||
-rw-r--r-- | engines/made/screen.cpp | 16 | ||||
-rw-r--r-- | engines/made/screen.h | 3 | ||||
-rw-r--r-- | engines/made/scriptfuncs.cpp | 24 |
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; } |