mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-13 21:31:53 +00:00
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
This commit is contained in:
parent
c8276b4684
commit
aacbaac131
170
simon/midi.cpp
170
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) {
|
||||
clearConstructs (_music);
|
||||
clearConstructs (_sfx);
|
||||
}
|
||||
|
||||
void MidiPlayer::clearConstructs (MusicInfo &info) {
|
||||
if (info.num_songs > 0) {
|
||||
byte i;
|
||||
for (i = 0; i < _num_songs; ++i) {
|
||||
free (_songs [i]);
|
||||
}
|
||||
_num_songs = 0;
|
||||
}
|
||||
|
||||
if (_data) {
|
||||
free (_data);
|
||||
_data = 0;
|
||||
}
|
||||
|
||||
if (_parser) {
|
||||
delete _parser;
|
||||
_parser = 0;
|
||||
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);
|
||||
}
|
||||
|
40
simon/midi.h
40
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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user