OPL: complete the drum instrument type

#310
This commit is contained in:
tildearrow 2022-05-31 17:44:52 -05:00
parent 050a98d63d
commit 9d10b5bf2b
4 changed files with 163 additions and 54 deletions

View file

@ -987,6 +987,9 @@ DivInstrument* DivEngine::getIns(int index, DivInstrumentType fallbackType) {
case DIV_INS_OPL:
return &song.nullInsOPL;
break;
case DIV_INS_OPL_DRUMS:
return &song.nullInsOPLDrums;
break;
default:
break;
}
@ -1683,6 +1686,9 @@ int DivEngine::addInstrument(int refChan) {
case DIV_INS_OPL:
*ins=song.nullInsOPL;
break;
case DIV_INS_OPL_DRUMS:
*ins=song.nullInsOPLDrums;
break;
default:
break;
}

View file

@ -784,10 +784,23 @@ int DivPlatformOPL::dispatch(DivCommand c) {
}
break;
}
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPL);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,c.chan>melodicChans?DIV_INS_OPL_DRUMS:DIV_INS_OPL);
if (chan[c.chan].insChanged) {
chan[c.chan].state=ins->fm;
if (c.chan>melodicChans && ins->type==DIV_INS_OPL_DRUMS) {
for (int i=0; i<4; i++) {
chan[melodicChans+i+1].state.alg=ins->fm.alg;
chan[melodicChans+i+1].state.fb=ins->fm.fb;
chan[melodicChans+i+1].state.opllPreset=ins->fm.opllPreset;
chan[melodicChans+i+1].state.fixedDrums=ins->fm.fixedDrums;
chan[melodicChans+i+1].state.kickFreq=ins->fm.kickFreq;
chan[melodicChans+i+1].state.snareHatFreq=ins->fm.snareHatFreq;
chan[melodicChans+i+1].state.tomTopFreq=ins->fm.tomTopFreq;
chan[melodicChans+i+1].state.op[0]=ins->fm.op[i];
}
} else {
chan[c.chan].state=ins->fm;
}
}
chan[c.chan].macroInit(ins);
@ -795,49 +808,81 @@ int DivPlatformOPL::dispatch(DivCommand c) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].insChanged) {
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
chan[c.chan].fourOp=(ops==4);
if (chan[c.chan].fourOp) {
chan[c.chan+1].macroInit(NULL);
}
update4OpMask=true;
for (int i=0; i<ops; i++) {
unsigned char slot=slots[i][c.chan];
if (slot==255) continue;
unsigned short baseAddr=slotMap[slot];
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
if (c.chan>melodicChans && ins->type==DIV_INS_OPL_DRUMS) {
for (int i=0; i<4; i++) {
int ch=melodicChans+1+i;
unsigned char slot=slots[0][ch];
if (slot==255) continue;
unsigned short baseAddr=slotMap[slot];
DivInstrumentFM::Operator& op=chan[ch].state.op[0];
chan[ch].fourOp=false;
if (isMuted[c.chan]) {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else {
if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) {
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6));
if (isMuted[ch]) {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else {
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[ch].outVol&0x3f))/63))|(op.ksl<<6));
}
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
if (oplType>1) {
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
}
if (isMuted[ch]) {
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1));
} else {
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1)|((chan[ch].pan&3)<<4));
}
}
} else {
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
chan[c.chan].fourOp=(ops==4);
if (chan[c.chan].fourOp) {
chan[c.chan+1].macroInit(NULL);
}
update4OpMask=true;
for (int i=0; i<ops; i++) {
unsigned char slot=slots[i][c.chan];
if (slot==255) continue;
unsigned short baseAddr=slotMap[slot];
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
if (isMuted[c.chan]) {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else {
if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) {
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6));
} else {
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
}
}
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
if (oplType>1) {
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
}
}
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
if (oplType>1) {
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
}
}
if (isMuted[c.chan]) {
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1));
if (ops==4) {
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1));
}
} else {
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&3)<<4));
if (ops==4) {
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&3)<<4));
if (isMuted[c.chan]) {
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1));
if (ops==4) {
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1));
}
} else {
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&3)<<4));
if (ops==4) {
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&3)<<4));
}
}
}
}
@ -845,20 +890,32 @@ int DivPlatformOPL::dispatch(DivCommand c) {
chan[c.chan].insChanged=false;
if (c.value!=DIV_NOTE_NULL) {
if (c.chan>=melodicChans && chan[c.chan].state.opllPreset==16 && chan[c.chan].state.fixedDrums) { // drums
if (c.chan==melodicChans) {
chan[c.chan].fixedFreq=(chan[c.chan].state.kickFreq&1023)<<(chan[c.chan].state.kickFreq>>10);
} else if (c.chan==melodicChans+1 || c.chan==melodicChans+4) {
chan[c.chan].fixedFreq=(chan[c.chan].state.snareHatFreq&1023)<<(chan[c.chan].state.snareHatFreq>>10);
} else if (c.chan==melodicChans+2 || c.chan==melodicChans+3) {
chan[c.chan].fixedFreq=(chan[c.chan].state.tomTopFreq&1023)<<(chan[c.chan].state.tomTopFreq>>10);
if (c.chan>melodicChans && ins->type==DIV_INS_OPL_DRUMS && chan[c.chan].state.fixedDrums) {
chan[melodicChans+1].fixedFreq=(chan[melodicChans+1].state.snareHatFreq&1023)<<(chan[melodicChans+1].state.snareHatFreq>>10);
chan[melodicChans+2].fixedFreq=(chan[melodicChans+2].state.tomTopFreq&1023)<<(chan[melodicChans+2].state.tomTopFreq>>10);
chan[melodicChans+3].fixedFreq=chan[melodicChans+2].fixedFreq;
chan[melodicChans+4].fixedFreq=chan[melodicChans+1].fixedFreq;
chan[melodicChans+1].freqChanged=true;
chan[melodicChans+2].freqChanged=true;
chan[melodicChans+3].freqChanged=true;
chan[melodicChans+4].freqChanged=true;
} else {
if (c.chan>=melodicChans && (chan[c.chan].state.opllPreset==16 || ins->type==DIV_INS_OPL_DRUMS) && chan[c.chan].state.fixedDrums) { // drums
if (c.chan==melodicChans) {
chan[c.chan].fixedFreq=(chan[c.chan].state.kickFreq&1023)<<(chan[c.chan].state.kickFreq>>10);
} else if (c.chan==melodicChans+1 || c.chan==melodicChans+4) {
chan[c.chan].fixedFreq=(chan[c.chan].state.snareHatFreq&1023)<<(chan[c.chan].state.snareHatFreq>>10);
} else if (c.chan==melodicChans+2 || c.chan==melodicChans+3) {
chan[c.chan].fixedFreq=(chan[c.chan].state.tomTopFreq&1023)<<(chan[c.chan].state.tomTopFreq>>10);
} else {
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
chan[c.chan].fixedFreq=0;
}
} else {
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
chan[c.chan].fixedFreq=0;
}
} else {
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
chan[c.chan].fixedFreq=0;
}
chan[c.chan].note=c.value;
chan[c.chan].freqChanged=true;

View file

@ -510,6 +510,7 @@ struct DivSong {
system[1]=DIV_SYSTEM_SMS;
// OPLL default instrument contest winner - piano_guitar_idk by Weeppiko
nullInsOPLL.type=DIV_INS_OPLL;
nullInsOPLL.fm.opllPreset=0;
nullInsOPLL.fm.alg=0;
nullInsOPLL.fm.fb=7;
@ -539,6 +540,7 @@ struct DivSong {
nullInsOPLL.fm.op[1].ssgEnv=8;
nullInsOPLL.name="This is a bug! Report!";
nullInsOPL.type=DIV_INS_OPL;
nullInsOPL.fm.alg=0;
nullInsOPL.fm.fb=7;
nullInsOPL.fm.op[0].dr=2;
@ -551,9 +553,52 @@ struct DivSong {
nullInsOPL.fm.op[1].rr=12;
nullInsOPL.fm.op[1].mult=1;
nullInsOPL.name="This is a bug! Report!";
nullInsOPL.fm.kickFreq=0x520;
nullInsOPL.fm.snareHatFreq=0x550;
nullInsOPL.fm.tomTopFreq=0x1c0;
nullInsOPL.fm.kickFreq=(1<<10)|576;
nullInsOPL.fm.snareHatFreq=(1<<10)|672;
nullInsOPL.fm.tomTopFreq=896;
nullInsOPLDrums=nullInsOPL;
nullInsOPLDrums.type=DIV_INS_OPL_DRUMS;
nullInsOPLDrums.fm.fixedDrums=true;
for (int i=0; i<4; i++) {
nullInsOPLDrums.fm.op[i].am=0;
nullInsOPLDrums.fm.op[i].vib=0;
nullInsOPLDrums.fm.op[i].ksr=0;
nullInsOPLDrums.fm.op[i].sus=0;
nullInsOPLDrums.fm.op[i].ws=0;
nullInsOPLDrums.fm.op[i].ksl=0;
nullInsOPLDrums.fm.op[i].tl=0;
}
// snare
nullInsOPLDrums.fm.op[0].ar=13;
nullInsOPLDrums.fm.op[0].dr=8;
nullInsOPLDrums.fm.op[0].sl=4;
nullInsOPLDrums.fm.op[0].rr=8;
nullInsOPLDrums.fm.op[0].mult=1;
// tom
nullInsOPLDrums.fm.op[1].ar=15;
nullInsOPLDrums.fm.op[1].dr=8;
nullInsOPLDrums.fm.op[1].sl=5;
nullInsOPLDrums.fm.op[1].rr=9;
nullInsOPLDrums.fm.op[1].mult=5;
// top
nullInsOPLDrums.fm.op[2].ar=10;
nullInsOPLDrums.fm.op[2].dr=10;
nullInsOPLDrums.fm.op[2].sl=5;
nullInsOPLDrums.fm.op[2].rr=5;
nullInsOPLDrums.fm.op[2].mult=1;
nullInsOPLDrums.fm.op[2].ksr=1;
// hi-hat
nullInsOPLDrums.fm.op[3].ar=12;
nullInsOPLDrums.fm.op[3].dr=8;
nullInsOPLDrums.fm.op[3].sl=10;
nullInsOPLDrums.fm.op[3].rr=7;
nullInsOPLDrums.fm.op[3].mult=2;
nullInsQSound.std.panLMacro.mode=true;
}

View file

@ -2316,7 +2316,8 @@ void FurnaceGUI::drawInsEdit() {
}
for (int i=0; i<opCount; i++) {
if (ins->type==DIV_INS_OPL_DRUMS) {
snprintf(label,31,"%s Macros",oplDrumNames[i]);
if (i>0) break;
snprintf(label,31,"Operator Macros");
} else {
snprintf(label,31,"OP%d Macros",i+1);
}