From 43ba2ff8f216138485e485e600610afe266a53bd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 3 Feb 2023 17:00:15 -0500 Subject: [PATCH] OPZ: implement LFO2 issue #831 untested and I can't test now --- papers/doc/7-systems/opz.md | 10 ++++ src/engine/dispatch.h | 8 +-- src/engine/platform/fmshared_OPM.h | 8 ++- src/engine/platform/tx81z.cpp | 80 +++++++++++++++++++++++++++--- src/engine/platform/tx81z.h | 2 +- src/engine/playback.cpp | 8 +-- src/engine/sysDef.cpp | 4 ++ 7 files changed, 104 insertions(+), 16 deletions(-) diff --git a/papers/doc/7-systems/opz.md b/papers/doc/7-systems/opz.md index c7952a55..555df814 100644 --- a/papers/doc/7-systems/opz.md +++ b/papers/doc/7-systems/opz.md @@ -45,6 +45,16 @@ no plans have been made for TX81Z MIDI passthrough, because: - `1Bxx`: set attack of operator 2. - `1Cxx`: set attack of operator 3. - `1Dxx`: set attack of operator 4. +- `1Exx`: set LFO AM depth. +- `1Fxx`: set LFO PM depth. +- `24xx`: set LFO 2 speed. +- `25xx`: set LFO 2 waveform. `xx` may be one of the following: + - `00`: saw + - `01`: square + - `02`: triangle + - `03`: noise +- `26xx`: set LFO 2 AM depth. +- `27xx`: set LFO 2 PM depth. - `28xy`: set reverb of operator. - `x` is the operator (1-4). a value of 0 means "all operators". - `y` is the value. diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 0378eba2..32540db2 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -103,9 +103,8 @@ enum DivDispatchCmds { DIV_CMD_FM_AM_DEPTH, // (depth) DIV_CMD_FM_PM_DEPTH, // (depth) - DIV_CMD_GENESIS_LFO, // unused? - - DIV_CMD_ARCADE_LFO, // unused? + DIV_CMD_FM_LFO2, // (speed) + DIV_CMD_FM_LFO2_WAVE, // (waveform) DIV_CMD_STD_NOISE_FREQ, // (freq) DIV_CMD_STD_NOISE_MODE, // (mode) @@ -215,6 +214,9 @@ enum DivDispatchCmds { DIV_CMD_SURROUND_PANNING, // (out, val) + DIV_CMD_FM_AM2_DEPTH, // (depth) + DIV_CMD_FM_PM2_DEPTH, // (depth) + DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol DIV_CMD_MAX diff --git a/src/engine/platform/fmshared_OPM.h b/src/engine/platform/fmshared_OPM.h index 02c30b7e..e922e8ab 100644 --- a/src/engine/platform/fmshared_OPM.h +++ b/src/engine/platform/fmshared_OPM.h @@ -41,8 +41,14 @@ class DivPlatformOPM: public DivPlatformFMBase { 0x00, 0x08, 0x10, 0x18 }; + unsigned char lfoValue, lfoValue2, lfoShape, lfoShape2; + DivPlatformOPM(): - DivPlatformFMBase() {} + DivPlatformFMBase(), + lfoValue(0), + lfoValue2(0), + lfoShape(0), + lfoShape2(0) {} }; #endif diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index db728489..80e69f19 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -26,6 +26,8 @@ #define ADDR_WS_FINE 0x100 // actually 0xc0 but bit 5 of data selects address #define ADDR_EGS_REV 0x120 +// actually 0x38 but bits 7 and 2 select address +#define ADDR_FMS2_AMS2 0x140 const char* regCheatSheetOPZ[]={ "Test", "00", @@ -139,7 +141,8 @@ void DivPlatformTX81Z::tick(bool sysTick) { } if (chan[i].std.wave.had) { - rWrite(0x1b,chan[i].std.wave.val&3); + lfoShape=chan[i].std.wave.val&3; + immWrite(0x1b,lfoShape|(lfoShape2<<2)); } if (chan[i].std.pitch.had) { @@ -177,7 +180,28 @@ void DivPlatformTX81Z::tick(bool sysTick) { } if (chan[i].std.ex3.had) { - immWrite(0x18,chan[i].std.ex3.val); + lfoValue=chan[i].std.ex3.val; + immWrite(0x18,lfoValue); + } + + if (chan[i].std.ex5.had) { + amDepth2=chan[i].std.ex5.val; + immWrite(0x17,amDepth2); + } + + if (chan[i].std.ex6.had) { + pmDepth2=chan[i].std.ex6.val; + immWrite(0x17,0x80|pmDepth2); + } + + if (chan[i].std.ex7.had) { + lfoValue2=chan[i].std.ex7.val; + immWrite(0x16,lfoValue2); + } + + if (chan[i].std.ex8.had) { + lfoShape2=chan[i].std.ex8.val&3; + immWrite(0x1b,lfoShape|(lfoShape2<<2)); } if (chan[i].std.alg.had) { @@ -286,6 +310,12 @@ void DivPlatformTX81Z::tick(bool sysTick) { oldWrites[i]=pendingWrites[i]; } } + for (int i=320; i<328; i++) { + if (pendingWrites[i]!=oldWrites[i]) { + immWrite(0x38+(i&7),(0x84|pendingWrites[i])); + oldWrites[i]=pendingWrites[i]; + } + } int hardResetElapsed=0; bool mustHardReset=false; @@ -405,7 +435,7 @@ void DivPlatformTX81Z::commitState(int ch, DivInstrument* ins) { rWrite(chanOffs[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3)|((chan[ch].chVolL&1)<<6)|((chan[ch].chVolR&1)<<7)); }*/ rWrite(chanOffs[ch]+ADDR_FMS_AMS,((chan[ch].state.fms&7)<<4)|(chan[ch].state.ams&3)); - //rWrite(chanOffs[ch]+ADDR_FMS_AMS,0x84|((chan[ch].state.fms2&7)<<4)|(chan[ch].state.ams2&3)); + rWrite(chanOffs[ch]+ADDR_FMS2_AMS2,((chan[ch].state.fms2&7)<<4)|(chan[ch].state.ams2&3)); } } @@ -528,11 +558,23 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { break; } case DIV_CMD_FM_LFO: { - rWrite(0x18,c.value); + lfoValue=c.value; + immWrite(0x18,lfoValue); break; } case DIV_CMD_FM_LFO_WAVE: { - rWrite(0x1b,c.value&3); + lfoShape=c.value&3; + immWrite(0x1b,lfoShape|(lfoShape2<<2)); + break; + } + case DIV_CMD_FM_LFO2: { + lfoValue2=c.value; + immWrite(0x16,lfoValue2); + break; + } + case DIV_CMD_FM_LFO2_WAVE: { + lfoShape2=c.value&3; + immWrite(0x1b,lfoShape|(lfoShape2<<2)); break; } case DIV_CMD_FM_FB: { @@ -810,6 +852,16 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { immWrite(0x19,0x80|pmDepth); break; } + case DIV_CMD_FM_AM2_DEPTH: { + amDepth2=c.value; + immWrite(0x17,amDepth); + break; + } + case DIV_CMD_FM_PM2_DEPTH: { + pmDepth2=c.value; + immWrite(0x17,0x80|pmDepth); + break; + } case DIV_CMD_FM_HARD_RESET: chan[c.chan].hardReset=c.value; break; @@ -880,7 +932,7 @@ void DivPlatformTX81Z::forceIns() { rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|((chan[i].chVolL&1)<<6)|((chan[i].chVolR&1)<<7)); }*/ rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3)); - //rWrite(chanOffs[i]+ADDR_FMS_AMS,0x84|((chan[i].state.fms2&7)<<4)|(chan[i].state.ams2&3)); + rWrite(chanOffs[i]+ADDR_FMS2_AMS2,((chan[i].state.fms2&7)<<4)|(chan[i].state.ams2&3)); if (chan[i].active) { chan[i].keyOn=true; chan[i].freqChanged=true; @@ -888,6 +940,11 @@ void DivPlatformTX81Z::forceIns() { } immWrite(0x19,amDepth); immWrite(0x19,0x80|pmDepth); + immWrite(0x17,amDepth2); + immWrite(0x17,0x80|pmDepth2); + immWrite(0x18,lfoValue); + immWrite(0x16,lfoValue2); + immWrite(0x1b,lfoShape|(lfoShape2<<2)); } void DivPlatformTX81Z::notifyInsChange(int ins) { @@ -958,12 +1015,19 @@ void DivPlatformTX81Z::reset() { delay=0; amDepth=0x7f; pmDepth=0x7f; + amDepth2=0x7f; + pmDepth2=0x7f; + lfoValue=0; + lfoValue2=0; + lfoShape=0; + lfoShape2=0; - //rWrite(0x18,0x10); immWrite(0x18,0x00); // LFO Freq Off + immWrite(0x16,0x00); immWrite(0x19,amDepth); immWrite(0x19,0x80|pmDepth); - //rWrite(0x1b,0x00); + immWrite(0x17,amDepth2); + immWrite(0x17,0x80|pmDepth2); extMode=false; } diff --git a/src/engine/platform/tx81z.h b/src/engine/platform/tx81z.h index e15158b7..d1ebd543 100644 --- a/src/engine/platform/tx81z.h +++ b/src/engine/platform/tx81z.h @@ -45,7 +45,7 @@ class DivPlatformTX81Z: public DivPlatformOPM { DivDispatchOscBuffer* oscBuf[8]; int baseFreqOff; int pcmL, pcmR, pcmCycles; - unsigned char amDepth, pmDepth; + unsigned char amDepth, pmDepth, amDepth2, pmDepth2; ymfm::ym2414* fm_ymfm; ymfm::ym2414::output_data out_ymfm; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index cc231817..485a020d 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -103,9 +103,8 @@ const char* cmdName[]={ "FM_AM_DEPTH", "FM_PM_DEPTH", - "GENESIS_LFO", - - "ARCADE_LFO", + "FM_LFO2", + "FM_LFO2_WAVE", "STD_NOISE_FREQ", "STD_NOISE_MODE", @@ -215,6 +214,9 @@ const char* cmdName[]={ "SURROUND_PANNING", + "FM_AM2_DEPTH", + "FM_PM2_DEPTH", + "ALWAYS_SET_VOLUME" }; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 0fc35f1a..154ad7eb 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -504,6 +504,10 @@ void DivEngine::registerSystems() { EffectHandlerMap fmOPZPostEffectHandlerMap(fmOPMPostEffectHandlerMap); fmOPZPostEffectHandlerMap.insert({ + {0x24, {DIV_CMD_FM_LFO2, "24xx: Set LFO 2 speed"}}, + {0x25, {DIV_CMD_FM_LFO2_WAVE, "25xx: Set LFO 2 waveform (0 saw, 1 square, 2 triangle, 3 noise)"}}, + {0x26, {DIV_CMD_FM_AM2_DEPTH, "26xx: Set AM 2 depth (0 to 7F)", effectValAnd<127>}}, + {0x27, {DIV_CMD_FM_PM2_DEPTH, "27xx: Set PM 2 depth (0 to 7F)", effectValAnd<127>}}, {0x28, {DIV_CMD_FM_REV, "28xy: Set reverb (x: operator from 1 to 4 (0 for all ops); y: reverb from 0 to 7)", effectOpVal<4>, effectValAnd<7>}}, {0x2a, {DIV_CMD_FM_WS, "2Axy: Set waveform (x: operator from 1 to 4 (0 for all ops); y: waveform from 0 to 7)", effectOpVal<4>, effectValAnd<7>}}, {0x2b, {DIV_CMD_FM_EG_SHIFT, "2Bxy: Set envelope generator shift (x: operator from 1 to 4 (0 for all ops); y: shift from 0 to 3)", effectOpVal<4>, effectValAnd<3>}},