shithub: choc

Download patch

ref: a09682d46edae813700eb693d0e5d5dccc652cd7
parent: 4f8f8a43e174f1e82dc0160c0ea96070e1cf6ef9
parent: 270a249e5e1d15a17c2f7b91c7cf53e28d342229
author: Simon Howard <fraggle+github@gmail.com>
date: Wed May 27 17:51:58 EDT 2015

Merge pull request #516 from khokh2001/oldopl

Older DMX's OPL voice allocation algorithm

--- a/src/doom/s_sound.c
+++ b/src/doom/s_sound.c
@@ -115,6 +115,7 @@
 {  
     int i;
 
+    I_SetOPLDriverVer(opl_v_new);
     I_PrecacheSounds(S_sfx, NUMSFX);
 
     S_SetSfxVolume(sfxVolume);
--- a/src/heretic/s_sound.c
+++ b/src/heretic/s_sound.c
@@ -516,6 +516,7 @@
 
 void S_Init(void)
 {
+    I_SetOPLDriverVer(opl_v_old);
     soundCurve = Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);
     if (snd_Channels > 8)
     {
--- a/src/hexen/s_sound.c
+++ b/src/hexen/s_sound.c
@@ -787,6 +787,7 @@
 
 void S_Init(void)
 {
+    I_SetOPLDriverVer(opl_v_old);
     SoundCurve = W_CacheLumpName("SNDCURVE", PU_STATIC);
 //      SoundCurve = Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);
 
--- a/src/i_oplmusic.c
+++ b/src/i_oplmusic.c
@@ -143,6 +143,9 @@
     // The current volume (register value) that has been set for this channel.
     unsigned int reg_volume;
 
+    // Priority.
+    unsigned int priority;
+
     // Next in linked list; a voice is always either in the
     // free list or the allocated list.
     opl_voice_t *next;
@@ -294,6 +297,7 @@
     124, 124, 125, 125, 126, 126, 127, 127
 };
 
+opl_driver_ver_t opl_drv_ver = opl_v_new;
 static boolean music_initialized = false;
 
 //static boolean musicpaused = false;
@@ -311,6 +315,7 @@
 static opl_voice_t voices[OPL_NUM_VOICES];
 static opl_voice_t *voice_free_list;
 static opl_voice_t *voice_alloced_list;
+static int voice_alloced_num;
 
 // Track data for playing tracks:
 
@@ -391,6 +396,8 @@
     *rover = result;
     result->next = NULL;
 
+    voice_alloced_num++;
+
     return result;
 }
 
@@ -410,6 +417,7 @@
         {
             *rover = voice->next;
             voice->next = NULL;
+            voice_alloced_num--;
             break;
         }
 
@@ -419,13 +427,20 @@
 
 // Release a voice back to the freelist.
 
+static void VoiceKeyOff(opl_voice_t *voice);
+
 static void ReleaseVoice(opl_voice_t *voice)
 {
     opl_voice_t **rover;
+    opl_voice_t *next;
+    boolean doublev;
 
     voice->channel = NULL;
     voice->note = 0;
 
+    doublev = voice->current_instr_voice != 0;
+    next = voice->next;
+
     // Remove from alloced list.
 
     RemoveVoiceFromAllocedList(voice);
@@ -441,6 +456,12 @@
 
     *rover = voice;
     voice->next = NULL;
+
+    if (next != NULL && doublev && opl_drv_ver == opl_v_old)
+    {
+        VoiceKeyOff(next);
+        ReleaseVoice(next);
+    }
 }
 
 // Load data to the specified operator
@@ -511,6 +532,11 @@
     // Hack to force a volume update.
 
     voice->reg_volume = 999;
+
+    // Calculate voice priority.
+
+    voice->priority = 0x0f - (data->carrier.attack >> 4)
+                    + 0x0f - (data->carrier.sustain & 0x0f);
 }
 
 static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume)
@@ -638,8 +664,9 @@
 static void KeyOffEvent(opl_track_data_t *track, midi_event_t *event)
 {
     opl_channel_data_t *channel;
+    opl_voice_t *rover;
+    opl_voice_t *prev;
     unsigned int key;
-    unsigned int i;
 
 /*
     printf("note off: channel %i, %i, %i\n",
@@ -654,16 +681,32 @@
     // Turn off voices being used to play this key.
     // If it is a double voice instrument there will be two.
 
-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    rover = voice_alloced_list;
+    prev = NULL;
+
+    while (rover!=NULL)
     {
-        if (voices[i].channel == channel && voices[i].key == key)
+        if (rover->channel == channel && rover->key == key)
         {
-            VoiceKeyOff(&voices[i]);
+            VoiceKeyOff(rover);
 
             // Finished with this voice now.
 
-            ReleaseVoice(&voices[i]);
+            ReleaseVoice(rover);
+            if (prev == NULL)
+            {
+                rover = voice_alloced_list;
+            }
+            else
+            {
+                rover = prev->next;
+            }
         }
+        else
+        {
+            prev = rover;
+            rover = rover->next;
+        }
     }
 }
 
@@ -701,7 +744,40 @@
     ReleaseVoice(result);
 }
 
+static void ReplaceExistingVoiceOld(opl_channel_data_t *channel)
+{
+    opl_voice_t *rover;
+    opl_voice_t *result;
+    opl_voice_t *roverend;
+    int i;
+    int priority;
 
+    result = voice_alloced_list;
+
+    roverend = voice_alloced_list;
+
+    for (i = 0; i < voice_alloced_num - 3; i++)
+    {
+        roverend = roverend->next;
+    }
+
+    priority = 0x8000;
+
+    for (rover = voice_alloced_list; rover != roverend; rover = rover->next)
+    {
+        if (rover->priority < priority
+         && rover->channel >= channel)
+        {
+            priority = rover->priority;
+            result = rover;
+        }
+    }
+
+    VoiceKeyOff(result);
+    ReleaseVoice(result);
+}
+
+
 static unsigned int FrequencyForVoice(opl_voice_t *voice)
 {
     genmidi_voice_t *gm_voice;
@@ -854,6 +930,7 @@
     genmidi_instr_t *instrument;
     opl_channel_data_t *channel;
     unsigned int note, key, volume;
+    boolean doublev;
 
 /*
     printf("note on: channel %i, %i, %i\n",
@@ -896,20 +973,45 @@
     {
         instrument = channel->instrument;
     }
+    doublev = (SHORT(instrument->flags) & GENMIDI_FLAG_2VOICE) != 0;
 
-    if (voice_free_list == NULL)
+	if (opl_drv_ver == opl_v_old)
     {
-        ReplaceExistingVoice();
-    }
+        if (voice_alloced_num == OPL_NUM_VOICES)
+        {
+            ReplaceExistingVoiceOld(channel);
+        }
+        if (voice_alloced_num == OPL_NUM_VOICES - 1 && doublev)
+        {
+            ReplaceExistingVoiceOld(channel);
+        }
 
-    // Find and program a voice for this instrument.  If this
-    // is a double voice instrument, we must do this twice.
+        // Find and program a voice for this instrument.  If this
+        // is a double voice instrument, we must do this twice.
 
-    VoiceKeyOn(channel, instrument, 0, note, key, volume);
+        if (doublev)
+        {
+            VoiceKeyOn(channel, instrument, 1, note, key, volume);
+        }
 
-    if ((SHORT(instrument->flags) & GENMIDI_FLAG_2VOICE) != 0)
+        VoiceKeyOn(channel, instrument, 0, note, key, volume);
+    }
+    else
     {
-        VoiceKeyOn(channel, instrument, 1, note, key, volume);
+        if (voice_free_list == NULL)
+        {
+            ReplaceExistingVoice();
+        }
+
+        // Find and program a voice for this instrument.  If this
+        // is a double voice instrument, we must do this twice.
+
+        VoiceKeyOn(channel, instrument, 0, note, key, volume);
+
+        if (doublev)
+        {
+            VoiceKeyOn(channel, instrument, 1, note, key, volume);
+        }
     }
 }
 
@@ -948,14 +1050,34 @@
 // Handler for the MIDI_CONTROLLER_ALL_NOTES_OFF channel event.
 static void AllNotesOff(opl_channel_data_t *channel, unsigned int param)
 {
-    unsigned int i;
+    opl_voice_t *rover;
+    opl_voice_t *prev;
 
-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    rover = voice_alloced_list;
+    prev = NULL;
+
+    while (rover!=NULL)
     {
-        if (voices[i].channel == channel)
+        if (rover->channel == channel)
         {
-            VoiceKeyOff(&voices[i]);
-            ReleaseVoice(&voices[i]);
+            VoiceKeyOff(rover);
+
+            // Finished with this voice now.
+
+            ReleaseVoice(rover);
+            if (prev == NULL)
+            {
+                rover = voice_alloced_list;
+            }
+            else
+            {
+                rover = prev->next;
+            }
+        }
+        else
+        {
+            prev = rover;
+            rover = rover->next;
         }
     }
 }
--- a/src/i_sound.c
+++ b/src/i_sound.c
@@ -66,6 +66,7 @@
 
 // For OPL module:
 
+extern opl_driver_ver_t opl_drv_ver;
 extern int opl_io_port;
 
 // For native music module:
@@ -470,5 +471,10 @@
         }
     }
 #endif
+}
+
+void I_SetOPLDriverVer(opl_driver_ver_t ver)
+{
+    opl_drv_ver = ver;
 }
 
--- a/src/i_sound.h
+++ b/src/i_sound.h
@@ -234,5 +234,12 @@
 
 void I_BindSoundVariables(void);
 
+typedef enum {
+    opl_v_old, // hexen heretic
+    opl_v_new // doom strife
+} opl_driver_ver_t;
+
+void I_SetOPLDriverVer(opl_driver_ver_t ver);
+
 #endif
 
--- a/src/strife/s_sound.c
+++ b/src/strife/s_sound.c
@@ -137,6 +137,7 @@
 {  
     int i;
 
+    I_SetOPLDriverVer(opl_v_new);
     I_PrecacheSounds(S_sfx, NUMSFX);
 
     S_SetSfxVolume(sfxVolume);