diff --git a/src/engine/platform/fmshared_OPM.h b/src/engine/platform/fmshared_OPM.h new file mode 100644 index 000000000..8db58ed98 --- /dev/null +++ b/src/engine/platform/fmshared_OPM.h @@ -0,0 +1,9 @@ +#define ADDR_MULT_DT 0x40 +#define ADDR_TL 0x60 +#define ADDR_RS_AR 0x80 +#define ADDR_AM_DR 0xa0 +#define ADDR_DT2_D2R 0xc0 +#define ADDR_SL_RR 0xe0 +#define ADDR_NOTE 0x28 +#define ADDR_KF 0x30 +#define ADDR_LR_FB_ALG 0x20 \ No newline at end of file diff --git a/src/engine/platform/fmshared_OPN.h b/src/engine/platform/fmshared_OPN.h new file mode 100644 index 000000000..aa079b536 --- /dev/null +++ b/src/engine/platform/fmshared_OPN.h @@ -0,0 +1,16 @@ +#ifndef _FMSHARED_OPN_H +#define _FMSHARED_OPN_H + +#define ADDR_MULT_DT 0x30 +#define ADDR_TL 0x40 +#define ADDR_RS_AR 0x50 +#define ADDR_AM_DR 0x60 +#define ADDR_DT2_D2R 0x70 +#define ADDR_SL_RR 0x80 +#define ADDR_SSG 0x90 +#define ADDR_FREQ 0xa0 +#define ADDR_FREQH 0xa4 +#define ADDR_FB_ALG 0xb0 +#define ADDR_LRAF 0xb4 + +#endif \ No newline at end of file diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index e7f705ff2..82217988c 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -100,8 +100,8 @@ void DivPlatformGenesis::tick() { if (chan[i].freqChanged) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch); int freqt=toFreq(chan[i].freq); - immWrite(chanOffs[i]+0xa4,freqt>>8); - immWrite(chanOffs[i]+0xa0,freqt&0xff); + immWrite(chanOffs[i]+ADDR_FREQH,freqt>>8); + immWrite(chanOffs[i]+ADDR_FREQ,freqt&0xff); if (chan[i].furnaceDac) { dacRate=(1280000*1.25)/chan[i].baseFreq; } @@ -163,8 +163,7 @@ void DivPlatformGenesis::muteChannel(int ch, bool mute) { return; } isMuted[ch]=mute; - DivInstrument* ins=parent->getIns(chan[ch].ins); - rWrite(chanOffs[ch]+0xb4,(isMuted[ch]?0:(chan[ch].pan<<6))|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); + rWrite(chanOffs[ch]+ADDR_LRAF,(isMuted[ch]?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4)); } int DivPlatformGenesis::dispatch(DivCommand c) { @@ -209,32 +208,36 @@ int DivPlatformGenesis::dispatch(DivCommand c) { chan[c.chan].furnaceDac=false; } break; - } + } + + if (chan[c.chan].insChanged) { + chan[c.chan].state=ins->fm; + } for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; - DivInstrumentFM::Operator op=ins->fm.op[i]; - if (isOutput[ins->fm.alg][i]) { + DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; + if (isOutput[chan[c.chan].state.alg][i]) { if (!chan[c.chan].active || chan[c.chan].insChanged) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(chan[c.chan].vol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].vol&0x7f))/127)); } } else { if (chan[c.chan].insChanged) { - rWrite(baseAddr+0x40,op.tl); + rWrite(baseAddr+ADDR_TL,op.tl); } } if (chan[c.chan].insChanged) { - rWrite(baseAddr+0x30,(op.mult&15)|(dtTable[op.dt&7]<<4)); - rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); - rWrite(baseAddr+0x60,(op.dr&31)|(op.am<<7)); - rWrite(baseAddr+0x70,op.d2r&31); - rWrite(baseAddr+0x80,(op.rr&15)|(op.sl<<4)); - rWrite(baseAddr+0x90,op.ssgEnv&15); + rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); + rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); + rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); + rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); + rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); + rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } } if (chan[c.chan].insChanged) { - rWrite(chanOffs[c.chan]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); - rWrite(chanOffs[c.chan]+0xb4,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); + rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)); + rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4)); } chan[c.chan].insChanged=false; @@ -255,14 +258,13 @@ int DivPlatformGenesis::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: { chan[c.chan].vol=c.value; - DivInstrument* ins=parent->getIns(chan[c.chan].ins); for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; - DivInstrumentFM::Operator op=ins->fm.op[i]; - if (isOutput[ins->fm.alg][i]) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(chan[c.chan].vol&0x7f))/127)); + DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; + if (isOutput[chan[c.chan].state.alg][i]) { + rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].vol&0x7f))/127)); } else { - rWrite(baseAddr+0x40,op.tl); + rWrite(baseAddr+ADDR_TL,op.tl); } } break; @@ -289,8 +291,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { chan[c.chan].pan=3; break; } - DivInstrument* ins=parent->getIns(chan[c.chan].ins); - rWrite(chanOffs[c.chan]+0xb4,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); + rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4)); break; } case DIV_CMD_PITCH: { @@ -349,33 +350,35 @@ int DivPlatformGenesis::dispatch(DivCommand c) { } case DIV_CMD_FM_MULT: { unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; - DivInstrument* ins=parent->getIns(chan[c.chan].ins); - DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]]; - rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4)); + DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; + op.mult=c.value2&15; + rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); break; } case DIV_CMD_FM_TL: { unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; - DivInstrument* ins=parent->getIns(chan[c.chan].ins); - if (isOutput[ins->fm.alg][c.value]) { - rWrite(baseAddr+0x40,127-(((127-c.value2)*(chan[c.chan].vol&0x7f))/127)); + DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; + op.tl=c.value2; + if (isOutput[chan[c.chan].state.alg][c.value]) { + rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].vol&0x7f))/127)); } else { - rWrite(baseAddr+0x40,c.value2); + rWrite(baseAddr+ADDR_TL,op.tl); } break; } case DIV_CMD_FM_AR: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator op=ins->fm.op[i]; + DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; + op.ar=c.value2&31; unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; - rWrite(baseAddr+0x50,(c.value2&31)|(op.rs<<6)); + rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } } else { - DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; + op.ar=c.value2&31; unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; - rWrite(baseAddr+0x50,(c.value2&31)|(op.rs<<6)); + rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } break; diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 8f8caf4e3..1f929b9ef 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -9,6 +9,7 @@ class DivPlatformGenesis: public DivDispatch { protected: struct Channel { + DivInstrumentFM state; unsigned char freqH, freqL; int freq, baseFreq, pitch; unsigned char ins; diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index fb81d8f8d..63075247f 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -17,12 +17,20 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(opChan[ch].ins); + + if (opChan[ch].insChanged) { + chan[2].state.alg=ins->fm.alg; + chan[2].state.fb=ins->fm.fb; + chan[2].state.fb=ins->fm.fms; + chan[2].state.ams=ins->fm.ams; + chan[2].state.op[ordch]=ins->fm.op[ordch]; + } unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; - DivInstrumentFM::Operator op=ins->fm.op[ordch]; + DivInstrumentFM::Operator& op=chan[2].state.op[ordch]; if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); - } else if (isOutput[ins->fm.alg][ordch]) { + } else if (isOutput[chan[2].state.alg][ordch]) { if (!opChan[ch].active || opChan[ch].insChanged) { rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127)); } @@ -40,8 +48,8 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { rWrite(baseAddr+0x90,op.ssgEnv&15); } if (opChan[ch].insChanged) { // TODO how does this work? - rWrite(chanOffs[2]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); - rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); + rWrite(chanOffs[2]+0xb0,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); + rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); } opChan[ch].insChanged=false; @@ -59,9 +67,8 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: { opChan[ch].vol=c.value; - DivInstrument* ins=parent->getIns(opChan[ch].ins); unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; - DivInstrumentFM::Operator op=ins->fm.op[ordch]; + DivInstrumentFM::Operator& op=chan[2].state.op[ordch]; if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); } else { @@ -91,9 +98,8 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { opChan[ch].pan=3; break; } - DivInstrument* ins=parent->getIns(opChan[ch].ins); // TODO: ??? - rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); + rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); break; } case DIV_CMD_PITCH: { @@ -141,33 +147,35 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { } case DIV_CMD_FM_MULT: { // TODO unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; - DivInstrument* ins=parent->getIns(opChan[ch].ins); - DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]]; - rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4)); + DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + op.mult=c.value2&15; + rWrite(baseAddr+0x30,(op.mult&15)|(dtTable[op.dt&7]<<4)); break; } case DIV_CMD_FM_TL: { // TODO unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; - DivInstrument* ins=parent->getIns(opChan[ch].ins); - if (isOutput[ins->fm.alg][c.value]) { - rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127)); + DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + op.tl=c.value2; + if (isOutput[chan[2].state.alg][c.value]) { + rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127)); } else { - rWrite(baseAddr+0x40,c.value2); + rWrite(baseAddr+0x40,op.tl); } break; } case DIV_CMD_FM_AR: { - DivInstrument* ins=parent->getIns(opChan[ch].ins); if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator op=ins->fm.op[i]; + DivInstrumentFM::Operator& op=chan[2].state.op[i]; + op.ar=c.value2&31; unsigned short baseAddr=chanOffs[2]|opOffs[i]; - rWrite(baseAddr+0x50,(c.value2&31)|(op.rs<<6)); + rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); } } else { - DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + op.ar=c.value2&31; unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; - rWrite(baseAddr+0x50,(c.value2&31)|(op.rs<<6)); + rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); } break; } @@ -198,12 +206,11 @@ void DivPlatformGenesisExt::muteChannel(int ch, bool mute) { isOpMuted[ch-2]=mute; int ordch=orderedOps[ch-2]; - DivInstrument* ins=parent->getIns(opChan[ch].ins); unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; - DivInstrumentFM::Operator op=ins->fm.op[ordch]; + DivInstrumentFM::Operator op=chan[2].state.op[ordch]; if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); - } else if (isOutput[ins->fm.alg][ordch]) { + } else if (isOutput[chan[2].state.alg][ordch]) { rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127)); } else { rWrite(baseAddr+0x40,op.tl); diff --git a/src/engine/platform/genesisshared.h b/src/engine/platform/genesisshared.h index 957729cee..512387ee2 100644 --- a/src/engine/platform/genesisshared.h +++ b/src/engine/platform/genesisshared.h @@ -25,3 +25,5 @@ static int orderedOps[4]={ #define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} #define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} } + +#include "fmshared_OPN.h" \ No newline at end of file