From cac807551f2d66fc501348c430b1899a1f0c6412 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 19 Jan 2023 03:15:41 -0500 Subject: [PATCH] OPN/2/A/B: Seamless Legato Ins Change (ExtCh) --- src/engine/platform/genesisext.cpp | 79 +++++++++++++++++------------- src/engine/platform/genesisext.h | 1 + src/engine/platform/ym2203ext.cpp | 73 +++++++++++++++------------ src/engine/platform/ym2203ext.h | 1 + src/engine/platform/ym2608ext.cpp | 79 +++++++++++++++++------------- src/engine/platform/ym2608ext.h | 1 + src/engine/platform/ym2610bext.cpp | 79 +++++++++++++++++------------- src/engine/platform/ym2610bext.h | 1 + src/engine/platform/ym2610ext.cpp | 79 +++++++++++++++++------------- src/engine/platform/ym2610ext.h | 1 + 10 files changed, 227 insertions(+), 167 deletions(-) diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 4aa410af..1b9c7d86 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -26,6 +26,44 @@ #define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6]))) +void DivPlatformGenesisExt::commitStateExt(int ch, DivInstrument* ins) { + int ordch=orderedOps[ch]; + + if (opChan[ch].insChanged) { + chan[2].state.alg=ins->fm.alg; + if (ch==0 || fbAllOps) { + chan[2].state.fb=ins->fm.fb; + } + chan[2].state.fms=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=chan[2].state.op[ordch]; + // TODO: how does this work?! + if (isOpMuted[ch]) { + rWrite(baseAddr+0x40,127); + } else { + if (opChan[ch].insChanged) { + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); + } + } + if (opChan[ch].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); + opChan[ch].mask=op.enable; + } + if (opChan[ch].insChanged) { // TODO how does this work? + rWrite(chanOffs[2]+0xb0,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); + rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); + } +} + int DivPlatformGenesisExt::dispatch(DivCommand c) { if (c.chan<2) { return DivPlatformGenesis::dispatch(c); @@ -44,16 +82,6 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); - if (opChan[ch].insChanged) { - chan[2].state.alg=ins->fm.alg; - if (ch==0 || fbAllOps) { - chan[2].state.fb=ins->fm.fb; - } - chan[2].state.fms=ins->fm.fms; - chan[2].state.ams=ins->fm.ams; - chan[2].state.op[ordch]=ins->fm.op[ordch]; - } - if (noExtMacros) { opChan[ch].macroInit(NULL); } else { @@ -62,30 +90,8 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { if (!opChan[ch].std.vol.will) { opChan[ch].outVol=opChan[ch].vol; } - - unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; - DivInstrumentFM::Operator& op=chan[2].state.op[ordch]; - // TODO: how does this work?! - if (isOpMuted[ch]) { - rWrite(baseAddr+0x40,127); - } else { - if (opChan[ch].insChanged) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); - } - } - if (opChan[ch].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); - opChan[ch].mask=op.enable; - } - if (opChan[ch].insChanged) { // TODO how does this work? - rWrite(chanOffs[2]+0xb0,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); - rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); - } + + commitStateExt(ch,ins); opChan[ch].insChanged=false; if (c.value!=DIV_NOTE_NULL) { @@ -202,6 +208,11 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { } break; case DIV_CMD_LEGATO: { + if (opChan[ch].insChanged) { + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); + commitStateExt(ch,ins); + opChan[ch].insChanged=false; + } opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].freqChanged=true; break; diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index 67955adc..e04faf23 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -29,6 +29,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { bool isOpMuted[4]; friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); + inline void commitStateExt(int ch, DivInstrument* ins); public: int dispatch(DivCommand c); void* getChanState(int chan); diff --git a/src/engine/platform/ym2203ext.cpp b/src/engine/platform/ym2203ext.cpp index 99d53357..87a887fc 100644 --- a/src/engine/platform/ym2203ext.cpp +++ b/src/engine/platform/ym2203ext.cpp @@ -24,6 +24,41 @@ #define CHIP_FREQBASE fmFreqBase #define CHIP_DIVIDER fmDivBase +void DivPlatformYM2203Ext::commitStateExt(int ch, DivInstrument* ins) { + int ordch=orderedOps[ch]; + + if (opChan[ch].insChanged) { + chan[2].state.alg=ins->fm.alg; + if (ch==0 || fbAllOps) { + chan[2].state.fb=ins->fm.fb; + } + chan[2].state.op[ordch]=ins->fm.op[ordch]; + } + + unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; + DivInstrumentFM::Operator& op=chan[2].state.op[ordch]; + // TODO: how does this work?! + if (isOpMuted[ch]) { + rWrite(baseAddr+0x40,127); + } else { + if (opChan[ch].insChanged) { + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); + } + } + if (opChan[ch].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); + opChan[ch].mask=op.enable; + } + if (opChan[ch].insChanged) { // TODO how does this work? + rWrite(chanOffs[2]+0xb0,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); + } +} + int DivPlatformYM2203Ext::dispatch(DivCommand c) { if (c.chan<2) { return DivPlatformYM2203::dispatch(c); @@ -42,14 +77,6 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); - if (opChan[ch].insChanged) { - chan[2].state.alg=ins->fm.alg; - if (ch==0 || fbAllOps) { - chan[2].state.fb=ins->fm.fb; - } - chan[2].state.op[ordch]=ins->fm.op[ordch]; - } - if (noExtMacros) { opChan[ch].macroInit(NULL); } else { @@ -58,29 +85,8 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) { if (!opChan[ch].std.vol.will) { opChan[ch].outVol=opChan[ch].vol; } - - unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; - DivInstrumentFM::Operator& op=chan[2].state.op[ordch]; - // TODO: how does this work?! - if (isOpMuted[ch]) { - rWrite(baseAddr+0x40,127); - } else { - if (opChan[ch].insChanged) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); - } - } - if (opChan[ch].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); - opChan[ch].mask=op.enable; - } - if (opChan[ch].insChanged) { // TODO how does this work? - rWrite(chanOffs[2]+0xb0,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); - } + + commitStateExt(ch,ins); opChan[ch].insChanged=false; if (c.value!=DIV_NOTE_NULL) { @@ -166,6 +172,11 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: { + if (opChan[ch].insChanged) { + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); + commitStateExt(ch,ins); + opChan[ch].insChanged=false; + } opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].freqChanged=true; break; diff --git a/src/engine/platform/ym2203ext.h b/src/engine/platform/ym2203ext.h index 6d8bb0ba..79d92043 100644 --- a/src/engine/platform/ym2203ext.h +++ b/src/engine/platform/ym2203ext.h @@ -28,6 +28,7 @@ class DivPlatformYM2203Ext: public DivPlatformYM2203 { OPNOpChannel opChan[4]; bool isOpMuted[4]; friend void putDispatchChip(void*,int); + inline void commitStateExt(int ch, DivInstrument* ins); public: int dispatch(DivCommand c); void* getChanState(int chan); diff --git a/src/engine/platform/ym2608ext.cpp b/src/engine/platform/ym2608ext.cpp index e8e35cdc..2247b775 100644 --- a/src/engine/platform/ym2608ext.cpp +++ b/src/engine/platform/ym2608ext.cpp @@ -24,6 +24,44 @@ #define CHIP_FREQBASE fmFreqBase #define CHIP_DIVIDER fmDivBase +void DivPlatformYM2608Ext::commitStateExt(int ch, DivInstrument* ins) { + int ordch=orderedOps[ch]; + + if (opChan[ch].insChanged) { + chan[2].state.alg=ins->fm.alg; + if (ch==0 || fbAllOps) { + chan[2].state.fb=ins->fm.fb; + } + chan[2].state.fms=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=chan[2].state.op[ordch]; + // TODO: how does this work?! + if (isOpMuted[ch]) { + rWrite(baseAddr+0x40,127); + } else { + if (opChan[ch].insChanged) { + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); + } + } + if (opChan[ch].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); + opChan[ch].mask=op.enable; + } + if (opChan[ch].insChanged) { // TODO how does this work? + rWrite(chanOffs[2]+0xb0,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); + rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); + } +} + int DivPlatformYM2608Ext::dispatch(DivCommand c) { if (c.chan<2) { return DivPlatformYM2608::dispatch(c); @@ -42,16 +80,6 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); - if (opChan[ch].insChanged) { - chan[2].state.alg=ins->fm.alg; - if (ch==0 || fbAllOps) { - chan[2].state.fb=ins->fm.fb; - } - chan[2].state.fms=ins->fm.fms; - chan[2].state.ams=ins->fm.ams; - chan[2].state.op[ordch]=ins->fm.op[ordch]; - } - if (noExtMacros) { opChan[ch].macroInit(NULL); } else { @@ -60,30 +88,8 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) { if (!opChan[ch].std.vol.will) { opChan[ch].outVol=opChan[ch].vol; } - - unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; - DivInstrumentFM::Operator& op=chan[2].state.op[ordch]; - // TODO: how does this work?! - if (isOpMuted[ch]) { - rWrite(baseAddr+0x40,127); - } else { - if (opChan[ch].insChanged) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); - } - } - if (opChan[ch].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); - opChan[ch].mask=op.enable; - } - if (opChan[ch].insChanged) { // TODO how does this work? - rWrite(chanOffs[2]+0xb0,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); - rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); - } + + commitStateExt(ch,ins); opChan[ch].insChanged=false; if (c.value!=DIV_NOTE_NULL) { @@ -184,6 +190,11 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: { + if (opChan[ch].insChanged) { + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); + commitStateExt(ch,ins); + opChan[ch].insChanged=false; + } opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].freqChanged=true; break; diff --git a/src/engine/platform/ym2608ext.h b/src/engine/platform/ym2608ext.h index e99518fb..160d855c 100644 --- a/src/engine/platform/ym2608ext.h +++ b/src/engine/platform/ym2608ext.h @@ -28,6 +28,7 @@ class DivPlatformYM2608Ext: public DivPlatformYM2608 { OPNOpChannelStereo opChan[4]; bool isOpMuted[4]; friend void putDispatchChip(void*,int); + inline void commitStateExt(int ch, DivInstrument* ins); public: int dispatch(DivCommand c); void* getChanState(int chan); diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index 28563b20..8462e557 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -20,6 +20,44 @@ #include "ym2610bext.h" #include +void DivPlatformYM2610BExt::commitStateExt(int ch, DivInstrument* ins) { + int ordch=orderedOps[ch]; + + if (opChan[ch].insChanged) { + chan[extChanOffs].state.alg=ins->fm.alg; + if (ch==0 || fbAllOps) { + chan[extChanOffs].state.fb=ins->fm.fb; + } + chan[extChanOffs].state.fms=ins->fm.fms; + chan[extChanOffs].state.ams=ins->fm.ams; + chan[extChanOffs].state.op[ordch]=ins->fm.op[ordch]; + } + + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[ordch]; + // TODO: how does this work?! + if (isOpMuted[ch]) { + rWrite(baseAddr+0x40,127); + } else { + if (opChan[ch].insChanged) { + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); + } + } + if (opChan[ch].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); + opChan[ch].mask=op.enable; + } + if (opChan[ch].insChanged) { // TODO how does this work? + rWrite(chanOffs[extChanOffs]+0xb0,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3)); + rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4)); + } +} + int DivPlatformYM2610BExt::dispatch(DivCommand c) { if (c.changetIns(opChan[ch].ins,DIV_INS_FM); - if (opChan[ch].insChanged) { - chan[extChanOffs].state.alg=ins->fm.alg; - if (ch==0 || fbAllOps) { - chan[extChanOffs].state.fb=ins->fm.fb; - } - chan[extChanOffs].state.fms=ins->fm.fms; - chan[extChanOffs].state.ams=ins->fm.ams; - chan[extChanOffs].state.op[ordch]=ins->fm.op[ordch]; - } - if (noExtMacros) { opChan[ch].macroInit(NULL); } else { @@ -56,30 +84,8 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { if (!opChan[ch].std.vol.will) { opChan[ch].outVol=opChan[ch].vol; } - - unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; - DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[ordch]; - // TODO: how does this work?! - if (isOpMuted[ch]) { - rWrite(baseAddr+0x40,127); - } else { - if (opChan[ch].insChanged) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); - } - } - if (opChan[ch].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); - opChan[ch].mask=op.enable; - } - if (opChan[ch].insChanged) { // TODO how does this work? - rWrite(chanOffs[extChanOffs]+0xb0,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3)); - rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4)); - } + + commitStateExt(ch,ins); opChan[ch].insChanged=false; if (c.value!=DIV_NOTE_NULL) { @@ -180,6 +186,11 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: { + if (opChan[ch].insChanged) { + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); + commitStateExt(ch,ins); + opChan[ch].insChanged=false; + } opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].freqChanged=true; break; diff --git a/src/engine/platform/ym2610bext.h b/src/engine/platform/ym2610bext.h index 50bd5bad..fcec3bd7 100644 --- a/src/engine/platform/ym2610bext.h +++ b/src/engine/platform/ym2610bext.h @@ -28,6 +28,7 @@ class DivPlatformYM2610BExt: public DivPlatformYM2610B { OPNOpChannelStereo opChan[4]; bool isOpMuted[4]; friend void putDispatchChip(void*,int); + inline void commitStateExt(int ch, DivInstrument* ins); public: int dispatch(DivCommand c); void* getChanState(int chan); diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index 03442dc5..dcf5b099 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -20,6 +20,44 @@ #include "ym2610ext.h" #include +void DivPlatformYM2610Ext::commitStateExt(int ch, DivInstrument* ins) { + int ordch=orderedOps[ch]; + + if (opChan[ch].insChanged) { + chan[extChanOffs].state.alg=ins->fm.alg; + if (ch==0 || fbAllOps) { + chan[extChanOffs].state.fb=ins->fm.fb; + } + chan[extChanOffs].state.fms=ins->fm.fms; + chan[extChanOffs].state.ams=ins->fm.ams; + chan[extChanOffs].state.op[ordch]=ins->fm.op[ordch]; + } + + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[ordch]; + // TODO: how does this work?! + if (isOpMuted[ch]) { + rWrite(baseAddr+0x40,127); + } else { + if (opChan[ch].insChanged) { + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); + } + } + if (opChan[ch].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); + opChan[ch].mask=op.enable; + } + if (opChan[ch].insChanged) { // TODO how does this work? + rWrite(chanOffs[extChanOffs]+0xb0,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3)); + rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4)); + } +} + int DivPlatformYM2610Ext::dispatch(DivCommand c) { if (c.changetIns(opChan[ch].ins,DIV_INS_FM); - if (opChan[ch].insChanged) { - chan[extChanOffs].state.alg=ins->fm.alg; - if (ch==0 || fbAllOps) { - chan[extChanOffs].state.fb=ins->fm.fb; - } - chan[extChanOffs].state.fms=ins->fm.fms; - chan[extChanOffs].state.ams=ins->fm.ams; - chan[extChanOffs].state.op[ordch]=ins->fm.op[ordch]; - } - if (noExtMacros) { opChan[ch].macroInit(NULL); } else { @@ -56,30 +84,8 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { if (!opChan[ch].std.vol.will) { opChan[ch].outVol=opChan[ch].vol; } - - unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; - DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[ordch]; - // TODO: how does this work?! - if (isOpMuted[ch]) { - rWrite(baseAddr+0x40,127); - } else { - if (opChan[ch].insChanged) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); - } - } - if (opChan[ch].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); - opChan[ch].mask=op.enable; - } - if (opChan[ch].insChanged) { // TODO how does this work? - rWrite(chanOffs[extChanOffs]+0xb0,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3)); - rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4)); - } + + commitStateExt(ch,ins); opChan[ch].insChanged=false; if (c.value!=DIV_NOTE_NULL) { @@ -180,6 +186,11 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: { + if (opChan[ch].insChanged) { + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); + commitStateExt(ch,ins); + opChan[ch].insChanged=false; + } opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].freqChanged=true; break; diff --git a/src/engine/platform/ym2610ext.h b/src/engine/platform/ym2610ext.h index e4103338..0cf0bf11 100644 --- a/src/engine/platform/ym2610ext.h +++ b/src/engine/platform/ym2610ext.h @@ -28,6 +28,7 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 { OPNOpChannelStereo opChan[4]; bool isOpMuted[4]; friend void putDispatchChip(void*,int); + inline void commitStateExt(int ch, DivInstrument* ins); public: int dispatch(DivCommand c); void* getChanState(int chan);