Committed my patch #2040074 ("XMIDI callback control events"). At the moment, I'm

not aware of any game that actually uses this XMIDI feature, so its primary
function right now is to silence lots of warnings while running the DOS version
of Simon the Sorcerer 2.

svn-id: r33763
This commit is contained in:
Torbjörn Andersson 2008-08-10 17:59:42 +00:00
parent 327ae17095
commit d08c3ba66b
3 changed files with 53 additions and 21 deletions

View file

@ -538,7 +538,11 @@ void MidiPlayer::loadXMIDI(Common::File *in, bool sfx) {
error("Expected 'FORM' tag but found '%c%c%c%c' instead", buf[0], buf[1], buf[2], buf[3]);
}
MidiParser *parser = MidiParser::createParser_XMIDI();
// In the DOS version of Simon the Sorcerer 2, the music contains lots
// of XMIDI callback controller events. As far as we know, they aren't
// actually used, so we disable the callback handler explicitly.
MidiParser *parser = MidiParser::createParser_XMIDI(NULL);
parser->setMidiDriver(this);
parser->setTimerRate(_driver->getBaseTempo());
if (!parser->loadMusic(p->data, size))

View file

@ -352,6 +352,8 @@ public:
};
public:
typedef void (*XMidiCallbackProc)(byte eventData, void *refCon);
MidiParser();
virtual ~MidiParser() { allNotesOff(); }
@ -370,8 +372,10 @@ public:
uint32 getPPQN() { return _ppqn; }
virtual uint32 getTick() { return _position._play_tick; }
static void defaultXMidiCallback(byte eventData, void *refCon);
static MidiParser *createParser_SMF();
static MidiParser *createParser_XMIDI();
static MidiParser *createParser_XMIDI(XMidiCallbackProc proc = defaultXMidiCallback, void *refCon = 0);
static void timerCallback(void *data) { ((MidiParser *) data)->onTimer(); }
};

View file

@ -46,13 +46,16 @@ protected:
Loop _loop[4];
int _loopCount;
XMidiCallbackProc _callbackProc;
void *_callbackData;
protected:
uint32 readVLQ2(byte * &data);
void resetTracking();
void parseNextEvent(EventInfo &info);
public:
MidiParser_XMIDI() : _inserted_delta(0) {}
MidiParser_XMIDI(XMidiCallbackProc proc, void *data) : _inserted_delta(0), _callbackProc(proc), _callbackData(data) {}
~MidiParser_XMIDI() { }
bool loadMusic(byte *data, uint32 size);
@ -103,23 +106,22 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) {
info.basic.param1 = *(_position._play_pos++);
info.basic.param2 = *(_position._play_pos++);
// Simplified XMIDI looping.
//
// I would really like to turn the loop events into some sort
// of NOP event (perhaps a dummy META event?), but for now we
// just pass them on to the MIDI driver. That has worked in the
// past, so it shouldn't cause any actual damage...
// This isn't a full XMIDI implementation, but it should
// hopefully be "good enough" for most things.
if (info.basic.param1 == 0x74) {
// XMIDI_CONTROLLER_FOR_LOOP
switch (info.basic.param1) {
// Simplified XMIDI looping.
case 0x74: { // XMIDI_CONTROLLER_FOR_LOOP
byte *pos = _position._play_pos;
if (_loopCount < ARRAYSIZE(_loop) - 1)
_loopCount++;
_loop[_loopCount].pos = pos;
_loop[_loopCount].repeat = info.basic.param2;
} else if (info.basic.param1 == 0x75) {
// XMIDI_CONTROLLER_NEXT_BREAK
break;
}
case 0x75: // XMIDI_CONTORLLER_NEXT_BREAK
if (_loopCount >= 0) {
if (info.basic.param2 < 64) {
// End the current loop.
@ -133,11 +135,27 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) {
}
}
}
} else if (info.basic.param1 >= 0x6e && info.basic.param1 <= 0x78) {
break;
case 0x77: // XMIDI_CONTROLLER_CALLBACK_TRIG
if (_callbackProc)
_callbackProc(info.basic.param2, _callbackData);
break;
default:
if (info.basic.param1 >= 0x6e && info.basic.param1 <= 0x78) {
warning("Unsupported XMIDI controller %d (0x%2x)",
info.basic.param1, info.basic.param1);
}
break;
}
// Should we really keep passing the XMIDI controller events to
// the MIDI driver, or should we turn them into some kind of
// NOP events? (Dummy meta events, perhaps?) Ah well, it has
// worked so far, so it shouldn't cause any damage...
break;
case 0xF: // Meta or SysEx event
switch (info.event & 0x0F) {
@ -336,4 +354,10 @@ void MidiParser_XMIDI::resetTracking() {
_inserted_delta = 0;
}
MidiParser *MidiParser::createParser_XMIDI() { return new MidiParser_XMIDI; }
void MidiParser::defaultXMidiCallback(byte eventData, void *data) {
warning("MidiParser: defaultXMidiCallback(%d)", eventData);
}
MidiParser *MidiParser::createParser_XMIDI(XMidiCallbackProc proc, void *data) {
return new MidiParser_XMIDI(proc, data);
}