diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 855c56e1..014f2a40 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -689,6 +689,112 @@ void DivPlatformOPL::muteChannel(int ch, bool mute) { } } +void DivPlatformOPL::commitState(int ch, DivInstrument* ins) { + if (chan[ch].insChanged) { + if (ch>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[ch].state=ins->fm; + } + } + + if (chan[ch].insChanged) { + if (ch>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[ch]) { + rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); + } else { + rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG_BROKEN(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&15)<<4)); + } + } + } else { + int ops=(slots[3][ch]!=255 && chan[ch].state.ops==4 && oplType==3)?4:2; + chan[ch].fourOp=(ops==4); + if (chan[ch].fourOp) { + /* + if (chan[ch+1].active) { + chan[ch+1].keyOff=true; + chan[ch+1].keyOn=false; + chan[ch+1].active=false; + }*/ + chan[ch+1].insChanged=true; + chan[ch+1].macroInit(NULL); + } + update4OpMask=true; + for (int i=0; imelodicChans) { + rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG_BROKEN(63-op.tl,chan[ch].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)); + } + } + + 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)); + if (ops==4) { + oldWrites[chanMap[ch+1]+ADDR_LR_FB_ALG]=-1; + rWrite(chanMap[ch+1]+ADDR_LR_FB_ALG,((chan[ch].state.alg>>1)&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&15)<<4)); + if (ops==4) { + oldWrites[chanMap[ch+1]+ADDR_LR_FB_ALG]=-1; + rWrite(chanMap[ch+1]+ADDR_LR_FB_ALG,((chan[ch].state.alg>>1)&1)|(chan[ch].state.fb<<1)|((chan[ch].pan&15)<<4)); + } + } + } + } +} + int DivPlatformOPL::dispatch(DivCommand c) { if (c.chan>=totalChans && c.chan!=adpcmChan) return 0; // ineffective in 4-op mode @@ -771,114 +877,12 @@ int DivPlatformOPL::dispatch(DivCommand c) { } DivInstrument* ins=parent->getIns(chan[c.chan].ins,c.chan>melodicChans?DIV_INS_OPL_DRUMS:DIV_INS_OPL); - if (chan[c.chan].insChanged) { - 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); if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } - if (chan[c.chan].insChanged) { - 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[ch]) { - rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); - } else { - rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG_BROKEN(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&15)<<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) { - /* - if (chan[c.chan+1].active) { - chan[c.chan+1].keyOff=true; - chan[c.chan+1].keyOn=false; - chan[c.chan+1].active=false; - }*/ - chan[c.chan+1].insChanged=true; - chan[c.chan+1].macroInit(NULL); - } - update4OpMask=true; - for (int i=0; imelodicChans) { - rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG_BROKEN(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)); - } - } - - 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&15)<<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&15)<<4)); - } - } - } - } - + commitState(c.chan,ins); chan[c.chan].insChanged=false; if (c.value!=DIV_NOTE_NULL) { @@ -1075,6 +1079,11 @@ int DivPlatformOPL::dispatch(DivCommand c) { iface.sampleBank=sampleBank; break; case DIV_CMD_LEGATO: { + if (chan[c.chan].insChanged) { + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); + commitState(c.chan,ins); + chan[c.chan].insChanged=false; + } chan[c.chan].baseFreq=(c.chan==adpcmChan)?(NOTE_ADPCMB(c.value)):(NOTE_FREQUENCY(c.value)); chan[c.chan].note=c.value; chan[c.chan].freqChanged=true; diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index 5e6b5316..b5285701 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -100,6 +100,7 @@ class DivPlatformOPL: public DivDispatch { int octave(int freq); int toFreq(int freq); double NOTE_ADPCMB(int note); + void commitState(int ch, DivInstrument* ins); friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index 68cb58b0..a1011f60 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -19,6 +19,7 @@ #include "opll.h" #include "../engine.h" +#include "../../ta-log.h" #include #include @@ -331,6 +332,55 @@ void DivPlatformOPLL::muteChannel(int ch, bool mute) { isMuted[ch]=mute; } +void DivPlatformOPLL::commitState(int ch, DivInstrument* ins) { + if (chan[ch].insChanged) { + chan[ch].state=ins->fm; + } + + if (chan[ch].insChanged) { + // update custom preset + if (chan[ch].state.opllPreset==0) { + DivInstrumentFM::Operator& mod=chan[ch].state.op[0]; + DivInstrumentFM::Operator& car=chan[ch].state.op[1]; + rWrite(0x00,(mod.am<<7)|(mod.vib<<6)|((mod.ssgEnv&8)<<2)|(mod.ksr<<4)|(mod.mult)); + rWrite(0x01,(car.am<<7)|(car.vib<<6)|((car.ssgEnv&8)<<2)|(car.ksr<<4)|(car.mult)); + rWrite(0x02,(mod.ksl<<6)|(mod.tl&63)); + rWrite(0x03,(car.ksl<<6)|((chan[ch].state.fms&1)<<4)|((chan[ch].state.ams&1)<<3)|chan[ch].state.fb); + rWrite(0x04,(mod.ar<<4)|(mod.dr)); + rWrite(0x05,(car.ar<<4)|(car.dr)); + rWrite(0x06,(mod.sl<<4)|(mod.rr)); + rWrite(0x07,(car.sl<<4)|(car.rr)); + lastCustomMemory=ch; + } + if (chan[ch].state.opllPreset==16) { // compatible drums mode + if (ch>=6) { + drums=true; + immWrite(0x16,0x20); + immWrite(0x26,0x05); + immWrite(0x16,0x20); + immWrite(0x26,0x05); + immWrite(0x17,0x50); + immWrite(0x27,0x05); + immWrite(0x17,0x50); + immWrite(0x27,0x05); + immWrite(0x18,0xC0); + immWrite(0x28,0x01); + } + } else { + if (ch>=6) { + if (drums) { + drums=false; + immWrite(0x0e,0); + drumState=0; + } + } + if (ch<9) { + rWrite(0x30+ch,((15-VOL_SCALE_LOG_BROKEN(chan[ch].outVol,15-chan[ch].state.op[1].tl,15))&15)|(chan[ch].state.opllPreset<<4)); + } + } + } +} + int DivPlatformOPLL::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { @@ -375,49 +425,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) { break; } - if (chan[c.chan].insChanged) { - // update custom preset - if (chan[c.chan].state.opllPreset==0) { - DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0]; - DivInstrumentFM::Operator& car=chan[c.chan].state.op[1]; - rWrite(0x00,(mod.am<<7)|(mod.vib<<6)|((mod.ssgEnv&8)<<2)|(mod.ksr<<4)|(mod.mult)); - rWrite(0x01,(car.am<<7)|(car.vib<<6)|((car.ssgEnv&8)<<2)|(car.ksr<<4)|(car.mult)); - rWrite(0x02,(mod.ksl<<6)|(mod.tl&63)); - rWrite(0x03,(car.ksl<<6)|((chan[c.chan].state.fms&1)<<4)|((chan[c.chan].state.ams&1)<<3)|chan[c.chan].state.fb); - rWrite(0x04,(mod.ar<<4)|(mod.dr)); - rWrite(0x05,(car.ar<<4)|(car.dr)); - rWrite(0x06,(mod.sl<<4)|(mod.rr)); - rWrite(0x07,(car.sl<<4)|(car.rr)); - lastCustomMemory=c.chan; - } - if (chan[c.chan].state.opllPreset==16) { // compatible drums mode - if (c.chan>=6) { - drums=true; - immWrite(0x16,0x20); - immWrite(0x26,0x05); - immWrite(0x16,0x20); - immWrite(0x26,0x05); - immWrite(0x17,0x50); - immWrite(0x27,0x05); - immWrite(0x17,0x50); - immWrite(0x27,0x05); - immWrite(0x18,0xC0); - immWrite(0x28,0x01); - } - } else { - if (c.chan>=6) { - if (drums) { - drums=false; - immWrite(0x0e,0); - drumState=0; - } - } - if (c.chan<9) { - rWrite(0x30+c.chan,((15-VOL_SCALE_LOG_BROKEN(chan[c.chan].outVol,15-chan[c.chan].state.op[1].tl,15))&15)|(chan[c.chan].state.opllPreset<<4)); - } - } - } - + commitState(c.chan,ins); chan[c.chan].insChanged=false; if (c.value!=DIV_NOTE_NULL) { @@ -541,6 +549,13 @@ int DivPlatformOPLL::dispatch(DivCommand c) { } case DIV_CMD_LEGATO: { if (c.chan>=9 && !properDrums) return 0; + if (c.chan<6 || (!drums && !properDrums)) { + if (chan[c.chan].insChanged) { + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPLL); + commitState(c.chan,ins); + chan[c.chan].insChanged=false; + } + } chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].note=c.value; chan[c.chan].freqChanged=true; diff --git a/src/engine/platform/opll.h b/src/engine/platform/opll.h index d36c119e..258113c4 100644 --- a/src/engine/platform/opll.h +++ b/src/engine/platform/opll.h @@ -73,6 +73,7 @@ class DivPlatformOPLL: public DivDispatch { int octave(int freq); int toFreq(int freq); + void commitState(int ch, DivInstrument* ins); friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int);