foxygit / doom Log in
commit e62bc4cee05ddb2d2fcf0f04aee90c9158188ca6
Author:     khokh2001 <alexeytf2@gmail.com>
AuthorDate: Mon Mar 9 16:32:08 2015 +0900
Commit:     khokh2001 <alexeytf2@gmail.com>
CommitDate: Mon Mar 9 16:32:08 2015 +0900

    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.
---
 src/doom/s_sound.c    |   1 +
 src/heretic/s_sound.c |   1 +
 src/hexen/s_sound.c   |   1 +
 src/i_oplmusic.c      | 158 ++++++++++++++++++++++++++++++++++++++++++++------
 src/i_sound.c         |   6 ++
 src/i_sound.h         |   7 +++
 src/strife/s_sound.c  |   1 +
 7 files changed, 157 insertions(+), 18 deletions(-)

diff --git a/src/doom/s_sound.c b/src/doom/s_sound.c
index f6d8be13..5a97a2f6 100644
--- a/src/doom/s_sound.c
+++ b/src/doom/s_sound.c
@@ -115,6 +115,7 @@ void S_Init(int sfxVolume, int musicVolume)
 {
     int i;

+    I_SetOPLDriverVer(opl_v_new);
     I_PrecacheSounds(S_sfx, NUMSFX);

     S_SetSfxVolume(sfxVolume);
diff --git a/src/heretic/s_sound.c b/src/heretic/s_sound.c
index 09f2032d..988dc039 100644
--- a/src/heretic/s_sound.c
+++ b/src/heretic/s_sound.c
@@ -516,6 +516,7 @@ void S_UpdateSounds(mobj_t * listener)

 void S_Init(void)
 {
+    I_SetOPLDriverVer(opl_v_old);
     soundCurve = Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);
     if (snd_Channels > 8)
     {
diff --git a/src/hexen/s_sound.c b/src/hexen/s_sound.c
index b5af53c7..60666566 100644
--- a/src/hexen/s_sound.c
+++ b/src/hexen/s_sound.c
@@ -787,6 +787,7 @@ void S_UpdateSounds(mobj_t * listener)

 void S_Init(void)
 {
+    I_SetOPLDriverVer(opl_v_old);
     SoundCurve = W_CacheLumpName("SNDCURVE", PU_STATIC);
 //      SoundCurve = Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);

diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c
index c02f1941..c3e4df27 100644
--- a/src/i_oplmusic.c
+++ b/src/i_oplmusic.c
@@ -143,6 +143,9 @@ struct opl_voice_s
     // 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 @@ static const unsigned int volume_mapping_table[] = {
     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 char (*percussion_names)[32];
 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 @@ static opl_voice_t *GetFreeVoice(void)
     *rover = result;
     result->next = NULL;

+    voice_alloced_num++;
+
     return result;
 }

@@ -409,6 +416,7 @@ static void RemoveVoiceFromAllocedList(opl_voice_t *voice)
         {
             *rover = voice->next;
             voice->next = NULL;
+            voice_alloced_num--;
             break;
         }

@@ -418,13 +426,20 @@ static void RemoveVoiceFromAllocedList(opl_voice_t *voice)

 // 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 @@ static void ReleaseVoice(opl_voice_t *voice)

     *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 @@ static void SetVoiceInstrument(opl_voice_t *voice,
     // 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 opl_channel_data_t *TrackChannelForEvent(opl_track_data_t *track,
 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,15 +677,31 @@ static void KeyOffEvent(opl_track_data_t *track, midi_event_t *event)
     // 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,6 +739,39 @@ static void ReplaceExistingVoice()
     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)
 {
@@ -849,6 +925,7 @@ static void KeyOnEvent(opl_track_data_t *track, midi_event_t *event)
     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 @@ static void KeyOnEvent(opl_track_data_t *track, midi_event_t *event)
     {
         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 @@ static void SetChannelVolume(opl_channel_data_t *channel, unsigned int volume)
 // 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;
         }
     }
 }
diff --git a/src/i_sound.c b/src/i_sound.c
index e70b9bc7..eac21307 100644
--- a/src/i_sound.c
+++ b/src/i_sound.c
@@ -66,6 +66,7 @@ extern music_module_t music_opl_module;

 // For OPL module:

+extern opl_driver_ver opl_drv_ver;
 extern int opl_io_port;

 // For native music module:
@@ -472,3 +473,8 @@ void I_BindSoundVariables(void)
 #endif
 }

+void I_SetOPLDriverVer(opl_driver_ver ver)
+{
+    opl_drv_ver = ver;
+}
+
diff --git a/src/i_sound.h b/src/i_sound.h
index e429e960..0808ac87 100644
--- a/src/i_sound.h
+++ b/src/i_sound.h
@@ -234,5 +234,12 @@ extern char *snd_musiccmd;

 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

diff --git a/src/strife/s_sound.c b/src/strife/s_sound.c
index d22f84e4..3f010ea1 100644
--- a/src/strife/s_sound.c
+++ b/src/strife/s_sound.c
@@ -137,6 +137,7 @@ void S_Init(int sfxVolume, int musicVolume, int voiceVolume)
 {
     int i;

+    I_SetOPLDriverVer(opl_v_new);
     I_PrecacheSounds(S_sfx, NUMSFX);

     S_SetSfxVolume(sfxVolume);