/** * Furnace Tracker - multi-system chiptune tracker * Copyright (C) 2021-2022 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. */ #include "gui.h" #include "debug.h" #include "IconsFontAwesome4.h" #include #include void FurnaceGUI::drawDebug() { static int bpOrder; static int bpRow; static int bpTick; static bool bpOn; if (nextWindow==GUI_WINDOW_DEBUG) { debugOpen=true; ImGui::SetNextWindowFocus(); nextWindow=GUI_WINDOW_NOTHING; } if (!debugOpen) return; ImGui::SetNextWindowSizeConstraints(ImVec2(400.0f*dpiScale,200.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); if (ImGui::Begin("Debug",&debugOpen,ImGuiWindowFlags_NoDocking)) { ImGui::Text("NOTE: use with caution."); if (ImGui::TreeNode("Debug Controls")) { if (e->isHalted()) { if (ImGui::Button("Resume")) e->resume(); } else { if (ImGui::Button("Pause")) e->halt(); } ImGui::SameLine(); if (ImGui::Button("Frame Advance")) e->haltWhen(DIV_HALT_TICK); ImGui::SameLine(); if (ImGui::Button("Row Advance")) e->haltWhen(DIV_HALT_ROW); ImGui::SameLine(); if (ImGui::Button("Pattern Advance")) e->haltWhen(DIV_HALT_PATTERN); if (ImGui::Button("Panic")) e->syncReset(); ImGui::SameLine(); if (ImGui::Button("Abort")) { abort(); } ImGui::TreePop(); } if (ImGui::TreeNode("Breakpoint")) { ImGui::InputInt("Order",&bpOrder); ImGui::InputInt("Row",&bpRow); ImGui::InputInt("Tick",&bpTick); ImGui::Checkbox("Enable",&bpOn); ImGui::TreePop(); } if (ImGui::TreeNode("Dispatch Status")) { ImGui::Text("for best results set latency to minimum or use the Frame Advance button."); ImGui::Columns(e->getTotalChannelCount()); for (int i=0; igetTotalChannelCount(); i++) { void* ch=e->getDispatchChanState(i); ImGui::TextColored(uiColors[GUI_COLOR_ACCENT_PRIMARY],"Ch. %d: %d, %d",i,e->dispatchOfChan[i],e->dispatchChanOfChan[i]); if (ch==NULL) { ImGui::Text("NULL"); } else { putDispatchChan(ch,e->dispatchChanOfChan[i],e->sysOfChan[i]); } ImGui::NextColumn(); } ImGui::Columns(); ImGui::TreePop(); } if (ImGui::TreeNode("Playback Status")) { ImGui::Text("for best results set latency to minimum or use the Frame Advance button."); ImGui::Columns(e->getTotalChannelCount()); for (int i=0; igetTotalChannelCount(); i++) { DivChannelState* ch=e->getChanState(i); ImGui::TextColored(uiColors[GUI_COLOR_ACCENT_PRIMARY],"Channel %d:",i); if (ch==NULL) { ImGui::Text("NULL"); } else { ImGui::Text("* General:"); ImGui::Text("- note = %d",ch->note); ImGui::Text("- oldNote = %d",ch->oldNote); ImGui::Text("- pitch = %d",ch->pitch); ImGui::Text("- portaSpeed = %d",ch->portaSpeed); ImGui::Text("- portaNote = %d",ch->portaNote); ImGui::Text("- volume = %.4x",ch->volume); ImGui::Text("- volSpeed = %d",ch->volSpeed); ImGui::Text("- cut = %d",ch->cut); ImGui::Text("- rowDelay = %d",ch->rowDelay); ImGui::Text("- volMax = %.4x",ch->volMax); ImGui::Text("- delayOrder = %d",ch->delayOrder); ImGui::Text("- delayRow = %d",ch->delayRow); ImGui::Text("- retrigSpeed = %d",ch->retrigSpeed); ImGui::Text("- retrigTick = %d",ch->retrigTick); ImGui::PushStyleColor(ImGuiCol_Text,(ch->vibratoDepth>0)?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_TEXT]); ImGui::Text("* Vibrato:"); ImGui::Text("- depth = %d",ch->vibratoDepth); ImGui::Text("- rate = %d",ch->vibratoRate); ImGui::Text("- pos = %d",ch->vibratoPos); ImGui::Text("- dir = %d",ch->vibratoDir); ImGui::Text("- fine = %d",ch->vibratoFine); ImGui::PopStyleColor(); ImGui::PushStyleColor(ImGuiCol_Text,(ch->tremoloDepth>0)?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_TEXT]); ImGui::Text("* Tremolo:"); ImGui::Text("- depth = %d",ch->tremoloDepth); ImGui::Text("- rate = %d",ch->tremoloRate); ImGui::Text("- pos = %d",ch->tremoloPos); ImGui::PopStyleColor(); ImGui::PushStyleColor(ImGuiCol_Text,(ch->arp>0)?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_TEXT]); ImGui::Text("* Arpeggio:"); ImGui::Text("- arp = %.2X",ch->arp); ImGui::Text("- stage = %d",ch->arpStage); ImGui::Text("- ticks = %d",ch->arpTicks); ImGui::PopStyleColor(); ImGui::Text("* Miscellaneous:"); ImGui::TextColored(ch->doNote?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Do Note"); ImGui::TextColored(ch->legato?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Legato"); ImGui::TextColored(ch->portaStop?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> PortaStop"); ImGui::TextColored(ch->keyOn?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Key On"); ImGui::TextColored(ch->keyOff?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Key Off"); ImGui::TextColored(ch->nowYouCanStop?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> NowYouCanStop"); ImGui::TextColored(ch->stopOnOff?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Stop on Off"); ImGui::TextColored(ch->arpYield?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Arp Yield"); ImGui::TextColored(ch->delayLocked?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> DelayLocked"); ImGui::TextColored(ch->inPorta?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> InPorta"); ImGui::TextColored(ch->scheduledSlideReset?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> SchedSlide"); } ImGui::NextColumn(); } ImGui::Columns(); ImGui::TreePop(); } if (ImGui::TreeNode("Sample Debug")) { for (int i=0; isong.sampleLen; i++) { DivSample* sample=e->getSample(i); if (sample==NULL) { ImGui::Text("%d: ",i); continue; } if (ImGui::TreeNode(fmt::sprintf("%d: %s",i,sample->name).c_str())) { ImGui::Text("rate: %d",sample->rate); ImGui::Text("centerRate: %d",sample->centerRate); ImGui::Text("loopStart: %d",sample->loopStart); ImGui::Text("loopOffP: %d",sample->loopOffP); ImGui::Text("depth: %d",sample->depth); ImGui::Text("length8: %d",sample->length8); ImGui::Text("length16: %d",sample->length16); ImGui::Text("length1: %d",sample->length1); ImGui::Text("lengthDPCM: %d",sample->lengthDPCM); ImGui::Text("lengthQSoundA: %d",sample->lengthQSoundA); ImGui::Text("lengthA: %d",sample->lengthA); ImGui::Text("lengthB: %d",sample->lengthB); ImGui::Text("lengthX68: %d",sample->lengthX68); ImGui::Text("lengthBRR: %d",sample->lengthBRR); ImGui::Text("lengthVOX: %d",sample->lengthVOX); ImGui::Text("off8: %x",sample->off8); ImGui::Text("off16: %x",sample->off16); ImGui::Text("off1: %x",sample->off1); ImGui::Text("offDPCM: %x",sample->offDPCM); ImGui::Text("offQSoundA: %x",sample->offQSoundA); ImGui::Text("offA: %x",sample->offA); ImGui::Text("offB: %x",sample->offB); ImGui::Text("offX68: %x",sample->offX68); ImGui::Text("offBRR: %x",sample->offBRR); ImGui::Text("offVOX: %x",sample->offVOX); ImGui::Text("offSegaPCM: %x",sample->offSegaPCM); ImGui::Text("offQSound: %x",sample->offQSound); ImGui::Text("offX1_010: %x",sample->offX1_010); ImGui::Text("offSU: %x",sample->offSU); ImGui::Text("samples: %d",sample->samples); ImGui::TreePop(); } } ImGui::TreePop(); } if (ImGui::TreeNode("Oscilloscope Debug")) { int c=0; for (int i=0; isong.systemLen; i++) { DivSystem system=e->song.system[i]; if (e->getChannelCount(system)>0) { if (ImGui::TreeNode(fmt::sprintf("%d: %s",i,e->getSystemName(system)).c_str())) { if (ImGui::BeginTable("OscilloscopeTable",4,ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("Channel"); ImGui::TableNextColumn(); ImGui::Text("Follow"); ImGui::TableNextColumn(); ImGui::Text("Address"); ImGui::TableNextColumn(); ImGui::Text("Data"); for (int j=0; jgetChannelCount(system); j++, c++) { ImGui::TableNextRow(); // channel ImGui::TableNextColumn(); ImGui::Text("%d",j); // follow ImGui::TableNextColumn(); ImGui::Checkbox(fmt::sprintf("##%d_OSCFollow_%d",i,c).c_str(),&e->getOscBuffer(c)->follow); // address ImGui::TableNextColumn(); int needle=e->getOscBuffer(c)->follow?e->getOscBuffer(c)->needle:e->getOscBuffer(c)->followNeedle; ImGui::BeginDisabled(e->getOscBuffer(c)->follow); if (ImGui::InputInt(fmt::sprintf("##%d_OSCFollowNeedle_%d",i,c).c_str(),&needle,1,100)) { e->getOscBuffer(c)->followNeedle=MIN(MAX(needle,0),65535); } ImGui::EndDisabled(); // data ImGui::TableNextColumn(); ImGui::Text("%d",e->getOscBuffer(c)->data[needle]); } ImGui::EndTable(); } ImGui::TreePop(); } } else { ImGui::Text("%d: ",i); continue; } } ImGui::TreePop(); } if (ImGui::TreeNode("Playground")) { if (pgSys<0 || pgSys>=e->song.systemLen) pgSys=0; if (ImGui::BeginCombo("System",fmt::sprintf("%d. %s",pgSys+1,e->getSystemName(e->song.system[pgSys])).c_str())) { for (int i=0; isong.systemLen; i++) { if (ImGui::Selectable(fmt::sprintf("%d. %s",i+1,e->getSystemName(e->song.system[i])).c_str())) { pgSys=i; break; } } ImGui::EndCombo(); } ImGui::Text("Program"); if (pgProgram.empty()) { ImGui::Text("-nothing here-"); } else { char id[32]; for (size_t index=0; indexpoke(pgSys,pgProgram); } ImGui::SameLine(); if (ImGui::Button("Clear")) { pgProgram.clear(); } ImGui::Text("Address"); ImGui::SameLine(); ImGui::SetNextItemWidth(100.0f*dpiScale); ImGui::InputInt("##PAddress",&pgAddr,0,0,ImGuiInputTextFlags_CharsHexadecimal); ImGui::SameLine(); ImGui::Text("Value"); ImGui::SameLine(); ImGui::SetNextItemWidth(100.0f*dpiScale); ImGui::InputInt("##PValue",&pgVal,0,0,ImGuiInputTextFlags_CharsHexadecimal); ImGui::SameLine(); if (ImGui::Button("Write")) { e->poke(pgSys,pgAddr,pgVal); } ImGui::SameLine(); if (ImGui::Button("Add")) { pgProgram.push_back(DivRegWrite(pgAddr,pgVal)); } if (ImGui::TreeNode("Register Cheatsheet")) { const char** sheet=e->getRegisterSheet(pgSys); if (sheet==NULL) { ImGui::Text("no cheatsheet available for this system."); } else { if (ImGui::BeginTable("RegisterSheet",2,ImGuiTableFlags_SizingFixedSame)) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("Name"); ImGui::TableNextColumn(); ImGui::Text("Address"); for (int i=0; sheet[i]!=NULL; i+=2) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%s",sheet[i]); ImGui::TableNextColumn(); ImGui::Text("$%s",sheet[i+1]); } ImGui::EndTable(); } } ImGui::TreePop(); } ImGui::TreePop(); } if (ImGui::TreeNode("ADSR Test Area")) { static int tl, ar, dr, d2r, sl, rr, sus, egt, algOrGlobalSus, instType; static float maxArDr, maxTl; ImGui::Text("This window was done out of frustration"); drawFMEnv(tl,ar,dr,d2r,rr,sl,sus,egt,algOrGlobalSus,maxTl,maxArDr,ImVec2(200.0f*dpiScale,100.0f*dpiScale),instType); ImGui::InputInt("tl",&tl); ImGui::InputInt("ar",&ar); ImGui::InputInt("dr",&dr); ImGui::InputInt("d2r",&d2r); ImGui::InputInt("sl",&sl); ImGui::InputInt("rr",&rr); ImGui::InputInt("sus",&sus); ImGui::InputInt("egt",&egt); ImGui::InputInt("algOrGlobalSus",&algOrGlobalSus); ImGui::InputInt("instType",&instType); ImGui::InputFloat("maxArDr",&maxArDr); ImGui::InputFloat("maxTl",&maxTl); ImGui::TreePop(); } if (ImGui::TreeNode("User Interface")) { if (ImGui::Button("Inspect")) { inspectorOpen=!inspectorOpen; } ImGui::TreePop(); } if (ImGui::TreeNode("Settings")) { if (ImGui::Button("Sync")) syncSettings(); ImGui::SameLine(); if (ImGui::Button("Commit")) commitSettings(); ImGui::SameLine(); if (ImGui::Button("Force Load")) e->loadConf(); ImGui::SameLine(); if (ImGui::Button("Force Save")) e->saveConf(); ImGui::TreePop(); } ImGui::Text("Song format version %d",e->song.version); ImGui::Text("Furnace version " DIV_VERSION " (%d)",DIV_ENGINE_VERSION); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_DEBUG; ImGui::End(); }