From 1b05fe577ddfef89c0676b549246df2a18a7b6b7 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 19 Jan 2023 02:23:05 -0500 Subject: [PATCH] OPN/2/A/B: Seamless Legato Ins Change --- src/engine/platform/genesis.cpp | 87 ++++++++++++++++++--------------- src/engine/platform/genesis.h | 1 + src/engine/platform/ym2203.cpp | 83 +++++++++++++++++-------------- src/engine/platform/ym2203.h | 2 + src/engine/platform/ym2608.cpp | 79 +++++++++++++++++------------- src/engine/platform/ym2608.h | 2 + src/engine/platform/ym2610.cpp | 79 +++++++++++++++++------------- src/engine/platform/ym2610.h | 2 + src/engine/platform/ym2610b.cpp | 79 +++++++++++++++++------------- src/engine/platform/ym2610b.h | 2 + 10 files changed, 238 insertions(+), 178 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index c344e8ae1..5cbed89ed 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -569,6 +569,47 @@ void DivPlatformGenesis::muteChannel(int ch, bool mute) { rWrite(chanOffs[ch]+ADDR_LRAF,(IS_REALLY_MUTED(ch)?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4)); } +void DivPlatformGenesis::commitState(int ch, DivInstrument* ins) { + if (chan[ch].insChanged) { + chan[ch].state=ins->fm; + chan[ch].opMask= + (chan[ch].state.op[0].enable?1:0)| + (chan[ch].state.op[2].enable?2:0)| + (chan[ch].state.op[1].enable?4:0)| + (chan[ch].state.op[3].enable?8:0); + } + + for (int i=0; i<4; i++) { + unsigned short baseAddr=chanOffs[ch]|opOffs[i]; + DivInstrumentFM::Operator& op=chan[ch].state.op[i]; + if (isMuted[ch]) { + rWrite(baseAddr+ADDR_TL,127); + } else { + if (KVS(ch,i)) { + if (!chan[ch].active || chan[ch].insChanged) { + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[ch].outVol&0x7f,127)); + } + } else { + if (chan[ch].insChanged) { + rWrite(baseAddr+ADDR_TL,op.tl); + } + } + } + if (chan[ch].insChanged) { + 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[ch].insChanged) { + rWrite(chanOffs[ch]+ADDR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3)); + rWrite(chanOffs[ch]+ADDR_LRAF,(IS_REALLY_MUTED(ch)?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4)); + } +} + int DivPlatformGenesis::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { @@ -651,49 +692,12 @@ int DivPlatformGenesis::dispatch(DivCommand c) { } if (c.chan>=6) break; - if (chan[c.chan].insChanged) { - chan[c.chan].state=ins->fm; - chan[c.chan].opMask= - (chan[c.chan].state.op[0].enable?1:0)| - (chan[c.chan].state.op[2].enable?2:0)| - (chan[c.chan].state.op[1].enable?4:0)| - (chan[c.chan].state.op[3].enable?8:0); - } - chan[c.chan].macroInit(ins); if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } - - for (int i=0; i<4; i++) { - unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; - DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isMuted[c.chan]) { - rWrite(baseAddr+ADDR_TL,127); - } else { - if (KVS(c.chan,i)) { - if (!chan[c.chan].active || chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[c.chan].outVol&0x7f,127)); - } - } else { - if (chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,op.tl); - } - } - } - if (chan[c.chan].insChanged) { - 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]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)); - rWrite(chanOffs[c.chan]+ADDR_LRAF,(IS_REALLY_MUTED(c.chan)?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4)); - } + + commitState(c.chan,ins); chan[c.chan].insChanged=false; if (c.value!=DIV_NOTE_NULL) { @@ -876,6 +880,11 @@ int DivPlatformGenesis::dispatch(DivCommand c) { } else if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) { chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false); } else { + 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=NOTE_FNUM_BLOCK(c.value,11); } chan[c.chan].note=c.value; diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index f3032cf9e..c420ac5d7 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -92,6 +92,7 @@ class DivPlatformGenesis: public DivPlatformOPN { friend void putDispatchChan(void*,int,int); inline void processDAC(int iRate); + inline void commitState(int ch, DivInstrument* ins); void acquire_nuked(short** buf, size_t len); void acquire_ymfm(short** buf, size_t len); diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index b76a5adbd..c2a547d8c 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -474,6 +474,46 @@ void DivPlatformYM2203::tick(bool sysTick) { } } +void DivPlatformYM2203::commitState(int ch, DivInstrument* ins) { + if (chan[ch].insChanged) { + chan[ch].state=ins->fm; + chan[ch].opMask= + (chan[ch].state.op[0].enable?1:0)| + (chan[ch].state.op[2].enable?2:0)| + (chan[ch].state.op[1].enable?4:0)| + (chan[ch].state.op[3].enable?8:0); + } + + for (int i=0; i<4; i++) { + unsigned short baseAddr=chanOffs[ch]|opOffs[i]; + DivInstrumentFM::Operator& op=chan[ch].state.op[i]; + if (isMuted[ch]) { + rWrite(baseAddr+ADDR_TL,127); + } else { + if (KVS(ch,i)) { + if (!chan[ch].active || chan[ch].insChanged) { + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[ch].outVol&0x7f,127)); + } + } else { + if (chan[ch].insChanged) { + rWrite(baseAddr+ADDR_TL,op.tl); + } + } + } + if (chan[ch].insChanged) { + 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[ch].insChanged) { + rWrite(chanOffs[ch]+ADDR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3)); + } +} + int DivPlatformYM2203::dispatch(DivCommand c) { if (c.chan>2) { c.chan-=3; @@ -489,43 +529,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) { } } - if (chan[c.chan].insChanged) { - chan[c.chan].state=ins->fm; - chan[c.chan].opMask= - (chan[c.chan].state.op[0].enable?1:0)| - (chan[c.chan].state.op[2].enable?2:0)| - (chan[c.chan].state.op[1].enable?4:0)| - (chan[c.chan].state.op[3].enable?8:0); - } - - for (int i=0; i<4; i++) { - unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; - DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isMuted[c.chan]) { - rWrite(baseAddr+ADDR_TL,127); - } else { - if (KVS(c.chan,i)) { - if (!chan[c.chan].active || chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[c.chan].outVol&0x7f,127)); - } - } else { - if (chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,op.tl); - } - } - } - if (chan[c.chan].insChanged) { - 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]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)); - } + commitState(c.chan,ins); chan[c.chan].insChanged=false; if (c.value!=DIV_NOTE_NULL) { @@ -616,6 +620,11 @@ int DivPlatformYM2203::dispatch(DivCommand c) { 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=NOTE_FNUM_BLOCK(c.value,11); chan[c.chan].freqChanged=true; break; diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index 8b8c0d6be..503f470b9 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -55,6 +55,8 @@ class DivPlatformYM2203: public DivPlatformOPN { friend void putDispatchChip(void*,int); + inline void commitState(int ch, DivInstrument* ins); + void acquire_combo(short** buf, size_t len); void acquire_ymfm(short** buf, size_t len); diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 08969eea6..063b3870b 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -789,6 +789,43 @@ void DivPlatformYM2608::tick(bool sysTick) { ay->getRegisterWrites().clear(); } +void DivPlatformYM2608::commitState(int ch, DivInstrument* ins) { + if (chan[ch].insChanged) { + chan[ch].state=ins->fm; + chan[ch].opMask= + (chan[ch].state.op[0].enable?1:0)| + (chan[ch].state.op[2].enable?2:0)| + (chan[ch].state.op[1].enable?4:0)| + (chan[ch].state.op[3].enable?8:0); + } + + for (int i=0; i<4; i++) { + unsigned short baseAddr=chanOffs[ch]|opOffs[i]; + DivInstrumentFM::Operator& op=chan[ch].state.op[i]; + if (KVS(ch,i)) { + if (!chan[ch].active || chan[ch].insChanged) { + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[ch].outVol&0x7f,127)); + } + } else { + if (chan[ch].insChanged) { + rWrite(baseAddr+ADDR_TL,op.tl); + } + } + if (chan[ch].insChanged) { + 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[ch].insChanged) { + rWrite(chanOffs[ch]+ADDR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3)); + rWrite(chanOffs[ch]+ADDR_LRAF,(isMuted[ch]?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4)); + } +} + int DivPlatformYM2608::dispatch(DivCommand c) { if (c.chan>5 && c.chan<9) { c.chan-=6; @@ -902,40 +939,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { } } - if (chan[c.chan].insChanged) { - chan[c.chan].state=ins->fm; - chan[c.chan].opMask= - (chan[c.chan].state.op[0].enable?1:0)| - (chan[c.chan].state.op[2].enable?2:0)| - (chan[c.chan].state.op[1].enable?4:0)| - (chan[c.chan].state.op[3].enable?8:0); - } - - for (int i=0; i<4; i++) { - unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; - DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (KVS(c.chan,i)) { - if (!chan[c.chan].active || chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[c.chan].outVol&0x7f,127)); - } - } else { - if (chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,op.tl); - } - } - if (chan[c.chan].insChanged) { - 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]+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)); - } + commitState(c.chan,ins); chan[c.chan].insChanged=false; if (c.value!=DIV_NOTE_NULL) { @@ -1063,6 +1067,13 @@ int DivPlatformYM2608::dispatch(DivCommand c) { break; case DIV_CMD_LEGATO: { if (c.chan==15 && !chan[c.chan].furnacePCM) break; + if (c.chan<=psgChanOffs) { + 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=NOTE_OPNB(c.chan,c.value); chan[c.chan].freqChanged=true; break; diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index 8d41997fc..f533497f9 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -70,6 +70,8 @@ class DivPlatformYM2608: public DivPlatformOPN { friend void putDispatchChip(void*,int); + inline void commitState(int ch, DivInstrument* ins); + void acquire_combo(short** buf, size_t len); void acquire_ymfm(short** buf, size_t len); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 5c62a491c..ba1c9440c 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -724,6 +724,43 @@ void DivPlatformYM2610::tick(bool sysTick) { ay->getRegisterWrites().clear(); } +void DivPlatformYM2610::commitState(int ch, DivInstrument* ins) { + if (chan[ch].insChanged) { + chan[ch].state=ins->fm; + chan[ch].opMask= + (chan[ch].state.op[0].enable?1:0)| + (chan[ch].state.op[2].enable?2:0)| + (chan[ch].state.op[1].enable?4:0)| + (chan[ch].state.op[3].enable?8:0); + } + + for (int i=0; i<4; i++) { + unsigned short baseAddr=chanOffs[ch]|opOffs[i]; + DivInstrumentFM::Operator& op=chan[ch].state.op[i]; + if (KVS(ch,i)) { + if (!chan[ch].active || chan[ch].insChanged) { + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[ch].outVol&0x7f,127)); + } + } else { + if (chan[ch].insChanged) { + rWrite(baseAddr+ADDR_TL,op.tl); + } + } + if (chan[ch].insChanged) { + 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[ch].insChanged) { + rWrite(chanOffs[ch]+ADDR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3)); + rWrite(chanOffs[ch]+ADDR_LRAF,(isMuted[ch]?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4)); + } +} + int DivPlatformYM2610::dispatch(DivCommand c) { if (c.chan>=psgChanOffs && c.chanfm; - chan[c.chan].opMask= - (chan[c.chan].state.op[0].enable?1:0)| - (chan[c.chan].state.op[2].enable?2:0)| - (chan[c.chan].state.op[1].enable?4:0)| - (chan[c.chan].state.op[3].enable?8:0); - } - - for (int i=0; i<4; i++) { - unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; - DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (KVS(c.chan,i)) { - if (!chan[c.chan].active || chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[c.chan].outVol&0x7f,127)); - } - } else { - if (chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,op.tl); - } - } - if (chan[c.chan].insChanged) { - 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]+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)); - } + commitState(c.chan,ins); chan[c.chan].insChanged=false; if (c.value!=DIV_NOTE_NULL) { @@ -1039,6 +1043,13 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; case DIV_CMD_LEGATO: { if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; + if (c.chan<=psgChanOffs) { + 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=NOTE_OPNB(c.chan,c.value); chan[c.chan].freqChanged=true; break; diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index bdf92dd52..3c95e2fb2 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -38,6 +38,8 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { friend void putDispatchChip(void*,int); + void commitState(int ch, DivInstrument* ins); + void acquire_combo(short** buf, size_t len); void acquire_ymfm(short** buf, size_t len); diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index a8f2329e4..39285d651 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -791,6 +791,43 @@ void DivPlatformYM2610B::tick(bool sysTick) { ay->getRegisterWrites().clear(); } +void DivPlatformYM2610B::commitState(int ch, DivInstrument* ins) { + if (chan[ch].insChanged) { + chan[ch].state=ins->fm; + chan[ch].opMask= + (chan[ch].state.op[0].enable?1:0)| + (chan[ch].state.op[2].enable?2:0)| + (chan[ch].state.op[1].enable?4:0)| + (chan[ch].state.op[3].enable?8:0); + } + + for (int i=0; i<4; i++) { + unsigned short baseAddr=chanOffs[ch]|opOffs[i]; + DivInstrumentFM::Operator& op=chan[ch].state.op[i]; + if (KVS(ch,i)) { + if (!chan[ch].active || chan[ch].insChanged) { + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[ch].outVol&0x7f,127)); + } + } else { + if (chan[ch].insChanged) { + rWrite(baseAddr+ADDR_TL,op.tl); + } + } + if (chan[ch].insChanged) { + 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[ch].insChanged) { + rWrite(chanOffs[ch]+ADDR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3)); + rWrite(chanOffs[ch]+ADDR_LRAF,(isMuted[ch]?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4)); + } +} + int DivPlatformYM2610B::dispatch(DivCommand c) { if (c.chan>=psgChanOffs && c.chanfm; - chan[c.chan].opMask= - (chan[c.chan].state.op[0].enable?1:0)| - (chan[c.chan].state.op[2].enable?2:0)| - (chan[c.chan].state.op[1].enable?4:0)| - (chan[c.chan].state.op[3].enable?8:0); - } - - for (int i=0; i<4; i++) { - unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; - DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (KVS(c.chan,i)) { - if (!chan[c.chan].active || chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[c.chan].outVol&0x7f,127)); - } - } else { - if (chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,op.tl); - } - } - if (chan[c.chan].insChanged) { - 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]+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)); - } + commitState(c.chan,ins); chan[c.chan].insChanged=false; if (c.value!=DIV_NOTE_NULL) { @@ -1106,6 +1110,13 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; case DIV_CMD_LEGATO: { if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; + if (c.chan<=psgChanOffs) { + 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=NOTE_OPNB(c.chan,c.value); chan[c.chan].freqChanged=true; break; diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index 7f0bad81c..1e66b03f1 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -34,6 +34,8 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { friend void putDispatchChip(void*,int); + void commitState(int ch, DivInstrument* ins); + void acquire_combo(short** buf, size_t len); void acquire_ymfm(short** buf, size_t len);