From 8e62a8d877b3c17035aa8fe0e353c5429812a318 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Fri, 29 Jan 2010 19:17:56 +0000 Subject: 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 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