aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/mididrv.h45
-rw-r--r--sound/midiparser.cpp33
-rw-r--r--sound/midiparser_smf.cpp3
-rw-r--r--sound/midiparser_xmidi.cpp3
-rw-r--r--sound/softsynth/adlib.cpp28
5 files changed, 74 insertions, 38 deletions
diff --git a/sound/mididrv.h b/sound/mididrv.h
index b2d4d37aa0..09d6e541d8 100644
--- a/sound/mididrv.h
+++ b/sound/mididrv.h
@@ -165,8 +165,24 @@ public:
/** Close the midi driver. */
virtual void close() = 0;
- /** Output a packed midi command to the midi stream. */
+ /**
+ * Output a packed midi command to the midi stream.
+ * The 'lowest' byte (i.e. b & 0xFF) is the status
+ * code, then come (if used) the first and second
+ * opcode.
+ */
virtual void send(uint32 b) = 0;
+
+ /**
+ * Output a midi command to the midi stream. Convenience wrapper
+ * around the usual 'packed' send method.
+ *
+ * Do NOT use this for sysEx transmission; instead, use the sysEx()
+ * method below.
+ */
+ void send(byte status, byte firstOp, byte secondOp) {
+ send(status | ((uint32)firstOp << 8) | ((uint32)secondOp << 16));
+ }
/** Get or set a property. */
virtual uint32 property(int prop, uint32 param) { return 0; }
@@ -175,18 +191,29 @@ public:
static const char *getErrorName(int error_code);
// HIGH-LEVEL SEMANTIC METHODS
- virtual void setPitchBendRange(byte channel, uint range)
- {
- send(( 0 << 16) | (101 << 8) | (0xB0 | channel));
- send(( 0 << 16) | (100 << 8) | (0xB0 | channel));
- send((range << 16) | ( 6 << 8) | (0xB0 | channel));
- send(( 0 << 16) | ( 38 << 8) | (0xB0 | channel));
- send(( 127 << 16) | (101 << 8) | (0xB0 | channel));
- send(( 127 << 16) | (100 << 8) | (0xB0 | channel));
+ virtual void setPitchBendRange(byte channel, uint range) {
+ send(0xB0 | channel, 101, 0);
+ send(0xB0 | channel, 100, 0);
+ send(0xB0 | channel, 6, range);
+ send(0xB0 | channel, 38, 0);
+ send(0xB0 | channel, 101, 127);
+ send(0xB0 | channel, 100, 127);
}
+ /**
+ * Transmit a sysEx to the midi device.
+ *
+ * The given msg MUST NOT contain the usual SysEx frame, i.e.
+ * do NOT include the leading 0xF0 and the trailing 0xF7.
+ *
+ * Furthermore, the maximal supported length of a SysEx
+ * is 254 bytes. Passing longer buffers can lead to
+ * undefined behavior (most likely, a crash).
+ */
virtual void sysEx(const byte *msg, uint16 length) { }
+
virtual void sysEx_customInstrument(byte channel, uint32 type, const byte *instr) { }
+
virtual void metaEvent(byte type, byte *data, uint16 length) { }
// Timing functions - MidiDriver now operates timers
diff --git a/sound/midiparser.cpp b/sound/midiparser.cpp
index 1219978ace..7ad8f3bc1c 100644
--- a/sound/midiparser.cpp
+++ b/sound/midiparser.cpp
@@ -121,7 +121,7 @@ void MidiParser::hangingNote(byte channel, byte note, uint32 time_left, bool rec
best = ptr;
if (ptr->time_left) {
if (recycle)
- _driver->send(0x80 | channel | note << 8);
+ _driver->send(0x80 | channel, note, 0);
--_hanging_notes_count;
}
break;
@@ -166,7 +166,7 @@ void MidiParser::onTimer() {
for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) {
if (ptr->time_left) {
if (ptr->time_left <= _timer_rate) {
- _driver->send(0x80 | ptr->channel | ptr->note << 8);
+ _driver->send(0x80 | ptr->channel, ptr->note, 0);
ptr->time_left = 0;
--_hanging_notes_count;
} else {
@@ -193,7 +193,11 @@ void MidiParser::onTimer() {
if (info.event == 0xF0) {
// SysEx event
- _driver->sysEx (info.ext.data, (uint16)info.length);
+ // Check for trailing 0xF7 -- if present, remove it.
+ if (info.ext.data[info.length-1] == 0xF7)
+ _driver->sysEx(info.ext.data, (uint16)info.length-1);
+ else
+ _driver->sysEx(info.ext.data, (uint16)info.length);
} else if (info.event == 0xFF) {
// META event
if (info.ext.type == 0x2F) {
@@ -223,7 +227,7 @@ void MidiParser::onTimer() {
else
activeNote(info.channel(), info.basic.param1, true);
}
- _driver->send(info.event | info.basic.param1 << 8 | info.basic.param2 << 16);
+ _driver->send(info.event, info.basic.param1, info.basic.param2);
}
@@ -249,7 +253,7 @@ void MidiParser::allNotesOff() {
for (i = 0; i < 128; ++i) {
for (j = 0; j < 16; ++j) {
if (_active_notes[i] & (1 << j)) {
- _driver->send(0x80 | j | i << 8);
+ _driver->send(0x80 | j, i, 0);
}
}
}
@@ -257,7 +261,7 @@ void MidiParser::allNotesOff() {
// Turn off all hanging notes
for (i = 0; i < ARRAYSIZE(_hanging_notes); i++) {
if (_hanging_notes[i].time_left) {
- _driver->send(0x80 | _hanging_notes[i].channel | _hanging_notes[i].note << 8);
+ _driver->send(0x80 | _hanging_notes[i].channel, _hanging_notes[i].note, 0);
_hanging_notes[i].time_left = 0;
}
}
@@ -267,7 +271,7 @@ void MidiParser::allNotesOff() {
// support this...).
for (i = 0; i < 16; ++i) {
- _driver->send(0x007BB0 | i); // All notes off
+ _driver->send(0xB0 | i, 0x7b, 0); // All notes off
}
memset(_active_notes, 0, sizeof(_active_notes));
@@ -323,7 +327,7 @@ void MidiParser::hangAllActiveNotes() {
for (j = 0; j < 16; ++j) {
if (temp_active[i] & (1 << j)) {
activeNote(j, i, false);
- _driver->send(0x80 | j | i << 8);
+ _driver->send(0x80 | j, i, 0);
}
}
}
@@ -368,10 +372,13 @@ bool MidiParser::jumpToTick(uint32 tick, bool fireEvents) {
_driver->metaEvent(info.ext.type, info.ext.data, (uint16) info.length);
}
} else if (fireEvents) {
- if (info.event == 0xF0)
- _driver->sysEx(info.ext.data, (uint16) info.length);
- else
- _driver->send(info.event | info.basic.param1 << 8 | info.basic.param2 << 16);
+ if (info.event == 0xF0) {
+ if (info.ext.data[info.length-1] == 0xF7)
+ _driver->sysEx(info.ext.data, (uint16)info.length-1);
+ else
+ _driver->sysEx(info.ext.data, (uint16)info.length);
+ } else
+ _driver->send(info.event, info.basic.param1, info.basic.param2);
}
parseNextEvent(_next_event);
@@ -411,7 +418,7 @@ void MidiParser::unloadMusic() {
if (_driver) {
for (int i = 0; i < 16; ++i) {
- _driver->send(0x4000E0 | i);
+ _driver->send(0xE0 | i, 0, 0x40);
}
}
}
diff --git a/sound/midiparser_smf.cpp b/sound/midiparser_smf.cpp
index dc810f9178..746624d35d 100644
--- a/sound/midiparser_smf.cpp
+++ b/sound/midiparser_smf.cpp
@@ -124,6 +124,9 @@ void MidiParser_SMF::parseNextEvent(EventInfo &info) {
info.ext.data = _position._play_pos;
_position._play_pos += info.length;
break;
+
+ default:
+ warning("MidiParser_XMIDI::parseNextEvent: Unsupported event code %x", info.event);
}
}
}
diff --git a/sound/midiparser_xmidi.cpp b/sound/midiparser_xmidi.cpp
index 4814964cd5..2ee63d13a0 100644
--- a/sound/midiparser_xmidi.cpp
+++ b/sound/midiparser_xmidi.cpp
@@ -120,6 +120,9 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) {
info.ext.data[2] = 0x20;
}
break;
+
+ default:
+ warning("MidiParser_XMIDI::parseNextEvent: Unsupported event code %x", info.event);
}
}
}
diff --git a/sound/softsynth/adlib.cpp b/sound/softsynth/adlib.cpp
index 3c9795ee12..96b1add13f 100644
--- a/sound/softsynth/adlib.cpp
+++ b/sound/softsynth/adlib.cpp
@@ -565,7 +565,7 @@ public:
int getRate() const { return _mixer->getOutputRate(); }
private:
- bool _game_SmallHeader;
+ bool _scummSmallHeader; // FIXME: This flag controls a special mode for SCUMM V3 games
FM_OPL *_opl;
byte *_adlib_reg_cache;
@@ -805,7 +805,7 @@ MidiDriver_ADLIB::MidiDriver_ADLIB(Audio::Mixer *mixer)
: MidiDriver_Emulated(mixer) {
uint i;
- _game_SmallHeader = false;
+ _scummSmallHeader = false;
_adlib_reg_cache = 0;
@@ -922,8 +922,8 @@ void MidiDriver_ADLIB::send(byte chan, uint32 b) {
uint32 MidiDriver_ADLIB::property(int prop, uint32 param) {
switch (prop) {
case PROP_OLD_ADLIB: // Older games used a different operator volume algorithm
- _game_SmallHeader = (param > 0);
- if (_game_SmallHeader) {
+ _scummSmallHeader = (param > 0);
+ if (_scummSmallHeader) {
_timer_p = 473;
_timer_q = 1000;
} else {
@@ -1041,7 +1041,7 @@ void MidiDriver_ADLIB::mc_inc_stuff(AdlibVoice *voice, Struct10 *s10, Struct11 *
switch (s11->param) {
case 0:
voice->_vol_2 = s10->start_value + s11->modify_val;
- if (!_game_SmallHeader) {
+ if (!_scummSmallHeader) {
adlib_set_param(voice->_channel, 0,
volume_table[lookup_table[voice->_vol_2]
[part->_vol_eff >> 2]]);
@@ -1051,7 +1051,7 @@ void MidiDriver_ADLIB::mc_inc_stuff(AdlibVoice *voice, Struct10 *s10, Struct11 *
break;
case 13:
voice->_vol_1 = s10->start_value + s11->modify_val;
- if (voice->_twochan && !_game_SmallHeader) {
+ if (voice->_twochan && !_scummSmallHeader) {
adlib_set_param(voice->_channel, 13,
volume_table[lookup_table[voice->_vol_1]
[part->_vol_eff >> 2]]);
@@ -1253,10 +1253,6 @@ void MidiDriver_ADLIB::adlib_playnote(int channel, int note) {
adlib_write(channel + 0xB0, oct | 0x20);
}
-// TODO: Replace this with RandomSource? But if so, please note that this
-// function will be called with negative parameters - getRandomNumber(-1) will
-// crash ScummVM, random_nr(-1) won't.
-
int MidiDriver_ADLIB::random_nr(int a) {
static byte _rand_seed = 1;
if (_rand_seed & 1) {
@@ -1310,8 +1306,8 @@ AdlibVoice *MidiDriver_ADLIB::allocate_voice(byte pri) {
}
}
- /* V3 games don't have note priorities, first comes wins. */
- if (_game_SmallHeader)
+ /* SCUMM V3 games don't have note priorities, first comes wins. */
+ if (_scummSmallHeader)
return NULL;
if (best)
@@ -1341,7 +1337,7 @@ void MidiDriver_ADLIB::mc_key_on(AdlibVoice *voice, AdlibInstrument *instr, byte
if (voice->_duration != 0)
voice->_duration *= 63;
- if (!_game_SmallHeader)
+ if (!_scummSmallHeader)
vol_1 = (instr->mod_scalingOutputLevel & 0x3F) + lookup_table[velocity >> 1][instr->mod_waveformSelect >> 2];
else
vol_1 = 0x3f - (instr->mod_scalingOutputLevel & 0x3F);
@@ -1349,7 +1345,7 @@ void MidiDriver_ADLIB::mc_key_on(AdlibVoice *voice, AdlibInstrument *instr, byte
vol_1 = 0x3F;
voice->_vol_1 = vol_1;
- if (!_game_SmallHeader)
+ if (!_scummSmallHeader)
vol_2 = (instr->car_scalingOutputLevel & 0x3F) + lookup_table[velocity >> 1][instr->car_waveformSelect >> 2];
else
vol_2 = 0x3f - (instr->car_scalingOutputLevel & 0x3F);
@@ -1359,7 +1355,7 @@ void MidiDriver_ADLIB::mc_key_on(AdlibVoice *voice, AdlibInstrument *instr, byte
c = part->_vol_eff >> 2;
- if (!_game_SmallHeader) {
+ if (!_scummSmallHeader) {
vol_2 = volume_table[lookup_table[vol_2][c]];
if (voice->_twochan)
vol_1 = volume_table[lookup_table[vol_1][c]];
@@ -1453,7 +1449,7 @@ void MidiDriver_ADLIB::mc_init_stuff(AdlibVoice *voice, Struct10 * s10,
void MidiDriver_ADLIB::struct10_init(Struct10 *s10, InstrumentExtra *ie) {
s10->active = 1;
- if (!_game_SmallHeader) {
+ if (!_scummSmallHeader) {
s10->cur_val = 0;
} else {
s10->cur_val = s10->start_value;