aboutsummaryrefslogtreecommitdiff
path: root/scumm/imuse.cpp
diff options
context:
space:
mode:
authorJamieson Christian2002-11-06 21:34:38 +0000
committerJamieson Christian2002-11-06 21:34:38 +0000
commit6fe39f5ba8b89e0ccb2cbf81f3d8bf0515ef51e7 (patch)
tree6d9e63de5d681541a57ebeb0091ecac313555e01 /scumm/imuse.cpp
parent85c7c9ffe62c5a059e18fcf6a7c2acf68476d23d (diff)
downloadscummvm-rg350-6fe39f5ba8b89e0ccb2cbf81f3d8bf0515ef51e7.tar.gz
scummvm-rg350-6fe39f5ba8b89e0ccb2cbf81f3d8bf0515ef51e7.tar.bz2
scummvm-rg350-6fe39f5ba8b89e0ccb2cbf81f3d8bf0515ef51e7.zip
Initial upgrades to support MT-32 emulation
svn-id: r5449
Diffstat (limited to 'scumm/imuse.cpp')
-rw-r--r--scumm/imuse.cpp102
1 files changed, 82 insertions, 20 deletions
diff --git a/scumm/imuse.cpp b/scumm/imuse.cpp
index 8010dee0ed..3e52af7876 100644
--- a/scumm/imuse.cpp
+++ b/scumm/imuse.cpp
@@ -33,7 +33,8 @@
*/
#define TICKS_PER_BEAT 480
-#define SYSEX_ID 0x7D
+#define IMUSE_SYSEX_ID 0x7D
+#define ROLAND_SYSEX_ID 0x41
#define PERCUSSION_CHANNEL 9
#define TRIGGER_ID 0
@@ -321,6 +322,7 @@ public:
virtual void part_changed(Part *part, uint16 what) = 0;
virtual void part_set_param(Part *part, byte param, int value) = 0;
virtual int part_update_active(Part *part, uint16 *active) = 0;
+ virtual byte get_channel_program (byte channel) = 0;
};
@@ -439,6 +441,7 @@ public:
int get_music_volume();
int set_master_volume(uint vol);
int get_master_volume();
+ byte get_channel_program (byte channel) { return _driver->get_channel_program (channel); }
bool start_sound(int sound);
int stop_sound(int sound);
int stop_all_sounds();
@@ -585,6 +588,8 @@ public:
void part_changed(Part *part, uint16 what);
void part_off(Part *part);
int part_update_active(Part *part, uint16 *active);
+ byte get_channel_program (byte) { return 255; }
+
void adjust_priorities() {
}
@@ -610,6 +615,7 @@ class IMuseGM : public IMuseDriver {
MidiDriver *_md;
MidiChannelGM _midi_channels[16];
+ byte _midi_program_last[16];
int16 _midi_pitchbend_last[16];
byte _midi_pitchbend_factor_last[16];
uint8 _midi_volume_last[16];
@@ -650,6 +656,7 @@ public:
void part_key_on(Part *part, byte note, byte velocity);
void part_key_off(Part *part, byte note);
void part_changed(Part *part, uint16 what);
+ byte get_channel_program (byte channel) { return _midi_program_last [channel]; }
static int midi_driver_thread(void *param);
@@ -2164,8 +2171,7 @@ byte *Player::parse_midi(byte *s)
case 0xF:
if (chan == 0) {
uint size = get_delta_time(&s);
- if (*s == SYSEX_ID)
- parse_sysex(s, size);
+ parse_sysex(s, size);
s += size;
} else if (chan == 0xF) {
cmd = *s++;
@@ -2193,6 +2199,15 @@ byte *Player::parse_midi(byte *s)
return s;
}
+struct {
+ char *name;
+ byte program;
+}
+roland_to_gm_map [] = {
+ // TODO: Construct this database.
+ { " ", 0 }
+};
+
void Player::parse_sysex(byte *p, uint len)
{
byte code;
@@ -2201,27 +2216,69 @@ void Player::parse_sysex(byte *p, uint len)
byte buf[128];
Part *part;
- /* too big? */
+ // Check SysEx manufacturer.
+ // Roland is 0x41
+ a = *p++;
+ --len;
+ if (a != IMUSE_SYSEX_ID) {
+ if (a == ROLAND_SYSEX_ID) {
+ // Roland custom instrument definition.
+ part = get_part (p[0] & 0x0F);
+ if (part) {
+ memcpy (buf, p + 6, 10);
+ buf[10] = '\0';
+ // debug (0, "[%02d] Roland (model 0x%02X, cmd 0x%02X) Instrument: \"%8s\"", p[0], p[1], p[2], buf);
+ for (b = 0; b < ARRAYSIZE(roland_to_gm_map); ++b) {
+ if (!memcmp (roland_to_gm_map[b].name, buf, 10)) {
+ a = roland_to_gm_map[b].program;
+ for (b = 0; b < ARRAYSIZE(mt32_to_gmidi); ++b) {
+ if (mt32_to_gmidi [b] == a) {
+ part->set_program (b);
+ return;
+ }
+ }
+ warning ("Could not find appropriate MT-32 program for GM program %d", (int) a);
+ return;
+ }
+ }
+ warning ("Could not find appropriate GM program for MT-32 custom instrument \"%s\"", buf);
+ }
+ } else {
+ warning ("Unknown SysEx manufacturer 0x%02X", (int) a);
+ return;
+ }
+ }
+ --len;
+
+ // Too big?
if (len >= sizeof(buf) * 2)
return;
- /* skip sysex manufacturer */
- p++;
- len -= 2;
-
switch (code = *p++) {
case 0:
if (g_scumm->_gameId != GID_SAMNMAX) {
- // Part on/off?
- // This seems to do the right thing for Monkey 2, at least.
- a = *p++ & 0x0F;
- part = get_part(a);
+ // There are 17 bytes of useful information beyond
+ // what we've read so far. All we know about them is
+ // as follows:
+ // BYTE 00: Channel #
+ // BYTE 02: BIT 01 (0x01): Part on? (1 = yes)
+ // BYTE 05: Volume (upper 4 bits) [guessing]
+ // BYTE 06: Volume (lower 4 bits) [guessing]
+ // BYTE 09: BIT 04 (0x08): Percussion? (1 = yes)
+ part = get_part (p[0] & 0x0F);
if (part) {
- debug(2, "%d => turning %s part %d", p[1], (p[1] == 2) ? "OFF" : "ON", a);
- part->set_onoff(p[1] != 2);
+ part->set_onoff (p[2] & 0x01);
+ part->set_vol ((p[5] & 0x0F) << 4 | (p[6] & 0x0F));
+ part->_percussion = ((p[9] & 0x08) > 0);
+ if (part->_percussion) {
+ if (part->_mc)
+ part->off();
+ } else {
+ part->changed (IMuseDriver::pcAll);
+ }
}
} else {
- // Jamieson630: Sam & Max seems to use this as a marker for
+ // Sam & Max seems to use this as a marker for
// ImSetTrigger. When a marker is encountered whose sound
// ID and (presumably) marker ID match what was set by
// ImSetTrigger, something magical is supposed to happen....
@@ -3344,7 +3401,7 @@ void Part::setup(Player *player)
player->_parts->_prev = this;
player->_parts = this;
- _percussion = true;
+ _percussion = (player->_isGM && _chan == 9); // true;
_on = true;
_pri_eff = player->_priority;
_pri = 0;
@@ -3358,12 +3415,15 @@ void Part::setup(Player *player)
_pitchbend_factor = 2;
_pitchbend = 0;
_effect_level = 64;
- _program = 255;
+ _program = player->_se->get_channel_program (_chan);
_chorus = 0;
_modwheel = 0;
_bank = 0;
_pedal = false;
_mc = NULL;
+
+ if (_program < 128)
+ changed (IMuseDriver::pcAll);
}
void Part::uninit()
@@ -4740,8 +4800,10 @@ void IMuseGM::init(IMuseInternal *eng, OSystem *syst)
_se = eng;
syst->create_thread(midi_driver_thread, this);
- for (i = 0, mc = _midi_channels; i != ARRAYSIZE(_midi_channels); i++, mc++)
+ for (i = 0, mc = _midi_channels; i != ARRAYSIZE(_midi_channels); i++, mc++) {
mc->_chan = i;
+ _midi_program_last [i] = 255;
+ }
}
void IMuseGM::uninit()
@@ -4828,8 +4890,7 @@ void IMuseGM::part_changed(Part *part, uint16 what)
MidiChannelGM *mc;
/* Mark for re-schedule if program changed when in pre-state */
- if (what & pcProgram && part->_percussion) {
- part->_percussion = false;
+ if (what & pcProgram && !part->_percussion && !part->_mc) {
update_pris();
}
@@ -4868,6 +4929,7 @@ void IMuseGM::part_changed(Part *part, uint16 what)
midiEffectLevel(mc->_chan, part->_effect_level);
if (what & pcProgram) {
+ _midi_program_last [part->_chan] = part->_program;
if (part->_bank) {
midiControl0(mc->_chan, part->_bank);
midiProgram(mc->_chan, part->_program, part->_player->_mt32emulate);