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.) | 
