shithub: choc

Download patch

ref: 8e62a8d877b3c17035aa8fe0e353c5429812a318
parent: 6fbd6eafb3dec01401a033eae2e2ec7a2d00ec1c
author: Simon Howard <[email protected]>
date: Fri Jan 29 14:17:56 EST 2010

When doing a MUS to MID conversion, allocate MIDI channels so that the
lowest-numbered MIDI channels are used before higher-numbered ones.
Fixes ear-piercing whistle sound in the MAP05 music when playing with
timidity and EAWPATS (thanks entryway / HackNeyed).

Subversion-branch: /trunk/chocolate-doom
Subversion-revision: 1831

--- a/NEWS
+++ b/NEWS
@@ -79,6 +79,8 @@
        linedef is one sided (thanks Alexander Waldmann).
      * Key settings in a configuration file that are out of range
        do not cause a crash (thanks entryway).
+     * Fix ear-piercing whistle when playing the MAP05 MIDI music
+       using timidity with EAWPATS (thanks entryway / HackNeyed).
 
     libtextscreen:
      * There is now a second, small textscreen font, so that the
--- a/src/mus2mid.c
+++ b/src/mus2mid.c
@@ -32,6 +32,11 @@
 #include "memio.h"
 #include "mus2mid.h"
 
+#define NUM_CHANNELS 16
+
+#define MIDI_PERCUSSION_CHAN 9
+#define MUS_PERCUSSION_CHAN 15
+
 // MUS event codes
 typedef enum
 {
@@ -100,6 +105,8 @@
     0x40, 0x43, 0x78, 0x7B, 0x7E, 0x7F, 0x79
 };
 
+static int channel_map[NUM_CHANNELS];
+
 // Write timestamp to a MIDI file.
 
 static boolean midi_writetime(unsigned int time, MEMFILE *midioutput)
@@ -346,6 +353,68 @@
                                              midioutput);
 }
 
+// Allocate a free MIDI channel.
+
+static int midi_allocate_channel(void)
+{
+    int result;
+    int max;
+    int i;
+
+    // Find the current highest-allocated channel.
+
+    max = -1;
+
+    for (i=0; i<NUM_CHANNELS; ++i)
+    {
+        if (channel_map[i] > max)
+        {
+            max = channel_map[i];
+        }
+    }
+
+    // max is now equal to the highest-allocated MIDI channel.  We can
+    // now allocate the next available channel.  This also works if
+    // no channels are currently allocated (max=-1)
+
+    result = max + 1;
+
+    // Don't allocate the MIDI percussion channel!
+
+    if (result == MIDI_PERCUSSION_CHAN)
+    {
+        ++result;
+    }
+
+    return result;
+}
+
+// Given a MUS channel number, get the MIDI channel number to use
+// in the outputted file.
+
+static int midi_get_channel(int mus_channel)
+{
+    // Find the MIDI channel to use for this MUS channel.
+    // MUS channel 15 is the percusssion channel.
+
+    if (mus_channel == MUS_PERCUSSION_CHAN)
+    {
+        return MIDI_PERCUSSION_CHAN;
+    }
+    else
+    {
+        // If a MIDI channel hasn't been allocated for this MUS channel
+        // yet, allocate the next free MIDI channel.
+
+        if (channel_map[mus_channel] == -1)
+        {
+            channel_map[mus_channel] = midi_allocate_channel();
+        }
+
+        return channel_map[mus_channel];
+    }
+}
+
 static boolean read_musheader(MEMFILE *file, musheader *header)
 {
     boolean result;
@@ -402,6 +471,13 @@
     // Used in building up time delays
     unsigned int timedelay;
 
+    // Initialise channel map to mark all channels as unused.
+
+    for (channel=0; channel<NUM_CHANNELS; ++channel)
+    {
+        channel_map[channel] = -1;
+    }
+
     // Grab the header
 
     if (!read_musheader(musinput, &musfileheader))
@@ -447,21 +523,8 @@
                 return true;
             }
 
-            channel = eventdescriptor & 0x0F;
+            channel = midi_get_channel(eventdescriptor & 0x0F);
             event = eventdescriptor & 0x70;
-
-            // Swap channels 15 and 9.
-            // MIDI channel 9 = percussion.
-            // MUS channel 15 = percussion.
-
-            if (channel == 15)
-            {
-                channel = 9;
-            }
-            else if (channel == 9)
-            {
-                channel = 15;
-            }
 
             switch (event)
             {