/** * Furnace Tracker - multi-system chiptune tracker * Copyright (C) 2021-2025 tildearrow and contributors * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define _USE_MATH_DEFINES #include "gui.h" #include "../ta-log.h" #include "imgui_internal.h" #include "../engine/macroInt.h" // i don't know whether this is the right thing to do #include "../engine/platform/sound/sid3.h" #include "IconsFontAwesome4.h" #include "furIcons.h" #include "misc/cpp/imgui_stdlib.h" #include "guiConst.h" #include "intConst.h" #include #include #include "plot_nolerp.h" #include "util.h" extern "C" { #include "../../extern/Nuked-OPLL/opll.h" } const char* ssgEnvTypes[8]={ _N("Down Down Down"), _N("Down."), _N("Down Up Down Up"), _N("Down UP"), _N("Up Up Up"), _N("Up."), _N("Up Down Up Down"), _N("Up DOWN") }; const char* fmParamNames[3][33]={ {_N("Algorithm"), _N("Feedback"), _N("LFO > Freq"), _N("LFO > Amp"), _N("Attack"), _N("Decay"), _N("Decay 2"), _N("Release"), _N("Sustain"), _N("Level"), _N("EnvScale"), _N("Multiplier"), _N("Detune"), _N("Detune 2"), _N("SSG-EG"), _N("AM"), _N("AM Depth"), _N("Vibrato Depth"), _N("Sustained"), _N("Sustained"), _N("Level Scaling"), _N("Sustain"), _N("Vibrato"), _N("Waveform"), _N("Scale Rate"), _N("OP2 Half Sine"), _N("OP1 Half Sine"), _N("EnvShift"), _N("Reverb"), _N("Fine"), _N("LFO2 > Freq"), _N("LFO2 > Amp"), _N("Octave")}, {"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "SR", "RR", "SL", "TL", "KS", "MULT", "DT", "DT2", "SSG-EG", "AM", "AMD", "FMD", "EGT", "EGT", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS/PMS2", "AMS2", "Block"}, {"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "D2R", "RR", "SL", "TL", "RS", "MULT", "DT", "DT2", "SSG-EG", "AM", "DAM", "DVB", "EGT", "EGS", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS/PMS2", "AMS2", "Block"} }; const char* esfmParamLongNames[9]={ _N("OP4 Noise Mode"), _N("Envelope Delay"), _N("Output Level"), _N("Modulation Input Level"), _N("Left Output"), _N("Right Output"), _N("Coarse Tune (semitones)"), _N("Detune"), _N("Fixed Frequency Mode") }; const char* esfmParamNames[9]={ _N("OP4 Noise Mode"), _N("Env. Delay"), _N("Output Level"), _N("ModInput"), _N("Left"), _N("Right"), _N("Tune"), _N("Detune"), _N("Fixed") }; const char* esfmParamShortNames[9]={ "NOI", "DL", "OL", "MI", "L", "R", "CT", "DT", "FIX" }; const char* fmParamShortNames[3][32]={ {"ALG", "FB", "FMS", "AMS", "A", "D", "D2", "R", "S", "TL", "RS", "ML", "DT", "DT2", "SSG", "AM", "DAM", "DVB", "SUS", "SUS", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS2", "AMS2"}, {"ALG", "FB", "FMS", "AMS", "A", "D", "SR", "R", "S", "TL", "KS", "ML", "DT", "DT2", "SSG", "AM", "AMD", "FMD", "EGT", "EGT", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS2", "AMS2"}, {"ALG", "FB", "FMS", "AMS", "A", "D", "D2", "R", "S", "TL", "RS", "ML", "DT", "DT2", "SSG", "AM", "DAM", "DVB", "EGT", "EGS", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS2", "AMS2"} }; const char* opllVariants[4]={ "OPLL", "YMF281", "YM2423", "VRC7" }; const char* opllInsNames[4][17]={ /* YM2413 */ { _N("User"), _N("1. Violin"), _N("2. Guitar"), _N("3. Piano"), _N("4. Flute"), _N("5. Clarinet"), _N("6. Oboe"), _N("7. Trumpet"), _N("8. Organ"), _N("9. Horn"), _N("10. Synth"), _N("11. Harpsichord"), _N("12. Vibraphone"), _N("13. Synth Bass"), _N("14. Acoustic Bass"), _N("15. Electric Guitar"), _N("Drums") }, /* YMF281 */ { _N("User"), _N("1. Electric String"), _N("2. Bow wow"), _N("3. Electric Guitar"), _N("4. Organ"), _N("5. Clarinet"), _N("6. Saxophone"), _N("7. Trumpet"), _N("8. Street Organ"), _N("9. Synth Brass"), _N("10. Electric Piano"), _N("11. Bass"), _N("12. Vibraphone"), _N("13. Chime"), _N("14. Tom Tom II"), _N("15. Noise"), _N("Drums") }, /* YM2423 */ { _N("User"), _N("1. Strings"), _N("2. Guitar"), _N("3. Electric Guitar"), _N("4. Electric Piano"), _N("5. Flute"), _N("6. Marimba"), _N("7. Trumpet"), _N("8. Harmonica"), _N("9. Tuba"), _N("10. Synth Brass"), _N("11. Short Saw"), _N("12. Vibraphone"), _N("13. Electric Guitar 2"), _N("14. Synth Bass"), _N("15. Sitar"), _N("Drums") }, // stolen from FamiTracker /* VRC7 */ { _N("User"), _N("1. Bell"), _N("2. Guitar"), _N("3. Piano"), _N("4. Flute"), _N("5. Clarinet"), _N("6. Rattling Bell"), _N("7. Trumpet"), _N("8. Reed Organ"), _N("9. Soft Bell"), _N("10. Xylophone"), _N("11. Vibraphone"), _N("12. Brass"), _N("13. Bass Guitar"), _N("14. Synth"), _N("15. Chorus"), _N("Drums") } }; const char* oplWaveforms[8]={ _N("Sine"), _N("Half Sine"), _N("Absolute Sine"), _N("Quarter Sine"), _N("Squished Sine"), _N("Squished AbsSine"), _N("Square"), _N("Derived Square") }; const char* oplWaveformsStandard[8]={ _N("Sine"), _N("Half Sine"), _N("Absolute Sine"), _N("Pulse Sine"), _N("Sine (Even Periods)"), _N("AbsSine (Even Periods)"), _N("Square"), _N("Derived Square") }; const char* opzWaveforms[8]={ _N("Sine"), _N("Triangle"), _N("Cut Sine"), _N("Cut Triangle"), _N("Squished Sine"), _N("Squished Triangle"), _N("Squished AbsSine"), _N("Squished AbsTriangle") }; const char* oplDrumNames[4]={ _N("Snare"), _N("Tom"), _N("Top"), _N("HiHat") }; const char* esfmNoiseModeNames[4]={ _N("Normal"), _N("Snare"), _N("HiHat"), _N("Top") }; const char* esfmNoiseModeDescriptions[4]={ _N("Noise disabled"), _N("Square + noise"), _N("Ringmod from OP3 + noise"), _N("Ringmod from OP3 + double pitch ModInput\nWARNING - has emulation issues; subject to change") }; const char* sid2WaveMixModes[5]={ _N("8580 SID"), _N("Bitwise AND"), _N("Bitwise OR"), _N("Bitwise XOR"), NULL }; const char* sid2ControlBits[4]={ _N("gate"), _N("sync"), _N("ring"), NULL }; const char* sid3ControlBits[4]={ _N("phase"), _N("sync"), _N("ring"), NULL }; const char* sid3WaveMixModes[6]={ _N("8580 SID"), _N("Bitwise AND"), _N("Bitwise OR"), _N("Bitwise XOR"), _N("Sum of the signals"), NULL }; const char* sid3SpecialWaveforms[]={ _N("Sine"), _N("Rect. Sine"), _N("Abs. Sine"), _N("Quart. Sine"), _N("Squish. Sine"), _N("Abs. Squish. Sine"), _N("Rect. Saw"), _N("Abs. Saw"), _N("Cubed Saw"), _N("Rect. Cubed Saw"), _N("Abs. Cubed Saw"), _N("Cubed Sine"), _N("Rect. Cubed Sine"), _N("Abs. Cubed Sine"), _N("Quart. Cubed Sine"), _N("Squish. Cubed Sine"), _N("Squish. Abs. Cub. Sine"), _N("Rect. Triangle"), _N("Abs. Triangle"), _N("Quart. Triangle"), _N("Squish. Triangle"), _N("Abs. Squish. Triangle"), _N("Cubed Triangle"), _N("Rect. Cubed Triangle"), _N("Abs. Cubed Triangle"), _N("Quart. Cubed Triangle"), _N("Squish. Cubed Triangle"), _N("Squish. Abs. Cub. Triangle"), // clipped _N("Clipped Sine"), _N("Clipped Rect. Sine"), _N("Clipped Abs. Sine"), _N("Clipped Quart. Sine"), _N("Clipped Squish. Sine"), _N("Clipped Abs. Squish. Sine"), _N("Clipped Rect. Saw"), _N("Clipped Abs. Saw"), _N("Clipped Cubed Saw"), _N("Clipped Rect. Cubed Saw"), _N("Clipped Abs. Cubed Saw"), _N("Clipped Cubed Sine"), _N("Clipped Rect. Cubed Sine"), _N("Clipped Abs. Cubed Sine"), _N("Clipped Quart. Cubed Sine"), _N("Clipped Squish. Cubed Sine"), _N("Clipped Squish. Abs. Cub. Sine"), _N("Clipped Rect. Triangle"), _N("Clipped Abs. Triangle"), _N("Clipped Quart. Triangle"), _N("Clipped Squish. Triangle"), _N("Clipped Abs. Squish. Triangle"), _N("Clipped Cubed Triangle"), _N("Clipped Rect. Cubed Triangle"), _N("Clipped Abs. Cubed Triangle"), _N("Clipped Quart. Cubed Triangle"), _N("Clipped Squish. Cubed Triangle"), _N("Clipped Squish. Abs. Cub. Triangle"), // two clipped simple waves _N("Clipped Triangle"), _N("Clipped Saw") }; const bool opIsOutput[8][4]={ {false,false,false,true}, {false,false,false,true}, {false,false,false,true}, {false,false,false,true}, {false,true,false,true}, {false,true,true,true}, {false,true,true,true}, {true,true,true,true} }; const bool opIsOutputOPL[4][4]={ {false,false,false,true}, {true,false,false,true}, {false,true,false,true}, {true,false,true,true} }; enum FMParams { FM_ALG=0, FM_FB=1, FM_FMS=2, FM_AMS=3, FM_AR=4, FM_DR=5, FM_D2R=6, FM_RR=7, FM_SL=8, FM_TL=9, FM_RS=10, FM_MULT=11, FM_DT=12, FM_DT2=13, FM_SSG=14, FM_AM=15, FM_DAM=16, FM_DVB=17, FM_EGT=18, FM_EGS=19, FM_KSL=20, FM_SUS=21, FM_VIB=22, FM_WS=23, FM_KSR=24, FM_DC=25, FM_DM=26, FM_EGSHIFT=27, FM_REV=28, FM_FINE=29, FM_FMS2=30, FM_AMS2=31, FM_BLOCK=32 }; enum ESFMParams { ESFM_NOISE=0, ESFM_DELAY=1, ESFM_OUTLVL=2, ESFM_MODIN=3, ESFM_LEFT=4, ESFM_RIGHT=5, ESFM_CT=6, ESFM_DT=7, ESFM_FIXED=8 }; #define FM_NAME(x) _(fmParamNames[settings.fmNames][x]) #define FM_SHORT_NAME(x) fmParamShortNames[settings.fmNames][x] #define ESFM_LONG_NAME(x) _(esfmParamLongNames[x]) #define ESFM_NAME(x) _(esfmParamNames[x]) #define ESFM_SHORT_NAME(x) (esfmParamShortNames[x]) const char* macroTypeLabels[4]={ ICON_FA_BAR_CHART "##IMacroType", ICON_FUR_ADSR "##IMacroType", ICON_FUR_TRI "##IMacroType", ICON_FA_SIGN_OUT "##IMacroType" }; const char* macroLFOShapes[4]={ _N("Triangle"), _N("Saw"), _N("Square"), _N("How did you even") }; const char* fmOperatorBits[5]={ "op1", "op2", "op3", "op4", NULL }; const char* c64ShapeBits[5]={ _N("triangle"), _N("saw"), _N("pulse"), _N("noise"), NULL }; const char* ayShapeBits[4]={ _N("tone"), _N("noise"), _N("envelope"), NULL }; const char* sid3ShapeBits[6]={ _N("triangle"), _N("saw"), _N("pulse"), _N("noise"), _N("special wave"), NULL }; const char* sid3FilterMatrixBits[5]={ _N("From filter 1"), _N("From filter 2"), _N("From filter 3"), _N("From filter 4"), NULL }; const char* ayEnvBits[4]={ _N("hold"), _N("alternate"), _N("direction"), _N("enable") }; const char* ssgEnvBits[5]={ "0", "1", "2", _N("enabled"), NULL }; const char* saaEnvBits[9]={ _N("mirror"), _N("loop"), _N("cut"), _N("direction"), _N("resolution"), _N("fixed"), _N("N/A"), _N("enabled"), NULL }; const char* snesModeBits[6]={ _N("noise"), _N("echo"), _N("pitch mod"), _N("invert right"), _N("invert left"), NULL }; const char* filtModeBits[5]={ _N("low"), _N("band"), _N("high"), _N("ch3off"), NULL }; const char* c64TestGateBits[5]={ _N("gate"), _N("sync"), _N("ring"), _N("test"), NULL }; const char* pokeyCtlBits[9]={ _N("15KHz"), _N("filter 2+4"), _N("filter 1+3"), _N("16-bit 3+4"), _N("16-bit 1+2"), _N("high3"), _N("high1"), _N("poly9"), NULL }; const char* mikeyFeedbackBits[11]={ "0", "1", "2", "3", "4", "5", "7", "10", "11", "int", NULL }; const char* msm5232ControlBits[7]={ _N("16'"), _N("8'"), _N("4'"), _N("2'"), _N("sustain"), NULL }; const char* tedControlBits[3]={ _N("square"), _N("noise"), NULL }; const char* c219ControlBits[4]={ _N("noise"), _N("invert"), _N("surround"), NULL }; const char* x1_010EnvBits[8]={ _N("enable"), _N("oneshot"), _N("split L/R"), _N("HinvR"), _N("VinvR"), _N("HinvL"), _N("VinvL"), NULL }; const char* suControlBits[5]={ _N("ring mod"), _N("low pass"), _N("high pass"), _N("band pass"), NULL }; const char* es5506FilterModes[4]={ "HP/K2, HP/K2", "HP/K2, LP/K1", "LP/K2, LP/K2", "LP/K2, LP/K1", }; const char* powerNoiseControlBits[3]={ _N("enable tap B"), _N("AM with slope"), NULL }; const char* powerNoiseSlopeControlBits[7]={ _N("invert B"), _N("invert A"), _N("reset B"), _N("reset A"), _N("clip B"), _N("clip A"), NULL }; const char* daveControlBits[5]={ _N("high pass"), _N("ring mod"), _N("swap counters (noise)"), _N("low pass (noise)"), NULL }; const char* panBits[5]={ _N("right"), _N("left"), _N("rear right"), _N("rear left"), NULL }; const char* oneBit[2]={ _N("on"), NULL }; const char* es5506EnvelopeModes[3]={ _N("k1 slowdown"), _N("k2 slowdown"), NULL }; const char* es5506ControlModes[3]={ _N("pause"), _N("reverse"), NULL }; const char* minModModeBits[3]={ _N("invert right"), _N("invert left"), NULL }; const int orderedOps[4]={ 0, 2, 1, 3 }; const char* singleWSEffects[7]={ _N("None"), _N("Invert"), _N("Add"), _N("Subtract"), _N("Average"), _N("Phase"), _N("Chorus") }; const char* dualWSEffects[9]={ _N("None (dual)"), _N("Wipe"), _N("Fade"), _N("Fade (ping-pong)"), _N("Overlay"), _N("Negative Overlay"), _N("Slide"), _N("Mix Chorus"), _N("Phase Modulation") }; const char* gbHWSeqCmdTypes[6]={ _N("Envelope"), _N("Sweep"), _N("Wait"), _N("Wait for Release"), _N("Loop"), _N("Loop until Release") }; const char* suHWSeqCmdTypes[7]={ _N("Volume Sweep"), _N("Frequency Sweep"), _N("Cutoff Sweep"), _N("Wait"), _N("Wait for Release"), _N("Loop"), _N("Loop until Release") }; const char* snesGainModes[5]={ _N("Direct"), _N("Decrease (linear)"), _N("Decrease (logarithmic)"), _N("Increase (linear)"), _N("Increase (bent line)") }; const int detuneMap[2][8]={ {-3, -2, -1, 0, 1, 2, 3, 4}, { 7, 6, 5, 0, 1, 2, 3, 4} }; const int detuneUnmap[2][11]={ {0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0}, {0, 0, 0, 3, 4, 5, 6, 7, 2, 1, 0} }; const int kslMap[4]={ 0, 2, 1, 3 }; const int _SID3_SPECIAL_WAVES=SID3_NUM_SPECIAL_WAVES-1; const int _SID3_NUM_CHANNELS=SID3_NUM_CHANNELS; const int _SID3_NUM_CHANNELS_MINUS_ONE=SID3_NUM_CHANNELS-1; // do not change these! // anything other than a checkbox will look ugly! // // if you really need to, and have a good rationale (and by good I mean a VERY // good one), please tell me and we'll sort it out. const char* macroAbsoluteMode="Fixed"; const char* macroRelativeMode="Relative"; const char* macroQSoundMode="QSound"; const char* macroDummyMode="Bug"; String macroHoverNote(int id, float val, void* u) { int* macroVal=(int*)u; if ((macroVal[id]&0xc0000000)==0x40000000 || (macroVal[id]&0xc0000000)==0x80000000) { if (val<-60 || val>=120) return "???"; return fmt::sprintf("%d: %s",id,noteNames[(int)val+60]); } return fmt::sprintf("%d: %d",id,(int)val); } String macroHover(int id, float val, void* u) { return fmt::sprintf("%d: %d",id,(int)val); } String macroHoverLoop(int id, float val, void* u) { if (val>1) return _("Release"); if (val>0) return _("Loop"); return ""; } String macroHoverBit30(int id, float val, void* u) { if (val>0) return _("Fixed"); return _("Relative"); } String macroHoverGain(int id, float val, void* u) { if (val>=224.0f) { return fmt::sprintf(_("%d: +%d (exponential)"),id,(int)(val-224)); } if (val>=192.0f) { return fmt::sprintf(_("%d: +%d (linear)"),id,(int)(val-192)); } if (val>=160.0f) { return fmt::sprintf(_("%d: -%d (exponential)"),id,(int)(val-160)); } if (val>=128.0f) { return fmt::sprintf(_("%d: -%d (linear)"),id,(int)(val-128)); } return fmt::sprintf(_("%d: %d (direct)"),id,(int)val); } String macroHoverES5506FilterMode(int id, float val, void* u) { String mode="???"; switch (((int)val)&3) { case 0: mode=_("HP/K2, HP/K2"); break; case 1: mode=_("HP/K2, LP/K1"); break; case 2: mode=_("LP/K2, LP/K2"); break; case 3: mode=_("LP/K2, LP/K1"); break; default: break; } return fmt::sprintf("%d: %s",id,mode); } String macroLFOWaves(int id, float val, void* u) { switch (((int)val)&3) { case 0: return _("Saw"); case 1: return _("Square"); case 2: return _("Triangle"); case 3: return _("Random"); default: return "???"; } return "???"; } String macroSID3SpecialWaves(int id, float val, void* u) { if ((int)val<0 || (int)val>=SID3_NUM_SPECIAL_WAVES) return "???"; return _(sid3SpecialWaveforms[(int)val%SID3_NUM_SPECIAL_WAVES]); } String macroSID3SourceChan(int id, float val, void* u) { if ((int)val>SID3_NUM_CHANNELS) return "???"; if ((int)val==SID3_NUM_CHANNELS) { return _("Self"); } else if ((int)val==SID3_NUM_CHANNELS-1) { return _("PCM/Wave channel"); } else { return fmt::sprintf(_("Channel %d"),(int)val+1); } } String macroSID3NoiseLFSR(int id, float val, void* u) { return _( "values close to SID2 noise modes:\n\n" "Mode 1: 524288\n" "Mode 2: 66\n" "Mode 3: 541065280" ); } String macroSID2WaveMixMode(int id, float val, void* u) { if ((int)val<0 || (int)val>3) return "???"; return _(sid2WaveMixModes[(int)val]); } String macroSID3WaveMixMode(int id, float val, void* u) { if ((int)val<0 || (int)val>4) return "???"; return _(sid3WaveMixModes[(int)val]); } void addAALine(ImDrawList* dl, const ImVec2& p1, const ImVec2& p2, const ImU32 color, float thickness=1.0f) { ImVec2 pt[2]; pt[0]=p1; pt[1]=p2; dl->AddPolyline(pt,2,color,ImDrawFlags_None,thickness); } void FurnaceGUI::drawSSGEnv(unsigned char type, const ImVec2& size) { ImDrawList* dl=ImGui::GetWindowDrawList(); ImGuiWindow* window=ImGui::GetCurrentWindow(); ImVec2 minArea=window->DC.CursorPos; ImVec2 maxArea=ImVec2( minArea.x+size.x, minArea.y+size.y ); ImRect rect=ImRect(minArea,maxArea); ImGuiStyle& style=ImGui::GetStyle(); ImU32 color=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_SSG]); ImGui::ItemSize(size,style.FramePadding.y); if (ImGui::ItemAdd(rect,ImGui::GetID("ssgEnvDisplay"))) { ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding); switch (type) { case 0: for (int i=0; i<4; i++) { ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2((float)i/4.0f,0.2)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2((float)(i+1)/4.0f,0.8)); addAALine(dl,pos1,pos2,color); pos1.x=pos2.x; if (i<3) addAALine(dl,pos1,pos2,color); } break; case 1: { ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.0,0.2)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.8)); addAALine(dl,pos1,pos2,color); pos1=ImLerp(rect.Min,rect.Max,ImVec2(1.0,0.8)); addAALine(dl,pos1,pos2,color); break; } case 2: { ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.0,0.2)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.8)); addAALine(dl,pos1,pos2,color); pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.2)); addAALine(dl,pos1,pos2,color); pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.8)); addAALine(dl,pos1,pos2,color); pos1=ImLerp(rect.Min,rect.Max,ImVec2(1.0,0.2)); addAALine(dl,pos1,pos2,color); break; } case 3: { ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.0,0.2)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.8)); addAALine(dl,pos1,pos2,color); pos1.x=pos2.x; addAALine(dl,pos1,pos2,color); pos2=ImLerp(rect.Min,rect.Max,ImVec2(1.0,0.2)); addAALine(dl,pos1,pos2,color); break; } case 4: for (int i=0; i<4; i++) { ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2((float)i/4.0f,0.8)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2((float)(i+1)/4.0f,0.2)); addAALine(dl,pos1,pos2,color); pos1.x=pos2.x; if (i<3) addAALine(dl,pos1,pos2,color); } break; case 5: { ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.0,0.8)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.2)); addAALine(dl,pos1,pos2,color); pos1=ImLerp(rect.Min,rect.Max,ImVec2(1.0,0.2)); addAALine(dl,pos1,pos2,color); break; } case 6: { ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.0,0.8)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.2)); addAALine(dl,pos1,pos2,color); pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.8)); addAALine(dl,pos1,pos2,color); pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.2)); addAALine(dl,pos1,pos2,color); pos1=ImLerp(rect.Min,rect.Max,ImVec2(1.0,0.8)); addAALine(dl,pos1,pos2,color); break; } case 7: { ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.0,0.8)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.2)); addAALine(dl,pos1,pos2,color); pos1.x=pos2.x; addAALine(dl,pos1,pos2,color); pos2=ImLerp(rect.Min,rect.Max,ImVec2(1.0,0.8)); addAALine(dl,pos1,pos2,color); break; } } } } void FurnaceGUI::drawWaveform(unsigned char type, bool opz, const ImVec2& size) { ImDrawList* dl=ImGui::GetWindowDrawList(); ImGuiWindow* window=ImGui::GetCurrentWindow(); ImVec2 waveform[65]; const size_t waveformLen=64; ImVec2 minArea=window->DC.CursorPos; ImVec2 maxArea=ImVec2( minArea.x+size.x, minArea.y+size.y ); ImRect rect=ImRect(minArea,maxArea); ImGuiStyle& style=ImGui::GetStyle(); ImU32 color=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_WAVE]); ImGui::ItemSize(size,style.FramePadding.y); if (ImGui::ItemAdd(rect,ImGui::GetID("wsDisplay"))) { ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding); if (opz) { switch (type) { case 0: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=sin(x*2.0*M_PI); waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; case 1: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=pow(sin(x*2.0*M_PI),2.0); if (x>=0.5) y=-y; waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; case 2: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=MAX(0.0,sin(x*2.0*M_PI)); waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; case 3: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=pow(MAX(0.0,sin(x*2.0*M_PI)),2.0); waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; case 4: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=(x>=0.5)?0.0:sin(x*4.0*M_PI); waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; case 5: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=(x>=0.5)?0.0:pow(sin(x*4.0*M_PI),2.0); if (x>=0.25) y=-y; waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; case 6: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=(x>=0.5)?0.0:fabs(sin(x*4.0*M_PI)); waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; case 7: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=(x>=0.5)?0.0:pow(sin(x*4.0*M_PI),2.0); waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; } } else { switch (type) { case 0: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=sin(x*2.0*M_PI); waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; case 1: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=MAX(0.0,sin(x*2.0*M_PI)); waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; case 2: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=fabs(sin(x*2.0*M_PI)); waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; case 3: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=fabs((tan(x*2.0*M_PI)>=0.0)?sin(x*2.0*M_PI):0.0); waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; case 4: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=(x>=0.5)?0.0:sin(x*4.0*M_PI); waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; case 5: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=(x>=0.5)?0.0:fabs(sin(x*4.0*M_PI)); waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; case 6: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=(x>=0.5)?-1.0:1.0; waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; case 7: for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=pow(2.0*(x-0.5),3.0); waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } break; } } dl->AddPolyline(waveform,waveformLen+1,color,ImDrawFlags_None,dpiScale); } } typedef double (*WaveFunc) (double a); WaveFunc waveFuncsIns[]={ sinus, rectSin, absSin, quartSin, squiSin, squiAbsSin, rectSaw, absSaw, cubSaw, rectCubSaw, absCubSaw, cubSine, rectCubSin, absCubSin, quartCubSin, squishCubSin, squishAbsCubSin, rectTri, absTri, quartTri, squiTri, absSquiTri, cubTriangle, cubRectTri, cubAbsTri, cubQuartTri, cubSquiTri, absCubSquiTri }; void FurnaceGUI::drawWaveformSID3(unsigned char type, const ImVec2& size) { ImDrawList* dl=ImGui::GetWindowDrawList(); ImGuiWindow* window=ImGui::GetCurrentWindow(); ImVec2 waveform[65]; const size_t waveformLen=64; ImVec2 minArea=window->DC.CursorPos; ImVec2 maxArea=ImVec2( minArea.x+size.x, minArea.y+size.y ); ImRect rect=ImRect(minArea,maxArea); ImGuiStyle& style=ImGui::GetStyle(); ImU32 color=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_WAVE]); ImGui::ItemSize(size,style.FramePadding.y); if (ImGui::ItemAdd(rect,ImGui::GetID("SID3wsDisplay"))) { ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding); if (type=SID3_NUM_UNIQUE_SPECIAL_WAVES && type1.0f) y=1.0f; if (y<-1.0f) y=-1.0f; waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.48)); } } else { if (type==SID3_NUM_UNIQUE_SPECIAL_WAVES*2) { for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=triangle(x*2.0*M_PI); y*=2.0f; // clipping if (y>1.0f) y=1.0f; if (y<-1.0f) y=-1.0f; waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } } if (type==SID3_NUM_UNIQUE_SPECIAL_WAVES*2+1) { for (size_t i=0; i<=waveformLen; i++) { float x=(float)i/(float)waveformLen; float y=saw(x*2.0*M_PI); y*=2.0f; // clipping if (y>1.0f) y=1.0f; if (y<-1.0f) y=-1.0f; waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5-y*0.4)); } } } dl->AddPolyline(waveform,waveformLen+1,color,ImDrawFlags_None,dpiScale); } } void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, const ImVec2& size) { ImDrawList* dl=ImGui::GetWindowDrawList(); ImGuiWindow* window=ImGui::GetCurrentWindow(); ImVec2 minArea=window->DC.CursorPos; ImVec2 maxArea=ImVec2( minArea.x+size.x, minArea.y+size.y ); ImRect rect=ImRect(minArea,maxArea); ImGuiStyle& style=ImGui::GetStyle(); ImU32 colorM=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_MOD]); ImU32 colorC=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_CAR]); ImU32 colorL=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ALG_LINE]); ImGui::ItemSize(size,style.FramePadding.y); if (ImGui::ItemAdd(rect,ImGui::GetID("alg"))) { ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ALG_BG]),true,style.FrameRounding); const float circleRadius=6.0f*dpiScale+1.0f; switch (algType) { case FM_ALGS_4OP: switch (alg) { case 0: { // 1 > 2 > 3 > 4 ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.2,0.5)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.4,0.5)); ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(0.6,0.5)); ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.8,0.5)); dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,colorM); dl->AddCircle(pos1,6.0f*dpiScale+1.0f,colorM); addAALine(dl,pos1,pos2,colorL); dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,colorM); addAALine(dl,pos2,pos3,colorL); dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,colorM); addAALine(dl,pos3,pos4,colorL); dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,colorC); pos1.x-=ImGui::CalcTextSize("1").x*0.5; pos2.x-=ImGui::CalcTextSize("2").x*0.5; pos3.x-=ImGui::CalcTextSize("3").x*0.5; pos4.x-=ImGui::CalcTextSize("4").x*0.5; pos1.y-=ImGui::CalcTextSize("1").y+circleRadius; pos2.y-=ImGui::CalcTextSize("2").y+circleRadius; pos3.y-=ImGui::CalcTextSize("3").y+circleRadius; pos4.y-=ImGui::CalcTextSize("4").y+circleRadius; dl->AddText(pos1,colorM,"1"); dl->AddText(pos2,colorM,"2"); dl->AddText(pos3,colorM,"3"); dl->AddText(pos4,colorC,"4"); break; } case 1: { // (1+2) > 3 > 4 ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.3)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.7)); ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.5)); ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.5)); dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,colorM); dl->AddCircle(pos1,6.0f*dpiScale+1.0f,colorM); addAALine(dl,pos1,pos3,colorL); dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,colorM); addAALine(dl,pos2,pos3,colorL); dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,colorM); addAALine(dl,pos3,pos4,colorL); dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,colorC); pos2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos1.x=pos2.x; pos3.x-=ImGui::CalcTextSize("3").x*0.5; pos4.x-=ImGui::CalcTextSize("4").x*0.5; pos1.y-=ImGui::CalcTextSize("1").y*0.5; pos2.y-=ImGui::CalcTextSize("2").y*0.5; pos3.y-=ImGui::CalcTextSize("3").y+circleRadius; pos4.y-=ImGui::CalcTextSize("4").y+circleRadius; dl->AddText(pos1,colorM,"1"); dl->AddText(pos2,colorM,"2"); dl->AddText(pos3,colorM,"3"); dl->AddText(pos4,colorC,"4"); break; } case 2: { // 1+(2>3) > 4 ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.3)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.7)); ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.7)); ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.5)); dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,colorM); dl->AddCircle(pos1,6.0f*dpiScale+1.0f,colorM); addAALine(dl,pos1,pos4,colorL); dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,colorM); addAALine(dl,pos2,pos3,colorL); dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,colorM); addAALine(dl,pos3,pos4,colorL); dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,colorC); pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos3.x-=ImGui::CalcTextSize("3").x+circleRadius+3.0*dpiScale; pos4.x-=ImGui::CalcTextSize("4").x*0.5; pos1.y-=ImGui::CalcTextSize("1").y*0.5; pos2.y-=ImGui::CalcTextSize("2").y*0.5; pos3.y-=ImGui::CalcTextSize("3").y*0.5; pos4.y-=ImGui::CalcTextSize("4").y+circleRadius; dl->AddText(pos1,colorM,"1"); dl->AddText(pos2,colorM,"2"); dl->AddText(pos3,colorM,"3"); dl->AddText(pos4,colorC,"4"); break; } case 3: { // (1>2)+3 > 4 ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.3)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.3)); ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.7)); ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.5)); dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,colorM); dl->AddCircle(pos1,6.0f*dpiScale+1.0f,colorM); addAALine(dl,pos1,pos2,colorL); dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,colorM); addAALine(dl,pos2,pos4,colorL); dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,colorM); addAALine(dl,pos3,pos4,colorL); dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,colorC); pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos3.x-=ImGui::CalcTextSize("3").x+circleRadius+3.0*dpiScale; pos4.x-=ImGui::CalcTextSize("4").x*0.5; pos1.y-=ImGui::CalcTextSize("1").y*0.5; pos2.y-=ImGui::CalcTextSize("2").y*0.5; pos3.y-=ImGui::CalcTextSize("3").y*0.5; pos4.y-=ImGui::CalcTextSize("4").y+circleRadius; dl->AddText(pos1,colorM,"1"); dl->AddText(pos2,colorM,"2"); dl->AddText(pos3,colorM,"3"); dl->AddText(pos4,colorC,"4"); break; } case 4: { // (1>2) + (3>4) ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.3)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.3)); ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.7)); ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.7)); ImVec2 pos5=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.5)); dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,colorM); dl->AddCircle(pos1,6.0f*dpiScale+1.0f,colorM); addAALine(dl,pos1,pos2,colorL); dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,colorC); dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,colorM); addAALine(dl,pos3,pos4,colorL); dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,colorC); addAALine(dl,pos2,pos5,colorL); addAALine(dl,pos4,pos5,colorL); pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos3.x-=ImGui::CalcTextSize("3").x+circleRadius+3.0*dpiScale; pos4.x-=ImGui::CalcTextSize("4").x+circleRadius+3.0*dpiScale; pos1.y-=ImGui::CalcTextSize("1").y*0.5; pos2.y-=ImGui::CalcTextSize("2").y*0.5; pos3.y-=ImGui::CalcTextSize("3").y*0.5; pos4.y-=ImGui::CalcTextSize("4").y*0.5; dl->AddText(pos1,colorM,"1"); dl->AddText(pos2,colorC,"2"); dl->AddText(pos3,colorM,"3"); dl->AddText(pos4,colorC,"4"); break; } case 5: { // 1 > (2+3+4) ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.5)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.25)); ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.5)); ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.75)); ImVec2 pos5=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.5)); dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,colorM); dl->AddCircle(pos1,6.0f*dpiScale+1.0f,colorM); addAALine(dl,pos1,pos2,colorL); addAALine(dl,pos1,pos3,colorL); addAALine(dl,pos1,pos4,colorL); dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,colorC); dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,colorC); dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,colorC); addAALine(dl,pos2,pos5,colorL); addAALine(dl,pos3,pos5,colorL); addAALine(dl,pos4,pos5,colorL); pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos3.x-=ImGui::CalcTextSize("3").x+circleRadius+3.0*dpiScale; pos4.x-=ImGui::CalcTextSize("4").x+circleRadius+3.0*dpiScale; pos1.y-=ImGui::CalcTextSize("1").y*0.5; pos2.y-=ImGui::CalcTextSize("2").y*0.5; pos3.y-=ImGui::CalcTextSize("3").y*0.5; pos4.y-=ImGui::CalcTextSize("4").y*0.5; dl->AddText(pos1,colorM,"1"); dl->AddText(pos2,colorC,"2"); dl->AddText(pos3,colorC,"3"); dl->AddText(pos4,colorC,"4"); break; } case 6: { // (1>2) + 3 + 4 ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.25)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.25)); ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.5)); ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.75)); ImVec2 pos5=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.5)); dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,colorM); dl->AddCircle(pos1,6.0f*dpiScale+1.0f,colorM); addAALine(dl,pos1,pos2,colorL); dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,colorC); dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,colorC); dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,colorC); addAALine(dl,pos2,pos5,colorL); addAALine(dl,pos3,pos5,colorL); addAALine(dl,pos4,pos5,colorL); pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos3.x-=ImGui::CalcTextSize("3").x+circleRadius+3.0*dpiScale; pos4.x-=ImGui::CalcTextSize("4").x+circleRadius+3.0*dpiScale; pos1.y-=ImGui::CalcTextSize("1").y*0.5; pos2.y-=ImGui::CalcTextSize("2").y*0.5; pos3.y-=ImGui::CalcTextSize("3").y*0.5; pos4.y-=ImGui::CalcTextSize("4").y*0.5; dl->AddText(pos1,colorM,"1"); dl->AddText(pos2,colorC,"2"); dl->AddText(pos3,colorC,"3"); dl->AddText(pos4,colorC,"4"); break; } case 7: { // 1 + 2 + 3 + 4 ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.2)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.35,0.4)); ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(0.45,0.6)); ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.55,0.8)); ImVec2 pos5=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.5)); dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,colorC); dl->AddCircle(pos1,6.0f*dpiScale+1.0f,colorC); dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,colorC); dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,colorC); dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,colorC); addAALine(dl,pos1,pos5,colorL); addAALine(dl,pos2,pos5,colorL); addAALine(dl,pos3,pos5,colorL); addAALine(dl,pos4,pos5,colorL); pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos3.x-=ImGui::CalcTextSize("3").x+circleRadius+3.0*dpiScale; pos4.x-=ImGui::CalcTextSize("4").x+circleRadius+3.0*dpiScale; pos1.y-=ImGui::CalcTextSize("1").y*0.5; pos2.y-=ImGui::CalcTextSize("2").y*0.5; pos3.y-=ImGui::CalcTextSize("3").y*0.5; pos4.y-=ImGui::CalcTextSize("4").y*0.5; dl->AddText(pos1,colorC,"1"); dl->AddText(pos2,colorC,"2"); dl->AddText(pos3,colorC,"3"); dl->AddText(pos4,colorC,"4"); break; } } break; case FM_ALGS_2OP_OPL: switch (alg) { case 0: { // 1 > 2 ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.33,0.5)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.67,0.5)); dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,colorM); dl->AddCircle(pos1,6.0f*dpiScale+1.0f,colorM); addAALine(dl,pos1,pos2,colorL); dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,colorC); pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos2.x+=circleRadius+3.0*dpiScale; pos1.y-=ImGui::CalcTextSize("1").y*0.5; pos2.y-=ImGui::CalcTextSize("2").y*0.5; dl->AddText(pos1,colorM,"1"); dl->AddText(pos2,colorC,"2"); break; } case 1: { // 1 + 2 ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.33,0.5)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.67,0.5)); dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,colorC); dl->AddCircle(pos1,6.0f*dpiScale+1.0f,colorC); dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,colorC); pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos2.x+=circleRadius+3.0*dpiScale; pos1.y-=ImGui::CalcTextSize("1").y*0.5; pos2.y-=ImGui::CalcTextSize("2").y*0.5; dl->AddText(pos1,colorC,"1"); dl->AddText(pos2,colorC,"2"); break; } } break; case FM_ALGS_4OP_OPL: switch (alg) { case 0: { // 1 > 2 > 3 > 4 ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.2,0.5)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.4,0.5)); ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(0.6,0.5)); ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.8,0.5)); dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,colorM); dl->AddCircle(pos1,6.0f*dpiScale+1.0f,colorM); addAALine(dl,pos1,pos2,colorL); dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,colorM); addAALine(dl,pos2,pos3,colorL); dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,colorM); addAALine(dl,pos3,pos4,colorL); dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,colorC); pos1.x-=ImGui::CalcTextSize("1").x*0.5; pos2.x-=ImGui::CalcTextSize("2").x*0.5; pos3.x-=ImGui::CalcTextSize("3").x*0.5; pos4.x-=ImGui::CalcTextSize("4").x*0.5; pos1.y-=ImGui::CalcTextSize("1").y+circleRadius; pos2.y-=ImGui::CalcTextSize("2").y+circleRadius; pos3.y-=ImGui::CalcTextSize("3").y+circleRadius; pos4.y-=ImGui::CalcTextSize("4").y+circleRadius; dl->AddText(pos1,colorM,"1"); dl->AddText(pos2,colorM,"2"); dl->AddText(pos3,colorM,"3"); dl->AddText(pos4,colorC,"4"); break; } case 1: { // 1 + (2 > 3 > 4) ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.4,0.3)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.2,0.7)); ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(0.4,0.7)); ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.6,0.7)); ImVec2 pos5=ImLerp(rect.Min,rect.Max,ImVec2(0.8,0.7)); dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,colorC); dl->AddCircle(pos1,6.0f*dpiScale+1.0f,colorC); addAALine(dl,pos1,pos5,colorL); dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,colorM); addAALine(dl,pos2,pos3,colorL); dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,colorM); addAALine(dl,pos3,pos4,colorL); dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,colorC); addAALine(dl,pos4,pos5,colorL); pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos3.x-=ImGui::CalcTextSize("3").x+circleRadius+3.0*dpiScale; pos4.x-=ImGui::CalcTextSize("4").x*0.5; pos1.y-=ImGui::CalcTextSize("1").y*0.5; pos2.y-=ImGui::CalcTextSize("2").y*0.5; pos3.y-=ImGui::CalcTextSize("3").y*0.5; pos4.y-=ImGui::CalcTextSize("4").y+circleRadius; dl->AddText(pos1,colorC,"1"); dl->AddText(pos2,colorM,"2"); dl->AddText(pos3,colorM,"3"); dl->AddText(pos4,colorC,"4"); break; } case 2: { // (1>2) + (3>4) ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.3)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.3)); ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.7)); ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.7)); ImVec2 pos5=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.5)); dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,colorM); dl->AddCircle(pos1,6.0f*dpiScale+1.0f,colorM); addAALine(dl,pos1,pos2,colorL); dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,colorC); dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,colorM); addAALine(dl,pos3,pos4,colorL); dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,colorC); addAALine(dl,pos2,pos5,colorL); addAALine(dl,pos4,pos5,colorL); pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos3.x-=ImGui::CalcTextSize("3").x+circleRadius+3.0*dpiScale; pos4.x-=ImGui::CalcTextSize("4").x+circleRadius+3.0*dpiScale; pos1.y-=ImGui::CalcTextSize("1").y*0.5; pos2.y-=ImGui::CalcTextSize("2").y*0.5; pos3.y-=ImGui::CalcTextSize("3").y*0.5; pos4.y-=ImGui::CalcTextSize("4").y*0.5; dl->AddText(pos1,colorM,"1"); dl->AddText(pos2,colorC,"2"); dl->AddText(pos3,colorM,"3"); dl->AddText(pos4,colorC,"4"); break; } case 3: { // 1 + (2 > 3) + 4 ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.25)); ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.25,0.5)); ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.5)); ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.5,0.75)); ImVec2 pos5=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.5)); dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,colorC); dl->AddCircle(pos1,6.0f*dpiScale+1.0f,colorC); addAALine(dl,pos2,pos3,colorL); dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,colorM); dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,colorC); dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,colorC); addAALine(dl,pos1,pos5,colorL); addAALine(dl,pos3,pos5,colorL); addAALine(dl,pos4,pos5,colorL); pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale; pos3.x-=ImGui::CalcTextSize("3").x+circleRadius+3.0*dpiScale; pos4.x-=ImGui::CalcTextSize("4").x+circleRadius+3.0*dpiScale; pos1.y-=ImGui::CalcTextSize("1").y*0.5; pos2.y-=ImGui::CalcTextSize("2").y*0.5; pos3.y-=ImGui::CalcTextSize("3").y*0.5; pos4.y-=ImGui::CalcTextSize("4").y*0.5; dl->AddText(pos1,colorC,"1"); dl->AddText(pos2,colorM,"2"); dl->AddText(pos3,colorC,"3"); dl->AddText(pos4,colorC,"4"); break; } } break; default: break; } } } void FurnaceGUI::drawESFMAlgorithm(DivInstrumentESFM& esfm, const ImVec2& size) { ImDrawList* dl=ImGui::GetWindowDrawList(); ImGuiWindow* window=ImGui::GetCurrentWindow(); ImVec2 minArea=window->DC.CursorPos; ImVec2 maxArea=ImVec2( minArea.x+size.x, minArea.y+size.y ); ImRect rect=ImRect(minArea,maxArea); ImGuiStyle& style=ImGui::GetStyle(); ImU32 colorM=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_MOD]); ImU32 colorC=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_CAR]); ImU32 colorsL[8]; for (int i=0; i<8; i++){ float alpha=(float)i/7.0f; ImVec4 color=uiColors[GUI_COLOR_FM_ALG_LINE]; color.w *= alpha; colorsL[i]=ImGui::GetColorU32(color); } ImGui::ItemSize(size,style.FramePadding.y); if (ImGui::ItemAdd(rect,ImGui::GetID("alg"))) { ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ALG_BG]),true,style.FrameRounding); const float circleRadius=6.0f*dpiScale+1.0f; //int modFb = esfm.op[0].modIn&7; int mod12 = esfm.op[1].modIn&7; int mod23 = esfm.op[2].modIn&7; int mod34 = esfm.op[3].modIn&7; int out1 = esfm.op[0].outLvl&7; int out2 = esfm.op[1].outLvl&7; int out3 = esfm.op[2].outLvl&7; int out4 = esfm.op[3].outLvl&7; bool isMod[4]; for (int i=0; i<4; i++) { DivInstrumentESFM::Operator& opE=esfm.op[i]; isMod[i]=true; if (opE.outLvl==7) isMod[i]=false; else if (opE.outLvl>0) { if (i==3) isMod[i]=false; else { DivInstrumentESFM::Operator& opENext=esfm.op[i+1]; if (opENext.modIn==0) isMod[i]=false; else if ((opE.outLvl-opENext.modIn)>=2) isMod[i]=false; } } } ImVec2 posOp1=ImLerp(rect.Min,rect.Max,ImVec2(0.2f,0.25f)); ImVec2 posOp2=ImLerp(rect.Min,rect.Max,ImVec2(0.4f,0.25f)); ImVec2 posOp3=ImLerp(rect.Min,rect.Max,ImVec2(0.6f,0.25f)); ImVec2 posOp4=ImLerp(rect.Min,rect.Max,ImVec2(0.8f,0.25f)); ImVec2 posBusbarOp1=ImLerp(rect.Min,rect.Max,ImVec2(0.2f,0.75f)); ImVec2 posBusbarOp2=ImLerp(rect.Min,rect.Max,ImVec2(0.4f,0.75f)); ImVec2 posBusbarOp3=ImLerp(rect.Min,rect.Max,ImVec2(0.6f,0.75f)); ImVec2 posBusbarOp4=ImLerp(rect.Min,rect.Max,ImVec2(0.8f,0.75f)); ImVec2 posBusbarStart=ImLerp(rect.Min,rect.Max,ImVec2(0.15f,0.75f)); ImVec2 posBusbarEnd=ImLerp(rect.Min,rect.Max,ImVec2(0.85f,0.75f)); bool busbarStartSeen=false; for (int i=0; i<4; i++) { DivInstrumentESFM::Operator& opE=esfm.op[i]; if (opE.outLvl>0) { if (!busbarStartSeen) { busbarStartSeen=true; posBusbarStart=ImLerp(rect.Min,rect.Max,ImVec2(0.15f+0.2f*i,0.75f)); } posBusbarEnd=ImLerp(rect.Min,rect.Max,ImVec2(0.25f+0.2f*i,0.75f)); } } if (mod12) addAALine(dl,posOp1,posOp2,colorsL[mod12]); if (mod23) addAALine(dl,posOp2,posOp3,colorsL[mod23]); if (mod34) addAALine(dl,posOp3,posOp4,colorsL[mod34]); if (out1) addAALine(dl,posOp1,posBusbarOp1,colorsL[out1]); if (out2) addAALine(dl,posOp2,posBusbarOp2,colorsL[out2]); if (out3) addAALine(dl,posOp3,posBusbarOp3,colorsL[out3]); if (out4) addAALine(dl,posOp4,posBusbarOp4,colorsL[out4]); addAALine(dl,posBusbarStart,posBusbarEnd,colorsL[2]); // addAALine(dl,posBusbarEnd,posBusbarEnd+ImVec2(-8.0f*dpiScale,-4.0f*dpiScale),colorsL[2]); // addAALine(dl,posBusbarEnd,posBusbarEnd+ImVec2(-8.0f*dpiScale,4.0f*dpiScale),colorsL[2]); // addAALine(dl,posBusbarStart+ImVec2(4.0f*dpiScale,-4.0f*dpiScale),posBusbarStart+ImVec2(4.0f*dpiScale,4.0f*dpiScale),colorsL[2]); dl->AddCircle(posOp1,6.0f*dpiScale+1.0f,isMod[0]?colorM:colorC); dl->AddCircleFilled(posOp1,4.0f*dpiScale+1.0f,isMod[0]?colorM:colorC); dl->AddCircleFilled(posOp2,4.0f*dpiScale+1.0f,isMod[1]?colorM:colorC); dl->AddCircleFilled(posOp3,4.0f*dpiScale+1.0f,isMod[2]?colorM:colorC); dl->AddCircleFilled(posOp4,4.0f*dpiScale+1.0f,isMod[3]?colorM:colorC); posOp1.x-=ImGui::CalcTextSize("1").x+circleRadius+3.0f*dpiScale; posOp2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0f*dpiScale; posOp3.x-=ImGui::CalcTextSize("3").x+circleRadius+3.0f*dpiScale; posOp4.x-=ImGui::CalcTextSize("4").x+circleRadius+3.0f*dpiScale; posOp1.y-=ImGui::CalcTextSize("1").y*0.5f; posOp2.y-=ImGui::CalcTextSize("2").y*0.5f; posOp3.y-=ImGui::CalcTextSize("3").y*0.5f; posOp4.y-=ImGui::CalcTextSize("4").y*0.5f; dl->AddText(posOp1,isMod[0]?colorM:colorC,"1"); dl->AddText(posOp2,isMod[1]?colorM:colorC,"2"); dl->AddText(posOp3,isMod[2]?colorM:colorC,"3"); dl->AddText(posOp4,isMod[3]?colorM:colorC,"4"); } } void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, unsigned char sus, unsigned char egt, unsigned char algOrGlobalSus, float maxTl, float maxArDr, float maxRr, const ImVec2& size, unsigned short instType) { ImDrawList* dl=ImGui::GetWindowDrawList(); ImGuiWindow* window=ImGui::GetCurrentWindow(); ImVec2 minArea=window->DC.CursorPos; ImVec2 maxArea=ImVec2( minArea.x+size.x, minArea.y+size.y ); ImRect rect=ImRect(minArea,maxArea); ImGuiStyle& style=ImGui::GetStyle(); ImU32 color=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ENVELOPE]); ImU32 colorR=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ENVELOPE_RELEASE]); // Relsease triangle ImU32 colorS=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ENVELOPE_SUS_GUIDE]); // Sustain horiz/vert line color ImGui::ItemSize(size,style.FramePadding.y); if (ImGui::ItemAdd(rect,ImGui::GetID("fmEnv"))) { ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding); //Adjust for OPLL global sustain setting if (instType==DIV_INS_OPLL && algOrGlobalSus==1.0){ rr = 5.0; } //calculate x positions float arPos=float(maxArDr-ar)/maxArDr; //peak of AR, start of DR float drPos=arPos+((sl/15.0)*(float(maxArDr-dr)/maxArDr)); //end of DR, start of D2R float d2rPos=drPos+(((15.0-sl)/15.0)*(float(31.0-d2r)/31.0)); //End of D2R float rrPos=(float(maxRr-rr)/float(maxRr)); //end of RR //shrink all the x positions horizontally arPos/=2.0; drPos/=2.0; d2rPos/=2.0; rrPos/=1.0; ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.0,1.0)); //the bottom corner ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(arPos,(tl/maxTl))); //peak of AR, start of DR ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(drPos,(float)((tl/maxTl)+(sl/15.0)-((tl/maxTl)*(sl/15.0))))); //end of DR, start of D2R ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(d2rPos,1.0)); //end of D2R ImVec2 posRStart=ImLerp(rect.Min,rect.Max,ImVec2(0.0,(tl/maxTl))); //release start ImVec2 posREnd=ImLerp(rect.Min,rect.Max,ImVec2(rrPos,1.0));//release end ImVec2 posSLineHEnd=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(float)((tl/maxTl)+(sl/15.0)-((tl/maxTl)*(sl/15.0))))); //sustain horizontal line end ImVec2 posSLineVEnd=ImLerp(rect.Min,rect.Max,ImVec2(drPos,1.0)); //sustain vertical line end ImVec2 posDecayRate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(tl/maxTl))); //Height of the peak of AR, forever ImVec2 posDecay2Rate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(float)((tl/maxTl)+(sl/15.0)-((tl/maxTl)*(sl/15.0))))); //Height of the peak of SR, forever //dl->Flags=ImDrawListFlags_AntiAliasedLines|ImDrawListFlags_AntiAliasedLinesUseTex; if (ar==0.0) { //if AR = 0, the envelope never starts dl->AddTriangleFilled(posRStart,posREnd,pos1,colorS); //draw release as shaded triangle behind everything addAALine(dl,pos1,pos4,color); //draw line on ground } else if (dr==0.0 && sl!=0.0) { //if DR = 0 and SL is not 0, then the envelope stays at max volume forever dl->AddTriangleFilled(posRStart,posREnd,pos1,colorS); //draw release as shaded triangle behind everything //addAALine(dl,pos3,posSLineHEnd,colorS); //draw horiz line through sustain level //addAALine(dl,pos3,posSLineVEnd,colorS); //draw vert. line through sustain level addAALine(dl,pos1,pos2,color); //A addAALine(dl,pos2,posDecayRate0Pt,color); //Line from A to end of graph } else if (d2r==0.0 || ((instType==DIV_INS_OPL || instType==DIV_INS_SNES || instType==DIV_INS_ESFM) && sus==1.0) || (instType==DIV_INS_OPLL && egt!=0.0)) { //envelope stays at the sustain level forever dl->AddTriangleFilled(posRStart,posREnd,pos1,colorS); //draw release as shaded triangle behind everything addAALine(dl,pos3,posSLineHEnd,colorR); //draw horiz line through sustain level addAALine(dl,pos3,posSLineVEnd,colorR); //draw vert. line through sustain level addAALine(dl,pos1,pos2,color); //A addAALine(dl,pos2,pos3,color); //D addAALine(dl,pos3,posDecay2Rate0Pt,color); //Line from D to end of graph } else { //draw graph normally dl->AddTriangleFilled(posRStart,posREnd,pos1,colorS); //draw release as shaded triangle behind everything addAALine(dl,pos3,posSLineHEnd,colorR); //draw horiz line through sustain level addAALine(dl,pos3,posSLineVEnd,colorR); //draw vert. line through sustain level addAALine(dl,pos1,pos2,color); //A addAALine(dl,pos2,pos3,color); //D addAALine(dl,pos3,pos4,color); //D2 } //dl->Flags^=ImDrawListFlags_AntiAliasedLines|ImDrawListFlags_AntiAliasedLinesUseTex; } } void FurnaceGUI::drawSID3Env(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, unsigned char sus, unsigned char egt, unsigned char algOrGlobalSus, float maxTl, float maxArDr, float maxRr, const ImVec2& size, unsigned short instType) { ImDrawList* dl=ImGui::GetWindowDrawList(); ImGuiWindow* window=ImGui::GetCurrentWindow(); ImVec2 minArea=window->DC.CursorPos; ImVec2 maxArea=ImVec2( minArea.x+size.x, minArea.y+size.y ); ImRect rect=ImRect(minArea,maxArea); ImGuiStyle& style=ImGui::GetStyle(); ImU32 color=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ENVELOPE]); ImU32 colorR=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ENVELOPE_RELEASE]); // Relsease triangle ImU32 colorS=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ENVELOPE_SUS_GUIDE]); // Sustain horiz/vert line color ImGui::ItemSize(size,style.FramePadding.y); if (ImGui::ItemAdd(rect,ImGui::GetID("fmEnv"))) { ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding); // Adjust for OPLL global sustain setting if (instType==DIV_INS_OPLL && algOrGlobalSus==1.0) { rr=5.0; } // calculate x positions float arPos=float(maxArDr-(float)ar)/maxArDr; // peak of AR, start of DR float drPos=arPos+(((float)sl/255.0)*(float(maxArDr-(float)dr)/maxArDr)); // end of DR, start of D2R float d2rPos=drPos+(((255.0-(float)sl)/255.0)*(float(255.0-(float)d2r)/255.0)); // End of D2R float rrPos=(float(maxRr-(float)rr)/float(maxRr)); // end of RR // shrink all the x positions horizontally arPos/=2.0; drPos/=2.0; d2rPos/=2.0; rrPos/=1.0; ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.0,1.0)); // the bottom corner ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(arPos,((float)tl/maxTl))); // peak of AR, start of DR ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(drPos,(float)(((float)tl/maxTl)+((float)sl/255.0)-(((float)tl/maxTl)*((float)sl/255.0))))); // end of DR, start of D2R ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(d2rPos,1.0)); // end of D2R ImVec2 posRStart=ImLerp(rect.Min,rect.Max,ImVec2(0.0,((float)tl/maxTl))); // release start ImVec2 posREnd=ImLerp(rect.Min,rect.Max,ImVec2(rrPos,1.0));// release end ImVec2 posSLineHEnd=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(float)(((float)tl/maxTl)+((float)sl/255.0)-(((float)tl/maxTl)*((float)sl/255.0))))); // sustain horizontal line end ImVec2 posSLineVEnd=ImLerp(rect.Min,rect.Max,ImVec2(drPos,1.0)); // sustain vertical line end ImVec2 posDecayRate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,((float)tl/maxTl))); // Height of the peak of AR, forever ImVec2 posDecay2Rate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(float)(((float)tl/maxTl)+((float)sl/255.0)-(((float)tl/maxTl)*((float)sl/255.0))))); // Height of the peak of SR, forever // dl->Flags=ImDrawListFlags_AntiAliasedLines|ImDrawListFlags_AntiAliasedLinesUseTex; if ((float)ar==0.0) { // if AR = 0, the envelope never starts dl->AddTriangleFilled(posRStart,posREnd,pos1,colorS); // draw release as shaded triangle behind everything addAALine(dl,pos1,pos4,color); // draw line on ground } else if ((float)dr==0.0 && (float)sl!=0.0) { // if DR = 0 and SL is not 0, then the envelope stays at max volume forever dl->AddTriangleFilled(posRStart,posREnd,pos1,colorS); // draw release as shaded triangle behind everything // addAALine(dl,pos3,posSLineHEnd,colorS); // draw horiz line through sustain level // addAALine(dl,pos3,posSLineVEnd,colorS); // draw vert. line through sustain level addAALine(dl,pos1,pos2,color); // A addAALine(dl,pos2,posDecayRate0Pt,color); // Line from A to end of graph } else if ((float)d2r==0.0 || ((instType==DIV_INS_OPL || instType==DIV_INS_SNES || instType == DIV_INS_ESFM) && sus==1.0) || (instType==DIV_INS_OPLL && egt!=0.0)) { // envelope stays at the sustain level forever dl->AddTriangleFilled(posRStart,posREnd,pos1,colorS); // draw release as shaded triangle behind everything addAALine(dl,pos3,posSLineHEnd,colorR); // draw horiz line through sustain level addAALine(dl,pos3,posSLineVEnd,colorR); // draw vert. line through sustain level addAALine(dl,pos1,pos2,color); // A addAALine(dl,pos2,pos3,color); // D addAALine(dl,pos3,posDecay2Rate0Pt,color); // Line from D to end of graph } else { // draw graph normally dl->AddTriangleFilled(posRStart,posREnd,pos1,colorS); // draw release as shaded triangle behind everything addAALine(dl,pos3,posSLineHEnd,colorR); // draw horiz line through sustain level addAALine(dl,pos3,posSLineVEnd,colorR); // draw vert. line through sustain level addAALine(dl,pos1,pos2,color); // A addAALine(dl,pos2,pos3,color); // D addAALine(dl,pos3,pos4,color); // D2 } //dl->Flags^=ImDrawListFlags_AntiAliasedLines|ImDrawListFlags_AntiAliasedLinesUseTex; } } void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char sLen, bool dir, const ImVec2& size) { ImDrawList* dl=ImGui::GetWindowDrawList(); ImGuiWindow* window=ImGui::GetCurrentWindow(); ImVec2 minArea=window->DC.CursorPos; ImVec2 maxArea=ImVec2( minArea.x+size.x, minArea.y+size.y ); ImRect rect=ImRect(minArea,maxArea); ImGuiStyle& style=ImGui::GetStyle(); ImU32 color=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ENVELOPE]); //ImU32 colorS=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ENVELOPE_SUS_GUIDE]); // Sustain horiz/vert line color ImGui::ItemSize(size,style.FramePadding.y); if (ImGui::ItemAdd(rect,ImGui::GetID("gbEnv"))) { ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding); float volY=1.0-((float)vol/15.0); float lenPos=(sLen>62)?1.0:((float)sLen/384.0); float envEndPoint=((float)len/7.0)*((float)(dir?(15-vol):vol)/15.0); ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.0,volY)); ImVec2 pos2; if (dir) { if (len>0) { if (lenPos0) { if (lenPos0 || sLen<63)?((dir && sLen>62)?0.0:1.0):volY)); addAALine(dl,pos1,pos2,color); if (lenPos>=envEndPoint && sLen<63 && dir) { pos3=ImLerp(rect.Min,rect.Max,ImVec2(lenPos,0.0)); addAALine(dl,pos2,pos3,color); ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(lenPos,1.0)); addAALine(dl,pos3,pos4,color); } else { addAALine(dl,pos2,pos3,color); } } } #define P(x) if (x) { \ MARK_MODIFIED; \ e->notifyInsChange(curIns); \ updateFMPreview=true; \ } #define PARAMETER MARK_MODIFIED; e->notifyInsChange(curIns); updateFMPreview=true; String genericGuide(float value) { return fmt::sprintf("%d",(int)value); } inline int deBit30(const int val) { if ((val&0xc0000000)==0x40000000 || (val&0xc0000000)==0x80000000) return val^0x40000000; return val; } inline bool enBit30(const int val) { if ((val&0xc0000000)==0x40000000 || (val&0xc0000000)==0x80000000) return true; return false; } void FurnaceGUI::kvsConfig(DivInstrument* ins, bool supportsKVS) { if (fmPreviewOn) { if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("left click to restart\nmiddle click to pause\nright click to see algorithm")); } if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { updateFMPreview=true; } if (ImGui::IsItemClicked(ImGuiMouseButton_Middle)) { fmPreviewPaused=!fmPreviewPaused; } } else if (supportsKVS) { if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("left click to configure TL scaling\nright click to see FM preview")); } } else { if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("right click to see FM preview")); } } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { fmPreviewOn=!fmPreviewOn; } if (ImGui::IsItemHovered() && CHECK_LONG_HOLD) { NOTIFY_LONG_HOLD; fmPreviewOn=!fmPreviewOn; } if (!fmPreviewOn && supportsKVS) { int opCount=4; if (ins->type==DIV_INS_OPLL) opCount=2; if (ins->type==DIV_INS_OPL) opCount=(ins->fm.ops==4)?4:2; if (ImGui::BeginPopupContextItem("IKVSOpt",ImGuiPopupFlags_MouseButtonLeft)) { ImGui::Text(_("operator level changes with volume?")); if (ImGui::BeginTable("KVSTable",4,ImGuiTableFlags_BordersInner)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch); for (int i=0; i<4; i++) { int o=(opCount==4 && ins->type!=DIV_INS_ESFM)?orderedOps[i]:i; if (!(i&1)) ImGui::TableNextRow(); const char* label=_("AUTO##OPKVS"); if (ins->fm.op[o].kvs==0) { label=_("NO##OPKVS"); } else if (ins->fm.op[o].kvs==1) { label=_("YES##OPKVS"); } ImGui::TableNextColumn(); ImGui::Text("%d",i+1); ImGui::TableNextColumn(); ImGui::PushID(o); if (ImGui::Button(label,ImVec2(ImGui::GetContentRegionAvail().x,0.0f))) { if (++ins->fm.op[o].kvs>2) ins->fm.op[o].kvs=0; PARAMETER; } ImGui::PopID(); } ImGui::EndTable(); } ImGui::EndPopup(); } } } void FurnaceGUI::drawFMPreview(const ImVec2& size) { float asFloat[FM_PREVIEW_SIZE]; for (int i=0; itemp.vZoom[i.macro->macroType] #define MACRO_VSCROLL i.ins->temp.vScroll[i.macro->macroType] void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float availableWidth, int index) { static float asFloat[256]; static int asInt[256]; static float loopIndicator[256]; static float bit30Indicator[256]; static bool doHighlight[256]; if ((i.macro->open&6)==0) { for (int j=0; j<256; j++) { bit30Indicator[j]=0; if (j+macroDragScroll>=i.macro->len) { asFloat[j]=0; asInt[j]=0; } else { asFloat[j]=deBit30(i.macro->val[j+macroDragScroll]); asInt[j]=deBit30(i.macro->val[j+macroDragScroll]); if (i.bit30) bit30Indicator[j]=enBit30(i.macro->val[j+macroDragScroll]); } if (j+macroDragScroll>=i.macro->len || (j+macroDragScroll>i.macro->rel && i.macro->looprel)) { loopIndicator[j]=0; } else { loopIndicator[j]=((i.macro->loop!=255 && (j+macroDragScroll)>=i.macro->loop))|((i.macro->rel!=255 && (j+macroDragScroll)==i.macro->rel)<<1); } } ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); if (MACRO_VZOOM<1) { if (i.macro->macroType==DIV_MACRO_ARP || i.isArp) { MACRO_VZOOM=24; MACRO_VSCROLL=120-12; } else if (i.macro->macroType==DIV_MACRO_PITCH || i.isPitch) { MACRO_VZOOM=128; MACRO_VSCROLL=2048-64; } else { MACRO_VZOOM=i.max-i.min; MACRO_VSCROLL=0; } } if (MACRO_VZOOM>(i.max-i.min)) { MACRO_VZOOM=i.max-i.min; } memset(doHighlight,0,256*sizeof(bool)); if (e->isRunning()) for (int j=0; jgetTotalChannelCount(); j++) { DivChannelState* chanState=e->getChanState(j); if (chanState==NULL) continue; if (chanState->keyOff) continue; if (chanState->lastIns!=curIns) continue; DivMacroInt* macroInt=e->getMacroInt(j); if (macroInt==NULL) continue; DivMacroStruct* macroStruct=macroInt->structByType(i.macro->macroType); if (macroStruct==NULL) continue; if (macroStruct->lastPos>i.macro->len) continue; if (macroStruct->lastPoslastPos>255) continue; if (!macroStruct->actualHad) continue; doHighlight[macroStruct->lastPos-macroDragScroll]=true; } if (i.isBitfield) { PlotBitfield("##IMacro",asInt,totalFit,0,i.bitfieldBits,i.max,ImVec2(availableWidth,(i.macro->open&1)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),doHighlight,uiColors[GUI_COLOR_MACRO_HIGHLIGHT],i.color,i.hoverFunc,i.hoverFuncUser); } else { PlotCustom("##IMacro",asFloat,totalFit,macroDragScroll,NULL,i.min+MACRO_VSCROLL,i.min+MACRO_VSCROLL+MACRO_VZOOM,ImVec2(availableWidth,(i.macro->open&1)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),i.color,i.macro->len-macroDragScroll,i.hoverFunc,i.hoverFuncUser,i.blockMode,(i.macro->open&1)?genericGuide:NULL,doHighlight,uiColors[GUI_COLOR_MACRO_HIGHLIGHT]); } if ((i.macro->open&1) && (ImGui::IsItemClicked(ImGuiMouseButton_Left) || ImGui::IsItemClicked(ImGuiMouseButton_Right))) { ImGui::InhibitInertialScroll(); macroDragStart=ImGui::GetItemRectMin(); macroDragAreaSize=ImVec2(availableWidth,i.height*dpiScale); if (i.isBitfield) { macroDragMin=i.min; macroDragMax=i.max; } else { macroDragMin=i.min+MACRO_VSCROLL; macroDragMax=i.min+MACRO_VSCROLL+MACRO_VZOOM; } macroDragBitMode=i.isBitfield; macroDragInitialValueSet=false; macroDragInitialValue=false; macroDragLen=totalFit; macroDragActive=true; macroDragBit30=i.bit30; macroDragSettingBit30=false; macroDragTarget=i.macro->val; macroDragChar=false; macroDragLineMode=(i.isBitfield)?false:ImGui::IsItemClicked(ImGuiMouseButton_Right); macroDragLineInitial=ImVec2(0,0); lastMacroDesc=i; processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); } if ((i.macro->open&1)) { if (ImGui::IsItemHovered()) { if (ctrlWheeling) { if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { MACRO_VZOOM+=wheelY*(1+(MACRO_VZOOM>>4)); if (MACRO_VZOOM<1) MACRO_VZOOM=1; if (MACRO_VZOOM>(i.max-i.min)) MACRO_VZOOM=i.max-i.min; if ((MACRO_VSCROLL+MACRO_VZOOM)>(i.max-i.min)) { MACRO_VSCROLL=(i.max-i.min)-MACRO_VZOOM; } } else if (settings.autoMacroStepSize==0) { macroPointSize+=wheelY; if (macroPointSize<1) macroPointSize=1; if (macroPointSize>256) macroPointSize=256; } } else if ((ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) && wheelY!=0) { MACRO_VSCROLL+=wheelY*(1+(MACRO_VZOOM>>4)); if (MACRO_VSCROLL<0) MACRO_VSCROLL=0; if (MACRO_VSCROLL>((i.max-i.min)-MACRO_VZOOM)) MACRO_VSCROLL=(i.max-i.min)-MACRO_VZOOM; } } // slider if (!i.isBitfield) { if (settings.oldMacroVSlider) { ImGui::SameLine(0.0f); if (ImGui::VSliderInt("##IMacroVScroll",ImVec2(20.0f*dpiScale,i.height*dpiScale),&MACRO_VSCROLL,0,(i.max-i.min)-MACRO_VZOOM,"",ImGuiSliderFlags_NoInput)) { if (MACRO_VSCROLL<0) MACRO_VSCROLL=0; if (MACRO_VSCROLL>((i.max-i.min)-MACRO_VZOOM)) MACRO_VSCROLL=(i.max-i.min)-MACRO_VZOOM; } if (ImGui::IsItemHovered() && ctrlWheeling) { MACRO_VSCROLL+=wheelY*(1+(MACRO_VZOOM>>4)); if (MACRO_VSCROLL<0) MACRO_VSCROLL=0; if (MACRO_VSCROLL>((i.max-i.min)-MACRO_VZOOM)) MACRO_VSCROLL=(i.max-i.min)-MACRO_VZOOM; } } else { ImS64 scrollV=(i.max-i.min-MACRO_VZOOM)-MACRO_VSCROLL; ImS64 availV=MACRO_VZOOM; ImS64 contentsV=(i.max-i.min); ImGui::SameLine(0.0f); ImGui::SetCursorPosX(ImGui::GetCursorPosX()-ImGui::GetStyle().ItemSpacing.x); ImRect scrollbarPos=ImRect(ImGui::GetCursorScreenPos(),ImGui::GetCursorScreenPos()); scrollbarPos.Max.x+=ImGui::GetStyle().ScrollbarSize; scrollbarPos.Max.y+=i.height*dpiScale; ImGui::Dummy(ImVec2(ImGui::GetStyle().ScrollbarSize,i.height*dpiScale)); if (ImGui::IsItemHovered() && ctrlWheeling) { MACRO_VSCROLL+=wheelY*(1+(MACRO_VZOOM>>4)); if (MACRO_VSCROLL<0) MACRO_VSCROLL=0; if (MACRO_VSCROLL>((i.max-i.min)-MACRO_VZOOM)) MACRO_VSCROLL=(i.max-i.min)-MACRO_VZOOM; } ImGuiID scrollbarID=ImGui::GetID("##IMacroVScroll"); ImGui::KeepAliveID(scrollbarID); if (ImGui::ScrollbarEx(scrollbarPos,scrollbarID,ImGuiAxis_Y,&scrollV,availV,contentsV,0)) { MACRO_VSCROLL=(i.max-i.min-MACRO_VZOOM)-scrollV; } } } // bit 30 area if (i.bit30) { PlotCustom("##IMacroBit30",bit30Indicator,totalFit,macroDragScroll,NULL,0,1,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),i.color,i.macro->len-macroDragScroll,¯oHoverBit30); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { ImGui::InhibitInertialScroll(); macroDragStart=ImGui::GetItemRectMin(); macroDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale); macroDragInitialValueSet=false; macroDragInitialValue=false; macroDragLen=totalFit; macroDragActive=true; macroDragBit30=i.bit30; macroDragSettingBit30=true; macroDragTarget=i.macro->val; macroDragChar=false; macroDragLineMode=false; macroDragLineInitial=ImVec2(0,0); lastMacroDesc=i; processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); } } // loop area PlotCustom("##IMacroLoop",loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),i.color,i.macro->len-macroDragScroll,¯oHoverLoop); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { ImGui::InhibitInertialScroll(); macroLoopDragStart=ImGui::GetItemRectMin(); macroLoopDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale); macroLoopDragLen=totalFit; if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { macroLoopDragTarget=&i.macro->rel; } else { macroLoopDragTarget=&i.macro->loop; } macroLoopDragActive=true; processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { ImGui::InhibitInertialScroll(); if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { i.macro->rel=255; } else { i.macro->loop=255; } } ImGui::SetNextItemWidth(availableWidth); String& mmlStr=mmlString[index]; if (ImGui::InputText("##IMacroMML",&mmlStr)) { decodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.min,(i.isBitfield)?((1<<(i.isBitfield?(i.max):0))-1):i.max,i.macro->rel,i.bit30); } if (!ImGui::IsItemActive()) { encodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.macro->rel,false,i.bit30); } } ImGui::PopStyleVar(); } else { if (i.macro->open&2) { const bool compact=(availableWidth<300.0f*dpiScale); if (ImGui::BeginTable("MacroADSR",compact?2:4)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.3); if (!compact) { ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.3); } //ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,0.4); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Bottom")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::InputInt("##MABottom",&i.macro->val[0],1,16)) { PARAMETER if (i.macro->val[0]val[0]=i.min; if (i.macro->val[0]>i.max) i.macro->val[0]=i.max; } if (compact) ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Top")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::InputInt("##MATop",&i.macro->val[1],1,16)) { PARAMETER if (i.macro->val[1]val[1]=i.min; if (i.macro->val[1]>i.max) i.macro->val[1]=i.max; } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Attack")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MAAR",&i.macro->val[2],0,255)) { PARAMETER if (i.macro->val[2]<0) i.macro->val[2]=0; if (i.macro->val[2]>255) i.macro->val[2]=255; } rightClickable if (compact) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Hold")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MAHT",&i.macro->val[3],0,255)) { PARAMETER if (i.macro->val[3]<0) i.macro->val[3]=0; if (i.macro->val[3]>255) i.macro->val[3]=255; } rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Decay")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MADR",&i.macro->val[4],0,255)) { PARAMETER if (i.macro->val[4]<0) i.macro->val[4]=0; if (i.macro->val[4]>255) i.macro->val[4]=255; } rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Sustain")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MASL",&i.macro->val[5],0,255)) { PARAMETER if (i.macro->val[5]<0) i.macro->val[5]=0; if (i.macro->val[5]>255) i.macro->val[5]=255; } rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("SusTime")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MAST",&i.macro->val[6],0,255)) { PARAMETER if (i.macro->val[6]<0) i.macro->val[6]=0; if (i.macro->val[6]>255) i.macro->val[6]=255; } rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("SusDecay")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MASR",&i.macro->val[7],0,255)) { PARAMETER if (i.macro->val[7]<0) i.macro->val[7]=0; if (i.macro->val[7]>255) i.macro->val[7]=255; } rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Release")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MARR",&i.macro->val[8],0,255)) { PARAMETER if (i.macro->val[8]<0) i.macro->val[8]=0; if (i.macro->val[8]>255) i.macro->val[8]=255; } rightClickable } else { ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Sustain")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MASL",&i.macro->val[5],0,255)) { PARAMETER if (i.macro->val[5]<0) i.macro->val[5]=0; if (i.macro->val[5]>255) i.macro->val[5]=255; } rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Hold")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MAHT",&i.macro->val[3],0,255)) { PARAMETER if (i.macro->val[3]<0) i.macro->val[3]=0; if (i.macro->val[3]>255) i.macro->val[3]=255; } rightClickable ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("SusTime")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MAST",&i.macro->val[6],0,255)) { PARAMETER if (i.macro->val[6]<0) i.macro->val[6]=0; if (i.macro->val[6]>255) i.macro->val[6]=255; } rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Decay")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MADR",&i.macro->val[4],0,255)) { PARAMETER if (i.macro->val[4]<0) i.macro->val[4]=0; if (i.macro->val[4]>255) i.macro->val[4]=255; } rightClickable ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("SusDecay")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MASR",&i.macro->val[7],0,255)) { PARAMETER if (i.macro->val[7]<0) i.macro->val[7]=0; if (i.macro->val[7]>255) i.macro->val[7]=255; } rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TableNextColumn(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Release")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MARR",&i.macro->val[8],0,255)) { PARAMETER if (i.macro->val[8]<0) i.macro->val[8]=0; if (i.macro->val[8]>255) i.macro->val[8]=255; } rightClickable } ImGui::EndTable(); } } if (i.macro->open&4) { const bool compact=(availableWidth<300.0f*dpiScale); if (ImGui::BeginTable("MacroLFO",compact?2:4)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.3); if (!compact) { ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.3); } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Bottom")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::InputInt("##MABottom",&i.macro->val[0],1,16)) { PARAMETER if (i.macro->val[0]val[0]=i.min; if (i.macro->val[0]>i.max) i.macro->val[0]=i.max; } if (compact) ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Top")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::InputInt("##MATop",&i.macro->val[1],1,16)) { PARAMETER if (i.macro->val[1]val[1]=i.min; if (i.macro->val[1]>i.max) i.macro->val[1]=i.max; } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Speed")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MLSpeed",&i.macro->val[11],0,255)) { PARAMETER if (i.macro->val[11]<0) i.macro->val[11]=0; if (i.macro->val[11]>255) i.macro->val[11]=255; } rightClickable if (compact) ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Phase")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MLPhase",&i.macro->val[13],0,1023)) { PARAMETER if (i.macro->val[13]<0) i.macro->val[13]=0; if (i.macro->val[13]>1023) i.macro->val[13]=1023; } rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Shape")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##MLShape",&i.macro->val[12],0,2,macroLFOShapes[i.macro->val[12]&3])) { PARAMETER if (i.macro->val[12]<0) i.macro->val[12]=0; if (i.macro->val[12]>2) i.macro->val[12]=2; } rightClickable ImGui::EndTable(); } } } } #define BUTTON_TO_SET_MODE(buttonType) \ if (buttonType(macroTypeLabels[(i.macro->open>>1)&3])) { \ unsigned char prevOpen=i.macro->open; \ if (i.macro->open>=4) { \ i.macro->open&=(~6); \ } else { \ i.macro->open+=2; \ } \ \ /* check whether macro type is now ADSR/LFO or sequence */ \ if (((prevOpen&6)?1:0)!=((i.macro->open&6)?1:0)) { \ /* swap memory */ \ /* this way the macro isn't corrupted if the user decides to go */ \ /* back to sequence mode */ \ i.macro->len^=i.ins->temp.lenMemory[i.macro->macroType]; \ i.ins->temp.lenMemory[i.macro->macroType]^=i.macro->len; \ i.macro->len^=i.ins->temp.lenMemory[i.macro->macroType]; \ \ for (int j=0; j<16; j++) { \ i.macro->val[j]^=i.ins->temp.typeMemory[i.macro->macroType][j]; \ i.ins->temp.typeMemory[i.macro->macroType][j]^=i.macro->val[j]; \ i.macro->val[j]^=i.ins->temp.typeMemory[i.macro->macroType][j]; \ } \ \ /* if ADSR/LFO, populate min/max */ \ if (i.macro->open&6) { \ if (i.macro->val[0]==0 && i.macro->val[1]==0) { \ i.macro->val[0]=i.min; \ i.macro->val[1]=i.max; \ } \ i.macro->val[0]=CLAMP(i.macro->val[0],i.min,i.max); \ i.macro->val[1]=CLAMP(i.macro->val[1],i.min,i.max); \ } \ } \ PARAMETER; \ } \ if (ImGui::IsItemHovered()) { \ switch (i.macro->open&6) { \ case 0: \ ImGui::SetTooltip(_("Macro type: Sequence")); \ break; \ case 2: \ ImGui::SetTooltip(_("Macro type: ADSR")); \ break; \ case 4: \ ImGui::SetTooltip(_("Macro type: LFO")); \ break; \ default: \ ImGui::SetTooltip(_("Macro type: What's going on here?")); \ break; \ } \ } \ if (i.macro->open&6) { \ i.macro->len=16; \ } #define BUTTON_TO_SET_PROPS(_x) \ pushToggleColors(_x.macro->speed!=1 || _x.macro->delay); \ ImGui::Button(ICON_FA_ELLIPSIS_H "##IMacroSet"); \ popToggleColors(); \ if (ImGui::IsItemHovered()) { \ ImGui::SetTooltip(_("Delay/Step Length")); \ } \ if (ImGui::BeginPopupContextItem("IMacroSetP",ImGuiPopupFlags_MouseButtonLeft)) { \ if (ImGui::InputScalar(_("Step Length (ticks)##IMacroSpeed"),ImGuiDataType_U8,&_x.macro->speed,&_ONE,&_THREE)) { \ if (_x.macro->speed<1) _x.macro->speed=1; \ MARK_MODIFIED; \ } \ if (ImGui::InputScalar(_("Delay##IMacroDelay"),ImGuiDataType_U8,&_x.macro->delay,&_ONE,&_THREE)) { \ MARK_MODIFIED; \ } \ ImGui::EndPopup(); \ } #define BUTTON_TO_SET_RELEASE(buttonType) \ pushToggleColors(i.macro->open&8); \ if (buttonType(ICON_FA_BOLT "##IMacroRelMode")) { \ i.macro->open^=8; \ } \ if (ImGui::IsItemHovered()) { \ if (i.macro->open&8) { \ ImGui::SetTooltip(_("Release mode: Active (jump to release pos)")); \ } else { \ ImGui::SetTooltip(_("Release mode: Passive (delayed release)")); \ } \ } \ popToggleColors(); \ void FurnaceGUI::drawMacros(std::vector& macros, FurnaceGUIMacroEditState& state, DivInstrument* ins) { int index=0; int maxMacroLen=0; float reservedSpace=(settings.oldMacroVSlider)?(20.0f*dpiScale+ImGui::GetStyle().ItemSpacing.x):ImGui::GetStyle().ScrollbarSize; for (FurnaceGUIMacroDesc& m: macros) { m.ins=ins; if (m.macro->len>maxMacroLen) maxMacroLen=m.macro->len; } switch (settings.macroLayout) { case 0: { if (ImGui::BeginTable("MacroSpace",2)) { float precalcWidth=0.0f; for (FurnaceGUIMacroDesc& i: macros) { float next=ImGui::CalcTextSize(i.displayName).x+ImGui::GetStyle().ItemInnerSpacing.x*2.0f+ImGui::CalcTextSize(ICON_FA_CHEVRON_UP).x+ImGui::GetStyle().ItemSpacing.x*2.0f; if (next>precalcWidth) precalcWidth=next; } ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,MAX(120.0f*dpiScale,precalcWidth)); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); ImGui::TableNextRow(); ImGui::TableNextColumn(); float lenAvail=ImGui::GetContentRegionAvail().x; //ImGui::Dummy(ImVec2(120.0f*dpiScale,dpiScale)); if (settings.autoMacroStepSize==0) { ImGui::SetNextItemWidth(120.0f*dpiScale); if (ImGui::InputInt("##MacroPointSize",¯oPointSize,1,4)) { if (macroPointSize<1) macroPointSize=1; if (macroPointSize>256) macroPointSize=256; } } ImGui::TableNextColumn(); float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; int totalFit=MIN(255,availableWidth/MAX(1,macroPointSize*dpiScale)); int scrollMax=0; if (settings.autoMacroStepSize!=0) totalFit=1; for (FurnaceGUIMacroDesc& i: macros) { if (i.macro->len>scrollMax) scrollMax=i.macro->len; if (settings.autoMacroStepSize==1) { if ((i.macro->open&6)==0 && totalFitlen) totalFit=i.macro->len; } else if (settings.autoMacroStepSize==2) { if ((i.macro->open&6)==0 && totalFitscrollMax) { macroDragScroll=scrollMax; } ImGui::BeginDisabled(scrollMax<1); ImGui::SetNextItemWidth(availableWidth); if (CWSliderInt("##MacroScroll",¯oDragScroll,0,scrollMax,"")) { if (macroDragScroll<0) macroDragScroll=0; if (macroDragScroll>scrollMax) macroDragScroll=scrollMax; } ImGui::EndDisabled(); // draw macros for (FurnaceGUIMacroDesc& i: macros) { ImGui::PushID(index); ImGui::TableNextRow(); // description ImGui::TableNextColumn(); ImGui::Text("%s",i.displayName); ImGui::SameLine(); if (ImGui::SmallButton((i.macro->open&1)?(ICON_FA_CHEVRON_UP "##IMacroOpen"):(ICON_FA_CHEVRON_DOWN "##IMacroOpen"))) { i.macro->open^=1; } if (i.macro->open&1) { if ((i.macro->open&6)==0) { ImGui::SetNextItemWidth(lenAvail); int macroLen=i.macro->len; if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED if (macroLen<0) macroLen=0; if (macroLen>255) macroLen=255; i.macro->len=macroLen; } } BUTTON_TO_SET_MODE(ImGui::Button); ImGui::SameLine(); BUTTON_TO_SET_PROPS(i); if ((i.macro->open&6)==0) { ImGui::SameLine(); BUTTON_TO_SET_RELEASE(ImGui::Button); } // do not change this! // anything other than a checkbox will look ugly! // if you really need more than two macro modes please tell me. if (i.modeName!=NULL) { bool modeVal=i.macro->mode; String modeName=fmt::sprintf("%s##IMacroMode",i.modeName); if (ImGui::Checkbox(modeName.c_str(),&modeVal)) { i.macro->mode=modeVal; } } } // macro area ImGui::TableNextColumn(); drawMacroEdit(i,totalFit,availableWidth,index); ImGui::PopID(); index++; } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TableNextColumn(); ImGui::BeginDisabled(scrollMax<1); ImGui::SetNextItemWidth(availableWidth); if (CWSliderInt("##MacroScroll",¯oDragScroll,0,scrollMax,"")) { if (macroDragScroll<0) macroDragScroll=0; if (macroDragScroll>scrollMax) macroDragScroll=scrollMax; } ImGui::EndDisabled(); ImGui::EndTable(); } break; } case 1: { ImGui::Text("Tabs"); break; } case 2: { int columns=round(ImGui::GetContentRegionAvail().x/(400.0*dpiScale)); int curColumn=0; if (columns<1) columns=1; if (ImGui::BeginTable("MacroGrid",columns,ImGuiTableFlags_BordersInner)) { for (FurnaceGUIMacroDesc& i: macros) { if (curColumn==0) ImGui::TableNextRow(); ImGui::TableNextColumn(); if (++curColumn>=columns) curColumn=0; float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; int totalFit=i.macro->len; if (totalFit<1) totalFit=1; ImGui::PushID(index); ImGui::TextUnformatted(i.displayName); ImGui::SameLine(); if (ImGui::SmallButton((i.macro->open&1)?(ICON_FA_CHEVRON_UP "##IMacroOpen"):(ICON_FA_CHEVRON_DOWN "##IMacroOpen"))) { i.macro->open^=1; } if (i.macro->open&1) { ImGui::SameLine(); BUTTON_TO_SET_MODE(ImGui::SmallButton); } drawMacroEdit(i,totalFit,availableWidth,index); if (i.macro->open&1) { if ((i.macro->open&6)==0) { ImGui::Text(_("Length")); ImGui::SameLine(); ImGui::SetNextItemWidth(120.0f*dpiScale); int macroLen=i.macro->len; if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED if (macroLen<0) macroLen=0; if (macroLen>255) macroLen=255; i.macro->len=macroLen; } ImGui::SameLine(); } BUTTON_TO_SET_PROPS(i); if ((i.macro->open&6)==0) { ImGui::SameLine(); BUTTON_TO_SET_RELEASE(ImGui::Button); } if (i.modeName!=NULL) { bool modeVal=i.macro->mode; String modeName=fmt::sprintf("%s##IMacroMode",i.modeName); ImGui::SameLine(); if (ImGui::Checkbox(modeName.c_str(),&modeVal)) { i.macro->mode=modeVal; } } } ImGui::PopID(); index++; } ImGui::EndTable(); } break; } case 3: { if (ImGui::BeginTable("MacroList",2,ImGuiTableFlags_Borders)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.2f); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.8f); ImGui::TableNextRow(); ImGui::TableNextColumn(); for (size_t i=0; ilen>0) { snprintf(buf,255,"%s [%d]###%s",macros[i].displayName,macros[i].macro->len,macros[i].displayName); } else { snprintf(buf,255,"%s",macros[i].displayName); } if (ImGui::Selectable(buf,state.selectedMacro==(int)i)) { state.selectedMacro=i; } } ImGui::TableNextColumn(); float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; int totalFit=MIN(255,availableWidth/MAX(1,macroPointSize*dpiScale)); if (macroDragScroll>255-totalFit) { macroDragScroll=255-totalFit; } if (state.selectedMacro<0 || state.selectedMacro>=(int)macros.size()) { state.selectedMacro=0; } if (state.selectedMacro>=0 && state.selectedMacro<(int)macros.size()) { FurnaceGUIMacroDesc& m=macros[state.selectedMacro]; m.macro->open|=1; float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; int totalFit=MIN(255,availableWidth/MAX(1,macroPointSize*dpiScale)); int scrollMax=0; for (FurnaceGUIMacroDesc& i: macros) { if (i.macro->len>scrollMax) scrollMax=i.macro->len; } if (settings.autoMacroStepSize==1) totalFit=MAX(1,m.macro->len); else if (settings.autoMacroStepSize==2) totalFit=MAX(1,maxMacroLen); scrollMax-=totalFit; if (scrollMax<0) scrollMax=0; if (macroDragScroll>scrollMax) { macroDragScroll=scrollMax; } ImGui::BeginDisabled(scrollMax<1); ImGui::SetNextItemWidth(availableWidth); if (CWSliderInt("##MacroScroll",¯oDragScroll,0,scrollMax,"")) { if (macroDragScroll<0) macroDragScroll=0; if (macroDragScroll>scrollMax) macroDragScroll=scrollMax; } ImGui::EndDisabled(); if (settings.autoMacroStepSize==0) { ImGui::SameLine(); ImGui::Button(ICON_FA_SEARCH_PLUS "##MacroZoomB"); if (ImGui::BeginPopupContextItem("MacroZoomP",ImGuiPopupFlags_MouseButtonLeft)) { ImGui::SetNextItemWidth(120.0f*dpiScale); if (ImGui::InputInt("##MacroPointSize",¯oPointSize,1,4)) { if (macroPointSize<1) macroPointSize=1; if (macroPointSize>256) macroPointSize=256; } ImGui::EndPopup(); } } m.height=ImGui::GetContentRegionAvail().y-ImGui::GetFontSize()-ImGui::GetFrameHeightWithSpacing()-(m.bit30?28.0f:12.0f)*dpiScale-ImGui::GetStyle().ItemSpacing.y*3.0f; if (m.height<10.0f*dpiScale) m.height=10.0f*dpiScale; m.height/=dpiScale; drawMacroEdit(m,totalFit,availableWidth,index); if (m.macro->open&1) { bool showLen=((m.macro->open&6)==0); int colCount=showLen ? 4 : 3; float availX=ImGui::GetContentRegionAvail().x; // fairly arbitrary scaling logic bool shortLabels=(availX<600.0f*dpiScale); float scalarItemWidth=MIN((availX-90.0f*dpiScale)/colCount, 120.0f*dpiScale); if (ImGui::BeginTable("##MacroMetaData",colCount)) { if (showLen) ImGui::TableSetupColumn("len",ImGuiTableColumnFlags_WidthStretch,0.0); ImGui::TableSetupColumn("stepLen",ImGuiTableColumnFlags_WidthStretch,0.0); ImGui::TableSetupColumn("delay",ImGuiTableColumnFlags_WidthStretch,0.0); ImGui::TableSetupColumn("buttons",ImGuiTableColumnFlags_WidthFixed,0.0); ImGui::TableNextRow(); if (showLen) { ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(shortLabels ? _("Len##macroEditLengthShortLabel") : _("Length")); if (shortLabels && ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _("Length")); ImGui::SameLine(); ImGui::SetNextItemWidth(scalarItemWidth); int macroLen=m.macro->len; if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED if (macroLen<0) macroLen=0; if (macroLen>255) macroLen=255; m.macro->len=macroLen; } } ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(shortLabels ? _("SLen##macroEditStepLenShortLabel") : _("StepLen")); if (shortLabels && ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _("StepLen")); ImGui::SameLine(); ImGui::SetNextItemWidth(scalarItemWidth); if (ImGui::InputScalar("##IMacroSpeed",ImGuiDataType_U8,&m.macro->speed,&_ONE,&_THREE)) { if (m.macro->speed<1) m.macro->speed=1; MARK_MODIFIED; } ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(shortLabels ? _("Del##macroEditDelayShortLabel") : _("Delay")); if (shortLabels && ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _("Delay")); ImGui::SameLine(); ImGui::SetNextItemWidth(scalarItemWidth); if (ImGui::InputScalar("##IMacroDelay",ImGuiDataType_U8,&m.macro->delay,&_ONE,&_THREE)) { MARK_MODIFIED; } ImGui::TableNextColumn(); { FurnaceGUIMacroDesc& i=m; BUTTON_TO_SET_MODE(ImGui::Button); if ((i.macro->open&6)==0) { ImGui::SameLine(); BUTTON_TO_SET_RELEASE(ImGui::Button); } } if (m.modeName!=NULL) { bool modeVal=m.macro->mode; String modeName=fmt::sprintf("%s##IMacroMode",m.modeName); ImGui::SameLine(); if (ImGui::Checkbox(modeName.c_str(),&modeVal)) { m.macro->mode=modeVal; } } ImGui::EndTable(); } } else { ImGui::Text(_("The heck? No, this isn't even working correctly...")); } } else { ImGui::Text(_("The only problem with that selectedMacro is that it's a bug...")); } // goes here ImGui::EndTable(); } break; } case 4: { ImGui::Text("Single (combo box)"); break; } } } void FurnaceGUI::alterSampleMap(int column, int val) { if (curIns<0 || curIns>=(int)e->song.ins.size()) return; DivInstrument* ins=e->song.ins[curIns]; int sampleMapMin=sampleMapSelStart; int sampleMapMax=sampleMapSelEnd; if (sampleMapMin>sampleMapMax) { sampleMapMin^=sampleMapMax; sampleMapMax^=sampleMapMin; sampleMapMin^=sampleMapMax; } for (int i=sampleMapMin; i<=sampleMapMax; i++) { if (i<0 || i>=120) continue; if (sampleMapColumn==1 && column==1) { ins->amiga.noteMap[i].freq=val; } else if (sampleMapColumn==0 && column==0) { if (val<0) { ins->amiga.noteMap[i].map=-1; } else if (sampleMapDigit>0) { ins->amiga.noteMap[i].map*=10; ins->amiga.noteMap[i].map+=val; } else { ins->amiga.noteMap[i].map=val; } if (ins->amiga.noteMap[i].map>=(int)e->song.sample.size()) { ins->amiga.noteMap[i].map=((int)e->song.sample.size())-1; } } else if (sampleMapColumn==2 && column==2) { if (val<0) { ins->amiga.noteMap[i].dpcmFreq=-1; } else if (sampleMapDigit>0) { ins->amiga.noteMap[i].dpcmFreq*=10; ins->amiga.noteMap[i].dpcmFreq+=val; } else { ins->amiga.noteMap[i].dpcmFreq=val; } if (ins->amiga.noteMap[i].dpcmFreq>15) { ins->amiga.noteMap[i].dpcmFreq%=10; } } else if (sampleMapColumn==3 && column==3) { if (val<0) { ins->amiga.noteMap[i].dpcmDelta=-1; } else if (sampleMapDigit>0) { if (ins->amiga.noteMap[i].dpcmDelta>7) { ins->amiga.noteMap[i].dpcmDelta=val; } else { ins->amiga.noteMap[i].dpcmDelta<<=4; ins->amiga.noteMap[i].dpcmDelta+=val; } } else { ins->amiga.noteMap[i].dpcmDelta=val; } } } bool advance=false; if (sampleMapColumn==1 && column==1) { advance=true; } else if (sampleMapColumn==0 && column==0) { int digits=1; if (e->song.sample.size()>=10) digits=2; if (e->song.sample.size()>=100) digits=3; if (++sampleMapDigit>=digits) { sampleMapDigit=0; advance=true; } } else if (sampleMapColumn==2 && column==2) { if (++sampleMapDigit>=2) { sampleMapDigit=0; advance=true; } } else if (sampleMapColumn==3 && column==3) { if (++sampleMapDigit>=2) { sampleMapDigit=0; advance=true; } } if (advance && sampleMapMin==sampleMapMax) { sampleMapSelStart++; if (sampleMapSelStart>119) sampleMapSelStart=119; sampleMapSelEnd=sampleMapSelStart; } MARK_MODIFIED; } #define DRUM_FREQ(name,db,df,prop) \ ImGui::TableNextRow(); \ ImGui::TableNextColumn(); \ if (ins->type==DIV_INS_OPLL) { \ block=(prop>>9)&7; \ fNum=prop&511; \ } else { \ block=(prop>>10)&7; \ fNum=prop&1023; \ } \ ImGui::Text(name); \ ImGui::TableNextColumn(); \ if (ImGui::InputInt(db,&block,1,1)) { \ if (block<0) block=0; \ if (block>7) block=7; \ if (ins->type==DIV_INS_OPLL) { \ prop=(block<<9)|fNum; \ } else { \ prop=(block<<10)|fNum; \ } \ } \ ImGui::TableNextColumn(); \ if (ImGui::InputInt(df,&fNum,1,16)) { \ if (fNum<0) fNum=0; \ if (ins->type==DIV_INS_OPLL) { \ if (fNum>511) fNum=511; \ prop=(block<<9)|fNum; \ } else { \ if (fNum>1023) fNum=1023; \ prop=(block<<10)|fNum; \ } \ } #define CENTER_TEXT(text) \ ImGui::SetCursorPosX(ImGui::GetCursorPosX()+0.5*(ImGui::GetContentRegionAvail().x-ImGui::CalcTextSize(text).x)); #define CENTER_VSLIDER \ ImGui::SetCursorPosX(ImGui::GetCursorPosX()+0.5f*ImGui::GetContentRegionAvail().x-10.0f*dpiScale); #define CENTER_TEXT_20(text) \ ImGui::SetCursorPosX(ImGui::GetCursorPosX()+0.5*(20.0f*dpiScale-ImGui::CalcTextSize(text).x)); #define TOOLTIP_TEXT(text) \ if (ImGui::IsItemHovered()) { \ ImGui::SetTooltip("%s", text); \ } #define OP_DRAG_POINT \ if (ImGui::Button(ICON_FA_ARROWS)) { \ } \ if (ImGui::BeginDragDropSource()) { \ opToMove=i; \ ImGui::SetDragDropPayload("FUR_OP",NULL,0,ImGuiCond_Once); \ ImGui::Button(ICON_FA_ARROWS "##SysDrag"); \ ImGui::SameLine(); \ if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \ ImGui::Text(_("(copying)")); \ } else { \ ImGui::Text(_("(swapping)")); \ } \ ImGui::EndDragDropSource(); \ } else if (ImGui::IsItemHovered()) { \ ImGui::SetTooltip(_("- drag to swap operator\n- shift-drag to copy operator")); \ } \ if (ImGui::BeginDragDropTarget()) { \ const ImGuiPayload* dragItem=ImGui::AcceptDragDropPayload("FUR_OP"); \ if (dragItem!=NULL) { \ if (dragItem->IsDataType("FUR_OP")) { \ if (opToMove!=i && opToMove>=0) { \ int destOp=(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_ESFM)?opOrder[i]:i; \ int sourceOp=(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_ESFM)?opOrder[opToMove]:opToMove; \ if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \ e->lockEngine([ins,destOp,sourceOp]() { \ ins->fm.op[destOp]=ins->fm.op[sourceOp]; \ ins->esfm.op[destOp]=ins->esfm.op[sourceOp]; \ }); \ } else { \ e->lockEngine([ins,destOp,sourceOp]() { \ DivInstrumentFM::Operator origOp=ins->fm.op[sourceOp]; \ DivInstrumentESFM::Operator origOpE=ins->esfm.op[sourceOp]; \ ins->fm.op[sourceOp]=ins->fm.op[destOp]; \ ins->esfm.op[sourceOp]=ins->esfm.op[destOp]; \ ins->fm.op[destOp]=origOp; \ ins->esfm.op[destOp]=origOpE; \ }); \ } \ PARAMETER; \ } \ opToMove=-1; \ } \ } \ ImGui::EndDragDropTarget(); \ } void FurnaceGUI::insTabWavetable(DivInstrument* ins) { if (ImGui::BeginTabItem(_("Wavetable"))) { switch (ins->type) { case DIV_INS_GB: case DIV_INS_NAMCO: case DIV_INS_SM8521: case DIV_INS_SWAN: wavePreviewLen=32; wavePreviewHeight=15; break; case DIV_INS_PCE: wavePreviewLen=32; wavePreviewHeight=31; break; case DIV_INS_VBOY: wavePreviewLen=32; wavePreviewHeight=63; break; case DIV_INS_SCC: wavePreviewLen=32; wavePreviewHeight=255; break; case DIV_INS_FDS: wavePreviewLen=64; wavePreviewHeight=63; break; case DIV_INS_N163: wavePreviewLen=ins->n163.waveLen; wavePreviewHeight=15; break; case DIV_INS_X1_010: wavePreviewLen=128; wavePreviewHeight=255; break; case DIV_INS_AMIGA: case DIV_INS_GBA_DMA: wavePreviewLen=ins->amiga.waveLen+1; wavePreviewHeight=255; break; case DIV_INS_SNES: wavePreviewLen=ins->amiga.waveLen+1; wavePreviewHeight=15; break; case DIV_INS_GBA_MINMOD: wavePreviewLen=ins->amiga.waveLen+1; wavePreviewHeight=255; break; case DIV_INS_SID3: wavePreviewLen=256; wavePreviewHeight=255; break; default: wavePreviewLen=32; wavePreviewHeight=31; break; } if (ImGui::Checkbox(_("Enable synthesizer"),&ins->ws.enabled)) { PARAMETER wavePreviewInit=true; } if (ins->ws.enabled) { ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ins->ws.effect&0x80) { if ((ins->ws.effect&0x7f)>=DIV_WS_DUAL_MAX) { ins->ws.effect=0; wavePreviewInit=true; } } else { if ((ins->ws.effect&0x7f)>=DIV_WS_SINGLE_MAX) { ins->ws.effect=0; wavePreviewInit=true; } } if (ImGui::BeginCombo("##WSEffect",(ins->ws.effect&0x80)?dualWSEffects[ins->ws.effect&0x7f]:singleWSEffects[ins->ws.effect&0x7f])) { ImGui::Text(_("Single-waveform")); ImGui::Indent(); for (int i=0; iws.effect=i; wavePreviewInit=true; } } ImGui::Unindent(); ImGui::Text(_("Dual-waveform")); ImGui::Indent(); for (int i=129; iws.effect=i; wavePreviewInit=true; } } ImGui::Unindent(); ImGui::EndCombo(); } const bool isSingleWaveFX=(ins->ws.effect>=128); if (ImGui::BeginTable("WSPreview",isSingleWaveFX?3:2)) { DivWavetable* wave1=e->getWave(ins->ws.wave1); DivWavetable* wave2=e->getWave(ins->ws.wave2); if (wavePreviewInit) { wavePreview.init(ins,wavePreviewLen,wavePreviewHeight,true); wavePreviewInit=false; } float wavePreview1[257]; float wavePreview2[257]; float wavePreview3[257]; for (int i=0; ilen; i++) { if (wave1->data[i]>wave1->max) { wavePreview1[i]=wave1->max; } else { wavePreview1[i]=wave1->data[i]; } } if (wave1->len>0) { wavePreview1[wave1->len]=wave1->data[wave1->len-1]; } for (int i=0; ilen; i++) { if (wave2->data[i]>wave2->max) { wavePreview2[i]=wave2->max; } else { wavePreview2[i]=wave2->data[i]; } } if (wave2->len>0) { wavePreview2[wave2->len]=wave2->data[wave2->len-1]; } if (ins->ws.enabled && (!wavePreviewPaused || wavePreviewInit)) { wavePreview.tick(true); WAKE_UP; } for (int i=0; i0) { wavePreview3[wavePreviewLen]=wavePreview3[wavePreviewLen-1]; } float ySize=(isSingleWaveFX?96.0f:128.0f)*dpiScale; ImGui::TableNextRow(); ImGui::TableNextColumn(); ImVec2 size1=ImVec2(ImGui::GetContentRegionAvail().x,ySize); PlotNoLerp("##WaveformP1",wavePreview1,wave1->len+1,0,"Wave 1",0,wave1->max,size1); if (isSingleWaveFX) { ImGui::TableNextColumn(); ImVec2 size2=ImVec2(ImGui::GetContentRegionAvail().x,ySize); PlotNoLerp("##WaveformP2",wavePreview2,wave2->len+1,0,"Wave 2",0,wave2->max,size2); } ImGui::TableNextColumn(); ImVec2 size3=ImVec2(ImGui::GetContentRegionAvail().x,ySize); PlotNoLerp("##WaveformP3",wavePreview3,wavePreviewLen+1,0,"Result",0,wavePreviewHeight,size3); ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ins->std.waveMacro.len>0) { ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_WARNING]); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Wave 1")); ImGui::SameLine(); ImGui::Text(ICON_FA_EXCLAMATION_TRIANGLE); ImGui::PopStyleColor(); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("waveform macro is controlling wave 1!\nthis value will be ineffective.")); } } else { ImGui::AlignTextToFramePadding(); ImGui::Text(_("Wave 1")); } ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::InputInt("##SelWave1",&ins->ws.wave1,1,4)) { PARAMETER if (ins->ws.wave1<0) ins->ws.wave1=0; if (ins->ws.wave1>=(int)e->song.wave.size()) ins->ws.wave1=e->song.wave.size()-1; wavePreviewInit=true; } if (ins->std.waveMacro.len>0) { if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("waveform macro is controlling wave 1!\nthis value will be ineffective.")); } } if (isSingleWaveFX) { ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Wave 2")); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::InputInt("##SelWave2",&ins->ws.wave2,1,4)) { PARAMETER if (ins->ws.wave2<0) ins->ws.wave2=0; if (ins->ws.wave2>=(int)e->song.wave.size()) ins->ws.wave2=e->song.wave.size()-1; wavePreviewInit=true; } } ImGui::TableNextColumn(); if (ImGui::Button(wavePreviewPaused?(ICON_FA_PLAY "##WSPause"):(ICON_FA_PAUSE "##WSPause"))) { wavePreviewPaused=!wavePreviewPaused; } if (ImGui::IsItemHovered()) { if (wavePreviewPaused) { ImGui::SetTooltip(_("Resume preview")); } else { ImGui::SetTooltip(_("Pause preview")); } } ImGui::SameLine(); if (ImGui::Button(ICON_FA_REPEAT "##WSRestart")) { wavePreviewInit=true; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Restart preview")); } ImGui::SameLine(); if (ImGui::Button(ICON_FA_UPLOAD "##WSCopy")) { curWave=e->addWave(); if (curWave==-1) { showError(_("too many wavetables!")); } else { wantScrollListWave=true; MARK_MODIFIED; RESET_WAVE_MACRO_ZOOM; nextWindow=GUI_WINDOW_WAVE_EDIT; DivWavetable* copyWave=e->song.wave[curWave]; copyWave->len=wavePreviewLen; copyWave->max=wavePreviewHeight; memcpy(copyWave->data,wavePreview.output,256*sizeof(int)); } } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Copy to new wavetable")); } ImGui::SameLine(); ImGui::Text("(%d×%d)",wavePreviewLen,wavePreviewHeight+1); ImGui::EndTable(); } if (ImGui::InputScalar(_("Update Rate"),ImGuiDataType_U8,&ins->ws.rateDivider,&_ONE,&_EIGHT)) { PARAMETER wavePreviewInit=true; } int speed=ins->ws.speed+1; if (ImGui::InputInt(_("Speed"),&speed,1,8)) { PARAMETER if (speed<1) speed=1; if (speed>256) speed=256; ins->ws.speed=speed-1; wavePreviewInit=true; } if (ImGui::InputScalar(_("Amount"),ImGuiDataType_U8,&ins->ws.param1,&_ONE,&_EIGHT)) { PARAMETER wavePreviewInit=true; } if (ins->ws.effect==DIV_WS_PHASE_MOD) { if (ImGui::InputScalar(_("Power"),ImGuiDataType_U8,&ins->ws.param2,&_ONE,&_EIGHT)) { PARAMETER wavePreviewInit=true; } } if (ImGui::Checkbox(_("Global"),&ins->ws.global)) { PARAMETER wavePreviewInit=true; } } else { ImGui::TextWrapped(_("wavetable synthesizer disabled.\nuse the Waveform macro to set the wave for this instrument.")); } ImGui::EndTabItem(); } } void FurnaceGUI::insTabSample(DivInstrument* ins) { const char* sampleTabName=_("Sample"); if (ins->type==DIV_INS_NES) sampleTabName=_("DPCM"); if (ImGui::BeginTabItem(sampleTabName)) { if (ins->type==DIV_INS_NES && e->song.oldDPCM) { ImGui::Text(_("new DPCM features disabled (compatibility)!")); if (ImGui::Button(_("click here to enable them."))) { e->song.oldDPCM=false; MARK_MODIFIED; } ImGui::EndTabItem(); return; } String sName; bool wannaOpenSMPopup=false; if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { sName=_("none selected"); } else { sName=e->song.sample[ins->amiga.initSample]->name; } if (ins->type==DIV_INS_PCE || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_X1_010 || ins->type==DIV_INS_SWAN || ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_VRC6 || ins->type==DIV_INS_SU || ins->type==DIV_INS_NDS || ins->type==DIV_INS_SUPERVISION || ins->type==DIV_INS_SID3) { P(ImGui::Checkbox(_("Use sample"),&ins->amiga.useSample)); if (ins->type==DIV_INS_X1_010) { if (ImGui::InputInt(_("Sample bank slot##BANKSLOT"),&ins->x1_010.bankSlot,1,4)) { PARAMETER if (ins->x1_010.bankSlot<0) ins->x1_010.bankSlot=0; if (ins->x1_010.bankSlot>=7) ins->x1_010.bankSlot=7; } } } ImGui::AlignTextToFramePadding(); ImGui::Text(_("Sample")); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::BeginCombo("##ISample",sName.c_str())) { String id; for (int i=0; isong.sampleLen; i++) { id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name); if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) { PARAMETER ins->amiga.initSample=i; } } ImGui::EndCombo(); } // Wavetable if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SNES || ins->type==DIV_INS_GBA_DMA || ins->type==DIV_INS_GBA_MINMOD) { const char* useWaveText=ins->type==DIV_INS_AMIGA?_("Use wavetable (Amiga/Generic DAC only)"):_("Use wavetable"); ImGui::BeginDisabled(ins->amiga.useNoteMap); P(ImGui::Checkbox(useWaveText,&ins->amiga.useWave)); if (ins->amiga.useWave) { int len=ins->amiga.waveLen+1; int origLen=len; if (ImGui::InputInt(_("Width"),&len,2,16)) { if (ins->type==DIV_INS_SNES || ins->type==DIV_INS_GBA_DMA) { if (len<16) len=16; if (len>256) len=256; if (len>origLen) { ins->amiga.waveLen=((len+15)&(~15))-1; } else { ins->amiga.waveLen=(len&(~15))-1; } } else { if (len<2) len=2; if (len>256) len=256; ins->amiga.waveLen=(len&(~1))-1; } PARAMETER } } ImGui::EndDisabled(); } // Note map ImGui::BeginDisabled(ins->amiga.useWave); P(ImGui::Checkbox(_("Use sample map"),&ins->amiga.useNoteMap)); if (ins->amiga.useNoteMap) { if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows)) sampleMapFocused=false; if (curWindowLast!=GUI_WINDOW_INS_EDIT) sampleMapFocused=false; if (!sampleMapFocused) sampleMapDigit=0; if (ImGui::BeginTable("NoteMap",(ins->type==DIV_INS_NES)?5:4,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); if (ins->type==DIV_INS_NES) ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupScrollFreeze(0,1); ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); ImGui::TableNextColumn(); ImGui::Text("#"); if (ins->type==DIV_INS_NES) { ImGui::TableNextColumn(); ImGui::Text(_("pitch")); ImGui::TableNextColumn(); ImGui::Text(_("delta")); } else { ImGui::TableNextColumn(); ImGui::Text(_("note")); } ImGui::TableNextColumn(); ImGui::Text(_("sample name")); int sampleMapMin=sampleMapSelStart; int sampleMapMax=sampleMapSelEnd; if (sampleMapMin>sampleMapMax) { sampleMapMin^=sampleMapMax; sampleMapMax^=sampleMapMin; sampleMapMin^=sampleMapMax; } ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(ImGuiCol_HeaderHovered)); ImGui::PushStyleColor(ImGuiCol_HeaderActive,ImGui::GetColorU32(ImGuiCol_HeaderHovered)); for (int i=0; i<120; i++) { DivInstrumentAmiga::SampleMap& sampleMap=ins->amiga.noteMap[i]; ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(ImGuiCol_TableHeaderBg)); ImGui::AlignTextToFramePadding(); ImGui::Text("%s",noteNames[60+i]); ImGui::TableNextColumn(); if (sampleMap.map<0 || sampleMap.map>=e->song.sampleLen) { sName=fmt::sprintf("---##SM%d",i); sampleMap.map=-1; } else { sName=fmt::sprintf("%3d##SM%d",sampleMap.map,i); } ImGui::PushFont(patFont); ImGui::AlignTextToFramePadding(); ImGui::SetNextItemWidth(ImGui::CalcTextSize("00000").x); ImGui::Selectable(sName.c_str(),(sampleMapWaitingInput && sampleMapColumn==0 && i>=sampleMapMin && i<=sampleMapMax)); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { sampleMapFocused=true; sampleMapColumn=0; sampleMapDigit=0; sampleMapSelStart=i; sampleMapSelEnd=i; sampleMapMin=sampleMapSelStart; sampleMapMax=sampleMapSelEnd; if (sampleMapMin>sampleMapMax) { sampleMapMin^=sampleMapMax; sampleMapMax^=sampleMapMin; sampleMapMin^=sampleMapMax; } ImGui::InhibitInertialScroll(); } if (sampleMapFocused && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && ImGui::IsMouseDown(ImGuiMouseButton_Left)) { sampleMapSelEnd=i; } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (sampleMapSelStart==sampleMapSelEnd) { sampleMapFocused=true; sampleMapColumn=0; sampleMapDigit=0; sampleMapSelStart=i; sampleMapSelEnd=i; sampleMapMin=sampleMapSelStart; sampleMapMax=sampleMapSelEnd; if (sampleMapMin>sampleMapMax) { sampleMapMin^=sampleMapMax; sampleMapMax^=sampleMapMin; sampleMapMin^=sampleMapMax; } } if (sampleMapFocused) { wannaOpenSMPopup=true; } } ImGui::PopFont(); if (ins->type==DIV_INS_NES) { // pitch ImGui::TableNextColumn(); ImGui::PushFont(patFont); ImGui::AlignTextToFramePadding(); ImGui::SetNextItemWidth(ImGui::CalcTextSize("0000").x); if (sampleMap.dpcmFreq<0) { sName=fmt::sprintf(" -- ##SD1%d",i); } else { sName=fmt::sprintf(" %2d ##SD1%d",sampleMap.dpcmFreq,i); } ImGui::Selectable(sName.c_str(),(sampleMapWaitingInput && sampleMapColumn==2 && i>=sampleMapMin && i<=sampleMapMax)); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { sampleMapFocused=true; sampleMapColumn=2; sampleMapDigit=0; sampleMapSelStart=i; sampleMapSelEnd=i; sampleMapMin=sampleMapSelStart; sampleMapMax=sampleMapSelEnd; if (sampleMapMin>sampleMapMax) { sampleMapMin^=sampleMapMax; sampleMapMax^=sampleMapMin; sampleMapMin^=sampleMapMax; } ImGui::InhibitInertialScroll(); } if (sampleMapFocused && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && ImGui::IsMouseDown(ImGuiMouseButton_Left)) { sampleMapSelEnd=i; } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (sampleMapSelStart==sampleMapSelEnd) { sampleMapFocused=true; sampleMapColumn=2; sampleMapDigit=0; sampleMapSelStart=i; sampleMapSelEnd=i; sampleMapMin=sampleMapSelStart; sampleMapMax=sampleMapSelEnd; if (sampleMapMin>sampleMapMax) { sampleMapMin^=sampleMapMax; sampleMapMax^=sampleMapMin; sampleMapMin^=sampleMapMax; } } if (sampleMapFocused) { wannaOpenSMPopup=true; } } ImGui::PopFont(); // delta ImGui::TableNextColumn(); ImGui::PushFont(patFont); ImGui::AlignTextToFramePadding(); ImGui::SetNextItemWidth(ImGui::CalcTextSize("0000").x); if (sampleMap.dpcmDelta<0) { sName=fmt::sprintf(" -- ##SD2%d",i); } else { sName=fmt::sprintf(" %2X ##SD2%d",sampleMap.dpcmDelta,i); } ImGui::Selectable(sName.c_str(),(sampleMapWaitingInput && sampleMapColumn==3 && i>=sampleMapMin && i<=sampleMapMax)); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { sampleMapFocused=true; sampleMapColumn=3; sampleMapDigit=0; sampleMapSelStart=i; sampleMapSelEnd=i; sampleMapMin=sampleMapSelStart; sampleMapMax=sampleMapSelEnd; if (sampleMapMin>sampleMapMax) { sampleMapMin^=sampleMapMax; sampleMapMax^=sampleMapMin; sampleMapMin^=sampleMapMax; } ImGui::InhibitInertialScroll(); } if (sampleMapFocused && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && ImGui::IsMouseDown(ImGuiMouseButton_Left)) { sampleMapSelEnd=i; } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (sampleMapSelStart==sampleMapSelEnd) { sampleMapFocused=true; sampleMapColumn=3; sampleMapDigit=0; sampleMapSelStart=i; sampleMapSelEnd=i; sampleMapMin=sampleMapSelStart; sampleMapMax=sampleMapSelEnd; if (sampleMapMin>sampleMapMax) { sampleMapMin^=sampleMapMax; sampleMapMax^=sampleMapMin; sampleMapMin^=sampleMapMax; } } if (sampleMapFocused) { wannaOpenSMPopup=true; } } ImGui::PopFont(); } else { ImGui::TableNextColumn(); sName="???"; if ((sampleMap.freq+60)>0 && (sampleMap.freq+60)<180) { sName=noteNames[sampleMap.freq+60]; } sName+=fmt::sprintf("##SN%d",i); ImGui::PushFont(patFont); ImGui::AlignTextToFramePadding(); ImGui::SetNextItemWidth(ImGui::CalcTextSize("00000").x); ImGui::Selectable(sName.c_str(),(sampleMapWaitingInput && sampleMapColumn==1 && i>=sampleMapMin && i<=sampleMapMax)); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { sampleMapFocused=true; sampleMapColumn=1; sampleMapDigit=0; sampleMapSelStart=i; sampleMapSelEnd=i; sampleMapMin=sampleMapSelStart; sampleMapMax=sampleMapSelEnd; if (sampleMapMin>sampleMapMax) { sampleMapMin^=sampleMapMax; sampleMapMax^=sampleMapMin; sampleMapMin^=sampleMapMax; } ImGui::InhibitInertialScroll(); } if (sampleMapFocused && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && ImGui::IsMouseDown(ImGuiMouseButton_Left)) { sampleMapSelEnd=i; } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (sampleMapSelStart==sampleMapSelEnd) { sampleMapFocused=true; sampleMapColumn=1; sampleMapDigit=0; sampleMapSelStart=i; sampleMapSelEnd=i; sampleMapMin=sampleMapSelStart; sampleMapMax=sampleMapSelEnd; if (sampleMapMin>sampleMapMax) { sampleMapMin^=sampleMapMax; sampleMapMax^=sampleMapMin; sampleMapMin^=sampleMapMax; } } if (sampleMapFocused) { wannaOpenSMPopup=true; } } ImGui::PopFont(); } ImGui::TableNextColumn(); String prevName="---"; if (sampleMap.map>=0 && sampleMap.mapsong.sampleLen) { prevName=e->song.sample[sampleMap.map]->name; } ImGui::PushID(i+2); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::BeginCombo("##SMSample",prevName.c_str())) { if (ImGui::Selectable("---")) { sampleMap.map=-1; } for (int k=0; ksong.sampleLen; k++) { String itemName=fmt::sprintf("%d: %s",k,e->song.sample[k]->name); if (ImGui::Selectable(itemName.c_str())) { sampleMap.map=k; } } ImGui::EndCombo(); } ImGui::PopID(); } ImGui::PopStyleColor(2); ImGui::EndTable(); } } else { sampleMapFocused=false; } ImGui::EndDisabled(); if (wannaOpenSMPopup) { ImGui::OpenPopup("SampleMapUtils"); } if (ImGui::BeginPopup("SampleMapUtils",ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings)) { if (sampleMapSelStart==sampleMapSelEnd && sampleMapSelStart>=0 && sampleMapSelStart<120) { if (ins->type==DIV_INS_NES) { if (ImGui::MenuItem(_("set entire map to this pitch"))) { if (sampleMapSelStart>=0 && sampleMapSelStart<120) { for (int i=0; i<120; i++) { if (i==sampleMapSelStart) continue; ins->amiga.noteMap[i].dpcmFreq=ins->amiga.noteMap[sampleMapSelStart].dpcmFreq; } } } if (ImGui::MenuItem(_("set entire map to this delta counter value"))) { if (sampleMapSelStart>=0 && sampleMapSelStart<120) { for (int i=0; i<120; i++) { if (i==sampleMapSelStart) continue; ins->amiga.noteMap[i].dpcmDelta=ins->amiga.noteMap[sampleMapSelStart].dpcmDelta; } } } } else { if (ImGui::MenuItem(_("set entire map to this note"))) { if (sampleMapSelStart>=0 && sampleMapSelStart<120) { for (int i=0; i<120; i++) { if (i==sampleMapSelStart) continue; ins->amiga.noteMap[i].freq=ins->amiga.noteMap[sampleMapSelStart].freq; } } } } if (ImGui::MenuItem(_("set entire map to this sample"))) { if (sampleMapSelStart>=0 && sampleMapSelStart<120) { for (int i=0; i<120; i++) { if (i==sampleMapSelStart) continue; ins->amiga.noteMap[i].map=ins->amiga.noteMap[sampleMapSelStart].map; } } } } if (ins->type==DIV_INS_NES) { if (ImGui::MenuItem(_("reset pitches"))) { for (int i=0; i<120; i++) { ins->amiga.noteMap[i].dpcmFreq=15; } } if (ImGui::MenuItem(_("clear delta counter values"))) { for (int i=0; i<120; i++) { ins->amiga.noteMap[i].dpcmDelta=-1; } } } else { if (ImGui::MenuItem(_("reset notes"))) { for (int i=0; i<120; i++) { ins->amiga.noteMap[i].freq=i; } } } if (ImGui::MenuItem(_("clear map samples"))) { for (int i=0; i<120; i++) { ins->amiga.noteMap[i].map=-1; } } ImGui::EndPopup(); } ImGui::EndTabItem(); } else { sampleMapFocused=false; } } void FurnaceGUI::insTabFMModernHeader(DivInstrument* ins) { ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); if (ins->type==DIV_INS_ESFM) { ImGui::TableNextColumn(); CENTER_TEXT(ESFM_SHORT_NAME(ESFM_MODIN)); ImGui::TextUnformatted(ESFM_SHORT_NAME(ESFM_MODIN)); TOOLTIP_TEXT(ESFM_LONG_NAME(ESFM_MODIN)); ImGui::TableNextColumn(); ImGui::TableNextColumn(); CENTER_TEXT(ESFM_SHORT_NAME(ESFM_DELAY)); ImGui::TextUnformatted(ESFM_SHORT_NAME(ESFM_DELAY)); TOOLTIP_TEXT(ESFM_LONG_NAME(ESFM_DELAY)); } ImGui::TableNextColumn(); CENTER_TEXT(FM_SHORT_NAME(FM_AR)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_AR)); TOOLTIP_TEXT(FM_NAME(FM_AR)); ImGui::TableNextColumn(); CENTER_TEXT(FM_SHORT_NAME(FM_DR)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_DR)); TOOLTIP_TEXT(FM_NAME(FM_DR)); if (settings.susPosition==0) { ImGui::TableNextColumn(); CENTER_TEXT(FM_SHORT_NAME(FM_SL)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_SL)); TOOLTIP_TEXT(FM_NAME(FM_SL)); } if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableNextColumn(); CENTER_TEXT(FM_SHORT_NAME(FM_D2R)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_D2R)); TOOLTIP_TEXT(FM_NAME(FM_D2R)); } ImGui::TableNextColumn(); CENTER_TEXT(FM_SHORT_NAME(FM_RR)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_RR)); TOOLTIP_TEXT(FM_NAME(FM_RR)); if (settings.susPosition==1) { ImGui::TableNextColumn(); CENTER_TEXT(FM_SHORT_NAME(FM_SL)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_SL)); TOOLTIP_TEXT(FM_NAME(FM_SL)); } ImGui::TableNextColumn(); if (settings.susPosition==2) { ImGui::TableNextColumn(); CENTER_TEXT(FM_SHORT_NAME(FM_SL)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_SL)); TOOLTIP_TEXT(FM_NAME(FM_SL)); } ImGui::TableNextColumn(); CENTER_TEXT(FM_SHORT_NAME(FM_TL)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_TL)); TOOLTIP_TEXT(FM_NAME(FM_TL)); if (settings.susPosition==3) { ImGui::TableNextColumn(); CENTER_TEXT(FM_SHORT_NAME(FM_SL)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_SL)); TOOLTIP_TEXT(FM_NAME(FM_SL)); } ImGui::TableNextColumn(); if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_RS)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_RS)); TOOLTIP_TEXT(FM_NAME(FM_RS)); } else { CENTER_TEXT(FM_SHORT_NAME(FM_KSL)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_KSL)); TOOLTIP_TEXT(FM_NAME(FM_KSL)); } if (ins->type==DIV_INS_OPZ) { ImGui::TableNextColumn(); CENTER_TEXT(FM_SHORT_NAME(FM_EGSHIFT)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_EGSHIFT)); TOOLTIP_TEXT(FM_NAME(FM_EGSHIFT)); ImGui::TableNextColumn(); CENTER_TEXT(FM_SHORT_NAME(FM_REV)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_REV)); TOOLTIP_TEXT(FM_NAME(FM_REV)); } if (ins->type==DIV_INS_ESFM) { ImGui::TableNextColumn(); CENTER_TEXT(ESFM_SHORT_NAME(ESFM_OUTLVL)); ImGui::TextUnformatted(ESFM_SHORT_NAME(ESFM_OUTLVL)); TOOLTIP_TEXT(ESFM_LONG_NAME(ESFM_OUTLVL)); } ImGui::TableNextColumn(); CENTER_TEXT(FM_SHORT_NAME(FM_MULT)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_MULT)); TOOLTIP_TEXT(FM_NAME(FM_MULT)); if (ins->type==DIV_INS_OPZ) { ImGui::TableNextColumn(); CENTER_TEXT(FM_SHORT_NAME(FM_FINE)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_FINE)); TOOLTIP_TEXT(FM_NAME(FM_FINE)); } if (ins->type==DIV_INS_ESFM) { ImGui::TableNextColumn(); CENTER_TEXT(ESFM_SHORT_NAME(ESFM_CT)); ImGui::TextUnformatted(ESFM_SHORT_NAME(ESFM_CT)); TOOLTIP_TEXT(ESFM_LONG_NAME(ESFM_CT)); } ImGui::TableNextColumn(); if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_DT)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_DT)); TOOLTIP_TEXT(FM_NAME(FM_DT)); ImGui::TableNextColumn(); } if (ins->type==DIV_INS_ESFM) { CENTER_TEXT(ESFM_SHORT_NAME(ESFM_DT)); ImGui::TextUnformatted(ESFM_SHORT_NAME(ESFM_DT)); TOOLTIP_TEXT(ESFM_LONG_NAME(ESFM_DT)); ImGui::TableNextColumn(); } if (ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_DT2)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_DT2)); TOOLTIP_TEXT(FM_NAME(FM_DT2)); ImGui::TableNextColumn(); } if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_AM)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_AM)); TOOLTIP_TEXT(FM_NAME(FM_AM)); } else { CENTER_TEXT("Other"); ImGui::TextUnformatted("Other"); } ImGui::TableNextColumn(); if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_ESFM) { ImGui::TableNextColumn(); CENTER_TEXT(FM_NAME(FM_WS)); ImGui::TextUnformatted(FM_NAME(FM_WS)); } else if (ins->type!=DIV_INS_OPLL && ins->type!=DIV_INS_OPM) { ImGui::TableNextColumn(); CENTER_TEXT(FM_NAME(FM_SSG)); ImGui::TextUnformatted(FM_NAME(FM_SSG)); } ImGui::TableNextColumn(); CENTER_TEXT(_("Envelope")); ImGui::TextUnformatted(_("Envelope")); } void FurnaceGUI::insTabFM(DivInstrument* ins) { int opCount=4; if (ins->type==DIV_INS_OPLL) opCount=2; if (ins->type==DIV_INS_OPL) opCount=(ins->fm.ops==4)?4:2; bool opsAreMutable=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM); if (ImGui::BeginTabItem("FM")) { DivInstrumentFM& fmOrigin=(ins->type==DIV_INS_OPLL && ins->fm.opllPreset>0 && ins->fm.opllPreset<16)?opllPreview:ins->fm; bool isPresent[4]; int isPresentCount=0; memset(isPresent,0,4*sizeof(bool)); for (int i=0; isong.systemLen; i++) { if (e->song.system[i]==DIV_SYSTEM_VRC7) { isPresent[3]=true; } else if (e->song.system[i]==DIV_SYSTEM_OPLL || e->song.system[i]==DIV_SYSTEM_OPLL_DRUMS) { isPresent[(e->song.systemFlags[i].getInt("patchSet",0))&3]=true; } } if (!isPresent[0] && !isPresent[1] && !isPresent[2] && !isPresent[3]) { isPresent[0]=true; } for (int i=0; i<4; i++) { if (isPresent[i]) isPresentCount++; } int presentWhich=0; for (int i=0; i<4; i++) { if (isPresent[i]) { presentWhich=i; break; } } if (ImGui::BeginTable("fmDetails",3,(ins->type==DIV_INS_ESFM)?ImGuiTableFlags_SizingStretchProp:ImGuiTableFlags_SizingStretchSame)) { String blockTxt=_("Automatic"); if (ins->fm.block>=1) { blockTxt=fmt::sprintf("%d",ins->fm.block-1); } ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,((ins->type==DIV_INS_ESFM)?0.40f:0.0f)); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,((ins->type==DIV_INS_ESFM)?0.25f:0.0f)); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,((ins->type==DIV_INS_ESFM)?0.35f:0.0f)); ImGui::TableNextRow(); switch (ins->type) { case DIV_INS_FM: case DIV_INS_OPM: ImGui::TableNextColumn(); P(CWSliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN)); rightClickable P(CWSliderScalar(FM_NAME(FM_FMS),ImGuiDataType_U8,&ins->fm.fms,&_ZERO,&_SEVEN)); rightClickable if (ins->type==DIV_INS_FM) { P(CWSliderScalar(FM_NAME(FM_BLOCK),ImGuiDataType_U8,&ins->fm.block,&_ZERO,&_EIGHT,blockTxt.c_str())); rightClickable } ImGui::TableNextColumn(); P(CWSliderScalar(FM_NAME(FM_ALG),ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&_SEVEN)); rightClickable P(CWSliderScalar(FM_NAME(FM_AMS),ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); if (fmPreviewOn) { drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); if (!fmPreviewPaused) { renderFMPreview(ins,1); WAKE_UP; } } else { drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); } kvsConfig(ins); break; case DIV_INS_OPZ: ImGui::TableNextColumn(); P(CWSliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN)); rightClickable P(CWSliderScalar(FM_NAME(FM_FMS),ImGuiDataType_U8,&ins->fm.fms,&_ZERO,&_SEVEN)); rightClickable P(CWSliderScalar(FM_NAME(FM_FMS2),ImGuiDataType_U8,&ins->fm.fms2,&_ZERO,&_SEVEN)); rightClickable ImGui::TableNextColumn(); P(CWSliderScalar(FM_NAME(FM_ALG),ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&_SEVEN)); rightClickable P(CWSliderScalar(FM_NAME(FM_AMS),ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE)); rightClickable P(CWSliderScalar(FM_NAME(FM_AMS2),ImGuiDataType_U8,&ins->fm.ams2,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); if (fmPreviewOn) { drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); if (!fmPreviewPaused) { renderFMPreview(ins,1); WAKE_UP; } } else { drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); } kvsConfig(ins); if (ImGui::Button(_("Request from TX81Z"))) { doAction(GUI_ACTION_TX81Z_REQUEST); } /* ImGui::SameLine(); if (ImGui::Button("Send to TX81Z")) { showError("Coming soon!"); } */ break; case DIV_INS_OPL: case DIV_INS_OPL_DRUMS: { bool fourOp=(ins->fm.ops==4 || ins->type==DIV_INS_OPL_DRUMS); bool drums=ins->fm.opllPreset==16; int algMax=fourOp?3:1; ImGui::TableNextColumn(); ins->fm.alg&=algMax; P(CWSliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN)); rightClickable P(CWSliderScalar(FM_NAME(FM_BLOCK),ImGuiDataType_U8,&ins->fm.block,&_ZERO,&_EIGHT,blockTxt.c_str())); rightClickable ImGui::TableNextColumn(); P(CWSliderScalar(FM_NAME(FM_ALG),ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&algMax)); rightClickable if (ins->type==DIV_INS_OPL) { ImGui::BeginDisabled(ins->fm.opllPreset==16); if (ImGui::Checkbox("4-op",&fourOp)) { PARAMETER ins->fm.ops=fourOp?4:2; } ImGui::EndDisabled(); ImGui::SameLine(); if (ImGui::Checkbox(_("Drums"),&drums)) { PARAMETER ins->fm.opllPreset=drums?16:0; } } ImGui::TableNextColumn(); if (fmPreviewOn) { drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); if (!fmPreviewPaused) { renderFMPreview(ins,1); WAKE_UP; } } else { drawAlgorithm(ins->fm.alg&algMax,fourOp?FM_ALGS_4OP_OPL:FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); } kvsConfig(ins); break; } case DIV_INS_OPLL: { bool dc=fmOrigin.fms; bool dm=fmOrigin.ams; bool sus=ins->fm.alg; ImGui::TableNextColumn(); ImGui::BeginDisabled(ins->fm.opllPreset!=0); P(CWSliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&fmOrigin.fb,&_ZERO,&_SEVEN)); rightClickable ImGui::EndDisabled(); P(CWSliderScalar(FM_NAME(FM_BLOCK),ImGuiDataType_U8,&ins->fm.block,&_ZERO,&_EIGHT,blockTxt.c_str())); rightClickable if (ins->fm.opllPreset!=0) { ins->fm.op[1].tl&=15; P(CWSliderScalar(_("Volume##TL"),ImGuiDataType_U8,&ins->fm.op[1].tl,&_FIFTEEN,&_ZERO)); rightClickable } ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_NAME(FM_SUS),&sus)) { PARAMETER ins->fm.alg=sus; } ImGui::BeginDisabled(ins->fm.opllPreset!=0); if (ImGui::Checkbox(FM_NAME(FM_DC),&dc)) { PARAMETER fmOrigin.fms=dc; } ImGui::SameLine(); if (ImGui::Checkbox(FM_NAME(FM_DM),&dm)) { PARAMETER fmOrigin.ams=dm; } ImGui::EndDisabled(); ImGui::TableNextColumn(); if (fmPreviewOn) { drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale)); if (!fmPreviewPaused) { renderFMPreview(ins,1); WAKE_UP; } } else { drawAlgorithm(0,FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale)); } kvsConfig(ins,false); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::BeginCombo("##LLPreset",_(opllInsNames[presentWhich][ins->fm.opllPreset]))) { if (isPresentCount>1) { if (ImGui::BeginTable("LLPresetList",isPresentCount)) { ImGui::TableNextRow(ImGuiTableRowFlags_Headers); for (int i=0; i<4; i++) { if (!isPresent[i]) continue; ImGui::TableNextColumn(); ImGui::Text(_("%s name"),opllVariants[i]); } for (int i=0; i<17; i++) { ImGui::TableNextRow(); for (int j=0; j<4; j++) { if (!isPresent[j]) continue; ImGui::TableNextColumn(); ImGui::PushID(j*17+i); if (ImGui::Selectable(_(opllInsNames[j][i]))) { ins->fm.opllPreset=i; } ImGui::PopID(); } } ImGui::EndTable(); } } else { for (int i=0; i<17; i++) { if (ImGui::Selectable(_(opllInsNames[presentWhich][i]))) { ins->fm.opllPreset=i; } } } ImGui::EndCombo(); } break; } case DIV_INS_ESFM: { ImGui::TableNextColumn(); P(CWSliderScalar(ESFM_LONG_NAME(ESFM_NOISE),ImGuiDataType_U8,&ins->esfm.noise,&_ZERO,&_THREE,_(esfmNoiseModeNames[ins->esfm.noise&3]))); rightClickable ImGui::TextUnformatted(_(esfmNoiseModeDescriptions[ins->esfm.noise&3])); ImGui::TableNextColumn(); P(CWSliderScalar(FM_NAME(FM_BLOCK),ImGuiDataType_U8,&ins->fm.block,&_ZERO,&_EIGHT,blockTxt.c_str())); rightClickable ImGui::TableNextColumn(); if (fmPreviewOn) { drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); if (!fmPreviewPaused) { renderFMPreview(ins,1); WAKE_UP; } } else { drawESFMAlgorithm(ins->esfm, ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); } kvsConfig(ins); } default: break; } ImGui::EndTable(); } if (ins->type==DIV_INS_OPLL && ins->fm.opllPreset==16) { ImGui::Text(_("this volume slider only works in compatibility (non-drums) system.")); } if (((ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL) && ins->fm.opllPreset==16) || ins->type==DIV_INS_OPL_DRUMS) { ins->fm.ops=2; P(ImGui::Checkbox(_("Fixed frequency mode"),&ins->fm.fixedDrums)); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("when enabled, drums will be set to the specified frequencies, ignoring the note.")); } if (ins->fm.fixedDrums) { int block=0; int fNum=0; if (ImGui::BeginTable("fixedDrumSettings",3)) { ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); ImGui::Text(_("Drum")); ImGui::TableNextColumn(); ImGui::Text(_("Block")); ImGui::TableNextColumn(); ImGui::Text(_("FreqNum")); DRUM_FREQ(_("Kick"),"##DBlock0","##DFreq0",ins->fm.kickFreq); DRUM_FREQ(_("Snare/Hi-hat"),"##DBlock1","##DFreq1",ins->fm.snareHatFreq); DRUM_FREQ(_("Tom/Top"),"##DBlock2","##DFreq2",ins->fm.tomTopFreq); ImGui::EndTable(); } } } bool willDisplayOps=true; if (ins->type==DIV_INS_OPLL && ins->fm.opllPreset!=0) willDisplayOps=false; if (!willDisplayOps && ins->type==DIV_INS_OPLL) { // update OPLL preset preview if (ins->fm.opllPreset>0 && ins->fm.opllPreset<16) { const opll_patch_t* patchROM=NULL; switch (presentWhich) { case 1: patchROM=OPLL_GetPatchROM(opll_type_ymf281); break; case 2: patchROM=OPLL_GetPatchROM(opll_type_ym2423); break; case 3: patchROM=OPLL_GetPatchROM(opll_type_ds1001); break; default: patchROM=OPLL_GetPatchROM(opll_type_ym2413); break; } const opll_patch_t* patch=&patchROM[ins->fm.opllPreset-1]; opllPreview.alg=ins->fm.alg; opllPreview.fb=patch->fb; opllPreview.fms=patch->dc; opllPreview.ams=patch->dm; opllPreview.op[0].tl=patch->tl; opllPreview.op[1].tl=ins->fm.op[1].tl; for (int i=0; i<2; i++) { opllPreview.op[i].am=patch->am[i]; opllPreview.op[i].vib=patch->vib[i]; opllPreview.op[i].ssgEnv=patch->et[i]?8:0; opllPreview.op[i].ksr=patch->ksr[i]; opllPreview.op[i].ksl=patch->ksl[i]; opllPreview.op[i].mult=patch->multi[i]; opllPreview.op[i].ar=patch->ar[i]; opllPreview.op[i].dr=patch->dr[i]; opllPreview.op[i].sl=patch->sl[i]; opllPreview.op[i].rr=patch->rr[i]; } } } ImGui::BeginDisabled(!willDisplayOps); if (settings.fmLayout==0 || settings.fmLayout==7) { int numCols=15; if (ins->type==DIV_INS_OPL ||ins->type==DIV_INS_OPL_DRUMS) numCols=13; if (ins->type==DIV_INS_OPLL) numCols=12; if (ins->type==DIV_INS_OPZ) numCols=19; if (ins->type==DIV_INS_ESFM) numCols=19; if (ImGui::BeginTable("FMOperators",numCols,ImGuiTableFlags_SizingStretchProp|ImGuiTableFlags_BordersH|ImGuiTableFlags_BordersOuterV)) { // configure columns ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); // op name if (ins->type==DIV_INS_ESFM) { ImGui::TableSetupColumn("c0e0",ImGuiTableColumnFlags_WidthStretch,0.05f); // outLvl ImGui::TableSetupColumn("c0e1",ImGuiTableColumnFlags_WidthFixed); // -separator- ImGui::TableSetupColumn("c0e2",ImGuiTableColumnFlags_WidthStretch,0.05f); // delay } ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.05f); // ar ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.05f); // dr if (settings.susPosition==0) { ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.05f); // sl } if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,0.05f); // d2r } ImGui::TableSetupColumn("c5",ImGuiTableColumnFlags_WidthStretch,0.05f); // rr if (settings.susPosition==1) { ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.05f); // sl } ImGui::TableSetupColumn("c6",ImGuiTableColumnFlags_WidthFixed); // -separator- if (settings.susPosition==2) { ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.05f); // sl } ImGui::TableSetupColumn("c7",ImGuiTableColumnFlags_WidthStretch,0.05f); // tl if (settings.susPosition==3) { ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.05f); // sl } ImGui::TableSetupColumn("c8",ImGuiTableColumnFlags_WidthStretch,0.05f); // rs/ksl if (ins->type==DIV_INS_OPZ) { ImGui::TableSetupColumn("c8z0",ImGuiTableColumnFlags_WidthStretch,0.05f); // egs ImGui::TableSetupColumn("c8z1",ImGuiTableColumnFlags_WidthStretch,0.05f); // rev } if (ins->type==DIV_INS_ESFM) { ImGui::TableSetupColumn("c8e0",ImGuiTableColumnFlags_WidthStretch,0.05f); // outLvl } ImGui::TableSetupColumn("c9",ImGuiTableColumnFlags_WidthStretch,0.05f); // mult if (ins->type==DIV_INS_OPZ) { ImGui::TableSetupColumn("c9z",ImGuiTableColumnFlags_WidthStretch,0.05f); // fine } if (ins->type==DIV_INS_ESFM) { ImGui::TableSetupColumn("c9e",ImGuiTableColumnFlags_WidthStretch,0.05f); // ct } if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM || ins->type==DIV_INS_ESFM) { ImGui::TableSetupColumn("c10",ImGuiTableColumnFlags_WidthStretch,0.05f); // dt } if (ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableSetupColumn("c11",ImGuiTableColumnFlags_WidthStretch,0.05f); // dt2 } ImGui::TableSetupColumn("c15",ImGuiTableColumnFlags_WidthFixed); // am ImGui::TableSetupColumn("c12",ImGuiTableColumnFlags_WidthFixed); // -separator- if (ins->type!=DIV_INS_OPLL && ins->type!=DIV_INS_OPM) { ImGui::TableSetupColumn("c13",ImGuiTableColumnFlags_WidthStretch,0.2f); // ssg/waveform } ImGui::TableSetupColumn("c14",ImGuiTableColumnFlags_WidthStretch,0.3f); // env float sliderHeight=((ImGui::GetContentRegionAvail().y-ImGui::GetFrameHeightWithSpacing()*(settings.fmLayout==7?4.0f:1.0f))/opCount)-ImGui::GetStyle().ItemSpacing.y; // header if (settings.fmLayout==0) { insTabFMModernHeader(ins); } // main view for (int i=0; itype!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_ESFM)?opOrder[i]:i]; DivInstrumentESFM::Operator& opE=ins->esfm.op[i]; // modern with more labels if (settings.fmLayout==7) { insTabFMModernHeader(ins); } ImGui::TableNextRow(); ImGui::TableNextColumn(); // push colors if (settings.separateFMColors) { bool mod=true; if (ins->type==DIV_INS_OPL_DRUMS) { mod=false; } else if (ins->type==DIV_INS_ESFM) { // this is the same as the KVS heuristic in platform/esfm.h if (opE.outLvl==7) { mod=false; } else if (opE.outLvl>0) { if (i==3) { mod=false; } else { DivInstrumentESFM::Operator& opENext=ins->esfm.op[i+1]; if (opENext.modIn==0) { mod=false; } else if ((opE.outLvl-opENext.modIn)>=2) { mod=false; } } } } else if (opCount==4) { if (ins->type==DIV_INS_OPL) { if (opIsOutputOPL[fmOrigin.alg&3][i]) mod=false; } else { if (opIsOutput[fmOrigin.alg&7][i]) mod=false; } } else { if (i==1 || (ins->type==DIV_INS_OPL && (fmOrigin.alg&1))) mod=false; } if (mod) { pushAccentColors( uiColors[GUI_COLOR_FM_PRIMARY_MOD], uiColors[GUI_COLOR_FM_SECONDARY_MOD], uiColors[GUI_COLOR_FM_BORDER_MOD], uiColors[GUI_COLOR_FM_BORDER_SHADOW_MOD] ); } else { pushAccentColors( uiColors[GUI_COLOR_FM_PRIMARY_CAR], uiColors[GUI_COLOR_FM_SECONDARY_CAR], uiColors[GUI_COLOR_FM_BORDER_CAR], uiColors[GUI_COLOR_FM_BORDER_SHADOW_CAR] ); } } if (i==0) { float sliderMinHeightOPL=ImGui::GetFrameHeight()*4.0+ImGui::GetStyle().ItemSpacing.y*3.0; float sliderMinHeightESFM=ImGui::GetFrameHeight()*5.0+ImGui::GetStyle().ItemSpacing.y*4.0; if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL) && sliderHeighttype==DIV_INS_ESFM && sliderHeighttype==DIV_INS_OPL_DRUMS) { opNameLabel=fmt::sprintf("%s",oplDrumNames[i]); } else if (ins->type==DIV_INS_OPL && fmOrigin.opllPreset==16) { if (i==1) { opNameLabel=_("Kick"); } else { opNameLabel=_("Env"); } } else { opNameLabel=fmt::sprintf("OP%d",i+1); } if (opsAreMutable) { pushToggleColors(op.enable); if (ImGui::Button(opNameLabel.c_str())) { op.enable=!op.enable; PARAMETER; } popToggleColors(); } else { ImGui::TextUnformatted(opNameLabel.c_str()); } // drag point OP_DRAG_POINT; int maxTl=127; if (ins->type==DIV_INS_OPLL) { if (i==1) { maxTl=15; } else { maxTl=63; } } if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_ESFM) { maxTl=63; } int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM)?31:15; bool ssgOn=op.ssgEnv&8; bool ksrOn=op.ksr; bool vibOn=op.vib; bool susOn=op.sus; bool fixedOn=opE.fixed; unsigned char ssgEnv=op.ssgEnv&7; if (ins->type==DIV_INS_ESFM) { ImGui::TableNextColumn(); CENTER_VSLIDER; P(CWVSliderScalar("##MODIN",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&opE.modIn,&_ZERO,&_SEVEN)); rightClickable ImGui::TableNextColumn(); ImGui::Dummy(ImVec2(4.0f*dpiScale,2.0f*dpiScale)); ImGui::TableNextColumn(); opE.delay&=7; CENTER_VSLIDER; P(CWVSliderScalar("##DELAY",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&opE.delay,&_ZERO,&_SEVEN)); rightClickable } ImGui::TableNextColumn(); op.ar&=maxArDr; CENTER_VSLIDER; P(CWVSliderScalar("##AR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO)); rightClickable ImGui::TableNextColumn(); op.dr&=maxArDr; CENTER_VSLIDER; P(CWVSliderScalar("##DR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO)); rightClickable if (settings.susPosition==0) { ImGui::TableNextColumn(); op.sl&=15; CENTER_VSLIDER; P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable } if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableNextColumn(); op.d2r&=31; CENTER_VSLIDER; P(CWVSliderScalar("##D2R",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO)); rightClickable } ImGui::TableNextColumn(); op.rr&=15; CENTER_VSLIDER; P(CWVSliderScalar("##RR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO)); rightClickable if (settings.susPosition==1) { ImGui::TableNextColumn(); op.sl&=15; CENTER_VSLIDER; P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable } ImGui::TableNextColumn(); ImGui::Dummy(ImVec2(4.0f*dpiScale,2.0f*dpiScale)); if (settings.susPosition==2) { ImGui::TableNextColumn(); op.sl&=15; CENTER_VSLIDER; P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable } ImGui::TableNextColumn(); op.tl&=maxTl; CENTER_VSLIDER; P(CWVSliderScalar("##TL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); rightClickable if (settings.susPosition==3) { ImGui::TableNextColumn(); op.sl&=15; CENTER_VSLIDER; P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable } ImGui::TableNextColumn(); CENTER_VSLIDER; if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { P(CWVSliderScalar("##RS",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE)); rightClickable } else { int ksl=ins->type==DIV_INS_OPLL?op.ksl:kslMap[op.ksl&3]; if (CWVSliderInt("##KSL",ImVec2(20.0f*dpiScale,sliderHeight),&ksl,0,3)) { op.ksl=(ins->type==DIV_INS_OPLL?ksl:kslMap[ksl&3]); PARAMETER; } rightClickable } if (ins->type==DIV_INS_OPZ) { ImGui::TableNextColumn(); CENTER_VSLIDER; P(CWVSliderScalar("##EGS",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); CENTER_VSLIDER; P(CWVSliderScalar("##REV",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dam,&_ZERO,&_SEVEN)); rightClickable } if (ins->type==DIV_INS_ESFM) { ImGui::TableNextColumn(); CENTER_VSLIDER; P(CWVSliderScalar("##OUTLVL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&opE.outLvl,&_ZERO,&_SEVEN)); rightClickable } ImGui::TableNextColumn(); pushWarningColor(ins->type==DIV_INS_OPL_DRUMS && i==0); CENTER_VSLIDER; P(CWVSliderScalar("##MULT",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN)); rightClickable if (ins->type==DIV_INS_OPL_DRUMS && i==0) { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("%s",_("Snare's multiplier is determined by HiHat's.")); } } popWarningColor(); if (ins->type==DIV_INS_OPZ) { ImGui::TableNextColumn(); CENTER_VSLIDER; bool egtOn=op.egt; if (!egtOn) { P(CWVSliderScalar("##FINE",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN)); rightClickable } } if (ins->type==DIV_INS_ESFM) { ImGui::TableNextColumn(); CENTER_VSLIDER; P(CWVSliderScalar("##CT",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_S8,&opE.ct,&_MINUS_TWENTY_FOUR,&_TWENTY_FOUR)); rightClickable } if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { int detune=detuneMap[settings.unsignedDetune?1:0][op.dt&7]; ImGui::TableNextColumn(); CENTER_VSLIDER; if (CWVSliderInt("##DT",ImVec2(20.0f*dpiScale,sliderHeight),&detune,settings.unsignedDetune?0:-3,settings.unsignedDetune?7:4)) { PARAMETER if (detune<-3) detune=-3; if (detune>7) detune=7; op.dt=detuneUnmap[settings.unsignedDetune?1:0][detune+3]; } rightClickable if (ins->type!=DIV_INS_FM) { ImGui::TableNextColumn(); CENTER_VSLIDER; P(CWVSliderScalar("##DT2",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable } ImGui::TableNextColumn(); bool amOn=op.am; if (ins->type==DIV_INS_OPZ) { bool egtOn=op.egt; bool susOn=op.sus; if (egtOn) { ImGui::SetCursorPosY(ImGui::GetCursorPosY()+0.5*(sliderHeight-ImGui::GetFrameHeight()*4.0-ImGui::GetStyle().ItemSpacing.y*3.5)); } else { ImGui::SetCursorPosY(ImGui::GetCursorPosY()+0.5*(sliderHeight-ImGui::GetFrameHeight()*2.0-ImGui::GetStyle().ItemSpacing.y*1.0)); } if (ImGui::Checkbox("AM",&amOn)) { PARAMETER op.am=amOn; } if (ImGui::Checkbox(_("Fixed"),&egtOn)) { PARAMETER op.egt=egtOn; } if (egtOn) { pushWarningColor(susOn && e->song.linearPitch!=2); if (ImGui::Checkbox(_("Pitch control"),&susOn)) { PARAMETER op.sus=susOn; // HACK: reset zoom and scroll in fixed pitch macros so that they draw correctly ins->temp.vZoom[DIV_MACRO_OP_SSG+(i<<5)]=-1; ins->temp.vZoom[DIV_MACRO_OP_SUS+(i<<5)]=-1; } popWarningColor(); if (ImGui::IsItemHovered()) { if (susOn && e->song.linearPitch!=2) { ImGui::SetTooltip(_("only works on linear pitch! go to Compatibility Flags > Pitch/Playback and set Pitch linearity to Full.")); } else { ImGui::SetTooltip(_("use op's arpeggio and pitch macros control instead of block/f-num macros")); } } } if (egtOn && !susOn) { int block=op.dt; int freqNum=(op.mult<<4)|(op.dvb&15); 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; } } } else { ImGui::SetCursorPosY(ImGui::GetCursorPosY()+0.5*(sliderHeight-ImGui::GetFrameHeight())); if (ImGui::Checkbox("##AM",&amOn)) { PARAMETER op.am=amOn; } } if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_OPZ && ins->type!=DIV_INS_OPM) { ImGui::TableNextColumn(); ImGui::Dummy(ImVec2(4.0f*dpiScale,2.0f*dpiScale)); ImGui::TableNextColumn(); ImGui::BeginDisabled(!ssgOn); drawSSGEnv(op.ssgEnv&7,ImVec2(ImGui::GetContentRegionAvail().x,sliderHeight-ImGui::GetFrameHeightWithSpacing())); ImGui::EndDisabled(); if (ImGui::Checkbox("##SSGOn",&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); } ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,_(ssgEnvTypes[ssgEnv]))) { PARAMETER op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); } } } else if (ins->type==DIV_INS_ESFM) { ImGui::TableNextColumn(); CENTER_VSLIDER; P(CWVSliderScalar("##DT",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_S8,&opE.dt,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable ImGui::TableNextColumn(); bool amOn=op.am; bool leftOn=opE.left; bool rightOn=opE.right; ImGui::SetCursorPosY(ImGui::GetCursorPosY()+0.5*(sliderHeight-ImGui::GetFrameHeight()*5.0-ImGui::GetStyle().ItemSpacing.y*4.0)); ImVec2 curPosBeforeDummy = ImGui::GetCursorPos(); ImGui::Dummy(ImVec2(ImGui::GetFrameHeightWithSpacing()*2.0f+ImGui::CalcTextSize(FM_SHORT_NAME(FM_DAM)).x*2.0f,1.0f)); ImGui::SetCursorPos(curPosBeforeDummy); if (ImGui::BeginTable("panCheckboxes",(fixedOn)?3:2,ImGuiTableFlags_SizingStretchProp)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,1.0); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,1.0); if (fixedOn) { ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,1.2); } float yCoordBeforeTablePadding=ImGui::GetCursorPosY(); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetCursorPosY(yCoordBeforeTablePadding); if (ImGui::Checkbox(ESFM_SHORT_NAME(ESFM_LEFT),&leftOn)) { PARAMETER opE.left=leftOn; } ImGui::TableNextColumn(); ImGui::SetCursorPosY(yCoordBeforeTablePadding); if (ImGui::Checkbox(ESFM_SHORT_NAME(ESFM_RIGHT),&rightOn)) { PARAMETER opE.right=rightOn; } if (fixedOn) { ImGui::TableNextColumn(); ImGui::SetCursorPosY(yCoordBeforeTablePadding); if (ImGui::Checkbox(FM_SHORT_NAME(FM_AM),&amOn)) { PARAMETER op.am=amOn; } } ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_SHORT_NAME(FM_KSR),&ksrOn)) { PARAMETER op.ksr=ksrOn; } ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_SHORT_NAME(FM_SUS),&susOn)) { PARAMETER op.sus=susOn; } if (fixedOn) { bool damOn=op.dam; ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_SHORT_NAME(FM_DAM),&damOn)) { PARAMETER op.dam=damOn; } } ImGui::EndTable(); } ImGui::SetCursorPosY(ImGui::GetCursorPosY()-0.5*ImGui::GetStyle().ItemSpacing.y); if (ImGui::Checkbox(ESFM_NAME(ESFM_FIXED),&fixedOn)) { PARAMETER opE.fixed=fixedOn; // HACK: reset zoom and scroll in fixed pitch macros so that they draw correctly ins->temp.vZoom[DIV_MACRO_OP_SSG+(i<<5)]=-1; ins->temp.vZoom[DIV_MACRO_OP_DT+(i<<5)]=-1; } if (ins->type==DIV_INS_ESFM) { if (fixedOn) { int block=(opE.ct>>2)&7; int freqNum=((opE.ct&3)<<8)|((unsigned char)opE.dt); if (ImGui::InputInt(_("Block"),&block,1,1)) { if (block<0) block=0; if (block>7) block=7; opE.ct=(opE.ct&(~(7<<2)))|(block<<2); } if (ImGui::InputInt(_("FreqNum"),&freqNum,1,16)) { if (freqNum<0) freqNum=0; if (freqNum>1023) freqNum=1023; opE.dt=freqNum&0xff; opE.ct=(opE.ct&(~3))|(freqNum>>8); } } else { if (ImGui::BeginTable("amVibCheckboxes",2,ImGuiTableFlags_SizingStretchSame)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); float yCoordBeforeTablePadding=ImGui::GetCursorPosY(); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetCursorPosY(yCoordBeforeTablePadding); if (ImGui::Checkbox(FM_SHORT_NAME(FM_AM),&amOn)) { PARAMETER op.am=amOn; } ImGui::TableNextColumn(); ImGui::SetCursorPosY(yCoordBeforeTablePadding); if (ImGui::Checkbox(FM_SHORT_NAME(FM_VIB),&vibOn)) { PARAMETER op.vib=vibOn; } bool damOn=op.dam; bool dvbOn=op.dvb; ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_SHORT_NAME(FM_DAM),&damOn)) { PARAMETER op.dam=damOn; } ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_SHORT_NAME(FM_DVB),&dvbOn)) { PARAMETER op.dvb=dvbOn; } ImGui::EndTable(); } } } } else if (ins->type!=DIV_INS_OPM) { ImGui::TableNextColumn(); bool amOn=op.am; ImGui::SetCursorPosY(ImGui::GetCursorPosY()+0.5*(sliderHeight-ImGui::GetFrameHeight()*4.0-ImGui::GetStyle().ItemSpacing.y*3.0)); if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER op.am=amOn; } if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER op.vib=vibOn; } if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER op.ksr=ksrOn; } if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER op.sus=susOn; } } else if (ins->type==DIV_INS_OPLL) { if (ImGui::Checkbox(FM_NAME(FM_EGS),&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); } } } if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_ESFM) { ImGui::TableNextColumn(); ImGui::Dummy(ImVec2(4.0f*dpiScale,2.0f*dpiScale)); ImGui::TableNextColumn(); drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(ImGui::GetContentRegionAvail().x,sliderHeight-ImGui::GetFrameHeightWithSpacing()*((ins->type==DIV_INS_ESFM && fixedOn)?3.0f:1.0f))); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { ImGui::SetTooltip(_("OPL2/3/4 only (last 4 waveforms are OPL3/4 only)")); } if (ins->type==DIV_INS_ESFM && fixedOn) { if (ImGui::Checkbox(FM_SHORT_NAME(FM_VIB),&vibOn)) { PARAMETER op.vib=vibOn; } bool dvbOn=op.dvb; if (ImGui::Checkbox(FM_SHORT_NAME(FM_DVB),&dvbOn)) { PARAMETER op.dvb=dvbOn; } } } else if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPM) { ImGui::TableNextColumn(); ImGui::Dummy(ImVec2(4.0f*dpiScale,2.0f*dpiScale)); } ImGui::TableNextColumn(); drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_ESFM)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,fmOrigin.alg,maxTl,maxArDr,15,ImVec2(ImGui::GetContentRegionAvail().x,sliderHeight),ins->type); if (settings.separateFMColors) { popAccentColors(); } ImGui::PopID(); } ImGui::EndTable(); } } else if (settings.fmLayout>=4 && settings.fmLayout<=6) { // alternate int columns=2; switch (settings.fmLayout) { case 4: // 2x2 columns=2; break; case 5: // 1x4 columns=1; break; case 6: // 4x1 columns=opCount; break; } char tempID[1024]; ImVec2 oldPadding=ImGui::GetStyle().CellPadding; ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(8.0f*dpiScale,4.0f*dpiScale)); if (ImGui::BeginTable("AltFMOperators",columns,ImGuiTableFlags_SizingStretchSame|ImGuiTableFlags_BordersInner)) { for (int i=0; itype!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_ESFM)?opOrder[i]:i]; DivInstrumentESFM::Operator& opE=ins->esfm.op[i]; if ((settings.fmLayout!=6 && ((i+1)&1)) || i==0 || settings.fmLayout==5) ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::PushID(fmt::sprintf("op%d",i).c_str()); // push colors if (settings.separateFMColors) { bool mod=true; if (ins->type==DIV_INS_OPL_DRUMS) { mod=false; } else if (ins->type==DIV_INS_ESFM) { // this is the same as the KVS heuristic in platform/esfm.h if (opE.outLvl==7) mod=false; else if (opE.outLvl>0) { if (i==3) mod=false; else { DivInstrumentESFM::Operator& opENext=ins->esfm.op[i+1]; if (opENext.modIn==0) mod=false; else if ((opE.outLvl-opENext.modIn)>=2) mod=false; } } } else if (opCount==4) { if (ins->type==DIV_INS_OPL) { if (opIsOutputOPL[fmOrigin.alg&3][i]) mod=false; } else { if (opIsOutput[fmOrigin.alg&7][i]) mod=false; } } else { if (i==1 || (ins->type==DIV_INS_OPL && (fmOrigin.alg&1))) mod=false; } if (mod) { pushAccentColors( uiColors[GUI_COLOR_FM_PRIMARY_MOD], uiColors[GUI_COLOR_FM_SECONDARY_MOD], uiColors[GUI_COLOR_FM_BORDER_MOD], uiColors[GUI_COLOR_FM_BORDER_SHADOW_MOD] ); } else { pushAccentColors( uiColors[GUI_COLOR_FM_PRIMARY_CAR], uiColors[GUI_COLOR_FM_SECONDARY_CAR], uiColors[GUI_COLOR_FM_BORDER_CAR], uiColors[GUI_COLOR_FM_BORDER_SHADOW_CAR] ); } } ImGui::Dummy(ImVec2(dpiScale,dpiScale)); if (ins->type==DIV_INS_OPL_DRUMS) { snprintf(tempID,1024,"%s",oplDrumNames[i]); } else if (ins->type==DIV_INS_OPL && fmOrigin.opllPreset==16) { if (i==1) { snprintf(tempID,1024,_("Envelope 2 (kick only)")); } else { snprintf(tempID,1024,_("Envelope")); } } else { snprintf(tempID,1024,_("Operator %d"),i+1); } float nextCursorPosX=ImGui::GetCursorPosX()+0.5*(ImGui::GetContentRegionAvail().x-ImGui::CalcTextSize(tempID).x-(opsAreMutable?(ImGui::GetStyle().FramePadding.x*2.0f):0.0f)); OP_DRAG_POINT; ImGui::SameLine(); ImGui::SetCursorPosX(nextCursorPosX); if (opsAreMutable) { pushToggleColors(op.enable); if (ImGui::Button(tempID)) { op.enable=!op.enable; PARAMETER; } popToggleColors(); } else { ImGui::TextUnformatted(tempID); } float sliderHeight=200.0f*dpiScale; float waveWidth=140.0*dpiScale*((ins->type==DIV_INS_ESFM)?0.85f:1.0f); float waveHeight=sliderHeight-ImGui::GetFrameHeightWithSpacing()*((ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPL || ins->type==DIV_INS_ESFM)?5.0f:4.5f); int maxTl=127; if (ins->type==DIV_INS_OPLL) { if (i==1) { maxTl=15; } else { maxTl=63; } } if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_ESFM) { maxTl=63; } int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM)?31:15; bool ssgOn=op.ssgEnv&8; bool ksrOn=op.ksr; bool vibOn=op.vib; bool egtOn=op.egt; bool susOn=op.sus; // yawn unsigned char ssgEnv=op.ssgEnv&7; ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,oldPadding); if (ImGui::BeginTable("opParams",4,ImGuiTableFlags_BordersInnerV)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,waveWidth); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed); ImGui::TableNextRow(); ImGui::TableNextColumn(); float textY=ImGui::GetCursorPosY(); if (ins->type==DIV_INS_ESFM) { CENTER_TEXT_20(ESFM_SHORT_NAME(ESFM_DELAY)); ImGui::TextUnformatted(ESFM_SHORT_NAME(ESFM_DELAY)); TOOLTIP_TEXT(ESFM_LONG_NAME(ESFM_DELAY)); } else { CENTER_TEXT_20(FM_SHORT_NAME(FM_AR)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_AR)); TOOLTIP_TEXT(FM_NAME(FM_AR)); } ImGui::TableNextColumn(); if (ins->type==DIV_INS_FM) { ImGui::Text(_("SSG-EG")); } else if (ins->type!=DIV_INS_OPM) { ImGui::Text(_("Waveform")); } ImGui::TableNextColumn(); ImGui::Text(_("Envelope")); ImGui::TableNextColumn(); // A/D/S/R ImGui::TableNextColumn(); if (ins->type==DIV_INS_ESFM) { opE.delay&=7; P(CWVSliderScalar("##DELAY",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&opE.delay,&_ZERO,&_SEVEN)); rightClickable ImGui::SameLine(); } op.ar&=maxArDr; float textX_AR=ImGui::GetCursorPosX(); P(CWVSliderScalar("##AR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO)); rightClickable ImGui::SameLine(); op.dr&=maxArDr; float textX_DR=ImGui::GetCursorPosX(); P(CWVSliderScalar("##DR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO)); rightClickable float textX_SL=0.0f; if (settings.susPosition==0) { ImGui::SameLine(); op.sl&=15; textX_SL=ImGui::GetCursorPosX(); P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable } float textX_D2R=0.0f; if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::SameLine(); op.d2r&=31; textX_D2R=ImGui::GetCursorPosX(); P(CWVSliderScalar("##D2R",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO)); rightClickable } ImGui::SameLine(); op.rr&=15; float textX_RR=ImGui::GetCursorPosX(); P(CWVSliderScalar("##RR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO)); rightClickable if (settings.susPosition>0) { ImGui::SameLine(); op.sl&=15; textX_SL=ImGui::GetCursorPosX(); P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable } ImVec2 prevCurPos=ImGui::GetCursorPos(); // labels if (ins->type==DIV_INS_ESFM) { ImGui::SetCursorPos(ImVec2(textX_AR,textY)); CENTER_TEXT_20(FM_SHORT_NAME(FM_AR)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_AR)); TOOLTIP_TEXT(FM_NAME(FM_AR)); } ImGui::SetCursorPos(ImVec2(textX_DR,textY)); CENTER_TEXT_20(FM_SHORT_NAME(FM_DR)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_DR)); TOOLTIP_TEXT(FM_NAME(FM_DR)); ImGui::SetCursorPos(ImVec2(textX_SL,textY)); CENTER_TEXT_20(FM_SHORT_NAME(FM_SL)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_SL)); TOOLTIP_TEXT(FM_NAME(FM_SL)); ImGui::SetCursorPos(ImVec2(textX_RR,textY)); CENTER_TEXT_20(FM_SHORT_NAME(FM_RR)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_RR)); TOOLTIP_TEXT(FM_NAME(FM_RR)); if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::SetCursorPos(ImVec2(textX_D2R,textY)); CENTER_TEXT_20(FM_SHORT_NAME(FM_D2R)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_D2R)); TOOLTIP_TEXT(FM_NAME(FM_D2R)); } ImGui::SetCursorPos(prevCurPos); ImGui::TableNextColumn(); switch (ins->type) { case DIV_INS_FM: { // SSG ImGui::BeginDisabled(!ssgOn); drawSSGEnv(op.ssgEnv&7,ImVec2(waveWidth,waveHeight)); ImGui::EndDisabled(); if (ImGui::Checkbox("##SSGOn",&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); } ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,_(ssgEnvTypes[ssgEnv]))) { PARAMETER op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); } // params ImGui::Separator(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable int detune=detuneMap[settings.unsignedDetune?1:0][op.dt&7]; ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT)); if (CWSliderInt("##DT",&detune,settings.unsignedDetune?0:-3,settings.unsignedDetune?7:4,tempID)) { PARAMETER if (detune<-3) detune=-3; if (detune>7) detune=7; op.dt=detuneUnmap[settings.unsignedDetune?1:0][detune+3]; } rightClickable ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS)); P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable break; } case DIV_INS_OPM: { // params ImGui::Separator(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable int detune=detuneMap[settings.unsignedDetune?1:0][op.dt&7]; ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT)); if (CWSliderInt("##DT",&detune,settings.unsignedDetune?0:-3,settings.unsignedDetune?7:4,tempID)) { PARAMETER if (detune<-3) detune=-3; if (detune>7) detune=7; op.dt=detuneUnmap[settings.unsignedDetune?1:0][detune+3]; } rightClickable ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT2)); P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE,tempID)); rightClickable ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS)); P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable break; } case DIV_INS_OPLL: // waveform drawWaveform(i==0?(fmOrigin.ams&1):(fmOrigin.fms&1),ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight)); // params ImGui::Separator(); if (ImGui::BeginTable("FMParamsInner",2)) { ImGui::TableNextRow(); ImGui::TableNextColumn(); bool amOn=op.am; if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER op.am=amOn; } ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER op.ksr=ksrOn; } ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER op.vib=vibOn; } ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_NAME(FM_EGS),&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); } ImGui::EndTable(); } ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_KSL)); P(CWSliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE,tempID)); rightClickable break; case DIV_INS_OPL: case DIV_INS_OPL_DRUMS: { // waveform drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight)); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { ImGui::SetTooltip(_("OPL2/3/4 only (last 4 waveforms are OPL3/4 only)")); } // params ImGui::Separator(); if (ImGui::BeginTable("FMParamsInner",2)) { ImGui::TableNextRow(); ImGui::TableNextColumn(); bool amOn=op.am; if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER op.am=amOn; } ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER op.ksr=ksrOn; } ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER op.vib=vibOn; } ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER op.sus=susOn; } ImGui::EndTable(); } pushWarningColor(ins->type==DIV_INS_OPL_DRUMS && i==0); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable if (ins->type==DIV_INS_OPL_DRUMS && i==0) { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("%s",_("Snare's multiplier is determined by HiHat's.")); } } popWarningColor(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_KSL)); int ksl=kslMap[op.ksl&3]; if (CWSliderInt("##KSL",&ksl,0,3,tempID)) { op.ksl=kslMap[ksl&3]; PARAMETER; } rightClickable break; } case DIV_INS_OPZ: { // waveform drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight)); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { ImGui::SetTooltip(_("OPL2/3/4 only (last 4 waveforms are OPL3/4 only)")); } // params ImGui::Separator(); if (egtOn) { if (!op.sus) { int block=op.dt; int freqNum=(op.mult<<4)|(op.dvb&15); ImGui::Text(_("Block")); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImVec2 cursorAlign=ImGui::GetCursorPos(); if (ImGui::InputInt("##Block",&block,1,1)) { if (block<0) block=0; if (block>7) block=7; op.dt=block; } ImGui::Text(_("Freq")); ImGui::SameLine(); ImGui::SetCursorPos(ImVec2(cursorAlign.x,ImGui::GetCursorPosY())); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); 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; } } } else { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable int detune=detuneMap[settings.unsignedDetune?1:0][op.dt&7]; ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT)); if (CWSliderInt("##DT",&detune,settings.unsignedDetune?0:-3,settings.unsignedDetune?7:4,tempID)) { PARAMETER if (detune<-3) detune=-3; if (detune>7) detune=7; op.dt=detuneUnmap[settings.unsignedDetune?1:0][detune+3]; } rightClickable } ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT2)); P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE,tempID)); rightClickable if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Only on YM2151 and YM2414 (OPM and OPZ)")); } ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS)); P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable break; } case DIV_INS_ESFM: // waveform drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight)); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable // params ImGui::Separator(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable if (opE.fixed) { int block=(opE.ct>>2)&7; int freqNum=((opE.ct&3)<<8)|((unsigned char)opE.dt); ImGui::Text(_("Blk")); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Block")); } ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); //ImVec2 cursorAlign=ImGui::GetCursorPos(); if (ImGui::InputInt("##Block",&block,1,1)) { if (block<0) block=0; if (block>7) block=7; opE.ct=(opE.ct&(~(7<<2)))|(block<<2); } ImGui::Text(_("F")); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Frequency (F-Num)")); } ImGui::SameLine(); //ImGui::SetCursorPos(ImVec2(cursorAlign.x,ImGui::GetCursorPosY())); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::InputInt("##FreqNum",&freqNum,1,16)) { if (freqNum<0) freqNum=0; if (freqNum>1023) freqNum=1023; opE.dt=freqNum&0xff; opE.ct=(opE.ct&(~3))|(freqNum>>8); } } else { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",ESFM_NAME(ESFM_CT)); P(CWSliderScalar("##CT",ImGuiDataType_S8,&opE.ct,&_MINUS_TWENTY_FOUR,&_TWENTY_FOUR,tempID)); rightClickable ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",ESFM_NAME(ESFM_DT)); P(CWSliderScalar("##DT",ImGuiDataType_S8,&opE.dt,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN,tempID)); rightClickable } if (ImGui::BeginTable("panCheckboxes",2,ImGuiTableFlags_SizingStretchSame)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0f); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0f); float yPosOutsideTablePadding=ImGui::GetCursorPosY(); bool leftOn=opE.left; bool rightOn=opE.right; ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetCursorPosY(yPosOutsideTablePadding); if (ImGui::Checkbox(ESFM_SHORT_NAME(ESFM_LEFT),&leftOn)) { PARAMETER opE.left=leftOn; } ImGui::TableNextColumn(); ImGui::SetCursorPosY(yPosOutsideTablePadding); if (ImGui::Checkbox(ESFM_SHORT_NAME(ESFM_RIGHT),&rightOn)) { PARAMETER opE.right=rightOn; } ImGui::EndTable(); } break; default: break; } ImGui::TableNextColumn(); float envHeight=sliderHeight;//-ImGui::GetStyle().ItemSpacing.y*2.0f; if (ins->type==DIV_INS_OPZ) { envHeight-=ImGui::GetFrameHeightWithSpacing()*2.0f; } if (ins->type==DIV_INS_ESFM) { envHeight-=ImGui::GetFrameHeightWithSpacing()*3.0f; } drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_ESFM)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,fmOrigin.alg,maxTl,maxArDr,15,ImVec2(ImGui::GetContentRegionAvail().x,envHeight),ins->type); if (ins->type==DIV_INS_OPZ) { ImGui::Separator(); if (ImGui::BeginTable("FMParamsInnerOPZ",2)) { ImGui::TableNextRow(); ImGui::TableNextColumn(); if (!egtOn) { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); 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; pushWarningColor(susOn && e->song.linearPitch!=2); if (ImGui::Checkbox(_("Pitch control"),&susOn)) { PARAMETER op.sus=susOn; // HACK: reset zoom and scroll in fixed pitch macros so that they draw correctly ins->temp.vZoom[DIV_MACRO_OP_SSG+(i<<5)]=-1; ins->temp.vZoom[DIV_MACRO_OP_SUS+(i<<5)]=-1; } popWarningColor(); if (ImGui::IsItemHovered()) { if (susOn && e->song.linearPitch!=2) { ImGui::SetTooltip(_("only works on linear pitch! go to Compatibility Flags > Pitch/Playback and set Pitch linearity to Full.")); } else { ImGui::SetTooltip(_("use op's arpeggio and pitch macros control instead of block/f-num macros")); } } } ImGui::TableNextColumn(); bool amOn=op.am; if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER op.am=amOn; } ImGui::SameLine(); if (ImGui::Checkbox(_("Fixed"),&egtOn)) { PARAMETER op.egt=egtOn; } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_EGSHIFT)); P(CWSliderScalar("##EGShift",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE,tempID)); rightClickable ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_REV)); P(CWSliderScalar("##REV",ImGuiDataType_U8,&op.dam,&_ZERO,&_SEVEN,tempID)); rightClickable ImGui::TableNextColumn(); ImGui::EndTable(); } } if (ins->type==DIV_INS_ESFM) { ImGui::Separator(); if (ImGui::BeginTable("FMParamsInnerESFM",2)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.64f); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.36f); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_KSL)); int ksl=kslMap[op.ksl&3]; if (CWSliderInt("##KSL",&ksl,0,3,tempID)) { op.ksl=kslMap[ksl&3]; PARAMETER; } rightClickable bool amOn=op.am; bool fixedOn=opE.fixed; ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_SHORT_NAME(FM_KSR),&ksrOn)) { PARAMETER op.ksr=ksrOn; } ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::BeginTable("vibAmCheckboxes",2)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0f); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0f); float yPosOutsideTablePadding=ImGui::GetCursorPosY(); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetCursorPosY(yPosOutsideTablePadding); if (ImGui::Checkbox(FM_SHORT_NAME(FM_VIB),&vibOn)) { PARAMETER op.vib=vibOn; } ImGui::TableNextColumn(); ImGui::SetCursorPosY(yPosOutsideTablePadding); if (ImGui::Checkbox(FM_SHORT_NAME(FM_AM),&amOn)) { PARAMETER op.am=amOn; } bool damOn=op.dam; bool dvbOn=op.dvb; ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_SHORT_NAME(FM_DVB),&dvbOn)) { PARAMETER op.dvb=dvbOn; } ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_SHORT_NAME(FM_DAM),&damOn)) { PARAMETER op.dam=damOn; } ImGui::EndTable(); } ImGui::TableNextColumn(); if (ImGui::Checkbox(FM_SHORT_NAME(FM_SUS),&susOn)) { PARAMETER op.sus=susOn; } if (ImGui::Checkbox(ESFM_NAME(ESFM_FIXED),&fixedOn)) { PARAMETER opE.fixed=fixedOn; // HACK: reset zoom and scroll in fixed pitch macros so that they draw correctly ins->temp.vZoom[DIV_MACRO_OP_SSG+(i<<5)]=-1; ins->temp.vZoom[DIV_MACRO_OP_DT+(i<<5)]=-1; } ImGui::EndTable(); } } ImGui::TableNextColumn(); op.tl&=maxTl; float tlSliderWidth=(ins->type==DIV_INS_ESFM)?20.0f*dpiScale:ImGui::GetFrameHeight(); float tlSliderHeight=sliderHeight-((ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM)?(ImGui::GetFrameHeightWithSpacing()+ImGui::CalcTextSize(FM_SHORT_NAME(FM_AM)).y+ImGui::GetStyle().ItemSpacing.y):0.0f); float textX_tl=ImGui::GetCursorPosX(); P(CWVSliderScalar("##TL",ImVec2(tlSliderWidth,tlSliderHeight),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); rightClickable if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_AM)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_AM)); TOOLTIP_TEXT(FM_NAME(FM_AM)); bool amOn=op.am; if (ImGui::Checkbox("##AM",&amOn)) { PARAMETER op.am=amOn; } } if (ins->type==DIV_INS_ESFM) { ImGui::SameLine(); float textX_outLvl=ImGui::GetCursorPosX(); P(CWVSliderScalar("##OUTLVL",ImVec2(tlSliderWidth,tlSliderHeight),ImGuiDataType_U8,&opE.outLvl,&_ZERO,&_SEVEN)); rightClickable ImGui::SameLine(); float textX_modIn=ImGui::GetCursorPosX(); P(CWVSliderScalar("##MODIN",ImVec2(tlSliderWidth,tlSliderHeight),ImGuiDataType_U8,&opE.modIn,&_ZERO,&_SEVEN)); rightClickable prevCurPos=ImGui::GetCursorPos(); ImGui::SetCursorPos(ImVec2(textX_tl,textY)); CENTER_TEXT_20(FM_SHORT_NAME(FM_TL)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_TL)); TOOLTIP_TEXT(FM_NAME(FM_TL)); ImGui::SetCursorPos(ImVec2(textX_outLvl,textY)); CENTER_TEXT_20(ESFM_SHORT_NAME(ESFM_OUTLVL)); ImGui::TextUnformatted(ESFM_SHORT_NAME(ESFM_OUTLVL)); TOOLTIP_TEXT(ESFM_LONG_NAME(ESFM_OUTLVL)); ImGui::SetCursorPos(ImVec2(textX_modIn,textY)); CENTER_TEXT_20(ESFM_SHORT_NAME(ESFM_MODIN)); ImGui::TextUnformatted(ESFM_SHORT_NAME(ESFM_MODIN)); TOOLTIP_TEXT(ESFM_LONG_NAME(ESFM_MODIN)); ImGui::SetCursorPos(prevCurPos); } else { prevCurPos=ImGui::GetCursorPos(); ImGui::SetCursorPos(ImVec2(textX_tl,textY)); CENTER_TEXT(FM_SHORT_NAME(FM_TL)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_TL)); TOOLTIP_TEXT(FM_NAME(FM_TL)); ImGui::SetCursorPos(prevCurPos); } ImGui::EndTable(); } ImGui::PopStyleVar(); if (settings.separateFMColors) { popAccentColors(); } ImGui::PopID(); } ImGui::EndTable(); } ImGui::PopStyleVar(); } else { // classic int columns=2; switch (settings.fmLayout) { case 1: // 2x2 columns=2; break; case 2: // 1x4 columns=1; break; case 3: // 4x1 columns=opCount; break; } if (ImGui::BeginTable("FMOperators",columns,ImGuiTableFlags_SizingStretchSame)) { for (int i=0; itype!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_ESFM)?opOrder[i]:i]; DivInstrumentESFM::Operator& opE=ins->esfm.op[i]; if ((settings.fmLayout!=3 && ((i+1)&1)) || i==0 || settings.fmLayout==2) ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Separator(); ImGui::PushID(fmt::sprintf("op%d",i).c_str()); // push colors if (settings.separateFMColors) { bool mod=true; if (ins->type==DIV_INS_OPL_DRUMS) { mod=false; } else if (ins->type==DIV_INS_ESFM) { // this is the same as the KVS heuristic in platform/esfm.h if (opE.outLvl==7) { mod=false; } else if (opE.outLvl>0) { if (i==3) { mod=false; } else { DivInstrumentESFM::Operator& opENext=ins->esfm.op[i+1]; if (opENext.modIn==0) { mod=false; } else if ((opE.outLvl-opENext.modIn)>=2) { mod=false; } } } } else if (opCount==4) { if (ins->type==DIV_INS_OPL) { if (opIsOutputOPL[fmOrigin.alg&3][i]) mod=false; } else { if (opIsOutput[fmOrigin.alg&7][i]) mod=false; } } else { if (i==1 || (ins->type==DIV_INS_OPL && (fmOrigin.alg&1))) mod=false; } if (mod) { pushAccentColors( uiColors[GUI_COLOR_FM_PRIMARY_MOD], uiColors[GUI_COLOR_FM_SECONDARY_MOD], uiColors[GUI_COLOR_FM_BORDER_MOD], uiColors[GUI_COLOR_FM_BORDER_SHADOW_MOD] ); } else { pushAccentColors( uiColors[GUI_COLOR_FM_PRIMARY_CAR], uiColors[GUI_COLOR_FM_SECONDARY_CAR], uiColors[GUI_COLOR_FM_BORDER_CAR], uiColors[GUI_COLOR_FM_BORDER_SHADOW_CAR] ); } } ImGui::Dummy(ImVec2(dpiScale,dpiScale)); String opNameLabel; OP_DRAG_POINT; ImGui::SameLine(); if (ins->type==DIV_INS_OPL_DRUMS) { opNameLabel=fmt::sprintf("%s",oplDrumNames[i]); } else if (ins->type==DIV_INS_OPL && fmOrigin.opllPreset==16) { if (i==1) { opNameLabel=_("Envelope 2 (kick only)"); } else { opNameLabel=_("Envelope"); } } else { opNameLabel=fmt::sprintf("OP%d",i+1); } if (opsAreMutable) { pushToggleColors(op.enable); if (ImGui::Button(opNameLabel.c_str())) { op.enable=!op.enable; PARAMETER; } popToggleColors(); } else { ImGui::TextUnformatted(opNameLabel.c_str()); } ImGui::SameLine(); bool amOn=op.am; if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER op.am=amOn; } int maxTl=127; if (ins->type==DIV_INS_OPLL) { if (i==1) { maxTl=15; } else { maxTl=63; } } if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_ESFM) { maxTl=63; } int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM)?31:15; bool ssgOn=op.ssgEnv&8; bool ksrOn=op.ksr; bool vibOn=op.vib; bool susOn=op.sus; // don't you make fun of this one unsigned char ssgEnv=op.ssgEnv&7; if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_OPZ && ins->type!=DIV_INS_OPM && ins->type!=DIV_INS_ESFM) { ImGui::SameLine(); if (ImGui::Checkbox((ins->type==DIV_INS_OPLL)?FM_NAME(FM_EGS):_("SSG On"),&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); } } if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_ESFM) { ImGui::SameLine(); if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER op.sus=susOn; } } if (ins->type==DIV_INS_OPZ) { ImGui::SameLine(); bool fixedOn=op.egt; if (ImGui::Checkbox(_("Fixed"),&fixedOn)) { PARAMETER op.egt=fixedOn; } bool susOn=op.sus; if (fixedOn) { ImGui::SameLine(); pushWarningColor(susOn && e->song.linearPitch!=2); if (ImGui::Checkbox(_("Pitch control"),&susOn)) { PARAMETER op.sus=susOn; // HACK: reset zoom and scroll in fixed pitch macros so that they draw correctly ins->temp.vZoom[DIV_MACRO_OP_SSG+(i<<5)]=-1; ins->temp.vZoom[DIV_MACRO_OP_SUS+(i<<5)]=-1; } popWarningColor(); if (ImGui::IsItemHovered()) { if (susOn && e->song.linearPitch!=2) { ImGui::SetTooltip(_("only works on linear pitch! go to Compatibility Flags > Pitch/Playback and set Pitch linearity to Full.")); } else { ImGui::SetTooltip(_("use op's arpeggio and pitch macros control instead of block/f-num macros")); } } } } //52.0 controls vert scaling; default 96 drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_ESFM)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,fmOrigin.alg,maxTl,maxArDr,15,ImVec2(ImGui::GetContentRegionAvail().x,52.0*dpiScale),ins->type); //P(CWSliderScalar(FM_NAME(FM_AR),ImGuiDataType_U8,&op.ar,&_ZERO,&_THIRTY_ONE)); rightClickable if (ImGui::BeginTable("opParams",2,ImGuiTableFlags_SizingStretchProp)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); \ ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,0.0); \ if (ins->type==DIV_INS_ESFM) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); opE.delay&=7; P(CWSliderScalar("##DELAY",ImGuiDataType_U8,&opE.delay,&_ZERO,&_SEVEN)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",ESFM_NAME(ESFM_DELAY)); } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); op.ar&=maxArDr; P(CWSliderScalar("##AR",ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_AR)); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); op.dr&=maxArDr; P(CWSliderScalar("##DR",ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_DR)); if (settings.susPosition==0) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##SL",ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_SL)); } if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##D2R",ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_D2R)); } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##RR",ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_RR)); if (settings.susPosition>0) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##SL",ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_SL)); } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); op.tl&=maxTl; P(CWSliderScalar("##TL",ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_TL)); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Separator(); ImGui::TableNextColumn(); ImGui::Separator(); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_RS)); } else { int ksl=ins->type==DIV_INS_OPLL?op.ksl:kslMap[op.ksl&3]; if (CWSliderInt("##KSL",&ksl,0,3)) { op.ksl=(ins->type==DIV_INS_OPLL?ksl:kslMap[ksl&3]); PARAMETER; } rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_KSL)); } if (ins->type==DIV_INS_OPZ) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar(FM_NAME(FM_EGSHIFT),ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_EGSHIFT)); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar(FM_NAME(FM_REV),ImGuiDataType_U8,&op.dam,&_ZERO,&_SEVEN)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_REV)); } if (ins->type==DIV_INS_OPZ) { if (op.egt) { bool susOn=op.sus; if (!susOn) { int block=op.dt; int freqNum=(op.mult<<4)|(op.dvb&15); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt(FM_NAME(FM_MULT),&block,0,7)) { PARAMETER if (block<0) block=0; if (block>7) block=7; op.dt=block; } rightClickable ImGui::TableNextColumn(); ImGui::Text("Block"); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt(FM_NAME(FM_FINE),&freqNum,0,255)) { PARAMETER if (freqNum<0) freqNum=0; if (freqNum>255) freqNum=255; op.mult=freqNum>>4; op.dvb=freqNum&15; } rightClickable ImGui::TableNextColumn(); ImGui::Text(_("FreqNum")); } } else { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar(FM_NAME(FM_MULT),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_MULT)); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar(FM_NAME(FM_FINE),ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_FINE)); } } else { ImGui::TableNextRow(); ImGui::TableNextColumn(); pushWarningColor(ins->type==DIV_INS_OPL_DRUMS && i==0); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar(FM_NAME(FM_MULT),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN)); rightClickable if (ins->type==DIV_INS_OPL_DRUMS && i==0) { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("%s",_("Snare's multiplier is determined by HiHat's.")); } } popWarningColor(); ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_MULT)); } if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { if (!(ins->type==DIV_INS_OPZ && op.egt)) { int detune=detuneMap[settings.unsignedDetune?1:0][op.dt&7]; ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##DT",&detune,settings.unsignedDetune?0:-3,settings.unsignedDetune?7:4)) { PARAMETER if (detune<-3) detune=-3; if (detune>7) detune=7; op.dt=detuneUnmap[settings.unsignedDetune?1:0][detune+3]; } rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_DT)); } if (ins->type!=DIV_INS_FM) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_DT2)); } if (ins->type==DIV_INS_FM) { // OPN only ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,_(ssgEnvTypes[ssgEnv]))) { PARAMETER op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); } rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_SSG)); } } if (ins->type==DIV_INS_ESFM) { bool fixedOn=opE.fixed; if (fixedOn) { int block=(opE.ct>>2)&7; int freqNum=((opE.ct&3)<<8)|((unsigned char)opE.dt); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::InputInt("##Block",&block,1,1)) { if (block<0) block=0; if (block>7) block=7; opE.ct=(opE.ct&(~(7<<2)))|(block<<2); } ImGui::TableNextColumn(); ImGui::Text(_("Block")); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::InputInt("##FreqNum",&freqNum,1,16)) { if (freqNum<0) freqNum=0; if (freqNum>1023) freqNum=1023; opE.dt=freqNum&0xff; opE.ct=(opE.ct&(~3))|(freqNum>>8); } ImGui::TableNextColumn(); ImGui::Text(_("FreqNum")); } else { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##CT",ImGuiDataType_S8,&opE.ct,&_MINUS_TWENTY_FOUR,&_TWENTY_FOUR)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",ESFM_NAME(ESFM_CT)); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##DT",ImGuiDataType_S8,&opE.dt,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",ESFM_NAME(ESFM_DT)); } } if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_ESFM) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { ImGui::SetTooltip(_("OPL2/3/4 only (last 4 waveforms are OPL3/4 only)")); } ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_WS)); } if (ins->type==DIV_INS_ESFM) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Separator(); ImGui::TableNextColumn(); ImGui::Separator(); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##OUTLVL",ImGuiDataType_U8,&opE.outLvl,&_ZERO,&_SEVEN)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",ESFM_NAME(ESFM_OUTLVL)); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##MODIN",ImGuiDataType_U8,&opE.modIn,&_ZERO,&_SEVEN)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",ESFM_NAME(ESFM_MODIN)); } ImGui::EndTable(); } if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_ESFM) { if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER op.vib=vibOn; } ImGui::SameLine(); if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER op.ksr=ksrOn; } } if (ins->type==DIV_INS_ESFM) { bool dvbOn=op.dvb; bool damOn=op.dam; bool leftOn=opE.left; bool rightOn=opE.right; bool fixedOn=opE.fixed; if (ImGui::Checkbox(FM_NAME(FM_DVB),&dvbOn)) { PARAMETER op.dvb=dvbOn; } ImGui::SameLine(); if (ImGui::Checkbox(FM_NAME(FM_DAM),&damOn)) { PARAMETER op.dam=damOn; } if (ImGui::Checkbox(ESFM_NAME(ESFM_LEFT),&leftOn)) { PARAMETER opE.left=leftOn; } ImGui::SameLine(); if (ImGui::Checkbox(ESFM_NAME(ESFM_RIGHT),&rightOn)) { PARAMETER opE.right=rightOn; } ImGui::SameLine(); if (ImGui::Checkbox(ESFM_NAME(ESFM_FIXED),&fixedOn)) { PARAMETER opE.fixed=fixedOn; // HACK: reset zoom and scroll in fixed pitch macros so that they draw correctly ins->temp.vZoom[DIV_MACRO_OP_SSG+(i<<5)]=-1; ins->temp.vZoom[DIV_MACRO_OP_DT+(i<<5)]=-1; } } if (settings.separateFMColors) { popAccentColors(); } ImGui::PopID(); } ImGui::EndTable(); } } ImGui::EndDisabled(); ImGui::EndTabItem(); } } void FurnaceGUI::drawInsSID3(DivInstrument* ins) { char buffer[100]; char buffer2[100]; if (ImGui::BeginTabItem("SID3")) { if (ImGui::BeginTable("sid3Waves",2,0)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0f); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,0.0f); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); ImGui::Text(_("Waveform")); ImGui::SameLine(); pushToggleColors(ins->sid3.triOn); if (ImGui::Button(_("tri"))) { PARAMETER ins->sid3.triOn=!ins->sid3.triOn; } popToggleColors(); ImGui::SameLine(); pushToggleColors(ins->sid3.sawOn); if (ImGui::Button(_("saw"))) { PARAMETER ins->sid3.sawOn=!ins->sid3.sawOn; } popToggleColors(); ImGui::SameLine(); pushToggleColors(ins->sid3.pulseOn); if (ImGui::Button(_("pulse"))) { PARAMETER ins->sid3.pulseOn=!ins->sid3.pulseOn; } popToggleColors(); ImGui::SameLine(); pushToggleColors(ins->sid3.noiseOn); if (ImGui::Button(_("noise"))) { PARAMETER ins->sid3.noiseOn=!ins->sid3.noiseOn; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Like in SID2,specific noise LFSR feedback bits config can produce tonal waves.\n" "Refer to the manual for LFSR bits macro configurations for which frequency calculation is altered\n" "in a way that makes tonal noise stay in tune.")); } popToggleColors(); ImGui::SameLine(); P(ImGui::Checkbox(_("1-bit noise"),&ins->sid3.oneBitNoise)); ImGui::SameLine(); pushToggleColors(ins->sid3.specialWaveOn); if (ImGui::Button(_("special"))) { PARAMETER ins->sid3.specialWaveOn=!ins->sid3.specialWaveOn; } popToggleColors(); P(CWSliderScalar(_("Special wave"),ImGuiDataType_U8,&ins->sid3.special_wave,&_ZERO,&_SID3_SPECIAL_WAVES,_(sid3SpecialWaveforms[ins->sid3.special_wave%SID3_NUM_SPECIAL_WAVES]))); rightClickable if (ImGui::Checkbox(_("Wavetable channel"),&ins->sid3.doWavetable)) { PARAMETER; ins->temp.vZoom[DIV_MACRO_WAVE]=-1; for (int i=0; i<256; i++) { ins->std.waveMacro.val[i]=0; } } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Forces waveform macro to control wavetable index.")); } bool invLeft=ins->sid3.phaseInv&SID3_INV_SIGNAL_LEFT; if (ImGui::Checkbox(_("Inv. left"),&invLeft)) { PARAMETER ins->sid3.phaseInv^=SID3_INV_SIGNAL_LEFT; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Invert left channel signal")); } ImGui::SameLine(); bool invRight=ins->sid3.phaseInv&SID3_INV_SIGNAL_RIGHT; if (ImGui::Checkbox(_("Inv. right"),&invRight)) { PARAMETER ins->sid3.phaseInv^=SID3_INV_SIGNAL_RIGHT; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Invert right channel signal")); } ImGui::TableNextColumn(); CENTER_TEXT(_("Special wave preview")); ImGui::TextUnformatted(_("Special wave preview")); drawWaveformSID3(ins->sid3.special_wave,ImVec2(120.0f*dpiScale,70.0f*dpiScale)); ImGui::EndTable(); } ImVec2 sliderSize=ImVec2(30.0f*dpiScale,256.0*dpiScale); if (ImGui::BeginTable("SID3EnvParams",6,ImGuiTableFlags_NoHostExtendX)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c5",ImGuiTableColumnFlags_WidthStretch); ImGui::TableNextRow(); ImGui::TableNextColumn(); CENTER_TEXT(_("A")); ImGui::TextUnformatted(_("A")); ImGui::TableNextColumn(); CENTER_TEXT(_("D")); ImGui::TextUnformatted(_("D")); ImGui::TableNextColumn(); CENTER_TEXT(_("S")); ImGui::TextUnformatted(_("S")); ImGui::TableNextColumn(); CENTER_TEXT(_("SR")); ImGui::TextUnformatted(_("SR")); ImGui::TableNextColumn(); CENTER_TEXT(_("R")); ImGui::TextUnformatted(_("R")); ImGui::TableNextColumn(); CENTER_TEXT(_("Envelope")); ImGui::TextUnformatted(_("Envelope")); ImGui::TableNextRow(); ImGui::TableNextColumn(); P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->sid3.a,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable ImGui::TableNextColumn(); P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->sid3.d,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable ImGui::TableNextColumn(); P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->sid3.s,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable ImGui::TableNextColumn(); P(CWVSliderScalar("##SustainRate",sliderSize,ImGuiDataType_U8,&ins->sid3.sr,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable ImGui::TableNextColumn(); P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->sid3.r,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable ImGui::TableNextColumn(); // the (ins->sid3.r==15?(ins->sid3.r-1):ins->sid3.r) is used so release part never becomes horizontal (which isn't the case with SID3 envelope) drawSID3Env(0,(ins->sid3.a==0?(255):(256-ins->sid3.a)),(ins->sid3.d==0?(255):(256-ins->sid3.d)),ins->sid3.sr,255-(ins->sid3.r==255?(ins->sid3.r-1):ins->sid3.r),255-ins->sid3.s,0,0,0,255,256,255,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); ImGui::EndTable(); } if (!ins->sid3.doWavetable) { strncpy(buffer,macroSID3WaveMixMode(0,(float)ins->sid3.mixMode,NULL).c_str(),40); P(CWSliderScalar(_("Wave Mix Mode"),ImGuiDataType_U8,&ins->sid3.mixMode,&_ZERO,&_FOUR,buffer)); P(CWSliderScalar(_("Duty"),ImGuiDataType_U16,&ins->sid3.duty,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable P(CWSliderScalar(_("Feedback"),ImGuiDataType_U8,&ins->sid3.feedback,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); bool resetDuty=ins->sid3.resetDuty; if (ImGui::Checkbox(_("Reset duty on new note"),&resetDuty)) { PARAMETER ins->sid3.resetDuty=resetDuty; } if (ImGui::Checkbox(_("Absolute Duty Macro"),&ins->sid3.dutyIsAbs)) { ins->temp.vZoom[DIV_MACRO_DUTY]=-1; PARAMETER; } } bool ringMod=ins->sid3.ringMod; if (ImGui::Checkbox(_("Ring Modulation"),&ringMod)) { PARAMETER ins->sid3.ringMod=ringMod; } ImGui::SameLine(); strncpy(buffer,macroSID3SourceChan(0,(float)ins->sid3.ring_mod_source,NULL).c_str(),40); P(CWSliderScalar(_("Source channel##rmsrc"),ImGuiDataType_U8,&ins->sid3.ring_mod_source,&_ZERO,&_SID3_NUM_CHANNELS,buffer)); bool oscSync=ins->sid3.oscSync; if (ImGui::Checkbox(_("Oscillator Sync"),&oscSync)) { PARAMETER ins->sid3.oscSync=oscSync; } ImGui::SameLine(); strncpy(buffer,macroSID3SourceChan(0,(float)ins->sid3.sync_source,NULL).c_str(),40); P(CWSliderScalar(_("Source channel##hssrc"),ImGuiDataType_U8,&ins->sid3.sync_source,&_ZERO,&_SID3_NUM_CHANNELS_MINUS_ONE,buffer)); bool phaseMod=ins->sid3.phase_mod; if (ImGui::Checkbox(_("Phase modulation"),&phaseMod)) { PARAMETER ins->sid3.phase_mod=phaseMod; } ImGui::SameLine(); strncpy(buffer,macroSID3SourceChan(0,(float)ins->sid3.phase_mod_source,NULL).c_str(),40); P(CWSliderScalar(_("Source channel##pmsrc"),ImGuiDataType_U8,&ins->sid3.phase_mod_source,&_ZERO,&_SID3_NUM_CHANNELS_MINUS_ONE,buffer)); ImGui::Separator(); if (!ins->sid3.doWavetable) { bool sepNoisePitch=ins->sid3.separateNoisePitch; if (ImGui::Checkbox(_("Separate noise pitch"),&sepNoisePitch)) { PARAMETER ins->sid3.separateNoisePitch=sepNoisePitch; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Make noise pitch independent from other waves' pitch.\nNoise pitch will be controllable via macros.")); } } for (int i=0; isid3.filt[i]; if (filt->enabled) { ImGui::Separator(); } bool enable=filt->enabled; snprintf(buffer,100,_("Enable filter %d"),i+1); if (ImGui::Checkbox(buffer,&enable)) { PARAMETER filt->enabled=enable; } if (filt->enabled) { bool init=filt->init; snprintf(buffer,100,_("Initialize filter %d"),i+1); if (ImGui::Checkbox(buffer,&init)) { PARAMETER filt->init=init; } ImGui::SameLine(); snprintf(buffer,100,_("Connect to channel input##contoinput%d"),i+1); bool toInput=filt->mode&SID3_FILTER_CHANNEL_INPUT; if (ImGui::Checkbox(buffer,&toInput)) { PARAMETER filt->mode^=SID3_FILTER_CHANNEL_INPUT; } snprintf(buffer,100,_("Cutoff##fcut%d"),i+1); P(CWSliderScalar(buffer,ImGuiDataType_U16,&filt->cutoff,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable snprintf(buffer,100,_("Resonance##fres%d"),i+1); P(CWSliderScalar(buffer,ImGuiDataType_U8,&filt->resonance,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable snprintf(buffer,100,_("Output volume##foutvol%d"),i+1); P(CWSliderScalar(buffer,ImGuiDataType_U8,&filt->output_volume,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable snprintf(buffer,100,_("Distortion level##fdist%d"),i+1); P(CWSliderScalar(buffer,ImGuiDataType_U8,&filt->distortion_level,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable ImGui::AlignTextToFramePadding(); ImGui::Text(_("Filter Mode")); ImGui::SameLine(); bool lp=filt->mode&SID3_FILTER_LP; pushToggleColors(lp); snprintf(buffer,100,_("low##flow%d"),i+1); if (ImGui::Button(buffer)) { PARAMETER filt->mode^=SID3_FILTER_LP; } popToggleColors(); ImGui::SameLine(); bool bp=filt->mode&SID3_FILTER_BP; pushToggleColors(bp); snprintf(buffer,100,_("band##fband%d"),i+1); if (ImGui::Button(buffer)) { PARAMETER filt->mode^=SID3_FILTER_BP; } popToggleColors(); ImGui::SameLine(); bool hp=filt->mode&SID3_FILTER_HP; pushToggleColors(hp); snprintf(buffer,100,_("high##fhigh%d"),i+1); if (ImGui::Button(buffer)) { PARAMETER filt->mode^=SID3_FILTER_HP; } popToggleColors(); ImGui::SameLine(); snprintf(buffer,100,_("Connect to channel output##contooutput%d"),i+1); bool toOutput=filt->mode&SID3_FILTER_OUTPUT; if (ImGui::Checkbox(buffer,&toOutput)) { PARAMETER filt->mode^=SID3_FILTER_OUTPUT; } snprintf(buffer,100,_("Absolute cutoff macro##abscutoff%d"),i+1); bool absCutoff=filt->absoluteCutoff; if (ImGui::Checkbox(buffer,&absCutoff)) { PARAMETER filt->absoluteCutoff=!filt->absoluteCutoff; ins->temp.vZoom[DIV_MACRO_OP_D2R+(i<<5)]=-1; } snprintf(buffer,100,_("Change cutoff with pitch##bindcutoff%d"),i+1); P(ImGui::Checkbox(buffer,&filt->bindCutoffToNote)); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Filter cutoff will change with frequency/pitch.\nSee settings below.")); } if (filt->bindCutoffToNote) { snprintf(buffer,100,_("Decrease cutoff when pitch increases##decreasecutoff%d"),i+1); P(ImGui::Checkbox(buffer,&filt->bindCutoffToNoteDir)); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("If this is enabled,filter cutoff will decrease if you increase the pitch.\n" "If this is disabled,filter cutoff will increase if you increase the pitch.")); } snprintf(buffer2,100,_("%s"),noteNameNormal(filt->bindCutoffToNoteCenter%12,(short)(filt->bindCutoffToNoteCenter / 12)-5)); snprintf(buffer,100,_("Cutoff change center note##bindcutcenternote%d"),i+1); P(CWSliderScalar(buffer,ImGuiDataType_U8,&filt->bindCutoffToNoteCenter,&_ZERO,&_ONE_HUNDRED_SEVENTY_NINE,buffer2)); rightClickable if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("The center note for cutoff changes. At this note no cutoff change happens.\nAs pitch goes lower or higher,cutoff changes apply.")); } snprintf(buffer,100,_("Cutoff change strength##bindcutstrength%d"),i+1); P(CWSliderScalar(buffer,ImGuiDataType_U8,&filt->bindCutoffToNoteStrength,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("How much cutoff changes for given pitch change.")); } snprintf(buffer,100,_("Scale cutoff only once on new note##bindcutnn%d"),i+1); P(ImGui::Checkbox(buffer,&filt->bindCutoffOnNote)); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Filter cutoff will be changed only once on new note.\nIf this option is disabled,cutoff scaling will be applied\nevery time a pitch change happens.")); } } snprintf(buffer,100,_("Change resonance with pitch##bindres%d"),i+1); P(ImGui::Checkbox(buffer,&filt->bindResonanceToNote)); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Filter resonance will change with frequency/pitch.\nSee settings below.")); } if (filt->bindResonanceToNote) { snprintf(buffer,100,_("Decrease resonance when pitch increases##decreaseres%d"),i+1); P(ImGui::Checkbox(buffer,&filt->bindResonanceToNoteDir)); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("If this is enabled,filter resonance will decrease if you increase the pitch.\n" "If this is disabled,filter resonance will increase if you increase the pitch.")); } snprintf(buffer2,100,_("%s"),noteNameNormal(filt->bindResonanceToNoteCenter%12,(short)(filt->bindResonanceToNoteCenter / 12)-5)); snprintf(buffer,100,_("Resonance change center note##bindrescenternote%d"),i+1); P(CWSliderScalar(buffer,ImGuiDataType_U8,&filt->bindResonanceToNoteCenter,&_ZERO,&_ONE_HUNDRED_SEVENTY_NINE,buffer2)); rightClickable if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("The center note for resonance changes. At this note no resonance change happens.\nAs pitch goes lower or higher,resonance changes apply.")); } snprintf(buffer,100,_("Resonance change strength##bindresstrength%d"),i+1); P(CWSliderScalar(buffer,ImGuiDataType_U8,&filt->bindResonanceToNoteStrength,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("How much resonance changes for given pitch change.")); } snprintf(buffer,100,_("Scale resonance only once on new note##bindresnn%d"),i+1); P(ImGui::Checkbox(buffer,&filt->bindResonanceOnNote)); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Filter resonance will be changed only once on new note.\nIf this option is disabled,resonance scaling will be applied\nevery time a pitch change happens.")); } } } } ImGui::Separator(); if (ImGui::BeginTable("SID3filtmatrix",1)) { if (waveGenVisible) ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,250.0f*dpiScale); ImGui::TableNextRow(); ImGui::TableNextColumn(); CENTER_TEXT(_("Filters connection matrix")); ImGui::Text(_("Filters connection matrix")); if (ImGui::BeginTable("SID3checkboxesmatrix",3+SID3_NUM_FILTERS)) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text(">>"); ImGui::TableNextColumn(); ImGui::Text(_("In")); for (int i=0; isid3.filt[i]; ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%d",i+1); ImGui::TableNextColumn(); snprintf(buffer,40,"##filtmatrixin%d",i+1); bool toInput=filt->mode&SID3_FILTER_CHANNEL_INPUT; if (ImGui::Checkbox(buffer,&toInput)) { PARAMETER filt->mode^=SID3_FILTER_CHANNEL_INPUT; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Feed signal from channel to filter %d input"),i+1); } for (int j=0; jfilter_matrix&(1<filter_matrix^=(1<mode&SID3_FILTER_OUTPUT; if (ImGui::Checkbox(buffer,&toOutput)) { PARAMETER filt->mode^=SID3_FILTER_OUTPUT; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Feed signal from filter %d output to channel output"),i+1); } } ImGui::EndTable(); } ImGui::EndTable(); } ImGui::EndTabItem(); } if (!ins->amiga.useSample) { insTabWavetable(ins); } insTabSample(ins); std::vector macroList; for (int i=0; istd.opMacros[i].d2rMacro,ins->sid3.filt[i].absoluteCutoff?0:-65535,65535,160,uiColors[GUI_COLOR_MACRO_FILTER])); macroList.push_back(FurnaceGUIMacroDesc(_("Resonance"),&ins->std.opMacros[i].damMacro,0,255,160,uiColors[GUI_COLOR_MACRO_FILTER])); macroList.push_back(FurnaceGUIMacroDesc(_("Filter Toggle"),&ins->std.opMacros[i].drMacro,0,1,32,uiColors[GUI_COLOR_MACRO_FILTER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Filter Mode"),&ins->std.opMacros[i].ksrMacro,0,3,48,uiColors[GUI_COLOR_MACRO_FILTER],false,NULL,NULL,true,filtModeBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Distortion Level"),&ins->std.opMacros[i].dt2Macro,0,255,160,uiColors[GUI_COLOR_MACRO_FILTER])); macroList.push_back(FurnaceGUIMacroDesc(_("Output Volume"),&ins->std.opMacros[i].dtMacro,0,255,160,uiColors[GUI_COLOR_MACRO_FILTER])); macroList.push_back(FurnaceGUIMacroDesc(_("Channel Input Connection"),&ins->std.opMacros[i].dvbMacro,0,1,32,uiColors[GUI_COLOR_MACRO_FILTER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Channel Output Connection"),&ins->std.opMacros[i].egtMacro,0,1,32,uiColors[GUI_COLOR_MACRO_FILTER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Connection Matrix Row"),&ins->std.opMacros[i].kslMacro,0,SID3_NUM_FILTERS,16*SID3_NUM_FILTERS,uiColors[GUI_COLOR_MACRO_FILTER],false,NULL,NULL,true,sid3FilterMatrixBits)); drawMacros(macroList,macroEditStateOP[i],ins); ImGui::EndTabItem(); } } } void FurnaceGUI::drawInsEdit() { if (nextWindow==GUI_WINDOW_INS_EDIT) { insEditOpen=true; ImGui::SetNextWindowFocus(); nextWindow=GUI_WINDOW_NOTHING; } if (!insEditOpen) return; if (mobileUI) { patWindowPos=(portrait?ImVec2(0.0f,(mobileMenuPos*-0.65*canvasH)):ImVec2((0.16*canvasH)+0.5*canvasW*mobileMenuPos,0.0f)); patWindowSize=(portrait?ImVec2(canvasW,canvasH-(0.16*canvasW)-(pianoOpen?(0.4*canvasW):0.0f)):ImVec2(canvasW-(0.16*canvasH),canvasH-(pianoOpen?(0.3*canvasH):0.0f))); ImGui::SetNextWindowPos(patWindowPos); ImGui::SetNextWindowSize(patWindowSize); } else { ImGui::SetNextWindowSizeConstraints(ImVec2(440.0f*dpiScale,400.0f*dpiScale),ImVec2(canvasW,canvasH)); } if (ImGui::Begin("Instrument Editor",&insEditOpen,globalWinFlags|(settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking),_("Instrument Editor"))) { DivInstrument* ins=NULL; if (curIns==-2) { ImGui::SetCursorPosY(ImGui::GetCursorPosY()+(ImGui::GetContentRegionAvail().y-ImGui::GetFrameHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)*0.5f); CENTER_TEXT(_("waiting...")); ImGui::Text(_("waiting...")); } else if (curIns<0 || curIns>=(int)e->song.ins.size()) { ImGui::SetCursorPosY(ImGui::GetCursorPosY()+(ImGui::GetContentRegionAvail().y-ImGui::GetFrameHeightWithSpacing()*(e->song.ins.empty()?2.0f:3.0f)+ImGui::GetStyle().ItemSpacing.y)*0.5f); CENTER_TEXT(_("no instrument selected")); ImGui::Text(_("no instrument selected")); if (ImGui::BeginTable("noAssetCenter",3)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.5f); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.5f); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TableNextColumn(); if (e->song.ins.size()>0) { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::BeginCombo("##InsSelect",_("select one..."))) { String name; for (size_t i=0; isong.ins.size(); i++) { name=fmt::sprintf("%.2X: %s##_INSS%d",i,e->song.ins[i]->name,i); if (ImGui::Selectable(name.c_str(),curIns==(int)i)) { curIns=i; wavePreviewInit=true; updateFMPreview=true; ins = e->song.ins[curIns]; } } ImGui::EndCombo(); } ImGui::AlignTextToFramePadding(); ImGui::TextUnformatted(_("or")); ImGui::SameLine(); } if (ImGui::Button(_("Open"))) { doAction(GUI_ACTION_INS_LIST_OPEN); } ImGui::SameLine(); ImGui::TextUnformatted(_("or")); ImGui::SameLine(); if (ImGui::Button(_("Create New"))) { doAction(GUI_ACTION_INS_LIST_ADD); } ImGui::TableNextColumn(); ImGui::EndTable(); } } else { ins=e->song.ins[curIns]; if (updateFMPreview) { renderFMPreview(ins); updateFMPreview=false; } if (settings.insEditColorize) { if (ins->type>=DIV_INS_MAX) { pushAccentColors(uiColors[GUI_COLOR_INSTR_UNKNOWN],uiColors[GUI_COLOR_INSTR_UNKNOWN],uiColors[GUI_COLOR_INSTR_UNKNOWN],ImVec4(0.0f,0.0f,0.0f,0.0f)); } else { pushAccentColors(uiColors[GUI_COLOR_INSTR_STD+ins->type],uiColors[GUI_COLOR_INSTR_STD+ins->type],uiColors[GUI_COLOR_INSTR_STD+ins->type],ImVec4(0.0f,0.0f,0.0f,0.0f)); } } if (ImGui::BeginTable("InsProp",3)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); ImGui::TableNextRow(); ImGui::TableNextColumn(); String insIndex=fmt::sprintf("%.2X",curIns); ImGui::SetNextItemWidth(72.0f*dpiScale); if (ImGui::BeginCombo("##InsSelect",insIndex.c_str())) { String name; for (size_t i=0; isong.ins.size(); i++) { name=fmt::sprintf("%.2X: %s##_INSS%d",i,e->song.ins[i]->name,i); if (ImGui::Selectable(name.c_str(),curIns==(int)i)) { curIns=i; ins=e->song.ins[curIns]; wavePreviewInit=true; updateFMPreview=true; } } ImGui::EndCombo(); } ImGui::TableNextColumn(); ImGui::Text(_("Name")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::PushID(2+curIns); if (ImGui::InputText("##Name",&ins->name)) { MARK_MODIFIED; } ImGui::PopID(); ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::Button(ICON_FA_FOLDER_OPEN "##IELoad")) { doAction(GUI_ACTION_INS_LIST_OPEN_REPLACE); } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Open")); } ImGui::SameLine(); if (ImGui::Button(ICON_FA_FLOPPY_O "##IESave")) { doAction(GUI_ACTION_INS_LIST_SAVE); } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Save")); } if (ImGui::BeginPopupContextItem("InsSaveFormats",ImGuiMouseButton_Right)) { if (ImGui::MenuItem(_("save as .dmp..."))) { doAction(GUI_ACTION_INS_LIST_SAVE_DMP); } ImGui::EndPopup(); } ImGui::TableNextColumn(); ImGui::Text(_("Type")); ImGui::TableNextColumn(); int insType=ins->type; ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); bool warnType=true; for (DivInstrumentType i: e->getPossibleInsTypes()) { if (i==insType) { warnType=false; } } pushWarningColor(warnType,warnType && failedNoteOn); if (ImGui::BeginCombo("##Type",(insType>=DIV_INS_MAX)?_("Unknown"):_(insTypes[insType][0]))) { std::vector insTypeList; if (settings.displayAllInsTypes) { for (int i=0; insTypes[i][0]; i++) { insTypeList.push_back((DivInstrumentType)i); } } else { insTypeList=e->getPossibleInsTypes(); } for (DivInstrumentType i: insTypeList) { if (ImGui::Selectable(insTypes[i][0],insType==i)) { ins->type=i; // reset macro zoom memset(ins->temp.vZoom,-1,sizeof(ins->temp.vZoom)); } } ImGui::EndCombo(); } else if (warnType) { if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("none of the currently present chips are able to play this instrument type!")); } } popWarningColor(); ImGui::EndTable(); } if (ImGui::BeginTabBar("insEditTab")) { std::vector macroList; if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPM || ins->type==DIV_INS_ESFM) { char label[32]; int opCount=4; if (ins->type==DIV_INS_OPLL) opCount=2; if (ins->type==DIV_INS_OPL) opCount=(ins->fm.ops==4)?4:2; insTabFM(ins); if (ins->type!=DIV_INS_ESFM) { if (ImGui::BeginTabItem(_("FM Macros"))) { if (ins->type==DIV_INS_OPLL) { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_FB),&ins->std.fbMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DC),&ins->std.fmsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DM),&ins->std.amsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_ALG),&ins->std.algMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_FB),&ins->std.fbMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS) { if (ins->type==DIV_INS_OPZ) { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_FMS),&ins->std.fmsMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AMS),&ins->std.amsMacro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_FMS2),&ins->std.ex9Macro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AMS2),&ins->std.ex10Macro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER])); } else { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_FMS),&ins->std.fmsMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AMS),&ins->std.amsMacro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER])); } } } if (ins->type==DIV_INS_FM) { macroList.push_back(FurnaceGUIMacroDesc(_("LFO Speed"),&ins->std.ex3Macro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER])); } if (ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { macroList.push_back(FurnaceGUIMacroDesc(_("AM Depth"),&ins->std.ex1Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("PM Depth"),&ins->std.ex2Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("LFO Speed"),&ins->std.ex3Macro,0,255,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("LFO Shape"),&ins->std.waveMacro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroLFOWaves)); } if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { macroList.push_back(FurnaceGUIMacroDesc(_("OpMask"),&ins->std.ex4Macro,0,4,128,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,fmOperatorBits)); } else if (ins->type==DIV_INS_OPZ) { macroList.push_back(FurnaceGUIMacroDesc(_("AM Depth 2"),&ins->std.ex5Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("PM Depth 2"),&ins->std.ex6Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("LFO2 Speed"),&ins->std.ex7Macro,0,255,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("LFO2 Shape"),&ins->std.ex8Macro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroLFOWaves)); } drawMacros(macroList,macroEditStateFM,ins); ImGui::EndTabItem(); } } for (int i=0; itype==DIV_INS_OPL_DRUMS) { if (i>0) break; snprintf(label,31,_("Operator Macros")); } else { snprintf(label,31,_("OP%d Macros"),i+1); } if (ImGui::BeginTabItem(label)) { ImGui::PushID(i); int ordi=(opCount==4 && ins->type!=DIV_INS_ESFM)?orderedOps[i]:i; int maxTl=127; if (ins->type==DIV_INS_OPLL) { if (i==1) { maxTl=15; } else { maxTl=63; } } if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_ESFM) { maxTl=63; } int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM)?31:15; if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { 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])); 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_RR),&ins->std.opMacros[ordi].rrMacro,0,15,64,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSL),&ins->std.opMacros[ordi].kslMacro,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_WS),&ins->std.opMacros[ordi].wsMacro,0,7,64,uiColors[GUI_COLOR_MACRO_OTHER])); 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_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)); } else if (ins->type==DIV_INS_OPLL) { 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])); 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_RR),&ins->std.opMacros[ordi].rrMacro,0,15,64,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSL),&ins->std.opMacros[ordi].kslMacro,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_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_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_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])); 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_RR),&ins->std.opMacros[ordi].rrMacro,0,15,64,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSL),&ins->std.opMacros[ordi].kslMacro,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_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])); 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)); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DVB),&ins->std.opMacros[ordi].dvbMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); 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 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])); 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])); 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)); 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],ins); ImGui::PopID(); ImGui::EndTabItem(); } } } if (ins->type==DIV_INS_GB) if (ImGui::BeginTabItem("Game Boy")) { P(ImGui::Checkbox(_("Use software envelope"),&ins->gb.softEnv)); P(ImGui::Checkbox(_("Initialize envelope on every note"),&ins->gb.alwaysInit)); P(ImGui::Checkbox(_("Double wave length (GBA only)"),&ins->gb.doubleWave)); ImGui::BeginDisabled(ins->gb.softEnv); if (ImGui::BeginTable("GBParams",2)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.6f); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.4f); ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::BeginTable("GBParamsI",2)) { ImGui::TableSetupColumn("ci0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("ci1",ImGuiTableColumnFlags_WidthStretch); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text(_("Volume")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##GBVolume",ImGuiDataType_U8,&ins->gb.envVol,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text(_("Length")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##GBEnvLen",ImGuiDataType_U8,&ins->gb.envLen,&_ZERO,&_SEVEN)); rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text(_("Sound Length")); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##GBSoundLen",ImGuiDataType_U8,&ins->gb.soundLen,&_ZERO,&_SIXTY_FOUR,ins->gb.soundLen>63?_("Infinity"):"%d")); rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text(_("Direction")); ImGui::TableNextColumn(); bool goesUp=ins->gb.envDir; if (ImGui::RadioButton(_("Up"),goesUp)) { PARAMETER goesUp=true; ins->gb.envDir=goesUp; } ImGui::SameLine(); if (ImGui::RadioButton(_("Down"),!goesUp)) { PARAMETER goesUp=false; ins->gb.envDir=goesUp; } ImGui::EndTable(); } ImGui::TableNextColumn(); drawGBEnv(ins->gb.envVol,ins->gb.envLen,ins->gb.soundLen,ins->gb.envDir,ImVec2(ImGui::GetContentRegionAvail().x,100.0f*dpiScale)); ImGui::EndTable(); } if (ImGui::BeginChild("HWSeq",ImGui::GetContentRegionAvail(),true,ImGuiWindowFlags_MenuBar)) { ImGui::BeginMenuBar(); ImGui::Text(_("Hardware Sequence")); ImGui::EndMenuBar(); if (ins->gb.hwSeqLen>0) if (ImGui::BeginTable("HWSeqList",3)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); int curFrame=0; ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); ImGui::Text(_("Tick")); ImGui::TableNextColumn(); ImGui::Text(_("Command")); ImGui::TableNextColumn(); ImGui::Text(_("Move/Remove")); for (int i=0; igb.hwSeqLen; i++) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%d (#%d)",curFrame,i); ImGui::TableNextColumn(); ImGui::PushID(i); if (ins->gb.hwSeq[i].cmd>=DivInstrumentGB::DIV_GB_HWCMD_MAX) { ins->gb.hwSeq[i].cmd=0; } int cmd=ins->gb.hwSeq[i].cmd; ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::Combo("##HWSeqCmd",&cmd,LocalizedComboGetter,gbHWSeqCmdTypes,DivInstrumentGB::DIV_GB_HWCMD_MAX)) { if (ins->gb.hwSeq[i].cmd!=cmd) { ins->gb.hwSeq[i].cmd=cmd; ins->gb.hwSeq[i].data=0; } } bool somethingChanged=false; switch (ins->gb.hwSeq[i].cmd) { case DivInstrumentGB::DIV_GB_HWCMD_ENVELOPE: { int hwsVol=(ins->gb.hwSeq[i].data&0xf0)>>4; bool hwsDir=ins->gb.hwSeq[i].data&8; int hwsLen=ins->gb.hwSeq[i].data&7; int hwsSoundLen=ins->gb.hwSeq[i].data>>8; if (CWSliderInt(_("Volume"),&hwsVol,0,15)) { somethingChanged=true; } if (CWSliderInt(_("Env Length"),&hwsLen,0,7)) { somethingChanged=true; } if (CWSliderInt(_("Sound Length"),&hwsSoundLen,0,64,hwsSoundLen>63?_("Infinity"):"%d")) { somethingChanged=true; } if (ImGui::RadioButton(_("Up"),hwsDir)) { PARAMETER hwsDir=true; somethingChanged=true; } ImGui::SameLine(); if (ImGui::RadioButton(_("Down"),!hwsDir)) { PARAMETER hwsDir=false; somethingChanged=true; } if (somethingChanged) { ins->gb.hwSeq[i].data=(hwsLen&7)|(hwsDir?8:0)|(hwsVol<<4)|(hwsSoundLen<<8); PARAMETER; } break; } case DivInstrumentGB::DIV_GB_HWCMD_SWEEP: { int hwsShift=ins->gb.hwSeq[i].data&7; int hwsSpeed=(ins->gb.hwSeq[i].data&0x70)>>4; bool hwsDir=ins->gb.hwSeq[i].data&8; if (CWSliderInt(_("Shift"),&hwsShift,0,7)) { somethingChanged=true; } if (CWSliderInt(_("Speed"),&hwsSpeed,0,7)) { somethingChanged=true; } if (ImGui::RadioButton(_("Up"),!hwsDir)) { PARAMETER hwsDir=false; somethingChanged=true; } ImGui::SameLine(); if (ImGui::RadioButton(_("Down"),hwsDir)) { PARAMETER hwsDir=true; somethingChanged=true; } if (somethingChanged) { ins->gb.hwSeq[i].data=(hwsShift&7)|(hwsDir?8:0)|(hwsSpeed<<4); PARAMETER; } break; } case DivInstrumentGB::DIV_GB_HWCMD_WAIT: { int len=ins->gb.hwSeq[i].data+1; curFrame+=ins->gb.hwSeq[i].data+1; if (ImGui::InputInt(_("Ticks"),&len,1,4)) { if (len<1) len=1; if (len>255) len=256; somethingChanged=true; } if (somethingChanged) { ins->gb.hwSeq[i].data=len-1; PARAMETER; } break; } case DivInstrumentGB::DIV_GB_HWCMD_WAIT_REL: curFrame++; break; case DivInstrumentGB::DIV_GB_HWCMD_LOOP: case DivInstrumentGB::DIV_GB_HWCMD_LOOP_REL: { int pos=ins->gb.hwSeq[i].data; if (ImGui::InputInt(_("Position"),&pos,1,1)) { if (pos<0) pos=0; if (pos>(ins->gb.hwSeqLen-1)) pos=(ins->gb.hwSeqLen-1); somethingChanged=true; } if (somethingChanged) { ins->gb.hwSeq[i].data=pos; PARAMETER; } break; } default: break; } ImGui::PopID(); ImGui::TableNextColumn(); ImGui::PushID(i+512); if (ImGui::Button(ICON_FA_CHEVRON_UP "##HWCmdUp")) { if (i>0) { e->lockEngine([ins,i]() { ins->gb.hwSeq[i-1].cmd^=ins->gb.hwSeq[i].cmd; ins->gb.hwSeq[i].cmd^=ins->gb.hwSeq[i-1].cmd; ins->gb.hwSeq[i-1].cmd^=ins->gb.hwSeq[i].cmd; ins->gb.hwSeq[i-1].data^=ins->gb.hwSeq[i].data; ins->gb.hwSeq[i].data^=ins->gb.hwSeq[i-1].data; ins->gb.hwSeq[i-1].data^=ins->gb.hwSeq[i].data; }); } MARK_MODIFIED; } ImGui::SameLine(); if (ImGui::Button(ICON_FA_CHEVRON_DOWN "##HWCmdDown")) { if (igb.hwSeqLen-1) { e->lockEngine([ins,i]() { ins->gb.hwSeq[i+1].cmd^=ins->gb.hwSeq[i].cmd; ins->gb.hwSeq[i].cmd^=ins->gb.hwSeq[i+1].cmd; ins->gb.hwSeq[i+1].cmd^=ins->gb.hwSeq[i].cmd; ins->gb.hwSeq[i+1].data^=ins->gb.hwSeq[i].data; ins->gb.hwSeq[i].data^=ins->gb.hwSeq[i+1].data; ins->gb.hwSeq[i+1].data^=ins->gb.hwSeq[i].data; }); } MARK_MODIFIED; } ImGui::SameLine(); pushDestColor(); if (ImGui::Button(ICON_FA_TIMES "##HWCmdDel")) { for (int j=i; jgb.hwSeqLen-1; j++) { ins->gb.hwSeq[j].cmd=ins->gb.hwSeq[j+1].cmd; ins->gb.hwSeq[j].data=ins->gb.hwSeq[j+1].data; } ins->gb.hwSeqLen--; } popDestColor(); ImGui::PopID(); } ImGui::EndTable(); } if (ImGui::Button(ICON_FA_PLUS "##HWCmdAdd")) { if (ins->gb.hwSeqLen<255) { ins->gb.hwSeq[ins->gb.hwSeqLen].cmd=0; ins->gb.hwSeq[ins->gb.hwSeqLen].data=0; ins->gb.hwSeqLen++; } } } ImGui::EndChild(); ImGui::EndDisabled(); ImGui::EndTabItem(); } if (ins->type==DIV_INS_C64 || ins->type==DIV_INS_SID2) if (ImGui::BeginTabItem((ins->type==DIV_INS_SID2)?"SID2":"C64")) { ImGui::AlignTextToFramePadding(); ImGui::Text(_("Waveform")); ImGui::SameLine(); pushToggleColors(ins->c64.triOn); if (ImGui::Button(_("tri"))) { PARAMETER ins->c64.triOn=!ins->c64.triOn; } popToggleColors(); ImGui::SameLine(); pushToggleColors(ins->c64.sawOn); if (ImGui::Button(_("saw"))) { PARAMETER ins->c64.sawOn=!ins->c64.sawOn; } popToggleColors(); ImGui::SameLine(); pushToggleColors(ins->c64.pulseOn); if (ImGui::Button(_("pulse"))) { PARAMETER ins->c64.pulseOn=!ins->c64.pulseOn; } popToggleColors(); ImGui::SameLine(); pushToggleColors(ins->c64.noiseOn); if (ImGui::Button(_("noise"))) { PARAMETER ins->c64.noiseOn=!ins->c64.noiseOn; } popToggleColors(); ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale); if (ImGui::BeginTable("C64EnvParams",5,ImGuiTableFlags_NoHostExtendX)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch); ImGui::TableNextRow(); ImGui::TableNextColumn(); CENTER_TEXT("A"); ImGui::TextUnformatted("A"); ImGui::TableNextColumn(); CENTER_TEXT("D"); ImGui::TextUnformatted("D"); ImGui::TableNextColumn(); CENTER_TEXT("S"); ImGui::TextUnformatted("S"); ImGui::TableNextColumn(); CENTER_TEXT("R"); ImGui::TextUnformatted("R"); ImGui::TableNextColumn(); CENTER_TEXT(_("Envelope")); ImGui::TextUnformatted(_("Envelope")); ImGui::TableNextRow(); ImGui::TableNextColumn(); P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->c64.a,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->c64.d,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->c64.s,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->c64.r,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); drawFMEnv((ins->type==DIV_INS_SID2)?(15-ins->sid2.volume):0,16-ins->c64.a,16-ins->c64.d,15-ins->c64.r,15-ins->c64.r,15-ins->c64.s,0,0,0,15,16,15,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); ImGui::EndTable(); } P(CWSliderScalar(_("Duty"),ImGuiDataType_U16,&ins->c64.duty,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE)); rightClickable bool resetDuty=ins->c64.resetDuty; if (ImGui::Checkbox(_("Reset duty on new note"),&resetDuty)) { PARAMETER ins->c64.resetDuty=resetDuty; } bool ringMod=ins->c64.ringMod; if (ImGui::Checkbox(_("Ring Modulation"),&ringMod)) { PARAMETER ins->c64.ringMod=ringMod; } bool oscSync=ins->c64.oscSync; if (ImGui::Checkbox(_("Oscillator Sync"),&oscSync)) { PARAMETER ins->c64.oscSync=oscSync; } P(ImGui::Checkbox(_("Enable filter"),&ins->c64.toFilter)); P(ImGui::Checkbox(_("Initialize filter"),&ins->c64.initFilter)); if (ins->type==DIV_INS_SID2) { P(CWSliderScalar(_("Cutoff"),ImGuiDataType_U16,&ins->c64.cut,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE)); rightClickable P(CWSliderScalar(_("Resonance"),ImGuiDataType_U8,&ins->c64.res,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable } else { P(CWSliderScalar(_("Cutoff"),ImGuiDataType_U16,&ins->c64.cut,&_ZERO,&_TWO_THOUSAND_FORTY_SEVEN)); rightClickable P(CWSliderScalar(_("Resonance"),ImGuiDataType_U8,&ins->c64.res,&_ZERO,&_FIFTEEN)); rightClickable } ImGui::AlignTextToFramePadding(); ImGui::Text(_("Filter Mode")); ImGui::SameLine(); pushToggleColors(ins->c64.lp); if (ImGui::Button(_("low"))) { PARAMETER ins->c64.lp=!ins->c64.lp; } popToggleColors(); ImGui::SameLine(); pushToggleColors(ins->c64.bp); if (ImGui::Button(_("band"))) { PARAMETER ins->c64.bp=!ins->c64.bp; } popToggleColors(); ImGui::SameLine(); pushToggleColors(ins->c64.hp); if (ImGui::Button(_("high"))) { PARAMETER ins->c64.hp=!ins->c64.hp; } popToggleColors(); if (ins->type!=DIV_INS_SID2) { ImGui::SameLine(); pushToggleColors(ins->c64.ch3off); if (ImGui::Button(_("ch3off"))) { PARAMETER ins->c64.ch3off=!ins->c64.ch3off; } popToggleColors(); } if (ins->type==DIV_INS_SID2) { P(CWSliderScalar(_("Noise Mode"),ImGuiDataType_U8,&ins->sid2.noiseMode,&_ZERO,&_THREE)); P(CWSliderScalar(_("Wave Mix Mode"),ImGuiDataType_U8,&ins->sid2.mixMode,&_ZERO,&_THREE,sid2WaveMixModes[ins->sid2.mixMode&3])); } if (ImGui::Checkbox(_("Absolute Cutoff Macro"),&ins->c64.filterIsAbs)) { ins->temp.vZoom[DIV_MACRO_ALG]=-1; PARAMETER; } if (ImGui::Checkbox(_("Absolute Duty Macro"),&ins->c64.dutyIsAbs)) { ins->temp.vZoom[DIV_MACRO_DUTY]=-1; PARAMETER; } if (ins->type!=DIV_INS_SID2) { P(ImGui::Checkbox(_("Don't test before new note"),&ins->c64.noTest)); } ImGui::EndTabItem(); } if (ins->type==DIV_INS_SU) if (ImGui::BeginTabItem("Sound Unit")) { P(ImGui::Checkbox(_("Switch roles of frequency and phase reset timer"),&ins->su.switchRoles)); if (ImGui::BeginChild("HWSeqSU",ImGui::GetContentRegionAvail(),true,ImGuiWindowFlags_MenuBar)) { ImGui::BeginMenuBar(); ImGui::Text(_("Hardware Sequence")); ImGui::EndMenuBar(); if (ins->su.hwSeqLen>0) if (ImGui::BeginTable("HWSeqListSU",3)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); int curFrame=0; ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); ImGui::Text(_("Tick")); ImGui::TableNextColumn(); ImGui::Text(_("Command")); ImGui::TableNextColumn(); ImGui::Text(_("Move/Remove")); for (int i=0; isu.hwSeqLen; i++) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%d (#%d)",curFrame,i); ImGui::TableNextColumn(); ImGui::PushID(i); if (ins->su.hwSeq[i].cmd>=DivInstrumentSoundUnit::DIV_SU_HWCMD_MAX) { ins->su.hwSeq[i].cmd=0; } int cmd=ins->su.hwSeq[i].cmd; ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::Combo("##HWSeqCmd",&cmd,LocalizedComboGetter,suHWSeqCmdTypes,DivInstrumentSoundUnit::DIV_SU_HWCMD_MAX)) { if (ins->su.hwSeq[i].cmd!=cmd) { ins->su.hwSeq[i].cmd=cmd; ins->su.hwSeq[i].val=0; ins->su.hwSeq[i].bound=0; ins->su.hwSeq[i].speed=0; } } bool somethingChanged=false; switch (ins->su.hwSeq[i].cmd) { case DivInstrumentSoundUnit::DIV_SU_HWCMD_VOL: { int swPeriod=ins->su.hwSeq[i].speed; int swBound=ins->su.hwSeq[i].bound; int swVal=ins->su.hwSeq[i].val&31; bool swDir=ins->su.hwSeq[i].val&32; bool swLoop=ins->su.hwSeq[i].val&64; bool swInvert=ins->su.hwSeq[i].val&128; if (ImGui::InputInt(_("Period"),&swPeriod,1,16)) { if (swPeriod<0) swPeriod=0; if (swPeriod>65535) swPeriod=65535; somethingChanged=true; } if (CWSliderInt(_("Amount"),&swVal,0,31)) { somethingChanged=true; } if (CWSliderInt(_("Bound"),&swBound,0,255)) { somethingChanged=true; } if (ImGui::RadioButton(_("Up"),swDir)) { PARAMETER swDir=true; somethingChanged=true; } ImGui::SameLine(); if (ImGui::RadioButton(_("Down"),!swDir)) { PARAMETER swDir=false; somethingChanged=true; } if (ImGui::Checkbox(_("Loop"),&swLoop)) { PARAMETER somethingChanged=true; } ImGui::SameLine(); if (ImGui::Checkbox(_("Flip"),&swInvert)) { PARAMETER somethingChanged=true; } if (somethingChanged) { ins->su.hwSeq[i].speed=swPeriod; ins->su.hwSeq[i].bound=swBound; ins->su.hwSeq[i].val=(swVal&31)|(swDir?32:0)|(swLoop?64:0)|(swInvert?128:0); PARAMETER; } break; } case DivInstrumentSoundUnit::DIV_SU_HWCMD_PITCH: case DivInstrumentSoundUnit::DIV_SU_HWCMD_CUT: { int swPeriod=ins->su.hwSeq[i].speed; int swBound=ins->su.hwSeq[i].bound; int swVal=ins->su.hwSeq[i].val&127; bool swDir=ins->su.hwSeq[i].val&128; if (ImGui::InputInt(_("Period"),&swPeriod,1,16)) { if (swPeriod<0) swPeriod=0; if (swPeriod>65535) swPeriod=65535; somethingChanged=true; } if (CWSliderInt(_("Amount"),&swVal,0,31)) { somethingChanged=true; } if (CWSliderInt(_("Bound"),&swBound,0,255)) { somethingChanged=true; } if (ImGui::RadioButton(_("Up"),swDir)) { PARAMETER swDir=true; somethingChanged=true; } ImGui::SameLine(); if (ImGui::RadioButton(_("Down"),!swDir)) { PARAMETER swDir=false; somethingChanged=true; } if (somethingChanged) { ins->su.hwSeq[i].speed=swPeriod; ins->su.hwSeq[i].bound=swBound; ins->su.hwSeq[i].val=(swVal&127)|(swDir?128:0); PARAMETER; } break; } case DivInstrumentSoundUnit::DIV_SU_HWCMD_WAIT: { int len=ins->su.hwSeq[i].val+1; curFrame+=ins->su.hwSeq[i].val+1; if (ImGui::InputInt(_("Ticks"),&len)) { if (len<1) len=1; if (len>255) len=256; somethingChanged=true; } if (somethingChanged) { ins->su.hwSeq[i].val=len-1; PARAMETER; } break; } case DivInstrumentSoundUnit::DIV_SU_HWCMD_WAIT_REL: curFrame++; break; case DivInstrumentSoundUnit::DIV_SU_HWCMD_LOOP: case DivInstrumentSoundUnit::DIV_SU_HWCMD_LOOP_REL: { int pos=ins->su.hwSeq[i].val; if (ImGui::InputInt(_("Position"),&pos,1,4)) { if (pos<0) pos=0; if (pos>(ins->su.hwSeqLen-1)) pos=(ins->su.hwSeqLen-1); somethingChanged=true; } if (somethingChanged) { ins->su.hwSeq[i].val=pos; PARAMETER; } break; } default: break; } ImGui::PopID(); ImGui::TableNextColumn(); ImGui::PushID(i+512); if (ImGui::Button(ICON_FA_CHEVRON_UP "##HWCmdUp")) { if (i>0) { e->lockEngine([ins,i]() { ins->su.hwSeq[i-1].cmd^=ins->su.hwSeq[i].cmd; ins->su.hwSeq[i].cmd^=ins->su.hwSeq[i-1].cmd; ins->su.hwSeq[i-1].cmd^=ins->su.hwSeq[i].cmd; ins->su.hwSeq[i-1].speed^=ins->su.hwSeq[i].speed; ins->su.hwSeq[i].speed^=ins->su.hwSeq[i-1].speed; ins->su.hwSeq[i-1].speed^=ins->su.hwSeq[i].speed; ins->su.hwSeq[i-1].val^=ins->su.hwSeq[i].val; ins->su.hwSeq[i].val^=ins->su.hwSeq[i-1].val; ins->su.hwSeq[i-1].val^=ins->su.hwSeq[i].val; ins->su.hwSeq[i-1].bound^=ins->su.hwSeq[i].bound; ins->su.hwSeq[i].bound^=ins->su.hwSeq[i-1].bound; ins->su.hwSeq[i-1].bound^=ins->su.hwSeq[i].bound; }); } MARK_MODIFIED; } ImGui::SameLine(); if (ImGui::Button(ICON_FA_CHEVRON_DOWN "##HWCmdDown")) { if (isu.hwSeqLen-1) { e->lockEngine([ins,i]() { ins->su.hwSeq[i+1].cmd^=ins->su.hwSeq[i].cmd; ins->su.hwSeq[i].cmd^=ins->su.hwSeq[i+1].cmd; ins->su.hwSeq[i+1].cmd^=ins->su.hwSeq[i].cmd; ins->su.hwSeq[i+1].speed^=ins->su.hwSeq[i].speed; ins->su.hwSeq[i].speed^=ins->su.hwSeq[i+1].speed; ins->su.hwSeq[i+1].speed^=ins->su.hwSeq[i].speed; ins->su.hwSeq[i+1].val^=ins->su.hwSeq[i].val; ins->su.hwSeq[i].val^=ins->su.hwSeq[i+1].val; ins->su.hwSeq[i+1].val^=ins->su.hwSeq[i].val; ins->su.hwSeq[i+1].bound^=ins->su.hwSeq[i].bound; ins->su.hwSeq[i].bound^=ins->su.hwSeq[i+1].bound; ins->su.hwSeq[i+1].bound^=ins->su.hwSeq[i].bound; }); } MARK_MODIFIED; } ImGui::SameLine(); pushDestColor(); if (ImGui::Button(ICON_FA_TIMES "##HWCmdDel")) { for (int j=i; jsu.hwSeqLen-1; j++) { ins->su.hwSeq[j].cmd=ins->su.hwSeq[j+1].cmd; ins->su.hwSeq[j].speed=ins->su.hwSeq[j+1].speed; ins->su.hwSeq[j].val=ins->su.hwSeq[j+1].val; ins->su.hwSeq[j].bound=ins->su.hwSeq[j+1].bound; } ins->su.hwSeqLen--; } popDestColor(); ImGui::PopID(); } ImGui::EndTable(); } if (ImGui::Button(ICON_FA_PLUS "##HWCmdAdd")) { if (ins->su.hwSeqLen<255) { ins->su.hwSeq[ins->su.hwSeqLen].cmd=0; ins->su.hwSeq[ins->su.hwSeqLen].speed=0; ins->su.hwSeq[ins->su.hwSeqLen].val=0; ins->su.hwSeq[ins->su.hwSeqLen].bound=0; ins->su.hwSeqLen++; } } } ImGui::EndChild(); ImGui::EndTabItem(); } if (ins->type==DIV_INS_SID3) { drawInsSID3(ins); } if (ins->type==DIV_INS_MSM6258 || ins->type==DIV_INS_MSM6295 || ins->type==DIV_INS_ADPCMA || ins->type==DIV_INS_ADPCMB || ins->type==DIV_INS_SEGAPCM || ins->type==DIV_INS_QSOUND || ins->type==DIV_INS_YMZ280B || ins->type==DIV_INS_RF5C68 || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU || ins->type==DIV_INS_SNES || ins->type==DIV_INS_ES5506 || ins->type==DIV_INS_K007232 || ins->type==DIV_INS_GA20 || ins->type==DIV_INS_K053260 || ins->type==DIV_INS_C140 || ins->type==DIV_INS_C219 || ins->type==DIV_INS_NDS || ins->type==DIV_INS_GBA_DMA || ins->type==DIV_INS_GBA_MINMOD || ins->type==DIV_INS_SUPERVISION) { insTabSample(ins); } if (ins->type==DIV_INS_N163) if (ImGui::BeginTabItem("Namco 163")) { bool preLoad=ins->n163.waveMode&0x1; if (ImGui::Checkbox(_("Load waveform"),&preLoad)) { PARAMETER ins->n163.waveMode=(ins->n163.waveMode&~0x1)|(preLoad?0x1:0); } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("when enabled, a waveform will be loaded into RAM.\nwhen disabled, only the offset and length change.")); } if (preLoad) { if (ImGui::InputInt(_("Waveform##WAVE"),&ins->n163.wave,1,10)) { PARAMETER if (ins->n163.wave<0) ins->n163.wave=0; if (ins->n163.wave>=e->song.waveLen) ins->n163.wave=e->song.waveLen-1; } } ImGui::Separator(); P(ImGui::Checkbox(_("Per-channel wave position/length"),&ins->n163.perChanPos)); if (ins->n163.perChanPos) { if (ImGui::BeginTable("N1PerChPos",3)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.5f); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.5f); ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); ImGui::Text(_("Ch")); ImGui::TableNextColumn(); ImGui::Text(_("Position")); ImGui::TableNextColumn(); ImGui::Text(_("Length")); for (int i=0; i<8; i++) { ImGui::PushID(64+i); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Dummy(ImVec2(dpiScale,ImGui::GetFrameHeightWithSpacing())); ImGui::SameLine(); ImGui::Text("%d",i+1); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::InputInt("##pcOff",&ins->n163.wavePosCh[i],1,16)) { PARAMETER if (ins->n163.wavePosCh[i]<0) ins->n163.wavePosCh[i]=0; if (ins->n163.wavePosCh[i]>255) ins->n163.wavePosCh[i]=255; } ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::InputInt("##pcLen",&ins->n163.waveLenCh[i],4,16)) { PARAMETER if (ins->n163.waveLenCh[i]<0) ins->n163.waveLenCh[i]=0; if (ins->n163.waveLenCh[i]>252) ins->n163.waveLenCh[i]=252; ins->n163.waveLenCh[i]&=0xfc; } ImGui::PopID(); } ImGui::EndTable(); } } else { if (ImGui::InputInt("Position##WAVEPOS",&ins->n163.wavePos,1,16)) { PARAMETER if (ins->n163.wavePos<0) ins->n163.wavePos=0; if (ins->n163.wavePos>255) ins->n163.wavePos=255; } if (ImGui::InputInt("Length##WAVELEN",&ins->n163.waveLen,4,16)) { PARAMETER if (ins->n163.waveLen<0) ins->n163.waveLen=0; if (ins->n163.waveLen>252) ins->n163.waveLen=252; ins->n163.waveLen&=0xfc; } } ImGui::EndTabItem(); } if (ins->type==DIV_INS_FDS) if (ImGui::BeginTabItem("FDS")) { float modTable[32]; int modTableInt[256]; ImGui::Checkbox(_("Compatibility mode"),&ins->fds.initModTableWithFirstWave); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("only use for compatibility with .dmf modules!\n- initializes modulation table with first wavetable\n- does not alter modulation parameters on instrument change")); } if (ImGui::InputInt(_("Modulation depth"),&ins->fds.modDepth,1,4)) { if (ins->fds.modDepth<0) ins->fds.modDepth=0; if (ins->fds.modDepth>63) ins->fds.modDepth=63; } if (ImGui::InputInt(_("Modulation speed"),&ins->fds.modSpeed,1,4)) { if (ins->fds.modSpeed<0) ins->fds.modSpeed=0; if (ins->fds.modSpeed>4095) ins->fds.modSpeed=4095; } ImGui::Text(_("Modulation table")); for (int i=0; i<32; i++) { modTable[i]=ins->fds.modTable[i]; modTableInt[i]=ins->fds.modTable[i]; } ImVec2 modTableSize=ImVec2(ImGui::GetContentRegionAvail().x,96.0f*dpiScale); PlotCustom("ModTable",modTable,32,0,NULL,-4,3,modTableSize,sizeof(float),ImVec4(1.0f,1.0f,1.0f,1.0f),0,NULL,NULL,true); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { macroDragStart=ImGui::GetItemRectMin(); macroDragAreaSize=modTableSize; macroDragMin=-4; macroDragMax=3; macroDragBitMode=false; macroDragInitialValueSet=false; macroDragInitialValue=false; macroDragLen=32; macroDragActive=true; macroDragCTarget=(unsigned char*)ins->fds.modTable; macroDragChar=true; macroDragLineMode=false; macroDragLineInitial=ImVec2(0,0); processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); ImGui::InhibitInertialScroll(); } ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); // wavetable text input size found here if (ImGui::InputText("##MMLModTable",&mmlStringModTable)) { int discardIt=0; memset(modTableInt,0,256*sizeof(int)); decodeMMLStrW(mmlStringModTable,modTableInt,discardIt,-4,3,false); for (int i=0; i<32; i++) { if (i>=discardIt) { modTableInt[i]=0; } else { if (modTableInt[i]<-4) modTableInt[i]=-4; if (modTableInt[i]>3) modTableInt[i]=3; } ins->fds.modTable[i]=modTableInt[i]; } MARK_MODIFIED; } if (!ImGui::IsItemActive()) { encodeMMLStr(mmlStringModTable,modTableInt,32,-1,-1,false); } ImGui::EndTabItem(); } if (ins->type==DIV_INS_VBOY) if (ImGui::BeginTabItem("Virtual Boy")) { float modTable[32]; int modTableInt[256]; P(ImGui::Checkbox(_("Set modulation table (channel 5 only)"),&ins->fds.initModTableWithFirstWave)); ImGui::BeginDisabled(!ins->fds.initModTableWithFirstWave); for (int i=0; i<32; i++) { modTable[i]=ins->fds.modTable[i]; modTableInt[i]=modTableHex?((unsigned char)ins->fds.modTable[i]):ins->fds.modTable[i]; } ImVec2 modTableSize=ImVec2(ImGui::GetContentRegionAvail().x,256.0f*dpiScale); PlotCustom("ModTable",modTable,32,0,NULL,-128,127,modTableSize,sizeof(float),ImVec4(1.0f,1.0f,1.0f,1.0f),0,NULL,NULL,true); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { macroDragStart=ImGui::GetItemRectMin(); macroDragAreaSize=modTableSize; macroDragMin=-128; macroDragMax=127; macroDragBitMode=false; macroDragInitialValueSet=false; macroDragInitialValue=false; macroDragLen=32; macroDragActive=true; macroDragCTarget=(unsigned char*)ins->fds.modTable; macroDragChar=true; macroDragLineMode=false; macroDragLineInitial=ImVec2(0,0); processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); ImGui::InhibitInertialScroll(); } if (ImGui::Button(modTableHex?"Hex##MTHex":"Dec##MTHex")) { modTableHex=!modTableHex; } ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); // wavetable text input size found here if (ImGui::InputText("##MMLModTable",&mmlStringModTable)) { int discardIt=0; memset(modTableInt,0,256*sizeof(int)); decodeMMLStrW(mmlStringModTable,modTableInt,discardIt,modTableHex?0:-128,modTableHex?255:127,modTableHex); for (int i=0; i<32; i++) { if (i>=discardIt) { modTableInt[i]=0; } else { if (modTableInt[i]>=128) modTableInt[i]-=256; } ins->fds.modTable[i]=modTableInt[i]; } MARK_MODIFIED; } if (!ImGui::IsItemActive()) { encodeMMLStr(mmlStringModTable,modTableInt,32,-1,-1,modTableHex); } ImGui::SameLine(); ImGui::EndDisabled(); ImGui::EndTabItem(); } if (ins->type==DIV_INS_ES5506) if (ImGui::BeginTabItem("ES5506")) { if (ImGui::BeginTable("ESParams",2,ImGuiTableFlags_SizingStretchSame)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); // filter ImGui::TableNextRow(); ImGui::TableNextColumn(); P(CWSliderScalar(_("Filter Mode"),ImGuiDataType_U8,&ins->es5506.filter.mode,&_ZERO,&_THREE,es5506FilterModes[ins->es5506.filter.mode&3])); ImGui::TableNextRow(); ImGui::TableNextColumn(); P(CWSliderScalar(_("Filter K1"),ImGuiDataType_U16,&ins->es5506.filter.k1,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable ImGui::TableNextColumn(); P(CWSliderScalar(_("Filter K2"),ImGuiDataType_U16,&ins->es5506.filter.k2,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable // envelope ImGui::TableNextRow(); ImGui::TableNextColumn(); P(CWSliderScalar(_("Envelope length"),ImGuiDataType_U16,&ins->es5506.envelope.ecount,&_ZERO,&_FIVE_HUNDRED_ELEVEN)); rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); P(CWSliderScalar(_("Left Volume Ramp"),ImGuiDataType_S8,&ins->es5506.envelope.lVRamp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable ImGui::TableNextColumn(); P(CWSliderScalar(_("Right Volume Ramp"),ImGuiDataType_S8,&ins->es5506.envelope.rVRamp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); P(CWSliderScalar(_("Filter K1 Ramp"),ImGuiDataType_S8,&ins->es5506.envelope.k1Ramp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable ImGui::TableNextColumn(); P(CWSliderScalar(_("Filter K2 Ramp"),ImGuiDataType_S8,&ins->es5506.envelope.k2Ramp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Checkbox(_("K1 Ramp Slowdown"),&ins->es5506.envelope.k1Slow); ImGui::TableNextColumn(); ImGui::Checkbox(_("K2 Ramp Slowdown"),&ins->es5506.envelope.k2Slow); ImGui::EndTable(); } ImGui::EndTabItem(); } if (ins->type==DIV_INS_MULTIPCM) { if (ImGui::BeginTabItem("MultiPCM")) { ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale); if (ImGui::BeginTable("MultiPCMADSRParams",7,ImGuiTableFlags_NoHostExtendX)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c5",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c6",ImGuiTableColumnFlags_WidthStretch); ImGui::TableNextRow(); ImGui::TableNextColumn(); CENTER_TEXT("AR"); ImGui::TextUnformatted("AR"); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Attack Rate")); } ImGui::TableNextColumn(); CENTER_TEXT("D1R"); ImGui::TextUnformatted("D1R"); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Decay 1 Rate")); } ImGui::TableNextColumn(); CENTER_TEXT("DL"); ImGui::TextUnformatted("DL"); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Decay Level")); } ImGui::TableNextColumn(); CENTER_TEXT("D2R"); ImGui::TextUnformatted("D2R"); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Decay 2 Rate")); } ImGui::TableNextColumn(); CENTER_TEXT("RR"); ImGui::TextUnformatted("RR"); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Release Rate")); } ImGui::TableNextColumn(); CENTER_TEXT("RC"); ImGui::TextUnformatted("RC"); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Rate Correction")); } ImGui::TableNextColumn(); CENTER_TEXT(_("Envelope")); ImGui::TextUnformatted(_("Envelope")); ImGui::TableNextRow(); ImGui::TableNextColumn(); P(CWVSliderScalar("##Attack Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.ar,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); P(CWVSliderScalar("##Decay 1 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d1r,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); P(CWVSliderScalar("##Decay Level",sliderSize,ImGuiDataType_U8,&ins->multipcm.dl,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); P(CWVSliderScalar("##Decay 2 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d2r,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); P(CWVSliderScalar("##Release Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.rr,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); P(CWVSliderScalar("##Rate Correction",sliderSize,ImGuiDataType_U8,&ins->multipcm.rc,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); drawFMEnv(0,ins->multipcm.ar,ins->multipcm.d1r,ins->multipcm.d2r,ins->multipcm.rr,ins->multipcm.dl,0,0,0,127,15,15,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); ImGui::EndTable(); } if (ImGui::BeginTable("MultiPCMLFOParams",3,ImGuiTableFlags_SizingStretchSame)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0); ImGui::TableNextColumn(); P(CWSliderScalar(_("LFO Rate"),ImGuiDataType_U8,&ins->multipcm.lfo,&_ZERO,&_SEVEN)); rightClickable ImGui::TableNextColumn(); P(CWSliderScalar(_("PM Depth"),ImGuiDataType_U8,&ins->multipcm.vib,&_ZERO,&_SEVEN)); rightClickable ImGui::TableNextColumn(); P(CWSliderScalar(_("AM Depth"),ImGuiDataType_U8,&ins->multipcm.am,&_ZERO,&_SEVEN)); rightClickable ImGui::EndTable(); } P(ImGui::Checkbox(_("Damp"),&ins->multipcm.damp)); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Only for OPL4 PCM.")); } P(ImGui::Checkbox(_("Pseudo Reverb"),&ins->multipcm.pseudoReverb)); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Only for OPL4 PCM.")); } P(ImGui::Checkbox(_("LFO Reset"),&ins->multipcm.lfoReset)); if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Only for OPL4 PCM.")); } P(ImGui::Checkbox(_("Disable volume change ramp"),&ins->multipcm.levelDirect)); ImGui::EndTabItem(); } } if (ins->type==DIV_INS_SNES) if (ImGui::BeginTabItem("SNES")) { P(ImGui::Checkbox(_("Use envelope"),&ins->snes.useEnv)); ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale); if (ins->snes.useEnv) { if (ImGui::BeginTable("SNESEnvParams",ins->snes.sus?6:5,ImGuiTableFlags_NoHostExtendX)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); if (ins->snes.sus) { ImGui::TableSetupColumn("c2x",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); } ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch); ImGui::TableNextRow(); ImGui::TableNextColumn(); CENTER_TEXT("A"); ImGui::TextUnformatted("A"); ImGui::TableNextColumn(); CENTER_TEXT("D"); ImGui::TextUnformatted("D"); ImGui::TableNextColumn(); CENTER_TEXT("S"); ImGui::TextUnformatted("S"); if (ins->snes.sus) { ImGui::TableNextColumn(); CENTER_TEXT("D2"); ImGui::TextUnformatted("D2"); } ImGui::TableNextColumn(); CENTER_TEXT("R"); ImGui::TextUnformatted("R"); ImGui::TableNextColumn(); CENTER_TEXT(_("Envelope")); ImGui::TextUnformatted(_("Envelope")); ImGui::TableNextRow(); ImGui::TableNextColumn(); P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->snes.a,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->snes.d,&_ZERO,&_SEVEN)); rightClickable ImGui::TableNextColumn(); P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->snes.s,&_ZERO,&_SEVEN)); rightClickable if (ins->snes.sus) { ImGui::TableNextColumn(); P(CWVSliderScalar("##Decay2",sliderSize,ImGuiDataType_U8,&ins->snes.d2,&_ZERO,&_THIRTY_ONE)); rightClickable } ImGui::TableNextColumn(); P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->snes.r,&_ZERO,&_THIRTY_ONE)); rightClickable ImGui::TableNextColumn(); drawFMEnv(0,ins->snes.a+1,1+ins->snes.d*2,ins->snes.sus?ins->snes.d2:ins->snes.r,ins->snes.sus?ins->snes.r:31,(14-ins->snes.s*2),(ins->snes.r==0 || (ins->snes.sus && ins->snes.d2==0)),0,0,7,16,31,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); ImGui::EndTable(); } ImGui::Text(_("Sustain/release mode:")); if (ImGui::RadioButton(_("Direct (cut on release)"),ins->snes.sus==0)) { ins->snes.sus=0; } if (ImGui::RadioButton(_("Effective (linear decrease)"),ins->snes.sus==1)) { ins->snes.sus=1; } if (ImGui::RadioButton(_("Effective (exponential decrease)"),ins->snes.sus==2)) { ins->snes.sus=2; } if (ImGui::RadioButton(_("Delayed (write R on release)"),ins->snes.sus==3)) { ins->snes.sus=3; } } else { if (ImGui::BeginTable("SNESGainParams",2,ImGuiTableFlags_NoHostExtendX)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); ImGui::TableNextRow(); ImGui::TableNextColumn(); CENTER_TEXT(_("Gain Mode")); ImGui::TextUnformatted(_("Gain Mode")); ImGui::TableNextColumn(); CENTER_TEXT(_("Gain")); ImGui::TextUnformatted(_("Gain")); ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::RadioButton(_("Direct"),ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)) { ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DIRECT; PARAMETER; } if (ImGui::RadioButton(_("Decrease (linear)"),ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LINEAR)) { ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LINEAR; PARAMETER; } if (ImGui::RadioButton(_("Decrease (logarithmic)"),ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LOG)) { ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LOG; PARAMETER; } if (ImGui::RadioButton(_("Increase (linear)"),ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_LINEAR)) { ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_LINEAR; PARAMETER; } if (ImGui::RadioButton(_("Increase (bent line)"),ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_INVLOG)) { ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_INVLOG; PARAMETER; } ImGui::TableNextColumn(); unsigned char gainMax=(ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)?127:31; if (ins->snes.gain>gainMax) ins->snes.gain=gainMax; P(CWVSliderScalar("##Gain",sliderSize,ImGuiDataType_U8,&ins->snes.gain,&_ZERO,&gainMax)); rightClickable ImGui::EndTable(); } if (ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LINEAR || ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LOG) { ImGui::TextWrapped(_("using decrease modes will not produce any sound at all, unless you know what you are doing.\nit is recommended to use the Gain macro for decrease instead.")); } } ImGui::EndTabItem(); } if (ins->type==DIV_INS_GB || (ins->type==DIV_INS_AMIGA && ins->amiga.useWave) || (ins->type==DIV_INS_GBA_DMA && ins->amiga.useWave) || (ins->type==DIV_INS_X1_010 && !ins->amiga.useSample) || ins->type==DIV_INS_N163 || ins->type==DIV_INS_FDS || (ins->type==DIV_INS_SWAN && !ins->amiga.useSample) || (ins->type==DIV_INS_PCE && !ins->amiga.useSample) || (ins->type==DIV_INS_VBOY) || ins->type==DIV_INS_SCC || ins->type==DIV_INS_SNES || ins->type==DIV_INS_NAMCO || ins->type==DIV_INS_SM8521 || (ins->type==DIV_INS_GBA_MINMOD && ins->amiga.useWave)) { insTabWavetable(ins); } if (ins->typesong.waveLen-1); switch (ins->type) { case DIV_INS_STD: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Noise Mode"),&ins->std.dutyMacro,0,3,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_FM: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_GB: if (ins->gb.softEnv) { macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); } macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Duty/Noise"),&ins->std.dutyMacro,0,3,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_C64: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Duty"),&ins->std.dutyMacro,ins->c64.dutyIsAbs?0:-4095,4095,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,4,64,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,true,c64ShapeBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Cutoff"),&ins->std.algMacro,ins->c64.filterIsAbs?0:-2047,2047,160,uiColors[GUI_COLOR_MACRO_FILTER])); macroList.push_back(FurnaceGUIMacroDesc(_("Resonance"),&ins->std.ex2Macro,0,15,64,uiColors[GUI_COLOR_MACRO_FILTER])); macroList.push_back(FurnaceGUIMacroDesc(_("Filter Mode"),&ins->std.ex1Macro,0,4,64,uiColors[GUI_COLOR_MACRO_FILTER],false,NULL,NULL,true,filtModeBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Filter Toggle"),&ins->std.ex3Macro,0,1,32,uiColors[GUI_COLOR_MACRO_FILTER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Special"),&ins->std.ex4Macro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,c64TestGateBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Attack"),&ins->std.ex5Macro,0,15,128,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("Decay"),&ins->std.ex6Macro,0,15,128,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("Sustain"),&ins->std.ex7Macro,0,15,128,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("Release"),&ins->std.ex8Macro,0,15,128,uiColors[GUI_COLOR_MACRO_ENVELOPE])); break; case DIV_INS_AMIGA: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,64,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); if (ins->std.panLMacro.mode) { macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,-16,16,63,uiColors[GUI_COLOR_MACRO_OTHER],false,macroQSoundMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Surround"),&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,127,158,uiColors[GUI_COLOR_MACRO_OTHER],false,macroQSoundMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,127,158,uiColors[GUI_COLOR_MACRO_OTHER])); } macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_PCE: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,31,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); if (!ins->amiga.useSample) { macroList.push_back(FurnaceGUIMacroDesc(_("Noise"),&ins->std.dutyMacro,0,1,160,uiColors[GUI_COLOR_MACRO_NOISE])); } macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_AY: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); if (!ins->amiga.useSample) { macroList.push_back(FurnaceGUIMacroDesc(_("Noise Freq"),&ins->std.dutyMacro,0,31,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,3,48,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,true,ayShapeBits)); } macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Envelope"),&ins->std.ex2Macro,0,4,64,uiColors[GUI_COLOR_MACRO_ENVELOPE],false,NULL,NULL,true,ayEnvBits)); macroList.push_back(FurnaceGUIMacroDesc(_("AutoEnv Num"),&ins->std.ex3Macro,0,15,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("AutoEnv Den"),&ins->std.algMacro,0,15,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("Force Period"),&ins->std.ex4Macro,0,4095,160,uiColors[GUI_COLOR_MACRO_PITCH])); macroList.push_back(FurnaceGUIMacroDesc(_("Env Period"),&ins->std.ex5Macro,0,65535,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); break; case DIV_INS_AY8930: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,31,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); if (!ins->amiga.useSample) { macroList.push_back(FurnaceGUIMacroDesc(_("Noise Freq"),&ins->std.dutyMacro,0,255,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,3,64,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,true,ayShapeBits)); } macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Duty"),&ins->std.ex1Macro,0,8,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Envelope"),&ins->std.ex2Macro,0,4,64,uiColors[GUI_COLOR_MACRO_ENVELOPE],false,NULL,NULL,true,ayEnvBits)); macroList.push_back(FurnaceGUIMacroDesc(_("AutoEnv Num"),&ins->std.ex3Macro,0,15,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("AutoEnv Den"),&ins->std.algMacro,0,15,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("Force Period"),&ins->std.ex4Macro,0,65535,160,uiColors[GUI_COLOR_MACRO_PITCH])); macroList.push_back(FurnaceGUIMacroDesc(_("Env Period"),&ins->std.ex5Macro,0,65535,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("Noise AND Mask"),&ins->std.fbMacro,0,8,96,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Noise OR Mask"),&ins->std.fmsMacro,0,8,96,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true)); break; case DIV_INS_TIA: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,15,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); break; case DIV_INS_SAA1099: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Duty/Noise"),&ins->std.dutyMacro,0,3,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,2,64,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,true,ayShapeBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Envelope"),&ins->std.ex1Macro,0,8,160,uiColors[GUI_COLOR_MACRO_ENVELOPE],false,NULL,NULL,true,saaEnvBits)); break; case DIV_INS_VIC: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("On/Off"),&ins->std.dutyMacro,0,1,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,15,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); break; case DIV_INS_PET: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,1,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,8,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,true,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); break; case DIV_INS_VRC6: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); if (!ins->amiga.useSample) { macroList.push_back(FurnaceGUIMacroDesc(_("Duty"),&ins->std.dutyMacro,0,7,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else { macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); } macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); if (ins->amiga.useSample) { macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } break; case DIV_INS_OPLL: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Patch"),&ins->std.waveMacro,0,15,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_OPL: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,63,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,0,4,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_FDS: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,32,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Mod Depth"),&ins->std.ex1Macro,0,63,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Mod Speed"),&ins->std.ex2Macro,0,4095,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Mod Position"),&ins->std.ex3Macro,0,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); break; case DIV_INS_VBOY: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Noise Length"),&ins->std.dutyMacro,0,7,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_N163: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Wave Pos"),&ins->std.dutyMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Wave Length"),&ins->std.ex1Macro,0,252,160,uiColors[GUI_COLOR_MACRO_OTHER])); break; case DIV_INS_SCC: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); break; case DIV_INS_OPZ: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Noise Freq"),&ins->std.dutyMacro,0,32,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_POKEY: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("AUDCTL"),&ins->std.dutyMacro,0,8,160,uiColors[GUI_COLOR_MACRO_GLOBAL],false,NULL,NULL,true,pokeyCtlBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,7,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); break; case DIV_INS_BEEPER: { bool zxPresent=false; for (int i=0; isong.systemLen; i++) { if (e->song.system[i]==DIV_SYSTEM_SFX_BEEPER) { zxPresent=true; break; } } macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,1,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); if (zxPresent) { macroList.push_back(FurnaceGUIMacroDesc(_("Pulse Width"),&ins->std.dutyMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); } macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); break; } case DIV_INS_SWAN: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); if (!ins->amiga.useSample) { macroList.push_back(FurnaceGUIMacroDesc(_("Noise"),&ins->std.dutyMacro,0,8,160,uiColors[GUI_COLOR_MACRO_NOISE])); } macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_MIKEY: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); if (!ins->amiga.useSample) { macroList.push_back(FurnaceGUIMacroDesc(_("Duty/Int"),&ins->std.dutyMacro,0,10,160,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true,mikeyFeedbackBits)); } macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Load LFSR"),&ins->std.ex1Macro,0,12,160,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true)); break; case DIV_INS_VERA: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,63,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Duty"),&ins->std.dutyMacro,0,63,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,3,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); break; case DIV_INS_X1_010: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); if (ins->amiga.useSample) { macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { macroList.push_back(FurnaceGUIMacroDesc(_("Envelope Mode"),&ins->std.ex1Macro,0,7,160,uiColors[GUI_COLOR_MACRO_ENVELOPE],false,NULL,NULL,true,x1_010EnvBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Envelope"),&ins->std.ex2Macro,0,255,160,uiColors[GUI_COLOR_MACRO_ENVELOPE],false,NULL,NULL,false,ayEnvBits)); macroList.push_back(FurnaceGUIMacroDesc(_("AutoEnv Num"),&ins->std.ex3Macro,0,15,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("AutoEnv Den"),&ins->std.algMacro,0,15,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); } break; case DIV_INS_VRC6_SAW: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,63,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); break; case DIV_INS_ES5506: { float usesAmigaVol=true; for (int i=0; isong.systemLen; i++) { if (e->song.system[i]==DIV_SYSTEM_ES5506) { if (!e->song.systemFlags[i].getBool("amigaVol",false)) { usesAmigaVol=false; break; } } } macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,usesAmigaVol?64:4095,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Filter Mode"),&ins->std.dutyMacro,0,3,160,uiColors[GUI_COLOR_MACRO_FILTER],false,NULL,¯oHoverES5506FilterMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,4095,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,4095,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Filter K1"),&ins->std.ex1Macro,((ins->std.ex1Macro.mode==1)?(-65535):0),65535,160,uiColors[GUI_COLOR_MACRO_FILTER],false,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Filter K2"),&ins->std.ex2Macro,((ins->std.ex2Macro.mode==1)?(-65535):0),65535,160,uiColors[GUI_COLOR_MACRO_FILTER],false,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Outputs"),&ins->std.fbMacro,0,5,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Control"),&ins->std.algMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506ControlModes)); break; } case DIV_INS_MULTIPCM: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,-7,7,45,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("LFO Speed"),&ins->std.ex1Macro,0,7,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("LFO Vib Depth"),&ins->std.fmsMacro,0,7,160,uiColors[GUI_COLOR_MACRO_PITCH])); macroList.push_back(FurnaceGUIMacroDesc(_("LFO AM Depth"),&ins->std.amsMacro,0,7,160,uiColors[GUI_COLOR_MACRO_VOLUME])); break; case DIV_INS_SNES: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Noise Freq"),&ins->std.dutyMacro,0,31,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,127,158,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,127,158,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Special"),&ins->std.ex1Macro,0,5,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,snesModeBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Gain"),&ins->std.ex2Macro,0,255,256,uiColors[GUI_COLOR_MACRO_VOLUME],false,NULL,macroHoverGain,false)); break; case DIV_INS_SU: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Duty/Noise"),&ins->std.dutyMacro,0,127,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,7,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,-127,127,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Cutoff"),&ins->std.ex1Macro,0,16383,160,uiColors[GUI_COLOR_MACRO_FILTER])); macroList.push_back(FurnaceGUIMacroDesc(_("Resonance"),&ins->std.ex2Macro,0,255,160,uiColors[GUI_COLOR_MACRO_FILTER])); macroList.push_back(FurnaceGUIMacroDesc(_("Control"),&ins->std.ex3Macro,0,4,64,uiColors[GUI_COLOR_MACRO_FILTER],false,NULL,NULL,true,suControlBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset Timer"),&ins->std.ex4Macro,0,65535,160,uiColors[GUI_COLOR_MACRO_PITCH])); // again reuse code from resonance macro but use ex4 instead break; case DIV_INS_NAMCO: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Noise"),&ins->std.dutyMacro,0,1,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); break; case DIV_INS_OPL_DRUMS: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,63,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,0,4,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_OPM: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Noise Freq"),&ins->std.dutyMacro,0,32,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_NES: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Duty/Noise"),&ins->std.dutyMacro,0,3,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_MSM6258: macroList.push_back(FurnaceGUIMacroDesc(_("Freq Divider"),&ins->std.dutyMacro,0,2,160,uiColors[GUI_COLOR_MACRO_GLOBAL])); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Clock Divider"),&ins->std.ex1Macro,0,1,160,uiColors[GUI_COLOR_MACRO_GLOBAL])); break; case DIV_INS_MSM6295: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,8,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Freq Divider"),&ins->std.dutyMacro,0,1,160,uiColors[GUI_COLOR_MACRO_GLOBAL])); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_ADPCMA: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,31,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Global Volume"),&ins->std.dutyMacro,0,63,160,uiColors[GUI_COLOR_MACRO_GLOBAL])); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_ADPCMB: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,255,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_SEGAPCM: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,127,158,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,127,158,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_QSOUND: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,16383,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Echo Level"),&ins->std.dutyMacro,0,32767,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,-16,16,63,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Surround"),&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Echo Feedback"),&ins->std.ex1Macro,0,16383,160,uiColors[GUI_COLOR_MACRO_GLOBAL])); macroList.push_back(FurnaceGUIMacroDesc(_("Echo Length"),&ins->std.ex2Macro,0,2725,160,uiColors[GUI_COLOR_MACRO_GLOBAL])); break; case DIV_INS_YMZ280B: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,255,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,-7,7,45,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_RF5C68: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,255,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_MSM5232: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Group Ctrl"),&ins->std.dutyMacro,0,5,160,uiColors[GUI_COLOR_MACRO_GLOBAL],false,NULL,NULL,true,msm5232ControlBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Group Attack"),&ins->std.ex1Macro,0,5,96,uiColors[GUI_COLOR_MACRO_GLOBAL])); macroList.push_back(FurnaceGUIMacroDesc(_("Group Decay"),&ins->std.ex2Macro,0,11,160,uiColors[GUI_COLOR_MACRO_GLOBAL])); macroList.push_back(FurnaceGUIMacroDesc(_("Noise"),&ins->std.ex3Macro,0,1,32,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true)); break; case DIV_INS_T6W28: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Noise Type"),&ins->std.dutyMacro,0,1,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_K007232: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_GA20: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,255,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_POKEMINI: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,2,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Pulse Width"),&ins->std.dutyMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); break; case DIV_INS_SUPERVISION: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Duty/Noise"),&ins->std.dutyMacro,0,3,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Noise/PCM Pan"),&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); break; case DIV_INS_SM8521: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,31,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); break; case DIV_INS_PV1000: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,1,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); break; case DIV_INS_K053260: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,-3,3,37,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_TED: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,8,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Square/Noise"),&ins->std.dutyMacro,0,2,80,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true,tedControlBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_C140: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,255,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_C219: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,255,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Control"),&ins->std.dutyMacro,0,3,120,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,c219ControlBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_ESFM: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,63,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("OP4 Noise Mode"),&ins->std.dutyMacro,0,3,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_POWERNOISE: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Control"),&ins->std.ex1Macro,0,2,32,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true,powerNoiseControlBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Tap A Location"),&ins->std.ex4Macro,0,15,96,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Tap B Location"),&ins->std.ex5Macro,0,15,96,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Load LFSR"),&ins->std.ex8Macro,0,16,256,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true)); break; case DIV_INS_POWERNOISE_SLOPE: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Control"),&ins->std.ex1Macro,0,6,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,powerNoiseSlopeControlBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Portion A Length"),&ins->std.ex2Macro,0,255,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Portion B Length"),&ins->std.ex3Macro,0,255,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Portion A Offset"),&ins->std.ex6Macro,0,15,96,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Portion B Offset"),&ins->std.ex7Macro,0,15,96,uiColors[GUI_COLOR_MACRO_OTHER])); break; case DIV_INS_DAVE: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,63,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Noise Freq"),&ins->std.dutyMacro,0,3,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,4,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,63,94,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,63,94,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Control"),&ins->std.ex1Macro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,daveControlBits)); break; case DIV_INS_NDS: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); if (!ins->amiga.useSample) { macroList.push_back(FurnaceGUIMacroDesc(_("Duty"),&ins->std.dutyMacro,0,7,160,uiColors[GUI_COLOR_MACRO_OTHER])); } macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,-64,63,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_GBA_DMA: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,2,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); break; case DIV_INS_GBA_MINMOD: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,255,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Special"),&ins->std.ex1Macro,0,2,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,minModModeBits)); break; case DIV_INS_BIFURCATOR: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,255,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Parameter"),&ins->std.dutyMacro,0,65535,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Load Value"),&ins->std.ex1Macro,0,65535,160,uiColors[GUI_COLOR_MACRO_OTHER])); break; case DIV_INS_SID2: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Duty"),&ins->std.dutyMacro,ins->c64.dutyIsAbs?0:-4095,4095,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,4,64,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,true,c64ShapeBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Cutoff"),&ins->std.algMacro,ins->c64.filterIsAbs?0:-4095,4095,160,uiColors[GUI_COLOR_MACRO_FILTER])); macroList.push_back(FurnaceGUIMacroDesc(_("Resonance"),&ins->std.ex2Macro,0,255,160,uiColors[GUI_COLOR_MACRO_FILTER])); macroList.push_back(FurnaceGUIMacroDesc(_("Filter Mode"),&ins->std.ex1Macro,0,3,64,uiColors[GUI_COLOR_MACRO_FILTER],false,NULL,NULL,true,filtModeBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Filter Toggle"),&ins->std.ex3Macro,0,1,32,uiColors[GUI_COLOR_MACRO_FILTER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Special"),&ins->std.ex4Macro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,sid2ControlBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Attack"),&ins->std.ex5Macro,0,15,128,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("Decay"),&ins->std.ex6Macro,0,15,128,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("Sustain"),&ins->std.ex7Macro,0,15,128,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("Release"),&ins->std.ex8Macro,0,15,128,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("Noise Mode"),&ins->std.fmsMacro,0,3,64,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Wave Mix"),&ins->std.amsMacro,0,3,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID2WaveMixMode)); break; case DIV_INS_UPD1771C: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,31,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,7,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Wave Pos"),&ins->std.ex1Macro,0,31,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Duty/Mode"),&ins->std.dutyMacro,0,1,160,uiColors[GUI_COLOR_MACRO_NOISE])); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); break; case DIV_INS_SID3: macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,255,160,uiColors[GUI_COLOR_MACRO_VOLUME])); macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); if (ins->sid3.doWavetable) { int waveCount=MAX(1,e->song.waveLen-1); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); } else { macroList.push_back(FurnaceGUIMacroDesc(_("Duty"),&ins->std.dutyMacro,ins->sid3.dutyIsAbs?0:-65535,65535,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,5,16 * 5,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,true,sid3ShapeBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Special Wave"),&ins->std.algMacro,0,SID3_NUM_SPECIAL_WAVES - 1,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,macroSID3SpecialWaves)); } if (ins->sid3.separateNoisePitch && !ins->sid3.doWavetable) { macroList.push_back(FurnaceGUIMacroDesc(_("Noise Arpeggio"),&ins->std.opMacros[3].amMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.opMacros[3].amMacro.val,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Noise Pitch"),&ins->std.opMacros[0].arMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode,NULL,false,NULL,false,NULL,false,true)); } macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Channel inversion"),&ins->std.opMacros[2].arMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,minModModeBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Key On/Off"),&ins->std.opMacros[0].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Special"),&ins->std.ex1Macro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,sid3ControlBits)); macroList.push_back(FurnaceGUIMacroDesc(_("Ring Mod Source"),&ins->std.fmsMacro,0,SID3_NUM_CHANNELS,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID3SourceChan)); macroList.push_back(FurnaceGUIMacroDesc(_("Hard Sync Source"),&ins->std.amsMacro,0,SID3_NUM_CHANNELS - 1,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID3SourceChan)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Mod Source"),&ins->std.fbMacro,0,SID3_NUM_CHANNELS - 1,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID3SourceChan)); if (!ins->sid3.doWavetable) { macroList.push_back(FurnaceGUIMacroDesc(_("Feedback"),&ins->std.opMacros[3].arMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); } macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); if (!ins->sid3.doWavetable) { macroList.push_back(FurnaceGUIMacroDesc(_("Noise Phase Reset"),&ins->std.opMacros[1].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } macroList.push_back(FurnaceGUIMacroDesc(_("Envelope Reset"),&ins->std.opMacros[2].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Attack"),&ins->std.ex2Macro,0,255,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("Decay"),&ins->std.ex3Macro,0,255,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("Sustain"),&ins->std.ex4Macro,0,255,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("Sustain Rate"),&ins->std.ex5Macro,0,255,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("Release"),&ins->std.ex6Macro,0,255,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); if (!ins->sid3.doWavetable) { macroList.push_back(FurnaceGUIMacroDesc(_("Noise LFSR bits"),&ins->std.ex7Macro,0,30,16 * 30,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,macroSID3NoiseLFSR,true)); macroList.push_back(FurnaceGUIMacroDesc(_("1-Bit Noise"),&ins->std.opMacros[1].arMacro,0,1,32,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Wave Mix"),&ins->std.ex8Macro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID3WaveMixMode)); } else { macroList.push_back(FurnaceGUIMacroDesc(_("Sample Mode"),&ins->std.opMacros[1].arMacro,0,1,32,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true)); } break; case DIV_INS_MAX: case DIV_INS_NULL: break; } drawMacros(macroList,macroEditStateMacros,ins); ImGui::EndTabItem(); } if (ins->type==DIV_INS_AY) { if (!ins->amiga.useSample) { if (ImGui::BeginTabItem(_("Timer Macros"))) { ImGui::Text(_("warning: timer effects are not supported by VGM export!")); macroList.push_back(FurnaceGUIMacroDesc(_("Timer FX"),&ins->std.ex6Macro,0,3,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("TFX Offset"),&ins->std.ex7Macro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true)); macroList.push_back(FurnaceGUIMacroDesc(_("Timer Num"),&ins->std.ex8Macro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Timer Den"),&ins->std.fmsMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("PWM Boundary"),&ins->std.amsMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); // workaround, because the gui will not set // zoom or scroll if we're not in macros tab ins->temp.vZoom[DIV_MACRO_EX7]=128; ins->temp.vScroll[DIV_MACRO_EX7]=2048-64; drawMacros(macroList,macroEditStateMacros,ins); ImGui::EndTabItem(); } } } if (ins->type==DIV_INS_POWERNOISE || ins->type==DIV_INS_POWERNOISE_SLOPE) { if (ImGui::BeginTabItem("PowerNoise")) { int pnOctave=ins->powernoise.octave; if (ImGui::InputInt(_("Octave offset"),&pnOctave,1,4)) { PARAMETER if (pnOctave<0) pnOctave=0; if (pnOctave>15) pnOctave=15; ins->powernoise.octave=pnOctave; } ImGui::Text(_("go to Macros for other parameters.")); ImGui::EndTabItem(); } } if (ins->type==DIV_INS_NES || ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_PCE || ins->type==DIV_INS_X1_010 || ins->type==DIV_INS_SWAN || ins->type==DIV_INS_VRC6) { insTabSample(ins); } if (ins->type>=DIV_INS_MAX) { if (ImGui::BeginTabItem(_("Error"))) { ImGui::Text(_("invalid instrument type! change it first.")); ImGui::EndTabItem(); } } ImGui::EndTabBar(); } if (settings.insEditColorize) { popAccentColors(); } } if (displayMacroMenu) { displayMacroMenu=false; if (lastMacroDesc.macro!=NULL) { ImGui::OpenPopup("macroMenu"); } } if (ImGui::BeginPopup("macroMenu",ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings)) { if (ImGui::MenuItem(_("copy"))) { String mmlStr; encodeMMLStr(mmlStr,lastMacroDesc.macro->val,lastMacroDesc.macro->len,lastMacroDesc.macro->loop,lastMacroDesc.macro->rel); SDL_SetClipboardText(mmlStr.c_str()); } if (ImGui::MenuItem(_("paste"))) { String mmlStr; char* clipText=SDL_GetClipboardText(); if (clipText!=NULL) { if (clipText[0]) { mmlStr=clipText; } SDL_free(clipText); } if (!mmlStr.empty()) { decodeMMLStr(mmlStr,lastMacroDesc.macro->val,lastMacroDesc.macro->len,lastMacroDesc.macro->loop,lastMacroDesc.min,(lastMacroDesc.isBitfield)?((1<<(lastMacroDesc.isBitfield?lastMacroDesc.max:0))-1):lastMacroDesc.max,lastMacroDesc.macro->rel); } } ImGui::Separator(); if (ImGui::MenuItem(_("clear"))) { lastMacroDesc.macro->len=0; lastMacroDesc.macro->loop=255; lastMacroDesc.macro->rel=255; for (int i=0; i<256; i++) { lastMacroDesc.macro->val[i]=0; } } if (ImGui::MenuItem(_("clear contents"))) { for (int i=0; i<256; i++) { lastMacroDesc.macro->val[i]=0; } } ImGui::Separator(); if (ImGui::BeginMenu(_("offset..."))) { ImGui::InputInt(_("X"),¯oOffX,1,10); ImGui::InputInt(_("Y"),¯oOffY,1,10); if (ImGui::Button(_("offset"))) { int oldData[256]; memset(oldData,0,256*sizeof(int)); memcpy(oldData,lastMacroDesc.macro->val,lastMacroDesc.macro->len*sizeof(int)); for (int i=0; ilen; i++) { int val=0; bool bit30=false; if ((i-macroOffX)>=0 && (i-macroOffX)len) { bit30=enBit30(oldData[i-macroOffX]); val=deBit30(oldData[i-macroOffX])+macroOffY; if (vallastMacroDesc.max) val=lastMacroDesc.max; } lastMacroDesc.macro->val[i]=val^(bit30?0x40000000:0); } if (lastMacroDesc.macro->looplen) { lastMacroDesc.macro->loop+=macroOffX; } else { lastMacroDesc.macro->loop=255; } if ((lastMacroDesc.macro->rel+macroOffX)>=0 && (lastMacroDesc.macro->rel+macroOffX)len) { lastMacroDesc.macro->rel+=macroOffX; } else { lastMacroDesc.macro->rel=255; } ImGui::CloseCurrentPopup(); } ImGui::EndMenu(); } if (ImGui::BeginMenu(_("scale..."))) { if (ImGui::InputFloat(_("X"),¯oScaleX,1.0f,10.0f,"%.2f%%")) { if (macroScaleX<0.1) macroScaleX=0.1; if (macroScaleX>12800.0) macroScaleX=12800.0; } ImGui::InputFloat(_("Y"),¯oScaleY,1.0f,10.0f,"%.2f%%"); if (ImGui::Button(_("scale"))) { int oldData[256]; memset(oldData,0,256*sizeof(int)); memcpy(oldData,lastMacroDesc.macro->val,lastMacroDesc.macro->len*sizeof(int)); lastMacroDesc.macro->len=MIN(255,((double)lastMacroDesc.macro->len*(macroScaleX/100.0))); for (int i=0; ilen; i++) { int val=0; bool bit30=false; double posX=round((double)i*(100.0/macroScaleX)-0.01); if (posX>=0 && posXlen) { val=round((double)deBit30(oldData[(int)posX])*(macroScaleY/100.0)); bit30=enBit30(oldData[(int)posX]); if (vallastMacroDesc.max) val=lastMacroDesc.max; } lastMacroDesc.macro->val[i]=val^(bit30?0x40000000:0); } ImGui::CloseCurrentPopup(); } ImGui::EndMenu(); } if (ImGui::BeginMenu(_("randomize..."))) { if (macroRandMinlastMacroDesc.max) macroRandMin=lastMacroDesc.max; if (macroRandMaxlastMacroDesc.max) macroRandMax=lastMacroDesc.max; ImGui::InputInt(_("Min"),¯oRandMin,1,10); ImGui::InputInt(_("Max"),¯oRandMax,1,10); if (ImGui::Button(_("randomize"))) { for (int i=0; ilen; i++) { int val=0; if (macroRandMax<=macroRandMin) { val=macroRandMin; } else { val=macroRandMin+(rand()%(macroRandMax-macroRandMin+1)); } lastMacroDesc.macro->val[i]=val; } ImGui::CloseCurrentPopup(); } ImGui::EndMenu(); } ImGui::EndPopup(); } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_INS_EDIT; ImGui::End(); } void FurnaceGUI::checkRecordInstrumentUndoStep() { if (insEditOpen && curIns>=0 && curIns<(int)e->song.ins.size()) { DivInstrument* ins=e->song.ins[curIns]; // invalidate cachedCurIns/any possible changes if the cachedCurIns was referencing a different // instrument altgoether bool insChanged=ins!=cachedCurInsPtr; if (insChanged) { insEditMayBeDirty=false; cachedCurInsPtr=ins; cachedCurIns=*ins; } cachedCurInsPtr=ins; // check against the last cached to see if diff -- note that modifications to instruments // happen outside drawInsEdit (e.g. cursor inputs are processed and can directly modify // macro data). but don't check until we think the user input is complete. bool delayDiff=ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsMouseDown(ImGuiMouseButton_Right) || ImGui::GetIO().WantCaptureKeyboard; if (!delayDiff && insEditMayBeDirty) { bool hasChange=ins->recordUndoStepIfChanged(e->processTime, &cachedCurIns); if (hasChange) { cachedCurIns=*ins; } insEditMayBeDirty=false; } } else { cachedCurInsPtr=NULL; insEditMayBeDirty=false; } } void FurnaceGUI::doUndoInstrument() { if (!insEditOpen) return; if (curIns<0 || curIns>=(int)e->song.ins.size()) return; DivInstrument* ins=e->song.ins[curIns]; // is locking the engine necessary? copied from doUndoSample e->lockEngine([this,ins]() { ins->undo(); cachedCurInsPtr=ins; cachedCurIns=*ins; }); } void FurnaceGUI::doRedoInstrument() { if (!insEditOpen) return; if (curIns<0 || curIns>=(int)e->song.ins.size()) return; DivInstrument* ins=e->song.ins[curIns]; // is locking the engine necessary? copied from doRedoSample e->lockEngine([this,ins]() { ins->redo(); cachedCurInsPtr=ins; cachedCurIns=*ins; }); }