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);