foxygit / doom Log in
commit 8e62a8d877b3c17035aa8fe0e353c5429812a318
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Fri Jan 29 19:17:56 2010 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Fri Jan 29 19:17:56 2010 +0000

    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
---
 NEWS          |  2 ++
 src/mus2mid.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 79 insertions(+), 14 deletions(-)

diff --git a/NEWS b/NEWS
index abe5aa9d..ba7c81b1 100644
--- 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
diff --git a/src/mus2mid.c b/src/mus2mid.c
index f84be548..3fea1462 100644
--- 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 @@ static byte mus2midi_translation[] =
     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 @@ static boolean midi_writechangecontroller_valueless(byte channel,
                                              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 @@ boolean mus2mid(MEMFILE *musinput, MEMFILE *midioutput)
     // 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,22 +523,9 @@ boolean mus2mid(MEMFILE *musinput, MEMFILE *midioutput)
                 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)
             {
                 case mus_releasekey: