mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 23:12:24 +00:00
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:
parent
76ed80fe56
commit
07586af6d1
2 changed files with 30 additions and 7 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
Loading…
Reference in a new issue