aboutsummaryrefslogtreecommitdiff
path: root/scumm
diff options
context:
space:
mode:
authorJamieson Christian2002-11-23 16:15:33 +0000
committerJamieson Christian2002-11-23 16:15:33 +0000
commitd2b94bd0e0ac80244e11d066f04ec4e44eb1c909 (patch)
treee8f64a9afd4019751796637a875dfc8f070e8026 /scumm
parent6ed12bc6aa0ddfc0da14e5e082656204986c7fc8 (diff)
downloadscummvm-rg350-d2b94bd0e0ac80244e11d066f04ec4e44eb1c909.tar.gz
scummvm-rg350-d2b94bd0e0ac80244e11d066f04ec4e44eb1c909.tar.bz2
scummvm-rg350-d2b94bd0e0ac80244e11d066f04ec4e44eb1c909.zip
Fixed invalid ImSetTrigger invocations, which fixes invalid do_command(0) calls.
Also included is eriktorbjorn's fix for Adlib instrument setup. svn-id: r5701
Diffstat (limited to 'scumm')
-rw-r--r--scumm/imuse.cpp110
1 files changed, 75 insertions, 35 deletions
diff --git a/scumm/imuse.cpp b/scumm/imuse.cpp
index f244c65088..09b069bd7d 100644
--- a/scumm/imuse.cpp
+++ b/scumm/imuse.cpp
@@ -339,6 +339,7 @@ struct Part {
struct ImTrigger {
int sound;
byte id;
+ uint16 expire;
byte command [4];
};
@@ -413,6 +414,7 @@ private:
uint16 _trigger_count;
ImTrigger _snm_triggers[16]; // Sam & Max triggers
+ uint16 _snm_trigger_index;
uint16 _channel_volume[8];
uint16 _channel_volume_eff[8]; /* NoSave */
@@ -445,6 +447,9 @@ private:
Part *allocate_part(byte pri);
+ int32 ImSetTrigger (int sound, int id, int a, int b, int c, int d);
+ int32 ImClearTrigger (int sound, int id);
+
int enqueue_command(int a, int b, int c, int d, int e, int f, int g);
int enqueue_trigger(int sound, int marker);
int query_queue(int param);
@@ -1587,24 +1592,10 @@ int32 IMuseInternal::do_command(int a, int b, int c, int d, int e, int f, int g,
if (g_scumm->_gameId != GID_SAMNMAX) {
return set_channel_volume(b, c);
} else {
- // Sam & Max: ImSetTrigger.
- // Sets a trigger for a particular player and
- // marker ID, along with do_command parameters
- // to invoke at the marker. The marker is
- // represented by MIDI SysEx block 00 xx (F7)
- // where "xx" is the marker ID.
- for (i = 0; i < 16; ++i) {
- if (!_snm_triggers [i].id) {
- _snm_triggers [i].id = d;
- _snm_triggers [i].sound = b;
- _snm_triggers [i].command [0] = e;
- _snm_triggers [i].command [1] = f;
- _snm_triggers [i].command [2] = g;
- _snm_triggers [i].command [3] = h;
- return 0;
- }
- }
- return -1;
+ if (e || f || g || h)
+ return ImSetTrigger (b, d, e, f, g, h);
+ else
+ return ImClearTrigger (b, d);
}
case 18:
if (g_scumm->_gameId != GID_SAMNMAX) {
@@ -1629,23 +1620,14 @@ int32 IMuseInternal::do_command(int a, int b, int c, int d, int e, int f, int g,
// Sam & Max: ImClearTrigger
// This should clear a trigger that's been set up
// with ImSetTrigger (cmd == 17). Seems to work....
- a = 0;
- for (i = 0; i < 16; ++i) {
- if (_snm_triggers [i].sound == b && _snm_triggers [i].id &&
- (d == -1 || _snm_triggers [i].id == d))
- {
- _snm_triggers [i].sound = _snm_triggers [i].id = 0;
- ++a;
- }
- }
- return (a > 0) ? 0 : -1;
+ return ImClearTrigger (b, d);
case 20: // FIXME: Deferred command system? - Sam and Max
return 0;
case 2:
case 3:
return 0;
default:
- warning("IMuseInternal::do_command invalid command %d", cmd);
+ warning("do_command (%d [%d/%d], %d, %d, %d, %d, %d, %d, %d) unsupported", a, param, cmd, b, c, d, e, f, g, h);
}
} else if (param == 1) {
if ((1 << cmd) & (0x783FFF)) {
@@ -1726,7 +1708,7 @@ int32 IMuseInternal::do_command(int a, int b, int c, int d, int e, int f, int g,
case 24:
return 0;
default:
- warning("IMuseInternal::do_command default midi command %d", cmd);
+ warning("do_command (%d [%d/%d], %d, %d, %d, %d, %d, %d, %d) unsupported", a, param, cmd, b, c, d, e, f, g, h);
return -1;
}
}
@@ -1734,6 +1716,67 @@ int32 IMuseInternal::do_command(int a, int b, int c, int d, int e, int f, int g,
return -1;
}
+int32 IMuseInternal::ImSetTrigger (int sound, int id, int a, int b, int c, int d) {
+ // Sam & Max: ImSetTrigger.
+ // Sets a trigger for a particular player and
+ // marker ID, along with do_command parameters
+ // to invoke at the marker. The marker is
+ // represented by MIDI SysEx block 00 xx (F7)
+ // where "xx" is the marker ID.
+ uint16 oldest_trigger = 0;
+ int oldest_index = -1;
+
+ int i;
+ for (i = 0; i < 16; ++i) {
+ ImTrigger *trig = &_snm_triggers [i];
+ if (!trig->id)
+ break;
+ if (trig->id == id && trig->sound == sound)
+ break;
+
+ uint16 diff;
+ if (trig->expire <= _snm_trigger_index)
+ diff = _snm_trigger_index - trig->expire;
+ else
+ diff = 0x10000 - trig->expire + _snm_trigger_index;
+
+ if (oldest_index < 0 || oldest_trigger < diff) {
+ oldest_index = i;
+ oldest_trigger = diff;
+ }
+ }
+
+ // If we didn't find a trigger, see if we can expire one.
+ if (i >= 16) {
+ if (oldest_index < 0)
+ return -1;
+ i = oldest_index;
+ }
+
+ _snm_triggers [i].id = id;
+ _snm_triggers [i].sound = sound;
+ _snm_triggers [i].expire = (++_snm_trigger_index & 0xFFFF);
+ _snm_triggers [i].command [0] = a;
+ _snm_triggers [i].command [1] = b;
+ _snm_triggers [i].command [2] = c;
+ _snm_triggers [i].command [3] = d;
+ return 0;
+}
+
+int32 IMuseInternal::ImClearTrigger (int sound, int id) {
+ int count = 0;
+ int i;
+ for (i = 0; i < 16; ++i) {
+ if (_snm_triggers [i].sound == sound && _snm_triggers [i].id &&
+ (id == -1 || _snm_triggers [i].id == id))
+ {
+ _snm_triggers [i].sound = _snm_triggers [i].id = 0;
+ ++count;
+ }
+ }
+ return (count > 0) ? 0 : -1;
+}
+
int IMuseInternal::set_channel_volume(uint chan, uint vol)
{
if (chan >= 8 || vol > 127)
@@ -5113,13 +5156,10 @@ void IMuseGM::part_changed(Part *part, uint16 what)
}
}
} else {
- debug (0, "Setting instrument (%d)", (int) _part_instr [part->_slot].oplvl_1);
- if (_part_instr [part->_slot].oplvl_1 != 0) {
- _md->sysEx_customInstrument (mc->_chan, 'ADL ', (byte *) (&_part_instr [part->_slot]));
- } else if (part->_program < 32) {
+ if (part->_program < 32) {
memcpy (&_part_instr [part->_slot], &_glob_instr[part->_program], sizeof (Instrument));
- _md->sysEx_customInstrument (mc->_chan, 'ADL ', (byte *) (&_part_instr [part->_slot]));
}
+ _md->sysEx_customInstrument (mc->_chan, 'ADL ', (byte *) (&_part_instr [part->_slot]));
}
}