OPN: ExtCh FMS/AMS effects

This commit is contained in:
tildearrow 2025-05-21 17:10:40 -05:00
parent 981e798519
commit ec1542a2b4
4 changed files with 102 additions and 62 deletions

View file

@ -31,17 +31,17 @@ void DivPlatformGenesisExt::commitStateExt(int ch, DivInstrument* ins) {
int ordch=orderedOps[ch];
if (opChan[ch].insChanged) {
chan[2].state.alg=ins->fm.alg;
chan[extChanOffs].state.alg=ins->fm.alg;
if (ch==0 || fbAllOps) {
chan[2].state.fb=ins->fm.fb;
chan[extChanOffs].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];
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[2]|opOffs[ordch];
DivInstrumentFM::Operator& op=chan[2].state.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] || !op.enable) {
rWrite(baseAddr+0x40,127);
@ -60,8 +60,8 @@ void DivPlatformGenesisExt::commitStateExt(int ch, DivInstrument* ins) {
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));
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));
}
}
@ -73,7 +73,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
c.chan-=3;
return DivPlatformGenesis::dispatch(c);
}
int ch=c.chan-2;
int ch=c.chan-extChanOffs;
int ordch=orderedOps[ch];
if (!extMode) {
c.chan=2;
@ -126,8 +126,8 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
if (!opChan[ch].std.vol.has) {
opChan[ch].outVol=c.value;
}
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
DivInstrumentFM::Operator& op=chan[2].state.op[ordch];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[ordch];
if (isOpMuted[ch] || !op.enable) {
rWrite(baseAddr+0x40,127);
} else {
@ -158,7 +158,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
opChan[i].pan=opChan[ch].pan;
}
}
rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4));
rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
lastExtChPan=opChan[ch].pan;
break;
}
@ -238,20 +238,30 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
break;
}
case DIV_CMD_FM_FB: {
chan[2].state.fb=c.value&7;
rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3));
chan[extChanOffs].state.fb=c.value&7;
rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3));
break;
}
case DIV_CMD_FM_FMS: {
chan[extChanOffs].state.fms=c.value&7;
rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
break;
}
case DIV_CMD_FM_AMS: {
chan[extChanOffs].state.ams=c.value&3;
rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
break;
}
case DIV_CMD_FM_MULT: {
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[extChanOffs].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: {
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
op.tl=c.value2;
if (isOpMuted[ch] || !op.enable) {
rWrite(baseAddr+0x40,127);
@ -265,15 +275,15 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
case DIV_CMD_FM_AR: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
op.ar=c.value2&31;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
}
} else {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
op.ar=c.value2&31;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
}
break;
@ -281,15 +291,15 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
case DIV_CMD_FM_RS: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
op.rs=c.value2&3;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
op.rs=c.value2&3;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
break;
@ -297,15 +307,15 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
case DIV_CMD_FM_AM: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
op.am=c.value2&1;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
op.am=c.value2&1;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
break;
@ -313,15 +323,15 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
case DIV_CMD_FM_DR: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
op.dr=c.value2&31;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
op.dr=c.value2&31;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
break;
@ -329,15 +339,15 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
case DIV_CMD_FM_SL: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
op.sl=c.value2&15;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
op.sl=c.value2&15;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
break;
@ -345,15 +355,15 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
case DIV_CMD_FM_RR: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
op.rr=c.value2&15;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
op.rr=c.value2&15;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
break;
@ -361,15 +371,15 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
case DIV_CMD_FM_D2R: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
op.d2r=c.value2&31;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
op.d2r=c.value2&31;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
}
break;
@ -377,15 +387,15 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
case DIV_CMD_FM_DT: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
op.dt=c.value&7;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
op.dt=c.value2&7;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
break;
@ -393,15 +403,15 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
case DIV_CMD_FM_SSG: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
op.ssgEnv=8^(c.value2&15);
unsigned short baseAddr=chanOffs[2]|opOffs[i];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
op.ssgEnv=8^(c.value2&15);
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
}
break;
@ -443,8 +453,8 @@ void DivPlatformGenesisExt::muteChannel(int ch, bool mute) {
if (extMode) {
for (int i=0; i<4; i++) {
int ordch=orderedOps[i];
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
DivInstrumentFM::Operator op=chan[2].state.op[ordch];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch];
DivInstrumentFM::Operator op=chan[extChanOffs].state.op[ordch];
if (isOpMuted[i] || !op.enable) {
rWrite(baseAddr+0x40,127);
} else {
@ -452,7 +462,7 @@ void DivPlatformGenesisExt::muteChannel(int ch, bool mute) {
}
}
rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch-2].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4));
rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch-2].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
}
}
@ -506,8 +516,8 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
if (extMode && !noExtMacros) for (int i=0; i<4; i++) {
if (opChan[i].std.vol.had) {
opChan[i].outVol=VOL_SCALE_LOG_BROKEN(opChan[i].vol,MIN(127,opChan[i].std.vol.val),127);
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]];
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[i]];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[i]];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[i]];
if (isOpMuted[i]) {
rWrite(baseAddr+ADDR_TL,127);
} else {
@ -579,8 +589,8 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
}
// param macros
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]];
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[i]];
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[i]];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[i]];
DivMacroInt::IntOp& m=opChan[i].std.op[orderedOps[i]];
if (m.am.had) {
op.am=m.am.val;

View file

@ -223,6 +223,16 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) {
rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3));
break;
}
case DIV_CMD_FM_FMS: {
chan[extChanOffs].state.fms=c.value&7;
rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
break;
}
case DIV_CMD_FM_AMS: {
chan[extChanOffs].state.ams=c.value&3;
rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
break;
}
case DIV_CMD_FM_MULT: {
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];

View file

@ -219,6 +219,16 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3));
break;
}
case DIV_CMD_FM_FMS: {
chan[extChanOffs].state.fms=c.value&7;
rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
break;
}
case DIV_CMD_FM_AMS: {
chan[extChanOffs].state.ams=c.value&3;
rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
break;
}
case DIV_CMD_FM_MULT: {
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];

View file

@ -219,6 +219,16 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3));
break;
}
case DIV_CMD_FM_FMS: {
chan[extChanOffs].state.fms=c.value&7;
rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
break;
}
case DIV_CMD_FM_AMS: {
chan[extChanOffs].state.ams=c.value&3;
rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
break;
}
case DIV_CMD_FM_MULT: {
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];