better channel allocation strategy

issue #376
This commit is contained in:
tildearrow 2022-04-28 05:04:34 -05:00
parent 859b2cf8db
commit 3906fc1dd4
2 changed files with 48 additions and 3 deletions

View file

@ -2138,10 +2138,12 @@ void DivEngine::noteOff(int chan) {
} }
void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) { void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) {
//if (ch<0 || ch>=chans) return; bool isViable[DIV_MAX_CHANS];
bool canPlayAnyway=false;
if (midiBaseChan<0) midiBaseChan=0; if (midiBaseChan<0) midiBaseChan=0;
if (midiBaseChan>=chans) midiBaseChan=chans-1; if (midiBaseChan>=chans) midiBaseChan=chans-1;
int finalChan=midiBaseChan; int finalChan=midiBaseChan;
int finalChanType=getChannelType(finalChan);
if (!playing) { if (!playing) {
reset(); reset();
@ -2149,16 +2151,55 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) {
playing=true; playing=true;
} }
// 1. check which channels are viable for this instrument
DivInstrument* insInst=getIns(ins);
for (int i=0; i<chans; i++) {
if (ins==-1 || ins>=song.insLen || getPreferInsType(i)==insInst->type || getPreferInsSecondType(i)==insInst->type) {
if (insInst->type==DIV_INS_OPL) {
if (insInst->fm.ops==2 || getChannelType(i)==DIV_CH_OP) {
isViable[i]=true;
canPlayAnyway=true;
} else {
isViable[i]=false;
}
} else {
isViable[i]=true;
canPlayAnyway=true;
}
} else {
isViable[i]=false;
}
}
if (!canPlayAnyway) return;
// 2. find a free channel
do { do {
if ((ins==-1 || ins>=song.insLen || getPreferInsType(finalChan)==getIns(ins)->type || getPreferInsSecondType(finalChan)==getIns(ins)->type) && chan[finalChan].midiNote==-1) { if (isViable[finalChan] && chan[finalChan].midiNote==-1 && getChannelType(finalChan)==finalChanType) {
chan[finalChan].midiNote=note; chan[finalChan].midiNote=note;
chan[finalChan].midiAge=midiAgeCounter++;
pendingNotes.push(DivNoteEvent(finalChan,ins,note,vol,true)); pendingNotes.push(DivNoteEvent(finalChan,ins,note,vol,true));
break; return;
} }
if (++finalChan>=chans) { if (++finalChan>=chans) {
finalChan=0; finalChan=0;
} }
} while (finalChan!=midiBaseChan); } while (finalChan!=midiBaseChan);
// 3. find the oldest channel
int candidate=finalChan;
do {
if (isViable[finalChan] && getChannelType(finalChan)==finalChanType && chan[finalChan].midiAge<chan[candidate].midiAge) {
candidate=finalChan;
}
if (++finalChan>=chans) {
finalChan=0;
}
} while (finalChan!=midiBaseChan);
chan[candidate].midiNote=note;
chan[candidate].midiAge=midiAgeCounter++;
pendingNotes.push(DivNoteEvent(candidate,ins,note,vol,true));
} }
void DivEngine::autoNoteOff(int ch, int note, int vol) { void DivEngine::autoNoteOff(int ch, int note, int vol) {

View file

@ -89,6 +89,7 @@ struct DivChannelState {
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, noteOnInhibit, resetArp; bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, noteOnInhibit, resetArp;
int midiNote, curMidiNote, midiPitch; int midiNote, curMidiNote, midiPitch;
size_t midiAge;
bool midiAftertouch; bool midiAftertouch;
DivChannelState(): DivChannelState():
@ -135,6 +136,7 @@ struct DivChannelState {
midiNote(-1), midiNote(-1),
curMidiNote(-1), curMidiNote(-1),
midiPitch(-1), midiPitch(-1),
midiAge(0),
midiAftertouch(false) {} midiAftertouch(false) {}
}; };
@ -339,6 +341,7 @@ class DivEngine {
int reversePitchTable[4096]; int reversePitchTable[4096];
int pitchTable[4096]; int pitchTable[4096];
int midiBaseChan; int midiBaseChan;
size_t midiAgeCounter;
blip_buffer_t* samp_bb; blip_buffer_t* samp_bb;
size_t samp_bbInLen; size_t samp_bbInLen;
@ -894,6 +897,7 @@ class DivEngine {
audioEngine(DIV_AUDIO_NULL), audioEngine(DIV_AUDIO_NULL),
exportMode(DIV_EXPORT_MODE_ONE), exportMode(DIV_EXPORT_MODE_ONE),
midiBaseChan(0), midiBaseChan(0),
midiAgeCounter(0),
samp_bb(NULL), samp_bb(NULL),
samp_bbInLen(0), samp_bbInLen(0),
samp_temp(0), samp_temp(0),