diff --git a/demos/Ice_Wind_OPMSPCM.fur b/demos/Ice_Wind_OPMSPCM.fur new file mode 100644 index 000000000..bf4612289 Binary files /dev/null and b/demos/Ice_Wind_OPMSPCM.fur differ diff --git a/demos/Jet_Pack_Adventure_GBAesque.fur b/demos/Jet_Pack_Adventure_GBAesque.fur new file mode 100644 index 000000000..928c4bd68 Binary files /dev/null and b/demos/Jet_Pack_Adventure_GBAesque.fur differ diff --git a/demos/Tubelectric_Fictional_Arcade.fur b/demos/Tubelectric_Fictional_Arcade.fur new file mode 100644 index 000000000..147c2ed31 Binary files /dev/null and b/demos/Tubelectric_Fictional_Arcade.fur differ diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index b90481589..2808e83d2 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -206,15 +206,27 @@ class DivDispatch { * @return a pointer, or NULL. */ virtual void* getChanState(int chan); + + /** + * get the register pool of this dispatch. + * @return a pointer, or NULL. + */ + virtual unsigned char* getRegisterPool(); /** - * get this dispatch's state. + * get the size of the register pool of this dispatch. + * @return the size. + */ + virtual int getRegisterPoolSize(); + + /** + * get this dispatch's state. DO NOT IMPLEMENT YET. * @return a pointer to the dispatch's state. must be deallocated manually! */ virtual void* getState(); /** - * set this dispatch's state. + * set this dispatch's state. DO NOT IMPLEMENT YET. * @param state a pointer to a state pertaining to this dispatch, * or NULL if this dispatch does not support state saves. */ diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 21d6789b9..06c57e914 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -400,6 +400,7 @@ bool DivEngine::saveAudio(const char* path, int loops, DivAudioExportModes mode) exportMode=mode; exporting=true; stop(); + repeatPattern=false; setOrder(0); remainingLoops=loops; exportThread=new std::thread(_runExportThread,this); @@ -548,9 +549,9 @@ void DivEngine::renderSamples() { if (diff>=tempstep) encoded|=1; acc+=jediTable[decstep+encoded]; - if (acc>0x7ff || acc<-0x800) { + /*if (acc>0x7ff || acc<-0x800) { logW("clipping! %d\n",acc); - } + }*/ acc&=0xfff; if (acc&0x800) acc|=~0xfff; decstep+=adStepSeek[encoded&7]*16; @@ -728,6 +729,13 @@ void* DivEngine::getDispatchChanState(int ch) { return disCont[dispatchOfChan[ch]].dispatch->getChanState(dispatchChanOfChan[ch]); } +unsigned char* DivEngine::getRegisterPool(int sys, int& size) { + if (sys<0 || sys>=song.systemLen) return NULL; + if (disCont[sys].dispatch==NULL) return NULL; + size=disCont[sys].dispatch->getRegisterPoolSize(); + return disCont[sys].dispatch->getRegisterPool(); +} + void DivEngine::enableCommandStream(bool enable) { cmdStreamEnabled=enable; } diff --git a/src/engine/engine.h b/src/engine/engine.h index d3be5ae94..71b0de303 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -37,8 +37,8 @@ warnings+=(String("\n")+x); \ } -#define DIV_VERSION "0.5.7pre4" -#define DIV_ENGINE_VERSION 52 +#define DIV_VERSION "0.5.7" +#define DIV_ENGINE_VERSION 53 enum DivStatusView { DIV_STATUS_NOTHING=0, @@ -529,6 +529,9 @@ class DivEngine { // get dispatch channel state void* getDispatchChanState(int chan); + + // get register pool + unsigned char* getRegisterPool(int sys, int& size); // enable command stream dumping void enableCommandStream(bool enable); diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 299e86076..ebb76ec76 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -135,6 +135,12 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.brokenShortcutSlides=false; ds.ignoreDuplicateSlides=true; + // 1.1 compat flags + if (ds.version>24) { + ds.waveDutyIsVol=true; + ds.legacyVolumeSlides=false; + } + // Neo Geo detune if (ds.system[0]==DIV_SYSTEM_YM2610 || ds.system[0]==DIV_SYSTEM_YM2610_EXT) { ds.tuning=443.23; diff --git a/src/engine/platform/abstract.cpp b/src/engine/platform/abstract.cpp index f9f8fc521..89e85a204 100644 --- a/src/engine/platform/abstract.cpp +++ b/src/engine/platform/abstract.cpp @@ -29,6 +29,14 @@ void* DivDispatch::getChanState(int chan) { return NULL; } +unsigned char* DivDispatch::getRegisterPool() { + return NULL; +} + +int DivDispatch::getRegisterPoolSize() { + return 0; +} + void* DivDispatch::getState() { return NULL; } diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 328a8401c..ed665e576 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -145,6 +145,7 @@ void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, si QueuedWrite& w=writes.front(); if (w.addrOrVal) { OPM_Write(&fm,1,w.val); + regPool[w.addr&0xff]=w.val; //printf("write: %x = %.2x\n",w.addr,w.val); writes.pop(); } else { @@ -216,6 +217,7 @@ void DivPlatformArcade::acquire_ymfm(short* bufL, short* bufR, size_t start, siz QueuedWrite& w=writes.front(); fm_ymfm->write(0x0+((w.addr>>8)<<1),w.addr); fm_ymfm->write(0x1+((w.addr>>8)<<1),w.val); + regPool[w.addr&0xff]=w.val; writes.pop(); delay=1; } @@ -877,6 +879,14 @@ void* DivPlatformArcade::getChanState(int ch) { return &chan[ch]; } +unsigned char* DivPlatformArcade::getRegisterPool() { + return regPool; +} + +int DivPlatformArcade::getRegisterPoolSize() { + return 256; +} + void DivPlatformArcade::poke(unsigned int addr, unsigned short val) { immWrite(addr,val); } @@ -887,6 +897,7 @@ void DivPlatformArcade::poke(std::vector& wlist) { void DivPlatformArcade::reset() { while (!writes.empty()) writes.pop(); + memset(regPool,0,256); if (useYMFM) { fm_ymfm->reset(); } else { diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index 19832b9f4..f43b54cce 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -71,6 +71,8 @@ class DivPlatformArcade: public DivDispatch { ymfm::ym2151::output_data out_ymfm; DivArcadeInterface iface; + unsigned char regPool[256]; + bool extMode, useYMFM; bool isMuted[13]; @@ -90,6 +92,8 @@ class DivPlatformArcade: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + unsigned char* getRegisterPool(); + int getRegisterPoolSize(); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index b1fc04719..2bcada1e8 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -94,6 +94,7 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l QueuedWrite w=writes.front(); ay->address_w(w.addr); ay->data_w(w.val); + regPool[w.addr&0x0f]=w.val; writes.pop(); } ay->sound_stream_update(ayBuf,len); @@ -400,9 +401,18 @@ void* DivPlatformAY8910::getChanState(int ch) { return &chan[ch]; } +unsigned char* DivPlatformAY8910::getRegisterPool() { + return regPool; +} + +int DivPlatformAY8910::getRegisterPoolSize() { + return 16; +} + void DivPlatformAY8910::reset() { while (!writes.empty()) writes.pop(); ay->device_reset(); + memset(regPool,0,16); for (int i=0; i<3; i++) { chan[i]=DivPlatformAY8910::Channel(); chan[i].vol=0x0f; diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index ba654e011..c22929900 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -47,6 +47,7 @@ class DivPlatformAY8910: public DivDispatch { }; std::queue writes; ay8910_device* ay; + unsigned char regPool[16]; unsigned char lastBusy; bool dacMode; @@ -76,6 +77,8 @@ class DivPlatformAY8910: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + unsigned char* getRegisterPool(); + int getRegisterPoolSize(); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 33347097e..3c56461bb 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -124,6 +124,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l } else { ay->data_w(w.val); } + regPool[w.addr&0x1f]=w.val; writes.pop(); } ay->sound_stream_update(ayBuf,len); @@ -462,9 +463,18 @@ void* DivPlatformAY8930::getChanState(int ch) { return &chan[ch]; } +unsigned char* DivPlatformAY8930::getRegisterPool() { + return regPool; +} + +int DivPlatformAY8930::getRegisterPoolSize() { + return 32; +} + void DivPlatformAY8930::reset() { while (!writes.empty()) writes.pop(); ay->device_reset(); + memset(regPool,0,32); for (int i=0; i<3; i++) { chan[i]=DivPlatformAY8930::Channel(); chan[i].vol=31; diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index 25e850117..2568fd7a9 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -47,6 +47,7 @@ class DivPlatformAY8930: public DivDispatch { }; std::queue writes; ay8930_device* ay; + unsigned char regPool[32]; unsigned char ayNoiseAnd, ayNoiseOr; bool bank; @@ -69,6 +70,8 @@ class DivPlatformAY8930: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + unsigned char* getRegisterPool(); + int getRegisterPoolSize(); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 0214d5f2b..6257daead 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -21,7 +21,7 @@ #include "../engine.h" #include -#define rWrite(a,v) if (!skipRegisterWrites) {sid.write(a,v); if (dumpWrites) {addWrite(a,v);} } +#define rWrite(a,v) if (!skipRegisterWrites) {sid.write(a,v); regPool[(a)&0x1f]=v; if (dumpWrites) {addWrite(a,v);} } #define CHIP_FREQBASE 524288 @@ -467,12 +467,21 @@ void* DivPlatformC64::getChanState(int ch) { return &chan[ch]; } +unsigned char* DivPlatformC64::getRegisterPool() { + return regPool; +} + +int DivPlatformC64::getRegisterPoolSize() { + return 32; +} + void DivPlatformC64::reset() { for (int i=0; i<3; i++) { chan[i]=DivPlatformC64::Channel(); } sid.reset(); + memset(regPool,0,32); rWrite(0x18,0x0f); diff --git a/src/engine/platform/c64.h b/src/engine/platform/c64.h index d1e8fa67f..9045e3332 100644 --- a/src/engine/platform/c64.h +++ b/src/engine/platform/c64.h @@ -70,6 +70,7 @@ class DivPlatformC64: public DivDispatch { int filtCut, resetTime; SID sid; + unsigned char regPool[32]; friend void putDispatchChan(void*,int,int); @@ -78,6 +79,8 @@ class DivPlatformC64: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + unsigned char* getRegisterPool(); + int getRegisterPoolSize(); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 3139da0bd..3944f67a4 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -21,8 +21,8 @@ #include "../engine.h" #include -#define rWrite(a,v) if (!skipRegisterWrites) {GB_apu_write(gb,a,v); if (dumpWrites) {addWrite(a,v);} } -#define immWrite(a,v) {GB_apu_write(gb,a,v); if (dumpWrites) {addWrite(a,v);} } +#define rWrite(a,v) if (!skipRegisterWrites) {GB_apu_write(gb,a,v); regPool[(a)&0x7f]=v; if (dumpWrites) {addWrite(a,v);} } +#define immWrite(a,v) {GB_apu_write(gb,a,v); regPool[(a)&0x7f]=v; if (dumpWrites) {addWrite(a,v);} } #define CHIP_DIVIDER 16 @@ -395,6 +395,14 @@ void* DivPlatformGB::getChanState(int ch) { return &chan[ch]; } +unsigned char* DivPlatformGB::getRegisterPool() { + return regPool; +} + +int DivPlatformGB::getRegisterPoolSize() { + return 64; +} + void DivPlatformGB::reset() { for (int i=0; i<4; i++) { chan[i]=DivPlatformGB::Channel(); @@ -403,6 +411,7 @@ void DivPlatformGB::reset() { addWrite(0xffffffff,0); } memset(gb,0,sizeof(GB_gameboy_t)); + memset(regPool,0,128); gb->model=GB_MODEL_DMG_B; GB_apu_init(gb); GB_set_sample_rate(gb,rate); diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index c7538d36f..04e36ad3c 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -55,6 +55,8 @@ class DivPlatformGB: public DivDispatch { unsigned char lastPan; GB_gameboy_t* gb; + unsigned char regPool[128]; + unsigned char procMute(); void updateWave(); friend void putDispatchChan(void*,int,int); @@ -62,6 +64,8 @@ class DivPlatformGB: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + unsigned char* getRegisterPool(); + int getRegisterPoolSize(); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 27b3df450..811726625 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -121,6 +121,7 @@ void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, s OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val); //printf("write: %x = %.2x\n",w.addr,w.val); lastBusy=0; + regPool[w.addr&0x1ff]=w.val; writes.pop(); } else { lastBusy++; @@ -190,6 +191,7 @@ void DivPlatformGenesis::acquire_ymfm(short* bufL, short* bufR, size_t start, si QueuedWrite& w=writes.front(); fm_ymfm->write(0x0+((w.addr>>8)<<1),w.addr); fm_ymfm->write(0x1+((w.addr>>8)<<1),w.val); + regPool[w.addr&0x1ff]=w.val; writes.pop(); lastBusy=1; } @@ -805,8 +807,17 @@ void* DivPlatformGenesis::getChanState(int ch) { return &chan[ch]; } +unsigned char* DivPlatformGenesis::getRegisterPool() { + return regPool; +} + +int DivPlatformGenesis::getRegisterPoolSize() { + return 512; +} + void DivPlatformGenesis::reset() { while (!writes.empty()) writes.pop(); + memset(regPool,0,512); if (useYMFM) { fm_ymfm->reset(); } diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 4ea6c41e5..717c6c3dc 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -79,6 +79,7 @@ class DivPlatformGenesis: public DivDispatch { ymfm::ym2612* fm_ymfm; ymfm::ym2612::output_data out_ymfm; DivYM2612Interface iface; + unsigned char regPool[512]; bool dacMode; int dacPeriod; @@ -106,6 +107,8 @@ class DivPlatformGenesis: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + unsigned char* getRegisterPool(); + int getRegisterPoolSize(); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 3266b2936..773a58f25 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -25,7 +25,7 @@ #define CHIP_DIVIDER 16 -#define rWrite(a,v) if (!skipRegisterWrites) {apu_wr_reg(nes,a,v); if (dumpWrites) {addWrite(a,v);} } +#define rWrite(a,v) if (!skipRegisterWrites) {apu_wr_reg(nes,a,v); regPool[(a)&0x7f]=v; if (dumpWrites) {addWrite(a,v);} } const char* regCheatSheetNES[]={ "S0Volume", "4000", @@ -444,6 +444,14 @@ void* DivPlatformNES::getChanState(int ch) { return &chan[ch]; } +unsigned char* DivPlatformNES::getRegisterPool() { + return regPool; +} + +int DivPlatformNES::getRegisterPoolSize() { + return 32; +} + void DivPlatformNES::reset() { for (int i=0; i<5; i++) { chan[i]=DivPlatformNES::Channel(); @@ -459,6 +467,7 @@ void DivPlatformNES::reset() { sampleBank=0; apu_turn_on(nes,apuType); + memset(regPool,0,128); nes->apu.cpu_cycles=0; nes->apu.cpu_opcode_cycle=0; diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index 63271c399..c1b699bcf 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -59,6 +59,7 @@ class DivPlatformNES: public DivDispatch { unsigned char sampleBank; unsigned char apuType; struct NESAPU* nes; + unsigned char regPool[128]; friend void putDispatchChan(void*,int,int); @@ -66,6 +67,8 @@ class DivPlatformNES: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + unsigned char* getRegisterPool(); + int getRegisterPoolSize(); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 01efd7131..ede1bd667 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -29,6 +29,7 @@ curChan=c; \ rWrite(0,curChan); \ } \ + regPool[16+((c)<<4)+((a)&0x0f)]=v; \ rWrite(a,v); \ } @@ -88,11 +89,12 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) chWrite(i,0x07,0); if (s->depth==8) { chWrite(i,0x04,0xdf); - chWrite(i,0x06,(((unsigned char)s->rendData[chan[i].dacPos++]+0x80)>>3)); + chWrite(i,0x06,(((unsigned char)s->rendData[chan[i].dacPos]+0x80)>>3)); } else { chWrite(i,0x04,0xdf); - chWrite(i,0x06,(((unsigned short)s->rendData[chan[i].dacPos++]+0x8000)>>11)); + chWrite(i,0x06,(((unsigned short)s->rendData[chan[i].dacPos]+0x8000)>>11)); } + chan[i].dacPos++; if (chan[i].dacPos>=s->rendLength) { if (s->loopStart>=0 && s->loopStart<=(int)s->rendLength) { chan[i].dacPos=s->loopStart; @@ -110,6 +112,7 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) while (!writes.empty() && cycles<24) { QueuedWrite w=writes.front(); pce->Write(cycles,w.addr,w.val); + regPool[w.addr&0x0f]=w.val; //cycles+=2; writes.pop(); } @@ -442,8 +445,17 @@ void* DivPlatformPCE::getChanState(int ch) { return &chan[ch]; } +unsigned char* DivPlatformPCE::getRegisterPool() { + return regPool; +} + +int DivPlatformPCE::getRegisterPoolSize() { + return 112; +} + void DivPlatformPCE::reset() { while (!writes.empty()) writes.pop(); + memset(regPool,0,128); for (int i=0; i<6; i++) { chan[i]=DivPlatformPCE::Channel(); } diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index e854426ea..2a5bd4fba 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -74,12 +74,15 @@ class DivPlatformPCE: public DivDispatch { int tempR[32]; unsigned char sampleBank, lfoMode, lfoSpeed; PCE_PSG* pce; + unsigned char regPool[128]; 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); + unsigned char* getRegisterPool(); + int getRegisterPoolSize(); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index f5d640b71..0bafaf157 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -83,6 +83,7 @@ void DivPlatformSAA1099::acquire_mame(short* bufL, short* bufR, size_t start, si QueuedWrite w=writes.front(); saa.control_w(w.addr); saa.data_w(w.val); + regPool[w.addr&0x1f]=w.val; writes.pop(); } saa.sound_stream_update(saaBuf,len); @@ -103,6 +104,7 @@ void DivPlatformSAA1099::acquire_saaSound(short* bufL, short* bufR, size_t start while (!writes.empty()) { QueuedWrite w=writes.front(); saa_saaSound->WriteAddressData(w.addr,w.val); + regPool[w.addr&0x1f]=w.val; writes.pop(); } saa_saaSound->GenerateMany((unsigned char*)saaBuf[0],len); @@ -367,8 +369,17 @@ void* DivPlatformSAA1099::getChanState(int ch) { return &chan[ch]; } +unsigned char* DivPlatformSAA1099::getRegisterPool() { + return regPool; +} + +int DivPlatformSAA1099::getRegisterPoolSize() { + return 32; +} + void DivPlatformSAA1099::reset() { while (!writes.empty()) writes.pop(); + memset(regPool,0,32); switch (core) { case DIV_SAA_CORE_MAME: saa=saa1099_device(); diff --git a/src/engine/platform/saa.h b/src/engine/platform/saa.h index 4f1135739..8df44f616 100644 --- a/src/engine/platform/saa.h +++ b/src/engine/platform/saa.h @@ -56,6 +56,7 @@ class DivPlatformSAA1099: public DivDispatch { DivSAACores core; saa1099_device saa; CSAASound* saa_saaSound; + unsigned char regPool[32]; unsigned char lastBusy; bool dacMode; @@ -85,6 +86,8 @@ class DivPlatformSAA1099: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + unsigned char* getRegisterPool(); + int getRegisterPoolSize(); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index f2c233103..2b99731fe 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -22,7 +22,7 @@ #include #include -#define rWrite(a,v) if (!skipRegisterWrites) {tia.set(a,v); if (dumpWrites) {addWrite(a,v);} } +#define rWrite(a,v) if (!skipRegisterWrites) {tia.set(a,v); regPool[((a)-0x15)&0x0f]=v; if (dumpWrites) {addWrite(a,v);} } const char* regCheatSheetTIA[]={ "AUDC0", "15", @@ -281,8 +281,17 @@ void* DivPlatformTIA::getChanState(int ch) { return &chan[ch]; } +unsigned char* DivPlatformTIA::getRegisterPool() { + return regPool; +} + +int DivPlatformTIA::getRegisterPoolSize() { + return 6; +} + void DivPlatformTIA::reset() { tia.reset(); + memset(regPool,0,16); for (int i=0; i<2; i++) { chan[i]=DivPlatformTIA::Channel(); chan[i].vol=0x0f; diff --git a/src/engine/platform/tia.h b/src/engine/platform/tia.h index 91d5ab452..ea149ec34 100644 --- a/src/engine/platform/tia.h +++ b/src/engine/platform/tia.h @@ -38,6 +38,7 @@ class DivPlatformTIA: public DivDispatch { Channel chan[2]; bool isMuted[2]; TIASound tia; + unsigned char regPool[16]; friend void putDispatchChan(void*,int,int); unsigned char dealWithFreq(unsigned char shape, int base, int pitch); @@ -46,6 +47,8 @@ class DivPlatformTIA: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + unsigned char* getRegisterPool(); + int getRegisterPoolSize(); void reset(); void forceIns(); void tick(); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index c51ad1f26..378a7b9c4 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -111,6 +111,7 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l QueuedWrite& w=writes.front(); fm->write(0x0+((w.addr>>8)<<1),w.addr); fm->write(0x1+((w.addr>>8)<<1),w.val); + regPool[w.addr&0x1ff]=w.val; writes.pop(); delay=4; } @@ -848,6 +849,14 @@ void* DivPlatformYM2610::getChanState(int ch) { return &chan[ch]; } +unsigned char* DivPlatformYM2610::getRegisterPool() { + return regPool; +} + +int DivPlatformYM2610::getRegisterPoolSize() { + return 512; +} + void DivPlatformYM2610::poke(unsigned int addr, unsigned short val) { immWrite(addr,val); } @@ -858,6 +867,7 @@ void DivPlatformYM2610::poke(std::vector& wlist) { void DivPlatformYM2610::reset() { while (!writes.empty()) writes.pop(); + memset(regPool,0,512); if (dumpWrites) { addWrite(0xffffffff,0); } diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index 0dea2ccf8..593e56686 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -59,6 +59,7 @@ class DivPlatformYM2610: public DivDispatch { ymfm::ym2610* fm; ymfm::ym2610::output_data fmout; DivYM2610Interface iface; + unsigned char regPool[512]; unsigned char lastBusy; bool dacMode; @@ -88,6 +89,8 @@ class DivPlatformYM2610: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + unsigned char* getRegisterPool(); + int getRegisterPoolSize(); void reset(); void forceIns(); void tick(); diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index e8c01c974..b2e8538f5 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -403,6 +403,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) { stop(); + repeatPattern=false; setOrder(0); isBusy.lock(); double origRate=got.rate; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index a61a0bc7c..7b019c6c0 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -154,7 +154,7 @@ bool FurnaceGUI::decodeNote(const char* what, short& note, short& octave) { String FurnaceGUI::encodeKeyMap(std::map& map) { String ret; for (std::map::value_type& i: map) { - ret+=fmt::printf("%d:%d;",i.first,i.second); + ret+=fmt::sprintf("%d:%d;",i.first,i.second); } return ret; } @@ -1383,7 +1383,6 @@ void FurnaceGUI::drawOsc() { if (!oscOpen) return; ImGui::SetNextWindowSizeConstraints(ImVec2(64.0f*dpiScale,32.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0,0)); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0,0)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0,0)); ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,ImVec2(0,0)); if (ImGui::Begin("Oscilloscope",&oscOpen)) { @@ -1397,7 +1396,7 @@ void FurnaceGUI::drawOsc() { ImGui::PlotLines("##SingleOsc",values,512,0,NULL,-1.0f,1.0f,ImGui::GetContentRegionAvail()); ImGui::EndDisabled(); } - ImGui::PopStyleVar(4); + ImGui::PopStyleVar(3); if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_OSCILLOSCOPE; ImGui::End(); } @@ -1491,7 +1490,7 @@ void FurnaceGUI::drawVolMeter() { ImGui::End(); } -const char* aboutLine[57]={ +const char* aboutLine[93]={ "tildearrow", "is proud to present", "", @@ -1501,8 +1500,39 @@ const char* aboutLine[57]={ "compatible with DefleMask modules.", "", "zero disassembly.", - "zero reverse-engineering.", - "only time and dedication.", + "just clean-room design,", + "time and dedication.", + "", + "> CREDITS <", + "", + "-- program --", + "tildearrow", + "", + "-- graphics --", + "tildearrow", + "", + "-- documentation --", + "tildearrow", + "freq-mod", + "nicco1690", + "DeMOSic", + "cam900", + "", + "-- demo songs --", + "0x5066", + "breakthetargets", + "kleeder", + "NikonTeen", + "SuperJet Spade", + "TheDuccinator", + "tildearrow", + "Ultraprogramer", + "", + "-- additional feedback/fixes --", + "fd", + "OPNA2608", + "plane", + "TheEssem", "", "powered by:", "Dear ImGui by Omar Cornut", @@ -1529,7 +1559,8 @@ const char* aboutLine[57]={ "ILLUMIDARO", "all members of Deflers of Noice!", "", - "copyright © 2021-2022 tildearrow.", + "copyright © 2021-2022 tildearrow", + "(and contributors).", "licensed under GPLv2+! see", "LICENSE for more information.", "", @@ -1548,7 +1579,11 @@ const char* aboutLine[57]={ "", "it also comes with ABSOLUTELY NO WARRANTY.", "", - "thanks to all contributors!" + "look out for Furnace 0.6 coming somewhere", + "before the equinox with more systems", + "and plenty of other things...", + "", + "thanks to all contributors/bug reporters!" }; void FurnaceGUI::drawAbout() { @@ -1590,7 +1625,7 @@ void FurnaceGUI::drawAbout() { skip=false; skip2=false; - for (int i=(-fmod(160-(aboutSin*2),160))*2; iscrH*dpiScale) continue; @@ -1630,7 +1665,7 @@ void FurnaceGUI::drawAbout() { while (aboutHue>1) aboutHue--; while (aboutSin>=2400) aboutSin-=2400; - if (aboutScroll>(42*57+scrH)) aboutScroll=-20; + if (aboutScroll>(42*93+scrH)) aboutScroll=-20; } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_ABOUT; ImGui::End(); @@ -2043,6 +2078,49 @@ void FurnaceGUI::drawChannels() { ImGui::End(); } +void FurnaceGUI::drawRegView() { + if (nextWindow==GUI_WINDOW_REGISTER_VIEW) { + channelsOpen=true; + ImGui::SetNextWindowFocus(); + nextWindow=GUI_WINDOW_NOTHING; + } + if (!regViewOpen) return; + if (ImGui::Begin("Register View",®ViewOpen)) { + for (int i=0; isong.systemLen; i++) { + ImGui::Text("%d. %s",i+1,getSystemName(e->song.system[i])); + int size=0; + unsigned char* regPool=e->getRegisterPool(i,size); + if (regPool==NULL) { + ImGui::Text("- no register pool available"); + } else { + ImGui::PushFont(patFont); + if (ImGui::BeginTable("Memory",17)) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + for (int i=0; i<16; i++) { + ImGui::TableNextColumn(); + ImGui::TextColored(uiColors[GUI_COLOR_PATTERN_ROW_INDEX]," %X",i); + } + for (int i=0; i<=((size-1)>>4); i++) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextColored(uiColors[GUI_COLOR_PATTERN_ROW_INDEX],"%.2X",i*16); + for (int j=0; j<16; j++) { + ImGui::TableNextColumn(); + if (i*16+j>=size) continue; + ImGui::Text("%.2x",regPool[i*16+j]); + } + } + ImGui::EndTable(); + } + ImGui::PopFont(); + } + } + } + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_REGISTER_VIEW; + ImGui::End(); +} + void FurnaceGUI::startSelection(int xCoarse, int xFine, int y) { if (xCoarse!=selStart.xCoarse || xFine!=selStart.xFine || y!=selStart.y) { curNibble=false; @@ -2826,6 +2904,7 @@ void FurnaceGUI::doRedo() { void FurnaceGUI::play(int row) { e->walkSong(loopOrder,loopRow,loopEnd); + memset(lastIns,-1,sizeof(int)*DIV_MAX_CHANS); if (row>0) { e->playToRow(row); } else { @@ -3056,6 +3135,9 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_WINDOW_CHANNELS: nextWindow=GUI_WINDOW_CHANNELS; break; + case GUI_ACTION_WINDOW_REGISTER_VIEW: + nextWindow=GUI_WINDOW_REGISTER_VIEW; + break; case GUI_ACTION_COLLAPSE_WINDOW: collapseWindow=true; @@ -3125,6 +3207,9 @@ void FurnaceGUI::doAction(int what) { case GUI_WINDOW_CHANNELS: channelsOpen=false; break; + case GUI_WINDOW_REGISTER_VIEW: + regViewOpen=false; + break; default: break; } @@ -4647,6 +4732,10 @@ bool FurnaceGUI::loop() { ImGui::EndMenu(); } if (ImGui::BeginMenu("settings")) { + if (ImGui::MenuItem("reset layout")) { + ImGui::LoadIniSettingsFromMemory(defaultLayout); + ImGui::SaveIniSettingsToDisk(finalLayoutPath); + } if (ImGui::MenuItem("settings...",BIND_FOR(GUI_ACTION_WINDOW_SETTINGS))) { syncSettings(); settingsOpen=true; @@ -4673,6 +4762,7 @@ bool FurnaceGUI::loop() { if (ImGui::MenuItem("piano/input pad",BIND_FOR(GUI_ACTION_WINDOW_PIANO),pianoOpen)) pianoOpen=!pianoOpen; if (ImGui::MenuItem("oscilloscope",BIND_FOR(GUI_ACTION_WINDOW_OSCILLOSCOPE),oscOpen)) oscOpen=!oscOpen; if (ImGui::MenuItem("volume meter",BIND_FOR(GUI_ACTION_WINDOW_VOL_METER),volMeterOpen)) volMeterOpen=!volMeterOpen; + if (ImGui::MenuItem("register view",BIND_FOR(GUI_ACTION_WINDOW_REGISTER_VIEW),regViewOpen)) regViewOpen=!regViewOpen; if (ImGui::MenuItem("statistics",BIND_FOR(GUI_ACTION_WINDOW_STATS),statsOpen)) statsOpen=!statsOpen; ImGui::EndMenu(); @@ -4776,6 +4866,7 @@ bool FurnaceGUI::loop() { drawPiano(); drawNotes(); drawChannels(); + drawRegView(); if (ImGuiFileDialog::Instance()->Display("FileDialog",ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove,ImVec2(600.0f*dpiScale,400.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale))) { //ImGui::GetIO().ConfigFlags&=~ImGuiConfigFlags_NavEnableKeyboard; @@ -5387,6 +5478,7 @@ bool FurnaceGUI::init() { pianoOpen=e->getConfBool("pianoOpen",false); notesOpen=e->getConfBool("notesOpen",false); channelsOpen=e->getConfBool("channelsOpen",false); + regViewOpen=e->getConfBool("regViewOpen",false); syncSettings(); @@ -5540,6 +5632,7 @@ bool FurnaceGUI::finish() { e->setConf("pianoOpen",pianoOpen); e->setConf("notesOpen",notesOpen); e->setConf("channelsOpen",channelsOpen); + e->setConf("regViewOpen",regViewOpen); // commit last window size e->setConf("lastWindowWidth",scrW); @@ -5609,6 +5702,7 @@ FurnaceGUI::FurnaceGUI(): pianoOpen(false), notesOpen(false), channelsOpen(false), + regViewOpen(false), selecting(false), curNibble(false), orderNibble(false), @@ -5665,6 +5759,7 @@ FurnaceGUI::FurnaceGUI(): oldOrdersLen(0) { // octave 1 + /* noteKeys[SDL_SCANCODE_Z]=0; noteKeys[SDL_SCANCODE_S]=1; noteKeys[SDL_SCANCODE_X]=2; @@ -5710,6 +5805,7 @@ FurnaceGUI::FurnaceGUI(): // env release noteKeys[SDL_SCANCODE_GRAVE]=102; + */ // value keys valueKeys[SDLK_0]=0; @@ -5748,4 +5844,5 @@ FurnaceGUI::FurnaceGUI(): memset(patChanX,0,sizeof(float)*(DIV_MAX_CHANS+1)); memset(patChanSlideY,0,sizeof(float)*(DIV_MAX_CHANS+1)); + memset(lastIns,-1,sizeof(int)*DIV_MAX_CHANS); } diff --git a/src/gui/gui.h b/src/gui/gui.h index f6683981e..31817e772 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -128,6 +128,7 @@ enum FurnaceGUIWindows { GUI_WINDOW_PIANO, GUI_WINDOW_NOTES, GUI_WINDOW_CHANNELS, + GUI_WINDOW_REGISTER_VIEW }; enum FurnaceGUIFileDialogs { @@ -210,6 +211,7 @@ enum FurnaceGUIActions { GUI_ACTION_WINDOW_PIANO, GUI_ACTION_WINDOW_NOTES, GUI_ACTION_WINDOW_CHANNELS, + GUI_ACTION_WINDOW_REGISTER_VIEW, GUI_ACTION_COLLAPSE_WINDOW, GUI_ACTION_CLOSE_WINDOW, @@ -521,7 +523,7 @@ class FurnaceGUI { bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen; bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen; bool mixerOpen, debugOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen; - bool pianoOpen, notesOpen, channelsOpen; + bool pianoOpen, notesOpen, channelsOpen, regViewOpen; SelectionPoint selStart, selEnd, cursor; bool selecting, curNibble, orderNibble, followOrders, followPattern, changeAllOrders; bool collapseWindow, demandScrollX, fancyPattern, wantPatName; @@ -568,9 +570,9 @@ class FurnaceGUI { int samplePreviewNote; // SDL_Scancode,int - std::map noteKeys; + std::map noteKeys; // SDL_Keycode,int - std::map valueKeys; + std::map valueKeys; int arpMacroScroll; @@ -621,6 +623,7 @@ class FurnaceGUI { std::deque redoHist; float keyHit[DIV_MAX_CHANS]; + int lastIns[DIV_MAX_CHANS]; void drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, const ImVec2& size); void drawFMEnv(unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, const ImVec2& size); @@ -648,6 +651,7 @@ class FurnaceGUI { void drawPiano(); void drawNotes(); void drawChannels(); + void drawRegView(); void drawAbout(); void drawSettings(); void drawDebug(); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index e1d87404d..765f666a1 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -480,7 +480,7 @@ void FurnaceGUI::drawFMEnv(unsigned char ar, unsigned char dr, unsigned char d2r #define PARAMETER modified=true; e->notifyInsChange(curIns); -#define NORMAL_MACRO(macro,macroLen,macroLoop,macroRel,macroMin,macroHeight,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,drawSlider,sliderVal,sliderLow,macroDispMin,bitOff,macroMode,macroColor,mmlStr,macroAMin,macroAMax,hoverFunc) \ +#define NORMAL_MACRO(macro,macroLen,macroLoop,macroRel,macroMin,macroHeight,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,drawSlider,sliderVal,sliderLow,macroDispMin,bitOff,macroMode,macroColor,mmlStr,macroAMin,macroAMax,hoverFunc,blockMode) \ ImGui::TableNextRow(); \ ImGui::TableNextColumn(); \ ImGui::Text("%s",displayName); \ @@ -517,7 +517,7 @@ void FurnaceGUI::drawFMEnv(unsigned char ar, unsigned char dr, unsigned char d2r if (bitfield) { \ PlotBitfield("##IMacro_" macroName,asInt,totalFit,0,bfVal,macroHeight,ImVec2(availableWidth,(displayLoop)?(displayHeight*dpiScale):(32.0f*dpiScale))); \ } else { \ - PlotCustom("##IMacro_" macroName,asFloat,totalFit,macroDragScroll,NULL,macroDispMin+macroMin,macroHeight+macroDispMin,ImVec2(availableWidth,(displayLoop)?(displayHeight*dpiScale):(32.0f*dpiScale)),sizeof(float),macroColor,macroLen-macroDragScroll,hoverFunc); \ + PlotCustom("##IMacro_" macroName,asFloat,totalFit,macroDragScroll,NULL,macroDispMin+macroMin,macroHeight+macroDispMin,ImVec2(availableWidth,(displayLoop)?(displayHeight*dpiScale):(32.0f*dpiScale)),sizeof(float),macroColor,macroLen-macroDragScroll,hoverFunc,blockMode); \ } \ if (displayLoop && ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \ macroDragStart=ImGui::GetItemRectMin(); \ @@ -779,15 +779,15 @@ void FurnaceGUI::drawInsEdit() { } if (ImGui::BeginTabItem("Macros (FM)")) { MACRO_BEGIN(0); - NORMAL_MACRO(ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel,0,7,"alg",FM_NAME(FM_ALG),96,ins->std.algMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,7,NULL); - NORMAL_MACRO(ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL); - NORMAL_MACRO(ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL); - NORMAL_MACRO(ins->std.amsMacro,ins->std.amsMacroLen,ins->std.amsMacroLoop,ins->std.amsMacroRel,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,3,NULL); + NORMAL_MACRO(ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel,0,7,"alg",FM_NAME(FM_ALG),96,ins->std.algMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,7,NULL,false); + NORMAL_MACRO(ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false); + NORMAL_MACRO(ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false); + NORMAL_MACRO(ins->std.amsMacro,ins->std.amsMacroLen,ins->std.amsMacroLoop,ins->std.amsMacroRel,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,3,NULL,false); - NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,127,"ex1","AM Depth",128,ins->std.ex1MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,127,NULL); - NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,127,"ex2","PM Depth",128,ins->std.ex2MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,127,NULL); - NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,255,"ex3","LFO Speed",128,ins->std.ex3MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,255,NULL); - NORMAL_MACRO(ins->std.waveMacro,ins->std.waveMacroLen,ins->std.waveMacroLoop,ins->std.waveMacroRel,0,3,"wave","LFO Shape",48,ins->std.waveMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[7],0,3,¯oLFOWaves); + NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,127,"ex1","AM Depth",128,ins->std.ex1MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,127,NULL,false); + NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,127,"ex2","PM Depth",128,ins->std.ex2MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,127,NULL,false); + NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,255,"ex3","LFO Speed",128,ins->std.ex3MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,255,NULL,false); + NORMAL_MACRO(ins->std.waveMacro,ins->std.waveMacroLen,ins->std.waveMacroLoop,ins->std.waveMacroRel,0,3,"wave","LFO Shape",48,ins->std.waveMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[7],0,3,¯oLFOWaves,false); MACRO_END; ImGui::EndTabItem(); } @@ -1018,47 +1018,47 @@ void FurnaceGUI::drawInsEdit() { if (settings.macroView==0) { // modern view MACRO_BEGIN(28*dpiScale); if (volMax>0) { - NORMAL_MACRO(ins->std.volMacro,ins->std.volMacroLen,ins->std.volMacroLoop,ins->std.volMacroRel,volMin,volMax,"vol",volumeLabel,160,ins->std.volMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_VOLUME],mmlString[0],volMin,volMax,NULL); + NORMAL_MACRO(ins->std.volMacro,ins->std.volMacroLen,ins->std.volMacroLoop,ins->std.volMacroRel,volMin,volMax,"vol",volumeLabel,160,ins->std.volMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_VOLUME],mmlString[0],volMin,volMax,NULL,false); } - NORMAL_MACRO(ins->std.arpMacro,ins->std.arpMacroLen,ins->std.arpMacroLoop,ins->std.arpMacroRel,arpMacroScroll,arpMacroScroll+24,"arp","Arpeggio",160,ins->std.arpMacroOpen,false,NULL,true,&arpMacroScroll,(arpMode?0:-80),0,0,&ins->std.arpMacroMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[1],-92,94,(ins->std.arpMacroMode?(¯oHoverNote):NULL)); + NORMAL_MACRO(ins->std.arpMacro,ins->std.arpMacroLen,ins->std.arpMacroLoop,ins->std.arpMacroRel,arpMacroScroll,arpMacroScroll+24,"arp","Arpeggio",160,ins->std.arpMacroOpen,false,NULL,true,&arpMacroScroll,(arpMode?0:-80),0,0,&ins->std.arpMacroMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[1],-92,94,(ins->std.arpMacroMode?(¯oHoverNote):NULL),true); if (dutyMax>0) { if (ins->type == DIV_INS_MIKEY) { - NORMAL_MACRO(ins->std.dutyMacro,ins->std.dutyMacroLen,ins->std.dutyMacroLoop,ins->std.dutyMacroRel,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacroOpen,true,mikeyFeedbackBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL); + NORMAL_MACRO(ins->std.dutyMacro,ins->std.dutyMacroLen,ins->std.dutyMacroLoop,ins->std.dutyMacroRel,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacroOpen,true,mikeyFeedbackBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false); } else { - NORMAL_MACRO(ins->std.dutyMacro,ins->std.dutyMacroLen,ins->std.dutyMacroLoop,ins->std.dutyMacroRel,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL); + NORMAL_MACRO(ins->std.dutyMacro,ins->std.dutyMacroLen,ins->std.dutyMacroLoop,ins->std.dutyMacroRel,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false); } } if (waveMax>0) { - NORMAL_MACRO(ins->std.waveMacro,ins->std.waveMacroLen,ins->std.waveMacroLoop,ins->std.waveMacroRel,0,waveMax,"wave","Waveform",bitMode?64:160,ins->std.waveMacroOpen,bitMode,waveNames,false,NULL,0,0,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0),NULL,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[3],0,waveMax,NULL); + NORMAL_MACRO(ins->std.waveMacro,ins->std.waveMacroLen,ins->std.waveMacroLoop,ins->std.waveMacroRel,0,waveMax,"wave","Waveform",bitMode?64:160,ins->std.waveMacroOpen,bitMode,waveNames,false,NULL,0,0,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0),NULL,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[3],0,waveMax,NULL,false); } if (ex1Max>0) { if (ins->type==DIV_INS_C64) { - NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Filter Mode",64,ins->std.ex1MacroOpen,true,filtModeBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL); + NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Filter Mode",64,ins->std.ex1MacroOpen,true,filtModeBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } else if (ins->type==DIV_INS_SAA1099) { - NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Envelope",160,ins->std.ex1MacroOpen,true,saaEnvBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL); + NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Envelope",160,ins->std.ex1MacroOpen,true,saaEnvBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } else { - NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Duty",160,ins->std.ex1MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL); + NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Duty",160,ins->std.ex1MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } } if (ex2Max>0) { if (ins->type==DIV_INS_C64) { - NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,ex2Max,"ex2","Resonance",64,ins->std.ex2MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL); + NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,ex2Max,"ex2","Resonance",64,ins->std.ex2MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); } else { - NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,ex2Max,"ex2","Envelope",64,ins->std.ex2MacroOpen,true,ayEnvBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL); + NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,ex2Max,"ex2","Envelope",64,ins->std.ex2MacroOpen,true,ayEnvBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); } } if (ins->type==DIV_INS_C64) { - NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,2,"ex3","Special",32,ins->std.ex3MacroOpen,true,c64SpecialBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,2,NULL); + NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,2,"ex3","Special",32,ins->std.ex3MacroOpen,true,c64SpecialBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,2,NULL,false); } if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930) { - NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,15,"ex3","AutoEnv Num",96,ins->std.ex3MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,15,NULL); - NORMAL_MACRO(ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel,0,15,"alg","AutoEnv Den",96,ins->std.algMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,15,NULL); + NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,15,"ex3","AutoEnv Num",96,ins->std.ex3MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,15,NULL,false); + NORMAL_MACRO(ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel,0,15,"alg","AutoEnv Den",96,ins->std.algMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,15,NULL,false); } if (ins->type==DIV_INS_AY8930) { // oh my i am running out of macros - NORMAL_MACRO(ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel,0,8,"fb","Noise AND Mask",96,ins->std.fbMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,8,NULL); - NORMAL_MACRO(ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel,0,8,"fms","Noise OR Mask",96,ins->std.fmsMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,8,NULL); + NORMAL_MACRO(ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel,0,8,"fb","Noise AND Mask",96,ins->std.fbMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,8,NULL,false); + NORMAL_MACRO(ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel,0,8,"fms","Noise OR Mask",96,ins->std.fmsMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,8,NULL,false); } MACRO_END; diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index b86180289..c6c78ba8d 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -86,6 +86,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int if (i<0 || i>=e->song.patLen) { return; } + bool isPushing=false; // check overflow highlight if (settings.overflowHighlight) { if (edit && cursor.y==i) { @@ -97,6 +98,19 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int } else if (e->song.hilightA>0 && !(i%e->song.hilightA)) { ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_HI_1])); } + } else { + isPushing=true; + if (edit && cursor.y==i) { + ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_EDITING])); + } else if (isPlaying && oldRow==i) { + ImGui::PushStyleColor(ImGuiCol_Header,0x40ffffff); + } else if (e->song.hilightB>0 && !(i%e->song.hilightB)) { + ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_HI_2])); + } else if (e->song.hilightA>0 && !(i%e->song.hilightA)) { + ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_HI_1])); + } else { + isPushing=false; + } } // row number if (settings.patRowsBase==1) { @@ -117,19 +131,6 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int ImGui::TableNextColumn(); patChanX[j]=ImGui::GetCursorPosX(); - // check overflow highlight - if (!settings.overflowHighlight) { - if (edit && cursor.y==i) { - ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(uiColors[GUI_COLOR_EDITING])); - } else if (isPlaying && oldRow==i) { - ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,0x40ffffff); - } else if (e->song.hilightB>0 && !(i%e->song.hilightB)) { - ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_HI_2])); - } else if (e->song.hilightA>0 && !(i%e->song.hilightA)) { - ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_HI_1])); - } - } - // selection highlight flags int sel1XSum=sel1.xCoarse*32+sel1.xFine; int sel2XSum=sel2.xCoarse*32+sel2.xFine; @@ -141,6 +142,8 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int bool cursorIns=(cursor.y==i && cursor.xCoarse==j && cursor.xFine==1); bool cursorVol=(cursor.y==i && cursor.xCoarse==j && cursor.xFine==2); + + // note sprintf(id,"%s##PN_%d_%d",noteName(pat->data[i][0],pat->data[i][1]),i,j); if (pat->data[i][0]==0 && pat->data[i][1]==0) { @@ -156,7 +159,9 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int demandX=ImGui::GetCursorPosX(); ImGui::PopStyleColor(3); } else { - ImGui::Selectable(id,selectedNote,ImGuiSelectableFlags_NoPadWithHalfSpacing,threeChars); + if (selectedNote) ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]); + ImGui::Selectable(id,isPushing || selectedNote,ImGuiSelectableFlags_NoPadWithHalfSpacing,threeChars); + if (selectedNote) ImGui::PopStyleColor(); } if (ImGui::IsItemClicked()) { startSelection(j,0,i); @@ -185,7 +190,9 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int demandX=ImGui::GetCursorPosX(); ImGui::PopStyleColor(3); } else { - ImGui::Selectable(id,selectedIns,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars); + if (selectedIns) ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]); + ImGui::Selectable(id,isPushing || selectedIns,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars); + if (selectedIns) ImGui::PopStyleColor(); } if (ImGui::IsItemClicked()) { startSelection(j,1,i); @@ -215,7 +222,9 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int demandX=ImGui::GetCursorPosX(); ImGui::PopStyleColor(3); } else { - ImGui::Selectable(id,selectedVol,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars); + if (selectedVol) ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]); + ImGui::Selectable(id,isPushing || selectedVol,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars); + if (selectedVol) ImGui::PopStyleColor(); } if (ImGui::IsItemClicked()) { startSelection(j,2,i); @@ -268,7 +277,9 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int demandX=ImGui::GetCursorPosX(); ImGui::PopStyleColor(3); } else { - ImGui::Selectable(id,selectedEffect,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars); + if (selectedEffect) ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]); + ImGui::Selectable(id,isPushing || selectedEffect,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars); + if (selectedEffect) ImGui::PopStyleColor(); } if (ImGui::IsItemClicked()) { startSelection(j,index-1,i); @@ -292,7 +303,9 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int demandX=ImGui::GetCursorPosX(); ImGui::PopStyleColor(3); } else { - ImGui::Selectable(id,selectedEffectVal,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars); + if (selectedEffectVal) ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]); + ImGui::Selectable(id,isPushing || selectedEffectVal,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars); + if (selectedEffectVal) ImGui::PopStyleColor(); } if (ImGui::IsItemClicked()) { startSelection(j,index,i); @@ -304,6 +317,9 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int } } } + if (isPushing) { + ImGui::PopStyleColor(); + } ImGui::TableNextColumn(); patChanX[chans]=ImGui::GetCursorPosX(); } @@ -315,6 +331,9 @@ void FurnaceGUI::drawPattern() { nextWindow=GUI_WINDOW_NOTHING; } if (!patternOpen) return; + + float scrollX=0; + if (e->isPlaying() && followPattern) cursor.y=oldRow; demandX=0; sel1=selStart; @@ -381,6 +400,15 @@ void FurnaceGUI::drawPattern() { if (ImGui::Selectable((extraChannelButtons==2)?" --##ExtraChannelButtons":" ++##ExtraChannelButtons",false,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale))) { if (++extraChannelButtons>2) extraChannelButtons=0; } + if (ImGui::IsItemHovered()) { + if (extraChannelButtons==2) { + ImGui::SetTooltip("Pattern names (click to collapse)\nRight-click for visualizer"); + } else if (extraChannelButtons==1) { + ImGui::SetTooltip("Expanded (click for pattern names)\nRight-click for visualizer"); + } else { + ImGui::SetTooltip("Compact (click to expand)\nRight-click for visualizer"); + } + } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { fancyPattern=!fancyPattern; e->enableCommandStream(fancyPattern); @@ -428,7 +456,6 @@ void FurnaceGUI::drawPattern() { ImGui::PushStyleColor(ImGuiCol_Header,chanHead); ImGui::PushStyleColor(ImGuiCol_HeaderActive,chanHeadActive); ImGui::PushStyleColor(ImGuiCol_HeaderHovered,chanHeadHover); - // help me why is the color leakingggggggg ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(chanHead)); if (muted) ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_CHANNEL_MUTED]); ImGui::Selectable(chanID,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale)); @@ -554,6 +581,7 @@ void FurnaceGUI::drawPattern() { } demandScrollX=false; } + scrollX=ImGui::GetScrollX(); ImGui::EndTable(); } @@ -569,7 +597,6 @@ void FurnaceGUI::drawPattern() { //if (i.cmd==DIV_CMD_NOTE_ON) continue; if (i.cmd==DIV_CMD_PRE_PORTA) continue; if (i.cmd==DIV_CMD_PRE_NOTE) continue; - if (i.cmd==DIV_CMD_INSTRUMENT) continue; if (i.cmd==DIV_CMD_SAMPLE_BANK) continue; if (i.cmd==DIV_CMD_GET_VOLUME) continue; if (i.cmd==DIV_ALWAYS_SET_VOLUME) continue; @@ -589,8 +616,8 @@ void FurnaceGUI::drawPattern() { switch (i.cmd) { case DIV_CMD_NOTE_ON: partIcon=ICON_FA_ASTERISK; - life=64.0f; - lifeSpeed=2.0f; + life=96.0f; + lifeSpeed=3.0f; break; case DIV_CMD_LEGATO: partIcon=ICON_FA_COG; @@ -618,6 +645,23 @@ void FurnaceGUI::drawPattern() { color=volGrad; break; } + case DIV_CMD_INSTRUMENT: { + if (lastIns[i.chan]==i.value) { + num=0; + break; + } + lastIns[i.chan]=i.value; + speedX=0.0f; + speedY=0.0f; + grav=0.0f; + frict=0.98; + spread=30.0f; + life=128.0f; + lifeSpeed=6.0f; + color=insGrad; + num=7+pow(i.value,0.6); + break; + } case DIV_CMD_PANNING: { if (i.value==0) { num=0; @@ -661,7 +705,7 @@ void FurnaceGUI::drawPattern() { particles.push_back(Particle( color, partIcon, - off.x+patChanX[i.chan]+fmod(rand(),width), + off.x+patChanX[i.chan]+fmod(rand(),width)-scrollX, off.y+(ImGui::GetWindowHeight()*0.5f)+randRange(0,patFont->FontSize), (speedX+randRange(-spread,spread))*0.5*dpiScale, (speedY+randRange(-spread,spread))*0.5*dpiScale, @@ -675,31 +719,30 @@ void FurnaceGUI::drawPattern() { // note slides ImVec2 arrowPoints[7]; - for (int i=0; iisPlaying()) for (int i=0; isong.chanShow[i]) continue; DivChannelState* ch=e->getChanState(i); if (ch->portaSpeed>0) { ImVec4 col=uiColors[GUI_COLOR_PATTERN_EFFECT_PITCH]; col.w*=0.2; float width=patChanX[i+1]-patChanX[i]; - if (e->isPlaying()) { - particles.push_back(Particle( - pitchGrad, - (ch->portaNote<=ch->note)?ICON_FA_CHEVRON_DOWN:ICON_FA_CHEVRON_UP, - off.x+patChanX[i]+fmod(rand(),width), - off.y+fmod(rand(),MAX(1,ImGui::GetWindowHeight())), - 0.0f, - (7.0f+(rand()%5)+pow(ch->portaSpeed,0.7f))*((ch->portaNote<=ch->note)?1:-1), - 0.0f, - 1.0f, - 255.0f, - 15.0f - )); - } + particles.push_back(Particle( + pitchGrad, + (ch->portaNote<=ch->note)?ICON_FA_CHEVRON_DOWN:ICON_FA_CHEVRON_UP, + off.x+patChanX[i]+fmod(rand(),width)-scrollX, + off.y+fmod(rand(),MAX(1,ImGui::GetWindowHeight())), + 0.0f, + (7.0f+(rand()%5)+pow(ch->portaSpeed,0.7f))*((ch->portaNote<=ch->note)?1:-1), + 0.0f, + 1.0f, + 255.0f, + 15.0f + )); - for (float j=-patChanSlideY[i]; j0.1) for (float j=-patChanSlideY[i]; jportaNote<=ch->note) { arrowPoints[0]=ImLerp(tMin,tMax,ImVec2(0.1,1.0-0.8)); arrowPoints[1]=ImLerp(tMin,tMax,ImVec2(0.5,1.0-0.0)); diff --git a/src/gui/plot_nolerp.cpp b/src/gui/plot_nolerp.cpp index c70450d22..1c1cf94ad 100644 --- a/src/gui/plot_nolerp.cpp +++ b/src/gui/plot_nolerp.cpp @@ -289,7 +289,7 @@ void PlotBitfield(const char* label, const int* values, int values_count, int va PlotBitfieldEx(label, &Plot_IntArrayGetter, (void*)&data, values_count, values_offset, overlay_text, bits, graph_size); } -int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_display_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float)) +int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_display_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float), bool blockMode) { ImGuiContext& g = *GImGui; ImGuiWindow* window = ImGui::GetCurrentWindow(); @@ -384,6 +384,10 @@ int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_gett bgColor); } + if (blockMode) { + window->DrawList->AddLine(ImLerp(inner_bb.Min,inner_bb.Max,ImVec2(0.0f,histogram_zero_line_t)),ImLerp(inner_bb.Min,inner_bb.Max,ImVec2(1.0f,histogram_zero_line_t)),col_base); + } + for (int n = 0; n < res_w; n++) { const float t1 = t0 + t_step; @@ -394,7 +398,7 @@ int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_gett // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU. ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0); - ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t)); + ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, blockMode?tp0.y:histogram_zero_line_t)); if (plot_type == ImGuiPlotType_Lines) { window->DrawList->AddLine(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base); @@ -403,6 +407,10 @@ int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_gett { if (pos1.x >= pos0.x + 2.0f) pos1.x -= 1.0f; + if (blockMode) { + pos0.y-=(inner_bb.Max.y-inner_bb.Min.y)*inv_scale; + //pos1.y+=1.0f; + } window->DrawList->AddRectFilled(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base); } @@ -423,8 +431,8 @@ int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_gett return idx_hovered; } -void PlotCustom(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float)) +void PlotCustom(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float), bool blockMode) { FurnacePlotArrayGetterData data(values, stride); - PlotCustomEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size, color, highlight, hoverFunc); + PlotCustomEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size, color, highlight, hoverFunc, blockMode); } \ No newline at end of file diff --git a/src/gui/plot_nolerp.h b/src/gui/plot_nolerp.h index d6e4d5e75..8e897c121 100644 --- a/src/gui/plot_nolerp.h +++ b/src/gui/plot_nolerp.h @@ -22,4 +22,4 @@ void PlotNoLerp(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); void PlotBitfield(const char* label, const int* values, int values_count, int values_offset = 0, const char** overlay_text = NULL, int bits = 8, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); -void PlotCustom(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float), ImVec4 fgColor = ImVec4(1.0f,1.0f,1.0f,1.0f), int highlight = 0, std::string (*hoverFunc)(int,float) = NULL); \ No newline at end of file +void PlotCustom(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float), ImVec4 fgColor = ImVec4(1.0f,1.0f,1.0f,1.0f), int highlight = 0, std::string (*hoverFunc)(int,float) = NULL, bool blockMode=false); \ No newline at end of file diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 8bf46a530..c6b27651e 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -22,7 +22,9 @@ #include "util.h" #include "IconsFontAwesome4.h" #include "misc/cpp/imgui_stdlib.h" +#include #include +#include #ifdef __APPLE__ #define FURKMOD_CMD FURKMOD_META @@ -30,6 +32,8 @@ #define FURKMOD_CMD FURKMOD_CTRL #endif +#define DEFAULT_NOTE_KEYS "5:7;6:4;7:3;8:16;10:6;11:8;12:24;13:10;16:11;17:9;18:26;19:28;20:12;21:17;22:1;23:19;24:23;25:5;26:14;27:2;28:21;29:0;30:100;31:13;32:15;34:18;35:20;36:22;38:25;39:27;43:100;46:101;47:29;48:31;53:102;" + const char* mainFonts[]={ "IBM Plex Sans", "Liberation Sans", @@ -113,6 +117,15 @@ void FurnaceGUI::promptKey(int which) { actionKeys[which]=0; } +struct MappedInput { + int scan; + int val; + MappedInput(): + scan(SDL_SCANCODE_UNKNOWN), val(0) {} + MappedInput(int s, int v): + scan(s), val(v) {} +}; + void FurnaceGUI::drawSettings() { if (nextWindow==GUI_WINDOW_SETTINGS) { settingsOpen=true; @@ -564,6 +577,7 @@ void FurnaceGUI::drawSettings() { UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_PIANO,"Piano"); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_NOTES,"Song Comments"); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_CHANNELS,"Channels"); + UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_REGISTER_VIEW,"Register View"); UI_KEYBIND_CONFIG(GUI_ACTION_COLLAPSE_WINDOW,"Collapse/expand current window"); UI_KEYBIND_CONFIG(GUI_ACTION_CLOSE_WINDOW,"Close current window"); @@ -571,6 +585,89 @@ void FurnaceGUI::drawSettings() { KEYBIND_CONFIG_END; ImGui::TreePop(); } + if (ImGui::TreeNode("Note input")) { + std::vector sorted; + if (ImGui::BeginTable("keysNoteInput",4)) { + for (std::map::value_type& i: noteKeys) { + std::vector::iterator j; + for (j=sorted.begin(); j!=sorted.end(); j++) { + if (j->val>i.second) { + break; + } + } + sorted.insert(j,MappedInput(i.first,i.second)); + } + + static char id[4096]; + + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::Text("Key"); + ImGui::TableNextColumn(); + ImGui::Text("Type"); + ImGui::TableNextColumn(); + ImGui::Text("Value"); + ImGui::TableNextColumn(); + ImGui::Text("Remove"); + + for (MappedInput& i: sorted) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%s",SDL_GetScancodeName((SDL_Scancode)i.scan)); + ImGui::TableNextColumn(); + if (i.val==102) { + snprintf(id,4095,"Envelope release##SNType_%d",i.scan); + if (ImGui::Button(id)) { + noteKeys[i.scan]=0; + } + } else if (i.val==101) { + snprintf(id,4095,"Note release##SNType_%d",i.scan); + if (ImGui::Button(id)) { + noteKeys[i.scan]=102; + } + } else if (i.val==100) { + snprintf(id,4095,"Note off##SNType_%d",i.scan); + if (ImGui::Button(id)) { + noteKeys[i.scan]=101; + } + } else { + snprintf(id,4095,"Note##SNType_%d",i.scan); + if (ImGui::Button(id)) { + noteKeys[i.scan]=100; + } + } + ImGui::TableNextColumn(); + if (i.val<100) { + snprintf(id,4095,"##SNValue_%d",i.scan); + if (ImGui::InputInt(id,&i.val,1,1)) { + if (i.val<0) i.val=0; + if (i.val>96) i.val=96; + noteKeys[i.scan]=i.val; + } + } + ImGui::TableNextColumn(); + snprintf(id,4095,ICON_FA_TIMES "##SNRemove_%d",i.scan); + if (ImGui::Button(id)) { + noteKeys.erase(i.scan); + } + } + ImGui::EndTable(); + + if (ImGui::BeginCombo("##SNAddNew","Add...")) { + for (int i=0; igetConfString("noteKeys",DEFAULT_NOTE_KEYS)); + parseKeybinds(); } @@ -1072,6 +1172,7 @@ void FurnaceGUI::commitSettings() { SAVE_KEYBIND(GUI_ACTION_WINDOW_PIANO); SAVE_KEYBIND(GUI_ACTION_WINDOW_NOTES); SAVE_KEYBIND(GUI_ACTION_WINDOW_CHANNELS); + SAVE_KEYBIND(GUI_ACTION_WINDOW_REGISTER_VIEW); SAVE_KEYBIND(GUI_ACTION_COLLAPSE_WINDOW); SAVE_KEYBIND(GUI_ACTION_CLOSE_WINDOW); @@ -1173,6 +1274,8 @@ void FurnaceGUI::commitSettings() { SAVE_KEYBIND(GUI_ACTION_ORDERS_MOVE_DOWN); SAVE_KEYBIND(GUI_ACTION_ORDERS_REPLAY); + e->setConf("noteKeys",encodeKeyMap(noteKeys)); + e->saveConf(); if (!e->switchMaster()) {