[Scummvm-cvs-logs] CVS: scummvm/sound mididrv.h,1.21,1.22 midiparser.cpp,1.5,1.6 midiparser.h,1.10,1.11

Jamieson Christian jamieson630 at users.sourceforge.net
Thu May 22 21:19:06 CEST 2003


Update of /cvsroot/scummvm/scummvm/sound
In directory sc8-pr-cvs1:/tmp/cvs-serv23560/sound

Modified Files:
	mididrv.h midiparser.cpp midiparser.h 
Log Message:
Revamped iMuse and Player classes. Player now uses MidiParser to parse its data, which will allow it to parse other MIDI formats. To receive parsed data, Player now derives from MidiDriver to act as a "fake MIDI driver".

Miscellaneous upgrades and fixes to MidiParser, including the Smart Jump (which could not be tested before iMuse started making use of the MidiParser).

*** THIS IS A BIG UPGRADE! EXTENSIVE REGRESSION TESTING IS NEEDED! ***

This has been tested through the intros and a number of other scenes from MI2, FOA and S&M.

NOTE! This upgrade introduces savegame format version V19. Earlier version savegames will load, but the music will simply start over from the beginning. Only V19 and later games will properly restore the position of the music! Don't say you weren't warned....

Index: mididrv.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/mididrv.h,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- mididrv.h	18 May 2003 14:50:10 -0000	1.21
+++ mididrv.h	23 May 2003 04:18:26 -0000	1.22
@@ -29,8 +29,9 @@
 
 // Abstract MIDI Driver Class
 class MidiDriver {
-
 public:
+	virtual ~MidiDriver() { }
+
 	// Error codes returned by open.
 	// Can be converted to a string with getErrorName()
 	enum {
@@ -41,7 +42,7 @@
 	};
 
 	enum {
-		PROP_TIMEDIV = 1,
+//		PROP_TIMEDIV = 1,
 		PROP_OLD_ADLIB = 2
 	};
 

Index: midiparser.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/midiparser.cpp,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- midiparser.cpp	22 May 2003 15:34:30 -0000	1.5
+++ midiparser.cpp	23 May 2003 04:18:26 -0000	1.6
@@ -26,6 +26,8 @@
 #include <stdio.h>
 #include <memory.h>
 
+
+
 //////////////////////////////////////////////////
 //
 // MidiParser implementation
@@ -42,15 +44,10 @@
 _smartJump (false),
 _num_tracks (0),
 _active_track (255),
-_play_pos (0),
-_play_time (0),
-_play_tick (0),
-_last_event_time (0),
-_last_event_tick (0),
-_running_status (0),
+_abort_parse (0),
 _hanging_notes_count (0)
 {
-	memset (_active_notes, 0, 128);
+	memset (_active_notes, 0, sizeof(_active_notes));
 }
 
 void MidiParser::property (int prop, int value) {
@@ -62,6 +59,12 @@
 	}
 }
 
+void MidiParser::setTempo (uint32 tempo) {
+	_tempo = tempo;
+	if (_ppqn)
+		_psec_per_tick = (tempo + (_ppqn >> 2)) / _ppqn;
+}
+
 // This is the conventional (i.e. SMF) variable length quantity
 uint32 MidiParser::readVLQ (byte * &data) {
 	byte str;
@@ -137,10 +140,11 @@
 	uint32 end_time;
 	uint32 event_time;
 
-	if (!_play_pos || !_driver)
+	if (!_position._play_pos || !_driver)
 		return;
 
-	end_time = _play_time + _timer_rate;
+	_abort_parse = false;
+	end_time = _position._play_time + _timer_rate;
 
 	// Scan our hanging notes for any
 	// that should be turned off.
@@ -160,18 +164,18 @@
 		}
 	}
 
-	while (true) {
+	while (!_abort_parse) {
 		EventInfo &info = _next_event;
 
-		event_time = _last_event_time + info.delta * _psec_per_tick;
+		event_time = _position._last_event_time + info.delta * _psec_per_tick;
 		if (event_time > end_time)
 			break;
 
 		// Process the next info.
-		_last_event_tick += info.delta;
+		_position._last_event_tick += info.delta;
 		if (info.event < 0x80) {
 			printf ("ERROR! Bad command or running status %02X\n", info.event);
-			_play_pos = 0;
+			_position._play_pos = 0;
 			return;
 		}
 
@@ -185,17 +189,16 @@
 				// as well as sending it to the output device.
 				allNotesOff();
 				if (_autoLoop) {
-					_play_pos = _tracks[_active_track];
+					_position._play_pos = _tracks[_active_track];
 					parseNextEvent (_next_event);
 				} else {
-					_play_pos = 0;
+					_position._play_pos = 0;
 					_driver->metaEvent (info.ext.type, info.ext.data, (uint16) info.length);
 				}
 				return;
 			} else if (info.ext.type == 0x51) {
 				if (info.length >= 3) {
-					_tempo = info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2];
-					_psec_per_tick = (_tempo + (_ppqn >> 2)) / _ppqn;
+					setTempo (info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]);
 				}
 			}
 			_driver->metaEvent (info.ext.type, info.ext.data, (uint16) info.length);
@@ -212,12 +215,16 @@
 		}
 
 
-		_last_event_time = event_time;
-		parseNextEvent (_next_event);
+		if (!_abort_parse) {
+			_position._last_event_time = event_time;
+			parseNextEvent (_next_event);
+		}
 	}
 
-	_play_time = end_time;
-	_play_tick = (_play_time - _last_event_time) / _psec_per_tick + _last_event_tick;
+	if (!_abort_parse) {
+		_position._play_time = end_time;
+		_position._play_tick = (_position._play_time - _position._last_event_time) / _psec_per_tick + _position._last_event_tick;
+	}
 }
 
 void MidiParser::allNotesOff() {
@@ -230,18 +237,11 @@
 	for (i = 0; i < ARRAYSIZE(_hanging_notes); ++i)
 		_hanging_notes[i].time_left = 0;
 	_hanging_notes_count = 0;
-	memset (_active_notes, 0, 128);
+	memset (_active_notes, 0, sizeof(_active_notes));
 }
 
 void MidiParser::resetTracking() {
-	_play_pos = 0;
-	_tempo = 500000;
-	_psec_per_tick = 500000 / _ppqn;
-	_play_time = 0;
-	_play_tick = 0;
-	_last_event_time = 0;
-	_last_event_tick = 0;
-	_running_status = 0;
+	_position.clear();
 }
 
 bool MidiParser::setTrack (int track) {
@@ -250,79 +250,107 @@
 	else if (track == _active_track)
 		return true;
 
+	if (_smartJump)
+		hangAllActiveNotes();
+	else
+		allNotesOff();
+
 	resetTracking();
-	allNotesOff();
 	_active_track = track;
-	_play_pos = _tracks[track];
+	_position._play_pos = _tracks[track];
 	parseNextEvent (_next_event);
 	return true;
 }
 
-void MidiParser::jumpToTick (uint32 tick) {
-	if (_active_track >= _num_tracks)
-		return;
-
-	if (!_smartJump) {
-		allNotesOff();
-	} else {
-		// Search for note off events until we have
-		// accounted for every active note.
-		uint32 advance_tick = _last_event_tick;
-		while (true) {
-			int i;
-			for (i = 0; i < 128; ++i)
-				if (_active_notes[i] != 0) break;
-			if (i == 128) break;
-			parseNextEvent (_next_event);
-			advance_tick += _next_event.delta;
-			if (_next_event.command() == 0x8) {
-				if (_active_notes [_next_event.basic.param1] & (1 << _next_event.channel())) {
-					hangingNote (_next_event.channel(), _next_event.basic.param1, (advance_tick - _last_event_tick) * _psec_per_tick);
-					_active_notes [_next_event.basic.param1] &= ~ (1 << _next_event.channel());
-				}
-			} else if (_next_event.event == 0xFF && _next_event.ext.type == 0x2F) {
-				break;
+void MidiParser::hangAllActiveNotes() {
+	// Search for note off events until we have
+	// accounted for every active note.
+	uint32 advance_tick = _position._last_event_tick;
+	while (true) {
+		int i;
+		for (i = 0; i < 128; ++i)
+			if (_active_notes[i] != 0) break;
+		if (i == 128) break;
+		parseNextEvent (_next_event);
+		advance_tick += _next_event.delta;
+		if (_next_event.command() == 0x8) {
+			if (_active_notes [_next_event.basic.param1] & (1 << _next_event.channel())) {
+				hangingNote (_next_event.channel(), _next_event.basic.param1, (advance_tick - _position._last_event_tick) * _psec_per_tick);
+				_active_notes [_next_event.basic.param1] &= ~ (1 << _next_event.channel());
 			}
+		} else if (_next_event.event == 0xFF && _next_event.ext.type == 0x2F) {
+			printf ("MidiParser::hangAllActiveNotes(): Hit End of Track with active notes left!\n");
+			memset (_active_notes, 0, sizeof (_active_notes));
+			break;
 		}
 	}
+}
+
+bool MidiParser::jumpToTick (uint32 tick, bool fireEvents) {
+	if (_active_track >= _num_tracks)
+		return false;
+
+	Tracker currentPos (_position);
+	EventInfo currentEvent (_next_event);
 
 	resetTracking();
-	_play_pos = _tracks[_active_track];
+	_position._play_pos = _tracks[_active_track];
 	parseNextEvent (_next_event);
-	if (tick == 0)
-		return;
-
-	while (true) {
-		EventInfo &info = _next_event;
-		if (_last_event_tick + info.delta >= tick) {
-			_play_time += (tick - _last_event_tick) * _psec_per_tick;
-			_play_tick = tick;
-			break;
-		}
+	if (tick > 0) {
+		while (true) {
+			EventInfo &info = _next_event;
+			if (_position._last_event_tick + info.delta >= tick) {
+				_position._play_time += (tick - _position._last_event_tick) * _psec_per_tick;
+				_position._play_tick = tick;
+				break;
+			}
 
-		_last_event_tick += info.delta;
-		_play_tick = _last_event_tick;
-		_play_time += info.delta * _psec_per_tick;
-		_last_event_time = _play_time;
+			_position._last_event_tick += info.delta;
+			_position._last_event_time += info.delta * _psec_per_tick;
+			_position._play_tick = _position._last_event_tick;
+			_position._play_time = _position._last_event_time;
 
-		if (info.event == 0xFF) {
-			if (info.ext.type == 0x2F) { // End of track
-				if (_autoLoop) {
-					_play_pos = _tracks[_active_track];
-					parseNextEvent (_next_event);
-				} else {
-					_play_pos = 0;
-					_driver->metaEvent (0x2F, info.ext.data, (uint16) info.length);
-				}
-				break;
-			} else if (info.ext.type == 0x51) { // Tempo
-				if (info.length >= 3) {
-					_tempo = info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2];
-					_psec_per_tick = (_tempo + (_ppqn >> 2)) / _ppqn;
+			if (info.event == 0xFF) {
+				if (info.ext.type == 0x2F) { // End of track
+					if (_autoLoop) {
+						_position._play_pos = _tracks[_active_track];
+						parseNextEvent (_next_event);
+					} else {
+						_position = currentPos;
+						_next_event = currentEvent;
+						return false;
+					}
+					break;
+				} else if (info.ext.type == 0x51) { // Tempo
+					if (info.length >= 3) {
+						setTempo (info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]);
+					}
 				}
+			} else if (fireEvents) {
+				if (info.event == 0xF0)
+					_driver->sysEx (info.ext.data, (uint16) info.length);
+				else
+					_driver->send (info.event | info.basic.param1 << 8 | info.basic.param2 << 16);
 			}
+
+			parseNextEvent (_next_event);
 		}
+	}
 
-		parseNextEvent (_next_event);
+	if (!_smartJump) {
+		allNotesOff();
+	} else {
+		EventInfo targetEvent (_next_event);
+		Tracker targetPosition (_position);
+
+		_position = currentPos;
+		_next_event = currentEvent;
+		hangAllActiveNotes();
+
+		_next_event = targetEvent;
+		_position = targetPosition;
 	}
+
+	_abort_parse = true;
+	return true;
 }

Index: midiparser.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/midiparser.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- midiparser.h	22 May 2003 15:34:30 -0000	1.10
+++ midiparser.h	23 May 2003 04:18:26 -0000	1.11
@@ -28,6 +28,43 @@
 
 class MidiDriver;
 
+
+
+//////////////////////////////////////////////////
+//
+// Support entities
+//
+//////////////////////////////////////////////////
+
+struct Tracker {
+	byte * _play_pos;
+	uint32 _play_time;
+	uint32 _play_tick;
+	uint32 _last_event_time;
+	uint32 _last_event_tick;
+	byte   _running_status;
+
+	Tracker() { clear(); }
+
+	Tracker (const Tracker &copy) :
+	_play_pos (copy._play_pos),
+	_play_time (copy._play_time),
+	_play_tick (copy._play_tick),
+	_last_event_time (copy._last_event_time),
+	_last_event_tick (copy._last_event_tick),
+	_running_status (copy._running_status)
+	{ }
+
+	void clear() {
+		_play_pos = 0;
+		_play_time = 0;
+		_play_tick = 0;
+		_last_event_time = 0;
+		_last_event_tick = 0;
+		_running_status = 0;
+	}
+};
+
 struct EventInfo {
 	byte * start; // Points to delta
 	uint32 delta;
@@ -55,6 +92,15 @@
 	NoteTimer() : channel(0), note(0), time_left(0) {}
 };
 
+
+
+
+//////////////////////////////////////////////////
+//
+// MidiParser declaration
+//
+//////////////////////////////////////////////////
+
 class MidiParser {
 private:
 	uint16    _active_notes[128]; // Each uint16 is a bit mask for channels that have that note on
@@ -70,17 +116,13 @@
 	bool   _autoLoop;       // For lightweight clients that don't monitor events
 	bool   _smartJump;      // Support smart expiration of hanging notes when jumping
 
-	byte * _tracks[16];
+	byte * _tracks[32];
 	byte   _num_tracks;
 	byte   _active_track;
 
-	byte * _play_pos;
-	uint32 _play_time;
-	uint32 _play_tick;
-	uint32 _last_event_time;
-	uint32 _last_event_tick;
-	byte   _running_status;
+	Tracker _position;
 	EventInfo _next_event;
+	bool   _abort_parse;     // If a jump or some other interruption occurs
 
 protected:
 	static uint32 readVLQ (byte * &data);
@@ -90,6 +132,7 @@
 
 	void activeNote (byte channel, byte note, bool active);
 	void hangingNote (byte channel, byte note, uint32 ticks_left);
+	void hangAllActiveNotes();
 
 	// Multi-byte read helpers
 	uint32 read4high (byte * &data) {
@@ -121,11 +164,13 @@
 	virtual void property (int prop, int value);
 
 	void setMidiDriver (MidiDriver *driver) { _driver = driver; }
-	void setTimerRate (uint32 rate) { _timer_rate = rate / 500; }
+	void setTimerRate (uint32 rate) { _timer_rate = rate; }
+	void setTempo (uint32 tempo);
 	void onTimer();
 
 	bool setTrack (int track);
-	void jumpToTick (uint32 tick);
+	bool jumpToTick (uint32 tick, bool fireEvents = false);
+	uint32 getTick() { return _position._play_tick; }
 
 	static MidiParser *createParser_SMF();
 	static MidiParser *createParser_XMIDI();





More information about the Scummvm-git-logs mailing list