diff options
-rw-r--r-- | simon/midi.cpp | 39 | ||||
-rw-r--r-- | simon/midi.h | 1 | ||||
-rw-r--r-- | simon/midiparser_s1d.cpp | 171 | ||||
-rw-r--r-- | simon/simon.cpp | 14 |
4 files changed, 224 insertions, 1 deletions
diff --git a/simon/midi.cpp b/simon/midi.cpp index b1129e15b8..663769ec55 100644 --- a/simon/midi.cpp +++ b/simon/midi.cpp @@ -27,6 +27,13 @@ #include "sound/mixer.h" #include "simon/simon.h" +// MidiParser_S1D is not considered part of the standard +// MidiParser suite, but we still try to mask its details +// and just provide a factory function. +extern MidiParser *MidiParser_createS1D(); + + + MidiPlayer::MidiPlayer (OSystem *system) { // Since initialize() is called every time the music changes, // this is where we'll initialize stuff that must persist @@ -448,3 +455,35 @@ void MidiPlayer::loadXMIDI (File *in, bool sfx) { p->parser = parser; // That plugs the power cord into the wall _system->unlock_mutex (_mutex); } + +void MidiPlayer::loadS1D (File *in, bool sfx) { + _system->lock_mutex (_mutex); + MusicInfo *p = sfx ? &_sfx : &_music; + clearConstructs (*p); + + uint32 size = in->readByte() | (in->readByte() << 8); + if (size != in->size() - 2) { + printf ("ERROR! Size mismatch in simon1demo MUS file (%ld versus reported %d)\n", (long) in->size() - 2, (long) size); + _system->unlock_mutex (_mutex); + return; + } + + p->data = (byte *) calloc (size, 1); + in->read (p->data, size); + + MidiParser *parser = MidiParser_createS1D(); + parser->setMidiDriver (this); + parser->setTimerRate (_driver->getBaseTempo()); + if (!parser->loadMusic (p->data, size)) { + printf ("Error reading track!\n"); + delete parser; + parser = 0; + } + + 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 2c6c6acbf8..95637f2c91 100644 --- a/simon/midi.h +++ b/simon/midi.h @@ -80,6 +80,7 @@ public: void loadSMF (File *in, int song, bool sfx = false); void loadMultipleSMF (File *in, bool sfx = false); void loadXMIDI (File *in, bool sfx = false); + void loadS1D (File *in, bool sfx = false); void setLoop (bool loop); void startTrack(int track); diff --git a/simon/midiparser_s1d.cpp b/simon/midiparser_s1d.cpp new file mode 100644 index 0000000000..1f327d19a3 --- /dev/null +++ b/simon/midiparser_s1d.cpp @@ -0,0 +1,171 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001-2003 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "sound/midiparser.h" +#include "sound/mididrv.h" +#include "common/util.h" + +#include <stdio.h> +#include <memory.h> + +////////////////////////////////////////////////// +// +// Simon 1 Demo version of MidiParser +// +////////////////////////////////////////////////// + +class MidiParser_S1D : public MidiParser { +protected: + byte *_data; + bool _no_delta; + +protected: + void parseNextEvent (EventInfo &info); + void resetTracking(); + uint32 readVLQ2 (byte * &data); + +public: + MidiParser_S1D() : _data(0), _no_delta(false) {} + + bool loadMusic (byte *data, uint32 size); + void unloadMusic(); +}; + + + +////////////////////////////////////////////////// +// +// MidiParser_S1D implementation +// +// This parser is the result of eyeballing the +// one MUS file that's included with simon1demo. +// So there might be some things missing. +// I've tried to notate question-mark areas +// where they occur. +// +////////////////////////////////////////////////// + +// The VLQs for simon1demo seem to be +// in Little Endian format. +uint32 MidiParser_S1D::readVLQ2 (byte * &data) { + byte str; + uint32 value = 0; + int i; + + for (i = 0; i < 4; ++i) { + str = data[0]; + ++data; + value |= (str & 0x7F) << (i * 7); + if (!(str & 0x80)) + break; + } + return value; +} + +void MidiParser_S1D::parseNextEvent (EventInfo &info) { + info.start = _position._play_pos; + info.delta = _no_delta ? 0 : readVLQ2 (_position._play_pos); + + _no_delta = false; + info.event = *(_position._play_pos++); + if (info.command() < 0x8) { + _no_delta = true; + info.event += 0x80; + } + + switch (info.command()) { + case 0x8: + info.basic.param1 = *(_position._play_pos++); + info.basic.param2 = 0; + info.length = 0; + break; + + case 0x9: + info.basic.param1 = *(_position._play_pos++); + info.basic.param2 = *(_position._play_pos++); // I'm ASSUMING this byte is velocity! + info.length = 0; + break; + + case 0xC: + info.basic.param1 = *(_position._play_pos++); + info.basic.param2 = 0; + ++_position._play_pos; // I have NO IDEA what the second byte is for. + break; + + case 0xF: + if (info.event == 0xFC) { + // This means End of Track. + // Rewrite in SMF (MIDI transmission) form. + info.event = 0xFF; + info.ext.type = 0x2F; + info.length = 0; + break; + } + // OTherwise fall through to default. + + default: + printf ("MidiParser_S1D: Warning! Unexpected byte 0x%02X found!\n", (int) info.event); + _abort_parse = true; + _position._play_pos = 0; + } +} + +bool MidiParser_S1D::loadMusic (byte *data, uint32 size) { + unloadMusic(); + + byte *pos = data; + if (*(pos++) != 0xFC) { + printf ("Warning: Expected 0xFC header but found 0x%02X instead\n", (int) *pos); + return false; + } + + // The next 3 bytes MIGHT be tempo, but we skip them and use the default. +// setTempo (*(pos++) | (*(pos++) << 8) | (*(pos++) << 16)); + pos += 3; + + // And now we're at the actual data. Only one track. + _num_tracks = 1; + _data = pos; + _tracks[0] = pos; + + // Note that we assume the original data passed in + // will persist beyond this call, i.e. we do NOT + // copy the data to our own buffer. Take warning.... + resetTracking(); + setTempo (500000); + setTrack (0); + return true; +} + +void MidiParser_S1D::resetTracking() { + MidiParser::resetTracking(); + _no_delta = false; +} + +void MidiParser_S1D::unloadMusic() { + resetTracking(); + allNotesOff(); + _data = 0; + _num_tracks = 0; + _active_track = 255; +} + +MidiParser *MidiParser_createS1D() { return new MidiParser_S1D; }
\ No newline at end of file diff --git a/simon/simon.cpp b/simon/simon.cpp index 970cb3454c..8a238294a9 100644 --- a/simon/simon.cpp +++ b/simon/simon.cpp @@ -5300,7 +5300,19 @@ void SimonState::loadMusic (uint music) { // TODO Add Protracker support for simon1amiga/cd32 warning("playMusic - Load %dtune attempt", music); } else if (_game & GF_DEMO) { - // TODO Add music support for simon1demo + midi.stop(); + midi.setLoop (true); + char buf[50]; + File *f = new File(); + sprintf(buf, "MOD%d.MUS", music); + f->open(buf, _gameDataPath); + if (f->isOpen() == false) { + warning("Can't load music from '%s'", buf); + return; + } + midi.loadS1D (f); + delete f; + midi.startTrack (0); } else { midi.stop(); midi.setLoop (true); // Must do this BEFORE loading music. (GMF may have its own override.) |