diff --git a/CMakeLists.txt b/CMakeLists.txt index 86e491c7..c638befe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,6 +170,7 @@ src/gui/font_ptMono.cpp src/gui/font_unifont.cpp src/gui/font_icon.cpp src/gui/fonts.cpp +src/gui/debug.cpp src/gui/gui.cpp) if (NOT WIN32 AND NOT APPLE) diff --git a/demos/bruno_time.fur b/demos/bruno_time.fur new file mode 100644 index 00000000..7905bed6 Binary files /dev/null and b/demos/bruno_time.fur differ diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index bb5e596b..953f0fc7 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -171,6 +171,12 @@ class DivDispatch { */ virtual void tick(); + /** + * get the state of a channel. + * @return a pointer, or NULL. + */ + virtual void* getChanState(int chan); + /** * get this dispatch's state. * @return a pointer to the dispatch's state. must be deallocated manually! diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index d24f935a..a85a0f11 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -3716,6 +3716,16 @@ void DivEngine::setLoops(int loops) { remainingLoops=loops; } +DivChannelState* DivEngine::getChanState(int ch) { + if (ch<0 || ch>=chans) return NULL; + return &chan[ch]; +} + +void* DivEngine::getDispatchChanState(int ch) { + if (ch<0 || ch>=chans) return NULL; + return disCont[dispatchOfChan[ch]].dispatch->getChanState(dispatchChanOfChan[ch]); +} + void DivEngine::playSub(bool preserveDrift) { reset(); if (preserveDrift && curOrder==0) return; diff --git a/src/engine/engine.h b/src/engine/engine.h index 5bd36304..de643fbe 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -150,9 +150,6 @@ class DivEngine { std::map conf; std::queue pendingNotes; bool isMuted[DIV_MAX_CHANS]; - DivSystem sysOfChan[DIV_MAX_CHANS]; - int dispatchOfChan[DIV_MAX_CHANS]; - int dispatchChanOfChan[DIV_MAX_CHANS]; std::mutex isBusy; String configPath; String configFile; @@ -206,6 +203,10 @@ class DivEngine { public: DivSong song; + DivSystem sysOfChan[DIV_MAX_CHANS]; + int dispatchOfChan[DIV_MAX_CHANS]; + int dispatchChanOfChan[DIV_MAX_CHANS]; + void runExportThread(); void nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size); DivInstrument* getIns(int index); @@ -448,6 +449,12 @@ class DivEngine { // set remaining loops. -1 means loop forever. void setLoops(int loops); + // get channel state + DivChannelState* getChanState(int chan); + + // get dispatch channel state + void* getDispatchChanState(int chan); + // set the audio system. void setAudio(DivAudioEngines which); diff --git a/src/engine/orders.h b/src/engine/orders.h index eb8cc2e0..2f771799 100644 --- a/src/engine/orders.h +++ b/src/engine/orders.h @@ -1,3 +1,6 @@ +#ifndef _ORDERS_H +#define _ORDERS_H + struct DivOrders { unsigned char ord[DIV_MAX_CHANS][128]; @@ -5,3 +8,5 @@ struct DivOrders { memset(ord,0,DIV_MAX_CHANS*128); } }; + +#endif \ No newline at end of file diff --git a/src/engine/platform/abstract.cpp b/src/engine/platform/abstract.cpp index 60cf94b1..2577119e 100644 --- a/src/engine/platform/abstract.cpp +++ b/src/engine/platform/abstract.cpp @@ -6,6 +6,10 @@ void DivDispatch::acquire(short* bufL, short* bufR, size_t start, size_t len) { void DivDispatch::tick() { } +void* DivDispatch::getChanState(int chan) { + return NULL; +} + void* DivDispatch::getState() { return NULL; } diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 1c81e6b8..80a06483 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -205,6 +205,10 @@ void DivPlatformAmiga::forceIns() { } } +void* DivPlatformAmiga::getChanState(int ch) { + return &chan[ch]; +} + void DivPlatformAmiga::reset() { for (int i=0; i<4; i++) { chan[i]=DivPlatformAmiga::Channel(); diff --git a/src/engine/platform/amiga.h b/src/engine/platform/amiga.h index dd40738b..14e8a6e2 100644 --- a/src/engine/platform/amiga.h +++ b/src/engine/platform/amiga.h @@ -45,9 +45,12 @@ class DivPlatformAmiga: public DivDispatch { Channel chan[4]; bool isMuted[4]; + friend void putDispatchChan(void*,int,int); + public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index b3766fba..3764702e 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -548,6 +548,10 @@ void DivPlatformArcade::notifyInsChange(int ins) { } } +void* DivPlatformArcade::getChanState(int ch) { + return &chan[ch]; +} + void DivPlatformArcade::reset() { while (!writes.empty()) writes.pop(); if (useYMFM) { diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index 7b0ae818..1eba2a4a 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -63,9 +63,12 @@ class DivPlatformArcade: public DivDispatch { void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len); void acquire_ymfm(short* bufL, short* bufR, size_t start, size_t len); + friend void putDispatchChan(void*,int,int); + public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 511de815..b10ae364 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -290,6 +290,10 @@ void DivPlatformAY8910::forceIns() { immWrite(0x0d,ayEnvMode); } +void* DivPlatformAY8910::getChanState(int ch) { + return &chan[ch]; +} + void DivPlatformAY8910::reset() { while (!writes.empty()) writes.pop(); ay->device_reset(); diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index 401e03c8..4a74fd7f 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -49,10 +49,13 @@ class DivPlatformAY8910: public DivDispatch { short ayEnvSlide; short* ayBuf[3]; size_t ayBufLen; + + friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 9953d6c4..c0f1c65e 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -328,6 +328,10 @@ void DivPlatformAY8930::forceIns() { } } +void* DivPlatformAY8930::getChanState(int ch) { + return &chan[ch]; +} + void DivPlatformAY8930::reset() { while (!writes.empty()) writes.pop(); ay->device_reset(); diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index a79f67ae..71b838a6 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -43,10 +43,13 @@ class DivPlatformAY8930: public DivDispatch { short ayEnvSlide[3]; short* ayBuf[3]; size_t ayBufLen; + + friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index eb590b78..b5760a3a 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -327,6 +327,10 @@ void DivPlatformC64::notifyInsDeletion(void* ins) { } } +void* DivPlatformC64::getChanState(int ch) { + return &chan[ch]; +} + void DivPlatformC64::reset() { for (int i=0; i<3; i++) { chan[i]=DivPlatformC64::Channel(); diff --git a/src/engine/platform/c64.h b/src/engine/platform/c64.h index 1d44efd6..e1785fc5 100644 --- a/src/engine/platform/c64.h +++ b/src/engine/platform/c64.h @@ -52,10 +52,13 @@ class DivPlatformC64: public DivDispatch { SID sid; + friend void putDispatchChan(void*,int,int); + void updateFilter(); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/dummy.cpp b/src/engine/platform/dummy.cpp index 497e2a01..d8512d40 100644 --- a/src/engine/platform/dummy.cpp +++ b/src/engine/platform/dummy.cpp @@ -31,6 +31,10 @@ void DivPlatformDummy::tick() { } } +void* DivPlatformDummy::getChanState(int ch) { + return &chan[ch]; +} + int DivPlatformDummy::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: diff --git a/src/engine/platform/dummy.h b/src/engine/platform/dummy.h index 958e4a7c..2b33a92b 100644 --- a/src/engine/platform/dummy.h +++ b/src/engine/platform/dummy.h @@ -15,10 +15,12 @@ class DivPlatformDummy: public DivDispatch { Channel chan[128]; bool isMuted[128]; unsigned char chans; + friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); void muteChannel(int ch, bool mute); int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void tick(); int init(DivEngine* parent, int channels, int sugRate, bool pal); diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 802a118d..702139f3 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -301,6 +301,10 @@ void DivPlatformGB::forceIns() { updateWave(); } +void* DivPlatformGB::getChanState(int ch) { + return &chan[ch]; +} + void DivPlatformGB::reset() { for (int i=0; i<4; i++) { chan[i]=DivPlatformGB::Channel(); diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index 6da4376d..424f5bc6 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -38,9 +38,11 @@ class DivPlatformGB: public DivDispatch { GB_gameboy_t* gb; unsigned char procMute(); void updateWave(); + friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 53ab5ce7..0c358c51 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -567,6 +567,10 @@ void DivPlatformGenesis::toggleRegisterDump(bool enable) { psg.toggleRegisterDump(enable); } +void* DivPlatformGenesis::getChanState(int ch) { + return &chan[ch]; +} + void DivPlatformGenesis::reset() { while (!writes.empty()) writes.pop(); OPN2_Reset(&fm); diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 3e007a57..b9d9e4b0 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -67,10 +67,13 @@ class DivPlatformGenesis: public DivDispatch { int octave(int freq); int toFreq(int freq); + + friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 15c5e771..7f354d45 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -296,6 +296,12 @@ void DivPlatformGenesisExt::forceIns() { } } +void* DivPlatformGenesisExt::getChanState(int ch) { + if (ch>=6) return &chan[ch-3]; + if (ch>=2) return &opChan[ch-2]; + return &chan[ch]; +} + void DivPlatformGenesisExt::reset() { DivPlatformGenesis::reset(); diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index 80b497e0..de7ca9d2 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -16,8 +16,10 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { }; OpChannel opChan[4]; bool isOpMuted[4]; + friend void putDispatchChan(void*,int,int); public: int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 35014a2c..e5c8c867 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -344,6 +344,10 @@ void DivPlatformNES::forceIns() { } } +void* DivPlatformNES::getChanState(int ch) { + return &chan[ch]; +} + void DivPlatformNES::reset() { for (int i=0; i<5; i++) { chan[i]=DivPlatformNES::Channel(); diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index a511a7a1..3249da98 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -42,10 +42,12 @@ class DivPlatformNES: public DivDispatch { struct NESAPU* nes; float freqBase; + friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 9ed7254a..59ebc08f 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -340,6 +340,10 @@ void DivPlatformPCE::forceIns() { } } +void* DivPlatformPCE::getChanState(int ch) { + return &chan[ch]; +} + void DivPlatformPCE::reset() { while (!writes.empty()) writes.pop(); for (int i=0; i<6; i++) { diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index bdf0bf32..e0739c9e 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -56,9 +56,11 @@ class DivPlatformPCE: public DivDispatch { unsigned char sampleBank; PCE_PSG* pce; void updateWave(int ch); + friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index a264cf44..6cc341a1 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -255,6 +255,10 @@ void DivPlatformSAA1099::forceIns() { rWrite(0x16,saaNoise[0]|(saaNoise[1]<<4)); } +void* DivPlatformSAA1099::getChanState(int ch) { + return &chan[ch]; +} + void DivPlatformSAA1099::reset() { while (!writes.empty()) writes.pop(); saa=saa1099_device(); diff --git a/src/engine/platform/saa.h b/src/engine/platform/saa.h index 26f6d25c..4bda0100 100644 --- a/src/engine/platform/saa.h +++ b/src/engine/platform/saa.h @@ -47,10 +47,12 @@ class DivPlatformSAA1099: public DivDispatch { size_t saaBufLen; unsigned char saaEnv[2]; unsigned char saaNoise[2]; + friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 831aec87..70d3d4bf 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -187,6 +187,10 @@ void DivPlatformSMS::forceIns() { } } +void* DivPlatformSMS::getChanState(int ch) { + return &chan[ch]; +} + void DivPlatformSMS::reset() { for (int i=0; i<4; i++) { chan[i]=DivPlatformSMS::Channel(); diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index 5dc75411..798685cc 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -31,10 +31,12 @@ class DivPlatformSMS: public DivDispatch { unsigned char snNoiseMode; bool updateSNMode; sn76496_device* sn; + friend void putDispatchChan(void*,int,int); public: int acquireOne(); void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index e31c507d..ebd587cc 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -228,6 +228,10 @@ void DivPlatformTIA::forceIns() { } } +void* DivPlatformTIA::getChanState(int ch) { + return &chan[ch]; +} + void DivPlatformTIA::reset() { tia.reset(); for (int i=0; i<2; i++) { diff --git a/src/engine/platform/tia.h b/src/engine/platform/tia.h index 8843ef67..180e2035 100644 --- a/src/engine/platform/tia.h +++ b/src/engine/platform/tia.h @@ -19,10 +19,12 @@ class DivPlatformTIA: public DivDispatch { Channel chan[2]; bool isMuted[2]; TIASound tia; + friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 8087c98e..fd5e367a 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -570,6 +570,10 @@ void DivPlatformYM2610::forceIns() { immWrite(0x0d,ayEnvMode); } +void* DivPlatformYM2610::getChanState(int ch) { + return &chan[ch]; +} + void DivPlatformYM2610::reset() { while (!writes.empty()) writes.pop(); if (dumpWrites) { diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index 0269a5b0..93879e6b 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -63,10 +63,12 @@ class DivPlatformYM2610: public DivDispatch { int octave(int freq); int toFreq(int freq); + friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index d582199f..71072eda 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -268,6 +268,13 @@ void DivPlatformYM2610Ext::forceIns() { } } + +void* DivPlatformYM2610Ext::getChanState(int ch) { + if (ch>=5) return &chan[ch-3]; + if (ch>=1) return &opChan[ch-1]; + return &chan[ch]; +} + void DivPlatformYM2610Ext::reset() { DivPlatformYM2610::reset(); diff --git a/src/engine/platform/ym2610ext.h b/src/engine/platform/ym2610ext.h index f5064c7f..94219803 100644 --- a/src/engine/platform/ym2610ext.h +++ b/src/engine/platform/ym2610ext.h @@ -16,8 +16,10 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 { }; OpChannel opChan[4]; bool isOpMuted[4]; + friend void putDispatchChan(void*,int,int); public: int dispatch(DivCommand c); + void* getChanState(int chan); void reset(); void forceIns(); void tick(); diff --git a/src/engine/song.h b/src/engine/song.h index f663d6cc..d05975a8 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -1,3 +1,5 @@ +#ifndef _SONG_H +#define _SONG_H #include #include @@ -158,3 +160,5 @@ struct DivSong { system[0]=DIV_SYSTEM_GENESIS; } }; + +#endif \ No newline at end of file diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp new file mode 100644 index 00000000..01988959 --- /dev/null +++ b/src/gui/debug.cpp @@ -0,0 +1,202 @@ +#include "debug.h" +#include "imgui.h" +#include "../engine/platform/genesis.h" +#include "../engine/platform/genesisext.h" +#include "../engine/platform/sms.h" +#include "../engine/platform/gb.h" +#include "../engine/platform/pce.h" +#include "../engine/platform/nes.h" +#include "../engine/platform/c64.h" +#include "../engine/platform/arcade.h" +#include "../engine/platform/ym2610.h" +#include "../engine/platform/ym2610ext.h" +#include "../engine/platform/ay.h" +#include "../engine/platform/ay8930.h" +#include "../engine/platform/tia.h" +#include "../engine/platform/saa.h" +#include "../engine/platform/amiga.h" +#include "../engine/platform/dummy.h" + +void putDispatchChan(void* data, int chanNum, int type) { + ImVec4 colorOn=ImVec4(1.0f,1.0f,0.0f,1.0f); + ImVec4 colorOff=ImVec4(0.3f,0.3f,0.3f,1.0f); + switch (type) { + case DIV_SYSTEM_GENESIS: { + DivPlatformGenesis::Channel* ch=(DivPlatformGenesis::Channel*)data; + ImGui::Text("> Genesis"); + ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); + ImGui::Text("* freq: %d",ch->freq); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text("- note: %d",ch->note); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::Text("- pan: %x",ch->pan); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); + ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + break; + } + case DIV_SYSTEM_SMS: { + DivPlatformSMS::Channel* ch=(DivPlatformSMS::Channel*)data; + ImGui::Text("> SMS"); + ImGui::Text("* freq: %d",ch->freq); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text("- note: %d",ch->note); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + break; + } + case DIV_SYSTEM_GB: { + DivPlatformGB::Channel* ch=(DivPlatformGB::Channel*)data; + ImGui::Text("> GameBoy"); + ImGui::Text("* freq: %d",ch->freq); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text("- note: %d",ch->note); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("- duty: %d",ch->duty); + ImGui::Text("- sweep: %.2x",ch->sweep); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::Text("- wave: %d",ch->wave); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->sweepChanged?colorOn:colorOff,">> SweepChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + break; + } + case DIV_SYSTEM_PCE: { + DivPlatformPCE::Channel* ch=(DivPlatformPCE::Channel*)data; + ImGui::Text("> PCEngine"); + ImGui::Text("* freq: %d",ch->freq); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text("- note: %d",ch->note); + ImGui::Text("* DAC:"); + ImGui::Text(" - period: %d",ch->dacPeriod); + ImGui::Text(" - rate: %d",ch->dacRate); + ImGui::Text(" - pos: %d",ch->dacPos); + ImGui::Text(" - sample: %d",ch->dacSample); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("- pan: %.2x",ch->pan); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::Text("- wave: %d",ch->wave); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->noise?colorOn:colorOff,">> Noise"); + ImGui::TextColored(ch->pcm?colorOn:colorOff,">> DAC"); + ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC"); + break; + } + case DIV_SYSTEM_NES: { + DivPlatformNES::Channel* ch=(DivPlatformNES::Channel*)data; + ImGui::Text("> NES"); + ImGui::Text("* freq: %d",ch->freq); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - prev: %d",ch->prevFreq); + ImGui::Text("- note: %d",ch->note); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("- duty: %d",ch->duty); + ImGui::Text("- sweep: %.2x",ch->sweep); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::Text("- wave: %d",ch->wave); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->sweepChanged?colorOn:colorOff,">> SweepChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC"); + break; + } + case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580: { + DivPlatformC64::Channel* ch=(DivPlatformC64::Channel*)data; + ImGui::Text("> C64"); + ImGui::Text("* freq: %d",ch->freq); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - prev: %d",ch->prevFreq); + ImGui::Text("- testWhen: %d",ch->testWhen); + ImGui::Text("- note: %d",ch->note); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("- duty: %d",ch->duty); + ImGui::Text("- sweep: %.2x",ch->sweep); + ImGui::Text("- wave: %.1x",ch->wave); + ImGui::Text("- ADSR: %.1x %.1x %.1x %.1x",ch->attack,ch->decay,ch->sustain,ch->release); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->sweepChanged?colorOn:colorOff,">> SweepChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->filter?colorOn:colorOff,">> Filter"); + ImGui::TextColored(ch->resetMask?colorOn:colorOff,">> ResetMask"); + ImGui::TextColored(ch->resetFilter?colorOn:colorOff,">> ResetFilter"); + ImGui::TextColored(ch->resetDuty?colorOn:colorOff,">> ResetDuty"); + ImGui::TextColored(ch->ring?colorOn:colorOff,">> Ring"); + ImGui::TextColored(ch->sync?colorOn:colorOff,">> Sync"); + break; + } + case DIV_SYSTEM_ARCADE: { + DivPlatformArcade::Channel* ch=(DivPlatformArcade::Channel*)data; + ImGui::Text("> Arcade"); + ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); + ImGui::Text("* freq: %d",ch->freq); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + //ImGui::Text("- note: %d",ch->note); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("- KOnCycles: %d",ch->konCycles); + ImGui::Text("- vol: %.2x",ch->vol); + //ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::Text("- chVolL: %.2x",ch->chVolL); + ImGui::Text("- chVolR: %.2x",ch->chVolR); + ImGui::Text("* PCM:"); + ImGui::Text(" - sample: %d",ch->pcm.sample); + ImGui::Text(" - pos: %d",ch->pcm.pos>>8); + ImGui::Text(" - subPos: %d",ch->pcm.pos&0xff); + ImGui::Text(" - len: %d",ch->pcm.len); + ImGui::Text(" - freq: %.2x",ch->pcm.freq); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); + ImGui::TextColored(ch->furnacePCM?colorOn:colorOff,">> FurnacePCM"); + //ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + break; + } + default: + ImGui::Text("Unknown system! Help!"); + break; + } +} \ No newline at end of file diff --git a/src/gui/debug.h b/src/gui/debug.h new file mode 100644 index 00000000..49f01bdc --- /dev/null +++ b/src/gui/debug.h @@ -0,0 +1,6 @@ +#ifndef _GUI_DEBUG_H +#define _GUI_DEBUG_H +#include "../engine/song.h" + +void putDispatchChan(void* data, int chanNum, int type); +#endif \ No newline at end of file diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index d5face38..8d1771d7 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1,5 +1,6 @@ #define _USE_MATH_DEFINES #include "gui.h" +#include "debug.h" #include "SDL_clipboard.h" #include "SDL_events.h" #include "SDL_keycode.h" @@ -2780,6 +2781,131 @@ void FurnaceGUI::commitSettings() { ImGui::GetIO().Fonts->Build(); } +void FurnaceGUI::drawDebug() { + static int bpOrder; + static int bpRow; + static int bpTick; + static bool bpOn; + if (!debugOpen) return; + if (ImGui::Begin("Debug",&debugOpen,ImGuiWindowFlags_NoDocking)) { + ImGui::Text("NOTE: use with caution."); + if (ImGui::TreeNode("Debug Controls")) { + ImGui::Button("Pause"); + ImGui::SameLine(); + ImGui::Button("Frame Advance"); + ImGui::SameLine(); + ImGui::Button("Row Advance"); + ImGui::SameLine(); + ImGui::Button("Pattern Advance"); + + ImGui::Button("Panic"); + 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("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); + } + ImGui::End(); +} + void FurnaceGUI::startSelection(int xCoarse, int xFine, int y) { if (xCoarse!=selStart.xCoarse || xFine!=selStart.xFine || y!=selStart.y) { curNibble=false; @@ -4379,6 +4505,7 @@ bool FurnaceGUI::loop() { ImGui::EndMenu(); } if (ImGui::BeginMenu("help")) { + if (ImGui::MenuItem("debug menu")) debugOpen=!debugOpen; if (ImGui::MenuItem("about...")) { aboutOpen=true; aboutScroll=0; @@ -4413,6 +4540,7 @@ bool FurnaceGUI::loop() { drawMixer(); drawPattern(); drawSettings(); + drawDebug(); if (ImGuiFileDialog::Instance()->Display("FileDialog",ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove,ImVec2(600.0f*dpiScale,400.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale))) { if (ImGuiFileDialog::Instance()->IsOk()) { @@ -4994,6 +5122,9 @@ FurnaceGUI::FurnaceGUI(): soloTimeout(0), orderEditMode(0), orderCursor(-1), + loopOrder(-1), + loopRow(-1), + loopEnd(-1), editControlsOpen(true), ordersOpen(true), insListOpen(true), @@ -5007,6 +5138,7 @@ FurnaceGUI::FurnaceGUI(): aboutOpen(false), settingsOpen(false), mixerOpen(false), + debugOpen(false), selecting(false), curNibble(false), orderNibble(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index 62142ae3..4f6f67b5 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -230,9 +230,10 @@ class FurnaceGUI { char finalLayoutPath[4096]; int curIns, curWave, curSample, curOctave, oldRow, oldOrder, oldOrder1, editStep, exportLoops, soloChan, soloTimeout, orderEditMode, orderCursor; + int loopOrder, loopRow, loopEnd; bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen; bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen; - bool mixerOpen; + bool mixerOpen, debugOpen; SelectionPoint selStart, selEnd, cursor; bool selecting, curNibble, orderNibble, extraChannelButtons, followOrders, followPattern, changeAllOrders; FurnaceGUIWindows curWindow; @@ -313,6 +314,7 @@ class FurnaceGUI { void drawMixer(); void drawAbout(); void drawSettings(); + void drawDebug(); void syncSettings(); void commitSettings();