Fix OPL Synth note cutoffs and issues after removal of MusLib

This should fix bug reported in https://forum.zdoom.org/viewtopic.php?
f=104&t=56682.
There were two problems:
1. Algorithm to select a free voice was not appropriate. Changed to a
simple "least-recently-freed voice" algorithm.
2. Sustained voices were treated as used voices and never got replaced.
Now sustained voices are preferentially replaced when there are no free
voices.
This commit is contained in:
Hisymak 2018-04-29 14:56:35 +02:00 committed by Christoph Oelckers
parent 76ed80fe56
commit 07586af6d1
2 changed files with 30 additions and 7 deletions

View file

@ -53,6 +53,8 @@ int musicBlock::releaseVoice(uint32_t slot, uint32_t killed)
struct OPLVoice *ch = &voices[slot];
io->WriteFrequency(slot, ch->note, ch->pitch, 0);
ch->index = ~0u;
ch->sustained = false;
if (!killed) ch->timestamp = ++timeCounter;
if (killed) io->MuteChannel(slot);
return slot;
}
@ -65,15 +67,25 @@ int musicBlock::releaseVoice(uint32_t slot, uint32_t killed)
int musicBlock::findFreeVoice()
{
// We want to prefer the least recently freed voice, as more recently
// freed voices can still play a tone from their release state.
// Sustained voices are replaced when there are no free voices.
uint32_t min_value = ~0u;
int result = -1;
for (uint32_t i = 0; i < io->NumChannels; ++i)
{
if (voices[i].index == ~0u)
uint32_t voice_value = voices[i].timestamp + (voices[i].sustained ? (1 << 31) : 0);
if ((voices[i].index == ~0u || voices[i].sustained) && (voice_value < min_value))
{
releaseVoice(i, 1);
return i;
min_value = voice_value;
result = i;
}
}
return -1;
if (result >= 0)
{
releaseVoice(result, 1);
}
return result;
}
//----------------------------------------------------------------------------
@ -94,7 +106,6 @@ int musicBlock::replaceExistingVoice()
// Lower numbered MIDI channels implicitly have a higher priority
// than higher-numbered channels, eg. MIDI channel 1 is never
// discarded for MIDI channel 2.
int result = 0;
for (uint32_t i = 0; i < io->NumChannels; ++i)
@ -236,7 +247,11 @@ void musicBlock::noteOff(uint32_t id, uint8_t note)
{
if (voices[i].index == id && voices[i].key == note)
{
if (sustain >= MIN_SUSTAIN) voices[i].sustained = true;
if (sustain >= MIN_SUSTAIN)
{
voices[i].sustained = true;
voices[i].timestamp = ++timeCounter;
}
else releaseVoice(i, 0);
}
}
@ -357,7 +372,11 @@ void musicBlock::notesOff(uint32_t id, int value)
{
if (voices[i].index == id)
{
if (oplchannels[id].Sustain >= MIN_SUSTAIN) voices[i].sustained = true;
if (oplchannels[id].Sustain >= MIN_SUSTAIN)
{
voices[i].sustained = true;
voices[i].timestamp = ++timeCounter;
}
else releaseVoice(i, 0);
}
}
@ -475,5 +494,7 @@ void musicBlock::stopAllVoices()
for (uint32_t i = 0; i < io->NumChannels; i++)
{
if (voices[i].index != ~0u) releaseVoice(i, 1);
voices[i].timestamp = 0;
}
timeCounter = 0;
}

View file

@ -15,6 +15,7 @@ struct OPLVoice
bool sustained;
int8_t fine_tuning;
int pitch;
uint32_t timestamp;
};
struct musicBlock {
@ -23,6 +24,7 @@ struct musicBlock {
OPLChannel oplchannels[NUM_CHANNELS];
OPLio *io;
uint32_t timeCounter;
struct GenMidiInstrument OPLinstruments[GENMIDI_NUM_TOTAL];