diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index f0934c48e..166832a7b 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -204,6 +204,32 @@ int DivEngine::getMaxVolume() { return 127; } +int DivEngine::getMaxDuty() { + switch (song.system) { + case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610_EXT: + return 31; + case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580: + return 8; + default: + return 3; + } + return 3; +} + +int DivEngine::getMaxWave() { + switch (song.system) { + case DIV_SYSTEM_PCE: case DIV_SYSTEM_GB: + return 31; + case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610_EXT: + return 7; + case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580: + return 8; + default: + return 1; + } + return 1; +} + bool DivEngine::load(void* f, size_t slen) { unsigned char* file; size_t len; diff --git a/src/engine/engine.h b/src/engine/engine.h index ef3afccc9..89f47ac89 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -125,6 +125,12 @@ class DivEngine { // get max STD volume int getMaxVolume(); + // get max STD duty + int getMaxDuty(); + + // get max STD wave + int getMaxWave(); + // get current order unsigned char getOrder(); diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 6372a5d06..2d66898d0 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -14,7 +14,34 @@ struct DivInstrumentFM { struct Operator { unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv; unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759 + Operator(): + am(0), + ar(0), + dr(0), + mult(0), + rr(0), + sl(0), + tl(0), + dt2(0), + rs(0), + dt(0), + d2r(0), + ssgEnv(0), + dam(0), + dvb(0), + egt(0), + ksl(0), + sus(0), + vib(0), + ws(0), + ksr(0) {} } op[4]; + DivInstrumentFM(): + alg(0), + fb(0), + fms(0), + ams(0), + ops(4) {} }; struct DivInstrumentSTD { @@ -25,10 +52,30 @@ struct DivInstrumentSTD { bool arpMacroMode; unsigned char volMacroLen, arpMacroLen, dutyMacroLen, waveMacroLen; signed char volMacroLoop, arpMacroLoop, dutyMacroLoop, waveMacroLoop; + DivInstrumentSTD(): + arpMacroMode(false), + volMacroLen(0), + arpMacroLen(0), + dutyMacroLen(0), + waveMacroLen(0), + volMacroLoop(-1), + arpMacroLoop(-1), + dutyMacroLoop(-1), + waveMacroLoop(-1) { + memset(volMacro,0,256*sizeof(int)); + memset(arpMacro,0,256*sizeof(int)); + memset(dutyMacro,0,256*sizeof(int)); + memset(waveMacro,0,256*sizeof(int)); + } }; struct DivInstrumentGB { unsigned char envVol, envDir, envLen, soundLen; + DivInstrumentGB(): + envVol(0), + envDir(0), + envLen(0), + soundLen(0) {} }; struct DivInstrumentC64 { @@ -39,6 +86,28 @@ struct DivInstrumentC64 { bool toFilter, volIsCutoff, initFilter; unsigned char res, cut; bool hp, lp, bp, ch3off; + + DivInstrumentC64(): + triOn(false), + sawOn(true), + pulseOn(false), + noiseOn(false), + a(0), + d(8), + s(0), + r(0), + duty(50), + ringMod(0), + oscSync(0), + toFilter(false), + volIsCutoff(false), + initFilter(false), + res(0), + cut(0), + hp(false), + lp(false), + bp(false), + ch3off(false) {} }; struct DivInstrument { @@ -52,11 +121,7 @@ struct DivInstrument { DivInstrument(): name(""), mode(false), - type(DIV_INS_FM) { - memset(&fm,0,sizeof(DivInstrumentFM)); - memset(&std,0,sizeof(DivInstrumentSTD)); - memset(&gb,0,sizeof(DivInstrumentGB)); - memset(&c64,0,sizeof(DivInstrumentC64)); + type(DIV_INS_STD) { } }; #endif diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 539b814aa..899443d0b 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -12,8 +12,10 @@ const int _ZERO=0; const int _ONE=1; const int _THREE=3; const int _SEVEN=7; -const int _FIFTEEN=15;; +const int _FIFTEEN=15; const int _THIRTY_ONE=31; +const int _SIXTY_FOUR=64; +const int _ONE_HUNDRED=100; const int _ONE_HUNDRED_TWENTY_SEVEN=127; const int opOrder[4]={ @@ -32,7 +34,6 @@ bool FurnaceGUI::loop() { switch (ev.type) { case SDL_MOUSEMOTION: if (macroDragActive) { - // do macro drag here! if (macroDragLen>0) { int x=(ev.motion.x-macroDragStart.x)*macroDragLen/macroDragAreaSize.x; if (x<0) x=0; @@ -43,9 +44,18 @@ bool FurnaceGUI::loop() { macroDragTarget[x]=y; } } + if (macroLoopDragActive) { + if (macroLoopDragLen>0) { + int x=(ev.motion.x-macroLoopDragStart.x)*macroLoopDragLen/macroLoopDragAreaSize.x; + if (x<0) x=0; + if (x>=macroLoopDragLen) x=-1; + *macroLoopDragTarget=x; + } + } break; case SDL_MOUSEBUTTONUP: macroDragActive=false; + macroLoopDragActive=false; break; case SDL_QUIT: quit=true; @@ -180,61 +190,245 @@ bool FurnaceGUI::loop() { float asFloat[128]; float loopIndicator[128]; + // GB specifics + if (e->song.system==DIV_SYSTEM_GB) { + ImGui::SliderScalar("Volume",ImGuiDataType_U8,&ins->gb.envVol,&_ZERO,&_FIFTEEN); + ImGui::SliderScalar("Envelope Length",ImGuiDataType_U8,&ins->gb.envLen,&_ZERO,&_SEVEN); + ImGui::SliderScalar("Sound Length",ImGuiDataType_U8,&ins->gb.soundLen,&_ZERO,&_SIXTY_FOUR,ins->gb.soundLen>63?"Infinity":"%d"); + bool goesUp=ins->gb.envDir; + if (ImGui::Checkbox("Up",&goesUp)) { + ins->gb.envDir=goesUp; + } + } + + // C64 specifics + if (e->song.system==DIV_SYSTEM_C64_6581 || e->song.system==DIV_SYSTEM_C64_8580) { + ImGui::Text("Waveform"); + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.triOn)?0.6f:0.2f,0.2f,1.0f)); + if (ImGui::Button("tri")) { + ins->c64.triOn=!ins->c64.triOn; + } + ImGui::PopStyleColor(); + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.sawOn)?0.6f:0.2f,0.2f,1.0f)); + if (ImGui::Button("saw")) { + ins->c64.sawOn=!ins->c64.sawOn; + } + ImGui::PopStyleColor(); + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.pulseOn)?0.6f:0.2f,0.2f,1.0f)); + if (ImGui::Button("pulse")) { + ins->c64.pulseOn=!ins->c64.pulseOn; + } + ImGui::PopStyleColor(); + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.noiseOn)?0.6f:0.2f,0.2f,1.0f)); + if (ImGui::Button("noise")) { + ins->c64.noiseOn=!ins->c64.noiseOn; + } + ImGui::PopStyleColor(); + + ImGui::SliderScalar("Attack",ImGuiDataType_U8,&ins->c64.a,&_ZERO,&_FIFTEEN); + ImGui::SliderScalar("Decay",ImGuiDataType_U8,&ins->c64.d,&_ZERO,&_FIFTEEN); + ImGui::SliderScalar("Sustain",ImGuiDataType_U8,&ins->c64.s,&_ZERO,&_FIFTEEN); + ImGui::SliderScalar("Release",ImGuiDataType_U8,&ins->c64.r,&_ZERO,&_FIFTEEN); + ImGui::SliderScalar("Duty",ImGuiDataType_U8,&ins->c64.duty,&_ZERO,&_ONE_HUNDRED); + + bool ringMod=ins->c64.ringMod; + if (ImGui::Checkbox("Ring Modulation",&ringMod)) ins->c64.ringMod=ringMod; + bool oscSync=ins->c64.oscSync; + if (ImGui::Checkbox("Oscillator Sync",&oscSync)) ins->c64.oscSync=oscSync; + + ImGui::Checkbox("Enable filter",&ins->c64.toFilter); + ImGui::Checkbox("Initialize filter",&ins->c64.initFilter); + + ImGui::SliderScalar("Cutoff",ImGuiDataType_U8,&ins->c64.cut,&_ZERO,&_ONE_HUNDRED); + ImGui::SliderScalar("Resonance",ImGuiDataType_U8,&ins->c64.res,&_ZERO,&_FIFTEEN); + + ImGui::Text("Filter Mode"); + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.lp)?0.6f:0.2f,0.2f,1.0f)); + if (ImGui::Button("low")) { + ins->c64.lp=!ins->c64.lp; + } + ImGui::PopStyleColor(); + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.bp)?0.6f:0.2f,0.2f,1.0f)); + if (ImGui::Button("band")) { + ins->c64.bp=!ins->c64.bp; + } + ImGui::PopStyleColor(); + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.hp)?0.6f:0.2f,0.2f,1.0f)); + if (ImGui::Button("high")) { + ins->c64.hp=!ins->c64.hp; + } + ImGui::PopStyleColor(); + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.ch3off)?0.6f:0.2f,0.2f,1.0f)); + if (ImGui::Button("ch3off")) { + ins->c64.ch3off=!ins->c64.ch3off; + } + ImGui::PopStyleColor(); + + ImGui::Checkbox("Volume Macro is Cutoff Macro",&ins->c64.volIsCutoff); + } + // volume macro - ImGui::Separator(); - ImGui::Text("Volume Macro"); - for (int i=0; istd.volMacroLen; i++) { - asFloat[i]=ins->std.volMacro[i]; - loopIndicator[i]=(ins->std.volMacroLoop!=-1 && i>=ins->std.volMacroLoop); - } - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); - int volMax=e->getMaxVolume(); - ImGui::PlotHistogram("##IVolMacro",asFloat,ins->std.volMacroLen,0,NULL,0,volMax,ImVec2(400.0f*dpiScale,200.0f*dpiScale)); - if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { - macroDragStart=ImGui::GetItemRectMin(); - macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale); - macroDragMin=0; - macroDragMax=volMax; - macroDragLen=ins->std.volMacroLen; - macroDragActive=true; - macroDragTarget=ins->std.volMacro; - printf("Start.\n"); - } - ImGui::PlotHistogram("##IVolMacroLoop",loopIndicator,ins->std.volMacroLen,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale)); - if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { - macroLoopDragStart=ImGui::GetItemRectMin(); - macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale); - macroLoopDragLen=ins->std.volMacroLen; - macroLoopDragTarget=&ins->std.volMacroLoop; - macroLoopDragActive=true; - } - ImGui::PopStyleVar(); - if (ImGui::InputScalar("Length##IVolMacroL",ImGuiDataType_U8,&ins->std.volMacroLen,&_ONE,&_THREE)) { - if (ins->std.volMacroLen>127) ins->std.volMacroLen=127; + if (e->song.system!=DIV_SYSTEM_GB) { + ImGui::Separator(); + if ((e->song.system==DIV_SYSTEM_C64_6581 || e->song.system==DIV_SYSTEM_C64_8580) && ins->c64.volIsCutoff) { + ImGui::Text("Relative Cutoff Macro"); + } else { + ImGui::Text("Volume Macro"); + } + for (int i=0; istd.volMacroLen; i++) { + if ((e->song.system==DIV_SYSTEM_C64_6581 || e->song.system==DIV_SYSTEM_C64_8580) && ins->c64.volIsCutoff) { + asFloat[i]=ins->std.volMacro[i]-18; + } else { + asFloat[i]=ins->std.volMacro[i]; + } + loopIndicator[i]=(ins->std.volMacroLoop!=-1 && i>=ins->std.volMacroLoop); + } + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); + int volMax=e->getMaxVolume(); + if (e->song.system==DIV_SYSTEM_C64_6581 || e->song.system==DIV_SYSTEM_C64_8580) { + if (ins->c64.volIsCutoff) volMax=36; + } + ImGui::PlotHistogram("##IVolMacro",asFloat,ins->std.volMacroLen,0,NULL,0,volMax,ImVec2(400.0f*dpiScale,200.0f*dpiScale)); + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { + macroDragStart=ImGui::GetItemRectMin(); + macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale); + macroDragMin=0; + macroDragMax=volMax; + macroDragLen=ins->std.volMacroLen; + macroDragActive=true; + macroDragTarget=ins->std.volMacro; + } + ImGui::PlotHistogram("##IVolMacroLoop",loopIndicator,ins->std.volMacroLen,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale)); + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { + macroLoopDragStart=ImGui::GetItemRectMin(); + macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale); + macroLoopDragLen=ins->std.volMacroLen; + macroLoopDragTarget=&ins->std.volMacroLoop; + macroLoopDragActive=true; + } + ImGui::PopStyleVar(); + if (ImGui::InputScalar("Length##IVolMacroL",ImGuiDataType_U8,&ins->std.volMacroLen,&_ONE,&_THREE)) { + if (ins->std.volMacroLen>127) ins->std.volMacroLen=127; + } } // arp macro ImGui::Separator(); ImGui::Text("Arpeggio Macro"); + bool arpMode=ins->std.arpMacroMode; for (int i=0; istd.arpMacroLen; i++) { - asFloat[i]=ins->std.arpMacro[i]; + asFloat[i]=arpMode?ins->std.arpMacro[i]:(ins->std.arpMacro[i]-12); + loopIndicator[i]=(ins->std.arpMacroLoop!=-1 && i>=ins->std.arpMacroLoop); } ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); - ImGui::PlotHistogram("##IArpMacro",asFloat,ins->std.arpMacroLen,0,NULL,-92,82,ImVec2(400.0f*dpiScale,200.0f*dpiScale)); + ImGui::PlotHistogram("##IArpMacro",asFloat,ins->std.arpMacroLen,0,NULL,arpMode?arpMacroScroll:(arpMacroScroll-12),arpMacroScroll+(arpMode?24:12),ImVec2(400.0f*dpiScale,200.0f*dpiScale)); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { macroDragStart=ImGui::GetItemRectMin(); macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale); - macroDragMin=-92; - macroDragMax=82; + macroDragMin=arpMacroScroll; + macroDragMax=arpMacroScroll+24; macroDragLen=ins->std.arpMacroLen; macroDragActive=true; macroDragTarget=ins->std.arpMacro; - printf("Start.\n"); + } + ImGui::SameLine(); + ImGui::VSliderInt("##IArpMacroPos",ImVec2(20.0f*dpiScale,200.0f*dpiScale),&arpMacroScroll,arpMode?0:-80,70); + ImGui::PlotHistogram("##IArpMacroLoop",loopIndicator,ins->std.arpMacroLen,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale)); + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { + macroLoopDragStart=ImGui::GetItemRectMin(); + macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale); + macroLoopDragLen=ins->std.arpMacroLen; + macroLoopDragTarget=&ins->std.arpMacroLoop; + macroLoopDragActive=true; } ImGui::PopStyleVar(); if (ImGui::InputScalar("Length##IArpMacroL",ImGuiDataType_U8,&ins->std.arpMacroLen,&_ONE,&_THREE)) { if (ins->std.arpMacroLen>127) ins->std.arpMacroLen=127; } + if (ImGui::Checkbox("Absolute",&arpMode)) { + ins->std.arpMacroMode=arpMode; + if (arpMode) { + if (arpMacroScroll<0) arpMacroScroll=0; + } + } + + // duty macro + ImGui::Separator(); + if (e->song.system==DIV_SYSTEM_C64_6581 || e->song.system==DIV_SYSTEM_C64_8580) { + ImGui::Text("Relative Duty Macro"); + } else if (e->song.system==DIV_SYSTEM_YM2610 || e->song.system==DIV_SYSTEM_YM2610_EXT) { + ImGui::Text("Noise Frequency Macro"); + } else { + ImGui::Text("Duty/Noise Mode Macro"); + } + for (int i=0; istd.dutyMacroLen; i++) { + asFloat[i]=ins->std.dutyMacro[i]; + loopIndicator[i]=(ins->std.dutyMacroLoop!=-1 && i>=ins->std.dutyMacroLoop); + } + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); + int dutyMax=e->getMaxDuty();; + ImGui::PlotHistogram("##IDutyMacro",asFloat,ins->std.dutyMacroLen,0,NULL,0,dutyMax,ImVec2(400.0f*dpiScale,200.0f*dpiScale)); + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { + macroDragStart=ImGui::GetItemRectMin(); + macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale); + macroDragMin=0; + macroDragMax=dutyMax; + macroDragLen=ins->std.dutyMacroLen; + macroDragActive=true; + macroDragTarget=ins->std.dutyMacro; + } + ImGui::PlotHistogram("##IDutyMacroLoop",loopIndicator,ins->std.dutyMacroLen,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale)); + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { + macroLoopDragStart=ImGui::GetItemRectMin(); + macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale); + macroLoopDragLen=ins->std.dutyMacroLen; + macroLoopDragTarget=&ins->std.dutyMacroLoop; + macroLoopDragActive=true; + } + ImGui::PopStyleVar(); + if (ImGui::InputScalar("Length##IDutyMacroL",ImGuiDataType_U8,&ins->std.dutyMacroLen,&_ONE,&_THREE)) { + if (ins->std.dutyMacroLen>127) ins->std.dutyMacroLen=127; + } + + // wave macro + ImGui::Separator(); + ImGui::Text("Waveform Macro"); + for (int i=0; istd.waveMacroLen; i++) { + asFloat[i]=ins->std.waveMacro[i]; + loopIndicator[i]=(ins->std.waveMacroLoop!=-1 && i>=ins->std.waveMacroLoop); + } + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); + int waveMax=e->getMaxWave(); + ImGui::PlotHistogram("##IWaveMacro",asFloat,ins->std.waveMacroLen,0,NULL,0,waveMax,ImVec2(400.0f*dpiScale,200.0f*dpiScale)); + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { + macroDragStart=ImGui::GetItemRectMin(); + macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale); + macroDragMin=0; + macroDragMax=waveMax; + macroDragLen=ins->std.waveMacroLen; + macroDragActive=true; + macroDragTarget=ins->std.waveMacro; + } + ImGui::PlotHistogram("##IWaveMacroLoop",loopIndicator,ins->std.waveMacroLen,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale)); + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { + macroLoopDragStart=ImGui::GetItemRectMin(); + macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale); + macroLoopDragLen=ins->std.waveMacroLen; + macroLoopDragTarget=&ins->std.waveMacroLoop; + macroLoopDragActive=true; + } + ImGui::PopStyleVar(); + if (ImGui::InputScalar("Length##IWaveMacroL",ImGuiDataType_U8,&ins->std.waveMacroLen,&_ONE,&_THREE)) { + if (ins->std.waveMacroLen>127) ins->std.waveMacroLen=127; + } } } } @@ -264,7 +458,7 @@ bool FurnaceGUI::init() { SDL_GetDisplayDPI(SDL_GetWindowDisplayIndex(sdlWin),&dpiScaleF,NULL,NULL); dpiScale=round(dpiScaleF/96.0f); if (dpiScale<1) dpiScale=1; - SDL_SetWindowSize(sdlWin,scrW*dpiScale,scrH*dpiScale); + if (dpiScale!=1) SDL_SetWindowSize(sdlWin,scrW*dpiScale,scrH*dpiScale); sdlRend=SDL_CreateRenderer(sdlWin,-1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC|SDL_RENDERER_TARGETTEXTURE); @@ -301,6 +495,7 @@ FurnaceGUI::FurnaceGUI(): dpiScale(1), curIns(0), curOctave(3), + arpMacroScroll(0), macroDragStart(0,0), macroDragAreaSize(0,0), macroDragTarget(NULL), diff --git a/src/gui/gui.h b/src/gui/gui.h index 45af21cd3..6e327d494 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -21,6 +21,8 @@ class FurnaceGUI { int curIns, curOctave; + int arpMacroScroll; + ImVec2 macroDragStart; ImVec2 macroDragAreaSize; int* macroDragTarget;