aboutsummaryrefslogtreecommitdiff
path: root/simon
diff options
context:
space:
mode:
authorJamieson Christian2003-05-24 01:26:05 +0000
committerJamieson Christian2003-05-24 01:26:05 +0000
commitaacbaac131af433234c4b73fe95446d208eca9df (patch)
tree002177193a590df33c1420b7cb32827f08fd6107 /simon
parentc8276b46842197b8d0abccc5713d76fc128df57f (diff)
downloadscummvm-rg350-aacbaac131af433234c4b73fe95446d208eca9df.tar.gz
scummvm-rg350-aacbaac131af433234c4b73fe95446d208eca9df.tar.bz2
scummvm-rg350-aacbaac131af433234c4b73fe95446d208eca9df.zip
Added support for simultaneous music and MIDI sound effects to simon1dos.
Note that 's' still toggles MIDI sound effects on and off. svn-id: r7872
Diffstat (limited to 'simon')
-rw-r--r--simon/midi.cpp170
-rw-r--r--simon/midi.h40
-rw-r--r--simon/simon.cpp19
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);