[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