mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-15 01:05:06 +00:00
388 lines
16 KiB
C++
388 lines
16 KiB
C++
/**
|
|
* 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 <fmt/printf.h>
|
|
#include <imgui.h>
|
|
|
|
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,globalWinFlags|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; i<e->getTotalChannelCount(); 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; i<e->getTotalChannelCount(); 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; i<e->song.sampleLen; i++) {
|
|
DivSample* sample=e->getSample(i);
|
|
if (sample==NULL) {
|
|
ImGui::Text("%d: <NULL!>",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("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("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; i<e->song.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; j<e->getChannelCount(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: <NULL!>",i);
|
|
continue;
|
|
}
|
|
}
|
|
ImGui::TreePop();
|
|
}
|
|
if (ImGui::TreeNode("Touch Point Information")) {
|
|
ImGui::Text("active:");
|
|
ImGui::Indent();
|
|
for (TouchPoint& i: activePoints) {
|
|
ImGui::Text("- %d: %.1f, %.1f (%.2f)",i.id,i.x,i.y,i.x);
|
|
}
|
|
ImGui::Unindent();
|
|
ImGui::Text("pressed:");
|
|
ImGui::Indent();
|
|
for (TouchPoint& i: pressedPoints) {
|
|
ImGui::Text("- %d: %.1f, %.1f (%.2f)",i.id,i.x,i.y,i.x);
|
|
}
|
|
ImGui::Unindent();
|
|
ImGui::Text("released:");
|
|
ImGui::Indent();
|
|
for (TouchPoint& i: releasedPoints) {
|
|
ImGui::Text("- %d: %.1f, %.1f (%.2f)",i.id,i.x,i.y,i.x);
|
|
}
|
|
ImGui::Unindent();
|
|
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; i<e->song.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; index<pgProgram.size(); index++) {
|
|
DivRegWrite& i=pgProgram[index];
|
|
snprintf(id,31,"pgw%d",(int)index);
|
|
ImGui::PushID(id);
|
|
ImGui::SetNextItemWidth(100.0f*dpiScale);
|
|
ImGui::InputScalar("##PAddress",ImGuiDataType_U32,&i.addr,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
|
|
ImGui::SameLine();
|
|
ImGui::Text("=");
|
|
ImGui::SameLine();
|
|
ImGui::SetNextItemWidth(100.0f*dpiScale);
|
|
ImGui::InputScalar("##PValue",ImGuiDataType_U16,&i.val,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
|
|
ImGui::SameLine();
|
|
if (ImGui::Button(ICON_FA_TIMES "##PRemove")) {
|
|
pgProgram.erase(pgProgram.begin()+index);
|
|
index--;
|
|
}
|
|
ImGui::PopID();
|
|
}
|
|
}
|
|
if (ImGui::Button("Execute")) {
|
|
e->poke(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();
|
|
}
|