summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSimon Howard2014-10-08 00:12:50 -0400
committerSimon Howard2014-10-08 00:12:50 -0400
commit9e9bb23d201c68a63690f96ba0c73110f4d999f4 (patch)
treec9f439fb9ee6686be7293c2c16a86a18ddd5fcae /src
parente4d9b85aa45fe31cb9b18a1ac8e9a95c7bc6ea5b (diff)
downloadchocolate-doom-9e9bb23d201c68a63690f96ba0c73110f4d999f4.tar.gz
chocolate-doom-9e9bb23d201c68a63690f96ba0c73110f4d999f4.tar.bz2
chocolate-doom-9e9bb23d201c68a63690f96ba0c73110f4d999f4.zip
midi: Fix "D_DDTBLU disease".
The Doom II MAP14/MAP20 music has a hanging note at the end of the track that is never turned off. If this is not reset when the track loops, there is a continuous (and annoying) drone sound throughout the next iteration of the song. Some information is here: http://www.doomworld.com/vb/source-ports/66802-the-d-ddtblu-disease/ This changes the mus2mid code to generate an "all notes off" controller event at the start of the MIDI track. This is specifically done at the start and not the end of the track because otherwise the looping of tracks like D_RUNNING is affected. Thanks to a whole host of people for help on this: @plumsinus for reporting the bug, @bradharding for devising a fix as part of Doom Retro, and Quasar for feedback and his own fix to the Eternity Engine. This fixes #412.
Diffstat (limited to 'src')
-rw-r--r--src/i_oplmusic.c19
-rw-r--r--src/midifile.h4
-rw-r--r--src/mus2mid.c10
3 files changed, 30 insertions, 3 deletions
diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c
index 5f9ab462..bcc8fe68 100644
--- a/src/i_oplmusic.c
+++ b/src/i_oplmusic.c
@@ -961,6 +961,21 @@ static void SetChannelVolume(opl_channel_data_t *channel, unsigned int volume)
}
}
+// Handler for the MIDI_CONTROLLER_ALL_NOTES_OFF channel event.
+static void AllNotesOff(opl_channel_data_t *channel, unsigned int param)
+{
+ unsigned int i;
+
+ for (i = 0; i < OPL_NUM_VOICES; ++i)
+ {
+ if (voices[i].channel == channel)
+ {
+ VoiceKeyOff(&voices[i]);
+ ReleaseVoice(&voices[i]);
+ }
+ }
+}
+
static void ControllerEvent(opl_track_data_t *track, midi_event_t *event)
{
unsigned int controller;
@@ -984,6 +999,10 @@ static void ControllerEvent(opl_track_data_t *track, midi_event_t *event)
SetChannelVolume(channel, param);
break;
+ case MIDI_CONTROLLER_ALL_NOTES_OFF:
+ AllNotesOff(channel, param);
+ break;
+
default:
#ifdef OPL_MIDI_DEBUG
fprintf(stderr, "Unknown MIDI controller type: %i\n", controller);
diff --git a/src/midifile.h b/src/midifile.h
index b539b1b5..490c2a0a 100644
--- a/src/midifile.h
+++ b/src/midifile.h
@@ -48,7 +48,9 @@ typedef enum
MIDI_CONTROLLER_DATA_ENTRY = 0x5,
MIDI_CONTROLLER_MAIN_VOLUME = 0x7,
- MIDI_CONTROLLER_PAN = 0xa
+ MIDI_CONTROLLER_PAN = 0xa,
+
+ MIDI_CONTROLLER_ALL_NOTES_OFF = 0x7b,
} midi_controller_t;
typedef enum
diff --git a/src/mus2mid.c b/src/mus2mid.c
index 2bf5ef9a..3cbcb0dd 100644
--- a/src/mus2mid.c
+++ b/src/mus2mid.c
@@ -383,7 +383,7 @@ static int AllocateMIDIChannel(void)
// Given a MUS channel number, get the MIDI channel number to use
// in the outputted file.
-static int GetMIDIChannel(int mus_channel)
+static int GetMIDIChannel(int mus_channel, MEMFILE *midioutput)
{
// Find the MIDI channel to use for this MUS channel.
// MUS channel 15 is the percusssion channel.
@@ -400,6 +400,12 @@ static int GetMIDIChannel(int mus_channel)
if (channel_map[mus_channel] == -1)
{
channel_map[mus_channel] = AllocateMIDIChannel();
+
+ // First time using the channel, send an "all notes off"
+ // event. This fixes "The D_DDTBLU disease" described here:
+ // http://www.doomworld.com/vb/source-ports/66802-the
+ WriteChangeController_Valueless(channel_map[mus_channel], 0x7b,
+ midioutput);
}
return channel_map[mus_channel];
@@ -514,7 +520,7 @@ boolean mus2mid(MEMFILE *musinput, MEMFILE *midioutput)
return true;
}
- channel = GetMIDIChannel(eventdescriptor & 0x0F);
+ channel = GetMIDIChannel(eventdescriptor & 0x0F, midioutput);
event = eventdescriptor & 0x70;
switch (event)