diff options
-rw-r--r-- | saga/events.cpp | 3 | ||||
-rw-r--r-- | saga/ite_introproc.cpp | 3 | ||||
-rw-r--r-- | saga/music.cpp | 194 | ||||
-rw-r--r-- | saga/reinherit.h | 16 | ||||
-rw-r--r-- | saga/saga.cpp | 12 | ||||
-rw-r--r-- | saga/saga.h | 2 | ||||
-rw-r--r-- | saga/sceneproc.cpp | 3 | ||||
-rw-r--r-- | saga/sound.cpp | 2 | ||||
-rw-r--r-- | saga/sound.h | 1 |
9 files changed, 178 insertions, 58 deletions
diff --git a/saga/events.cpp b/saga/events.cpp index 3a7a009177..b1e104a623 100644 --- a/saga/events.cpp +++ b/saga/events.cpp @@ -47,6 +47,7 @@ #include "render_mod.h" #include "game_mod.h" #include "sndres.h" +#include "music.h" /* * Begin module @@ -315,7 +316,7 @@ static int HandleOneShot(R_EVENT * event) case R_MUSIC_EVENT: - SYSMUSIC_Play(event->param, event->param2); + _vm->_music->play(event->param, event->param2); break; case R_BG_EVENT: diff --git a/saga/ite_introproc.cpp b/saga/ite_introproc.cpp index 37ab1bc862..6b0fb0dfc4 100644 --- a/saga/ite_introproc.cpp +++ b/saga/ite_introproc.cpp @@ -45,6 +45,7 @@ #include "sndres.h" #include "text_mod.h" #include "palanim_mod.h" +#include "music.h" /* * Begin module: @@ -803,7 +804,7 @@ int ITE_IntroValleyProc(int param, R_SCENE_INFO * scene_info) /* Begin ITE title theme music * \*----------------------------------------------------- */ - SYSMUSIC_Stop(); + _vm->_music->stop(); event.type = R_ONESHOT_EVENT; event.code = R_MUSIC_EVENT; diff --git a/saga/music.cpp b/saga/music.cpp index 2c230679bf..f345cfb83b 100644 --- a/saga/music.cpp +++ b/saga/music.cpp @@ -20,78 +20,200 @@ * $Header$ * */ +#include "saga.h" #include "reinherit.h" #include "yslib.h" -namespace Saga { - -static int MusicInitialized = 0; +#include "music.h" +#include "rscfile_mod.h" +#include "game_mod.h" +#include "sound/mididrv.h" +#include "sound/midiparser.h" -int SYSMUSIC_Init(int enabled) -{ - YS_IGNORE_PARAM(enabled); +namespace Saga { - if (MusicInitialized) { - return R_FAILURE; +// Instrument mapping for MT32 tracks emulated under GM. +static const byte mt32_to_gm[128] = { +// 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 0, 2, 4, 4, 5, 3, 16, 17, 18, 16, 16, 19, 20, 21, // 0x + 6, 6, 6, 7, 7, 7, 8, 112, 62, 62, 63, 63, 38, 38, 39, 39, // 1x + 88, 95, 52, 98, 97, 99, 14, 54, 102, 96, 53, 102, 81, 100, 14, 80, // 2x + 48, 48, 49, 45, 41, 40, 42, 42, 43, 46, 45, 24, 25, 28, 27, 104, // 3x + 32, 32, 34, 33, 36, 37, 35, 35, 79, 73, 72, 72, 74, 75, 64, 65, // 4x + 66, 67, 71, 71, 68, 69, 70, 22, 56, 59, 57, 57, 60, 60, 58, 61, // 5x + 61, 11, 11, 98, 14, 9, 14, 13, 12, 107, 107, 77, 78, 78, 76, 76, // 6x + 47, 117, 127, 118, 118, 116, 115, 119, 115, 112, 55, 124, 123, 0, 14, 117 // 7x +}; + +MusicPlayer::MusicPlayer(MidiDriver *driver) : _driver(driver), _looping(false) { + this->open(); +} + +MusicPlayer::~MusicPlayer() { + _driver->setTimerCallback(NULL, NULL); + _parser->unloadMusic(); + this->close(); + } + +void MusicPlayer::setVolume(int volume) { + if (volume < 0) + volume = 0; + else if (volume > 255) + volume = 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) { + 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 && !_nativeMT32) { + b = (b & 0xFFFF00FF) | mt32_to_gm[(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(); - MusicInitialized = 1; - return R_SUCCESS; + if (_channel[channel]) + _channel[channel]->send(b); +} + +void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) { + //Only thing we care about is End of Track. + if (type != 0x2F) + return; + + if (_looping) + _parser->jumpToTick(0); + else + stopMusic(); +} + +void MusicPlayer::onTimer(void *refCon) { + MusicPlayer *music = (MusicPlayer *)refCon; + if (music->_isPlaying) + music->_parser->onTimer(); +} + +void MusicPlayer::playMusic() { + _isPlaying = true; +} + +void MusicPlayer::stopMusic() { + _isPlaying = false; + _parser->unloadMusic(); } -int SYSMUSIC_Shutdown(void) -{ - if (!MusicInitialized) { - return R_FAILURE; - } - MusicInitialized = 0; - return R_SUCCESS; +Music::Music(MidiDriver *driver, int enabled) : _enabled(enabled) { + _player = new MusicPlayer(driver); + _musicInitialized = 1; } -int SYSMUSIC_Play(ulong music_rn, uint flags) -{ - if (!MusicInitialized) { +Music::~Music() { + delete _player; +} + +int Music::play(ulong music_rn, uint flags) { + R_RSCFILE_CONTEXT *rsc_ctxt = NULL; + + uchar *resource_data; + size_t resource_size; + + if (!_musicInitialized) { return R_FAILURE; } - YS_IGNORE_PARAM(music_rn); - YS_IGNORE_PARAM(flags); + if (!_enabled) { + return R_SUCCESS; + } + + /* Load XMI resource data */ + GAME_GetFileContext(&rsc_ctxt, R_GAME_RESOURCEFILE, 0); + + if (RSC_LoadResource(rsc_ctxt, music_rn, &resource_data, + &resource_size) != R_SUCCESS ) { + R_printf(R_STDERR, "SYSMUSIC_Play(): Resource load failed: %ld", + music_rn); + return R_FAILURE; + } + + MidiParser *parser = MidiParser::createParser_XMIDI(); + if (!parser->loadMusic(resource_data, resource_size)) { + warning("Error reading track!"); + delete parser; + parser = 0; + } - return R_SUCCESS; + debug(0, "Music::play(%d, %d)", music_rn, flags); + parser->setTrack(0); + _player->_parser = parser; + _player->playMusic(); + return R_SUCCESS; } -int SYSMUSIC_Pause(void) -{ - if (!MusicInitialized) { +int Music::pause(void) { + if (!_musicInitialized) { return R_FAILURE; } return R_SUCCESS; - } -int SYSMUSIC_Resume(void) -{ - if (!MusicInitialized) { +int Music::resume(void) { + if (!_musicInitialized) { return R_FAILURE; } return R_SUCCESS; - } -int SYSMUSIC_Stop(void) -{ - - if (!MusicInitialized) { +int Music::stop(void) { + if (!_musicInitialized) { return R_FAILURE; } return R_SUCCESS; - } } // End of namespace Saga diff --git a/saga/reinherit.h b/saga/reinherit.h index c6e5c107e1..49f30b3ace 100644 --- a/saga/reinherit.h +++ b/saga/reinherit.h @@ -142,22 +142,6 @@ int TRANSITION_Dissolve(uchar *dst_img, \*--------------------------------------------------------------------------*/ /* - * System : Music -\*--------------------------------------------------------------------------*/ -enum SYSMUSIC_FLAGS { - - R_MUSIC_LOOP = 0x01 -}; - -int SYSMUSIC_Init(int enabled); -int SYSMUSIC_Shutdown(void); - -int SYSMUSIC_Play(ulong music_rn, uint flags); -int SYSMUSIC_Pause(void); -int SYSMUSIC_Resume(void); -int SYSMUSIC_Stop(void); - -/* * System : Graphics \*--------------------------------------------------------------------------*/ #define R_PAL_ENTRIES 256 diff --git a/saga/saga.cpp b/saga/saga.cpp index 668f354551..10d139bccc 100644 --- a/saga/saga.cpp +++ b/saga/saga.cpp @@ -55,6 +55,7 @@ #include "text_mod.h" #include "objectmap_mod.h" #include "sound.h" +#include "music.h" struct SAGAGameSettings { const char *name; @@ -176,6 +177,7 @@ void SagaEngine::go() { SCENE_Register(); MainData.sound_enabled = 1; + MainData.music_enabled = 1; CVAR_RegisterFunc(CF_testfunc, "testfunc", "foo [ optional foo ]", R_CVAR_NONE, 0, -1); @@ -242,7 +244,13 @@ void SagaEngine::go() { /* On some platforms, graphics initialization also initializes sound * ( Win32 DirectX )... Music must be initialized before sound for * native midi support */ - SYSMUSIC_Init(MainData.music_enabled); + MidiDriver *driver = GameDetector::createMidi(GameDetector::detectMusicDriver(MDT_NATIVE | MDT_ADLIB | MDT_PREFER_NATIVE)); + if (!driver) + driver = MidiDriver_ADLIB_create(_mixer); + else if (ConfMan.getBool("native_mt32")) + driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); + + _music = new Music(driver, MainData.music_enabled); if (!MainData.music_enabled) { R_printf(R_STDOUT, "Music disabled.\n"); } @@ -319,7 +327,7 @@ void SagaEngine::shutdown() { delete _sndRes; /* Shutdown system modules */ - SYSMUSIC_Shutdown(); + delete _music; delete _sound; _system->quit(); diff --git a/saga/saga.h b/saga/saga.h index 270b61e137..2221fd433d 100644 --- a/saga/saga.h +++ b/saga/saga.h @@ -36,6 +36,7 @@ namespace Saga { class SndRes; class Sound; +class Music; #define R_PBOUNDS(n,max) (((n)>=(0))&&((n)<(max))) @@ -59,6 +60,7 @@ class SagaEngine:public Engine { SndRes *_sndRes; Sound *_sound; + Music *_music; }; // FIXME: Global var. We use it until everything will be turned into objects diff --git a/saga/sceneproc.cpp b/saga/sceneproc.cpp index 3782aa5f3d..4a3d06ac19 100644 --- a/saga/sceneproc.cpp +++ b/saga/sceneproc.cpp @@ -41,6 +41,7 @@ #include "scene_mod.h" #include "palanim_mod.h" #include "sound.h" +#include "music.h" /* * Begin module @@ -66,7 +67,7 @@ int InitialSceneProc(int param, R_SCENE_INFO * scene_info) case SCENE_BEGIN: - SYSMUSIC_Stop(); + _vm->_music->stop(); _vm->_sound->stopVoice(); /* Fade palette to black from intro scene diff --git a/saga/sound.cpp b/saga/sound.cpp index 1b3b95d91d..30a05b08d1 100644 --- a/saga/sound.cpp +++ b/saga/sound.cpp @@ -40,7 +40,7 @@ namespace Saga { \*--------------------------------------------------------------------------*/ Sound::Sound(SagaEngine *vm, SoundMixer *mixer, int enabled) : - _vm(vm), _mixer(mixer) { + _vm(vm), _mixer(mixer), _enabled(enabled) { int result; /* Load sound module resource file contexts */ diff --git a/saga/sound.h b/saga/sound.h index a9307b8d0b..8101925c3a 100644 --- a/saga/sound.h +++ b/saga/sound.h @@ -69,6 +69,7 @@ class Sound { private: int _soundInitialized; + int _enabled; R_GAME_SOUNDINFO _snd_info; |