shithub: choc

Download patch

ref: e62bc4cee05ddb2d2fcf0f04aee90c9158188ca6
parent: 70e39d13808d9a6de004bde9570a2db001cc95e4
author: khokh2001 <alexeytf2@gmail.com>
date: Mon Mar 9 12:32:08 EDT 2015

Hexen and Heretic use older DMX. Since OPL Voice Allocating algorithm differ. This commit adds old DMX's voice allocating alogrithm for Hexen and Heretic.

--- 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 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:
 
@@ -390,6 +395,8 @@
     *rover = result;
     result->next = NULL;
 
+    voice_alloced_num++;
+
     return result;
 }
 
@@ -409,6 +416,7 @@
         {
             *rover = voice->next;
             voice->next = NULL;
+            voice_alloced_num--;
             break;
         }
 
@@ -418,13 +426,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);
@@ -440,6 +455,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
@@ -510,6 +531,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)
@@ -634,8 +660,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",
@@ -650,16 +677,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;
+        }
     }
 }
 
@@ -696,7 +739,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;
@@ -849,6 +925,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",
@@ -891,20 +968,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);
+        }
     }
 }
 
@@ -943,14 +1045,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 opl_drv_ver;
 extern int opl_io_port;
 
 // For native music module:
@@ -470,5 +471,10 @@
         }
     }
 #endif
+}
+
+void I_SetOPLDriverVer(opl_driver_ver 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;
+
+void I_SetOPLDriverVer(opl_driver_ver 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);