From e58518ed62912173a07ed82c1a68c96eaff01546 Mon Sep 17 00:00:00 2001 From: LTVA1 <87536432+LTVA1@users.noreply.github.com> Date: Sun, 25 Aug 2024 13:33:01 +0300 Subject: [PATCH] first attempt, arp & pitch macros work --- src/engine/platform/tx81z.cpp | 70 ++++++++++++++++++++++++++++++ src/engine/platform/tx81z.h | 66 +++++++++++++++++++++++++++- src/gui/insEdit.cpp | 82 ++++++++++++++++++++++++++++++----- 3 files changed, 206 insertions(+), 12 deletions(-) diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 3fee5e04e..42feec95a 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -102,6 +102,15 @@ inline int hScale(int note) { return ((note/12)<<4)+(noteMap[note%12]); } +int DivPlatformTX81Z::toFreq(int freq) { + int block=0; + while (freq>0xff) { + freq>>=1; + block++; + } + return ((block&7)<<8)|(freq&0xff); +} + void DivPlatformTX81Z::tick(bool sysTick) { for (int i=0; i<8; i++) { chan[i].std.next(); @@ -289,6 +298,66 @@ void DivPlatformTX81Z::tick(bool sysTick) { op.dt2=m.dt2.val; rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6)); } + + /*if (ImGui::InputInt(_("Block"),&block,1,1)) { + if (block<0) block=0; + if (block>7) block=7; + op.dt=block; + } + if (ImGui::InputInt(_("FreqNum"),&freqNum,1,16)) { + if (freqNum<0) freqNum=0; + if (freqNum>255) freqNum=255; + op.mult=freqNum>>4; + op.dvb=freqNum&15; + }*/ + + // fixed pitch + bool freqChangeOp = false; + + if(op.egt) + { + if (op.sus) { + chan[i].handleArpFmOp(freqChangeOp, 0, j); //arp and pitch macros + chan[i].handlePitchFmOp(freqChangeOp, j); + } else { + if (m.ssg.had) { //block and f-num macros + op.dt=m.ssg.val&7; + rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|((op.egt?(op.dt&7):dtTable[op.dt&7])<<4)); + } + if (m.sus.had) { + op.mult=(m.sus.val & 0xff) >> 4; + op.dvb=(m.sus.val & 0xf); + rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|((op.egt?(op.dt&7):dtTable[op.dt&7])<<4)); + rWrite(baseAddr+ADDR_WS_FINE,(op.dvb&15)|(op.ws<<4)); + } + } + } + + if(freqChangeOp) + { + int arp=chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff; + int pitch2=chan[i].pitch2; + int fixedArp=chan[i].fixedArp; + if(chan[i].opsState[j].hasOpArp) { + arp=chan[i].opsState[j].fixedArp?chan[i].opsState[j].baseNoteOverride:chan[i].opsState[j].arpOff; + fixedArp=chan[i].opsState[j].fixedArp; + } + if(chan[i].opsState[j].hasOpPitch) { + pitch2=chan[i].opsState[j].pitch2; + } + int opFreq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,arp,fixedArp,false,2, pitch2,chipClock,524288 / 4,0); + if (opFreq<0) opFreq=0; + if (opFreq>65280) opFreq=65280; + int freqt=toFreq(opFreq); + + op.dt=(freqt >> 8) & 7; + + op.mult=(freqt & 0xff) >> 4; + op.dvb=(freqt & 0xf); + + rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|((op.egt?(op.dt&7):dtTable[op.dt&7])<<4)); + rWrite(baseAddr+ADDR_WS_FINE,(op.dvb&15)|(op.ws<<4)); + } } } @@ -444,6 +513,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPZ); + memset(chan[c.chan].opsState, 0, sizeof(chan[c.chan].opsState)); chan[c.chan].macroInit(ins); if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; diff --git a/src/engine/platform/tx81z.h b/src/engine/platform/tx81z.h index 8c97ed22e..c2577a214 100644 --- a/src/engine/platform/tx81z.h +++ b/src/engine/platform/tx81z.h @@ -36,10 +36,74 @@ class DivPlatformTX81Z: public DivPlatformOPM { struct Channel: public FMChannel { unsigned char chVolL, chVolR; + + struct { + int baseNoteOverride; + bool fixedArp; + int arpOff; + int pitch2; + bool hasOpArp; + bool hasOpPitch; + } opsState[4]; + + void handleArpFmOp(bool& freqChange, int offset=0, int o=0) { + DivMacroInt::IntOp& m=this->std.op[o]; + if (m.ssg.had) { + opsState[o].hasOpArp=true; + + if (m.ssg.val<0) { + if (!(m.ssg.val&0x40000000)) { + opsState[o].baseNoteOverride=(m.ssg.val|0x40000000)+offset; + opsState[o].fixedArp=true; + } else { + opsState[o].arpOff=m.ssg.val; + opsState[o].fixedArp=false; + } + } else { + if (m.ssg.val&0x40000000) { + opsState[o].baseNoteOverride=(m.ssg.val&(~0x40000000))+offset; + opsState[o].fixedArp=true; + } else { + opsState[o].arpOff=m.ssg.val; + opsState[o].fixedArp=false; + } + } + freqChange = true; + } + + else + { + opsState[o].hasOpArp=false; + } + } + + void handlePitchFmOp(bool& freqChange, int o) + { + DivMacroInt::IntOp& m=this->std.op[o]; + + if (m.sus.had) { + opsState[o].hasOpPitch=true; + + if (m.sus.mode) { + opsState[o].pitch2+=m.sus.val; + CLAMP_VAR(opsState[o].pitch2,-131071,131071); + } else { + opsState[o].pitch2=m.sus.val; + } + freqChange = true; + } + + else + { + opsState[o].hasOpPitch=false; + } + } Channel(): FMChannel(), chVolL(1), - chVolR(1) {} + chVolR(1) { + memset(opsState, 0, sizeof(opsState)); + } }; Channel chan[8]; DivDispatchOscBuffer* oscBuf[8]; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 120eac9e7..bcb82f88a 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3803,7 +3803,22 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) { if (ins->type==DIV_INS_OPZ) { ImGui::TableNextColumn(); CENTER_VSLIDER; - P(CWVSliderScalar("##FINE",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN)); rightClickable + bool egtOn=op.egt; + if(egtOn) + { + bool susOn=op.sus; + if (ImGui::Checkbox("Pitch control",&susOn)) { PARAMETER + op.sus=susOn; + } + if(ImGui::IsItemHovered()) + { + ImGui::SetTooltip(_("Use op's arpeggio and pitch macros control instead of block/f-num macros")); + } + } + else + { + P(CWVSliderScalar("##FINE",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN)); rightClickable + } } if (ins->type==DIV_INS_ESFM) { @@ -4593,6 +4608,17 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) { snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_FINE)); P(CWSliderScalar("##FINE",ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN,tempID)); rightClickable } + else + { + bool susOn=op.sus; + if (ImGui::Checkbox("Pitch control",&susOn)) { PARAMETER + op.sus=susOn; + } + if(ImGui::IsItemHovered()) + { + ImGui::SetTooltip(_("Use op's arpeggio and pitch macros control instead of block/f-num macros")); + } + } ImGui::TableNextColumn(); bool amOn=op.am; @@ -4897,6 +4923,18 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) { if (ImGui::Checkbox(_("Fixed"),&fixedOn)) { PARAMETER op.egt=fixedOn; } + bool susOn=op.sus; + if(fixedOn) + { + ImGui::SameLine(); + if (ImGui::Checkbox("Pitch control",&susOn)) { PARAMETER + op.sus=susOn; + } + if(ImGui::IsItemHovered()) + { + ImGui::SetTooltip(_("Use op's arpeggio and pitch macros control instead of block/f-num macros")); + } + } } //52.0 controls vert scaling; default 96 @@ -5555,6 +5593,13 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_EGS),&ins->std.opMacros[ordi].egtMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else if (ins->type==DIV_INS_ESFM) { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_TL),&ins->std.opMacros[ordi].tlMacro,0,maxTl,128,uiColors[GUI_COLOR_MACRO_VOLUME])); + if (ins->esfm.op[ordi].fixed) { + macroList.push_back(FurnaceGUIMacroDesc(_("Block"),&ins->std.opMacros[ordi].ssgMacro,0,7,64,uiColors[GUI_COLOR_MACRO_PITCH],true)); + macroList.push_back(FurnaceGUIMacroDesc(_("FreqNum"),&ins->std.opMacros[ordi].dtMacro,0,1023,160,uiColors[GUI_COLOR_MACRO_PITCH])); + } else { + macroList.push_back(FurnaceGUIMacroDesc(_("Op. Arpeggio"),&ins->std.opMacros[ordi].ssgMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.opMacros[ordi].ssgMacro.val,true)); + macroList.push_back(FurnaceGUIMacroDesc(_("Op. Pitch"),&ins->std.opMacros[ordi].dtMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode,NULL,false,NULL,false,NULL,false,true)); + } macroList.push_back(FurnaceGUIMacroDesc(ESFM_NAME(ESFM_DELAY),&ins->std.opMacros[ordi].dt2Macro,0,7,64,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AR),&ins->std.opMacros[ordi].arMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DR),&ins->std.opMacros[ordi].drMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_ENVELOPE])); @@ -5565,14 +5610,6 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_WS),&ins->std.opMacros[ordi].wsMacro,0,7,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(ESFM_NAME(ESFM_OUTLVL),&ins->std.opMacros[ordi].egtMacro,0,7,64,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(ESFM_NAME(ESFM_MODIN),&ins->std.opMacros[ordi].d2rMacro,0,7,64,uiColors[GUI_COLOR_MACRO_VOLUME])); - if (ins->esfm.op[ordi].fixed) { - macroList.push_back(FurnaceGUIMacroDesc(_("Block"),&ins->std.opMacros[ordi].ssgMacro,0,7,64,uiColors[GUI_COLOR_MACRO_PITCH],true)); - macroList.push_back(FurnaceGUIMacroDesc(_("FreqNum"),&ins->std.opMacros[ordi].dtMacro,0,1023,160,uiColors[GUI_COLOR_MACRO_PITCH])); - } else { - macroList.push_back(FurnaceGUIMacroDesc(_("Op. Arpeggio"),&ins->std.opMacros[ordi].ssgMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.opMacros[ordi].ssgMacro.val,true)); - macroList.push_back(FurnaceGUIMacroDesc(_("Op. Pitch"),&ins->std.opMacros[ordi].dtMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode,NULL,false,NULL,false,NULL,false,true)); - } - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DAM),&ins->std.opMacros[ordi].damMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); @@ -5580,7 +5617,7 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.opMacros[ordi].susMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Op. Panning"),&ins->std.opMacros[ordi].rsMacro,0,2,40,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); - } else { + } else if(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_TL),&ins->std.opMacros[ordi].tlMacro,0,maxTl,128,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AR),&ins->std.opMacros[ordi].arMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DR),&ins->std.opMacros[ordi].drMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_ENVELOPE])); @@ -5590,7 +5627,7 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_RS),&ins->std.opMacros[ordi].rsMacro,0,3,32,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_MULT),&ins->std.opMacros[ordi].multMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DT),&ins->std.opMacros[ordi].dtMacro,0,7,64,uiColors[GUI_COLOR_MACRO_PITCH])); - if (ins->type==DIV_INS_OPM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_OPM) { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DT2),&ins->std.opMacros[ordi].dt2Macro,0,3,32,uiColors[GUI_COLOR_MACRO_PITCH])); } macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); @@ -5598,6 +5635,29 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_FM) { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SSG),&ins->std.opMacros[ordi].ssgMacro,0,4,64,uiColors[GUI_COLOR_MACRO_ENVELOPE],false,NULL,NULL,true,ssgEnvBits)); } + } else if(ins->type==DIV_INS_OPZ) { + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_TL),&ins->std.opMacros[ordi].tlMacro,0,maxTl,128,uiColors[GUI_COLOR_MACRO_VOLUME])); + if (ins->fm.op[ordi].egt) + { + if (!ins->fm.op[ordi].sus) { + macroList.push_back(FurnaceGUIMacroDesc(_("Block"),&ins->std.opMacros[ordi].ssgMacro,0,7,64,uiColors[GUI_COLOR_MACRO_PITCH],true)); + macroList.push_back(FurnaceGUIMacroDesc(_("FreqNum"),&ins->std.opMacros[ordi].susMacro,0,255,160,uiColors[GUI_COLOR_MACRO_PITCH])); + } else { + macroList.push_back(FurnaceGUIMacroDesc(_("Op. Arpeggio"),&ins->std.opMacros[ordi].ssgMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.opMacros[ordi].ssgMacro.val,true)); + macroList.push_back(FurnaceGUIMacroDesc(_("Op. Pitch"),&ins->std.opMacros[ordi].susMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode,NULL,false,NULL,false,NULL,false,true)); + } + } + + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AR),&ins->std.opMacros[ordi].arMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_ENVELOPE])); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DR),&ins->std.opMacros[ordi].drMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_ENVELOPE])); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_D2R),&ins->std.opMacros[ordi].d2rMacro,0,31,64,uiColors[GUI_COLOR_MACRO_ENVELOPE])); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_RR),&ins->std.opMacros[ordi].rrMacro,0,15,64,uiColors[GUI_COLOR_MACRO_ENVELOPE])); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SL),&ins->std.opMacros[ordi].slMacro,0,15,64,uiColors[GUI_COLOR_MACRO_ENVELOPE])); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_RS),&ins->std.opMacros[ordi].rsMacro,0,3,32,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_MULT),&ins->std.opMacros[ordi].multMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DT),&ins->std.opMacros[ordi].dtMacro,0,7,64,uiColors[GUI_COLOR_MACRO_PITCH])); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DT2),&ins->std.opMacros[ordi].dt2Macro,0,3,32,uiColors[GUI_COLOR_MACRO_PITCH])); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } drawMacros(macroList,macroEditStateOP[ordi]); ImGui::PopID();