aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scumm/imuse.cpp146
-rw-r--r--scumm/instrument.cpp43
-rw-r--r--scumm/instrument.h2
-rw-r--r--scumm/resource.cpp5
4 files changed, 127 insertions, 69 deletions
diff --git a/scumm/imuse.cpp b/scumm/imuse.cpp
index 07ac0d758a..12432423f0 100644
--- a/scumm/imuse.cpp
+++ b/scumm/imuse.cpp
@@ -29,6 +29,10 @@
#include "scumm/sound.h"
#include "common/util.h"
+// Unremark this statement to activate some of
+// the most common iMuse diagnostic messages.
+// #define IMUSE_DEBUG
+
//
// Some constants
//
@@ -229,6 +233,7 @@ struct Part {
// New abstract instrument definition
Instrument _instrument;
+ bool _unassigned_instrument; // For diagnostic reporting purposes only
// Used to be in MidiDriver
uint16 _actives[8];
@@ -302,7 +307,7 @@ private:
MidiDriver *_md;
Instrument _glob_instr[32]; // Adlib custom instruments
- byte _midi_program_last[16];
+ Instrument _midi_instrument_last[16];
int16 _midi_pitchbend_last[16];
byte _midi_pitchbend_factor_last[16];
uint8 _midi_volume_last[16];
@@ -340,13 +345,14 @@ public:
void set_instrument(uint slot, byte *instr);
void part_load_global_instrument (Part *part, byte slot);
void part_set_param(Part *part, byte param, int value) {}
- void part_key_on(Part *part, byte note, byte velocity);
- void part_key_off(Part *part, byte note);
+// 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]; }
+ void get_channel_instrument (byte channel, Instrument *instrument) { _midi_instrument_last[channel].copy_to (instrument); }
static int midi_driver_thread(void *param);
+ MidiChannel *getPercussionChannel() { return _md->getPercussionChannel(); }
uint32 get_base_tempo() { return _md->getBaseTempo(); }
byte get_hardware_type() { return 5; }
};
@@ -471,7 +477,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); }
+ void get_channel_instrument (byte channel, Instrument *instrument) { _driver->get_channel_instrument (channel, instrument); }
bool startSound(int sound);
int stopSound(int sound);
int stop_all_sounds();
@@ -714,7 +720,7 @@ bool IMuseInternal::startSound(int sound) {
if (!mdhd) {
mdhd = findTag(sound, MDPG_TAG, 0);
if (!mdhd) {
- warning("SE::startSound failed: Couldn't find sound %d", sound);
+ debug (2, "SE::startSound failed: Couldn't find sound %d", sound);
return false;
}
}
@@ -737,7 +743,6 @@ bool IMuseInternal::startSound(int sound) {
return false;
player->clear();
-
return player->startSound(sound);
}
@@ -860,14 +865,25 @@ void IMuseInternal::handle_marker(uint id, byte data) {
uint16 *p;
uint pos;
- pos = _queue_end;
- if (pos == _queue_pos)
- return;
-
if (_queue_adding && _queue_sound == id && data == _queue_marker)
return;
- p = _cmd_queue[pos].array;
+ // Fix for bug #733401: It would seem that sometimes the
+ // queue read position gets out of sync (possibly just
+ // reset to zero). Therefore, the read position should
+ // skip over any empty (i.e. all zeros) queue entries
+ // until it finds a legit entry to review.
+ pos = _queue_end;
+ while (pos != _queue_pos) {
+ p = _cmd_queue[pos].array;
+ if ((p[0] | p[1] | p[2] | p[3] | p[4] | p[5] | p[6] | p[7]) != 0)
+ break;
+ warning ("Skipping empty command queue entry at position %d", pos);
+ pos = (pos + 1) & (ARRAYSIZE(_cmd_queue) - 1);
+ }
+
+ if (pos == _queue_pos)
+ return;
if (p[0] != TRIGGER_ID || p[1] != id || p[2] != data)
return;
@@ -1269,6 +1285,10 @@ int32 IMuseInternal::doCommand(int a, int b, int c, int d, int e, int f, int g,
if (!_initialized && (cmd || param))
return -1;
+#ifdef IMUSE_DEBUG
+ debug (0, "doCommand - %d (%d/%d), %d, %d, %d, %d, %d, %d, %d", a, (int) param, (int) cmd, b, c, d, e, f, g, h);
+#endif
+
if (param == 0) {
switch (cmd) {
case 6:
@@ -2057,6 +2077,18 @@ void Player::parse_sysex(byte *p, uint len) {
if (len >= sizeof(buf) * 2)
return;
+#ifdef IMUSE_DEBUG
+ for (a = 0; a < len + 1 && a < 20; ++a) {
+ sprintf ((char *)&buf[a*3], " %02X", p[a]);
+ } // next for
+ if (a < len + 1) {
+ buf[a*3] = buf[a*3+1] = buf[a*3+2] = '.';
+ ++a;
+ } // end if
+ buf[a*3] = '\0';
+ debug (0, "SysEx:%s", buf);
+#endif
+
switch (code = *p++) {
case 0:
if (g_scumm->_gameId != GID_SAMNMAX) {
@@ -2118,10 +2150,16 @@ void Player::parse_sysex(byte *p, uint len) {
a = *p++ & 0x0F;
if (_se->_hardware_type != *p++ && false)
break;
- decode_sysex_bytes(p, buf, len - 3);
part = get_part(a);
- if (part)
- part->set_instrument((byte *) buf);
+ if (part) {
+ if (len == 63) {
+ decode_sysex_bytes(p, buf, len - 3);
+ part->set_instrument((byte *) buf);
+ } else {
+ // SPK tracks have len == 49 here, and are not supported
+ part->set_program (254); // Must be invalid, but not 255 (which is reserved)
+ }
+ }
break;
case 17: // Adlib instrument definition (Global)
@@ -2909,6 +2947,7 @@ int IMuseInternal::save_or_load(Serializer *ser, Scumm *scumm) {
MKLINE(IMuseInternal, _trigger_count, sleUint16, VER_V8),
MKARRAY(IMuseInternal, _channel_volume[0], sleUint16, 8, VER_V8),
MKARRAY(IMuseInternal, _volchan_table[0], sleUint16, 8, VER_V8),
+ // TODO: Add _cmd_queue in here
MKEND()
};
@@ -3149,11 +3188,38 @@ void Part::load_global_instrument (byte slot) {
}
void Part::key_on(byte note, byte velocity) {
- _drv->part_key_on(this, note, velocity);
+ MidiChannel *mc = _mc;
+ _actives[note >> 4] |= (1 << (note & 0xF));
+
+ // DEBUG
+ if (_unassigned_instrument && !_percussion) {
+ warning ("[%02d] No instrument specified", (int) _chan);
+ _unassigned_instrument = false;
+ return;
+ }
+
+ if (mc && _instrument.isValid()) {
+ mc->noteOn (note, velocity);
+ } else if (_percussion) {
+ mc = _drv->getPercussionChannel();
+ if (!mc)
+ return;
+ mc->volume (_vol_eff);
+ mc->programChange (_bank);
+ mc->noteOn (note, velocity);
+ }
}
void Part::key_off(byte note) {
- _drv->part_key_off(this, note);
+ MidiChannel *mc = _mc;
+ _actives[note >> 4] &= ~(1 << (note & 0xF));
+ if (mc) {
+ mc->noteOff (note);
+ } else if (_percussion) {
+ mc = _drv->getPercussionChannel();
+ if (mc)
+ mc->noteOff (note);
+ }
}
void Part::init(IMuseDriver * driver) {
@@ -3189,17 +3255,17 @@ void Part::setup(Player *player) {
_pitchbend_factor = 2;
_pitchbend = 0;
_effect_level = 64;
-// _program = player->_se->get_channel_program (_chan);
-// _instrument.program (_program, player->_mt32emulate);
_program = 255;
_instrument.clear();
+ _unassigned_instrument = true;
+// player->_se->get_channel_instrument (_chan, &_instrument);
_chorus = 0;
_modwheel = 0;
_bank = 0;
_pedal = false;
_mc = NULL;
- if (_program < 128)
+ if (_instrument.isValid())
changed (IMuseDriver::pcAll);
}
@@ -3272,7 +3338,6 @@ IMuseDriver::IMuseDriver (MidiDriver *midi) {
// any changes that are sent (which would cause
// the changes to be ignored).
for (i = 0; i < 16; ++i) {
- _midi_program_last [i] =
_midi_pitchbend_factor_last [i] =
_midi_volume_last [i] =
_midi_modwheel_last [i] =
@@ -3360,36 +3425,6 @@ void IMuseDriver::midiSilence(byte chan) {
_md->send((123 << 8) | 0xB0 | chan);
}
-
-void IMuseDriver::part_key_on(Part *part, byte note, byte velocity) {
- MidiChannel *mc = part->_mc;
-
- part->_actives[note >> 4] |= (1 << (note & 0xF));
- if (mc) {
- mc->noteOn (note, velocity);
- } else if (part->_percussion) {
- mc = _md->getPercussionChannel();
- if (!mc)
- return;
- mc->volume (part->_vol_eff);
- mc->programChange (part->_bank);
- mc->noteOn (note, velocity);
- }
-}
-
-void IMuseDriver::part_key_off(Part *part, byte note) {
- MidiChannel *mc = part->_mc;
-
- part->_actives[note >> 4] &= ~(1 << (note & 0xF));
- if (mc) {
- mc->noteOff (note);
- } else if (part->_percussion) {
- mc = _md->getPercussionChannel();
- if (mc)
- mc->noteOff (note);
- }
-}
-
void IMuseDriver::init(IMuseInternal *eng, OSystem *syst) {
int i;
@@ -3404,8 +3439,8 @@ void IMuseDriver::init(IMuseInternal *eng, OSystem *syst) {
_se = eng;
_md->setTimerCallback (NULL, &IMuseDriver::timer_callback);
- for (i = 0; i != ARRAYSIZE(_midi_program_last); i++) {
- _midi_program_last [i] = 255;
+ for (i = 0; i != ARRAYSIZE(_midi_instrument_last); i++) {
+ _midi_instrument_last [i].clear();
}
}
@@ -3536,8 +3571,11 @@ void IMuseDriver::part_changed(Part *part, uint16 what) {
if (what & pcEffectLevel)
mc->effectLevel (part->_effect_level);
- if (what & pcProgram)
+ if (what & pcProgram && part->_instrument.isValid()) {
part->_instrument.send (mc);
+ part->_unassigned_instrument = false;
+// part->_instrument.copy_to (&_midi_instrument_last [part->_chan]);
+ }
if (what & pcChorus)
mc->chorusLevel (part->_effect_level);
diff --git a/scumm/instrument.cpp b/scumm/instrument.cpp
index da6fc2865d..169ab67e35 100644
--- a/scumm/instrument.cpp
+++ b/scumm/instrument.cpp
@@ -135,6 +135,7 @@ public:
void saveOrLoad (Serializer *s);
void send (MidiChannel *mc);
void copy_to (Instrument *dest) { dest->program (_program, _mt32); }
+ bool is_valid() { return (_program < 128); }
};
class Instrument_Adlib : public InstrumentInternal {
@@ -164,6 +165,7 @@ public:
void saveOrLoad (Serializer *s);
void send (MidiChannel *mc);
void copy_to (Instrument *dest) { dest->adlib ((byte *) &_instrument); }
+ bool is_valid() { return true; }
};
class Instrument_Roland : public InstrumentInternal {
@@ -228,12 +230,15 @@ private:
char _instrument_name [11];
+ uint8 getEquivalentGM();
+
public:
Instrument_Roland (byte *data);
Instrument_Roland (Serializer *s);
void saveOrLoad (Serializer *s);
void send (MidiChannel *mc);
void copy_to (Instrument *dest) { dest->roland ((byte *) &_instrument); }
+ bool is_valid() { return (NATIVE_MT32 ? true : (_instrument_name[0] != '\0')); }
};
////////////////////////////////////////
@@ -377,6 +382,10 @@ Instrument_Roland::Instrument_Roland (byte *data) {
memcpy (&_instrument, data, sizeof (_instrument));
memcpy (&_instrument_name, &_instrument.common.name, sizeof (_instrument.common.name));
_instrument_name[10] = '\0';
+ if (!NATIVE_MT32 && getEquivalentGM() >= 128) {
+ warning ("MT-32 instrument \"%s\" not supported yet", _instrument_name);
+ _instrument_name[0] = '\0';
+ }
}
Instrument_Roland::Instrument_Roland (Serializer *s) {
@@ -388,12 +397,17 @@ Instrument_Roland::Instrument_Roland (Serializer *s) {
}
void Instrument_Roland::saveOrLoad (Serializer *s) {
- if (s->isSaving())
+ if (s->isSaving()) {
s->saveBytes (&_instrument, sizeof (_instrument));
- else
+ } else {
s->loadBytes (&_instrument, sizeof (_instrument));
- memcpy (&_instrument_name, &_instrument.common.name, sizeof (_instrument.common.name));
- _instrument_name[10] = '\0';
+ memcpy (&_instrument_name, &_instrument.common.name, sizeof (_instrument.common.name));
+ _instrument_name[10] = '\0';
+ if (!NATIVE_MT32 && getEquivalentGM() >= 128) {
+ warning ("MT-32 instrument \"%s\" not supported yet", _instrument_name);
+ _instrument_name[0] = '\0';
+ }
+ } // end if
}
void Instrument_Roland::send (MidiChannel *mc) {
@@ -402,14 +416,17 @@ void Instrument_Roland::send (MidiChannel *mc) {
mc->device()->sysEx ((byte *) &_instrument, sizeof (_instrument));
} else {
// Convert to a GM program change.
- byte i;
- for (i = 0; i != ARRAYSIZE(roland_to_gm_map); ++i) {
- if (!memcmp (roland_to_gm_map[i].name, _instrument.common.name, 10)) {
- mc->programChange (roland_to_gm_map[i].program);
- return;
- }
- }
- warning ("MT-32 instrument \"%s\" not supported yet", _instrument_name);
- mc->programChange (0);
+ byte program = getEquivalentGM();
+ if (program < 128)
+ mc->programChange (program);
+ }
+}
+
+uint8 Instrument_Roland::getEquivalentGM() {
+ byte i;
+ for (i = 0; i != ARRAYSIZE(roland_to_gm_map); ++i) {
+ if (!memcmp (roland_to_gm_map[i].name, _instrument.common.name, 10))
+ return roland_to_gm_map[i].program;
}
+ return 255;
}
diff --git a/scumm/instrument.h b/scumm/instrument.h
index 1d021466ad..f3607eab4d 100644
--- a/scumm/instrument.h
+++ b/scumm/instrument.h
@@ -34,6 +34,7 @@ public:
virtual void saveOrLoad (Serializer *s) = 0;
virtual void send (MidiChannel *mc) = 0;
virtual void copy_to (Instrument *dest) = 0;
+ virtual bool is_valid() = 0;
};
class Instrument {
@@ -58,6 +59,7 @@ public:
void roland (byte *instrument);
byte getType() { return _type; }
+ bool isValid() { return (_instrument ? _instrument->is_valid() : false); }
void saveOrLoad (Serializer *s);
void send (MidiChannel *mc) { if (_instrument) _instrument->send (mc); }
};
diff --git a/scumm/resource.cpp b/scumm/resource.cpp
index f9fd93651e..1ca9b5e1e0 100644
--- a/scumm/resource.cpp
+++ b/scumm/resource.cpp
@@ -724,8 +724,9 @@ int Scumm::readSoundResource(int type, int idx) {
pri = 2;
break;
case MKID('SPK '):
- if (!_use_adlib)
- pri = 0;
+ pri = -1;
+// if (!_use_adlib)
+// pri = 0;
break;
}