diff options
Diffstat (limited to 'simon')
-rw-r--r-- | simon/midi.cpp | 170 | ||||
-rw-r--r-- | simon/midi.h | 40 | ||||
-rw-r--r-- | simon/simon.cpp | 19 |
3 files changed, 131 insertions, 98 deletions
diff --git a/simon/midi.cpp b/simon/midi.cpp index c751fb866e..02cf6aec8a 100644 --- a/simon/midi.cpp +++ b/simon/midi.cpp @@ -34,23 +34,18 @@ MidiPlayer::MidiPlayer (OSystem *system) { _system = system; _mutex = system->create_mutex(); _driver = 0; - _parser = 0; - _data = 0; + _enable_sfx = true; + _current = 0; + memset(_volumeTable, 127, sizeof(_volumeTable)); _masterVolume = 255; _paused = false; + _currentTrack = 255; _loopTrack = 0; - _queuedTrack = 255; _loopQueuedTrack = 0; - - _num_songs = 0; - memset(_songs, 0, sizeof(_songs)); - memset(_song_sizes, 0, sizeof(_song_sizes)); - - _midi_sfx_toggle = false; } MidiPlayer::~MidiPlayer() { @@ -83,6 +78,9 @@ void MidiPlayer::close() { } void MidiPlayer::send (uint32 b) { + if (!_current) + return; + byte volume; if ((b & 0xFFF0) == 0x07B0) { @@ -90,9 +88,16 @@ void MidiPlayer::send (uint32 b) { volume = (byte) ((b >> 16) & 0xFF) * _masterVolume / 255; _volumeTable [b & 0xF] = volume; b = (b & 0xFF00FFFF) | (volume << 16); - } else if ((b & 0xF0) == 0xE0) { - // Skip pitch bends completely. They're screwed up in Simon games. - return; + } else if ((b & 0xF0) == 0xC0) { + int chan = b & 0x0F; + if (!_current->in_use [chan]) + _driver->send (0x007BB0 | chan); // All Notes Off + _current->in_use [chan] = true; + } else if ((b & 0xFFF0) == 0x007BB0) { + // Only respond to an All Notes Off if this channel + // has already been marked "in use" by this parser. + if (!_current->in_use [b & 0x0F]) + return; } _driver->send (b); @@ -100,11 +105,11 @@ void MidiPlayer::send (uint32 b) { void MidiPlayer::metaEvent (byte type, byte *data, uint16 length) { // Only thing we care about is End of Track. - if (type != 0x2F) + if (!_current || type != 0x2F || _current == &_sfx) return; if (_loopTrack) { - _parser->jumpToTick (0); + _current->parser->jumpToTick (0); } else if (_queuedTrack != 255) { _currentTrack = 255; byte destination = _queuedTrack; @@ -125,48 +130,57 @@ void MidiPlayer::metaEvent (byte type, byte *data, uint16 length) { } void MidiPlayer::onTimer (void *data) { - MidiPlayer *player = (MidiPlayer *) data; - player->_system->lock_mutex (player->_mutex); - if (!player->_paused && player->_parser && player->_currentTrack != 255) - player->_parser->onTimer(); - player->_system->unlock_mutex (player->_mutex); + MidiPlayer *p = (MidiPlayer *) data; + p->_system->lock_mutex (p->_mutex); + if (!p->_paused) { + if (p->_music.parser && p->_currentTrack != 255) { + p->_current = &p->_music; + p->_music.parser->onTimer(); + } + if (p->_sfx.parser) { + p->_current = &p->_sfx; + p->_sfx.parser->onTimer(); + } + p->_current = 0; + } + p->_system->unlock_mutex (p->_mutex); } void MidiPlayer::startTrack (int track) { if (track == _currentTrack) return; - if (_num_songs > 0) { - if (track >= _num_songs) + if (_music.num_songs > 0) { + if (track >= _music.num_songs) return; _system->lock_mutex (_mutex); - if (_parser) { - delete _parser; - _parser = 0; + if (_music.parser) { + delete _music.parser; + _music.parser = 0; } MidiParser *parser = MidiParser::createParser_SMF(); parser->property (MidiParser::mpMalformedPitchBends, 1); parser->setMidiDriver (this); parser->setTimerRate (_driver->getBaseTempo()); - if (!parser->loadMusic (_songs[track], _song_sizes[track])) { + if (!parser->loadMusic (_music.songs[track], _music.song_sizes[track])) { printf ("Error reading track!\n"); delete parser; parser = 0; } _currentTrack = (byte) track; - _parser = parser; // That plugs the power cord into the wall - } else if (_parser) { + _music.parser = parser; // That plugs the power cord into the wall + } else if (_music.parser) { _system->lock_mutex (_mutex); - if (!_parser->setTrack (track)) { + if (!_music.parser->setTrack (track)) { _system->unlock_mutex (_mutex); return; } _currentTrack = (byte) track; - _parser->jumpToTick (0); + _music.parser->jumpToTick (0); } _system->unlock_mutex (_mutex); @@ -174,8 +188,8 @@ void MidiPlayer::startTrack (int track) { void MidiPlayer::stop() { _system->lock_mutex (_mutex); - if (_parser) - _parser->jumpToTick(0); + if (_music.parser) + _music.parser->jumpToTick(0); _currentTrack = 255; _system->unlock_mutex (_mutex); } @@ -239,23 +253,21 @@ void MidiPlayer::queueTrack (int track, bool loop) { } void MidiPlayer::clearConstructs() { - if (_num_songs > 0) { - byte i; - for (i = 0; i < _num_songs; ++i) { - free (_songs [i]); - } - _num_songs = 0; - } - - if (_data) { - free (_data); - _data = 0; - } + clearConstructs (_music); + clearConstructs (_sfx); +} - if (_parser) { - delete _parser; - _parser = 0; +void MidiPlayer::clearConstructs (MusicInfo &info) { + if (info.num_songs > 0) { + byte i; + for (i = 0; i < info.num_songs; ++i) + free (info.songs [i]); } + if (info.data) + free (info.data); + if (info.parser) + delete info.parser; + info.clear(); } static int simon1_gmf_size[] = { @@ -265,9 +277,10 @@ static int simon1_gmf_size[] = { 17256, 5103, 8794, 4884, 16 }; -void MidiPlayer::loadSMF (File *in, int song) { +void MidiPlayer::loadSMF (File *in, int song, bool sfx) { _system->lock_mutex (_mutex); - clearConstructs(); + MusicInfo *p = sfx ? &_sfx : &_music; + clearConstructs (*p); uint32 size = in->size() - in->pos(); if (size > 64000) @@ -276,31 +289,33 @@ void MidiPlayer::loadSMF (File *in, int song) { // When allocating space, add 4 bytes in case // this is a GMF and we have to tack on our own // End of Track event. - _data = (byte *) calloc (size + 4, 1); - in->read (_data, size); + p->data = (byte *) calloc (size + 4, 1); + in->read (p->data, size); // For GMF files, we're going to have to use // hardcoded size tables. - if (!memcmp (_data, "GMF\x1", 4) && size == 64000) + if (!memcmp (p->data, "GMF\x1", 4) && size == 64000) size = simon1_gmf_size [song]; MidiParser *parser = MidiParser::createParser_SMF(); parser->property (MidiParser::mpMalformedPitchBends, 1); parser->setMidiDriver (this); parser->setTimerRate (_driver->getBaseTempo()); - if (!parser->loadMusic (_data, size)) { + if (!parser->loadMusic (p->data, size)) { printf ("Error reading track!\n"); delete parser; parser = 0; } - _currentTrack = 255; - memset(_volumeTable, 127, sizeof(_volumeTable)); - _parser = parser; // That plugs the power cord into the wall + if (!sfx) { + _currentTrack = 255; + memset(_volumeTable, 127, sizeof(_volumeTable)); + } + p->parser = parser; // That plugs the power cord into the wall _system->unlock_mutex (_mutex); } -void MidiPlayer::loadMultipleSMF (File *in) { +void MidiPlayer::loadMultipleSMF (File *in, bool sfx) { // This is a special case for Simon 2 Windows. // Instead of having multiple sequences as // separate tracks in a Type 2 file, simon2win @@ -311,16 +326,18 @@ void MidiPlayer::loadMultipleSMF (File *in) { // treat them as separate tracks -- for the // purpose of jumps, anyway. _system->lock_mutex (_mutex); - clearConstructs(); - _num_songs = in->readByte(); - if (_num_songs > 16) { - printf ("playMultipleSMF: %d is too many songs to keep track of!\n", (int) _num_songs); + MusicInfo *p = sfx ? &_sfx : &_music; + clearConstructs (*p); + + p->num_songs = in->readByte(); + if (p->num_songs > 16) { + printf ("playMultipleSMF: %d is too many songs to keep track of!\n", (int) p->num_songs); _system->unlock_mutex (_mutex); return; } byte i; - for (i = 0; i < _num_songs; ++i) { + for (i = 0; i < p->num_songs; ++i) { byte buf[5]; uint32 pos = in->pos(); @@ -343,20 +360,23 @@ void MidiPlayer::loadMultipleSMF (File *in) { uint32 pos2 = in->pos() - 4; uint32 size = pos2 - pos; - _songs[i] = (byte *) calloc (size, 1); + p->songs[i] = (byte *) calloc (size, 1); in->seek (pos, SEEK_SET); - in->read (_songs[i], size); - _song_sizes[i] = size; + in->read (p->songs[i], size); + p->song_sizes[i] = size; } - _currentTrack = 255; - memset(_volumeTable, 127, sizeof(_volumeTable)); + if (!sfx) { + _currentTrack = 255; + memset(_volumeTable, 127, sizeof(_volumeTable)); + } _system->unlock_mutex (_mutex); } -void MidiPlayer::loadXMIDI (File *in) { +void MidiPlayer::loadXMIDI (File *in, bool sfx) { _system->lock_mutex (_mutex); - clearConstructs(); + MusicInfo *p = sfx ? &_sfx : &_music; + clearConstructs (*p); char buf[4]; uint32 pos = in->pos(); @@ -378,8 +398,8 @@ void MidiPlayer::loadXMIDI (File *in) { } size += 4 + in->readUint32BE(); in->seek (pos, 0); - _data = (byte *) calloc (size, 1); - in->read (_data, size); + p->data = (byte *) calloc (size, 1); + in->read (p->data, size); } else { printf ("ERROR! Expected 'FORM' tag but found '%c%c%c%c' instead!\n", buf[0], buf[1], buf[2], buf[3]); _system->unlock_mutex (_mutex); @@ -389,14 +409,16 @@ void MidiPlayer::loadXMIDI (File *in) { MidiParser *parser = MidiParser::createParser_XMIDI(); parser->setMidiDriver (this); parser->setTimerRate (_driver->getBaseTempo()); - if (!parser->loadMusic (_data, size)) { + if (!parser->loadMusic (p->data, size)) { printf ("Error reading track!\n"); delete parser; parser = 0; } - _currentTrack = 255; - memset(_volumeTable, 127, sizeof(_volumeTable)); - _parser = parser; // That plugs the power cord into the wall + if (!sfx) { + _currentTrack = 255; + memset(_volumeTable, 127, sizeof(_volumeTable)); + } + p->parser = parser; // That plugs the power cord into the wall _system->unlock_mutex (_mutex); } diff --git a/simon/midi.h b/simon/midi.h index 8e14a239bc..02930f8960 100644 --- a/simon/midi.h +++ b/simon/midi.h @@ -28,38 +28,58 @@ class File; class OSystem; +struct MusicInfo { + MidiParser *parser; + byte * data; + byte num_songs; // For Type 1 SMF resources + byte * songs[16]; // For Type 1 SMF resources + uint32 song_sizes[16]; // For Type 1 SMF resources + bool in_use[16]; // Tracks which resource is using which MIDI channels + + MusicInfo() { clear(); } + void clear() { + parser = 0; data = 0; num_songs = 0; + memset (songs, 0, sizeof (songs)); + memset (song_sizes, 0, sizeof (song_sizes)); + memset (in_use, 0, sizeof (in_use)); + } +}; + class MidiPlayer : public MidiDriver { protected: OSystem *_system; void *_mutex; MidiDriver *_driver; - MidiParser *_parser; - byte *_data; + MusicInfo _music; + MusicInfo _sfx; + MusicInfo *_current; // Allows us to establish current context for operations. + + // These are maintained for both music and SFX byte _volumeTable[16]; // 0-127 byte _masterVolume; // 0-255 bool _paused; + + // These are only used for music. byte _currentTrack; bool _loopTrack; byte _queuedTrack; bool _loopQueuedTrack; - byte _num_songs; - byte *_songs[16]; - uint32 _song_sizes[16]; - static void onTimer (void *data); void clearConstructs(); + void clearConstructs (MusicInfo &info); public: - bool _midi_sfx_toggle; + bool _enable_sfx; +public: MidiPlayer (OSystem *system); virtual ~MidiPlayer(); - void loadSMF (File *in, int song); - void loadMultipleSMF (File *in); - void loadXMIDI (File *in); + void loadSMF (File *in, int song, bool sfx = false); + void loadMultipleSMF (File *in, bool sfx = false); + void loadXMIDI (File *in, bool sfx = false); void setLoop (bool loop); void startTrack(int track); diff --git a/simon/simon.cpp b/simon/simon.cpp index 6e58d81931..59323cc93c 100644 --- a/simon/simon.cpp +++ b/simon/simon.cpp @@ -1065,7 +1065,7 @@ void SimonState::loadTablesIntoMem(uint subr_id) { } void SimonState::playSting(uint a) { - if (!midi._midi_sfx_toggle) + if (!midi._enable_sfx) return; char filename[11]; @@ -1088,7 +1088,7 @@ void SimonState::playSting(uint a) { // midi.shutdown(); _mus_file->seek(_mus_offsets[a], SEEK_SET); - midi.loadSMF (_mus_file, a); + midi.loadSMF (_mus_file, a, true); midi.startTrack (0); } @@ -3335,13 +3335,9 @@ void SimonState::processSpecialKeys() { break; case 's': - if (_game == GAME_SIMON1DOS) { - midi._midi_sfx_toggle ^= 1; - if (midi._midi_sfx_toggle) - midi.stop(); - else - loadMusic(_last_music_played); - } else + if (_game == GAME_SIMON1DOS) + midi._enable_sfx ^= 1; + else _sound->effectsPause(_effects_paused ^= 1); break; @@ -4990,8 +4986,6 @@ void SimonState::go() { if (_language >= 2) _subtitles = true; - midi._midi_sfx_toggle = false; - while (1) { hitarea_stuff(); handle_verb_clicked(_verb_hitarea); @@ -5292,9 +5286,6 @@ bool SimonState::load_game(uint slot) { } void SimonState::loadMusic (uint music) { - if (midi._midi_sfx_toggle) - return; - if (_game & GF_SIMON2) { // Simon 2 music midi.stop(); _game_file->seek(_game_offsets_ptr[gss->MUSIC_INDEX_BASE + music - 1], SEEK_SET); |