From ab5c981b10f68d786f60a55c2e7261f793c4bc72 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 26 Apr 2008 17:03:53 +0000 Subject: [PATCH] - Changed EMIDI controller 110-113 handling to more accurately match the EMIDI specs: Track designations and exclusions should be ignored past the initial beat, and EMIDI program change and volume events should be ignored unless they were used in the initial beat. SVN r944 (trunk) --- docs/rh-log.txt | 4 ++ src/sound/music_midi_midiout.cpp | 67 ++++++++++++++++++++------------ 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 5730014d9..4809fc581 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,8 @@ April 26, 2008 +- Changed EMIDI controller 110-113 handling to more accurately match the + EMIDI specs: Track designations and exclusions should be ignored past + the initial beat, and EMIDI program change and volume events should be + ignored unless they were used in the initial beat. - Fixed: When FMOD::System::init() returns FMOD_ERR_OUTPUT_CREATEBUFFER, it could also be because the user selected PCM-Float output, but the driver doesn't support it (even if it claims to *cough*Audigy XP drivers*cough*). diff --git a/src/sound/music_midi_midiout.cpp b/src/sound/music_midi_midiout.cpp index bcadf6d28..204b765fd 100644 --- a/src/sound/music_midi_midiout.cpp +++ b/src/sound/music_midi_midiout.cpp @@ -60,6 +60,7 @@ struct MIDISong2::TrackInfo size_t TrackP; size_t MaxTrackP; DWORD Delay; + DWORD PlayedTime; bool Finished; BYTE RunningStatus; SBYTE LoopCount; @@ -274,6 +275,7 @@ void MIDISong2 :: DoRestart() Tracks[i].LoopCount = -1; Tracks[i].EProgramChange = false; Tracks[i].EVolume = false; + Tracks[i].PlayedTime = 0; } ProcessInitialMetaEvents (); for (i = 0; i < NumTracks; ++i) @@ -314,7 +316,7 @@ DWORD *MIDISong2::MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time) start_events = events; while (TrackDue && events < max_event_p && tot_time <= max_time) { - // It's possible that this tick may be nothing meta-events and + // It's possible that this tick may be nothing but meta-events and // not generate any real events. Repeat this until we actually // get some output so we don't send an empty buffer to the MIDI // device. @@ -359,6 +361,7 @@ void MIDISong2::AdvanceTracks(DWORD time) if (!Tracks[i].Finished) { Tracks[i].Delay -= time; + Tracks[i].PlayedTime += time; } } } @@ -436,49 +439,63 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) } break; - case 39: // Fine channel volume - // Skip fine volume adjustment because I am lazy. - // (And it doesn't seem to be used much anyway.) - event = MIDI_META; + case 7+32: // Channel volume (LSB) + if (track->EVolume) + { + event = MIDI_META; + } + // It should be safe to pass this straight through to the + // MIDI device, since it's a very fine amount. break; - case 110: // EMIDI Track Designation + case 110: // EMIDI Track Designation - InitBeat only // Instruments 4, 5, 6, and 7 are all FM synth. // The rest are all wavetable. - if (data2 == 127) + if (track->PlayedTime < (DWORD)Division) { - track->Designation = ~0; - } - else - { - if (data2 <= 9) + if (data2 == 127) + { + track->Designation = ~0; + } + else if (data2 <= 9) { track->Designation |= 1 << data2; } + track->Designated = true; + event = MIDI_META; } - track->Designated = true; - event = MIDI_META; break; - case 111: // EMIDI Track Exclusion - if (track->Designated) + case 111: // EMIDI Track Exclusion - InitBeat only + if (track->PlayedTime < (DWORD)Division) { - track->Designation &= ~(1 << data2); + if (track->Designated && data2 <= 9) + { + track->Designation &= ~(1 << data2); + } + event = MIDI_META; } - event = MIDI_META; break; case 112: // EMIDI Program Change - track->EProgramChange = true; - event = 0xC0 | (event & 0x0F); - data1 = data2; - data2 = 0; + // Ignored unless it also appears in the InitBeat + if (track->PlayedTime < (DWORD)Division || track->EProgramChange) + { + track->EProgramChange = true; + event = 0xC0 | (event & 0x0F); + data1 = data2; + data2 = 0; + } break; case 113: // EMIDI Volume - track->EVolume = true; - data1 = 7; - data2 = VolumeControllerChange(event & 15, data2); + // Ignored unless it also appears in the InitBeat + if (track->PlayedTime < (DWORD)Division || track->EVolume) + { + track->EVolume = true; + data1 = 7; + data2 = VolumeControllerChange(event & 15, data2); + } break; case 116: // EMIDI Loop Begin