[Scummvm-cvs-logs] CVS: scummvm/sound midiparser.cpp,NONE,1.1 midiparser.h,1.5,1.6 module.mk,1.8,1.9

Jamieson Christian jamieson630 at users.sourceforge.net
Mon May 19 11:48:09 CEST 2003


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

Modified Files:
	midiparser.h module.mk 
Added Files:
	midiparser.cpp 
Log Message:
Moved common parsing logic into MidiParser base class.
Added auto-loop capability.

--- NEW FILE: midiparser.cpp ---
/* 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: /cvsroot/scummvm/scummvm/sound/midiparser.cpp,v 1.1 2003/05/19 18:47:50 jamieson630 Exp $
 *
 */

#include "midiparser.h"
#include "mididrv.h"
#include "common/util.h"

#include <stdio.h>
#include <memory.h>

//////////////////////////////////////////////////
//
// MidiParser implementation
//
//////////////////////////////////////////////////

MidiParser::MidiParser() :
_driver (0),
_timer_rate (0x4A0000),
_ppqn (96),
_tempo (500000),
_psec_per_tick (5208), // 500000 / 96
_autoLoop (false),
_num_tracks (0),
_active_track (255),
_play_pos (0),
_play_time (0),
_last_event_time (0),
_last_event_tick (0),
_running_status (0)
{ }

void MidiParser::property (int prop, int value) {
	switch (prop) {
	case mpAutoLoop:
		_autoLoop = (value != 0);
	}
}

// This is the conventional (i.e. SMF) variable length quantity
uint32 MidiParser::readVLQ (byte * &data) {
	byte str;
	uint32 value = 0;
	int i;

	for (i = 0; i < 4; ++i) {
		str = data[0];
		++data;
		value = (value << 7) | (str & 0x7F);
		if (!(str & 0x80))
			break;
	}
	return value;
}

void MidiParser::onTimer() {
	uint32 end_time;
	uint32 event_time;

	if (!_play_pos || !_driver)
		return;

	end_time = _play_time + _timer_rate;

	while (true) {
		EventInfo &info = _next_event;

		event_time = _last_event_time + info.delta * _psec_per_tick;
		if (event_time > end_time)
			break;

		// Process the next info.
		_last_event_tick += info.delta;
		if (info.event < 0x80) {
			printf ("ERROR! Bad command or running status %02X", info.event);
			_play_pos = 0;
			return;
		}
		_running_status = info.event;

		if (info.event == 0xF0) {
			// SysEx event
			_driver->sysEx (info.data, (uint16) info.length);
		} else if (info.event == 0xFF) {
			// META event
			if (info.type == 0x2F) {
				// End of Track must be processed by us,
				// as well as sending it to the output device.
				allNotesOff();
				if (_autoLoop) {
					_play_pos = _tracks[_active_track];
					parseNextEvent (_next_event);
				} else {
					_play_pos = 0;
					_driver->metaEvent (info.type, info.data, (uint16) info.length);
				}
				return;
			} else if (info.type == 0x51) {
				if (info.length >= 3) {
					_tempo = info.data[0] << 16 | info.data[1] << 8 | info.data[2];
					_psec_per_tick = (_tempo + (_ppqn >> 2)) / _ppqn;
				}
			}
			_driver->metaEvent (info.type, info.data, (uint16) info.length);
		} else {
			_driver->send (info.event | info.param1 << 8 | info.param2 << 16);
		}


		_last_event_time = event_time;
		parseNextEvent (_next_event);
	}

	_play_time = end_time;
}

void MidiParser::allNotesOff() {
	if (!_driver)
		return;

	int i;
	for (i = 0; i < 15; ++i) {
		_driver->send (0x007BB0 | i);
	}
}

void MidiParser::resetTracking() {
	_play_pos = 0;
	_tempo = 500000;
	_psec_per_tick = 500000 / _ppqn;
	_play_time = 0;
	_last_event_time = 0;
	_last_event_tick = 0;
	_running_status = 0;
}

void MidiParser::setTrack (byte track) {
	if (track >= _num_tracks || track == _active_track)
		return;
	resetTracking();
	allNotesOff();
	_active_track = track;
	_play_pos = _tracks[track];
	parseNextEvent (_next_event);
}

void MidiParser::jumpToTick (uint32 tick) {
	if (_active_track >= _num_tracks)
		return;
	resetTracking();
	allNotesOff();

	_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;
			break;
		}

		_last_event_tick += info.delta;
		_play_time += info.delta * _psec_per_tick;
		_last_event_time = _play_time;

		if (info.event == 0xFF) {
			if (info.type == 0x2F) { // End of track
				if (_autoLoop) {
					_play_pos = _tracks[_active_track];
					parseNextEvent (_next_event);
				} else {
					_play_pos = 0;
					_driver->metaEvent (0x2F, info.data, (uint16) info.length);
				}
				break;
			} else if (info.type == 0x51) { // Tempo
				if (info.length >= 3) {
					_tempo = info.data[0] << 16 | info.data[1] << 8 | info.data[2];
					_psec_per_tick = (_tempo + (_ppqn >> 2)) / _ppqn;
				}
			}
		}

		parseNextEvent (_next_event);
	}
}

Index: midiparser.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/midiparser.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- midiparser.h	19 May 2003 09:01:25 -0000	1.5
+++ midiparser.h	19 May 2003 18:47:50 -0000	1.6
@@ -28,29 +28,86 @@
 
 class MidiDriver;
 
+struct EventInfo {
+	byte * start; // Points to delta
+	uint32 delta;
+	byte   event;
+	union {
+		struct {
+			byte param1;
+			byte param2;
+		};
+		struct {
+			byte   type; // Used for METAs
+			byte * data; // Used for SysEx and METAs
+			uint32 length; // Used for SysEx and METAs
+		};
+	};
+
+	byte channel() { return event & 0x0F; }
+	byte command() { return event >> 4; }
+};
+
 class MidiParser {
 protected:
 	MidiDriver *_driver;
 	uint32 _timer_rate;
+	uint32 _ppqn;           // Pulses (ticks) Per Quarter Note
+	uint32 _tempo;          // Microseconds per quarter note
+	uint32 _psec_per_tick;  // Microseconds per tick (_tempo / _ppqn)
+	bool   _autoLoop;       // For lightweight clients that don't monitor events
+
+	byte * _tracks[16];
+	byte   _num_tracks;
+	byte   _active_track;
+
+	byte * _play_pos;
+	uint32 _play_time;
+	uint32 _last_event_time;
+	uint32 _last_event_tick;
+	byte   _running_status; // Cache of last MIDI command, used in compressed streams
+	EventInfo _next_event;
+
+protected:
+	static uint32 readVLQ (byte * &data);
+	void resetTracking();
+	void allNotesOff();
+	virtual void parseNextEvent (EventInfo &info) = 0;
+
+	// Multi-byte read helpers
+	uint32 read4high (byte * &data) {
+		uint32 val = 0;
+		int i;
+		for (i = 0; i < 4; ++i) val = (val << 8) | *data++;
+		return val;
+	}
+	uint16 read2low  (byte * &data) {
+		uint16 val = 0;
+		int i;
+		for (i = 0; i < 2; ++i) val |= (*data++) << (i * 8);
+		return val;
+	}
 
 public:
 	enum {
-		mpMalformedPitchBends = 1
+		mpMalformedPitchBends = 1,
+		mpAutoLoop = 2
 	};
 
 public:
+	MidiParser();
 	virtual ~MidiParser() { }
 
 	virtual bool loadMusic (byte *data, uint32 size) = 0;
 	virtual void unloadMusic() = 0;
-	virtual void property (int prop, int value) { }
+	virtual void property (int prop, int value);
 
 	void setMidiDriver (MidiDriver *driver) { _driver = driver; }
 	void setTimerRate (uint32 rate) { _timer_rate = rate / 500; }
-	virtual void onTimer() = 0;
+	void onTimer();
 
-	virtual void setTrack (byte track) = 0;
-	virtual void jumpToTick (uint32 tick) = 0;
+	void setTrack (byte track);
+	void jumpToTick (uint32 tick);
 
 	static MidiParser *createParser_SMF();
 	static MidiParser *createParser_XMIDI();

Index: module.mk
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/module.mk,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- module.mk	19 May 2003 00:49:13 -0000	1.8
+++ module.mk	19 May 2003 18:47:50 -0000	1.9
@@ -2,6 +2,7 @@
 
 MODULE_OBJS = \
 	sound/fmopl.o \
+	sound/midiparser.o \
 	sound/midiparser_smf.o \
 	sound/midiparser_xmidi.o \
 	sound/mixer.o \





More information about the Scummvm-git-logs mailing list