From e0e6a45000baa89f7bbe08a2d03883a29bc7c0cf Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 6 Jun 2022 19:04:52 +0900 Subject: [PATCH 001/101] Prepare for reducing duplicates for 4op FM related codes, Add and correct bunch of presets, Add various clock, type options for chips Prepare for reducing duplicates for 4op FM related codes Add and correct bunch of presets - mostly based on MAME source. - Neo Geo AES uses slightly difference clock for NTSC, PAL colorbust frequency. - Turbosound FM + SAA: Some Turbosound FM has additional SAA1099, for additional sound channel and Plays SAM coupe tune? - PC-98: - Sound Orchestra: OPN with hardpanned stereo, some model has with OPL family FM addons. V variation has Y8950 and supports ADPCM. - Sound Blaster 16 for PC-9800: This famous PC sound card is also exists for PC-98, with optional OPN PC-9801-26(K) compatibility on some models. - IBM PCjr: PC with SN PSG sound, but less popular than previous models, and compatible Tandy 1000. - Tandy 1000: PCjr and previous IBM PC compatible, also has SN PSG (later embedded in their ASIC, like Sega). - Hexion: One of konami's budget arcade hardware with SCC + MSM6295 sound system, like their amusement hardware in this era. - DJ Boy, Atari JSA IIIs, Skimaxx: How to panning sound or plays stereo sound on MSM6295 - just use MSM6295s per each output! - Air Buster: One of arcade hardware with OPN + MSM6295 sound system, Used this configuration is also some hardwares. - Tecmo system: One of arcade hardware with pretty unique sound system: OPL3, YMZ280B, MSM6295; first 2 entry is mostly used in music, last entry is mostly used in sound effect. - Sunsoft Shanghai 3: Predecessor of Sunsoft Arcade is using YM2149 rather than FM, MSM6295 is still there. - Atari Klax: example of arcade hardware sound system with single MSM6295 only. - Ikari warriors: This early SNK Triple-Z80 hardware uses 2 OPL1s and no ADPCM supports. - Coreland Cyber Tank: This rare arcade machine's stereo sound is like SB Pro, but it's actually produced in 2 Y8950s. - Data East MLC: Latest arcade hardware from Data East, with single YMZ280B for sound. - Kaneko Jackie Chan: Predecessor of Super Kaneko Nova System hardware, also with YMZ280B. - Super Kaneko Nova System: Latest arcade hardware from Kaneko, with single YMZ280B for sound. this announced 3D acceleration addon, but finally cancelled. - Toaplan 1: Home of Late 80-Early 90s Good ol' stuffs, Example of arcade sound system with single OPL2 - Namco Pac-Land: and this era, Namco start to change Custom 15 WSG to their Custom 30 WSG with featured RAM based waveform, and mailbox feature. - Namco System 1: One of latest usage of Custom 30 WSG, with OPM FM hardware and 8 bit DAC and Stereo output. Add various clock, type options for chips - SN7: Prepare to add 17 bit noise variation, Game gear stereo extentsion, NCR PSG variation (MAME core only for now) - OPN, OPNA: Add placeholder for prescaler option - OPL: Prepare for OPL3L, OPL4 downscaled output rate option --- extern/Nuked-PSG/ympsg.c | 9 +- extern/Nuked-PSG/ympsg.h | 5 +- src/engine/platform/arcade.cpp | 61 +- src/engine/platform/arcade.h | 19 +- src/engine/platform/ay.cpp | 100 +- src/engine/platform/ay.h | 8 + src/engine/platform/fmshared_OPM.h | 21 +- src/engine/platform/fmshared_OPN.h | 25 +- .../{genesisshared.h => fmsharedbase.h} | 65 +- src/engine/platform/genesis.cpp | 8 +- src/engine/platform/genesis.h | 15 +- src/engine/platform/genesisext.cpp | 4 - src/engine/platform/msm6258.h | 13 +- src/engine/platform/msm6295.cpp | 57 +- src/engine/platform/msm6295.h | 109 +-- src/engine/platform/opl.cpp | 102 +- src/engine/platform/opl.h | 6 +- src/engine/platform/scc.cpp | 27 +- src/engine/platform/scc.h | 1 + src/engine/platform/sms.cpp | 211 +++-- src/engine/platform/sms.h | 15 +- src/engine/platform/sound/sn76496.cpp | 83 +- src/engine/platform/sound/sn76496.h | 113 ++- src/engine/platform/tx81z.cpp | 36 +- src/engine/platform/tx81z.h | 19 +- src/engine/platform/ym2203.cpp | 57 +- src/engine/platform/ym2203.h | 23 +- src/engine/platform/ym2203ext.cpp | 5 +- src/engine/platform/ym2203shared.h | 45 - src/engine/platform/ym2608.cpp | 40 +- src/engine/platform/ym2608.h | 24 +- src/engine/platform/ym2608ext.cpp | 3 - src/engine/platform/ym2610.cpp | 43 +- src/engine/platform/ym2610.h | 26 +- src/engine/platform/ym2610b.cpp | 40 +- src/engine/platform/ym2610b.h | 17 +- src/engine/platform/ym2610bext.cpp | 3 - src/engine/platform/ym2610ext.cpp | 3 - src/engine/platform/ym2610shared.h | 45 - src/engine/platform/ymz280b.cpp | 44 +- src/engine/platform/ymz280b.h | 1 + src/engine/song.h | 124 ++- src/gui/insEdit.cpp | 7 +- src/gui/presets.cpp | 893 +++++++++++++++--- src/gui/sysConf.cpp | 352 ++++--- src/main.cpp | 1 + 46 files changed, 2027 insertions(+), 901 deletions(-) rename src/engine/platform/{genesisshared.h => fmsharedbase.h} (60%) delete mode 100644 src/engine/platform/ym2203shared.h delete mode 100644 src/engine/platform/ym2610shared.h diff --git a/extern/Nuked-PSG/ympsg.c b/extern/Nuked-PSG/ympsg.c index 3df4f8e39..935b43ea9 100644 --- a/extern/Nuked-PSG/ympsg.c +++ b/extern/Nuked-PSG/ympsg.c @@ -130,7 +130,7 @@ static void YMPSG_ClockInternal1(ympsg_t *chip) else if (noise_of && !chip->noise_of) { noise_bit1 = (chip->noise >> chip->noise_tap2) & 1; - noise_bit2 = (chip->noise >> 12) & 1; + noise_bit2 = (chip->noise >> chip->noise_tap1) & 1; noise_bit1 ^= noise_bit2; noise_next = ((noise_bit1 && ((chip->noise_data >> 2) & 1)) || ((chip->noise & chip->noise_size) == 0)); chip->noise <<= 1; @@ -257,13 +257,14 @@ uint16_t YMPSG_Read(ympsg_t *chip) return data; } -void YMPSG_Init(ympsg_t *chip, uint8_t real_sn) +void YMPSG_Init(ympsg_t *chip, uint8_t real_sn, uint8_t noise_tap1, uint8_t noise_tap2, uint32_t noise_size) { uint32_t i; memset(chip, 0, sizeof(ympsg_t)); YMPSG_SetIC(chip, 1); - chip->noise_tap2 = real_sn ? 13 : 15; - chip->noise_size = real_sn ? 16383 : 32767; + chip->noise_tap1 = noise_tap1; + chip->noise_tap2 = noise_tap2; + chip->noise_size = noise_size; for (i = 0; i < 17; i++) { chip->vol_table[i]=(real_sn?tipsg_vol[i]:ympsg_vol[i]) * 8192.0f; diff --git a/extern/Nuked-PSG/ympsg.h b/extern/Nuked-PSG/ympsg.h index c00b3d720..97e039e3c 100644 --- a/extern/Nuked-PSG/ympsg.h +++ b/extern/Nuked-PSG/ympsg.h @@ -46,8 +46,9 @@ typedef struct { uint8_t sign_l; uint8_t noise_sign_l; uint16_t noise; + uint8_t noise_tap1; uint8_t noise_tap2; - uint16_t noise_size; + uint32_t noise_size; uint8_t test; uint8_t volume_out[4]; @@ -68,7 +69,7 @@ typedef struct { void YMPSG_Write(ympsg_t *chip, uint8_t data); uint16_t YMPSG_Read(ympsg_t *chip); -void YMPSG_Init(ympsg_t *chip, uint8_t real_sn); +void YMPSG_Init(ympsg_t *chip, uint8_t real_sn, uint8_t noise_tap1, uint8_t noise_tap2, uint32_t noise_size); void YMPSG_SetIC(ympsg_t *chip, uint32_t ic); void YMPSG_Clock(ympsg_t *chip); int YMPSG_GetOutput(ympsg_t *chip); diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 564467256..f6fa7d70a 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -22,38 +22,6 @@ #include #include -#include "fmshared_OPM.h" - -static unsigned short chanOffs[8]={ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 -}; -static unsigned short opOffs[4]={ - 0x00, 0x08, 0x10, 0x18 -}; -static bool isOutput[8][4]={ - // 1 3 2 4 - {false,false,false,true}, - {false,false,false,true}, - {false,false,false,true}, - {false,false,false,true}, - {false,false,true ,true}, - {false,true ,true ,true}, - {false,true ,true ,true}, - {true ,true ,true ,true}, -}; -static unsigned char dtTable[8]={ - 7,6,5,0,1,2,3,4 -}; - -static int orderedOps[4]={ - 0,2,1,3 -}; - -#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} -#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} } - -#define NOTE_LINEAR(x) (((x)<<6)+baseFreqOff+log2(parent->song.tuning/440.0)*12.0*64.0) - const char* regCheatSheetOPM[]={ "Test", "00", "NoteCtl", "08", @@ -198,7 +166,7 @@ void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, si OPM_Write(&fm,1,w.val); regPool[w.addr&0xff]=w.val; //printf("write: %x = %.2x\n",w.addr,w.val); - writes.pop(); + writes.pop_front(); } else { OPM_Write(&fm,0,w.addr); w.addrOrVal=true; @@ -239,7 +207,7 @@ void DivPlatformArcade::acquire_ymfm(short* bufL, short* bufR, size_t start, siz 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(); + writes.pop_front(); delay=1; } } @@ -934,7 +902,7 @@ void DivPlatformArcade::poke(std::vector& wlist) { } void DivPlatformArcade::reset() { - while (!writes.empty()) writes.pop(); + while (!writes.empty()) writes.pop_front(); memset(regPool,0,256); if (useYMFM) { fm_ymfm->reset(); @@ -974,15 +942,20 @@ void DivPlatformArcade::reset() { } void DivPlatformArcade::setFlags(unsigned int flags) { - if (flags==2) { - chipClock=4000000.0; - baseFreqOff=-122; - } else if (flags==1) { - chipClock=COLOR_PAL*4.0/5.0; - baseFreqOff=12; - } else { - chipClock=COLOR_NTSC; - baseFreqOff=0; + switch (flags&0xff) { + default: + case 0: + chipClock=COLOR_NTSC; + baseFreqOff=0; + break; + case 1: + chipClock=COLOR_PAL*4.0/5.0; + baseFreqOff=12; + break; + case 2: + chipClock=4000000.0; + baseFreqOff=-122; + break; } rate=chipClock/64; for (int i=0; i<8; i++) { diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index 6f68eedad..9d0e39685 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -20,18 +20,23 @@ #ifndef _ARCADE_H #define _ARCADE_H #include "../dispatch.h" +#include "../macroInt.h" #include "../instrument.h" #include #include "../../../extern/opm/opm.h" #include "sound/ymfm/ymfm_opm.h" -#include "../macroInt.h" +#include "fmshared_OPM.h" class DivArcadeInterface: public ymfm::ymfm_interface { }; -class DivPlatformArcade: public DivDispatch { +class DivPlatformArcade: public DivDispatch, public DivPlatformOPMBase { protected: + const unsigned short chanOffs[8]={ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + struct Channel { DivInstrumentFM state; DivMacroInt std; @@ -71,17 +76,9 @@ class DivPlatformArcade: public DivDispatch { }; Channel chan[8]; DivDispatchOscBuffer* oscBuf[8]; - struct QueuedWrite { - unsigned short addr; - unsigned char val; - bool addrOrVal; - QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} - }; - std::queue writes; opm_t fm; - int delay, baseFreqOff; + int baseFreqOff; int pcmL, pcmR, pcmCycles; - unsigned char lastBusy; unsigned char amDepth, pmDepth; ymfm::ym2151* fm_ymfm; diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index a3d325ade..2f2b20c57 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -27,7 +27,7 @@ #define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} #define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(regRemap(a),v); if (dumpWrites) {addWrite(regRemap(a),v);} } -#define CHIP_DIVIDER ((sunsoft||clockSel)?16:8) +#define CHIP_DIVIDER (extMode?extDiv:((sunsoft||clockSel)?16:8)) const char* regCheatSheetAY[]={ "FreqL_A", "0", @@ -561,8 +561,6 @@ void DivPlatformAY8910::reset() { delay=0; - extMode=false; - ioPortA=false; ioPortB=false; portAVal=0; @@ -592,49 +590,61 @@ void DivPlatformAY8910::poke(std::vector& wlist) { } void DivPlatformAY8910::setFlags(unsigned int flags) { - clockSel=(flags>>7)&1; - switch (flags&15) { - case 1: - chipClock=COLOR_PAL*2.0/5.0; - break; - case 2: - chipClock=1750000; - break; - case 3: - chipClock=2000000; - break; - case 4: - chipClock=1500000; - break; - case 5: - chipClock=1000000; - break; - case 6: - chipClock=COLOR_NTSC/4.0; - break; - case 7: - chipClock=COLOR_PAL*3.0/8.0; - break; - case 8: - chipClock=COLOR_PAL*3.0/16.0; - break; - case 9: - chipClock=COLOR_PAL/4.0; - break; - case 10: - chipClock=2097152; - break; - case 11: - chipClock=COLOR_NTSC; - break; - case 12: - chipClock=3600000; - break; - default: - chipClock=COLOR_NTSC/2.0; - break; + if (extMode) { + chipClock=extClock; + rate=chipClock/extDiv; + } else { + clockSel=(flags>>7)&1; + switch (flags&15) { + default: + case 0: + chipClock=COLOR_NTSC/2.0; + break; + case 1: + chipClock=COLOR_PAL*2.0/5.0; + break; + case 2: + chipClock=1750000; + break; + case 3: + chipClock=2000000; + break; + case 4: + chipClock=1500000; + break; + case 5: + chipClock=1000000; + break; + case 6: + chipClock=COLOR_NTSC/4.0; + break; + case 7: + chipClock=COLOR_PAL*3.0/8.0; + break; + case 8: + chipClock=COLOR_PAL*3.0/16.0; + break; + case 9: + chipClock=COLOR_PAL/4.0; + break; + case 10: + chipClock=2097152; + break; + case 11: + chipClock=COLOR_NTSC; + break; + case 12: + chipClock=3600000; + break; + case 13: + chipClock=20000000/16; + break; + case 14: + chipClock=1536000; + break; + } + rate=chipClock/8; } - rate=chipClock/8; for (int i=0; i<3; i++) { oscBuf[i]->rate=rate; } diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index f93d34bdc..8ff5f39c5 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -70,6 +70,9 @@ class DivPlatformAY8910: public DivDispatch { int delay; bool extMode; + unsigned int extClock; + unsigned char extDiv; + bool stereo, sunsoft, intellivision, clockSel; bool ioPortA, ioPortB; unsigned char portAVal, portBVal; @@ -110,5 +113,10 @@ class DivPlatformAY8910: public DivDispatch { const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); + DivPlatformAY8910(bool useExtMode=false, unsigned int eclk=COLOR_NTSC, unsigned char ediv=8): + DivDispatch(), + extMode(useExtMode), + extClock(eclk), + extDiv(ediv) {} }; #endif diff --git a/src/engine/platform/fmshared_OPM.h b/src/engine/platform/fmshared_OPM.h index 0ab05344b..ed5f63dd4 100644 --- a/src/engine/platform/fmshared_OPM.h +++ b/src/engine/platform/fmshared_OPM.h @@ -17,6 +17,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#ifndef _FMSHARED_OPM_H +#define _FMSHARED_OPM_H + +#include "fmsharedbase.h" + #define ADDR_MULT_DT 0x40 #define ADDR_TL 0x60 #define ADDR_RS_AR 0x80 @@ -26,4 +31,18 @@ #define ADDR_NOTE 0x28 #define ADDR_KF 0x30 #define ADDR_FMS_AMS 0x38 -#define ADDR_LR_FB_ALG 0x20 \ No newline at end of file +#define ADDR_LR_FB_ALG 0x20 + +#define NOTE_LINEAR(x) (((x)<<6)+baseFreqOff+log2(parent->song.tuning/440.0)*12.0*64.0) + +class DivPlatformOPMBase: public DivPlatformFMBase { + protected: + const unsigned short opOffs[4]={ + 0x00, 0x08, 0x10, 0x18 + }; + + DivPlatformOPMBase(): + DivPlatformFMBase() {} +}; + +#endif diff --git a/src/engine/platform/fmshared_OPN.h b/src/engine/platform/fmshared_OPN.h index a709aa1a3..6e5426b51 100644 --- a/src/engine/platform/fmshared_OPN.h +++ b/src/engine/platform/fmshared_OPN.h @@ -20,6 +20,8 @@ #ifndef _FMSHARED_OPN_H #define _FMSHARED_OPN_H +#include "fmsharedbase.h" + #define ADDR_MULT_DT 0x30 #define ADDR_TL 0x40 #define ADDR_RS_AR 0x50 @@ -32,6 +34,9 @@ #define ADDR_FB_ALG 0xb0 #define ADDR_LRAF 0xb4 +#define CHIP_FREQBASE fmFreqBase +#define CHIP_DIVIDER fmDivBase + #define PLEASE_HELP_ME(_targetChan) \ int boundaryBottom=parent->calcBaseFreq(chipClock,CHIP_FREQBASE,0,false); \ int boundaryTop=parent->calcBaseFreq(chipClock,CHIP_FREQBASE,12,false); \ @@ -93,4 +98,22 @@ return 2; \ } -#endif \ No newline at end of file +class DivPlatformOPNBase: public DivPlatformFMBase { + protected: + const unsigned short opOffs[4]={ + 0x00, 0x04, 0x08, 0x0c + }; + + const double fmFreqBase; + const double fmDivBase; + const unsigned char ayDiv; + + DivPlatformOPNBase(double f=9440540.0, double d=72, unsigned char a=32): + DivPlatformFMBase(), + fmFreqBase(f), + fmDivBase(d), + ayDiv(a) {} + +}; + +#endif diff --git a/src/engine/platform/genesisshared.h b/src/engine/platform/fmsharedbase.h similarity index 60% rename from src/engine/platform/genesisshared.h rename to src/engine/platform/fmsharedbase.h index d58d339e6..a3b0e634f 100644 --- a/src/engine/platform/genesisshared.h +++ b/src/engine/platform/fmsharedbase.h @@ -17,30 +17,10 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -static unsigned short chanOffs[6]={ - 0x00, 0x01, 0x02, 0x100, 0x101, 0x102 -}; -static unsigned short opOffs[4]={ - 0x00, 0x04, 0x08, 0x0c -}; -static bool isOutput[8][4]={ - // 1 3 2 4 - {false,false,false,true}, - {false,false,false,true}, - {false,false,false,true}, - {false,false,false,true}, - {false,false,true ,true}, - {false,true ,true ,true}, - {false,true ,true ,true}, - {true ,true ,true ,true}, -}; -static unsigned char dtTable[8]={ - 7,6,5,0,1,2,3,4 -}; +#ifndef _FMSHARED_BASE_H +#define _FMSHARED_BASE_H -static int orderedOps[4]={ - 0,2,1,3 -}; +#include #define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} #define immWrite(a,v) if (!skipRegisterWrites) {writes.push_back(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);} } @@ -57,4 +37,41 @@ static int orderedOps[4]={ } \ } -#include "fmshared_OPN.h" +class DivPlatformFMBase { + protected: + const bool isOutput[8][4]={ + // 1 3 2 4 + {false,false,false,true}, + {false,false,false,true}, + {false,false,false,true}, + {false,false,false,true}, + {false,false,true ,true}, + {false,true ,true ,true}, + {false,true ,true ,true}, + {true ,true ,true ,true}, + }; + const unsigned char dtTable[8]={ + 7,6,5,0,1,2,3,4 + }; + + const int orderedOps[4]={ + 0,2,1,3 + }; + + struct QueuedWrite { + unsigned short addr; + unsigned char val; + bool addrOrVal; + QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} + }; + std::deque writes; + + unsigned char lastBusy; + int delay; + + DivPlatformFMBase(): + lastBusy(0), + delay(0) {} +}; + +#endif diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 6cba30ddb..a832bab4a 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -22,13 +22,10 @@ #include #include -#include "genesisshared.h" - static unsigned char konOffs[6]={ 0, 1, 2, 4, 5, 6 }; -#define CHIP_FREQBASE 9440540 const char* DivPlatformGenesis::getEffectName(unsigned char effect) { switch (effect) { @@ -1169,12 +1166,13 @@ void DivPlatformGenesis::setSoftPCM(bool value) { } void DivPlatformGenesis::setFlags(unsigned int flags) { - switch (flags) { + switch (flags&(~0x80000000)) { + default: + case 0: chipClock=COLOR_NTSC*15.0/7.0; break; case 1: chipClock=COLOR_PAL*12.0/7.0; break; case 2: chipClock=8000000.0; break; case 3: chipClock=COLOR_NTSC*12.0/7.0; break; case 4: chipClock=COLOR_NTSC*9.0/4.0; break; - default: chipClock=COLOR_NTSC*15.0/7.0; break; } ladder=flags&0x80000000; OPN2_SetChipType(ladder?ym3438_mode_ym2612:0); diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index b4862427d..71493fa5e 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -20,18 +20,22 @@ #ifndef _GENESIS_H #define _GENESIS_H #include "../dispatch.h" -#include +#include "../macroInt.h" #include "../../../extern/Nuked-OPN2/ym3438.h" #include "sound/ymfm/ymfm_opn.h" -#include "sms.h" +#include "fmshared_OPN.h" class DivYM2612Interface: public ymfm::ymfm_interface { }; -class DivPlatformGenesis: public DivDispatch { +class DivPlatformGenesis: public DivDispatch, public DivPlatformOPNBase { protected: + const unsigned short chanOffs[6]={ + 0x00, 0x01, 0x02, 0x100, 0x101, 0x102 + }; + struct Channel { DivInstrumentFM state; DivMacroInt std; @@ -98,8 +102,6 @@ class DivPlatformGenesis: public DivDispatch { }; std::deque writes; ym3438_t fm; - int delay; - unsigned char lastBusy; ymfm::ym2612* fm_ymfm; ymfm::ym2612::output_data out_ymfm; @@ -150,6 +152,9 @@ class DivPlatformGenesis: public DivDispatch { const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); + DivPlatformGenesis(): + DivDispatch(), + DivPlatformOPNBase(9440540.0, 72, 32) {} ~DivPlatformGenesis(); }; #endif diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index cc4abc88b..76837f649 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -21,10 +21,6 @@ #include "../engine.h" #include -#include "genesisshared.h" - -#define CHIP_FREQBASE 9440540 - int DivPlatformGenesisExt::dispatch(DivCommand c) { if (c.chan<2) { return DivPlatformGenesis::dispatch(c); diff --git a/src/engine/platform/msm6258.h b/src/engine/platform/msm6258.h index ea0482f37..3a05bcf82 100644 --- a/src/engine/platform/msm6258.h +++ b/src/engine/platform/msm6258.h @@ -26,10 +26,6 @@ class DivPlatformMSM6258: public DivDispatch { protected: - const unsigned short chanOffs[6]={ - 0x00, 0x01, 0x02, 0x100, 0x101, 0x102 - }; - struct Channel { unsigned char freqH, freqL; int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; @@ -77,12 +73,10 @@ class DivPlatformMSM6258: public DivDispatch { struct QueuedWrite { unsigned short addr; unsigned char val; - bool addrOrVal; - QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} + QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v) {} }; std::queue writes; okim6258_device* msm; - unsigned char regPool[512]; unsigned char lastBusy; unsigned char* adpcmMem; @@ -91,11 +85,6 @@ class DivPlatformMSM6258: public DivDispatch { int delay, updateOsc, sample, samplePos; - bool extMode; - - short oldWrites[512]; - short pendingWrites[512]; - friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index 541dded63..0d88d35dd 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -24,6 +24,7 @@ #include #define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} } +#define rWriteDelay(a,v,d) if (!skipRegisterWrites) {writes.emplace(a,v,d); if (dumpWrites) {addWrite(a,v);} } const char** DivPlatformMSM6295::getRegisterSheet() { return NULL; @@ -38,8 +39,11 @@ const char* DivPlatformMSM6295::getEffectName(unsigned char effect) { return NULL; } -u8 DivMSM6295Interface::read_byte(u32 address) { - return adpcmMem[address&0xffff]; +u8 DivPlatformMSM6295::read_byte(u32 address) { + if (adpcmMem==NULL || address>=getSampleMemCapacity(0)) { + return 0; + } + return adpcmMem[address&0x3ffff]; } void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t len) { @@ -49,7 +53,7 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t QueuedWrite& w=writes.front(); switch (w.addr) { case 0: // command - msm->command_w(w.val); + msm.command_w(w.val); break; case 8: // chip clock select (VGM) case 9: @@ -57,7 +61,7 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t case 11: break; case 12: // rate select - msm->ss_w(!w.val); + msm.ss_w(!w.val); break; case 14: // enable bankswitch break; @@ -70,21 +74,21 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t break; } writes.pop(); - delay=32; + delay=w.delay; } } else { delay--; } - msm->tick(); + msm.tick(); - bufL[h]=msm->out()<<4; + bufL[h]=msm.out()<<4; if (++updateOsc>=22) { updateOsc=0; // TODO: per-channel osc for (int i=0; i<4; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=msm->m_voice[i].m_muted?0:(msm->m_voice[i].m_out<<6); + oscBuf[i]->data[oscBuf[i]->needle++]=msm.m_voice[i].m_muted?0:(msm.m_voice[i].m_out<<6); } } } @@ -118,7 +122,7 @@ int DivPlatformMSM6295::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - rWrite(0,(8<getSample(12*sampleBank+c.value%12); chan[c.chan].sample=12*sampleBank+c.value%12; - rWrite(0,(8<(parent->song.sample.size()/12)) { sampleBank=parent->song.sample.size()/12; } - iface.sampleBank=sampleBank; break; case DIV_CMD_LEGATO: { break; @@ -212,7 +215,7 @@ int DivPlatformMSM6295::dispatch(DivCommand c) { void DivPlatformMSM6295::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - msm->m_voice[ch].m_muted=mute; + msm.m_voice[ch].m_muted=mute; } void DivPlatformMSM6295::forceIns() { @@ -249,8 +252,8 @@ void DivPlatformMSM6295::poke(std::vector& wlist) { void DivPlatformMSM6295::reset() { while (!writes.empty()) writes.pop(); - msm->reset(); - msm->ss_w(false); + msm.reset(); + msm.ss_w(rateSelInit); if (dumpWrites) { addWrite(0xffffffff,0); } @@ -264,7 +267,8 @@ void DivPlatformMSM6295::reset() { } sampleBank=0; - rateSel=false; + rateSel=rateSelInit; + rWrite(12,!rateSelInit); delay=0; } @@ -339,7 +343,9 @@ void DivPlatformMSM6295::renderSamples() { } void DivPlatformMSM6295::setFlags(unsigned int flags) { - switch (flags) { + rateSelInit=(flags>>7)&1; + switch (flags&0x7f) { + default: case 0: chipClock=4000000/4; break; @@ -379,8 +385,11 @@ void DivPlatformMSM6295::setFlags(unsigned int flags) { case 12: chipClock=1500000; break; - default: - chipClock=4000000/4; + case 13: + chipClock=3000000; + break; + case 14: + chipClock=COLOR_NTSC/3.0; break; } rate=chipClock/3; @@ -388,14 +397,16 @@ void DivPlatformMSM6295::setFlags(unsigned int flags) { isMuted[i]=false; oscBuf[i]->rate=rate/22; } + if (rateSel!=rateSelInit) { + rWrite(12,!rateSelInit); + rateSel=rateSelInit; + } } int DivPlatformMSM6295::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { parent=p; adpcmMem=new unsigned char[getSampleMemCapacity(0)]; adpcmMemLen=0; - iface.adpcmMem=adpcmMem; - iface.sampleBank=0; dumpWrites=false; skipRegisterWrites=false; updateOsc=0; @@ -403,7 +414,6 @@ int DivPlatformMSM6295::init(DivEngine* p, int channels, int sugRate, unsigned i isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } - msm=new msm6295_core(iface); setFlags(flags); reset(); return 4; @@ -413,7 +423,6 @@ void DivPlatformMSM6295::quit() { for (int i=0; i<4; i++) { delete oscBuf[i]; } - delete msm; delete[] adpcmMem; } diff --git a/src/engine/platform/msm6295.h b/src/engine/platform/msm6295.h index 2930a169b..463384f14 100644 --- a/src/engine/platform/msm6295.h +++ b/src/engine/platform/msm6295.h @@ -24,60 +24,31 @@ #include #include "sound/oki/msm6295.hpp" -class DivMSM6295Interface: public vgsound_emu_mem_intf { - public: - unsigned char* adpcmMem; - int sampleBank; - u8 read_byte(u32 address); - DivMSM6295Interface(): adpcmMem(NULL), sampleBank(0) {} -}; - -class DivPlatformMSM6295: public DivDispatch { +class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf { protected: - const unsigned short chanOffs[6]={ - 0x00, 0x01, 0x02, 0x100, 0x101, 0x102 - }; - struct Channel { - unsigned char freqH, freqL; - int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; - unsigned char psgMode, autoEnvNum, autoEnvDen; + int note, ins; signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; + bool active, insChanged, freqChanged, keyOn, keyOff, furnacePCM, hardReset; int vol, outVol; int sample; - unsigned char pan; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); - pitch2=0; } Channel(): - freqH(0), - freqL(0), - freq(0), - baseFreq(0), - pitch(0), - pitch2(0), - portaPauseFreq(0), note(0), ins(-1), - psgMode(1), - autoEnvNum(0), - autoEnvDen(0), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), - portaPause(false), - inPorta(false), furnacePCM(false), hardReset(false), vol(0), outVol(15), - sample(-1), - pan(3) {} + sample(-1) {} }; Channel chan[4]; DivDispatchOscBuffer* oscBuf[4]; @@ -85,56 +56,58 @@ class DivPlatformMSM6295: public DivDispatch { struct QueuedWrite { unsigned short addr; unsigned char val; - bool addrOrVal; - QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} + unsigned short delay; + QueuedWrite(unsigned short a, unsigned char v, unsigned short d=32): + addr(a), + val(v), + delay(d) {} }; std::queue writes; - msm6295_core* msm; - unsigned char regPool[512]; + msm6295_core msm; unsigned char lastBusy; unsigned char* adpcmMem; size_t adpcmMemLen; - DivMSM6295Interface iface; unsigned char sampleBank; int delay, updateOsc; - bool extMode; - bool rateSel; + bool rateSel=false, rateSelInit=false; - short oldWrites[512]; - short pendingWrites[512]; - 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); - DivDispatchOscBuffer* getOscBuffer(int chan); - unsigned char* getRegisterPool(); - int getRegisterPoolSize(); - void reset(); - void forceIns(); - void tick(bool sysTick=true); - void muteChannel(int ch, bool mute); - bool keyOffAffectsArp(int ch); - float getPostAmp(); - void notifyInsChange(int ins); - void notifyInsDeletion(void* ins); - void poke(unsigned int addr, unsigned short val); - void poke(std::vector& wlist); - void setFlags(unsigned int flags); - const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); - const void* getSampleMem(int index); - size_t getSampleMemCapacity(int index); - size_t getSampleMemUsage(int index); - void renderSamples(); + virtual u8 read_byte(u32 address) override; + virtual void acquire(short* bufL, short* bufR, size_t start, size_t len) override; + virtual int dispatch(DivCommand c) override; + virtual void* getChanState(int chan) override; + virtual DivDispatchOscBuffer* getOscBuffer(int chan) override; + virtual unsigned char* getRegisterPool() override; + virtual int getRegisterPoolSize() override; + virtual void reset() override; + virtual void forceIns() override; + virtual void tick(bool sysTick=true) override; + virtual void muteChannel(int ch, bool mute) override; + virtual bool keyOffAffectsArp(int ch) override; + virtual float getPostAmp() override; + virtual void notifyInsChange(int ins) override; + virtual void notifyInsDeletion(void* ins) override; + virtual void poke(unsigned int addr, unsigned short val) override; + virtual void poke(std::vector& wlist) override; + virtual void setFlags(unsigned int flags) override; + virtual const char** getRegisterSheet() override; + virtual const char* getEffectName(unsigned char effect) override; + virtual const void* getSampleMem(int index) override; + virtual size_t getSampleMemCapacity(int index) override; + virtual size_t getSampleMemUsage(int index) override; + virtual void renderSamples() override; - int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); - void quit(); + virtual int init(DivEngine* parent, int channels, int sugRate, unsigned int flags) override; + virtual void quit() override; + DivPlatformMSM6295(): + DivDispatch(), + vgsound_emu_mem_intf(), + msm(*this) {} ~DivPlatformMSM6295(); }; #endif diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index c8d728292..a40f41143 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -277,8 +277,13 @@ void DivPlatformOPL::acquire_nuked(short* bufL, short* bufR, size_t start, size_ regPool[w.addr&511]=w.val; writes.pop(); } - - OPL3_Generate(&fm,o); os[0]+=o[0]; os[1]+=o[1]; + + if (downsample) { + OPL3_GenerateResampled(&fm,o); + } else { + OPL3_Generate(&fm,o); + } + os[0]+=o[0]; os[1]+=o[1]; if (adpcmChan>=0) { adpcmB->clock(); @@ -778,7 +783,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { immWrite(11,(end>>2)&0xff); immWrite(12,(end>>10)&0xff); immWrite(7,(s->loopStart>=0)?0xb0:0xa0); // start/repeat - int freq=(65536.0*(double)s->rate)/(double)rate; + int freq=(65536.0*(double)s->rate)/(double)chipRateBase; immWrite(16,freq&0xff); immWrite(17,(freq>>8)&0xff); } @@ -1504,7 +1509,12 @@ void DivPlatformOPL::reset() { fm_ymfm->reset(); } */ - OPL3_Reset(&fm,rate); + if (downsample) { + const unsigned int downsampledRate=(unsigned int)(49716.0*(double(rate)/chipRateBase)); + OPL3_Reset(&fm,downsampledRate); + } else { + OPL3_Reset(&fm,rate); + } if (dumpWrites) { addWrite(0xffffffff,0); } @@ -1621,6 +1631,7 @@ void DivPlatformOPL::setYMFM(bool use) { void DivPlatformOPL::setOPLType(int type, bool drums) { pretendYMU=false; + downsample=false; adpcmChan=-1; switch (type) { case 1: case 2: case 8950: @@ -1650,10 +1661,13 @@ void DivPlatformOPL::setOPLType(int type, bool drums) { if (type==759) { pretendYMU=true; adpcmChan=16; + } else if (type==4) { + downsample=true; } break; } - if (type==759) { + chipType=type; + if (type==759 || type==4) { oplType=3; } else if (type==8950) { oplType=1; @@ -1688,17 +1702,73 @@ void DivPlatformOPL::setFlags(unsigned int flags) { rate=chipClock/36; }*/ - if (oplType==3) { - chipClock=COLOR_NTSC*4.0; - rate=chipClock/288; - } else { - chipClock=COLOR_NTSC; - rate=chipClock/72; - } - - if (pretendYMU) { - rate=48000; - chipClock=rate*288; + switch (chipType) { + default: + case 1: case 2: case 8950: + switch (flags&0xff) { + case 0x00: + chipClock=COLOR_NTSC; + break; + case 0x01: + chipClock=COLOR_PAL*4.0/5.0; + break; + case 0x02: + chipClock=4000000.0; + break; + case 0x03: + chipClock=3000000.0; + break; + case 0x04: + chipClock=31948800/8; + break; + case 0x05: + chipClock=3500000.0; + break; + } + rate=chipClock/72; + chipRateBase=double(rate); + break; + case 3: + switch (flags&0xff) { + case 0x00: + chipClock=COLOR_NTSC*4.0; + break; + case 0x01: + chipClock=COLOR_PAL*16.0/5.0; + break; + case 0x02: + chipClock=14000000.0; + break; + case 0x03: + chipClock=16000000.0; + break; + case 0x04: + chipClock=15000000.0; + break; + } + rate=chipClock/288; + chipRateBase=double(rate); + break; + case 4: + switch (flags&0xff) { + case 0x02: + chipClock=33868800.0; + break; + case 0x00: + chipClock=COLOR_NTSC*8.0; + break; + case 0x01: + chipClock=COLOR_PAL*32.0/5.0; + break; + } + chipRateBase=double(chipClock)/684.0; + rate=chipClock/768; + break; + case 759: + rate=48000; + chipRateBase=double(rate); + chipClock=rate*288; + break; } for (int i=0; i<18; i++) { diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index 61ea46481..9d2d17742 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -95,8 +95,8 @@ class DivPlatformOPL: public DivDispatch { const unsigned char** slots; const unsigned short* chanMap; const unsigned char* outChanMap; - double chipFreqBase; - int delay, oplType, chans, melodicChans, totalChans, adpcmChan, sampleBank; + double chipFreqBase, chipRateBase; + int delay, chipType, oplType, chans, melodicChans, totalChans, adpcmChan, sampleBank; unsigned char lastBusy; unsigned char drumState; unsigned char drumVol[5]; @@ -107,7 +107,7 @@ class DivPlatformOPL: public DivDispatch { unsigned char lfoValue; - bool useYMFM, update4OpMask, pretendYMU; + bool useYMFM, update4OpMask, pretendYMU, downsample; short oldWrites[512]; short pendingWrites[512]; diff --git a/src/engine/platform/scc.cpp b/src/engine/platform/scc.cpp index 2ab6f1aa4..1b70d956c 100644 --- a/src/engine/platform/scc.cpp +++ b/src/engine/platform/scc.cpp @@ -373,6 +373,27 @@ void DivPlatformSCC::setChipModel(bool isplus) { isPlus=isplus; } +void DivPlatformSCC::setFlags(unsigned int flags) { + switch (flags&0x7f) { + case 0x00: + chipClock=COLOR_NTSC/2.0; + break; + case 0x01: + chipClock=COLOR_PAL*2.0/5.0; + break; + case 0x02: + chipClock=3000000.0/2.0; + break; + case 0x03: + chipClock=4000000.0/2.0; + break; + } + rate=chipClock/8; + for (int i=0; i<5; i++) { + oscBuf[i]->rate=rate; + } +} + int DivPlatformSCC::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { parent=p; dumpWrites=false; @@ -382,11 +403,7 @@ int DivPlatformSCC::init(DivEngine* p, int channels, int sugRate, unsigned int f isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } - chipClock=COLOR_NTSC/2.0; - rate=chipClock/8; - for (int i=0; i<5; i++) { - oscBuf[i]->rate=rate; - } + setFlags(flags); if (isPlus) { scc=new k052539_scc_core; regBase=0xa0; diff --git a/src/engine/platform/scc.h b/src/engine/platform/scc.h index df6ef84e5..d83e02934 100644 --- a/src/engine/platform/scc.h +++ b/src/engine/platform/scc.h @@ -84,6 +84,7 @@ class DivPlatformSCC: public DivDispatch { void poke(std::vector& wlist); const char** getRegisterSheet(); const char* getEffectName(unsigned char effect); + void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void setChipModel(bool isPlus); void quit(); diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index c5cf1091a..c83108a62 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -21,15 +21,21 @@ #include "../engine.h" #include -#define rWrite(v) {if (!skipRegisterWrites) {writes.push(v); if (dumpWrites) {addWrite(0x200,v);}}} +#define rWrite(a,v) {if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(0x200+a,v);}}} const char* regCheatSheetSN[]={ "DATA", "0", NULL }; +const char* regCheatSheetGG[]={ + "DATA", "0", + "Stereo", "1", + NULL +}; + const char** DivPlatformSMS::getRegisterSheet() { - return regCheatSheetSN; + return isStereo()?regCheatSheetGG:regCheatSheetSN; } const char* DivPlatformSMS::getEffectName(unsigned char effect) { @@ -45,8 +51,8 @@ void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_ int o=0; for (size_t h=start; hwrite(w); + QueuedWrite w=writes.front(); + if (stereo && (w.addr&1)) + sn->stereo_w(w.val); + else + sn->write(w.val); writes.pop(); } + sn->sound_stream_update(snBuf,len); + if (stereo) { + for (size_t i=0; isound_stream_update(bufL+h,1); for (int i=0; i<4; i++) { if (isMuted[i]) { oscBuf[i]->data[oscBuf[i]->needle++]=0; @@ -106,23 +133,17 @@ void DivPlatformSMS::acquire(short* bufL, short* bufR, size_t start, size_t len) } } -int DivPlatformSMS::acquireOne() { - short v; - sn->sound_stream_update(&v,1); - return v; -} - void DivPlatformSMS::tick(bool sysTick) { for (int i=0; i<4; i++) { int CHIP_DIVIDER=64; - if (i==3 && isRealSN) CHIP_DIVIDER=60; + if (i==3) CHIP_DIVIDER=noiseDivider; chan[i].std.next(); if (chan[i].std.vol.had) { chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); if (chan[i].outVol<0) chan[i].outVol=0; // old formula // ((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))>>4; - rWrite(0x90|(i<<5)|(isMuted[i]?15:(15-(chan[i].outVol&15)))); + rWrite(0,0x90|(i<<5)|(isMuted[i]?15:(15-(chan[i].outVol&15)))); } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { @@ -161,6 +182,13 @@ void DivPlatformSMS::tick(bool sysTick) { } } } + if (isStereo()) { + if (chan[i].std.panL.had) { + lastPan&=~(0x11<>1)&1)<1023) chan[i].freq=1023; if (chan[i].freq<8) chan[i].freq=1; //if (chan[i].actualNote>0x5d) chan[i].freq=0x01; - rWrite(0x80|i<<5|(chan[i].freq&15)); - rWrite(chan[i].freq>>4); + rWrite(0,0x80|i<<5|(chan[i].freq&15)); + rWrite(0,chan[i].freq>>4); // what? /*if (i==2 && snNoiseMode&2) { chan[3].baseFreq=chan[2].baseFreq; @@ -188,24 +216,24 @@ void DivPlatformSMS::tick(bool sysTick) { } } if (chan[3].freqChanged || updateSNMode) { - chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,true,0,chan[3].pitch2,chipClock,isRealSN?60:64); + chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,true,0,chan[3].pitch2,chipClock,noiseDivider); if (chan[3].freq>1023) chan[3].freq=1023; if (chan[3].actualNote>0x5d) chan[3].freq=0x01; if (snNoiseMode&2) { // take period from channel 3 if (updateSNMode || resetPhase) { if (snNoiseMode&1) { - rWrite(0xe7); + rWrite(0,0xe7); } else { - rWrite(0xe3); + rWrite(0,0xe3); } if (updateSNMode) { - rWrite(0xdf); + rWrite(0,0xdf); } } if (chan[3].freqChanged) { - rWrite(0xc0|(chan[3].freq&15)); - rWrite(chan[3].freq>>4); + rWrite(0,0xc0|(chan[3].freq&15)); + rWrite(0,chan[3].freq>>4); } } else { // 3 fixed values unsigned char value; @@ -222,7 +250,7 @@ void DivPlatformSMS::tick(bool sysTick) { value=2-value; if (value!=oldValue || updateSNMode || resetPhase) { oldValue=value; - rWrite(0xe0|value|((snNoiseMode&1)<<2)); + rWrite(0,0xe0|value|((snNoiseMode&1)<<2)); } } } @@ -233,7 +261,7 @@ void DivPlatformSMS::tick(bool sysTick) { int DivPlatformSMS::dispatch(DivCommand c) { int CHIP_DIVIDER=64; - if (c.chan==3 && isRealSN) CHIP_DIVIDER=60; + if (c.chan==3) CHIP_DIVIDER=noiseDivider; switch (c.cmd) { case DIV_CMD_NOTE_ON: if (c.value!=DIV_NOTE_NULL) { @@ -243,7 +271,7 @@ int DivPlatformSMS::dispatch(DivCommand c) { chan[c.chan].actualNote=c.value; } chan[c.chan].active=true; - rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); + rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; @@ -251,7 +279,7 @@ int DivPlatformSMS::dispatch(DivCommand c) { break; case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; - rWrite(0x9f|c.chan<<5); + rWrite(0,0x9f|c.chan<<5); chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: @@ -268,7 +296,7 @@ int DivPlatformSMS::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (chan[c.chan].active) rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); + if (chan[c.chan].active) rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); } break; case DIV_CMD_GET_VOLUME: @@ -308,6 +336,18 @@ int DivPlatformSMS::dispatch(DivCommand c) { snNoiseMode=(c.value&1)|((c.value&16)>>3); updateSNMode=true; break; + case DIV_CMD_PANNING: { + if (isStereo()) { + lastPan&=~(0x11<0) pan|=0x01; + if (c.value2>0) pan|=0x10; + if (pan==0) pan=0x11; + lastPan|=pan<device_start(); - YMPSG_Init(&sn_nuked,isRealSN); + YMPSG_Init(&sn_nuked,isRealSN,12,isRealSN?13:15,isRealSN?16383:32767); snNoiseMode=3; - rWrite(0xe7); + rWrite(0,0xe7); updateSNMode=false; oldValue=0xff; + lastPan=0xff; + if (isStereo()) { + rWrite(1,0xff); + } +} + +bool DivPlatformSMS::isStereo() { + return (!nuked) && stereo; } bool DivPlatformSMS::keyOffAffectsArp(int ch) { @@ -391,45 +439,88 @@ void DivPlatformSMS::notifyInsDeletion(void* ins) { } void DivPlatformSMS::poke(unsigned int addr, unsigned short val) { - rWrite(val); + rWrite(addr,val); } void DivPlatformSMS::poke(std::vector& wlist) { - for (DivRegWrite& i: wlist) rWrite(i.val); + for (DivRegWrite& i: wlist) rWrite(i.addr,i.val); } void DivPlatformSMS::setFlags(unsigned int flags) { - if ((flags&3)==3) { - chipClock=COLOR_NTSC/2.0; - } else if ((flags&3)==2) { - chipClock=4000000; - } else if ((flags&3)==1) { - chipClock=COLOR_PAL*4.0/5.0; - } else { - chipClock=COLOR_NTSC; + switch (flags&0xff03) { + default: + case 0x0000: + chipClock=COLOR_NTSC; + break; + case 0x0001: + chipClock=COLOR_PAL*4.0/5.0; + break; + case 0x0002: + chipClock=4000000; + break; + case 0x0003: + chipClock=COLOR_NTSC/2.0; + break; + case 0x0100: + chipClock=3000000; + break; + case 0x0101: + chipClock=2000000; + break; } resetPhase=!(flags&16); - + noiseDivider=64; if (sn!=NULL) delete sn; - switch ((flags>>2)&3) { - case 1: // TI - sn=new sn76496_base_device(0x4000, 0x4000, 0x01, 0x02, true, 1, false, true); - isRealSN=true; - break; - case 2: // TI+Atari - sn=new sn76496_base_device(0x4000, 0x0f35, 0x01, 0x02, true, 1, false, true); - isRealSN=true; - break; - case 3: // Game Gear (not fully emulated yet!) - sn=new sn76496_base_device(0x8000, 0x8000, 0x01, 0x08, false, 1, false, false); - isRealSN=false; - break; + switch (flags&0xcc) { default: // Sega - sn=new sn76496_base_device(0x8000, 0x8000, 0x01, 0x08, false, 1, false, false); + case 0x00: + sn=new segapsg_device(); isRealSN=false; + stereo=false; + break; + case 0x04: // TI SN76489 + sn=new sn76489_device(); + isRealSN=true; + noiseDivider=60; + stereo=false; + break; + case 0x08: // TI+Atari + sn=new sn76496_base_device(0x4000, 0x0f35, 0x01, 0x02, true, false, 8, false, true); + isRealSN=true; + noiseDivider=60; + stereo=false; + break; + case 0x0c: // Game Gear (not fully emulated yet!) + sn=new gamegear_device(); + isRealSN=false; + stereo=true; + break; + case 0x40: // TI SN76489A + sn=new sn76489a_device(); + isRealSN=false; // TODO + noiseDivider=68; + stereo=false; + break; + case 0x44: // TI SN76496 + sn=new sn76496_device(); + isRealSN=false; // TODO + noiseDivider=68; + stereo=false; + break; + case 0x48: // NCR 8496 + sn=new ncr8496_device(); + isRealSN=false; + noiseDivider=64; + stereo=false; + break; + case 0x4c: // Tandy PSSJ 3-voice sound + sn=new pssj3_device(); + isRealSN=false; + noiseDivider=64; + stereo=false; break; } - rate=chipClock/16; + rate=nuked?chipClock/16:chipClock/2; for (int i=0; i<4; i++) { oscBuf[i]->rate=rate; } @@ -445,12 +536,15 @@ int DivPlatformSMS::init(DivEngine* p, int channels, int sugRate, unsigned int f skipRegisterWrites=false; resetPhase=false; oldValue=0xff; + lastPan=0xff; for (int i=0; i<4; i++) { isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } sn=NULL; setFlags(flags); + snBufLen=65536; + for (int i=0; i<2; i++) snBuf[i]=new short[snBufLen]; reset(); return 4; } @@ -459,6 +553,9 @@ void DivPlatformSMS::quit() { for (int i=0; i<4; i++) { delete oscBuf[i]; } + for (int i=0; i<2; i++) { + delete[] snBuf[i]; + } if (sn!=NULL) delete sn; } diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index 3c97a9a5c..56f6beda4 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -58,21 +58,31 @@ class DivPlatformSMS: public DivDispatch { Channel chan[4]; DivDispatchOscBuffer* oscBuf[4]; bool isMuted[4]; + unsigned char lastPan; + short* snBuf[2]; + size_t snBufLen; unsigned char oldValue; unsigned char snNoiseMode; + int noiseDivider=64; bool updateSNMode; bool resetPhase; bool isRealSN; + bool stereo; bool nuked; sn76496_base_device* sn; ympsg_t sn_nuked; - std::queue writes; + struct QueuedWrite { + unsigned short addr; + unsigned char val; + bool addrOrVal; + QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} + }; + std::queue writes; friend void putDispatchChan(void*,int,int); void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len); void acquire_mame(short* bufL, short* bufR, size_t start, size_t len); public: - int acquireOne(); void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); @@ -81,6 +91,7 @@ class DivPlatformSMS: public DivDispatch { void forceIns(); void tick(bool sysTick=true); void muteChannel(int ch, bool mute); + bool isStereo(); bool keyOffAffectsArp(int ch); bool keyOffAffectsPorta(int ch); int getPortaFloor(int ch); diff --git a/src/engine/platform/sound/sn76496.cpp b/src/engine/platform/sound/sn76496.cpp index 351c94d86..5062ea7a8 100644 --- a/src/engine/platform/sound/sn76496.cpp +++ b/src/engine/platform/sound/sn76496.cpp @@ -128,7 +128,7 @@ 10/12/2019: Michael Zapf * READY line handling by own emu_timer, not depending on sound_stream_update - additional modifications by tildearrow for furnace + additional modifications by tildearrow, cam900 for furnace TODO: * Implement the TMS9919 - any difference to sn94624? * Implement the T6W28; has registers in a weird order, needs writes @@ -150,18 +150,20 @@ sn76496_base_device::sn76496_base_device( int feedbackmask, - int noise_start, + int noise_start, int noisetap1, int noisetap2, bool negate, + bool stereo, int clockdivider, bool ncr, bool sega) : m_feedback_mask(feedbackmask) - , m_noise_start(noise_start) + , m_noise_start(noise_start) , m_whitenoise_tap1(noisetap1) , m_whitenoise_tap2(noisetap2) - , m_negate(negate) + , m_negate(negate) + , m_stereo(stereo) , m_clock_divider(clockdivider) , m_ncr_style_psg(ncr) , m_sega_style_psg(sega) @@ -169,10 +171,54 @@ sn76496_base_device::sn76496_base_device( } sn76496_device::sn76496_device() - : sn76496_base_device(0x8000, 0x8000, 0x01, 0x08, false, 1, false, false) + : sn76496_base_device(0x10000, 0x04, 0x08, false, false, 8, false, true) { } +y2404_device::y2404_device() + : sn76496_base_device(0x10000, 0x04, 0x08, false, false, 8, false, true) +{ +} + +sn76489_device::sn76489_device() + : sn76496_base_device(0x4000, 0x01, 0x02, true, false, 8, false, true) +{ +} + +sn76489a_device::sn76489a_device() + : sn76496_base_device(0x10000, 0x04, 0x08, false, false, 8, false, true) +{ +} + +sn76494_device::sn76494_device() + : sn76496_base_device(0x10000, 0x04, 0x08, false, false, 1, false, true) +{ +} + +sn94624_device::sn94624_device() + : sn76496_base_device(0x4000, 0x01, 0x02, true, false, 1, false, true) +{ +} + +ncr8496_device::ncr8496_device() + : sn76496_base_device(0x8000, 0x02, 0x20, true, false, 8, true, true) +{ +} + +pssj3_device::pssj3_device() + : sn76496_base_device(0x8000, 0x02, 0x20, false, false, 8, true, true) +{ +} + +gamegear_device::gamegear_device() + : sn76496_base_device(0x8000, 0x01, 0x08, true, true, 8, false, false) +{ +} + +segapsg_device::segapsg_device() + : sn76496_base_device(0x8000, 0x01, 0x08, true, false, 8, false, false) +{ +} void sn76496_base_device::device_start() { @@ -199,6 +245,7 @@ void sn76496_base_device::device_start() m_RNG = m_feedback_mask; m_output[3] = m_RNG & 1; + m_stereo_mask = 0xFF; // all channels enabled m_current_clock = m_clock_divider-1; // set gain @@ -225,6 +272,11 @@ void sn76496_base_device::device_start() m_ready_state = true; } +void sn76496_base_device::stereo_w(u8 data) +{ + if (m_stereo) m_stereo_mask = data; +} + void sn76496_base_device::write(u8 data) { int n, r, c; @@ -285,7 +337,7 @@ inline bool sn76496_base_device::in_noise_mode() return ((m_register[6] & 4)!=0); } -void sn76496_base_device::sound_stream_update(short* outputs, int outLen) +void sn76496_base_device::sound_stream_update(short** outputs, int outLen) { int i; @@ -336,13 +388,30 @@ void sn76496_base_device::sound_stream_update(short* outputs, int outLen) } } + if (m_stereo) + { + out = ((((m_stereo_mask & 0x10)!=0) && (m_output[0]!=0))? m_volume[0] : 0) + + ((((m_stereo_mask & 0x20)!=0) && (m_output[1]!=0))? m_volume[1] : 0) + + ((((m_stereo_mask & 0x40)!=0) && (m_output[2]!=0))? m_volume[2] : 0) + + ((((m_stereo_mask & 0x80)!=0) && (m_output[3]!=0))? m_volume[3] : 0); + + out2= ((((m_stereo_mask & 0x1)!=0) && (m_output[0]!=0))? m_volume[0] : 0) + + ((((m_stereo_mask & 0x2)!=0) && (m_output[1]!=0))? m_volume[1] : 0) + + ((((m_stereo_mask & 0x4)!=0) && (m_output[2]!=0))? m_volume[2] : 0) + + ((((m_stereo_mask & 0x8)!=0) && (m_output[3]!=0))? m_volume[3] : 0); + } + else + { out= ((m_output[0]!=0)? m_volume[0]:0) +((m_output[1]!=0)? m_volume[1]:0) +((m_output[2]!=0)? m_volume[2]:0) +((m_output[3]!=0)? m_volume[3]:0); + } if (m_negate) { out = -out; out2 = -out2; } - outputs[sampindex]=out; + outputs[0][sampindex]=out; + if (m_stereo) + outputs[1][sampindex]=out; } } diff --git a/src/engine/platform/sound/sn76496.h b/src/engine/platform/sound/sn76496.h index 4c24e938c..7a8a5c625 100644 --- a/src/engine/platform/sound/sn76496.h +++ b/src/engine/platform/sound/sn76496.h @@ -1,7 +1,7 @@ // license:BSD-3-Clause // copyright-holders:Nicola Salmoria -// additional modifications by tildearrow for furnace +// additional modifications by tildearrow, cam900 for furnace #ifndef MAME_SOUND_SN76496_H #define MAME_SOUND_SN76496_H @@ -14,34 +14,57 @@ class sn76496_base_device { public: void stereo_w(u8 data); void write(u8 data); - void device_start(); - void sound_stream_update(short* outputs, int outLen); - inline int32_t get_channel_output(int ch) { - return ((m_output[ch]!=0)?m_volume[ch]:0); - } + void device_start(); + void sound_stream_update(short** outputs, int outLen); + inline int32_t get_channel_output(int ch) { + return ((m_output[ch]!=0)?m_volume[ch]:0); + } //DECLARE_READ_LINE_MEMBER( ready_r ) { return m_ready_state ? 1 : 0; } sn76496_base_device( int feedbackmask, - int noise_start, + int noise_start, int noisetap1, int noisetap2, bool negate, + bool stereo, int clockdivider, bool ncr, bool sega); + sn76496_base_device( + int feedbackmask, + int noisetap1, + int noisetap2, + bool negate, + bool stereo, + int clockdivider, + bool ncr, + bool sega) + : sn76496_base_device( + feedbackmask, + feedbackmask, + noisetap1, + noisetap2, + negate, + stereo, + clockdivider, + ncr, + sega) + {} + private: inline bool in_noise_mode(); bool m_ready_state; - const int32_t m_feedback_mask; // mask for feedback - const int32_t m_noise_start; // noise start value - const int32_t m_whitenoise_tap1; // mask for white noise tap 1 (higher one, usually bit 14) - const int32_t m_whitenoise_tap2; // mask for white noise tap 2 (lower one, usually bit 13) - bool m_negate; // output negate flag - const int32_t m_clock_divider; // clock divider + const int32_t m_feedback_mask; // mask for feedback + const int32_t m_noise_start; // noise start value + const int32_t m_whitenoise_tap1; // mask for white noise tap 1 (higher one, usually bit 14) + const int32_t m_whitenoise_tap2; // mask for white noise tap 2 (lower one, usually bit 13) + bool m_negate; // output negate flag + const bool m_stereo; // whether we're dealing with stereo or not + const int32_t m_clock_divider; // clock divider const bool m_ncr_style_psg; // flag to ignore writes to regs 1,3,5,6,7 with bit 7 low const bool m_sega_style_psg; // flag to make frequency zero acts as if it is one more than max (0x3ff+1) or if it acts like 0; the initial register is pointing to 0x3 instead of 0x0; the volume reg is preloaded with 0xF instead of 0x0 @@ -51,6 +74,7 @@ private: int32_t m_volume[4]; // db volume of voice 0-2 and noise uint32_t m_RNG; // noise generator LFSR int32_t m_current_clock; + int32_t m_stereo_mask; // the stereo output mask int32_t m_period[4]; // Length of 1/2 of waveform int32_t m_count[4]; // Position within the waveform int32_t m_output[4]; // 1-bit output of each channel, pre-volume @@ -63,4 +87,67 @@ public: sn76496_device(); }; +// Y2404 not verified yet. todo: verify; (don't be fooled by the Y, it's a TI chip, not Yamaha) +class y2404_device : public sn76496_base_device +{ +public: + y2404_device(); +}; + +// SN76489 not verified yet. todo: verify; +class sn76489_device : public sn76496_base_device +{ +public: + sn76489_device(); +}; + +// SN76489A: whitenoise verified, phase verified, periodic verified (by plgdavid) +class sn76489a_device : public sn76496_base_device +{ +public: + sn76489a_device(); +}; + +// SN76494 not verified, (according to datasheet: same as sn76489a but without the /8 divider) +class sn76494_device : public sn76496_base_device +{ +public: + sn76494_device(); +}; + +// SN94624 whitenoise verified, phase verified, period verified; verified by PlgDavid +class sn94624_device : public sn76496_base_device +{ +public: + sn94624_device(); +}; + +// NCR8496 whitenoise verified, phase verified; verified by ValleyBell & NewRisingSun +class ncr8496_device : public sn76496_base_device +{ +public: + ncr8496_device(); +}; + +// PSSJ-3 whitenoise verified, phase verified; verified by ValleyBell & NewRisingSun +class pssj3_device : public sn76496_base_device +{ +public: + pssj3_device(); +}; + +// Verified by Justin Kerk +class gamegear_device : public sn76496_base_device +{ +public: + gamegear_device(); +}; + +// todo: verify; from smspower wiki, assumed to have same invert as gamegear +class segapsg_device : public sn76496_base_device +{ +public: + segapsg_device(); +}; + #endif // MAME_SOUND_SN76496_H diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 569f722b0..d530d9ee3 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -22,43 +22,11 @@ #include #include -#include "fmshared_OPM.h" - // actually 0x40 but the upper bit of data selects address #define ADDR_WS_FINE 0x100 // actually 0xc0 but bit 5 of data selects address #define ADDR_EGS_REV 0x120 -static unsigned short chanOffs[8]={ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 -}; -static unsigned short opOffs[4]={ - 0x00, 0x08, 0x10, 0x18 -}; -static bool isOutput[8][4]={ - // 1 3 2 4 - {false,false,false,true}, - {false,false,false,true}, - {false,false,false,true}, - {false,false,false,true}, - {false,false,true ,true}, - {false,true ,true ,true}, - {false,true ,true ,true}, - {true ,true ,true ,true}, -}; -static unsigned char dtTable[8]={ - 7,6,5,0,1,2,3,4 -}; - -static int orderedOps[4]={ - 0,2,1,3 -}; - -#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} -#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} } - -#define NOTE_LINEAR(x) (((x)<<6)+baseFreqOff+log2(parent->song.tuning/440.0)*12.0*64.0) - const char* regCheatSheetOPZ[]={ "Test", "00", "NoteCtl", "08", @@ -233,7 +201,7 @@ void DivPlatformTX81Z::acquire(short* bufL, short* bufR, size_t start, size_t le 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(); + writes.pop_front(); delay=1; } } @@ -1048,7 +1016,7 @@ void DivPlatformTX81Z::poke(std::vector& wlist) { } void DivPlatformTX81Z::reset() { - while (!writes.empty()) writes.pop(); + while (!writes.empty()) writes.pop_front(); memset(regPool,0,330); fm_ymfm->reset(); if (dumpWrites) { diff --git a/src/engine/platform/tx81z.h b/src/engine/platform/tx81z.h index 60ea66ae0..93f220f1c 100644 --- a/src/engine/platform/tx81z.h +++ b/src/engine/platform/tx81z.h @@ -20,17 +20,22 @@ #ifndef _TX81Z_H #define _TX81Z_H #include "../dispatch.h" +#include "../macroInt.h" #include "../instrument.h" #include #include "sound/ymfm/ymfm_opz.h" -#include "../macroInt.h" +#include "fmshared_OPM.h" class DivTXInterface: public ymfm::ymfm_interface { }; -class DivPlatformTX81Z: public DivDispatch { +class DivPlatformTX81Z: public DivDispatch, public DivPlatformOPMBase { protected: + const unsigned short chanOffs[8]={ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + struct Channel { DivInstrumentFM state; DivMacroInt std; @@ -69,16 +74,8 @@ class DivPlatformTX81Z: public DivDispatch { }; Channel chan[8]; DivDispatchOscBuffer* oscBuf[8]; - struct QueuedWrite { - unsigned short addr; - unsigned char val; - bool addrOrVal; - QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} - }; - std::queue writes; - int delay, baseFreqOff; + int baseFreqOff; int pcmL, pcmR, pcmCycles; - unsigned char lastBusy; unsigned char amDepth, pmDepth; ymfm::ym2414* fm_ymfm; diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 3303fbf87..de54d8a61 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -23,16 +23,7 @@ #include #include -#include "sound/ymfm/ymfm_opn.h" -#include "ym2203shared.h" -#include "fmshared_OPN.h" - -static unsigned char konOffs[3]={ - 0, 1, 2 -}; - -#define CHIP_DIVIDER 32 const char* regCheatSheetYM2203[]={ // SSG @@ -299,7 +290,7 @@ void DivPlatformYM2203::acquire(short* bufL, short* bufR, size_t start, size_t l fm->write(0x0,w.addr); fm->write(0x1,w.val); regPool[w.addr&0xff]=w.val; - writes.pop(); + writes.pop_front(); delay=6; } } @@ -954,7 +945,7 @@ void DivPlatformYM2203::poke(std::vector& wlist) { } void DivPlatformYM2203::reset() { - while (!writes.empty()) writes.pop(); + while (!writes.empty()) writes.pop_front(); memset(regPool,0,256); if (dumpWrites) { addWrite(0xffffffff,0); @@ -1016,21 +1007,27 @@ void DivPlatformYM2203::setSkipRegisterWrites(bool value) { } void DivPlatformYM2203::setFlags(unsigned int flags) { - unsigned char ayFlags=16; - if (flags==3) { - chipClock=3000000.0; - ayFlags=20; - } else if (flags==2) { - chipClock=4000000.0; - ayFlags=19; - } else if (flags==1) { - chipClock=COLOR_PAL*4.0/5.0; - ayFlags=17; - } else { - chipClock=COLOR_NTSC; - ayFlags=16; + switch (flags&0x3f) { + default: + case 0x00: + chipClock=COLOR_NTSC; + break; + case 0x01: + chipClock=COLOR_PAL*4.0/5.0; + break; + case 0x02: + chipClock=4000000.0; + break; + case 0x03: + chipClock=3000000.0; + break; + case 0x04: + chipClock=31948800/8; + break; + case 0x05: + chipClock=3000000.0/2.0; + break; } - ay->setFlags(ayFlags); rate=fm->sample_rate(chipClock); for (int i=0; i<6; i++) { oscBuf[i]->rate=rate; @@ -1047,14 +1044,14 @@ int DivPlatformYM2203::init(DivEngine* p, int channels, int sugRate, unsigned in } fm=new ymfm::ym2203(iface); fm->set_fidelity(ymfm::OPN_FIDELITY_MIN); - // YM2149, 2MHz - ay=new DivPlatformAY8910; - ay->init(p,3,sugRate,19); - ay->toggleRegisterDump(true); setFlags(flags); + // YM2149, 2MHz + ay=new DivPlatformAY8910(true,chipClock,ayDiv); + ay->init(p,3,sugRate,16); + ay->toggleRegisterDump(true); reset(); - return 16; + return 6; } void DivPlatformYM2203::quit() { diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index ab527eeaa..c072647c4 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -21,21 +21,25 @@ #define _YM2203_H #include "../dispatch.h" #include "../macroInt.h" -#include #include "sound/ymfm/ymfm_opn.h" #include "ay.h" +#include "fmshared_OPN.h" class DivYM2203Interface: public ymfm::ymfm_interface { }; -class DivPlatformYM2203: public DivDispatch { +class DivPlatformYM2203: public DivDispatch, public DivPlatformOPNBase { protected: const unsigned short chanOffs[3]={ 0x00, 0x01, 0x02 }; + const unsigned char konOffs[3]={ + 0, 1, 2 + }; + struct Channel { DivInstrumentFM state; unsigned char freqH, freqL; @@ -79,24 +83,14 @@ class DivPlatformYM2203: public DivDispatch { Channel chan[6]; DivDispatchOscBuffer* oscBuf[6]; bool isMuted[6]; - struct QueuedWrite { - unsigned short addr; - unsigned char val; - bool addrOrVal; - QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} - }; - std::queue writes; ymfm::ym2203* fm; ymfm::ym2203::output_data fmout; DivYM2203Interface iface; - unsigned char regPool[512]; - unsigned char lastBusy; + unsigned char regPool[256]; DivPlatformAY8910* ay; unsigned char sampleBank; - int delay; - bool extMode; short oldWrites[256]; @@ -127,6 +121,9 @@ class DivPlatformYM2203: public DivDispatch { void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); + DivPlatformYM2203(): + DivDispatch(), + DivPlatformOPNBase(4720270.0, 36, 16) {} ~DivPlatformYM2203(); }; #endif diff --git a/src/engine/platform/ym2203ext.cpp b/src/engine/platform/ym2203ext.cpp index 95937207d..350a58704 100644 --- a/src/engine/platform/ym2203ext.cpp +++ b/src/engine/platform/ym2203ext.cpp @@ -21,9 +21,6 @@ #include "../engine.h" #include -#include "ym2203shared.h" -#include "fmshared_OPN.h" - int DivPlatformYM2203Ext::dispatch(DivCommand c) { if (c.chan<2) { return DivPlatformYM2203::dispatch(c); @@ -510,7 +507,7 @@ int DivPlatformYM2203Ext::init(DivEngine* parent, int channels, int sugRate, uns } reset(); - return 19; + return 9; } void DivPlatformYM2203Ext::quit() { diff --git a/src/engine/platform/ym2203shared.h b/src/engine/platform/ym2203shared.h deleted file mode 100644 index 5aec79161..000000000 --- a/src/engine/platform/ym2203shared.h +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Furnace Tracker - multi-system chiptune tracker - * Copyright (C) 2021-2022 tildearrow and contributors - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -static unsigned short opOffs[4]={ - 0x00, 0x04, 0x08, 0x0c -}; -static bool isOutput[8][4]={ - // 1 3 2 4 - {false,false,false,true}, - {false,false,false,true}, - {false,false,false,true}, - {false,false,false,true}, - {false,false,true ,true}, - {false,true ,true ,true}, - {false,true ,true ,true}, - {true ,true ,true ,true}, -}; -static unsigned char dtTable[8]={ - 7,6,5,0,1,2,3,4 -}; - -static int orderedOps[4]={ - 0,2,1,3 -}; - -#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} -#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} } - -#define CHIP_FREQBASE 4720270 diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index b6f1e16f8..9756a44af 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -24,16 +24,7 @@ #include #include -#include "sound/ymfm/ymfm_opn.h" -#include "ym2610shared.h" -#include "fmshared_OPN.h" - -static unsigned char konOffs[6]={ - 0, 1, 2, 4, 5, 6 -}; - -#define CHIP_DIVIDER 32 const char* regCheatSheetYM2608[]={ // SSG @@ -450,7 +441,7 @@ void DivPlatformYM2608::acquire(short* bufL, short* bufR, size_t start, size_t l 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(); + writes.pop_front(); delay=4; } } @@ -1278,7 +1269,7 @@ void DivPlatformYM2608::poke(std::vector& wlist) { } void DivPlatformYM2608::reset() { - while (!writes.empty()) writes.pop(); + while (!writes.empty()) writes.pop_front(); memset(regPool,0,512); if (dumpWrites) { addWrite(0xffffffff,0); @@ -1397,6 +1388,22 @@ void DivPlatformYM2608::renderSamples() { adpcmBMemLen=memPos+256; } +void DivPlatformYM2608::setFlags(unsigned int flags) { + switch (flags&0x3f) { + default: + case 0x00: + chipClock=8000000.0; + break; + case 0x01: + chipClock=31948800/4; + break; + } + rate=fm->sample_rate(chipClock); + for (int i=0; i<16; i++) { + oscBuf[i]->rate=rate; + } +} + int DivPlatformYM2608::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { parent=p; adpcmBMem=new unsigned char[getSampleMemCapacity(0)]; @@ -1409,16 +1416,11 @@ int DivPlatformYM2608::init(DivEngine* p, int channels, int sugRate, unsigned in isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } - chipClock=8000000; fm=new ymfm::ym2608(iface); - fm->set_fidelity(ymfm::OPN_FIDELITY_MIN); - rate=fm->sample_rate(chipClock); - for (int i=0; i<16; i++) { - oscBuf[i]->rate=rate; - } + setFlags(flags); // YM2149, 2MHz - ay=new DivPlatformAY8910; - ay->init(p,3,sugRate,19); + ay=new DivPlatformAY8910(true,chipClock,32); + ay->init(p,3,sugRate,16); ay->toggleRegisterDump(true); reset(); return 16; diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index 5c6736295..ffa7a160c 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -21,10 +21,10 @@ #define _YM2608_H #include "../dispatch.h" #include "../macroInt.h" -#include #include "sound/ymfm/ymfm_opn.h" #include "ay.h" +#include "fmshared_OPN.h" class DivYM2608Interface: public ymfm::ymfm_interface { public: @@ -35,12 +35,16 @@ class DivYM2608Interface: public ymfm::ymfm_interface { DivYM2608Interface(): adpcmBMem(NULL), sampleBank(0) {} }; -class DivPlatformYM2608: public DivDispatch { +class DivPlatformYM2608: public DivDispatch, public DivPlatformOPNBase { protected: const unsigned short chanOffs[6]={ 0x00, 0x01, 0x02, 0x100, 0x101, 0x102 }; + const unsigned char konOffs[6]={ + 0, 1, 2, 4, 5, 6 + }; + struct Channel { DivInstrumentFM state; unsigned char freqH, freqL; @@ -86,17 +90,9 @@ class DivPlatformYM2608: public DivDispatch { Channel chan[16]; DivDispatchOscBuffer* oscBuf[16]; bool isMuted[16]; - struct QueuedWrite { - unsigned short addr; - unsigned char val; - bool addrOrVal; - QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} - }; - std::queue writes; ymfm::ym2608* fm; ymfm::ym2608::output_data fmout; unsigned char regPool[512]; - unsigned char lastBusy; unsigned char* adpcmBMem; size_t adpcmBMemLen; @@ -106,9 +102,9 @@ class DivPlatformYM2608: public DivDispatch { unsigned char sampleBank; unsigned char writeRSSOff, writeRSSOn; - int delay; - bool extMode; + double fmFreqBase; + unsigned char ayDiv; short oldWrites[512]; short pendingWrites[512]; @@ -141,8 +137,12 @@ class DivPlatformYM2608: public DivDispatch { size_t getSampleMemCapacity(int index); size_t getSampleMemUsage(int index); void renderSamples(); + void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); + DivPlatformYM2608(): + DivDispatch(), + DivPlatformOPNBase(9440540.0, 72, 32) {} ~DivPlatformYM2608(); }; #endif diff --git a/src/engine/platform/ym2608ext.cpp b/src/engine/platform/ym2608ext.cpp index 441640b45..38d2b4b28 100644 --- a/src/engine/platform/ym2608ext.cpp +++ b/src/engine/platform/ym2608ext.cpp @@ -21,9 +21,6 @@ #include "../engine.h" #include -#include "ym2610shared.h" -#include "fmshared_OPN.h" - int DivPlatformYM2608Ext::dispatch(DivCommand c) { if (c.chan<2) { return DivPlatformYM2608::dispatch(c); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 89ccc6c0e..d8d8e8572 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -24,19 +24,6 @@ #include #include -#include "ym2610shared.h" - -#include "fmshared_OPN.h" - -static unsigned char konOffs[4]={ - 1, 2, 5, 6 -}; - -static unsigned char bchOffs[4]={ - 1, 2, 4, 5 -}; - -#define CHIP_DIVIDER 32 const char* regCheatSheetYM2610[]={ // SSG @@ -494,7 +481,7 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l 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(); + writes.pop_front(); delay=4; } } @@ -1325,7 +1312,7 @@ void DivPlatformYM2610::poke(std::vector& wlist) { } void DivPlatformYM2610::reset() { - while (!writes.empty()) writes.pop(); + while (!writes.empty()) writes.pop_front(); memset(regPool,0,512); if (dumpWrites) { addWrite(0xffffffff,0); @@ -1397,6 +1384,22 @@ void DivPlatformYM2610::setSkipRegisterWrites(bool value) { ay->setSkipRegisterWrites(value); } +void DivPlatformYM2610::setFlags(unsigned int flags) { + switch (flags&0xff) { + default: + case 0x00: + chipClock=8000000.0; + break; + case 0x01: + chipClock=24167829/3; + break; + } + rate=chipClock/16; + for (int i=0; i<14; i++) { + oscBuf[i]->rate=rate; + } +} + int DivPlatformYM2610::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { DivPlatformYM2610Base::init(p, channels, sugRate, flags); dumpWrites=false; @@ -1405,15 +1408,11 @@ int DivPlatformYM2610::init(DivEngine* p, int channels, int sugRate, unsigned in isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } - chipClock=8000000; - rate=chipClock/16; - for (int i=0; i<14; i++) { - oscBuf[i]->rate=rate; - } fm=new ymfm::ym2610(iface); + setFlags(flags); // YM2149, 2MHz - ay=new DivPlatformAY8910; - ay->init(p,3,sugRate,19); + ay=new DivPlatformAY8910(true,chipClock,32); + ay->init(p,3,sugRate,16); ay->toggleRegisterDump(true); reset(); return 14; diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index 92f4ca077..37c0fa839 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -21,8 +21,8 @@ #define _YM2610_H #include "../dispatch.h" #include "../macroInt.h" -#include #include "ay.h" +#include "fmshared_OPN.h" #include "sound/ymfm/ymfm_opn.h" class DivYM2610Interface: public ymfm::ymfm_interface { @@ -35,7 +35,7 @@ class DivYM2610Interface: public ymfm::ymfm_interface { DivYM2610Interface(): adpcmAMem(NULL), adpcmBMem(NULL), sampleBank(0) {} }; -class DivPlatformYM2610Base: public DivDispatch { +class DivPlatformYM2610Base: public DivDispatch, public DivPlatformOPNBase { protected: unsigned char* adpcmAMem; size_t adpcmAMemLen; @@ -50,6 +50,9 @@ class DivPlatformYM2610Base: public DivDispatch { void renderSamples(); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); + DivPlatformYM2610Base(): + DivDispatch(), + DivPlatformOPNBase(9440540.0, 72, 32) {} }; class DivPlatformYM2610: public DivPlatformYM2610Base { @@ -58,6 +61,14 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { 0x01, 0x02, 0x101, 0x102 }; + const unsigned char konOffs[4]={ + 1, 2, 5, 6 + }; + + const unsigned char bchOffs[4]={ + 1, 2, 4, 5 + }; + struct Channel { DivInstrumentFM state; unsigned char freqH, freqL; @@ -103,24 +114,14 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { Channel chan[14]; DivDispatchOscBuffer* oscBuf[14]; bool isMuted[14]; - struct QueuedWrite { - unsigned short addr; - unsigned char val; - bool addrOrVal; - QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} - }; - std::queue writes; ymfm::ym2610* fm; ymfm::ym2610::output_data fmout; DivPlatformAY8910* ay; unsigned char regPool[512]; - unsigned char lastBusy; unsigned char sampleBank; - int delay; - bool extMode; short oldWrites[512]; @@ -150,6 +151,7 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { void poke(std::vector& wlist); const char** getRegisterSheet(); const char* getEffectName(unsigned char effect); + void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformYM2610(); diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 0e466f6fc..90ddeb403 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -23,16 +23,6 @@ #include #include -#include "ym2610shared.h" - -#include "fmshared_OPN.h" - -static unsigned char konOffs[6]={ - 0, 1, 2, 4, 5, 6 -}; - -#define CHIP_DIVIDER 32 - const char* regCheatSheetYM2610B[]={ // SSG "SSG_FreqL_A", "000", @@ -472,7 +462,7 @@ void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t 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(); + writes.pop_front(); delay=4; } } @@ -1303,7 +1293,7 @@ void DivPlatformYM2610B::poke(std::vector& wlist) { } void DivPlatformYM2610B::reset() { - while (!writes.empty()) writes.pop(); + while (!writes.empty()) writes.pop_front(); memset(regPool,0,512); if (dumpWrites) { addWrite(0xffffffff,0); @@ -1375,6 +1365,22 @@ void DivPlatformYM2610B::setSkipRegisterWrites(bool value) { ay->setSkipRegisterWrites(value); } +void DivPlatformYM2610B::setFlags(unsigned int flags) { + switch (flags&0xff) { + default: + case 0x00: + chipClock=8000000.0; + break; + case 0x01: + chipClock=24167829/3; + break; + } + rate=chipClock/16; + for (int i=0; i<16; i++) { + oscBuf[i]->rate=rate; + } +} + int DivPlatformYM2610B::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { DivPlatformYM2610Base::init(p, channels, sugRate, flags); dumpWrites=false; @@ -1383,15 +1389,11 @@ int DivPlatformYM2610B::init(DivEngine* p, int channels, int sugRate, unsigned i isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } - chipClock=8000000; - rate=chipClock/16; - for (int i=0; i<16; i++) { - oscBuf[i]->rate=rate; - } fm=new ymfm::ym2610b(iface); + setFlags(flags); // YM2149, 2MHz - ay=new DivPlatformAY8910; - ay->init(p,3,sugRate,19); + ay=new DivPlatformAY8910(true,chipClock,32); + ay->init(p,3,sugRate,16); ay->toggleRegisterDump(true); reset(); return 16; diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index 3a034028a..1262ba028 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -32,6 +32,10 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { 0x00, 0x01, 0x02, 0x100, 0x101, 0x102 }; + const unsigned char konOffs[6]={ + 0, 1, 2, 4, 5, 6 + }; + struct Channel { DivInstrumentFM state; unsigned char freqH, freqL; @@ -77,24 +81,16 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { Channel chan[16]; DivDispatchOscBuffer* oscBuf[16]; bool isMuted[16]; - struct QueuedWrite { - unsigned short addr; - unsigned char val; - bool addrOrVal; - QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} - }; - std::queue writes; ymfm::ym2610b* fm; ymfm::ym2610b::output_data fmout; unsigned char regPool[512]; - unsigned char lastBusy; DivPlatformAY8910* ay; unsigned char sampleBank; - int delay; - bool extMode; + double fmFreqBase=9440540; + unsigned char ayDiv=32; short oldWrites[512]; short pendingWrites[512]; @@ -123,6 +119,7 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { void poke(std::vector& wlist); const char** getRegisterSheet(); const char* getEffectName(unsigned char effect); + void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformYM2610B(); diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index cd7e494b9..b4c154faa 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -21,9 +21,6 @@ #include "../engine.h" #include -#include "ym2610shared.h" -#include "fmshared_OPN.h" - int DivPlatformYM2610BExt::dispatch(DivCommand c) { if (c.chan<2) { return DivPlatformYM2610B::dispatch(c); diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index bf6df44e7..0ac118a1a 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -21,9 +21,6 @@ #include "../engine.h" #include -#include "ym2610shared.h" -#include "fmshared_OPN.h" - int DivPlatformYM2610Ext::dispatch(DivCommand c) { if (c.chan<1) { return DivPlatformYM2610::dispatch(c); diff --git a/src/engine/platform/ym2610shared.h b/src/engine/platform/ym2610shared.h deleted file mode 100644 index 8d8847c2e..000000000 --- a/src/engine/platform/ym2610shared.h +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Furnace Tracker - multi-system chiptune tracker - * Copyright (C) 2021-2022 tildearrow and contributors - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -static unsigned short opOffs[4]={ - 0x00, 0x04, 0x08, 0x0c -}; -static bool isOutput[8][4]={ - // 1 3 2 4 - {false,false,false,true}, - {false,false,false,true}, - {false,false,false,true}, - {false,false,false,true}, - {false,false,true ,true}, - {false,true ,true ,true}, - {false,true ,true ,true}, - {true ,true ,true ,true}, -}; -static unsigned char dtTable[8]={ - 7,6,5,0,1,2,3,4 -}; - -static int orderedOps[4]={ - 0,2,1,3 -}; - -#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} -#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} } - -#define CHIP_FREQBASE 9440540 diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index 1c4997c2e..87497238e 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -431,6 +431,42 @@ void DivPlatformYMZ280B::setChipModel(int type) { chipType=type; } +void DivPlatformYMZ280B::setFlags(unsigned int flags) { + switch (chipType) { + default: + case 280: + switch (flags&0xff) { + case 0x00: + chipClock=16934400; + break; + case 0x01: + chipClock=COLOR_NTSC*4.0; + break; + case 0x02: + chipClock=COLOR_PAL*16.0/5.0; + break; + case 0x03: + chipClock=16000000; + break; + case 0x04: + chipClock=50000000.0/3.0; + break; + case 0x05: + chipClock=14000000; + break; + } + rate=chipClock/384; + break; + case 759: + rate=32000; + chipClock=rate*384; + break; + } + for (int i=0; i<8; i++) { + oscBuf[i]->rate=rate; + } +} + int DivPlatformYMZ280B::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { parent=p; dumpWrites=false; @@ -440,18 +476,12 @@ int DivPlatformYMZ280B::init(DivEngine* p, int channels, int sugRate, unsigned i isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } - setFlags(flags); - - rate=(chipType==759)?32000:44100; - chipClock=rate*384; sampleMem=new unsigned char[getSampleMemCapacity()]; sampleMemLen=0; ymz280b.device_start(sampleMem); + setFlags(flags); reset(); - for (int i=0; i<8; i++) { - oscBuf[i]->rate=rate; - } return 8; } diff --git a/src/engine/platform/ymz280b.h b/src/engine/platform/ymz280b.h index 4957d8998..97c64d21e 100644 --- a/src/engine/platform/ymz280b.h +++ b/src/engine/platform/ymz280b.h @@ -95,6 +95,7 @@ class DivPlatformYMZ280B: public DivDispatch { size_t getSampleMemCapacity(int index = 0); size_t getSampleMemUsage(int index = 0); void renderSamples(); + void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); private: diff --git a/src/engine/song.h b/src/engine/song.h index 10c00d27f..a5b68c267 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -237,28 +237,42 @@ struct DivSong { // - 1: PAL // - 2: Dendy // - SMS/SN76489: - // - bit 0-1: clock rate - // - 0: NTSC (3.58MHz) - // - 1: PAL (3.55MHz) - // - 2: Other (4MHz) - // - 3: half NTSC (1.79MHz) - // - bit 2-3: noise type - // - 0: Sega VDP (16-bit noise) - // - 1: real SN76489 (15-bit noise) - // - 2: real SN76489 with Atari-like short noise buzz (15-bit noise) - // - 3: Game Gear (16-bit noise, stereo) + // - bit 0-1, 8-15: clock rate + // - 0000: 3.58MHz (NTSC) + // - 0001: 3.55MHz (PAL) + // - 0002: 4MHz (Other) + // - 0003: 1.79MHz (half NTSC) + // - 0100: 3MHz + // - 0101: 2MHz + // - bit 2-3, 6-7: chip type + // - 00: Sega VDP (16-bit noise) + // - 04: real SN76489 (15-bit noise) + // - 08: real SN76489 with Atari-like short noise buzz (15-bit noise) + // - 0c: Game Gear (16-bit noise, stereo) + // - 40: real SN76489A (17-bit noise) + // - 44: real SN76496 (17-bit noise) + // - 48: NCR 8496 (16-bit noise) + // - 4c: Tandy PSSJ-3 (16-bit noise) // - bit 4: disable noise phase reset - // - YM2612: - // - bit 0-1: clock rate + // - YM2612/YM3438: + // - bit 0-30: clock rate // - 0: Genesis NTSC (7.67MHz) // - 1: Genesis PAL (7.61MHz) - // - 2: 8MHz + // - 2: FM Towns (8MHz) // - 3: AtGames Genesis (6.13MHz) + // - 4: Sega System 32 (8.06MHz) + // - bit 31: DAC distortion + // - 0: disable + // - 1: enable // - YM2151: - // - bit 0-1: clock rate + // - bit 0-7: clock rate // - 0: 3.58MHz (NTSC) // - 1: 3.55MHz (PAL) // - 2: 4MHz + // - YM2610(B): + // - bit 0-7: clock rate + // - 0: 8MHz (Neo Geo MVS) + // - 1: 8.06MHz (Neo Geo AES) // - AY-3-8910/AY8930: // - bit 0-3: clock rate // - 0: 1.79MHz (MSX NTSC) @@ -274,6 +288,8 @@ struct DivSong { // - 10: 2.097152MHz (Game Boy) // - 11: 3.58MHz (Darky) // - 12: 3.6MHz (Darky) + // - 13: 1.25MHz + // - 14: 1.536MHz // - bit 4-5: chip type (ignored on AY8930) // - 0: AY-3-8910 or similar // - 1: YM2149 @@ -287,9 +303,9 @@ struct DivSong { // - 1: low (internally divided to half) // - SAA1099: // - bit 0-1: clock rate - // - 0: 8MHz (SAM Coupé, Game Blaster) - // - 1: 7.15MHz - // - 2: 7.09MHz + // - 0: 8MHz (SAM Coupé) + // - 1: 7.15MHz (Game Blaster, NTSC) + // - 2: 7.09MHz (PAL) // - Amiga: // - bit 0: clock rate // - 0: 7.15MHz (NTSC) @@ -330,6 +346,80 @@ struct DivSong { // - bit 4: stereo // - 0: mono // - 1: stereo + // - YM2203: + // - bit 0-4: clock rate + // - 0: 3.58MHz (MTSC) + // - 1: 3.55MHz (PAL) + // - 2: 4MHz + // - 3: 3MHz + // - 4: 3.9936MHz (PC-88, PC-98) + // - 5: 1.5MHz + // - bit 5-6: output rate (TODO) + // - 0: FM: clock / 72, SSG: clock / 16 + // - 1: FM: clock / 36, SSG: clock / 8 + // - 2: FM: clock / 24, SSG: clock / 4 + // - YM2608: + // - bit 0-4: clock rate + // - 0: 8MHz + // - 1: 7.987MHz (PC-88, PC-98) + // - bit 5-6: output rate (TODO) + // - 0: FM: clock / 144, SSG: clock / 32 + // - 1: FM: clock / 72, SSG: clock / 16 + // - 2: FM: clock / 48, SSG: clock / 8 + // - YM3526, YM3812, Y8950: + // - bit 0-7: clock rate + // - 0: 3.58MHz (MTSC) + // - 1: 3.55MHz (PAL) + // - 2: 4MHz + // - 3: 3MHz + // - 4: 3.9936MHz (PC-88, PC-98) + // - 5: 3.5MHz + // - YMF262: + // - bit 0-7: clock rate + // - 0: 14.32MHz (MTSC) + // - 1: 14.19MHz (PAL) + // - 2: 14MHz + // - 3: 16MHz + // - 4: 15MHz + // - YMF289B: (TODO) + // - bit 0-7: clock rate + // - 0: 33.8688MHz + // - 1: 28.64MHz (MTSC) + // - 2: 28.38MHz (PAL) + // - MSM6295: + // - bit 0-6: clock rate + // - 0: 1MHz + // - 1: 1.056MHz + // - 2: 4MHz + // - 3: 4.224MHz + // - 4: 3.58MHz (NTSC) + // - 5: 1.79MHz (Half NTSC) + // - 6: 1.023MHz + // - 7: 0.895MHz (Quarter NTSC) + // - 8: 2MHz + // - 9: 2.112MHz + // - 10: 0.875MHz + // - 11: 0.9375MHz + // - 12: 1.5MHz + // - 13: 3MHz + // - 14: 1.193MHz + // - bit 7: Output rate + // - 0: clock / 132 + // - 1: clock / 165 + // - SCC/+: + // - bit 0-6: clock rate + // - 0: 1.79MHz (MSX NTSC) + // - 1: 1.77MHz (PAL) + // - 2: 1.5MHz + // - 3: 2MHz + // - YMZ280B: + // - bit 0-7: clock rate + // - 0: 16.9344MHz + // - 1: 14.32MHz (MTSC) + // - 2: 14.19MHz (PAL) + // - 3: 16MHz + // - 4: 16.67MHz + // - 5: 14MHz unsigned int systemFlags[32]; // song information diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 7d7fa050b..94dbd5b4e 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3092,7 +3092,12 @@ void FurnaceGUI::drawInsEdit() { int panMax=0; bool panSingle=false; bool panSingleNoBit=false; - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_GB || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_VERA) { + if (ins->type==DIV_INS_STD ||//Game Gear + ins->type==DIV_INS_FM || + ins->type==DIV_INS_OPL || + ins->type==DIV_INS_GB || + ins->type==DIV_INS_OPZ || + ins->type==DIV_INS_VERA) { panMax=1; panSingle=true; } diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 994902e8e..a841f15b1 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -221,18 +221,55 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "TI SN76489A", { + DIV_SYSTEM_SMS, 64, 0, 0x40, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "TI SN76496", { + DIV_SYSTEM_SMS, 64, 0, 0x44, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NCR 8496", { + DIV_SYSTEM_SMS, 64, 0, 0x48, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Tandy PSSJ 3-voice sound", { + DIV_SYSTEM_SMS, 64, 0, 0x4c, + // 8 bit DAC + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "Sega PSG (SN76489-like)", { DIV_SYSTEM_SMS, 64, 0, 0, 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Sega PSG (SN76489-like, Stereo)", { + DIV_SYSTEM_SMS, 64, 0, 0xc, + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "AY-3-8910", { DIV_SYSTEM_AY8910, 64, 0, 0, 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "AY-3-8914", { + DIV_SYSTEM_AY8910, 64, 0, 48, + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "Yamaha YM2149(F)", { DIV_SYSTEM_AY8910, 64, 0, 16, @@ -515,6 +552,12 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Sega Game Gear", { + DIV_SYSTEM_SMS, 64, 0, 0xc, + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "Game Boy", { DIV_SYSTEM_GB, 64, 0, 0, @@ -603,13 +646,13 @@ void FurnaceGUI::initSystemPresets() { )); cat.systems.push_back(FurnaceGUISysDef( "Neo Geo AES", { - DIV_SYSTEM_YM2610_FULL, 64, 0, 0, + DIV_SYSTEM_YM2610_FULL, 64, 0, 1, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "Neo Geo AES (extended channel 2)", { - DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 0, + DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 1, 0 } )); @@ -779,7 +822,7 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "MSX + Playsoniq", { DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_SMS, 64, 0, 0, + DIV_SYSTEM_SMS, 64, 0, 0, // Sega VDP DIV_SYSTEM_C64_8580, 64, 0, 0, DIV_SYSTEM_SCC_PLUS, 64, 0, 0, 0 @@ -800,26 +843,110 @@ void FurnaceGUI::initSystemPresets() { } )); cat.systems.push_back(FurnaceGUISysDef( - "NEC PC-98 (with PC-9801-26K)", { - DIV_SYSTEM_OPN, 64, 0, 3, + "NEC PC-98 (with PC-9801-26/K)", { + DIV_SYSTEM_OPN, 64, 0, 4, // 3.9936MHz but some compatible card has 4MHz 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "NEC PC-98 (with PC-9801-26K; extended channel 3)", { - DIV_SYSTEM_OPN_EXT, 64, 0, 3, + "NEC PC-98 (with PC-9801-26/K; extended channel 3)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 4, // 3.9936MHz but some compatible card has 4MHz 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "NEC PC-98 (with PC-9801-86)", { - DIV_SYSTEM_PC98, 64, 0, 3, + "NEC PC-98 (with Sound Orchestra)", { + DIV_SYSTEM_OPN, 64, 0, 4, + DIV_SYSTEM_OPL2, 64, 0, 4, 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "NEC PC-98 (with PC-9801-86; extended channel 3)", { - DIV_SYSTEM_PC98_EXT, 64, 0, 3, + "NEC PC-98 (with Sound Orchestra; extended channel 3)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 4, + DIV_SYSTEM_OPL2, 64, 0, 4, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with Sound Orchestra in drums mode)", { + DIV_SYSTEM_OPN, 64, 0, 4, + DIV_SYSTEM_OPL2_DRUMS, 64, 0, 4, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with Sound Orchestra in drums mode; extended channel 3)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 4, + DIV_SYSTEM_OPL2_DRUMS, 64, 0, 4, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with Sound Orchestra V)", { + DIV_SYSTEM_OPN, 64, 0, 4, + DIV_SYSTEM_Y8950, 64, 0, 4, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with Sound Orchestra V; extended channel 3)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 4, + DIV_SYSTEM_Y8950, 64, 0, 4, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with Sound Orchestra V in drums mode)", { + DIV_SYSTEM_OPN, 64, 0, 4, + DIV_SYSTEM_Y8950_DRUMS, 64, 0, 4, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with Sound Orchestra V in drums mode; extended channel 3)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 4, + DIV_SYSTEM_Y8950_DRUMS, 64, 0, 4, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with PC-9801-86)", { // -73 also has OPNA + DIV_SYSTEM_PC98, 64, 0, 1, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with PC-9801-86; extended channel 3)", { // -73 also has OPNA + DIV_SYSTEM_PC98_EXT, 64, 0, 1, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible)", { + DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz + DIV_SYSTEM_OPL3, 64, 0, 0, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible; extended channel 3)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz + DIV_SYSTEM_OPL3, 64, 0, 0, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible in drums mode)", { + DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz + DIV_SYSTEM_OPL3_DRUMS, 64, 0, 2, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible in drums mode; extended channel 3)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz + DIV_SYSTEM_OPL3_DRUMS, 64, 0, 2, 0 } )); @@ -839,8 +966,76 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "ZX Spectrum (128K) with TurboSound FM", { DIV_SYSTEM_AY8910, 64, 0, 1, - DIV_SYSTEM_OPN, 64, 0, 0, - DIV_SYSTEM_OPN, 64, 0, 0, + DIV_SYSTEM_OPN, 64, 0, 1, + DIV_SYSTEM_OPN, 64, 0, 1, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "ZX Spectrum (128K) with TurboSound FM (extended channel 3 on first OPN)", { + DIV_SYSTEM_AY8910, 64, 0, 1, + DIV_SYSTEM_OPN_EXT, 64, 0, 1, + DIV_SYSTEM_OPN, 64, 0, 1, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "ZX Spectrum (128K) with TurboSound FM (extended channel 3 on second OPN)", { + DIV_SYSTEM_AY8910, 64, 0, 1, + DIV_SYSTEM_OPN, 64, 0, 1, + DIV_SYSTEM_OPN_EXT, 64, 0, 1, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "ZX Spectrum (128K) with TurboSound FM (extended channel 3 on both OPNs)", { + DIV_SYSTEM_AY8910, 64, 0, 1, + DIV_SYSTEM_OPN_EXT, 64, 0, 1, + DIV_SYSTEM_OPN_EXT, 64, 0, 1, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "ZX Spectrum (128K) with TurboSound FM + SAA", { + DIV_SYSTEM_AY8910, 64, 0, 1, + DIV_SYSTEM_OPN, 64, 0, 1, + DIV_SYSTEM_OPN, 64, 0, 1, + DIV_SYSTEM_SAA1099, 64, 0, 0, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "ZX Spectrum (128K) with TurboSound FM + SAA (extended channel 3 on first OPN)", { + DIV_SYSTEM_AY8910, 64, 0, 1, + DIV_SYSTEM_OPN_EXT, 64, 0, 1, + DIV_SYSTEM_OPN, 64, 0, 1, + DIV_SYSTEM_SAA1099, 64, 0, 0, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "ZX Spectrum (128K) with TurboSound FM + SAA (extended channel 3 on second OPN)", { + DIV_SYSTEM_AY8910, 64, 0, 1, + DIV_SYSTEM_OPN, 64, 0, 1, + DIV_SYSTEM_OPN_EXT, 64, 0, 1, + DIV_SYSTEM_SAA1099, 64, 0, 0, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "ZX Spectrum (128K) with TurboSound FM + SAA (extended channel 3 on both OPNs)", { + DIV_SYSTEM_AY8910, 64, 0, 1, + DIV_SYSTEM_OPN_EXT, 64, 0, 1, + DIV_SYSTEM_OPN_EXT, 64, 0, 1, + DIV_SYSTEM_SAA1099, 64, 0, 0, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "ZX Spectrum (128K) with TurboSound", { + DIV_SYSTEM_AY8910, 64, 0, 1, + DIV_SYSTEM_AY8910, 64, 0, 1, // or YM2149 + DIV_SYSTEM_AY8910, 64, 0, 1, // or YM2149 0 } )); @@ -858,7 +1053,7 @@ void FurnaceGUI::initSystemPresets() { )); cat.systems.push_back(FurnaceGUISysDef( "BBC Micro", { - DIV_SYSTEM_SMS, 64, 0, 6, + DIV_SYSTEM_SMS, 64, 0, 0x42, // SN76489A 4MHz 0 } )); @@ -868,6 +1063,20 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "IBM PCjr", { + // it can be enable sound output at once + DIV_SYSTEM_SMS, 64, 0, 0x44, // SN76496 + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Tandy 1000", { + DIV_SYSTEM_SMS, 64, 0, 0x44, // NCR 8496 or SN76496 or Tandy PSSJ(with 8 bit DAC) + DIV_SYSTEM_PCSPKR, 64, 0, 0, + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "PC + Covox Sound Master", { DIV_SYSTEM_AY8930, 64, 0, 3, @@ -990,7 +1199,7 @@ void FurnaceGUI::initSystemPresets() { )); cat.systems.push_back(FurnaceGUISysDef( "FM Towns", { - DIV_SYSTEM_YM2612, 64, 0, 2, + DIV_SYSTEM_YM2612, 64, 0, 2, // YM3438 DIV_SYSTEM_RF5C68, 64, 0, 0, 0 } @@ -1007,32 +1216,172 @@ void FurnaceGUI::initSystemPresets() { cat=FurnaceGUISysCategory("Arcade systems","INSERT COIN"); cat.systems.push_back(FurnaceGUISysDef( "Bally Midway MCR", { - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 0, + // SSIO sound board + DIV_SYSTEM_AY8910, 64, 0, 3, // 2MHz + DIV_SYSTEM_AY8910, 64, 0, 3, // 2MHz + // additional sound boards, mostly software controlled DAC 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "Gyruss", { + "Konami Gyruss", { DIV_SYSTEM_AY8910, 64, 0, 0, DIV_SYSTEM_AY8910, 64, 0, 0, DIV_SYSTEM_AY8910, 64, 0, 0, DIV_SYSTEM_AY8910, 64, 0, 0, DIV_SYSTEM_AY8910, 64, 0, 0, + // additional discrete sound logics + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Konami Bubble System", { + DIV_SYSTEM_AY8910, 64, 0, 0, + DIV_SYSTEM_AY8910, 64, 0, 0, + DIV_SYSTEM_BUBSYS_WSG, 64, 0, 0, + // VLM5030 exists but not used for music at all + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Konami Hexion", { + DIV_SYSTEM_SCC, 64, 0, 2, // 1.5MHz (3MHz input) + DIV_SYSTEM_MSM6295, 64, 0, 1, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "Sega Kyugo", { - DIV_SYSTEM_AY8910, 64, 0, 4, - DIV_SYSTEM_AY8910, 64, 0, 4, + DIV_SYSTEM_AY8910, 64, 0, 14, + DIV_SYSTEM_AY8910, 64, 0, 14, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Sega System 1", { + DIV_SYSTEM_SMS, 64, 0, 0x42, // SN76489A 4MHz + DIV_SYSTEM_SMS, 64, 0, 0x0141, // SN76489A 2MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Sega Hang-On", { + DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz + DIV_SYSTEM_SEGAPCM, 64, 0, 0, // discrete logics, 62.5KHz output rate + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Sega Hang-On (extended channel 3)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz + DIV_SYSTEM_SEGAPCM, 64, 0, 0, // discrete logics, 62.5KHz output rate 0 } )); cat.systems.push_back(FurnaceGUISysDef( "Sega OutRun/X Board", { - DIV_SYSTEM_YM2151, 64, 0, 2, - DIV_SYSTEM_SEGAPCM, 64, 0, 0, + DIV_SYSTEM_YM2151, 64, 0, 2, // 4MHz + DIV_SYSTEM_SEGAPCM, 64, 0, 0, // ASIC, 31.25KHz output rate + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Sega System 18", { + DIV_SYSTEM_YM2612, 64, 0, 2, // discrete 8MHz YM3438 + DIV_SYSTEM_YM2612, 64, 0, 2, // ^^ + DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Sega System 18 (extended channel 3 on first OPN2C)", { + DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // discrete 8MHz YM3438 + DIV_SYSTEM_YM2612, 64, 0, 2, // ^^ + DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Sega System 18 (extended channel 3 on second OPN2C)", { + DIV_SYSTEM_YM2612, 64, 0, 2, // discrete 8MHz YM3438 + DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // ^^ + DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Sega System 18 (extended channel 3 on both OPN2Cs)", { + DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // discrete 8MHz YM3438 + DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // ^^ + DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Sega System 32", { + DIV_SYSTEM_YM2612, 64, 0, 4, // discrete 8.05MHz YM3438 + DIV_SYSTEM_YM2612, 64, 0, 4, // ^^ + DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Sega System 32 (extended channel 3 on first OPN2C)", { + DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // discrete 8.05MHz YM3438 + DIV_SYSTEM_YM2612, 64, 0, 4, // ^^ + DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Sega System 32 (extended channel 3 on second OPN2C)", { + DIV_SYSTEM_YM2612, 64, 0, 4, // discrete 8.05MHz YM3438 + DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // ^^ + DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Sega System 32 (extended channel 3 on both OPN2Cs)", { + DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // discrete 8.05MHz YM3438 + DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // ^^ + DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Capcom Exed Eyes", { + DIV_SYSTEM_AY8910, 64, 0, 4, // 1.5MHz + DIV_SYSTEM_SMS, 64, 0, 0x0104, // SN76489 3MHz + DIV_SYSTEM_SMS, 64, 0, 0x0104, // SN76489 3MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Capcom Arcade", { // 1943, Side arms, etc + DIV_SYSTEM_OPN, 64, 0, 5, // 4 or 1.5MHz; various per games + DIV_SYSTEM_OPN, 64, 0, 5, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Capcom Arcade (extended channel 3 on first OPN)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 5, + DIV_SYSTEM_OPN, 64, 0, 5, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Capcom Arcade (extended channel 3 on second OPN)", { + DIV_SYSTEM_OPN, 64, 0, 5, + DIV_SYSTEM_OPN_EXT, 64, 0, 5, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Capcom Arcade (extended channel 3 on both OPNs)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 5, + DIV_SYSTEM_OPN_EXT, 64, 0, 5, 0 } )); @@ -1043,145 +1392,433 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Capcom CPS-2 (QSound)", { + DIV_SYSTEM_QSOUND, 64, 0, 0, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Jaleco Ginga NinkyouDen", { + DIV_SYSTEM_AY8910, 64, 0, 16, // 1.79MHz + DIV_SYSTEM_Y8950, 64, 0, 0, // 3.58MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Jaleco Ginga NinkyouDen (drums mode)", { + DIV_SYSTEM_AY8910, 64, 0, 16, // 1.79MHz + DIV_SYSTEM_Y8950_DRUMS, 64, 0, 0, // 3.58MHz + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "Jaleco Mega System 1", { - DIV_SYSTEM_YM2151, 64, 0, 2, - DIV_SYSTEM_MSM6295, 64, 0, 0, - DIV_SYSTEM_MSM6295, 64, 0, 0, + DIV_SYSTEM_YM2151, 64, 0, 1, // 3.5MHz (7MHz / 2) + DIV_SYSTEM_MSM6295, 64, 0, 2, // 4MHz + DIV_SYSTEM_MSM6295, 64, 0, 2, // 4MHz 0 } )); cat.systems.push_back(FurnaceGUISysDef( "NMK 16-bit Arcade", { - DIV_SYSTEM_OPN, 64, 0, 0, - DIV_SYSTEM_MSM6295, 64, 0, 2, - DIV_SYSTEM_MSM6295, 64, 0, 2, + DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz; optional + DIV_SYSTEM_MSM6295, 64, 0, 130, // 4MHz + DIV_SYSTEM_MSM6295, 64, 0, 130, // ^^ 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "Data East Arcade", { - DIV_SYSTEM_OPN, 64, 0, 0, - DIV_SYSTEM_OPL2, 64, 0, 0, - DIV_SYSTEM_MSM6295, 64, 0, 0, + "NMK 16-bit Arcade (extended channel 3)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz; optional + DIV_SYSTEM_MSM6295, 64, 0, 130, // 4MHz + DIV_SYSTEM_MSM6295, 64, 0, 130, // ^^ + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Kaneko DJ Boy", { + DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz + DIV_SYSTEM_MSM6295, 64, -127, 12, // 1.5MHz, Left output + DIV_SYSTEM_MSM6295, 64, 127, 12, // 1.5MHz, Right output + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Kaneko DJ Boy (extended channel 3)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz + DIV_SYSTEM_MSM6295, 64, -127, 12, // 1.5MHz, Left output + DIV_SYSTEM_MSM6295, 64, 127, 12, // 1.5MHz, Right output + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Kaneko Air Buster", { + DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz + DIV_SYSTEM_MSM6295, 64, 0, 141, // 3MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Kaneko Air Buster (extended channel 3)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz + DIV_SYSTEM_MSM6295, 64, 0, 141, // 3MHz 0 } )); cat.systems.push_back(FurnaceGUISysDef( "Kaneko Toybox System", { - DIV_SYSTEM_AY8910, 64, 0, 1, - DIV_SYSTEM_AY8910, 64, 0, 1, - DIV_SYSTEM_MSM6295, 64, 0, 0, + DIV_SYSTEM_AY8910, 64, 0, 19, // YM2149 2MHz + DIV_SYSTEM_AY8910, 64, 0, 19, // ^^ + DIV_SYSTEM_MSM6295, 64, 0, 8, // 2MHz 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "Tecmo Arcade", { - DIV_SYSTEM_OPN, 64, 0, 0, - DIV_SYSTEM_OPN, 64, 0, 0, - DIV_SYSTEM_MSM6295, 64, 0, 0, + "Kaneko Jackie Chan", { + DIV_SYSTEM_YMZ280B, 64, 0, 3, // 16MHz 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "Seibu Kaihatsu Arcade", { - DIV_SYSTEM_OPL2, 64, 0, 0, - DIV_SYSTEM_MSM6295, 64, 0, 0, + "Super Kaneko Nova System", { + DIV_SYSTEM_YMZ280B, 64, 0, 4, // 16.67MHz (33.33MHz / 2) 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "Data East Arcade (Dark Seal)", { - DIV_SYSTEM_YM2151, 64, 0, 2, - DIV_SYSTEM_OPN, 64, 0, 0, - DIV_SYSTEM_MSM6295, 64, 0, 0, - DIV_SYSTEM_MSM6295, 64, 0, 8, + "Tecmo Ninja Gaiden", { // Ninja Gaiden, Raiga, etc + DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz + DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz + DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Tecmo Ninja Gaiden (extended channel 3 on first OPN)", { // Ninja Gaiden, Raiga, etc + DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz + DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz + DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Tecmo Ninja Gaiden (extended channel 3 on second OPN)", { // Ninja Gaiden, Raiga, etc + DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz + DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz + DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Tecmo Ninja Gaiden (extended channel 3 on both OPNs)", { // Ninja Gaiden, Raiga, etc + DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz + DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz + DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Tecmo System", { + DIV_SYSTEM_OPL3, 64, 0, 0, + DIV_SYSTEM_YMZ280B, 64, 0, 0, + DIV_SYSTEM_MSM6295, 64, 0, 8, // 2MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Tecmo System (drums mode)", { + DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0, + DIV_SYSTEM_YMZ280B, 64, 0, 0, + DIV_SYSTEM_MSM6295, 64, 0, 8, // 2MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Seibu Kaihatsu Raiden", { // Raiden, Seibu cup soccer, Zero team, etc + DIV_SYSTEM_OPL2, 64, 0, 0, // YM3812 3.58MHz + DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 or 1.023MHz (28.636363MHz / 28); various per games + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Seibu Kaihatsu Raiden (drums mode)", { // Raiden, Seibu cup soccer, Zero team, etc + DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, // YM3812 3.58MHz + DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 or 1.023MHz (28.636363MHz / 28); various per games + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Sunsoft Shanghai 3", { + DIV_SYSTEM_AY8910, 64, 0, 20, // YM2149 1.5MHz + DIV_SYSTEM_MSM6295, 64, 0, 1, // 1.056MHz 0 } )); cat.systems.push_back(FurnaceGUISysDef( "Sunsoft Arcade", { - DIV_SYSTEM_YM2612, 64, 0, 4, - DIV_SYSTEM_MSM6295, 64, 0, 0, + DIV_SYSTEM_YM2612, 64, 0, 2, // discrete YM3438 8MHz + DIV_SYSTEM_MSM6295, 64, 0, 1, // 1.056MHz 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "Atari Arcade (Rampart)", { - DIV_SYSTEM_OPLL, 64, 0, 0, - DIV_SYSTEM_MSM6295, 64, 0, 0, + "Sunsoft Arcade (extended channel 3)", { + DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // discrete YM3438 8MHz + DIV_SYSTEM_MSM6295, 64, 0, 1, // 1.056MHz 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "Data East Deco 156", { - DIV_SYSTEM_MSM6295, 64, 0, 0, - DIV_SYSTEM_MSM6295, 64, 0, 8, + "Atari Klax", { + DIV_SYSTEM_MSM6295, 64, 0, 7, // 0.895MHz (3.579545MHz / 4) 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "SNK Triple Z80 (Chopper)", { //or Namco? - DIV_SYSTEM_Y8950, 64, 0, 0, - DIV_SYSTEM_OPL2, 64, 0, 0, + "Atari Rampart", { + DIV_SYSTEM_OPLL, 64, 0, 0, // 3.579545MHz + DIV_SYSTEM_MSM6295, 64, 0, 14, // 1.193MHz (3.579545MHz / 3) 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "Sega System 18", { - DIV_SYSTEM_YM2612, 64, 0, 2, - DIV_SYSTEM_YM2612, 64, 0, 2, - DIV_SYSTEM_RF5C68, 64, 0, 1, + "Atari Rampart (drums mode)", { + DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, // 3.579545MHz + DIV_SYSTEM_MSM6295, 64, 0, 14, // 1.193MHz (3.579545MHz / 3) 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "Sega System 1", { - DIV_SYSTEM_SMS, 64, 0, 2, - DIV_SYSTEM_SMS, 64, 0, 3, - 0 - } - )); - cat.systems.push_back(FurnaceGUISysDef( - "Sega System 32", { - DIV_SYSTEM_YM2612, 64, 0, 4, - DIV_SYSTEM_YM2612, 64, 0, 4, - DIV_SYSTEM_RF5C68, 64, 0, 2, - 0 - } - )); - cat.systems.push_back(FurnaceGUISysDef( - "Sega Hang-On", { - DIV_SYSTEM_OPN, 64, 0, 0, - DIV_SYSTEM_SEGAPCM, 64, 0, 0, - 0 - } - )); - cat.systems.push_back(FurnaceGUISysDef( - "SNK Alpha-68K", { - DIV_SYSTEM_OPN, 64, 0, 0, - DIV_SYSTEM_OPLL, 64, 0, 0, + "Atari JSA IIIs", { + DIV_SYSTEM_YM2151, 64, 0, 0, // 3.579545MHz + DIV_SYSTEM_MSM6295, 64, -127, 14, // 1.193MHz (3.579545MHz / 3), Left output + DIV_SYSTEM_MSM6295, 64, 127, 14, // 1.193MHz (3.579545MHz / 3), Right output 0 } )); cat.systems.push_back(FurnaceGUISysDef( "Data East Karnov", { - DIV_SYSTEM_OPN, 64, 0, 0, - DIV_SYSTEM_OPL, 64, 0, 0, + DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz + DIV_SYSTEM_OPL, 64, 0, 3, // 3MHz 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "Capcom Arcade", { - DIV_SYSTEM_OPN, 64, 0, 0, - DIV_SYSTEM_OPN, 64, 0, 0, + "Data East Karnov (extended channel 3)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz + DIV_SYSTEM_OPL, 64, 0, 3, // 3MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Data East Karnov (drums mode)", { + DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz + DIV_SYSTEM_OPL_DRUMS, 64, 0, 3, // 3MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Data East Karnov (extended channel 3; drums mode)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz + DIV_SYSTEM_OPL_DRUMS, 64, 0, 3, // 3MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Data East Arcade", { // Bad dudes, Robocop, etc + DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz + DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz + DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Data East Arcade (extended channel 3)", { // Bad dudes, Robocop, etc + DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz + DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz + DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Data East Arcade (drums mode)", { // Bad dudes, Robocop, etc + DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz + DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz + DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Data East Arcade (extended channel 3; drums mode)", { // Bad dudes, Robocop, etc + DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz + DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz + DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional 0 } )); cat.systems.push_back(FurnaceGUISysDef( "Data East PCX", { - DIV_SYSTEM_OPN, 64, 0, 0, - DIV_SYSTEM_PCE, 64, 0, 2, + DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz + DIV_SYSTEM_PCE, 64, 0, 0, + // software controlled MSM5205 + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Data East PCX (extended channel 3)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz + DIV_SYSTEM_PCE, 64, 0, 0, + // software controlled MSM5205 + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Data East Dark Seal", { // Dark Seal, Crude Buster, Vapor Trail, etc + DIV_SYSTEM_YM2151, 64, 0, 0, // 3.580MHz (32.22MHz / 9) + DIV_SYSTEM_OPN, 64, 0, 2, // 4.0275MHz (32.22MHz / 8); optional + DIV_SYSTEM_MSM6295, 64, 0, 0, // 1.007MHz (32.22MHz / 32) + DIV_SYSTEM_MSM6295, 64, 0, 8, // 2.014MHz (32.22MHz / 16); optional + // HuC6280 is for control them, internal sound isn't used + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Data East Dark Seal (extended channel 3)", { // Dark Seal, Crude Buster, Vapor Trail, etc + DIV_SYSTEM_YM2151, 64, 0, 0, // 3.580MHz (32.22MHz / 9) + DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4.0275MHz (32.22MHz / 8); optional + DIV_SYSTEM_MSM6295, 64, 0, 0, // 1.007MHz (32.22MHz / 32) + DIV_SYSTEM_MSM6295, 64, 0, 8, // 2.014MHz (32.22MHz / 16); optional + // HuC6280 is for control them, internal sound isn't used + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Data East Deco 156", { + DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 or 1.007MHz (32.22MHz / 32); various per games + DIV_SYSTEM_MSM6295, 64, 0, 8, // 1 or 2 or 2.014MHz (32.22MHz / 16); various per games + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Data East MLC", { + DIV_SYSTEM_YMZ280B, 64, 0, 5, // 14MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "SNK Ikari Warriors", { + DIV_SYSTEM_OPL, 64, 0, 2, + DIV_SYSTEM_OPL, 64, 0, 2, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "SNK Ikari Warriors (drums mode on first OPL)", { + DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, + DIV_SYSTEM_OPL, 64, 0, 2, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "SNK Ikari Warriors (drums mode on second OPL)", { + DIV_SYSTEM_OPL, 64, 0, 2, + DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "SNK Ikari Warriors (drums mode on both OPLs)", { + DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, + DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "SNK Triple Z80", { + DIV_SYSTEM_Y8950, 64, 0, 2, + DIV_SYSTEM_OPL, 64, 0, 2, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "SNK Triple Z80 (drums mode on Y8950)", { + DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, + DIV_SYSTEM_OPL, 64, 0, 2, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "SNK Triple Z80 (drums mode on OPL)", { + DIV_SYSTEM_Y8950, 64, 0, 2, + DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "SNK Triple Z80 (drums mode on Y8950 and OPL)", { + DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, + DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "SNK Chopper I", { + DIV_SYSTEM_Y8950, 64, 0, 2, + DIV_SYSTEM_OPL2, 64, 0, 2, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "SNK Chopper I (drums mode on Y8950)", { + DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, + DIV_SYSTEM_OPL2, 64, 0, 2, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "SNK Chopper I (drums mode on OPL2)", { + DIV_SYSTEM_Y8950, 64, 0, 2, + DIV_SYSTEM_OPL2_DRUMS, 64, 0, 2, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "SNK Chopper I (drums mode on Y8950 and OPL2)", { + DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, + DIV_SYSTEM_OPL2_DRUMS, 64, 0, 2, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Alpha denshi Alpha-68K", { + DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz + DIV_SYSTEM_OPLL, 64, 0, 0, // 3.58MHz + // software controlled 8 bit DAC + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Alpha denshi Alpha-68K (extended channel 3)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz + DIV_SYSTEM_OPLL, 64, 0, 0, // 3.58MHz + // software controlled 8 bit DAC + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Alpha denshi Alpha-68K (drums mode)", { + DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz + DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, // 3.58MHz + // software controlled 8 bit DAC + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Alpha denshi Alpha-68K (extended channel 3; drums mode)", { + DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz + DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, // 3.58MHz + // software controlled 8 bit DAC 0 } )); @@ -1198,35 +1835,34 @@ void FurnaceGUI::initSystemPresets() { } )); cat.systems.push_back(FurnaceGUISysDef( - "Capcom Exed Eyes", { - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_SMS, 64, 0, 0, + "Nichibutsu Mag Max", { + DIV_SYSTEM_AY8910, 64, 0, 13, + DIV_SYSTEM_AY8910, 64, 0, 13, + DIV_SYSTEM_AY8910, 64, 0, 13, 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "Nichibutsu Arcade", { - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 0, - 0 - } - )); - cat.systems.push_back(FurnaceGUISysDef( - "Namco (3-channel WSG)", { + "Namco (3-channel WSG)", { // Pac-Man, Galaga, Xevious, etc DIV_SYSTEM_NAMCO, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "Namco (8-channel WSG)", { + "Namco Mappy", { // Mappy, Super Pac-Man, Libble Rabble, etc DIV_SYSTEM_NAMCO_15XX, 64, 0, 0, 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Namco Pac-Land", { // Pac-Land, Baraduke, Sky kid, etc + DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "Namco System 1", { + DIV_SYSTEM_YM2151, 64, 0, 0, DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, 0 } @@ -1243,12 +1879,6 @@ void FurnaceGUI::initSystemPresets() { 0 } )); - cat.systems.push_back(FurnaceGUISysDef( - "Capcom CPS-2 (QSound)", { - DIV_SYSTEM_QSOUND, 64, 0, 0, - 0 - } - )); cat.systems.push_back(FurnaceGUISysDef( "Seta 1", { DIV_SYSTEM_X1_010, 64, 0, 0, @@ -1275,18 +1905,37 @@ void FurnaceGUI::initSystemPresets() { } )); cat.systems.push_back(FurnaceGUISysDef( - "SNK Triple Z80", { - DIV_SYSTEM_Y8950, 64, 0, 0, - DIV_SYSTEM_OPL, 64, 0, 0, + "Coreland Cyber Tank", { + DIV_SYSTEM_Y8950, 64, -127, 0, // 3.58MHz, Left output + DIV_SYSTEM_Y8950, 64, 127, 0, // 3.58MHz, Right output 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "Konami Bubble System", { - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_BUBSYS_WSG, 64, 0, 0, - // VLM5030 exists but not used for music at all + "Coreland Cyber Tank (drums mode)", { + DIV_SYSTEM_Y8950, 64, -127, 0, // 3.58MHz, Left output + DIV_SYSTEM_Y8950, 64, 127, 0, // 3.58MHz, Right output + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "ICE Skimaxx", { + DIV_SYSTEM_MSM6295, 64, -127, 130, // 4MHz, Left output + DIV_SYSTEM_MSM6295, 64, 127, 130, // 4MHz, Right output + DIV_SYSTEM_MSM6295, 64, -127, 8, // 2MHz, Left output + DIV_SYSTEM_MSM6295, 64, 127, 8, // 2MHz, Right output + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Toaplan 1", { + DIV_SYSTEM_OPL2, 64, 0, 5, // 3.5MHz + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Toaplan 1 (drums mode)", { + DIV_SYSTEM_OPL2_DRUMS, 64, 0, 5, // 3.5MHz 0 } )); diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 91d542bd7..8878ca8f4 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -28,19 +28,19 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool case DIV_SYSTEM_YM2612_EXT: case DIV_SYSTEM_YM2612_FRAC: case DIV_SYSTEM_YM2612_FRAC_EXT: { - if (ImGui::RadioButton("NTSC (7.67MHz)",(flags&7)==0)) { + if (ImGui::RadioButton("NTSC (7.67MHz)",(flags&(~0x80000000))==0)) { copyOfFlags=(flags&0x80000000)|0; } - if (ImGui::RadioButton("PAL (7.61MHz)",(flags&7)==1)) { + if (ImGui::RadioButton("PAL (7.61MHz)",(flags&(~0x80000000))==1)) { copyOfFlags=(flags&0x80000000)|1; } - if (ImGui::RadioButton("FM Towns (8MHz)",(flags&7)==2)) { + if (ImGui::RadioButton("FM Towns (8MHz)",(flags&(~0x80000000))==2)) { copyOfFlags=(flags&0x80000000)|2; } - if (ImGui::RadioButton("AtGames Genesis (6.13MHz)",(flags&7)==3)) { + if (ImGui::RadioButton("AtGames Genesis (6.13MHz)",(flags&(~0x80000000))==3)) { copyOfFlags=(flags&0x80000000)|3; } - if (ImGui::RadioButton("Sega System 32 (8.05MHz)",(flags&7)==4)) { + if (ImGui::RadioButton("Sega System 32 (8.05MHz)",(flags&(~0x80000000))==4)) { copyOfFlags=(flags&0x80000000)|4; } bool ladder=flags&0x80000000; @@ -51,43 +51,52 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool } case DIV_SYSTEM_SMS: { ImGui::Text("Clock rate:"); - if (ImGui::RadioButton("NTSC (3.58MHz)",(flags&3)==0)) { - copyOfFlags=(flags&(~3))|0; - + if (ImGui::RadioButton("3.58MHz (NTSC)",(flags&0xff03)==0x0000)) { + copyOfFlags=(flags&(~0xff03))|0x0000; } - if (ImGui::RadioButton("PAL (3.55MHz)",(flags&3)==1)) { - copyOfFlags=(flags&(~3))|1; - + if (ImGui::RadioButton("3.55MHz (PAL)",(flags&0xff03)==0x0001)) { + copyOfFlags=(flags&(~0xff03))|0x0001; } - if (ImGui::RadioButton("BBC Micro (4MHz)",(flags&3)==2)) { - copyOfFlags=(flags&(~3))|2; - + if (ImGui::RadioButton("4MHz (BBC Micro)",(flags&0xff03)==0x0002)) { + copyOfFlags=(flags&(~0xff03))|0x0002; } - if (ImGui::RadioButton("Half NTSC (1.79MHz)",(flags&3)==3)) { - copyOfFlags=(flags&(~3))|3; - + if (ImGui::RadioButton("1.79MHz (Half NTSC)",(flags&0xff03)==0x0003)) { + copyOfFlags=(flags&(~0xff03))|0x0003; + } + if (ImGui::RadioButton("3MHz (Exed Exes)",(flags&0xff03)==0x0100)) { + copyOfFlags=(flags&(~0xff03))|0x0100; + } + if (ImGui::RadioButton("2MHz (Sega System 1)",(flags&0xff03)==0x0101)) { + copyOfFlags=(flags&(~0xff03))|0x0101; } ImGui::Text("Chip type:"); - if (ImGui::RadioButton("Sega VDP/Master System",((flags>>2)&3)==0)) { - copyOfFlags=(flags&(~12))|0; - + if (ImGui::RadioButton("Sega VDP/Master System",(flags&0xcc)==0x00)) { + copyOfFlags=(flags&(~0xcc))|0x00; } - if (ImGui::RadioButton("TI SN76489",((flags>>2)&3)==1)) { - copyOfFlags=(flags&(~12))|4; - + if (ImGui::RadioButton("TI SN76489",(flags&0xcc)==0x04)) { + copyOfFlags=(flags&(~0xcc))|0x04; } - if (ImGui::RadioButton("TI SN76489 with Atari-like short noise",((flags>>2)&3)==2)) { - copyOfFlags=(flags&(~12))|8; - + if (ImGui::RadioButton("TI SN76489 with Atari-like short noise",(flags&0xcc)==0x08)) { + copyOfFlags=(flags&(~0xcc))|0x08; + } + if (ImGui::RadioButton("Game Gear",(flags&0xcc)==0x0c)) { + copyOfFlags=(flags&(~0xcc))|0x0c; + } + if (ImGui::RadioButton("TI SN76489A",(flags&0xcc)==0x40)) { + copyOfFlags=(flags&(~0xcc))|0x40; + } + if (ImGui::RadioButton("TI SN76496",(flags&0xcc)==0x44)) { + copyOfFlags=(flags&(~0xcc))|0x44; + } + if (ImGui::RadioButton("NCR 8496",(flags&0xcc)==0x48)) { + copyOfFlags=(flags&(~0xcc))|0x48; + } + if (ImGui::RadioButton("Tandy PSSJ 3-voice sound",(flags&0xcc)==0x4c)) { + copyOfFlags=(flags&(~0xcc))|0x4c; } - /*if (ImGui::RadioButton("Game Gear",(flags>>2)==3)) { - copyOfFlags=(flags&3)|12); - }*/ - bool noPhaseReset=flags&16; if (ImGui::Checkbox("Disable noise period change phase reset",&noPhaseReset)) { copyOfFlags=(flags&(~16))|(noPhaseReset<<4); - } break; } @@ -97,37 +106,29 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool ImGui::Text("Clock rate:"); if (ImGui::RadioButton("NTSC (3.58MHz)",(flags&15)==0)) { copyOfFlags=(flags&(~15))|0; - } if (ImGui::RadioButton("PAL (3.55MHz)",(flags&15)==1)) { copyOfFlags=(flags&(~15))|1; - } if (ImGui::RadioButton("BBC Micro (4MHz)",(flags&15)==2)) { copyOfFlags=(flags&(~15))|2; - } if (ImGui::RadioButton("Half NTSC (1.79MHz)",(flags&15)==3)) { copyOfFlags=(flags&(~15))|3; - } if (type!=DIV_SYSTEM_VRC7) { ImGui::Text("Patch set:"); if (ImGui::RadioButton("Yamaha YM2413",((flags>>4)&15)==0)) { copyOfFlags=(flags&(~0xf0))|0; - } if (ImGui::RadioButton("Yamaha YMF281",((flags>>4)&15)==1)) { copyOfFlags=(flags&(~0xf0))|0x10; - } if (ImGui::RadioButton("Yamaha YM2423",((flags>>4)&15)==2)) { copyOfFlags=(flags&(~0xf0))|0x20; - } if (ImGui::RadioButton("Konami VRC7",((flags>>4)&15)==3)) { copyOfFlags=(flags&(~0xf0))|0x30; - } } break; @@ -135,15 +136,12 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool case DIV_SYSTEM_YM2151: if (ImGui::RadioButton("NTSC/X16 (3.58MHz)",flags==0)) { copyOfFlags=0; - } if (ImGui::RadioButton("PAL (3.55MHz)",flags==1)) { copyOfFlags=1; - } if (ImGui::RadioButton("X1/X68000 (4MHz)",flags==2)) { copyOfFlags=2; - } break; case DIV_SYSTEM_NES: @@ -152,30 +150,37 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool case DIV_SYSTEM_MMC5: if (ImGui::RadioButton("NTSC (1.79MHz)",flags==0)) { copyOfFlags=0; - } if (ImGui::RadioButton("PAL (1.67MHz)",flags==1)) { copyOfFlags=1; - } if (ImGui::RadioButton("Dendy (1.77MHz)",flags==2)) { copyOfFlags=2; - } break; case DIV_SYSTEM_C64_8580: case DIV_SYSTEM_C64_6581: if (ImGui::RadioButton("NTSC (1.02MHz)",flags==0)) { copyOfFlags=0; - } if (ImGui::RadioButton("PAL (0.99MHz)",flags==1)) { copyOfFlags=1; - } if (ImGui::RadioButton("SSI 2001 (0.89MHz)",flags==2)) { copyOfFlags=2; - + } + break; + case DIV_SYSTEM_YM2610: + case DIV_SYSTEM_YM2610_EXT: + case DIV_SYSTEM_YM2610_FULL: + case DIV_SYSTEM_YM2610_FULL_EXT: + case DIV_SYSTEM_YM2610B: + case DIV_SYSTEM_YM2610B_EXT: + if (ImGui::RadioButton("8MHz (Neo Geo MVS)",(flags&0xff)==0)) { + copyOfFlags=(flags&(~0xff))|0; + } + if (ImGui::RadioButton("8.06MHz (Neo Geo AES)",(flags&0xff)==1)) { + copyOfFlags=(flags&(~0xff))|1; } break; case DIV_SYSTEM_AY8910: @@ -183,87 +188,74 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool ImGui::Text("Clock rate:"); if (ImGui::RadioButton("1.79MHz (ZX Spectrum NTSC/MSX)",(flags&15)==0)) { copyOfFlags=(flags&(~15))|0; - } if (ImGui::RadioButton("1.77MHz (ZX Spectrum)",(flags&15)==1)) { copyOfFlags=(flags&(~15))|1; - } if (ImGui::RadioButton("1.75MHz (ZX Spectrum)",(flags&15)==2)) { copyOfFlags=(flags&(~15))|2; - } if (ImGui::RadioButton("2MHz (Atari ST/Sharp X1)",(flags&15)==3)) { copyOfFlags=(flags&(~15))|3; - } if (ImGui::RadioButton("1.5MHz (Vectrex)",(flags&15)==4)) { copyOfFlags=(flags&(~15))|4; - } if (ImGui::RadioButton("1MHz (Amstrad CPC)",(flags&15)==5)) { copyOfFlags=(flags&(~15))|5; - } if (ImGui::RadioButton("0.89MHz (Pre-divided Sunsoft 5B)",(flags&15)==6)) { copyOfFlags=(flags&(~15))|6; - } if (ImGui::RadioButton("1.67MHz (?)",(flags&15)==7)) { copyOfFlags=(flags&(~15))|7; - } if (ImGui::RadioButton("0.83MHz (Pre-divided Sunsoft 5B on PAL)",(flags&15)==8)) { copyOfFlags=(flags&(~15))|8; - } if (ImGui::RadioButton("1.10MHz (Gamate/VIC-20 PAL)",(flags&15)==9)) { copyOfFlags=(flags&(~15))|9; - } if (ImGui::RadioButton("2^21Hz (Game Boy)",(flags&15)==10)) { copyOfFlags=(flags&(~15))|10; - } if (ImGui::RadioButton("3.58MHz (Darky)",(flags&15)==11)) { copyOfFlags=(flags&(~15))|11; - } if (ImGui::RadioButton("3.6MHz (Darky)",(flags&15)==12)) { copyOfFlags=(flags&(~15))|12; - + } + if (ImGui::RadioButton("1.25MHz (Mag Max)",(flags&15)==13)) { + copyOfFlags=(flags&(~15))|13; + } + if (ImGui::RadioButton("1.536MHz (Kyugo)",(flags&15)==14)) { + copyOfFlags=(flags&(~15))|14; } if (type==DIV_SYSTEM_AY8910) { ImGui::Text("Chip type:"); if (ImGui::RadioButton("AY-3-8910",(flags&0x30)==0)) { copyOfFlags=(flags&(~0x30))|0; - } if (ImGui::RadioButton("YM2149(F)",(flags&0x30)==16)) { copyOfFlags=(flags&(~0x30))|16; - } if (ImGui::RadioButton("Sunsoft 5B",(flags&0x30)==32)) { copyOfFlags=(flags&(~0x30))|32; - } if (ImGui::RadioButton("AY-3-8914",(flags&0x30)==48)) { copyOfFlags=(flags&(~0x30))|48; - } } bool stereo=flags&0x40; ImGui::BeginDisabled((type==DIV_SYSTEM_AY8910) && ((flags&0x30)==32)); if (ImGui::Checkbox("Stereo##_AY_STEREO",&stereo)) { copyOfFlags=(flags&(~0x40))|(stereo?0x40:0); - } ImGui::EndDisabled(); bool clockSel=flags&0x80; ImGui::BeginDisabled((type==DIV_SYSTEM_AY8910) && ((flags&0x30)!=16)); if (ImGui::Checkbox("Half Clock divider##_AY_CLKSEL",&clockSel)) { copyOfFlags=(flags&(~0x80))|(clockSel?0x80:0); - } ImGui::EndDisabled(); break; @@ -375,86 +367,223 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool } break; } - case DIV_SYSTEM_OPN: { - if (ImGui::RadioButton("NTSC (3.58MHz)",(flags&3)==0)) { - copyOfFlags=(flags&0x80000000)|0; + case DIV_SYSTEM_OPN: + case DIV_SYSTEM_OPN_EXT: { + ImGui::Text("Clock rate:"); + if (ImGui::RadioButton("3.58MHz (NTSC)",(flags&31)==0)) { + copyOfFlags=(flags&(~31))|0; } - if (ImGui::RadioButton("PAL (3.54MHz)",(flags&3)==1)) { - copyOfFlags=(flags&0x80000000)|1; + if (ImGui::RadioButton("3.54MHz (PAL)",(flags&31)==1)) { + copyOfFlags=(flags&(~31))|1; } - if (ImGui::RadioButton("Arcade (4MHz)",(flags&3)==2)) { - copyOfFlags=(flags&0x80000000)|2; + if (ImGui::RadioButton("4MHz",(flags&31)==2)) { + copyOfFlags=(flags&(~31))|2; } - if (ImGui::RadioButton("PC-9801-26K? TODO: CONFIRM (3MHz)",(flags&3)==3)) { - copyOfFlags=(flags&0x80000000)|3; + if (ImGui::RadioButton("3MHz",(flags&31)==3)) { + copyOfFlags=(flags&(~31))|3; } + if (ImGui::RadioButton("3.9936MHz (PC-88/PC-98)",(flags&31)==4)) { + copyOfFlags=(flags&(~31))|4; + } + if (ImGui::RadioButton("1.5MHz",(flags&31)==5)) { + copyOfFlags=(flags&(~31))|5; + } + /* + ImGui::Text("Output rate: (DOES NOT WORK YET!)"); + if (ImGui::RadioButton("FM: clock / 72, SSG: clock / 16",(flags&96)==0)) { + copyOfFlags=(flags&(~96))|0; + } + if (ImGui::RadioButton("FM: clock / 36, SSG: clock / 8",(flags&96)==32)) { + copyOfFlags=(flags&(~96))|32; + } + if (ImGui::RadioButton("FM: clock / 24, SSG: clock / 4",(flags&96)==64)) { + copyOfFlags=(flags&(~96))|64; + } + */ + break; + } + case DIV_SYSTEM_PC98: + case DIV_SYSTEM_PC98_EXT: { + ImGui::Text("Clock rate:"); + if (ImGui::RadioButton("8MHz (Arcade)",(flags&31)==0)) { + copyOfFlags=(flags&(~31))|0; + } + if (ImGui::RadioButton("7.987MHz (PC-88/PC-98)",(flags&31)==1)) { + copyOfFlags=(flags&(~31))|1; + } + /* + ImGui::Text("Output rate: (DOES NOT WORK YET!)"); + if (ImGui::RadioButton("FM: clock / 144, SSG: clock / 32",(flags&96)==0)) { + copyOfFlags=(flags&(~96))|0; + } + if (ImGui::RadioButton("FM: clock / 72, SSG: clock / 16",(flags&96)==32)) { + copyOfFlags=(flags&(~96))|32; + } + if (ImGui::RadioButton("FM: clock / 48, SSG: clock / 8",(flags&96)==64)) { + copyOfFlags=(flags&(~96))|64; + } + */ break; } case DIV_SYSTEM_RF5C68: { ImGui::Text("Clock rate:"); if (ImGui::RadioButton("8MHz (FM Towns)",(flags&15)==0)) { copyOfFlags=(flags&(~15))|0; - } if (ImGui::RadioButton("10MHz (Sega System 18)",(flags&15)==1)) { copyOfFlags=(flags&(~15))|1; - } if (ImGui::RadioButton("12.5MHz (Sega CD/System 32)",(flags&15)==2)) { copyOfFlags=(flags&(~15))|2; - } ImGui::Text("Chip type:"); if (ImGui::RadioButton("RF5C68 (10-bit output)",((flags>>4)&15)==0)) { copyOfFlags=(flags&(~240))|0; - } if (ImGui::RadioButton("RF5C164 (16-bit output)",((flags>>4)&15)==1)) { copyOfFlags=(flags&(~240))|16; - } break; } case DIV_SYSTEM_MSM6295: { ImGui::Text("Clock rate:"); - if (ImGui::RadioButton("1MHz",flags==0)) { - copyOfFlags=0; + if (ImGui::RadioButton("1MHz",(flags&127)==0)) { + copyOfFlags=(flags&(~127))|0; } - if (ImGui::RadioButton("1.056MHz",flags==1)) { - copyOfFlags=1; + if (ImGui::RadioButton("1.056MHz",(flags&127)==1)) { + copyOfFlags=(flags&(~127))|1; } - if (ImGui::RadioButton("4MHz",flags==2)) { - copyOfFlags=2; + if (ImGui::RadioButton("4MHz",(flags&127)==2)) { + copyOfFlags=(flags&(~127))|2; } - if (ImGui::RadioButton("4.224MHz",flags==3)) { - copyOfFlags=3; + if (ImGui::RadioButton("4.224MHz",(flags&127)==3)) { + copyOfFlags=(flags&(~127))|3; } - if (ImGui::RadioButton("3.58MHz",flags==4)) { - copyOfFlags=4; + if (ImGui::RadioButton("3.58MHz",(flags&127)==4)) { + copyOfFlags=(flags&(~127))|4; } - if (ImGui::RadioButton("1.79MHz",flags==5)) { - copyOfFlags=5; + if (ImGui::RadioButton("1.79MHz",(flags&127)==5)) { + copyOfFlags=(flags&(~127))|5; } - if (ImGui::RadioButton("1.02MHz",flags==6)) { - copyOfFlags=6; + if (ImGui::RadioButton("1.02MHz",(flags&127)==6)) { + copyOfFlags=(flags&(~127))|6; } - if (ImGui::RadioButton("0.89MHz",flags==7)) { - copyOfFlags=7; + if (ImGui::RadioButton("0.89MHz",(flags&127)==7)) { + copyOfFlags=(flags&(~127))|7; } - if (ImGui::RadioButton("2MHz",flags==8)) { - copyOfFlags=8; + if (ImGui::RadioButton("2MHz",(flags&127)==8)) { + copyOfFlags=(flags&(~127))|8; } - if (ImGui::RadioButton("2.112MHz",flags==9)) { - copyOfFlags=9; + if (ImGui::RadioButton("2.112MHz",(flags&127)==9)) { + copyOfFlags=(flags&(~127))|9; } - if (ImGui::RadioButton("0.875MHz",flags==10)) { - copyOfFlags=10; + if (ImGui::RadioButton("0.875MHz",(flags&127)==10)) { + copyOfFlags=(flags&(~127))|10; } - if (ImGui::RadioButton("0.9375MHz",flags==11)) { - copyOfFlags=11; + if (ImGui::RadioButton("0.9375MHz",(flags&127)==11)) { + copyOfFlags=(flags&(~127))|11; } - if (ImGui::RadioButton("1.5MHz",flags==12)) { - copyOfFlags=12; + if (ImGui::RadioButton("1.5MHz",(flags&127)==12)) { + copyOfFlags=(flags&(~127))|12; + } + if (ImGui::RadioButton("3MHz",(flags&127)==13)) { + copyOfFlags=(flags&(~127))|13; + } + if (ImGui::RadioButton("1.193MHz (Atari)",(flags&127)==14)) { + copyOfFlags=(flags&(~127))|14; + } + ImGui::Text("Output rate:"); + if (ImGui::RadioButton("clock / 132",(flags&128)==0)) { + copyOfFlags=(flags&(~128))|0; + } + if (ImGui::RadioButton("clock / 165",(flags&128)==128)) { + copyOfFlags=(flags&(~128))|128; + } + break; + } + case DIV_SYSTEM_SCC: + case DIV_SYSTEM_SCC_PLUS: { + ImGui::Text("Clock rate:"); + if (ImGui::RadioButton("1.79MHz (NTSC/MSX)",(flags&127)==0)) { + copyOfFlags=(flags&(~127))|0; + } + if (ImGui::RadioButton("1.77MHz (PAL)",(flags&127)==1)) { + copyOfFlags=(flags&(~127))|1; + } + if (ImGui::RadioButton("1.5MHz (Arcade)",(flags&127)==2)) { + copyOfFlags=(flags&(~127))|2; + } + if (ImGui::RadioButton("2MHz",(flags&127)==3)) { + copyOfFlags=(flags&(~127))|3; + } + break; + } + case DIV_SYSTEM_OPL: + case DIV_SYSTEM_OPL_DRUMS: + case DIV_SYSTEM_OPL2: + case DIV_SYSTEM_OPL2_DRUMS: + case DIV_SYSTEM_Y8950: + case DIV_SYSTEM_Y8950_DRUMS: { + ImGui::Text("Clock rate:"); + if (ImGui::RadioButton("3.58MHz (NTSC)",(flags&255)==0)) { + copyOfFlags=(flags&(~255))|0; + } + if (ImGui::RadioButton("3.54MHz (PAL)",(flags&255)==1)) { + copyOfFlags=(flags&(~255))|1; + } + if (ImGui::RadioButton("4MHz",(flags&255)==2)) { + copyOfFlags=(flags&(~255))|2; + } + if (ImGui::RadioButton("3MHz",(flags&255)==3)) { + copyOfFlags=(flags&(~255))|3; + } + if (ImGui::RadioButton("3.9936MHz (PC-88/PC-98)",(flags&255)==4)) { + copyOfFlags=(flags&(~255))|4; + } + if (ImGui::RadioButton("3.5MHz",(flags&255)==5)) { + copyOfFlags=(flags&(~255))|5; + } + break; + } + case DIV_SYSTEM_OPL3: + case DIV_SYSTEM_OPL3_DRUMS: { + ImGui::Text("Clock rate:"); + if (ImGui::RadioButton("14.32MHz (MTSC)",(flags&255)==0)) { + copyOfFlags=(flags&(~255))|0; + } + if (ImGui::RadioButton("14.19MHz (PAL)",(flags&255)==1)) { + copyOfFlags=(flags&(~255))|1; + } + if (ImGui::RadioButton("14MHz",(flags&255)==2)) { + copyOfFlags=(flags&(~255))|2; + } + if (ImGui::RadioButton("16MHz",(flags&255)==3)) { + copyOfFlags=(flags&(~255))|3; + } + if (ImGui::RadioButton("15MHz",(flags&255)==4)) { + copyOfFlags=(flags&(~255))|4; + } + break; + } + case DIV_SYSTEM_YMZ280B: { + ImGui::Text("Clock rate:"); + if (ImGui::RadioButton("16.9344MHz",(flags&255)==0)) { + copyOfFlags=(flags&(~255))|0; + } + if (ImGui::RadioButton("14.32MHz (MTSC)",(flags&255)==1)) { + copyOfFlags=(flags&(~255))|1; + } + if (ImGui::RadioButton("14.19MHz (PAL)",(flags&255)==3)) { + copyOfFlags=(flags&(~255))|2; + } + if (ImGui::RadioButton("16MHz",(flags&255)==3)) { + copyOfFlags=(flags&(~255))|3; + } + if (ImGui::RadioButton("16.67MHz",(flags&255)==4)) { + copyOfFlags=(flags&(~255))|4; + } + if (ImGui::RadioButton("14MHz",(flags&255)==5)) { + copyOfFlags=(flags&(~255))|5; } break; } @@ -462,17 +591,8 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool case DIV_SYSTEM_SWAN: case DIV_SYSTEM_VERA: case DIV_SYSTEM_BUBSYS_WSG: - case DIV_SYSTEM_YM2610: - case DIV_SYSTEM_YM2610_EXT: - case DIV_SYSTEM_YM2610_FULL: - case DIV_SYSTEM_YM2610_FULL_EXT: - case DIV_SYSTEM_YM2610B: - case DIV_SYSTEM_YM2610B_EXT: case DIV_SYSTEM_YMU759: case DIV_SYSTEM_PET: - case DIV_SYSTEM_SCC: - case DIV_SYSTEM_SCC_PLUS: - case DIV_SYSTEM_YMZ280B: ImGui::Text("nothing to configure"); break; default: diff --git a/src/main.cpp b/src/main.cpp index 079058528..63cc5efbf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -152,6 +152,7 @@ TAParamResult pVersion(String) { printf("- puNES by FHorse (GPLv2)\n"); printf("- reSID by Dag Lem (GPLv2)\n"); printf("- Stella by Stella Team (GPLv2)\n"); + printf("- vgsound_emu by cam900 (BSD 3-clause)\n"); return TA_PARAM_QUIT; } From d1aeabe464daacc1cc55bc473659be18b1cd072a Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 6 Jun 2022 19:26:34 +0900 Subject: [PATCH 002/101] Fix compile --- src/engine/platform/fmshared_OPM.h | 22 +++++++++++----------- src/engine/platform/fmshared_OPN.h | 24 ++++++++++++------------ src/engine/platform/genesis.cpp | 4 ---- src/engine/platform/genesis.h | 4 ++++ 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/engine/platform/fmshared_OPM.h b/src/engine/platform/fmshared_OPM.h index ed5f63dd4..c21d1c180 100644 --- a/src/engine/platform/fmshared_OPM.h +++ b/src/engine/platform/fmshared_OPM.h @@ -22,21 +22,21 @@ #include "fmsharedbase.h" -#define ADDR_MULT_DT 0x40 -#define ADDR_TL 0x60 -#define ADDR_RS_AR 0x80 -#define ADDR_AM_DR 0xa0 -#define ADDR_DT2_D2R 0xc0 -#define ADDR_SL_RR 0xe0 -#define ADDR_NOTE 0x28 -#define ADDR_KF 0x30 -#define ADDR_FMS_AMS 0x38 -#define ADDR_LR_FB_ALG 0x20 - #define NOTE_LINEAR(x) (((x)<<6)+baseFreqOff+log2(parent->song.tuning/440.0)*12.0*64.0) class DivPlatformOPMBase: public DivPlatformFMBase { protected: + const unsigned char ADDR_MULT_DT=0x40; + const unsigned char ADDR_TL=0x60; + const unsigned char ADDR_RS_AR=0x80; + const unsigned char ADDR_AM_DR=0xa0; + const unsigned char ADDR_DT2_D2R=0xc0; + const unsigned char ADDR_SL_RR=0xe0; + const unsigned char ADDR_NOTE=0x28; + const unsigned char ADDR_KF=0x30; + const unsigned char ADDR_FMS_AMS=0x38; + const unsigned char ADDR_LR_FB_ALG=0x20; + const unsigned short opOffs[4]={ 0x00, 0x08, 0x10, 0x18 }; diff --git a/src/engine/platform/fmshared_OPN.h b/src/engine/platform/fmshared_OPN.h index 6e5426b51..ae40748b4 100644 --- a/src/engine/platform/fmshared_OPN.h +++ b/src/engine/platform/fmshared_OPN.h @@ -22,18 +22,6 @@ #include "fmsharedbase.h" -#define ADDR_MULT_DT 0x30 -#define ADDR_TL 0x40 -#define ADDR_RS_AR 0x50 -#define ADDR_AM_DR 0x60 -#define ADDR_DT2_D2R 0x70 -#define ADDR_SL_RR 0x80 -#define ADDR_SSG 0x90 -#define ADDR_FREQ 0xa0 -#define ADDR_FREQH 0xa4 -#define ADDR_FB_ALG 0xb0 -#define ADDR_LRAF 0xb4 - #define CHIP_FREQBASE fmFreqBase #define CHIP_DIVIDER fmDivBase @@ -100,6 +88,18 @@ class DivPlatformOPNBase: public DivPlatformFMBase { protected: + const unsigned char ADDR_MULT_DT=0x30; + const unsigned char ADDR_TL=0x40; + const unsigned char ADDR_RS_AR=0x50; + const unsigned char ADDR_AM_DR=0x60; + const unsigned char ADDR_DT2_D2R=0x70; + const unsigned char ADDR_SL_RR=0x80; + const unsigned char ADDR_SSG=0x90; + const unsigned char ADDR_FREQ=0xa0; + const unsigned char ADDR_FREQH=0xa4; + const unsigned char ADDR_FB_ALG=0xb0; + const unsigned char ADDR_LRAF=0xb4; + const unsigned short opOffs[4]={ 0x00, 0x04, 0x08, 0x0c }; diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 512f55f81..b9a5c6866 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -22,10 +22,6 @@ #include #include -static unsigned char konOffs[6]={ - 0, 1, 2, 4, 5, 6 -}; - #define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6]))) const char* DivPlatformGenesis::getEffectName(unsigned char effect) { diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 70b3dc8a3..e4bdfffab 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -36,6 +36,10 @@ class DivPlatformGenesis: public DivDispatch, public DivPlatformOPNBase { 0x00, 0x01, 0x02, 0x100, 0x101, 0x102 }; + const unsigned char konOffs[6]={ + 0, 1, 2, 4, 5, 6 + }; + struct Channel { DivInstrumentFM state; DivMacroInt std; From ebbd9784e689af27feea032ef1ca55d1f5c105a4 Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 6 Jun 2022 19:40:37 +0900 Subject: [PATCH 003/101] Reduce more FM codes --- src/engine/platform/arcade.h | 10 ++-------- src/engine/platform/fmsharedbase.h | 7 ++++++- src/engine/platform/genesis.h | 10 ++-------- src/engine/platform/tx81z.h | 10 ++-------- src/engine/platform/ym2203.h | 10 ++-------- src/engine/platform/ym2608.h | 10 ++-------- src/engine/platform/ym2610.h | 10 ++-------- src/engine/platform/ym2610b.h | 7 +------ 8 files changed, 19 insertions(+), 55 deletions(-) diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index 189ce1e9b..00af8f259 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -19,19 +19,18 @@ #ifndef _ARCADE_H #define _ARCADE_H -#include "../dispatch.h" +#include "fmshared_OPM.h" #include "../macroInt.h" #include "../instrument.h" #include #include "../../../extern/opm/opm.h" #include "sound/ymfm/ymfm_opm.h" -#include "fmshared_OPM.h" class DivArcadeInterface: public ymfm::ymfm_interface { }; -class DivPlatformArcade: public DivDispatch, public DivPlatformOPMBase { +class DivPlatformArcade: public DivPlatformOPMBase { protected: const unsigned short chanOffs[8]={ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 @@ -85,14 +84,9 @@ class DivPlatformArcade: public DivDispatch, public DivPlatformOPMBase { ymfm::ym2151::output_data out_ymfm; DivArcadeInterface iface; - unsigned char regPool[256]; - bool extMode, useYMFM; bool isMuted[8]; - - short oldWrites[256]; - short pendingWrites[256]; int octave(int freq); int toFreq(int freq); diff --git a/src/engine/platform/fmsharedbase.h b/src/engine/platform/fmsharedbase.h index a3b0e634f..355b05c23 100644 --- a/src/engine/platform/fmsharedbase.h +++ b/src/engine/platform/fmsharedbase.h @@ -20,6 +20,7 @@ #ifndef _FMSHARED_BASE_H #define _FMSHARED_BASE_H +#include "../dispatch.h" #include #define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} @@ -37,7 +38,7 @@ } \ } -class DivPlatformFMBase { +class DivPlatformFMBase: public DivDispatch { protected: const bool isOutput[8][4]={ // 1 3 2 4 @@ -69,6 +70,10 @@ class DivPlatformFMBase { unsigned char lastBusy; int delay; + unsigned char regPool[512]; + short oldWrites[512]; + short pendingWrites[512]; + DivPlatformFMBase(): lastBusy(0), delay(0) {} diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index e4bdfffab..ace427f6e 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -19,18 +19,17 @@ #ifndef _GENESIS_H #define _GENESIS_H -#include "../dispatch.h" +#include "fmshared_OPN.h" #include "../macroInt.h" #include "../../../extern/Nuked-OPN2/ym3438.h" #include "sound/ymfm/ymfm_opn.h" -#include "fmshared_OPN.h" class DivYM2612Interface: public ymfm::ymfm_interface { }; -class DivPlatformGenesis: public DivDispatch, public DivPlatformOPNBase { +class DivPlatformGenesis: public DivPlatformOPNBase { protected: const unsigned short chanOffs[6]={ 0x00, 0x01, 0x02, 0x100, 0x101, 0x102 @@ -112,7 +111,6 @@ class DivPlatformGenesis: public DivDispatch, public DivPlatformOPNBase { ymfm::ym2612* fm_ymfm; ymfm::ym2612::output_data out_ymfm; DivYM2612Interface iface; - unsigned char regPool[512]; unsigned char lfoValue; @@ -121,9 +119,6 @@ class DivPlatformGenesis: public DivDispatch, public DivPlatformOPNBase { bool extMode, softPCM, useYMFM; bool ladder; - short oldWrites[512]; - short pendingWrites[512]; - unsigned char dacVolTable[128]; friend void putDispatchChan(void*,int,int); @@ -160,7 +155,6 @@ class DivPlatformGenesis: public DivDispatch, public DivPlatformOPNBase { int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); DivPlatformGenesis(): - DivDispatch(), DivPlatformOPNBase(9440540.0, 72, 32) {} ~DivPlatformGenesis(); }; diff --git a/src/engine/platform/tx81z.h b/src/engine/platform/tx81z.h index b185de5f6..16167ede4 100644 --- a/src/engine/platform/tx81z.h +++ b/src/engine/platform/tx81z.h @@ -19,18 +19,17 @@ #ifndef _TX81Z_H #define _TX81Z_H -#include "../dispatch.h" +#include "fmshared_OPM.h" #include "../macroInt.h" #include "../instrument.h" #include #include "sound/ymfm/ymfm_opz.h" -#include "fmshared_OPM.h" class DivTXInterface: public ymfm::ymfm_interface { }; -class DivPlatformTX81Z: public DivDispatch, public DivPlatformOPMBase { +class DivPlatformTX81Z: public DivPlatformOPMBase { protected: const unsigned short chanOffs[8]={ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 @@ -82,15 +81,10 @@ class DivPlatformTX81Z: public DivDispatch, public DivPlatformOPMBase { ymfm::ym2414::output_data out_ymfm; DivTXInterface iface; - unsigned char regPool[330]; - bool extMode; bool isMuted[8]; - short oldWrites[330]; - short pendingWrites[330]; - int octave(int freq); int toFreq(int freq); diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index 70be354d6..c650583df 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -19,18 +19,17 @@ #ifndef _YM2203_H #define _YM2203_H -#include "../dispatch.h" +#include "fmshared_OPN.h" #include "../macroInt.h" #include "sound/ymfm/ymfm_opn.h" #include "ay.h" -#include "fmshared_OPN.h" class DivYM2203Interface: public ymfm::ymfm_interface { }; -class DivPlatformYM2203: public DivDispatch, public DivPlatformOPNBase { +class DivPlatformYM2203: public DivPlatformOPNBase { protected: const unsigned short chanOffs[3]={ 0x00, 0x01, 0x02 @@ -86,16 +85,12 @@ class DivPlatformYM2203: public DivDispatch, public DivPlatformOPNBase { ymfm::ym2203* fm; ymfm::ym2203::output_data fmout; DivYM2203Interface iface; - unsigned char regPool[256]; DivPlatformAY8910* ay; unsigned char sampleBank; bool extMode; - short oldWrites[256]; - short pendingWrites[256]; - friend void putDispatchChan(void*,int,int); public: @@ -123,7 +118,6 @@ class DivPlatformYM2203: public DivDispatch, public DivPlatformOPNBase { int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); DivPlatformYM2203(): - DivDispatch(), DivPlatformOPNBase(4720270.0, 36, 16) {} ~DivPlatformYM2203(); }; diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index a6d4399a4..21eb487fd 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -19,12 +19,11 @@ #ifndef _YM2608_H #define _YM2608_H -#include "../dispatch.h" +#include "fmshared_OPN.h" #include "../macroInt.h" #include "sound/ymfm/ymfm_opn.h" #include "ay.h" -#include "fmshared_OPN.h" class DivYM2608Interface: public ymfm::ymfm_interface { public: @@ -35,7 +34,7 @@ class DivYM2608Interface: public ymfm::ymfm_interface { DivYM2608Interface(): adpcmBMem(NULL), sampleBank(0) {} }; -class DivPlatformYM2608: public DivDispatch, public DivPlatformOPNBase { +class DivPlatformYM2608: public DivPlatformOPNBase { protected: const unsigned short chanOffs[6]={ 0x00, 0x01, 0x02, 0x100, 0x101, 0x102 @@ -92,7 +91,6 @@ class DivPlatformYM2608: public DivDispatch, public DivPlatformOPNBase { bool isMuted[16]; ymfm::ym2608* fm; ymfm::ym2608::output_data fmout; - unsigned char regPool[512]; unsigned char* adpcmBMem; size_t adpcmBMemLen; @@ -106,9 +104,6 @@ class DivPlatformYM2608: public DivDispatch, public DivPlatformOPNBase { double fmFreqBase; unsigned char ayDiv; - short oldWrites[512]; - short pendingWrites[512]; - double NOTE_OPNB(int ch, int note); double NOTE_ADPCMB(int note); friend void putDispatchChan(void*,int,int); @@ -142,7 +137,6 @@ class DivPlatformYM2608: public DivDispatch, public DivPlatformOPNBase { int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); DivPlatformYM2608(): - DivDispatch(), DivPlatformOPNBase(9440540.0, 72, 32) {} ~DivPlatformYM2608(); }; diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index 39bc82f39..069707dd7 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -19,10 +19,9 @@ #ifndef _YM2610_H #define _YM2610_H -#include "../dispatch.h" +#include "fmshared_OPN.h" #include "../macroInt.h" #include "ay.h" -#include "fmshared_OPN.h" #include "sound/ymfm/ymfm_opn.h" class DivYM2610Interface: public ymfm::ymfm_interface { @@ -35,7 +34,7 @@ class DivYM2610Interface: public ymfm::ymfm_interface { DivYM2610Interface(): adpcmAMem(NULL), adpcmBMem(NULL), sampleBank(0) {} }; -class DivPlatformYM2610Base: public DivDispatch, public DivPlatformOPNBase { +class DivPlatformYM2610Base: public DivPlatformOPNBase { protected: unsigned char* adpcmAMem; size_t adpcmAMemLen; @@ -51,7 +50,6 @@ class DivPlatformYM2610Base: public DivDispatch, public DivPlatformOPNBase { int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); DivPlatformYM2610Base(): - DivDispatch(), DivPlatformOPNBase(9440540.0, 72, 32) {} }; @@ -118,15 +116,11 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { ymfm::ym2610::output_data fmout; DivPlatformAY8910* ay; - unsigned char regPool[512]; unsigned char sampleBank; bool extMode; - short oldWrites[512]; - short pendingWrites[512]; - double NOTE_OPNB(int ch, int note); double NOTE_ADPCMB(int note); friend void putDispatchChan(void*,int,int); diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index 737251e4f..0d1dca2b7 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -19,12 +19,11 @@ #ifndef _YM2610B_H #define _YM2610B_H -#include "../dispatch.h" +#include "ym2610.h" #include "../macroInt.h" #include #include "sound/ymfm/ymfm_opn.h" -#include "ym2610.h" class DivPlatformYM2610B: public DivPlatformYM2610Base { protected: @@ -83,7 +82,6 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { bool isMuted[16]; ymfm::ym2610b* fm; ymfm::ym2610b::output_data fmout; - unsigned char regPool[512]; DivPlatformAY8910* ay; unsigned char sampleBank; @@ -91,9 +89,6 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { bool extMode; double fmFreqBase=9440540; unsigned char ayDiv=32; - - short oldWrites[512]; - short pendingWrites[512]; double NOTE_OPNB(int ch, int note); double NOTE_ADPCMB(int note); From 5473b8722dca28cc3e9a65cf4b6fa3cca7e61ab9 Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 6 Jun 2022 19:52:13 +0900 Subject: [PATCH 004/101] Fix compile, Remove unused include --- src/engine/platform/fmsharedbase.h | 31 +++++++++++++++--------------- src/engine/platform/ym2610b.h | 1 - 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/engine/platform/fmsharedbase.h b/src/engine/platform/fmsharedbase.h index 355b05c23..2555d2676 100644 --- a/src/engine/platform/fmsharedbase.h +++ b/src/engine/platform/fmsharedbase.h @@ -23,21 +23,6 @@ #include "../dispatch.h" #include -#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} -#define immWrite(a,v) if (!skipRegisterWrites) {writes.push_back(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);} } -#define urgentWrite(a,v) if (!skipRegisterWrites) { \ - if (writes.empty()) { \ - writes.push_back(QueuedWrite(a,v)); \ - } else if (writes.size()>16 || writes.front().addrOrVal) { \ - writes.push_back(QueuedWrite(a,v)); \ - } else { \ - writes.push_front(QueuedWrite(a,v)); \ - } \ - if (dumpWrites) { \ - addWrite(a,v); \ - } \ -} - class DivPlatformFMBase: public DivDispatch { protected: const bool isOutput[8][4]={ @@ -75,8 +60,24 @@ class DivPlatformFMBase: public DivDispatch { short pendingWrites[512]; DivPlatformFMBase(): + DivDispatch(), lastBusy(0), delay(0) {} }; +#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} +#define immWrite(a,v) if (!skipRegisterWrites) {writes.push_back(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);} } +#define urgentWrite(a,v) if (!skipRegisterWrites) { \ + if (writes.empty()) { \ + writes.push_back(QueuedWrite(a,v)); \ + } else if (writes.size()>16 || writes.front().addrOrVal) { \ + writes.push_back(QueuedWrite(a,v)); \ + } else { \ + writes.push_front(QueuedWrite(a,v)); \ + } \ + if (dumpWrites) { \ + addWrite(a,v); \ + } \ +} + #endif diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index 0d1dca2b7..fefb06929 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -21,7 +21,6 @@ #define _YM2610B_H #include "ym2610.h" #include "../macroInt.h" -#include #include "sound/ymfm/ymfm_opn.h" From 8bc545c8abc46e4061e2db47cc8de367dec3e93c Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 6 Jun 2022 22:45:16 +0900 Subject: [PATCH 005/101] Fix compile (again) --- src/engine/platform/fmshared_OPM.h | 15 +++++++++++++++ src/engine/platform/fmshared_OPN.h | 15 +++++++++++++++ src/engine/platform/fmsharedbase.h | 15 --------------- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/engine/platform/fmshared_OPM.h b/src/engine/platform/fmshared_OPM.h index c21d1c180..585a42d9e 100644 --- a/src/engine/platform/fmshared_OPM.h +++ b/src/engine/platform/fmshared_OPM.h @@ -22,6 +22,21 @@ #include "fmsharedbase.h" +#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} +#define immWrite(a,v) if (!skipRegisterWrites) {writes.push_back(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);} } +#define urgentWrite(a,v) if (!skipRegisterWrites) { \ + if (writes.empty()) { \ + writes.push_back(QueuedWrite(a,v)); \ + } else if (writes.size()>16 || writes.front().addrOrVal) { \ + writes.push_back(QueuedWrite(a,v)); \ + } else { \ + writes.push_front(QueuedWrite(a,v)); \ + } \ + if (dumpWrites) { \ + addWrite(a,v); \ + } \ +} + #define NOTE_LINEAR(x) (((x)<<6)+baseFreqOff+log2(parent->song.tuning/440.0)*12.0*64.0) class DivPlatformOPMBase: public DivPlatformFMBase { diff --git a/src/engine/platform/fmshared_OPN.h b/src/engine/platform/fmshared_OPN.h index ae40748b4..b3cd7c3ae 100644 --- a/src/engine/platform/fmshared_OPN.h +++ b/src/engine/platform/fmshared_OPN.h @@ -22,6 +22,21 @@ #include "fmsharedbase.h" +#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} +#define immWrite(a,v) if (!skipRegisterWrites) {writes.push_back(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);} } +#define urgentWrite(a,v) if (!skipRegisterWrites) { \ + if (writes.empty()) { \ + writes.push_back(QueuedWrite(a,v)); \ + } else if (writes.size()>16 || writes.front().addrOrVal) { \ + writes.push_back(QueuedWrite(a,v)); \ + } else { \ + writes.push_front(QueuedWrite(a,v)); \ + } \ + if (dumpWrites) { \ + addWrite(a,v); \ + } \ +} + #define CHIP_FREQBASE fmFreqBase #define CHIP_DIVIDER fmDivBase diff --git a/src/engine/platform/fmsharedbase.h b/src/engine/platform/fmsharedbase.h index 2555d2676..f13126147 100644 --- a/src/engine/platform/fmsharedbase.h +++ b/src/engine/platform/fmsharedbase.h @@ -65,19 +65,4 @@ class DivPlatformFMBase: public DivDispatch { delay(0) {} }; -#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} -#define immWrite(a,v) if (!skipRegisterWrites) {writes.push_back(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);} } -#define urgentWrite(a,v) if (!skipRegisterWrites) { \ - if (writes.empty()) { \ - writes.push_back(QueuedWrite(a,v)); \ - } else if (writes.size()>16 || writes.front().addrOrVal) { \ - writes.push_back(QueuedWrite(a,v)); \ - } else { \ - writes.push_front(QueuedWrite(a,v)); \ - } \ - if (dumpWrites) { \ - addWrite(a,v); \ - } \ -} - #endif From 74e3892fd997e40148c64ce2e81c5a3f3ba9feb1 Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 6 Jun 2022 23:26:22 +0900 Subject: [PATCH 006/101] Finally fixed --- src/engine/platform/fmshared_OPM.h | 15 --------------- src/engine/platform/fmshared_OPN.h | 15 --------------- src/engine/platform/fmsharedbase.h | 28 ++++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/engine/platform/fmshared_OPM.h b/src/engine/platform/fmshared_OPM.h index 585a42d9e..c21d1c180 100644 --- a/src/engine/platform/fmshared_OPM.h +++ b/src/engine/platform/fmshared_OPM.h @@ -22,21 +22,6 @@ #include "fmsharedbase.h" -#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} -#define immWrite(a,v) if (!skipRegisterWrites) {writes.push_back(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);} } -#define urgentWrite(a,v) if (!skipRegisterWrites) { \ - if (writes.empty()) { \ - writes.push_back(QueuedWrite(a,v)); \ - } else if (writes.size()>16 || writes.front().addrOrVal) { \ - writes.push_back(QueuedWrite(a,v)); \ - } else { \ - writes.push_front(QueuedWrite(a,v)); \ - } \ - if (dumpWrites) { \ - addWrite(a,v); \ - } \ -} - #define NOTE_LINEAR(x) (((x)<<6)+baseFreqOff+log2(parent->song.tuning/440.0)*12.0*64.0) class DivPlatformOPMBase: public DivPlatformFMBase { diff --git a/src/engine/platform/fmshared_OPN.h b/src/engine/platform/fmshared_OPN.h index b3cd7c3ae..ae40748b4 100644 --- a/src/engine/platform/fmshared_OPN.h +++ b/src/engine/platform/fmshared_OPN.h @@ -22,21 +22,6 @@ #include "fmsharedbase.h" -#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} -#define immWrite(a,v) if (!skipRegisterWrites) {writes.push_back(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);} } -#define urgentWrite(a,v) if (!skipRegisterWrites) { \ - if (writes.empty()) { \ - writes.push_back(QueuedWrite(a,v)); \ - } else if (writes.size()>16 || writes.front().addrOrVal) { \ - writes.push_back(QueuedWrite(a,v)); \ - } else { \ - writes.push_front(QueuedWrite(a,v)); \ - } \ - if (dumpWrites) { \ - addWrite(a,v); \ - } \ -} - #define CHIP_FREQBASE fmFreqBase #define CHIP_DIVIDER fmDivBase diff --git a/src/engine/platform/fmsharedbase.h b/src/engine/platform/fmsharedbase.h index f13126147..640997392 100644 --- a/src/engine/platform/fmsharedbase.h +++ b/src/engine/platform/fmsharedbase.h @@ -59,6 +59,34 @@ class DivPlatformFMBase: public DivDispatch { short oldWrites[512]; short pendingWrites[512]; + inline void rWrite(unsigned short a, short v) { + if (!skipRegisterWrites) { + pendingWrites[a]=v; + } + } + inline void immWrite(unsigned short a, unsigned char v) { + if (!skipRegisterWrites) { + writes.push_back(QueuedWrite(a,v)); + if (dumpWrites) { + addWrite(a,v); + } + } + } + inline void urgentWrite(unsigned short a, unsigned char v) { + if (!skipRegisterWrites) { + if (writes.empty()) { + writes.push_back(QueuedWrite(a,v)); + } else if (writes.size()>16 || writes.front().addrOrVal) { + writes.push_back(QueuedWrite(a,v)); + } else { + writes.push_front(QueuedWrite(a,v)); + } + if (dumpWrites) { + addWrite(a,v); + } + } + } + DivPlatformFMBase(): DivDispatch(), lastBusy(0), From 44cee98868c46bdeba73e4288f800ba8920964a2 Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 6 Jun 2022 23:46:33 +0900 Subject: [PATCH 007/101] Oops --- src/gui/sysConf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index fcd01e0dd..e758b1798 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -123,7 +123,7 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool } if (ImGui::RadioButton("Yamaha YMF281",((flags>>4)&15)==1)) { copyOfFlags=(flags&(~0xf0))|0x10; - + } if (ImGui::RadioButton("Yamaha YM2423",((flags>>4)&15)==2)) { copyOfFlags=(flags&(~0xf0))|0x20; } From d3a3473f19877f3c305c4c69adab6234dfd5dd4a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 6 Jun 2022 13:32:57 -0500 Subject: [PATCH 008/101] commit requested changes --- src/engine/platform/fmshared_OPN.h | 4 ++-- src/engine/platform/genesis.h | 4 ++-- src/engine/platform/ym2203.h | 4 ++-- src/engine/platform/ym2608.h | 4 ++-- src/engine/platform/ym2610.h | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/engine/platform/fmshared_OPN.h b/src/engine/platform/fmshared_OPN.h index ae40748b4..7632e78f7 100644 --- a/src/engine/platform/fmshared_OPN.h +++ b/src/engine/platform/fmshared_OPN.h @@ -86,7 +86,7 @@ return 2; \ } -class DivPlatformOPNBase: public DivPlatformFMBase { +class DivPlatformOPN: public DivPlatformFMBase { protected: const unsigned char ADDR_MULT_DT=0x30; const unsigned char ADDR_TL=0x40; @@ -108,7 +108,7 @@ class DivPlatformOPNBase: public DivPlatformFMBase { const double fmDivBase; const unsigned char ayDiv; - DivPlatformOPNBase(double f=9440540.0, double d=72, unsigned char a=32): + DivPlatformOPN(double f=9440540.0, double d=72, unsigned char a=32): DivPlatformFMBase(), fmFreqBase(f), fmDivBase(d), diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index ace427f6e..7d2004f33 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -29,7 +29,7 @@ class DivYM2612Interface: public ymfm::ymfm_interface { }; -class DivPlatformGenesis: public DivPlatformOPNBase { +class DivPlatformGenesis: public DivPlatformOPN { protected: const unsigned short chanOffs[6]={ 0x00, 0x01, 0x02, 0x100, 0x101, 0x102 @@ -155,7 +155,7 @@ class DivPlatformGenesis: public DivPlatformOPNBase { int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); DivPlatformGenesis(): - DivPlatformOPNBase(9440540.0, 72, 32) {} + DivPlatformOPN(9440540.0, 72, 32) {} ~DivPlatformGenesis(); }; #endif diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index c650583df..6d7bc4207 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -29,7 +29,7 @@ class DivYM2203Interface: public ymfm::ymfm_interface { }; -class DivPlatformYM2203: public DivPlatformOPNBase { +class DivPlatformYM2203: public DivPlatformOPN { protected: const unsigned short chanOffs[3]={ 0x00, 0x01, 0x02 @@ -118,7 +118,7 @@ class DivPlatformYM2203: public DivPlatformOPNBase { int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); DivPlatformYM2203(): - DivPlatformOPNBase(4720270.0, 36, 16) {} + DivPlatformOPN(4720270.0, 36, 16) {} ~DivPlatformYM2203(); }; #endif diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index 21eb487fd..c1f43f4df 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -34,7 +34,7 @@ class DivYM2608Interface: public ymfm::ymfm_interface { DivYM2608Interface(): adpcmBMem(NULL), sampleBank(0) {} }; -class DivPlatformYM2608: public DivPlatformOPNBase { +class DivPlatformYM2608: public DivPlatformOPN { protected: const unsigned short chanOffs[6]={ 0x00, 0x01, 0x02, 0x100, 0x101, 0x102 @@ -137,7 +137,7 @@ class DivPlatformYM2608: public DivPlatformOPNBase { int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); DivPlatformYM2608(): - DivPlatformOPNBase(9440540.0, 72, 32) {} + DivPlatformOPN(9440540.0, 72, 32) {} ~DivPlatformYM2608(); }; #endif diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index 069707dd7..dde7ed105 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -34,7 +34,7 @@ class DivYM2610Interface: public ymfm::ymfm_interface { DivYM2610Interface(): adpcmAMem(NULL), adpcmBMem(NULL), sampleBank(0) {} }; -class DivPlatformYM2610Base: public DivPlatformOPNBase { +class DivPlatformYM2610Base: public DivPlatformOPN { protected: unsigned char* adpcmAMem; size_t adpcmAMemLen; @@ -50,7 +50,7 @@ class DivPlatformYM2610Base: public DivPlatformOPNBase { int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); DivPlatformYM2610Base(): - DivPlatformOPNBase(9440540.0, 72, 32) {} + DivPlatformOPN(9440540.0, 72, 32) {} }; class DivPlatformYM2610: public DivPlatformYM2610Base { From 3e953f57b368f679c570ed1f95b9054c2dc97517 Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 7 Jun 2022 12:57:09 +0900 Subject: [PATCH 009/101] Prepare for TI-99/4A support only works on MAME core only for now. --- src/engine/platform/arcade.h | 2 +- src/engine/platform/fmshared_OPM.h | 4 ++-- src/engine/platform/opl.cpp | 2 +- src/engine/platform/sms.cpp | 20 +++++++++++++++++++- src/engine/platform/sms.h | 1 + src/engine/platform/sound/sn76496.cpp | 16 ++++++++-------- src/engine/platform/tx81z.h | 2 +- src/engine/platform/ym2203.cpp | 2 +- src/engine/platform/ym2608.cpp | 2 +- src/engine/song.h | 3 +++ src/gui/presets.cpp | 6 ++++++ src/gui/sysConf.cpp | 9 +++++++++ 12 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index 00af8f259..daa883620 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -30,7 +30,7 @@ class DivArcadeInterface: public ymfm::ymfm_interface { }; -class DivPlatformArcade: public DivPlatformOPMBase { +class DivPlatformArcade: public DivPlatformOPM { protected: const unsigned short chanOffs[8]={ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 diff --git a/src/engine/platform/fmshared_OPM.h b/src/engine/platform/fmshared_OPM.h index c21d1c180..97844656d 100644 --- a/src/engine/platform/fmshared_OPM.h +++ b/src/engine/platform/fmshared_OPM.h @@ -24,7 +24,7 @@ #define NOTE_LINEAR(x) (((x)<<6)+baseFreqOff+log2(parent->song.tuning/440.0)*12.0*64.0) -class DivPlatformOPMBase: public DivPlatformFMBase { +class DivPlatformOPM: public DivPlatformFMBase { protected: const unsigned char ADDR_MULT_DT=0x40; const unsigned char ADDR_TL=0x60; @@ -41,7 +41,7 @@ class DivPlatformOPMBase: public DivPlatformFMBase { 0x00, 0x08, 0x10, 0x18 }; - DivPlatformOPMBase(): + DivPlatformOPM(): DivPlatformFMBase() {} }; diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 43ce2f5f3..45cbd619b 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -1723,7 +1723,7 @@ void DivPlatformOPL::setFlags(unsigned int flags) { chipClock=3000000.0; break; case 0x04: - chipClock=31948800/8; + chipClock=38400*13*8; // 31948800/8 break; case 0x05: chipClock=3500000.0; diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index f6624b97f..e5be23045 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -472,8 +472,12 @@ void DivPlatformSMS::setFlags(unsigned int flags) { case 0x0101: chipClock=2000000; break; + case 0x0102: + chipClock=COLOR_NTSC/8.0; + break; } resetPhase=!(flags&16); + divider=16; noiseDivider=64; if (sn!=NULL) delete sn; switch (flags&0xcc) { @@ -524,8 +528,22 @@ void DivPlatformSMS::setFlags(unsigned int flags) { noiseDivider=64; stereo=false; break; + case 0x80: // TI SN94624 + sn=new sn94624_device(); + isRealSN=true; + noiseDivider=60; + stereo=false; + divider=2; + break; + case 0x84: // TI SN76494 + sn=new sn76494_device(); + isRealSN=false; // TODO + noiseDivider=68; + stereo=false; + divider=2; + break; } - rate=nuked?chipClock/16:chipClock/2; + rate=chipClock/divider; for (int i=0; i<4; i++) { oscBuf[i]->rate=rate; } diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index c4e4179fe..423995772 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -63,6 +63,7 @@ class DivPlatformSMS: public DivDispatch { size_t snBufLen; unsigned char oldValue; unsigned char snNoiseMode; + int divider=16; int noiseDivider=64; bool updateSNMode; bool resetPhase; diff --git a/src/engine/platform/sound/sn76496.cpp b/src/engine/platform/sound/sn76496.cpp index 5062ea7a8..afb82ad3a 100644 --- a/src/engine/platform/sound/sn76496.cpp +++ b/src/engine/platform/sound/sn76496.cpp @@ -171,22 +171,22 @@ sn76496_base_device::sn76496_base_device( } sn76496_device::sn76496_device() - : sn76496_base_device(0x10000, 0x04, 0x08, false, false, 8, false, true) + : sn76496_base_device(0x10000, 0x04, 0x08, false, false, 1/*8*/, false, true) { } y2404_device::y2404_device() - : sn76496_base_device(0x10000, 0x04, 0x08, false, false, 8, false, true) + : sn76496_base_device(0x10000, 0x04, 0x08, false, false, 1/*8*/, false, true) { } sn76489_device::sn76489_device() - : sn76496_base_device(0x4000, 0x01, 0x02, true, false, 8, false, true) + : sn76496_base_device(0x4000, 0x01, 0x02, true, false, 1/*8*/, false, true) { } sn76489a_device::sn76489a_device() - : sn76496_base_device(0x10000, 0x04, 0x08, false, false, 8, false, true) + : sn76496_base_device(0x10000, 0x04, 0x08, false, false, 1/*8*/, false, true) { } @@ -201,22 +201,22 @@ sn94624_device::sn94624_device() } ncr8496_device::ncr8496_device() - : sn76496_base_device(0x8000, 0x02, 0x20, true, false, 8, true, true) + : sn76496_base_device(0x8000, 0x02, 0x20, true, false, 1/*8*/, true, true) { } pssj3_device::pssj3_device() - : sn76496_base_device(0x8000, 0x02, 0x20, false, false, 8, true, true) + : sn76496_base_device(0x8000, 0x02, 0x20, false, false, 1/*8*/, true, true) { } gamegear_device::gamegear_device() - : sn76496_base_device(0x8000, 0x01, 0x08, true, true, 8, false, false) + : sn76496_base_device(0x8000, 0x01, 0x08, true, true, 1/*8*/, false, false) { } segapsg_device::segapsg_device() - : sn76496_base_device(0x8000, 0x01, 0x08, true, false, 8, false, false) + : sn76496_base_device(0x8000, 0x01, 0x08, true, false, 1/*8*/, false, false) { } diff --git a/src/engine/platform/tx81z.h b/src/engine/platform/tx81z.h index 16167ede4..e867416cf 100644 --- a/src/engine/platform/tx81z.h +++ b/src/engine/platform/tx81z.h @@ -29,7 +29,7 @@ class DivTXInterface: public ymfm::ymfm_interface { }; -class DivPlatformTX81Z: public DivPlatformOPMBase { +class DivPlatformTX81Z: public DivPlatformOPM { protected: const unsigned short chanOffs[8]={ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 3176a1a4b..42314615b 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -1027,7 +1027,7 @@ void DivPlatformYM2203::setFlags(unsigned int flags) { chipClock=3000000.0; break; case 0x04: - chipClock=31948800/8; + chipClock=38400*13*8; // 31948800/8 break; case 0x05: chipClock=3000000.0/2.0; diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index d4871486b..875f4148d 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -1400,7 +1400,7 @@ void DivPlatformYM2608::setFlags(unsigned int flags) { chipClock=8000000.0; break; case 0x01: - chipClock=31948800/4; + chipClock=38400*13*16; // 31948800/4 break; } rate=fm->sample_rate(chipClock); diff --git a/src/engine/song.h b/src/engine/song.h index a5b68c267..6bbb00cf8 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -244,6 +244,7 @@ struct DivSong { // - 0003: 1.79MHz (half NTSC) // - 0100: 3MHz // - 0101: 2MHz + // - 0102: 447KHz (NTSC / 8) // - bit 2-3, 6-7: chip type // - 00: Sega VDP (16-bit noise) // - 04: real SN76489 (15-bit noise) @@ -253,6 +254,8 @@ struct DivSong { // - 44: real SN76496 (17-bit noise) // - 48: NCR 8496 (16-bit noise) // - 4c: Tandy PSSJ-3 (16-bit noise) + // - 80: real SN94624 (15-bit noise) + // - 84: real SN76494 (17-bit noise) // - bit 4: disable noise phase reset // - YM2612/YM3438: // - bit 0-30: clock rate diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index a841f15b1..d0e63c111 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1211,6 +1211,12 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "TI-99/4A", { + DIV_SYSTEM_SMS, 64, 0, 0x182, // SN94624 447KHz + 0 + } + )); sysCategories.push_back(cat); cat=FurnaceGUISysCategory("Arcade systems","INSERT COIN"); diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index e758b1798..02d06db30 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -69,6 +69,9 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::RadioButton("2MHz (Sega System 1)",(flags&0xff03)==0x0101)) { copyOfFlags=(flags&(~0xff03))|0x0101; } + if (ImGui::RadioButton("447KHz (TI-99/4A)",(flags&0xff03)==0x0102)) { + copyOfFlags=(flags&(~0xff03))|0x0102; + } ImGui::Text("Chip type:"); if (ImGui::RadioButton("Sega VDP/Master System",(flags&0xcc)==0x00)) { copyOfFlags=(flags&(~0xcc))|0x00; @@ -94,6 +97,12 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::RadioButton("Tandy PSSJ 3-voice sound",(flags&0xcc)==0x4c)) { copyOfFlags=(flags&(~0xcc))|0x4c; } + if (ImGui::RadioButton("TI SN94624",(flags&0xcc)==0x80)) { + copyOfFlags=(flags&(~0xcc))|0x80; + } + if (ImGui::RadioButton("TI SN76494",(flags&0xcc)==0x84)) { + copyOfFlags=(flags&(~0xcc))|0x84; + } bool noPhaseReset=flags&16; if (ImGui::Checkbox("Disable noise period change phase reset",&noPhaseReset)) { copyOfFlags=(flags&(~16))|(noPhaseReset<<4); From 7bbfe3af7c8cab34ca65d9416e5dd0cedebc7d1e Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 7 Jun 2022 23:59:50 +0900 Subject: [PATCH 010/101] Fix per-channel osc --- src/engine/platform/sms.cpp | 24 ++++++++++++++---------- src/engine/platform/sound/sn76496.cpp | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index e5be23045..35bb9c40c 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -101,7 +101,20 @@ void DivPlatformSMS::acquire_mame(short* bufL, short* bufR, size_t start, size_t sn->write(w.val); writes.pop(); } - sn->sound_stream_update(snBuf,len); + for (size_t h=0; hsound_stream_update(outs,1); + for (int i=0; i<4; i++) { + if (isMuted[i]) { + oscBuf[i]->data[oscBuf[i]->needle++]=0; + } else { + oscBuf[i]->data[oscBuf[i]->needle++]=sn->get_channel_output(i); + } + } + } if (stereo) { for (size_t i=0; idata[oscBuf[i]->needle++]=0; - } else { - oscBuf[i]->data[oscBuf[i]->needle++]=sn->get_channel_output(i); - } - } - } } void DivPlatformSMS::acquire(short* bufL, short* bufR, size_t start, size_t len) { diff --git a/src/engine/platform/sound/sn76496.cpp b/src/engine/platform/sound/sn76496.cpp index afb82ad3a..4bbb5848a 100644 --- a/src/engine/platform/sound/sn76496.cpp +++ b/src/engine/platform/sound/sn76496.cpp @@ -411,7 +411,7 @@ void sn76496_base_device::sound_stream_update(short** outputs, int outLen) if (m_negate) { out = -out; out2 = -out2; } outputs[0][sampindex]=out; - if (m_stereo) + if (m_stereo && (outputs[1] != nullptr)) outputs[1][sampindex]=out; } } From 6aa88b07705e2b618b58045e7478e116d041329e Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 8 Jun 2022 10:10:55 +0900 Subject: [PATCH 011/101] Move on .cpp, prepare for variable rate support --- src/engine/platform/fmshared_OPN.h | 9 +++------ src/engine/platform/genesis.cpp | 3 +++ src/engine/platform/genesisext.cpp | 3 +++ src/engine/platform/ym2203.cpp | 3 ++- src/engine/platform/ym2203ext.cpp | 3 +++ src/engine/platform/ym2608.cpp | 3 ++- src/engine/platform/ym2608ext.cpp | 3 +++ src/engine/platform/ym2610.cpp | 2 ++ src/engine/platform/ym2610b.cpp | 3 +++ src/engine/platform/ym2610bext.cpp | 3 +++ src/engine/platform/ym2610ext.cpp | 3 +++ 11 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/engine/platform/fmshared_OPN.h b/src/engine/platform/fmshared_OPN.h index 7632e78f7..74e13219f 100644 --- a/src/engine/platform/fmshared_OPN.h +++ b/src/engine/platform/fmshared_OPN.h @@ -22,9 +22,6 @@ #include "fmsharedbase.h" -#define CHIP_FREQBASE fmFreqBase -#define CHIP_DIVIDER fmDivBase - #define PLEASE_HELP_ME(_targetChan) \ int boundaryBottom=parent->calcBaseFreq(chipClock,CHIP_FREQBASE,0,false); \ int boundaryTop=parent->calcBaseFreq(chipClock,CHIP_FREQBASE,12,false); \ @@ -104,9 +101,9 @@ class DivPlatformOPN: public DivPlatformFMBase { 0x00, 0x04, 0x08, 0x0c }; - const double fmFreqBase; - const double fmDivBase; - const unsigned char ayDiv; + double fmFreqBase; + double fmDivBase; + unsigned char ayDiv; DivPlatformOPN(double f=9440540.0, double d=72, unsigned char a=32): DivPlatformFMBase(), diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index b9a5c6866..b3afdd2a3 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -22,6 +22,9 @@ #include #include +#define CHIP_FREQBASE fmFreqBase +#define CHIP_DIVIDER fmDivBase + #define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6]))) const char* DivPlatformGenesis::getEffectName(unsigned char effect) { diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 057049eaa..cd4d603c1 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -21,6 +21,9 @@ #include "../engine.h" #include +#define CHIP_FREQBASE fmFreqBase +#define CHIP_DIVIDER fmDivBase + int DivPlatformGenesisExt::dispatch(DivCommand c) { if (c.chan<2) { return DivPlatformGenesis::dispatch(c); diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 42314615b..a25c0e964 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -23,7 +23,8 @@ #include #include - +#define CHIP_FREQBASE fmFreqBase +#define CHIP_DIVIDER fmDivBase const char* regCheatSheetYM2203[]={ // SSG diff --git a/src/engine/platform/ym2203ext.cpp b/src/engine/platform/ym2203ext.cpp index fbef7b043..d3fd3487b 100644 --- a/src/engine/platform/ym2203ext.cpp +++ b/src/engine/platform/ym2203ext.cpp @@ -21,6 +21,9 @@ #include "../engine.h" #include +#define CHIP_FREQBASE fmFreqBase +#define CHIP_DIVIDER fmDivBase + int DivPlatformYM2203Ext::dispatch(DivCommand c) { if (c.chan<2) { return DivPlatformYM2203::dispatch(c); diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 875f4148d..46b8b0ad1 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -24,7 +24,8 @@ #include #include - +#define CHIP_FREQBASE fmFreqBase +#define CHIP_DIVIDER fmDivBase const char* regCheatSheetYM2608[]={ // SSG diff --git a/src/engine/platform/ym2608ext.cpp b/src/engine/platform/ym2608ext.cpp index d33bf9edb..91c3a897f 100644 --- a/src/engine/platform/ym2608ext.cpp +++ b/src/engine/platform/ym2608ext.cpp @@ -21,6 +21,9 @@ #include "../engine.h" #include +#define CHIP_FREQBASE fmFreqBase +#define CHIP_DIVIDER fmDivBase + int DivPlatformYM2608Ext::dispatch(DivCommand c) { if (c.chan<2) { return DivPlatformYM2608::dispatch(c); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index df340804a..bed59c203 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -24,6 +24,8 @@ #include #include +#define CHIP_FREQBASE fmFreqBase +#define CHIP_DIVIDER fmDivBase const char* regCheatSheetYM2610[]={ // SSG diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 16f198f7e..a2291c3f4 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -23,6 +23,9 @@ #include #include +#define CHIP_FREQBASE fmFreqBase +#define CHIP_DIVIDER fmDivBase + const char* regCheatSheetYM2610B[]={ // SSG "SSG_FreqL_A", "000", diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index 61a997895..b5e1ac9fb 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -21,6 +21,9 @@ #include "../engine.h" #include +#define CHIP_FREQBASE fmFreqBase +#define CHIP_DIVIDER fmDivBase + int DivPlatformYM2610BExt::dispatch(DivCommand c) { if (c.chan<2) { return DivPlatformYM2610B::dispatch(c); diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index f2006c1cc..6f9c8700d 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -21,6 +21,9 @@ #include "../engine.h" #include +#define CHIP_FREQBASE fmFreqBase +#define CHIP_DIVIDER fmDivBase + int DivPlatformYM2610Ext::dispatch(DivCommand c) { if (c.chan<1) { return DivPlatformYM2610::dispatch(c); From 38f4b75b128178d27bcedc8fb48a8d04b0721efc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 8 Jun 2022 18:02:04 -0500 Subject: [PATCH 012/101] GUI: find and replace, part 4 --- src/gui/findReplace.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 0daf34125..8c05be991 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -366,7 +366,24 @@ void FurnaceGUI::drawFindReplace() { if (ImGui::BeginTable("QueryReplace",3)) { ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text("..."); + ImGui::Text("Note"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Ins"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Volume"); + + /*ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Effect"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Value");*/ + ImGui::EndTable(); } if (ImGui::Button("Replace##QueryReplace")) { From caf548c6394126748b1e233ee162c132620d17df Mon Sep 17 00:00:00 2001 From: itsragedev <66060223+itsragedev@users.noreply.github.com> Date: Thu, 9 Jun 2022 15:43:19 +0200 Subject: [PATCH 013/101] add terrible demo (#520) --- demos/the_erfngjt.fur | Bin 0 -> 739 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/the_erfngjt.fur diff --git a/demos/the_erfngjt.fur b/demos/the_erfngjt.fur new file mode 100644 index 0000000000000000000000000000000000000000..5d70dca8e8a0e47841c913bab96be83b1a14c033 GIT binary patch literal 739 zcmV<90v!E#ob6c6Zqq;zo?Y7{b^=C7oRElxkdTln^@hZSwm_vys8kSfu0_I6MAFJ7 z7fu}d47>s_zytKeQ}7_%V0SIYpINX1!49{Z#r+eGrfpybXu502thkWc5pkVobNB_excpkl*ydQmrQ8@fE z6~13jfyZ|lOX3*&DeOmWfQuUdk8cC~xC7wa1$Ywxe7^_q`@X2=0~x8nIk(kM&X^?~ zvy@+-%(&&ZofY&=d|^=v2Zyiw^7R%M%=I~W+XucQcOi7e*W7CS3n%OZe+m%i1L%S(oO&(dVE7CTQKUzwFILv%sv?)^ z+Pb6aTAK1Vd5ZD`&XIG$6d?rG+H6n{M%W6zA72#kz zNeq3s4)M@&A+CeG80a63^E_=aC8#YauP|FyrW7Aop%Vy#~%qf*;)h-#=@U}ao2l-nWPD>k){T#*H$fh`5!k^_&{hdqL7sb;d{4Sw~Iv4Ec>J30r9|zUPL3;Fl z9FO@aPD&4IsQ3-V0NG4YBVoT^Lvqx+%qlaah zW%2rCYLzw=&uyq~=5a?IK90dcC_g1oAHNQIr~||!hB`nzV#@4mnTDeDSQ)>*q0H-} VZ73_Zp{N<#*o~dB{{lA$)Q>%Rau)yq literal 0 HcmV?d00001 From 0e05f3b67bc6895bdca0d69b463256a1e350827b Mon Sep 17 00:00:00 2001 From: LoKiToon <98922449+LoKiToon@users.noreply.github.com> Date: Thu, 9 Jun 2022 20:41:01 +0300 Subject: [PATCH 014/101] Add files via upload --- demos/E1M4OPL2.fur | Bin 0 -> 4122 bytes demos/FDS TEST.fur | Bin 0 -> 1574 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/E1M4OPL2.fur create mode 100644 demos/FDS TEST.fur diff --git a/demos/E1M4OPL2.fur b/demos/E1M4OPL2.fur new file mode 100644 index 0000000000000000000000000000000000000000..19f8ce54f34c5214eac28024ce513c961d392c01 GIT binary patch literal 4122 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 AZvX%Q literal 0 HcmV?d00001 diff --git a/demos/FDS TEST.fur b/demos/FDS TEST.fur new file mode 100644 index 0000000000000000000000000000000000000000..54b6d3b40607fd0367a5de8f511989df758bb900 GIT binary patch literal 1574 zcmV+>2HE*|ob6mqOdCfOezVwsf!07t)Ssl;P>>QNDoC5EQq=}1(Aa7ye+J1G2TFYa zvJeGGRYhqz^pHlX)LOLXRDud@nM9QgQjtQAJ@!JXV5R9fRYOnhp&{;!ch}y+j+Zgp zWCzbPPky|adEc8i^Y-m}42_*L7bk{C!m={?(aia9;|KuAkR@MN=Lcz_xEKLkXlsEo za8;H70tviCeGPI_iv{H#{q(7GSQ#CeROI&2sd2gQld0*jBKL=*A#V-{Ux)ISjCP1mNvg@b4!9yiEYtF@M<%@Zl+dsnYA)N-br*RX0Nj)) zA9Ep8-jt)g47t43^i?|MK_0I}ZT5oHl8#HM#ydvS4ezFu1?^>wdARMtH}@w$M1i#% zi*+pTWOpoC?F$?$9NFFNzKzlbK`wI41kDLuMQ{_%nm2mAD$^)iXuw!#nz<}A_>Lg$ za|Oi~iM87xo2`Ra<7YK~M&k;N%QY_3*rT!TUWvxV8oM>teL@;b8tcCUrQK`}Mxxzm z?1l2%rw6+jJxMIqvAmPrv1GL`aIA3nDtx&b^DKO)xGa3Mf~V77)cPv@$3mhw)f-g+3aaowGD4%uM*+&!_ez91`@=kWglGVPz zvBD|%Li0M8g@!z(&@HL!gn+(Yqz{7sejK+`CY0-=MI-IwQ#o!f-Uk(nbu8~>cPv@$ z3mhw)LM%!yV^KQIWl^%CeAZ!SAMy0VFBa=q-pTG*vf39oRyYM;Xx`wW(4ePKXjt%A z@y)Rg_Qn56VzG|po$QV!t9^lEg;O|%X0UajBQ5AxZ1P@-`8iO(vGxMymoOjI+Kl`% z<|CM2#QZ$wLzqcPAqVy3fS%L^awty@;`aoa- zgUiQj+G^V>tG+%PnTtjT5_j&5jmKh&GCmYie!rYrTT5P2Ldngs_)0LbF%VJ`SX|y5 zOAII*!SO`Y-{bFzL?ZJiI($8m`MTq%rL^@cxwa}&*WT6}si|LzVrmEkHpXI!jg7<~ zTlbU8Yb(Lf>MuX8#S<7K9*-|C2b4hlwMbp0uI7uYXRA&Gc1*SzX5G6d`?w@k^e29j zdX)0Q&xaQYP*j51^v)rXgLN$6P(DtjpSNz~H}XCH-&8HYb<%NAmVs>4&$j-)v`W_V zQR-nZ7OlnuQujYyZK!Sq>95p!((kLO>ZtYAZQolNN{%UwRo}Ioymdo~1!8_*m9O{V z%H}|PVXn7f!N2r_qQrws{sn)aArMMLqkbIh1?*dQYk#kCixuN_Mv&d<#$9hFyYPNt z>5mxuv--ok|B}P}XZ447{~?ZQ6IUksfzAy$8Q_a8ZIL$Uh9yZ@PlFy6V?;RySc z{r?V3VfoK`WfcBvayB8dDPhNiSg(vuTM*v;XT35C|20`p2;&EkR>p)Z98j7ILA<*@RGUnaG!;$^Wq0uVI>< zGC(=>9*Vw%qId7ov-(f#ZHPDrXZytq?Ap^={a| zVVa!^Aa`&3*R$fX_P5J_yZjOH&(BZhcxDqq5((je1rhPL*MAm&$k|gSA&lRmwwi>H zg?wP;Y(nVg5ZPv9N2lp&vWL>&X?mJ0QTjVgPm`UtPgwVlAtCg02y+8Y)6+K;GVSj) YJxxZG{!Y`=WEZ8s)AUsNUy`BxAD+J{f&c&j literal 0 HcmV?d00001 From 6ccd2e222b97abc0fa5f28b17c46e07aaacaab4c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 9 Jun 2022 16:10:51 -0500 Subject: [PATCH 015/101] try CoInitializeEx on Windows --- src/main.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 079058528..8c90c7c8e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,6 +30,7 @@ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include +#include #include #else #include @@ -243,6 +244,12 @@ void initParams() { // TODO: add crash log int main(int argc, char** argv) { initLog(); +#ifdef _WIN32 + HRESULT coResult=CoInitializeEx(NULL,COINIT_MULTITHREADED); + if (coResult!=S_OK) { + logE("CoInitializeEx failed!"); + } +#endif #if !(defined(__APPLE__) || defined(_WIN32) || defined(ANDROID)) // workaround for Wayland HiDPI issue if (getenv("SDL_VIDEODRIVER")==NULL) { @@ -446,6 +453,12 @@ int main(int argc, char** argv) { logI("stopping engine."); e.quit(); + +#ifdef _WIN32 + if (coResult==S_OK || coResult==S_FALSE) { + CoUninitialize(); + } +#endif return 0; } From 7dc3dc96c4c0bec8e13f32feba056ba040c60239 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 9 Jun 2022 16:41:54 -0500 Subject: [PATCH 016/101] GUI: find and replace, part 5 --- src/gui/findReplace.cpp | 41 +++++++++++++++++++++++++++++++++++------ src/gui/gui.h | 19 +++++++++++++++++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 8c05be991..071d05ea0 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -17,6 +17,7 @@ const char* queryModes[GUI_QUERY_MAX]={ const char* queryReplaceModes[GUI_QUERY_REPLACE_MAX]={ "set", "add", + "add (overflow)", "clear" }; @@ -363,18 +364,33 @@ void FurnaceGUI::drawFindReplace() { } if (ImGui::TreeNode("Replace")) { - if (ImGui::BeginTable("QueryReplace",3)) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Note"); + if (ImGui::BeginTable("QueryReplace",3,ImGuiTableFlags_BordersOuter)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.5); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.5); ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text("Ins"); + ImGui::Checkbox("Note",&queryReplaceNoteDo); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##NRMode",&queryReplaceNoteMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); + ImGui::TableNextColumn(); + ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text("Volume"); + ImGui::Checkbox("Ins",&queryReplaceInsDo); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##IRMode",&queryReplaceInsMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Checkbox("Volume",&queryReplaceVolDo); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##VRMode",&queryReplaceVolMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); /*ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -386,6 +402,19 @@ void FurnaceGUI::drawFindReplace() { ImGui::EndTable(); } + ImGui::Text("Effect replace mode:"); + if (ImGui::RadioButton("Clear effects",queryReplaceEffectPos==0)) { + queryReplaceEffectPos=0; + } + if (ImGui::RadioButton("Replace matches only",queryReplaceEffectPos==1)) { + queryReplaceEffectPos=1; + } + if (ImGui::RadioButton("Replace matches, then free spaces",queryReplaceEffectPos==2)) { + queryReplaceEffectPos=2; + } + if (ImGui::RadioButton("Insert in free spaces",queryReplaceEffectPos==3)) { + queryReplaceEffectPos=3; + } if (ImGui::Button("Replace##QueryReplace")) { // TODO } diff --git a/src/gui/gui.h b/src/gui/gui.h index 2ee6170aa..107deb9d2 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -818,6 +818,7 @@ enum FurnaceGUIFindQueryModes { enum FurnaceGUIFindQueryReplaceModes { GUI_QUERY_REPLACE_SET=0, GUI_QUERY_REPLACE_ADD, + GUI_QUERY_REPLACE_ADD_OVERFLOW, GUI_QUERY_REPLACE_CLEAR, GUI_QUERY_REPLACE_MAX @@ -1175,6 +1176,24 @@ class FurnaceGUI { int curQueryRangeY; int curQueryEffectPos; + int queryReplaceEffectCount; + int queryReplaceEffectPos; + int queryReplaceNoteMode; + int queryReplaceInsMode; + int queryReplaceVolMode; + int queryReplaceEffectMode[8]; + int queryReplaceEffectValMode[8]; + int queryReplaceNote; + int queryReplaceIns; + int queryReplaceVol; + int queryReplaceEffect[8]; + int queryReplaceEffectVal[8]; + bool queryReplaceNoteDo; + bool queryReplaceInsDo; + bool queryReplaceVolDo; + bool queryReplaceEffectDo[8]; + bool queryReplaceEffectValDo[8]; + struct ActiveNote { int chan; int note; From 04bbffac13e4bbf3773b925be6b9ae884ef6d1af Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 9 Jun 2022 16:54:14 -0500 Subject: [PATCH 017/101] more MIDI debug messages --- src/audio/rtmidi.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/audio/rtmidi.cpp b/src/audio/rtmidi.cpp index a5c5bad02..b431a89d8 100644 --- a/src/audio/rtmidi.cpp +++ b/src/audio/rtmidi.cpp @@ -75,8 +75,12 @@ bool TAMidiInRtMidi::openDevice(String name) { try { bool portOpen=false; unsigned int count=port->getPortCount(); + logD("finding port %s...",name); for (unsigned int i=0; igetPortName(i)==name) { + String portName=port->getPortName(i); + logV("- %d: %s",i,portName); + if (portName==name) { + logD("opening port %d...",i); port->openPort(i); portOpen=true; break; @@ -184,8 +188,12 @@ bool TAMidiOutRtMidi::openDevice(String name) { try { bool portOpen=false; unsigned int count=port->getPortCount(); + logD("finding port %s...",name); for (unsigned int i=0; igetPortName(i)==name) { + String portName=port->getPortName(i); + logV("- %d: %s",i,portName); + if (portName==name) { + logD("opening port %d...",i); port->openPort(i); portOpen=true; break; @@ -248,4 +256,4 @@ bool TAMidiOutRtMidi::quit() { port=NULL; } return true; -} \ No newline at end of file +} From eac4f50d9297f5478c8ca596389193f305f4cd19 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 9 Jun 2022 18:04:50 -0500 Subject: [PATCH 018/101] sanitize MIDI port names on Windows/Linux --- src/audio/rtmidi.cpp | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/audio/rtmidi.cpp b/src/audio/rtmidi.cpp index b431a89d8..31a3e66ae 100644 --- a/src/audio/rtmidi.cpp +++ b/src/audio/rtmidi.cpp @@ -21,6 +21,26 @@ #include "../ta-log.h" #include "taAudio.h" +String sanitizePortName(const String& name) { +#if defined(_WIN32) + // remove port number + size_t namePos=name.rfind(' '); + if (namePos!=String::npos) { + return name.substr(0,namePos); + } + return name; +#elif defined(__linux__) + // remove port location + size_t namePos=name.rfind(' '); + if (namePos!=String::npos) { + return name.substr(0,namePos); + } + return name; +#else + return name; +#endif +} + // --- IN --- bool TAMidiInRtMidi::gather() { @@ -56,7 +76,7 @@ std::vector TAMidiInRtMidi::listDevices() { unsigned int count=port->getPortCount(); logD("got port count."); for (unsigned int i=0; igetPortName(i); + String name=sanitizePortName(port->getPortName(i)); if (name!="") ret.push_back(name); } } catch (RtMidiError& e) { @@ -77,7 +97,7 @@ bool TAMidiInRtMidi::openDevice(String name) { unsigned int count=port->getPortCount(); logD("finding port %s...",name); for (unsigned int i=0; igetPortName(i); + String portName=sanitizePortName(port->getPortName(i)); logV("- %d: %s",i,portName); if (portName==name) { logD("opening port %d...",i); @@ -190,7 +210,7 @@ bool TAMidiOutRtMidi::openDevice(String name) { unsigned int count=port->getPortCount(); logD("finding port %s...",name); for (unsigned int i=0; igetPortName(i); + String portName=sanitizePortName(port->getPortName(i)); logV("- %d: %s",i,portName); if (portName==name) { logD("opening port %d...",i); @@ -230,7 +250,7 @@ std::vector TAMidiOutRtMidi::listDevices() { try { unsigned int count=port->getPortCount(); for (unsigned int i=0; igetPortName(i); + String name=sanitizePortName(port->getPortName(i)); if (name!="") ret.push_back(name); } } catch (RtMidiError& e) { From dd05429c0eb8da08f329bb0f8d37d2cd94915b1f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 9 Jun 2022 18:16:51 -0500 Subject: [PATCH 019/101] WaveSynth: initialize wave to 0 on SCC/Bubble Syst --- src/engine/platform/bubsyswsg.cpp | 2 +- src/engine/platform/scc.cpp | 2 +- src/engine/waveSynth.cpp | 7 ++++++- src/engine/waveSynth.h | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/bubsyswsg.cpp b/src/engine/platform/bubsyswsg.cpp index 85d50e668..48a078803 100644 --- a/src/engine/platform/bubsyswsg.cpp +++ b/src/engine/platform/bubsyswsg.cpp @@ -306,7 +306,7 @@ void DivPlatformBubSysWSG::reset() { for (int i=0; i<2; i++) { chan[i]=DivPlatformBubSysWSG::Channel(); chan[i].std.setEngine(parent); - chan[i].ws.setEngine(parent); + chan[i].ws.setEngine(parent,8); chan[i].ws.init(NULL,32,15,false); } if (dumpWrites) { diff --git a/src/engine/platform/scc.cpp b/src/engine/platform/scc.cpp index 011f63bca..0cfe5a462 100644 --- a/src/engine/platform/scc.cpp +++ b/src/engine/platform/scc.cpp @@ -332,7 +332,7 @@ void DivPlatformSCC::reset() { for (int i=0; i<5; i++) { chan[i]=DivPlatformSCC::Channel(); chan[i].std.setEngine(parent); - chan[i].ws.setEngine(parent); + chan[i].ws.setEngine(parent,128); chan[i].ws.init(NULL,32,255,false); chan[i].vol=15; chan[i].outVol=15; diff --git a/src/engine/waveSynth.cpp b/src/engine/waveSynth.cpp index e69031686..82b5d5ddc 100644 --- a/src/engine/waveSynth.cpp +++ b/src/engine/waveSynth.cpp @@ -243,8 +243,13 @@ void DivWaveSynth::changeWave2(int num) { first=true; } -void DivWaveSynth::setEngine(DivEngine* engine) { +void DivWaveSynth::setEngine(DivEngine* engine, int waveFloor) { e=engine; + memset(wave1,waveFloor,256); + memset(wave2,waveFloor,256); + for (int i=0; i<256; i++) { + output[i]=waveFloor; + } } void DivWaveSynth::init(DivInstrument* which, int w, int h, bool insChanged) { diff --git a/src/engine/waveSynth.h b/src/engine/waveSynth.h index 8709b0846..26f5b259b 100644 --- a/src/engine/waveSynth.h +++ b/src/engine/waveSynth.h @@ -70,7 +70,7 @@ class DivWaveSynth { * @param insChanged whether the instrument has changed. */ void init(DivInstrument* which, int width, int height, bool insChanged=false); - void setEngine(DivEngine* engine); + void setEngine(DivEngine* engine, int waveFloor=0); DivWaveSynth(): e(NULL), pos(0), From 936d9dfa49f996910ff54b72abc3d13c8569865c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 9 Jun 2022 18:52:38 -0500 Subject: [PATCH 020/101] GUI: find and replace, part 6 --- src/gui/findReplace.cpp | 85 +++++++++++++++++++++++++++++++++++++---- src/gui/gui.cpp | 26 +++++++++++++ src/gui/gui.h | 2 +- src/gui/intConst.cpp | 1 + src/gui/intConst.h | 1 + 5 files changed, 106 insertions(+), 9 deletions(-) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 071d05ea0..7ac12d1de 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -3,6 +3,7 @@ #include "IconsFontAwesome4.h" #include "misc/cpp/imgui_stdlib.h" #include "guiConst.h" +#include "intConst.h" const char* queryModes[GUI_QUERY_MAX]={ "ignore", @@ -290,7 +291,11 @@ void FurnaceGUI::drawFindReplace() { curQuery.push_back(FurnaceGUIFindQuery()); } - if (ImGui::BeginTable("QueryLimits",2)) { + if (ImGui::BeginTable("QueryLimits",3)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.5f); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.5f); + ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -333,6 +338,7 @@ void FurnaceGUI::drawFindReplace() { } ImGui::EndDisabled(); + ImGui::TableNextColumn(); ImGui::Text("Match effect position:"); if (ImGui::RadioButton("No",curQueryEffectPos==0)) { @@ -356,8 +362,6 @@ void FurnaceGUI::drawFindReplace() { ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Checkbox("From start",&curQueryFromStart); - ImGui::TableNextColumn(); ImGui::Checkbox("Backwards",&curQueryBackwards); ImGui::EndTable(); @@ -373,10 +377,49 @@ void FurnaceGUI::drawFindReplace() { ImGui::TableNextColumn(); ImGui::Checkbox("Note",&queryReplaceNoteDo); ImGui::TableNextColumn(); + ImGui::BeginDisabled(!queryReplaceNoteDo); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::Combo("##NRMode",&queryReplaceNoteMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); ImGui::TableNextColumn(); - + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (queryReplaceNoteMode==GUI_QUERY_REPLACE_SET) { + if (queryReplaceNote==130) { + snprintf(tempID,1024,"REL"); + } else if (queryReplaceNote==129) { + snprintf(tempID,1024,"==="); + } else if (queryReplaceNote==128) { + snprintf(tempID,1024,"OFF"); + } else if (queryReplaceNote>=-60 && queryReplaceNote<120) { + snprintf(tempID,1024,"%s",noteNames[queryReplaceNote+60]); + } else { + snprintf(tempID,1024,"???"); + queryReplaceNote=0; + } + if (ImGui::BeginCombo("##NRValueC",tempID)) { + for (int j=0; j<180; j++) { + snprintf(tempID,1024,"%s",noteNames[j]); + if (ImGui::Selectable(tempID,queryReplaceNote==(j-60))) { + queryReplaceNote=j-60; + } + } + if (ImGui::Selectable("OFF",queryReplaceNote==128)) { + queryReplaceNote=128; + } + if (ImGui::Selectable("===",queryReplaceNote==129)) { + queryReplaceNote=129; + } + if (ImGui::Selectable("REL",queryReplaceNote==130)) { + queryReplaceNote=130; + } + ImGui::EndCombo(); + } + } else if (queryReplaceNoteMode==GUI_QUERY_REPLACE_ADD || queryReplaceNoteMode==GUI_QUERY_REPLACE_ADD_OVERFLOW) { + if (ImGui::InputInt("##NRValue",&queryReplaceNote,1,12)) { + if (queryReplaceNote<-180) queryReplaceNote=-180; + if (queryReplaceNote>180) queryReplaceNote=180; + } + } + ImGui::EndDisabled(); ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -384,6 +427,19 @@ void FurnaceGUI::drawFindReplace() { ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::Combo("##IRMode",&queryReplaceInsMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (queryReplaceInsMode==GUI_QUERY_REPLACE_SET) { + if (ImGui::InputScalar("##IRValueH",ImGuiDataType_S32,&queryReplaceIns,&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) { + if (queryReplaceIns<0) queryReplaceIns=0; + if (queryReplaceIns>255) queryReplaceIns=255; + } + } else if (queryReplaceInsMode==GUI_QUERY_REPLACE_ADD || queryReplaceInsMode==GUI_QUERY_REPLACE_ADD_OVERFLOW) { + if (ImGui::InputInt("##IRValue",&queryReplaceIns,1,12)) { + if (queryReplaceIns<-255) queryReplaceIns=-255; + if (queryReplaceIns>255) queryReplaceIns=255; + } + } ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -391,14 +447,27 @@ void FurnaceGUI::drawFindReplace() { ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::Combo("##VRMode",&queryReplaceVolMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); - - /*ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text("Effect"); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (queryReplaceVolMode==GUI_QUERY_REPLACE_SET) { + if (ImGui::InputScalar("##VRValueH",ImGuiDataType_S32,&queryReplaceVol,&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) { + if (queryReplaceVol<0) queryReplaceVol=0; + if (queryReplaceVol>255) queryReplaceVol=255; + } + } else if (queryReplaceVolMode==GUI_QUERY_REPLACE_ADD || queryReplaceVolMode==GUI_QUERY_REPLACE_ADD_OVERFLOW) { + if (ImGui::InputInt("##VRValue",&queryReplaceVol,1,12)) { + if (queryReplaceVol<-255) queryReplaceVol=-255; + if (queryReplaceVol>255) queryReplaceVol=255; + } + } ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text("Value");*/ + ImGui::Text("Later"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Later"); ImGui::EndTable(); } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index ed1805f7d..c1107d2e7 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4431,6 +4431,25 @@ FurnaceGUI::FurnaceGUI(): wavePreviewLen(32), wavePreviewHeight(255), wavePreviewInit(true), + pgSys(0), + pgAddr(0), + pgVal(0), + curQueryRangeX(false), + curQueryBackwards(false), + curQueryRangeXMin(0), curQueryRangeXMax(0), + curQueryRangeY(0), + curQueryEffectPos(0), + queryReplaceEffectCount(0), + queryReplaceEffectPos(0), + queryReplaceNoteMode(0), + queryReplaceInsMode(0), + queryReplaceVolMode(0), + queryReplaceNote(0), + queryReplaceIns(0), + queryReplaceVol(0), + queryReplaceNoteDo(false), + queryReplaceInsDo(false), + queryReplaceVolDo(false), wavePreviewOn(false), wavePreviewKey((SDL_Scancode)0), wavePreviewNote(0), @@ -4624,4 +4643,11 @@ FurnaceGUI::FurnaceGUI(): memset(pianoKeyHit,0,sizeof(float)*180); memset(pianoKeyPressed,0,sizeof(bool)*180); + + memset(queryReplaceEffectMode,0,sizeof(int)*8); + memset(queryReplaceEffectValMode,0,sizeof(int)*8); + memset(queryReplaceEffect,0,sizeof(int)*8); + memset(queryReplaceEffectVal,0,sizeof(int)*8); + memset(queryReplaceEffectDo,0,sizeof(bool)*8); + memset(queryReplaceEffectValDo,0,sizeof(bool)*8); } diff --git a/src/gui/gui.h b/src/gui/gui.h index 107deb9d2..8d565da28 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1171,7 +1171,7 @@ class FurnaceGUI { int pgSys, pgAddr, pgVal; std::vector curQuery; - bool curQueryRangeX, curQueryFromStart, curQueryBackwards; + bool curQueryRangeX, curQueryBackwards; int curQueryRangeXMin, curQueryRangeXMax; int curQueryRangeY; int curQueryEffectPos; diff --git a/src/gui/intConst.cpp b/src/gui/intConst.cpp index 9c7f53b94..8bee0f88c 100644 --- a/src/gui/intConst.cpp +++ b/src/gui/intConst.cpp @@ -25,6 +25,7 @@ const int _THREE=3; const int _SEVEN=7; const int _TEN=10; const int _FIFTEEN=15; +const int _SIXTEEN=16; const int _THIRTY_ONE=31; const int _SIXTY_FOUR=64; const int _ONE_HUNDRED=100; diff --git a/src/gui/intConst.h b/src/gui/intConst.h index c6b13b9af..98c6c34ff 100644 --- a/src/gui/intConst.h +++ b/src/gui/intConst.h @@ -27,6 +27,7 @@ extern const int _THREE; extern const int _SEVEN; extern const int _TEN; extern const int _FIFTEEN; +extern const int _SIXTEEN; extern const int _THIRTY_ONE; extern const int _SIXTY_FOUR; extern const int _ONE_HUNDRED; From 30bd73f83a5306fecfe2cc33591addf8f1f653cb Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 10 Jun 2022 02:17:17 -0500 Subject: [PATCH 021/101] GUI: find and replace, part 7 the next parts will be dedicated on getting it working --- src/gui/findReplace.cpp | 69 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 4 deletions(-) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 7ac12d1de..36048737e 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -425,6 +425,7 @@ void FurnaceGUI::drawFindReplace() { ImGui::TableNextColumn(); ImGui::Checkbox("Ins",&queryReplaceInsDo); ImGui::TableNextColumn(); + ImGui::BeginDisabled(!queryReplaceInsDo); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::Combo("##IRMode",&queryReplaceInsMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); ImGui::TableNextColumn(); @@ -440,11 +441,13 @@ void FurnaceGUI::drawFindReplace() { if (queryReplaceIns>255) queryReplaceIns=255; } } + ImGui::EndDisabled(); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Checkbox("Volume",&queryReplaceVolDo); ImGui::TableNextColumn(); + ImGui::BeginDisabled(!queryReplaceVolDo); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::Combo("##VRMode",&queryReplaceVolMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); ImGui::TableNextColumn(); @@ -460,14 +463,72 @@ void FurnaceGUI::drawFindReplace() { if (queryReplaceVol>255) queryReplaceVol=255; } } + ImGui::EndDisabled(); + + for (int i=0; i255) queryReplaceEffect[i]=255; + } + } else if (queryReplaceEffectMode[i]==GUI_QUERY_REPLACE_ADD || queryReplaceEffectMode[i]==GUI_QUERY_REPLACE_ADD_OVERFLOW) { + if (ImGui::InputInt("##ERValue",&queryReplaceEffect[i],1,12)) { + if (queryReplaceEffect[i]<-255) queryReplaceEffect[i]=-255; + if (queryReplaceEffect[i]>255) queryReplaceEffect[i]=255; + } + } + ImGui::EndDisabled(); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Checkbox("Value",&queryReplaceEffectValDo[i]); + ImGui::TableNextColumn(); + ImGui::BeginDisabled(!queryReplaceEffectValDo[i]); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##ERMode",&queryReplaceEffectValMode[i],queryReplaceModes,GUI_QUERY_REPLACE_MAX); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_SET) { + if (ImGui::InputScalar("##ERValueH",ImGuiDataType_S32,&queryReplaceEffectVal[i],&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) { + if (queryReplaceEffectVal[i]<0) queryReplaceEffectVal[i]=0; + if (queryReplaceEffectVal[i]>255) queryReplaceEffectVal[i]=255; + } + } else if (queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_ADD || queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_ADD_OVERFLOW) { + if (ImGui::InputInt("##ERValue",&queryReplaceEffectVal[i],1,12)) { + if (queryReplaceEffectVal[i]<-255) queryReplaceEffectVal[i]=-255; + if (queryReplaceEffectVal[i]>255) queryReplaceEffectVal[i]=255; + } + } + ImGui::EndDisabled(); + + + ImGui::PopID(); + } ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text("Later"); - - ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text("Later"); + if (queryReplaceEffectCount<8) { + if (ImGui::Button("Add effect")) { + queryReplaceEffectCount++; + } + } + ImGui::TableNextColumn(); + if (queryReplaceEffectCount>0) { + if (ImGui::Button("Remove effect")) { + queryReplaceEffectCount--; + } + } ImGui::EndTable(); } From fa9fb6f8f5e79488f4739b3497b6b74d10df4237 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 10 Jun 2022 18:27:47 -0500 Subject: [PATCH 022/101] GUI: find and replace, part 8 --- src/gui/findReplace.cpp | 127 ++++++++++++++++++++++++++++++++++++++++ src/gui/gui.h | 16 +++++ 2 files changed, 143 insertions(+) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 36048737e..a7dad8e83 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -22,6 +22,133 @@ const char* queryReplaceModes[GUI_QUERY_REPLACE_MAX]={ "clear" }; +int queryNote(int note, int octave) { + if (note==100) { + return 128; + } else if (note==101) { // note off and envelope release + return 129; + } else if (note==102) { // envelope release only + return 130; + } else if (octave==0 && note==0) { + return -1; + } else if (note==0 && octave!=0) { + return -1; // bug note? + } + int seek=(note+(signed char)octave*12); + if (seek<-60 || seek>=120) { + return -1; // out of range note + } + return seek; +} + +bool checkCondition(int mode, int arg, int argMax, int val, bool noteMode=false) { + switch (mode) { + case GUI_QUERY_IGNORE: + return true; + break; + case GUI_QUERY_MATCH: + return (val==arg); + break; + case GUI_QUERY_MATCH_NOT: + return (val!=-1 && val!=arg); + break; + case GUI_QUERY_RANGE: + return (val>=arg && val<=argMax); + break; + case GUI_QUERY_RANGE_NOT: + return (val!=-1 && (valargMax) && (!noteMode || val<120)); + break; + case GUI_QUERY_ANY: + return (val!=-1); + break; + case GUI_QUERY_NONE: + return (val==-1); + break; + } + return false; +} + +void FurnaceGUI::doFind() { + int firstOrder=0; + int lastOrder=e->curSubSong->ordersLen-1; + + if (curQueryRangeY==1 || curQueryRangeY==2) { + firstOrder=curOrder; + lastOrder=curOrder; + } + + int firstRow=0; + int lastRow=e->curSubSong->patLen-1; + + if (curQueryRangeY==1) { + firstRow=selStart.y; + lastRow=selEnd.y; + } + + int firstChan=0; + int lastChan=e->getTotalChannelCount()-1; + + if (curQueryRangeX) { + firstChan=curQueryRangeXMin; + lastChan=curQueryRangeXMax; + } + + curQueryResults.clear(); + + for (int i=firstOrder; i<=lastOrder; i++) { + for (int j=firstRow; j<=lastRow; j++) { + for (int k=firstChan; k<=lastChan; k++) { + DivPattern* p=e->curPat[k].getPattern(e->curOrders->ord[k][i],false); + bool matched=false; + for (FurnaceGUIFindQuery& l: curQuery) { + if (matched) break; + + if (!checkCondition(l.noteMode,l.note,l.noteMax,queryNote(p->data[j][0],p->data[j][1]),true)) continue; + if (!checkCondition(l.insMode,l.ins,l.insMax,p->data[j][2])) continue; + if (!checkCondition(l.volMode,l.vol,l.volMax,p->data[j][3])) continue; + + if (l.effectCount>0) { + bool notMatched=false; + switch (curQueryEffectPos) { + case 0: // no + // TODO + for (int m=0; mcurPat[k].effectCols; n++) { + if (!checkCondition(l.effectMode[m],l.effect[m],l.effectMax[m],p->data[j][4+m*2])) continue; + if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->data[j][5+m*2])) continue; + } + } + break; + case 1: // lax + break; + case 2: // strict + for (int m=0; mdata[j][4+m*2])) { + notMatched=true; + break; + } + if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->data[j][5+m*2])) { + notMatched=true; + break; + } + } + break; + } + if (notMatched) continue; + } + + matched=true; + } + if (matched) { + curQueryResults.push_back(FurnaceGUIQueryResult(e->getCurrentSubSong(),i,j,k)); + } + } + } + } + + printf("%d %d %d %d\n",firstOrder,lastOrder,firstRow,lastRow); +} + #define FIRST_VISIBLE(x) (x==GUI_QUERY_MATCH || x==GUI_QUERY_MATCH_NOT || x==GUI_QUERY_RANGE || x==GUI_QUERY_RANGE_NOT) #define SECOND_VISIBLE(x) (x==GUI_QUERY_RANGE || x==GUI_QUERY_RANGE_NOT) diff --git a/src/gui/gui.h b/src/gui/gui.h index 8d565da28..260a73419 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -856,6 +856,20 @@ struct FurnaceGUIFindQuery { } }; +struct FurnaceGUIQueryResult { + int subsong, order, x, y; + FurnaceGUIQueryResult(): + subsong(0), + order(0), + x(0), + y(0) {} + FurnaceGUIQueryResult(int ss, int o, int xPos, int yPos): + subsong(ss), + order(o), + x(xPos), + y(yPos) {} +}; + class FurnaceGUI { DivEngine* e; @@ -1171,6 +1185,7 @@ class FurnaceGUI { int pgSys, pgAddr, pgVal; std::vector curQuery; + std::vector curQueryResults; bool curQueryRangeX, curQueryBackwards; int curQueryRangeXMin, curQueryRangeXMax; int curQueryRangeY; @@ -1475,6 +1490,7 @@ class FurnaceGUI { void doExpand(int multiplier); void doUndo(); void doRedo(); + void doFind(); void editOptions(bool topMenu); void noteInput(int num, int key, int vol=-1); void valueInput(int num, bool direct=false, int target=-1); From 7354b1221ce7b9f554fabc78076ae7870e42b2c9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 11 Jun 2022 02:14:30 -0500 Subject: [PATCH 023/101] GUI: find and replace, part 9 --- src/gui/findReplace.cpp | 1022 +++++++++++++++++++++------------------ src/gui/gui.cpp | 1 + src/gui/gui.h | 1 + 3 files changed, 549 insertions(+), 475 deletions(-) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index a7dad8e83..700078bb5 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -4,6 +4,7 @@ #include "misc/cpp/imgui_stdlib.h" #include "guiConst.h" #include "intConst.h" +#include "../ta-log.h" const char* queryModes[GUI_QUERY_MAX]={ "ignore", @@ -140,13 +141,12 @@ void FurnaceGUI::doFind() { matched=true; } if (matched) { - curQueryResults.push_back(FurnaceGUIQueryResult(e->getCurrentSubSong(),i,j,k)); + curQueryResults.push_back(FurnaceGUIQueryResult(e->getCurrentSubSong(),i,k,j)); } } } } - - printf("%d %d %d %d\n",firstOrder,lastOrder,firstRow,lastRow); + queryViewingResults=true; } #define FIRST_VISIBLE(x) (x==GUI_QUERY_MATCH || x==GUI_QUERY_MATCH_NOT || x==GUI_QUERY_RANGE || x==GUI_QUERY_RANGE_NOT) @@ -167,515 +167,587 @@ void FurnaceGUI::drawFindReplace() { int index=0; int eraseIndex=-1; char tempID[1024]; - for (FurnaceGUIFindQuery& i: curQuery) { - if (ImGui::BeginTable("FindRep",4,ImGuiTableFlags_BordersOuter)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.5); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.25); - ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.25); - ImGui::PushID(index); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Note"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::Combo("##NCondition",&i.noteMode,queryModes,GUI_QUERY_MAX); - ImGui::TableNextColumn(); - if (FIRST_VISIBLE(i.noteMode)) { - if ((i.noteMode==GUI_QUERY_RANGE || i.noteMode==GUI_QUERY_RANGE_NOT) && i.note>=120) { - i.note=0; - } - if (i.note==130) { - snprintf(tempID,1024,"REL"); - } else if (i.note==129) { - snprintf(tempID,1024,"==="); - } else if (i.note==128) { - snprintf(tempID,1024,"OFF"); - } else if (i.note>=-60 && i.note<120) { - snprintf(tempID,1024,"%s",noteNames[i.note+60]); + if (ImGui::BeginTabBar("FindOrReplace")) { + if (ImGui::BeginTabItem("Find")) { + if (queryViewingResults) { + if (!curQueryResults.empty()) { + ImVec2 avail=ImGui::GetContentRegionAvail(); + avail.y-=ImGui::GetFrameHeightWithSpacing(); + if (ImGui::BeginTable("FindResults",4,ImGuiTableFlags_Borders|ImGuiTableFlags_ScrollY,avail)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,ImGui::CalcTextSize("order").x); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,ImGui::CalcTextSize("row").x); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed); + + ImGui::TableSetupScrollFreeze(0,1); + + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::Text("order"); + ImGui::TableNextColumn(); + ImGui::Text("row"); + ImGui::TableNextColumn(); + ImGui::Text("channel"); + ImGui::TableNextColumn(); + ImGui::Text("go"); + + int index=0; + for (FurnaceGUIQueryResult& i: curQueryResults) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (settings.orderRowsBase==1) { + ImGui::Text("%.2X",i.order); + } else { + ImGui::Text("%d",i.order); + } + ImGui::TableNextColumn(); + if (settings.patRowsBase==1) { + ImGui::Text("%.2X",i.y); + } else { + ImGui::Text("%d",i.y); + } + ImGui::TableNextColumn(); + ImGui::Text("%d (%s)",i.x+1,e->getChannelName(i.x)); + if (ImGui::TableNextColumn()) { + snprintf(tempID,1024,ICON_FA_CHEVRON_RIGHT "##_FR%d",index); + if (ImGui::Selectable(tempID)) { + e->changeSongP(i.subsong); + if (e->isPlaying()) { + followPattern=false; + } else { + e->setOrder(i.order); + } + curOrder=i.order; + cursor.xCoarse=i.x; + cursor.xFine=0; + cursor.y=i.y; + selStart=cursor; + selEnd=cursor; + demandScrollX=true; + updateScroll(cursor.y); + nextWindow=GUI_WINDOW_PATTERN; + } + } + index++; + } + ImGui::EndTable(); + } } else { - snprintf(tempID,1024,"???"); - i.note=0; + ImGui::Text("no matches found!"); } - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("##NN1",tempID)) { - for (int j=0; j<180; j++) { - snprintf(tempID,1024,"%s",noteNames[j]); - if (ImGui::Selectable(tempID,i.note==(j-60))) { - i.note=j-60; - } - } - if (i.noteMode!=GUI_QUERY_RANGE && i.noteMode!=GUI_QUERY_RANGE_NOT) { - if (ImGui::Selectable("OFF",i.note==128)) { - i.note=128; - } - if (ImGui::Selectable("===",i.note==129)) { - i.note=129; - } - if (ImGui::Selectable("REL",i.note==130)) { - i.note=130; - } - } - ImGui::EndCombo(); + if (ImGui::Button("Back")) { + queryViewingResults=false; } - } - ImGui::TableNextColumn(); - if (SECOND_VISIBLE(i.noteMode)) { - if (i.noteMax<-60 || i.noteMax>=120) { - i.noteMax=0; - } - if (i.noteMax>=-60 && i.noteMax<120) { - snprintf(tempID,1024,"%s",noteNames[i.noteMax+60]); - } else { - snprintf(tempID,1024,"???"); - } - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("##NN2",tempID)) { - for (int j=0; j<180; j++) { - snprintf(tempID,1024,"%s",noteNames[j]); - if (ImGui::Selectable(tempID,i.noteMax==(j-60))) { - i.noteMax=j-60; + } else { + for (FurnaceGUIFindQuery& i: curQuery) { + ImGui::PushID(index+0x100); + if (ImGui::BeginTable("FindRep",4,ImGuiTableFlags_BordersOuter)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.5); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.25); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.25); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Note"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##NCondition",&i.noteMode,queryModes,GUI_QUERY_MAX); + ImGui::TableNextColumn(); + if (FIRST_VISIBLE(i.noteMode)) { + if ((i.noteMode==GUI_QUERY_RANGE || i.noteMode==GUI_QUERY_RANGE_NOT) && i.note>=120) { + i.note=0; + } + if (i.note==130) { + snprintf(tempID,1024,"REL"); + } else if (i.note==129) { + snprintf(tempID,1024,"==="); + } else if (i.note==128) { + snprintf(tempID,1024,"OFF"); + } else if (i.note>=-60 && i.note<120) { + snprintf(tempID,1024,"%s",noteNames[i.note+60]); + } else { + snprintf(tempID,1024,"???"); + i.note=0; + } + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("##NN1",tempID)) { + for (int j=0; j<180; j++) { + snprintf(tempID,1024,"%s",noteNames[j]); + if (ImGui::Selectable(tempID,i.note==(j-60))) { + i.note=j-60; + } + } + if (i.noteMode!=GUI_QUERY_RANGE && i.noteMode!=GUI_QUERY_RANGE_NOT) { + if (ImGui::Selectable("OFF",i.note==128)) { + i.note=128; + } + if (ImGui::Selectable("===",i.note==129)) { + i.note=129; + } + if (ImGui::Selectable("REL",i.note==130)) { + i.note=130; + } + } + ImGui::EndCombo(); + } + } + ImGui::TableNextColumn(); + if (SECOND_VISIBLE(i.noteMode)) { + if (i.noteMax<-60 || i.noteMax>=120) { + i.noteMax=0; + } + if (i.noteMax>=-60 && i.noteMax<120) { + snprintf(tempID,1024,"%s",noteNames[i.noteMax+60]); + } else { + snprintf(tempID,1024,"???"); + } + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("##NN2",tempID)) { + for (int j=0; j<180; j++) { + snprintf(tempID,1024,"%s",noteNames[j]); + if (ImGui::Selectable(tempID,i.noteMax==(j-60))) { + i.noteMax=j-60; + } + } + ImGui::EndCombo(); + } } - } - ImGui::EndCombo(); - } - } - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Ins"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::Combo("##ICondition",&i.insMode,queryModes,GUI_QUERY_MAX); - ImGui::TableNextColumn(); - if (FIRST_VISIBLE(i.insMode)) { - snprintf(tempID,1024,"%.2X",i.ins); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("II1",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.ins==j)) { - i.ins=j; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Ins"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##ICondition",&i.insMode,queryModes,GUI_QUERY_MAX); + ImGui::TableNextColumn(); + if (FIRST_VISIBLE(i.insMode)) { + snprintf(tempID,1024,"%.2X",i.ins); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("II1",tempID)) { + for (int j=0; j<256; j++) { + snprintf(tempID,1024,"%.2X",j); + if (ImGui::Selectable(tempID,i.ins==j)) { + i.ins=j; + } + } + ImGui::EndCombo(); + } } - } - ImGui::EndCombo(); - } - } - ImGui::TableNextColumn(); - if (SECOND_VISIBLE(i.insMode)) { - snprintf(tempID,1024,"%.2X",i.insMax); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("II2",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.insMax==j)) { - i.insMax=j; + ImGui::TableNextColumn(); + if (SECOND_VISIBLE(i.insMode)) { + snprintf(tempID,1024,"%.2X",i.insMax); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("II2",tempID)) { + for (int j=0; j<256; j++) { + snprintf(tempID,1024,"%.2X",j); + if (ImGui::Selectable(tempID,i.insMax==j)) { + i.insMax=j; + } + } + ImGui::EndCombo(); + } } - } - ImGui::EndCombo(); - } - } - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Volume"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::Combo("##VCondition",&i.volMode,queryModes,GUI_QUERY_MAX); - ImGui::TableNextColumn(); - if (FIRST_VISIBLE(i.volMode)) { - snprintf(tempID,1024,"%.2X",i.vol); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("VV1",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.vol==j)) { - i.vol=j; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Volume"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##VCondition",&i.volMode,queryModes,GUI_QUERY_MAX); + ImGui::TableNextColumn(); + if (FIRST_VISIBLE(i.volMode)) { + snprintf(tempID,1024,"%.2X",i.vol); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("VV1",tempID)) { + for (int j=0; j<256; j++) { + snprintf(tempID,1024,"%.2X",j); + if (ImGui::Selectable(tempID,i.vol==j)) { + i.vol=j; + } + } + ImGui::EndCombo(); + } } - } - ImGui::EndCombo(); - } - } - ImGui::TableNextColumn(); - if (SECOND_VISIBLE(i.volMode)) { - snprintf(tempID,1024,"%.2X",i.volMax); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("VV2",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.volMax==j)) { - i.volMax=j; + ImGui::TableNextColumn(); + if (SECOND_VISIBLE(i.volMode)) { + snprintf(tempID,1024,"%.2X",i.volMax); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("VV2",tempID)) { + for (int j=0; j<256; j++) { + snprintf(tempID,1024,"%.2X",j); + if (ImGui::Selectable(tempID,i.volMax==j)) { + i.volMax=j; + } + } + ImGui::EndCombo(); + } } - } - ImGui::EndCombo(); - } - } - for (int j=0; j0) { + if (ImGui::Button("Remove effect")) { + i.effectCount--; + } + } + ImGui::EndTable(); + } + ImGui::PopID(); + index++; + } + if (eraseIndex>=0) { + curQuery.erase(curQuery.begin()+eraseIndex); + } + if (ImGui::Button(ICON_FA_PLUS "##AddQuery")) { + curQuery.push_back(FurnaceGUIFindQuery()); + } + + if (ImGui::BeginTable("QueryLimits",3)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.5f); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.5f); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::Text("Search range:"); + + if (ImGui::RadioButton("Song",curQueryRangeY==0)) { + curQueryRangeY=0; + } + if (ImGui::RadioButton("Selection",curQueryRangeY==1)) { + curQueryRangeY=1; + } + if (ImGui::RadioButton("Pattern",curQueryRangeY==2)) { + curQueryRangeY=2; + } + + ImGui::TableNextColumn(); + ImGui::Checkbox("Confine to channels",&curQueryRangeX); + + ImGui::BeginDisabled(!curQueryRangeX); + snprintf(tempID,1024,"%d: %s",curQueryRangeXMin+1,e->getChannelName(curQueryRangeXMin)); + if (ImGui::BeginCombo("From",tempID)) { + for (int i=0; igetTotalChannelCount(); i++) { + snprintf(tempID,1024,"%d: %s",i+1,e->getChannelName(i)); + if (ImGui::Selectable(tempID,curQueryRangeXMin==i)) { + curQueryRangeXMin=i; + } + } + ImGui::EndCombo(); + } + + snprintf(tempID,1024,"%d: %s",curQueryRangeXMax+1,e->getChannelName(curQueryRangeXMax)); + if (ImGui::BeginCombo("To",tempID)) { + for (int i=0; igetTotalChannelCount(); i++) { + snprintf(tempID,1024,"%d: %s",i+1,e->getChannelName(i)); + if (ImGui::Selectable(tempID,curQueryRangeXMax==i)) { + curQueryRangeXMax=i; + } + } + ImGui::EndCombo(); + } + ImGui::EndDisabled(); + + ImGui::TableNextColumn(); + ImGui::Text("Match effect position:"); + + if (ImGui::RadioButton("No",curQueryEffectPos==0)) { + curQueryEffectPos=0; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("match effects regardless of position."); + } + if (ImGui::RadioButton("Lax",curQueryEffectPos==1)) { + curQueryEffectPos=1; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("match effects only if they appear in-order."); + } + if (ImGui::RadioButton("Strict",curQueryEffectPos==2)) { + curQueryEffectPos=2; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("match effects only if they appear exactly as specified."); + } + + ImGui::EndTable(); + } + + if (ImGui::Button("Find")) { + doFind(); + } + } + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Replace")) { + if (ImGui::BeginTable("QueryReplace",3,ImGuiTableFlags_BordersOuter)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.5); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.5); + ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text("Effect"); + ImGui::Checkbox("Note",&queryReplaceNoteDo); + ImGui::TableNextColumn(); + ImGui::BeginDisabled(!queryReplaceNoteDo); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##NRMode",&queryReplaceNoteMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::Combo("##ECondition",&i.effectMode[j],queryModes,GUI_QUERY_MAX); - ImGui::TableNextColumn(); - if (FIRST_VISIBLE(i.effectMode[j])) { - snprintf(tempID,1024,"%.2X",i.effect[j]); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("EE1",tempID)) { - for (int k=0; k<256; k++) { - snprintf(tempID,1024,"%.2X",k); - if (ImGui::Selectable(tempID,i.effect[j]==k)) { - i.effect[j]=k; + if (queryReplaceNoteMode==GUI_QUERY_REPLACE_SET) { + if (queryReplaceNote==130) { + snprintf(tempID,1024,"REL"); + } else if (queryReplaceNote==129) { + snprintf(tempID,1024,"==="); + } else if (queryReplaceNote==128) { + snprintf(tempID,1024,"OFF"); + } else if (queryReplaceNote>=-60 && queryReplaceNote<120) { + snprintf(tempID,1024,"%s",noteNames[queryReplaceNote+60]); + } else { + snprintf(tempID,1024,"???"); + queryReplaceNote=0; + } + if (ImGui::BeginCombo("##NRValueC",tempID)) { + for (int j=0; j<180; j++) { + snprintf(tempID,1024,"%s",noteNames[j]); + if (ImGui::Selectable(tempID,queryReplaceNote==(j-60))) { + queryReplaceNote=j-60; } } + if (ImGui::Selectable("OFF",queryReplaceNote==128)) { + queryReplaceNote=128; + } + if (ImGui::Selectable("===",queryReplaceNote==129)) { + queryReplaceNote=129; + } + if (ImGui::Selectable("REL",queryReplaceNote==130)) { + queryReplaceNote=130; + } ImGui::EndCombo(); } - } - ImGui::TableNextColumn(); - if (SECOND_VISIBLE(i.effectMode[j])) { - snprintf(tempID,1024,"%.2X",i.effectMax[j]); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("EE2",tempID)) { - for (int k=0; k<256; k++) { - snprintf(tempID,1024,"%.2X",k); - if (ImGui::Selectable(tempID,i.effectMax[j]==k)) { - i.effectMax[j]=k; - } - } - ImGui::EndCombo(); - } - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Value"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::Combo("##EVCondition",&i.effectValMode[j],queryModes,GUI_QUERY_MAX); - ImGui::TableNextColumn(); - if (FIRST_VISIBLE(i.effectValMode[j])) { - snprintf(tempID,1024,"%.2X",i.effectVal[j]); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("EV1",tempID)) { - for (int k=0; k<256; k++) { - snprintf(tempID,1024,"%.2X",k); - if (ImGui::Selectable(tempID,i.effectVal[j]==k)) { - i.effectVal[j]=k; - } - } - ImGui::EndCombo(); - } - } - ImGui::TableNextColumn(); - if (SECOND_VISIBLE(i.effectValMode[j])) { - snprintf(tempID,1024,"%.2X",i.effectValMax[j]); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("EV2",tempID)) { - for (int k=0; k<256; k++) { - snprintf(tempID,1024,"%.2X",k); - if (ImGui::Selectable(tempID,i.effectValMax[j]==k)) { - i.effectValMax[j]=k; - } - } - ImGui::EndCombo(); - } - } - - ImGui::PopID(); - } - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - if (ImGui::Button(ICON_FA_MINUS "##DelQuery")) { - eraseIndex=index; - } - ImGui::TableNextColumn(); - if (i.effectCount<8) { - if (ImGui::Button("Add effect")) { - i.effectCount++; - } - } - ImGui::TableNextColumn(); - if (i.effectCount>0) { - if (ImGui::Button("Remove effect")) { - i.effectCount--; - } - } - ImGui::PopID(); - ImGui::EndTable(); - } - index++; - } - if (ImGui::Button("Find")) { - - } - ImGui::SameLine(); - if (eraseIndex>=0) { - curQuery.erase(curQuery.begin()+eraseIndex); - } - if (ImGui::Button(ICON_FA_PLUS "##AddQuery")) { - curQuery.push_back(FurnaceGUIFindQuery()); - } - - if (ImGui::BeginTable("QueryLimits",3)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.5f); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.5f); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - - ImGui::Text("Search range:"); - - if (ImGui::RadioButton("Song",curQueryRangeY==0)) { - curQueryRangeY=0; - } - if (ImGui::RadioButton("Selection",curQueryRangeY==1)) { - curQueryRangeY=1; - } - if (ImGui::RadioButton("Pattern",curQueryRangeY==2)) { - curQueryRangeY=2; - } - - ImGui::TableNextColumn(); - ImGui::Checkbox("Confine to channels",&curQueryRangeX); - - ImGui::BeginDisabled(!curQueryRangeX); - snprintf(tempID,1024,"%d: %s",curQueryRangeXMin+1,e->getChannelName(curQueryRangeXMin)); - if (ImGui::BeginCombo("From",tempID)) { - for (int i=0; igetTotalChannelCount(); i++) { - snprintf(tempID,1024,"%d: %s",i+1,e->getChannelName(i)); - if (ImGui::Selectable(tempID,curQueryRangeXMin==i)) { - curQueryRangeXMin=i; - } - } - ImGui::EndCombo(); - } - - snprintf(tempID,1024,"%d: %s",curQueryRangeXMax+1,e->getChannelName(curQueryRangeXMax)); - if (ImGui::BeginCombo("To",tempID)) { - for (int i=0; igetTotalChannelCount(); i++) { - snprintf(tempID,1024,"%d: %s",i+1,e->getChannelName(i)); - if (ImGui::Selectable(tempID,curQueryRangeXMax==i)) { - curQueryRangeXMax=i; - } - } - ImGui::EndCombo(); - } - ImGui::EndDisabled(); - - ImGui::TableNextColumn(); - ImGui::Text("Match effect position:"); - - if (ImGui::RadioButton("No",curQueryEffectPos==0)) { - curQueryEffectPos=0; - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("match effects regardless of position."); - } - if (ImGui::RadioButton("Lax",curQueryEffectPos==1)) { - curQueryEffectPos=1; - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("match effects only if they appear in-order."); - } - if (ImGui::RadioButton("Strict",curQueryEffectPos==2)) { - curQueryEffectPos=2; - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("match effects only if they appear exactly as specified."); - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Checkbox("Backwards",&curQueryBackwards); - - ImGui::EndTable(); - } - - if (ImGui::TreeNode("Replace")) { - if (ImGui::BeginTable("QueryReplace",3,ImGuiTableFlags_BordersOuter)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.5); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.5); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Checkbox("Note",&queryReplaceNoteDo); - ImGui::TableNextColumn(); - ImGui::BeginDisabled(!queryReplaceNoteDo); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::Combo("##NRMode",&queryReplaceNoteMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (queryReplaceNoteMode==GUI_QUERY_REPLACE_SET) { - if (queryReplaceNote==130) { - snprintf(tempID,1024,"REL"); - } else if (queryReplaceNote==129) { - snprintf(tempID,1024,"==="); - } else if (queryReplaceNote==128) { - snprintf(tempID,1024,"OFF"); - } else if (queryReplaceNote>=-60 && queryReplaceNote<120) { - snprintf(tempID,1024,"%s",noteNames[queryReplaceNote+60]); - } else { - snprintf(tempID,1024,"???"); - queryReplaceNote=0; - } - if (ImGui::BeginCombo("##NRValueC",tempID)) { - for (int j=0; j<180; j++) { - snprintf(tempID,1024,"%s",noteNames[j]); - if (ImGui::Selectable(tempID,queryReplaceNote==(j-60))) { - queryReplaceNote=j-60; - } - } - if (ImGui::Selectable("OFF",queryReplaceNote==128)) { - queryReplaceNote=128; - } - if (ImGui::Selectable("===",queryReplaceNote==129)) { - queryReplaceNote=129; - } - if (ImGui::Selectable("REL",queryReplaceNote==130)) { - queryReplaceNote=130; - } - ImGui::EndCombo(); - } - } else if (queryReplaceNoteMode==GUI_QUERY_REPLACE_ADD || queryReplaceNoteMode==GUI_QUERY_REPLACE_ADD_OVERFLOW) { - if (ImGui::InputInt("##NRValue",&queryReplaceNote,1,12)) { - if (queryReplaceNote<-180) queryReplaceNote=-180; - if (queryReplaceNote>180) queryReplaceNote=180; - } - } - ImGui::EndDisabled(); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Checkbox("Ins",&queryReplaceInsDo); - ImGui::TableNextColumn(); - ImGui::BeginDisabled(!queryReplaceInsDo); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::Combo("##IRMode",&queryReplaceInsMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (queryReplaceInsMode==GUI_QUERY_REPLACE_SET) { - if (ImGui::InputScalar("##IRValueH",ImGuiDataType_S32,&queryReplaceIns,&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) { - if (queryReplaceIns<0) queryReplaceIns=0; - if (queryReplaceIns>255) queryReplaceIns=255; - } - } else if (queryReplaceInsMode==GUI_QUERY_REPLACE_ADD || queryReplaceInsMode==GUI_QUERY_REPLACE_ADD_OVERFLOW) { - if (ImGui::InputInt("##IRValue",&queryReplaceIns,1,12)) { - if (queryReplaceIns<-255) queryReplaceIns=-255; - if (queryReplaceIns>255) queryReplaceIns=255; - } - } - ImGui::EndDisabled(); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Checkbox("Volume",&queryReplaceVolDo); - ImGui::TableNextColumn(); - ImGui::BeginDisabled(!queryReplaceVolDo); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::Combo("##VRMode",&queryReplaceVolMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (queryReplaceVolMode==GUI_QUERY_REPLACE_SET) { - if (ImGui::InputScalar("##VRValueH",ImGuiDataType_S32,&queryReplaceVol,&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) { - if (queryReplaceVol<0) queryReplaceVol=0; - if (queryReplaceVol>255) queryReplaceVol=255; - } - } else if (queryReplaceVolMode==GUI_QUERY_REPLACE_ADD || queryReplaceVolMode==GUI_QUERY_REPLACE_ADD_OVERFLOW) { - if (ImGui::InputInt("##VRValue",&queryReplaceVol,1,12)) { - if (queryReplaceVol<-255) queryReplaceVol=-255; - if (queryReplaceVol>255) queryReplaceVol=255; - } - } - ImGui::EndDisabled(); - - for (int i=0; i255) queryReplaceEffect[i]=255; - } - } else if (queryReplaceEffectMode[i]==GUI_QUERY_REPLACE_ADD || queryReplaceEffectMode[i]==GUI_QUERY_REPLACE_ADD_OVERFLOW) { - if (ImGui::InputInt("##ERValue",&queryReplaceEffect[i],1,12)) { - if (queryReplaceEffect[i]<-255) queryReplaceEffect[i]=-255; - if (queryReplaceEffect[i]>255) queryReplaceEffect[i]=255; + } else if (queryReplaceNoteMode==GUI_QUERY_REPLACE_ADD || queryReplaceNoteMode==GUI_QUERY_REPLACE_ADD_OVERFLOW) { + if (ImGui::InputInt("##NRValue",&queryReplaceNote,1,12)) { + if (queryReplaceNote<-180) queryReplaceNote=-180; + if (queryReplaceNote>180) queryReplaceNote=180; } } ImGui::EndDisabled(); ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Checkbox("Value",&queryReplaceEffectValDo[i]); + ImGui::Checkbox("Ins",&queryReplaceInsDo); ImGui::TableNextColumn(); - ImGui::BeginDisabled(!queryReplaceEffectValDo[i]); + ImGui::BeginDisabled(!queryReplaceInsDo); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::Combo("##ERMode",&queryReplaceEffectValMode[i],queryReplaceModes,GUI_QUERY_REPLACE_MAX); + ImGui::Combo("##IRMode",&queryReplaceInsMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_SET) { - if (ImGui::InputScalar("##ERValueH",ImGuiDataType_S32,&queryReplaceEffectVal[i],&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) { - if (queryReplaceEffectVal[i]<0) queryReplaceEffectVal[i]=0; - if (queryReplaceEffectVal[i]>255) queryReplaceEffectVal[i]=255; + if (queryReplaceInsMode==GUI_QUERY_REPLACE_SET) { + if (ImGui::InputScalar("##IRValueH",ImGuiDataType_S32,&queryReplaceIns,&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) { + if (queryReplaceIns<0) queryReplaceIns=0; + if (queryReplaceIns>255) queryReplaceIns=255; } - } else if (queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_ADD || queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_ADD_OVERFLOW) { - if (ImGui::InputInt("##ERValue",&queryReplaceEffectVal[i],1,12)) { - if (queryReplaceEffectVal[i]<-255) queryReplaceEffectVal[i]=-255; - if (queryReplaceEffectVal[i]>255) queryReplaceEffectVal[i]=255; + } else if (queryReplaceInsMode==GUI_QUERY_REPLACE_ADD || queryReplaceInsMode==GUI_QUERY_REPLACE_ADD_OVERFLOW) { + if (ImGui::InputInt("##IRValue",&queryReplaceIns,1,12)) { + if (queryReplaceIns<-255) queryReplaceIns=-255; + if (queryReplaceIns>255) queryReplaceIns=255; } } ImGui::EndDisabled(); - - ImGui::PopID(); - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TableNextColumn(); - if (queryReplaceEffectCount<8) { - if (ImGui::Button("Add effect")) { - queryReplaceEffectCount++; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Checkbox("Volume",&queryReplaceVolDo); + ImGui::TableNextColumn(); + ImGui::BeginDisabled(!queryReplaceVolDo); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##VRMode",&queryReplaceVolMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (queryReplaceVolMode==GUI_QUERY_REPLACE_SET) { + if (ImGui::InputScalar("##VRValueH",ImGuiDataType_S32,&queryReplaceVol,&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) { + if (queryReplaceVol<0) queryReplaceVol=0; + if (queryReplaceVol>255) queryReplaceVol=255; + } + } else if (queryReplaceVolMode==GUI_QUERY_REPLACE_ADD || queryReplaceVolMode==GUI_QUERY_REPLACE_ADD_OVERFLOW) { + if (ImGui::InputInt("##VRValue",&queryReplaceVol,1,12)) { + if (queryReplaceVol<-255) queryReplaceVol=-255; + if (queryReplaceVol>255) queryReplaceVol=255; + } } - } - ImGui::TableNextColumn(); - if (queryReplaceEffectCount>0) { - if (ImGui::Button("Remove effect")) { - queryReplaceEffectCount--; - } - } + ImGui::EndDisabled(); - ImGui::EndTable(); + for (int i=0; i255) queryReplaceEffect[i]=255; + } + } else if (queryReplaceEffectMode[i]==GUI_QUERY_REPLACE_ADD || queryReplaceEffectMode[i]==GUI_QUERY_REPLACE_ADD_OVERFLOW) { + if (ImGui::InputInt("##ERValue",&queryReplaceEffect[i],1,12)) { + if (queryReplaceEffect[i]<-255) queryReplaceEffect[i]=-255; + if (queryReplaceEffect[i]>255) queryReplaceEffect[i]=255; + } + } + ImGui::EndDisabled(); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Checkbox("Value",&queryReplaceEffectValDo[i]); + ImGui::TableNextColumn(); + ImGui::BeginDisabled(!queryReplaceEffectValDo[i]); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##ERMode",&queryReplaceEffectValMode[i],queryReplaceModes,GUI_QUERY_REPLACE_MAX); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_SET) { + if (ImGui::InputScalar("##ERValueH",ImGuiDataType_S32,&queryReplaceEffectVal[i],&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) { + if (queryReplaceEffectVal[i]<0) queryReplaceEffectVal[i]=0; + if (queryReplaceEffectVal[i]>255) queryReplaceEffectVal[i]=255; + } + } else if (queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_ADD || queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_ADD_OVERFLOW) { + if (ImGui::InputInt("##ERValue",&queryReplaceEffectVal[i],1,12)) { + if (queryReplaceEffectVal[i]<-255) queryReplaceEffectVal[i]=-255; + if (queryReplaceEffectVal[i]>255) queryReplaceEffectVal[i]=255; + } + } + ImGui::EndDisabled(); + + + ImGui::PopID(); + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TableNextColumn(); + if (queryReplaceEffectCount<8) { + if (ImGui::Button("Add effect")) { + queryReplaceEffectCount++; + } + } + ImGui::TableNextColumn(); + if (queryReplaceEffectCount>0) { + if (ImGui::Button("Remove effect")) { + queryReplaceEffectCount--; + } + } + + ImGui::EndTable(); + } + ImGui::Text("Effect replace mode:"); + if (ImGui::RadioButton("Clear effects",queryReplaceEffectPos==0)) { + queryReplaceEffectPos=0; + } + if (ImGui::RadioButton("Replace matches only",queryReplaceEffectPos==1)) { + queryReplaceEffectPos=1; + } + if (ImGui::RadioButton("Replace matches, then free spaces",queryReplaceEffectPos==2)) { + queryReplaceEffectPos=2; + } + if (ImGui::RadioButton("Insert in free spaces",queryReplaceEffectPos==3)) { + queryReplaceEffectPos=3; + } + if (ImGui::Button("Replace##QueryReplace")) { + // TODO + } + ImGui::EndTabItem(); } - ImGui::Text("Effect replace mode:"); - if (ImGui::RadioButton("Clear effects",queryReplaceEffectPos==0)) { - queryReplaceEffectPos=0; - } - if (ImGui::RadioButton("Replace matches only",queryReplaceEffectPos==1)) { - queryReplaceEffectPos=1; - } - if (ImGui::RadioButton("Replace matches, then free spaces",queryReplaceEffectPos==2)) { - queryReplaceEffectPos=2; - } - if (ImGui::RadioButton("Insert in free spaces",queryReplaceEffectPos==3)) { - queryReplaceEffectPos=3; - } - if (ImGui::Button("Replace##QueryReplace")) { - // TODO - } - ImGui::TreePop(); + ImGui::EndTabBar(); } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_FIND; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index c1107d2e7..b982987c3 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4450,6 +4450,7 @@ FurnaceGUI::FurnaceGUI(): queryReplaceNoteDo(false), queryReplaceInsDo(false), queryReplaceVolDo(false), + queryViewingResults(false), wavePreviewOn(false), wavePreviewKey((SDL_Scancode)0), wavePreviewNote(0), diff --git a/src/gui/gui.h b/src/gui/gui.h index 260a73419..300fa8fca 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1208,6 +1208,7 @@ class FurnaceGUI { bool queryReplaceVolDo; bool queryReplaceEffectDo[8]; bool queryReplaceEffectValDo[8]; + bool queryViewingResults; struct ActiveNote { int chan; From 44341d8ccd6134b44a44f28fd7e4b177eaa65c37 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 11 Jun 2022 03:53:34 -0500 Subject: [PATCH 024/101] GUI: find and replace, part 10 find kind of works (only lax mode left to do) then i'll do replace --- src/gui/findReplace.cpp | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 700078bb5..77c1a7e3a 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -112,25 +112,36 @@ void FurnaceGUI::doFind() { bool notMatched=false; switch (curQueryEffectPos) { case 0: // no - // TODO for (int m=0; mcurPat[k].effectCols; n++) { - if (!checkCondition(l.effectMode[m],l.effect[m],l.effectMax[m],p->data[j][4+m*2])) continue; - if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->data[j][5+m*2])) continue; + if (!checkCondition(l.effectMode[m],l.effect[m],l.effectMax[m],p->data[j][4+n*2])) continue; + if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->data[j][5+n*2])) continue; + allGood=true; + break; + } + if (!allGood) { + notMatched=true; + break; } } break; case 1: // lax break; case 2: // strict - for (int m=0; mdata[j][4+m*2])) { - notMatched=true; - break; - } - if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->data[j][5+m*2])) { - notMatched=true; - break; + int effectMax=l.effectCount; + if (effectMax>e->curPat[k].effectCols) { + notMatched=true; + } else { + for (int m=0; mdata[j][4+m*2])) { + notMatched=true; + break; + } + if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->data[j][5+m*2])) { + notMatched=true; + break; + } } } break; From 3ebbb85f4c265c9106a8612761484fe619259fb2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 11 Jun 2022 22:36:49 -0500 Subject: [PATCH 025/101] add another demo song MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit requested by AURORA✭FIELDS --- demos/Funky_Bubbles_OPL3.fur | Bin 0 -> 6660 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/Funky_Bubbles_OPL3.fur diff --git a/demos/Funky_Bubbles_OPL3.fur b/demos/Funky_Bubbles_OPL3.fur new file mode 100644 index 0000000000000000000000000000000000000000..5f2ffd24433d6661622af33ad8ab6daad526d037 GIT binary patch literal 6660 zcma)9cTm$^v!)XSLKG>H4ljaA73n2Xq=*m|cmV}MM-=IukWiG+qzZ_D0Yp%dCQVvG z1gRoTqzIwcPy>Mk0$e`tJM+!`?)~G=oS8G{nLYd4XMa2U>Z#FfeX*+B-Qt|j>Sfg9<+9duk z6nn51&|(Q2o(fCyEU&2P_ouR!Cgk+yX}Zz0qWg=f44l%Zh+Z}j^Y?Ed2~?6U}}lF4f1H1 z=9F4Zb9&$qQ6|JZMiHIeVWlxZu*}3k>2gD|XRx;y$cho@(|`yVg*{>v$vOkIqbK(e zXioRQ5vRvetrlqd;AK9VBg{?DNf-@$i-*<}3AUdvrGe}yMnG+7gGo6w*aKM_FF5Or z7oLv1R3ArGWNj{HRDN1(zg5f4KjDh&7T~U#cE=scuxfqz9hE%&7$-aJird<(nn~uc z+FopuB6oyyQx9~xJ*+EdI^J@xQv_KB5tC7zP^;~|gNNJe91phVx2k8HN~D7qKQUGu zS27}N9C2B{q{*GjQo#fRsYl1J7}d2N;iypS?SX!)ZF0Z$_DQmJ<$fWf5cw9X*5MUa zJH$xTG^K_SeQLsba;V69G8@2pLQvqo0eON8qDC^-Bk@tp)0Hz-km{Lmq$h3-_Q0Ex zzztt8=5F5OVnrNnNs%Wzt z@?staxxQBD;~q|y%DG5#+=EGvj28ZI>U8&P7|y!fOqco6wYU@6;huJ578Yb^O076w z^n~RUSHtC9zXG9qR;=su*4|nV|DY`E@=WyN9W@VF1){~SR8?F2g2!v?YQ4y}d@6W% z*+YXuNPU}5n3EWFdP93w$1NnATe|gwoAPgh!0AnXRbGQlVN!pt1n(@G@o+g6kSEOi zzVhY{-j6?tQ<6@ni$z34)FpWv-mw-xtvR|w-(NKfslx1iAG#ej4hio@dburfK&J9a zHvj5U`P_hM#P27|1Z46kKY+e@Qjt5o-BfzAN-{mtz^&AcqF4Qusnw-~lL^=QrW#@* zwqXfov-W0J)`r;ssocZ=_cdGO)9jj;f2)sL+wE>4U(ym}q-6sq2!v9ewsSla%k;0R z2PFsWtP`snmot?BOMU`hJp!DZ;%*d=s4Z3KOIu;|7`LQ`UQdy3+R{1?Omqt79YDPT zk6*mY@b(yAIW*R5B=xc8aScV?-I6f2M`BSG+1=0YR$NLI1`B z6b=qMJ;TfAEBxuIxGgOK`%4`|*_EDQi}#;ofIb}=2<`UgK71hdbA#*jLnja)K9djO zxv}vITV+(l=4I5x7kzkuhSy`OZvXa4b*?iSj^eJ%{JSxa^h5vsYQ)Lx4I8AD0L<=j3*B9b zNL3YfG0feKNau14FP%*A7f={Wl>Hx`Ug2Wclvo{}J6AR^fjyez1U!aF^ElU6+HPMk z^5gWak|7_4lES(kW_={baCEq}N5AOM1IP1u2-13I<6HyPtLwLlzc4J8VOma4h?y4X zaD$kaCZ(!R5)yDf0xDAp433woKZ9X*A8Y0XiND@m#mq+UWOv{?PzIyQvbnIeD6V9A z%RVawT*C`*wrro*rureJE~>{a$DczL>Usr(bx(uM8szn#7lpTkkjR5&9IR@;|x6L+$ujbA28Mkl_AGx6$ zt~38ZM4lcR?8xbea?%-Q8pU5qmf5q8)lzcZ11qtOT3-&+;}!oOxxTZz!l_lwt%2bL zGL@+XD+Ufa9aR5z)P1YewpmWfO7N|C_ zd}CokyF5qKwW%vWp}|vRv~1y=U^crT3tD1S(04<8RLhqUIw$zosK7#Ff=y65LC|-~ zp!_JZ{DUAvV{s_&%3*wqU{a4@;u>CP5YOo_#pNKB7`%}XycOr%pqaMu%kWo@*m#is z)A94Q8!_+8M)jYb{$0cj&BtOePY@-_bK{B-EDCT_J|Nyyc$4h z0<@HTK)%ML{|sduBZltr3|Gh?KZU;vw?B?1qB-j!K7hcz)5c8Q6op4qOgwHW^5N{8 z40a8kYJrawXSOcH4h4|SKSpC--o~;?A#5YO4knflGCGO&hn&69-JMy=M%WA8u>O}2 zA(T>cTTdx6t|#EAeljA<2g!-LX{j%BU3WmBfC!G1M~Uu71QbnX6i&wsB=qJK;C=`* zF&j1*K_9DW>UyPRtM^CpT!zkpR{Edh46+pfy9HH@^VMD2R{}IO-U-=hsUAw9o||O5 z^q{g}Nyy9-zW<;I%w$^yn`lITJuDIY!*Is9F5l*H_f6>B`nJ~~Q`zsCIkxM?vYy=_ z=s3m9@!kVOcZ%j>UDyUe$R|xaIuUoV!P)!zVt;1=`&K1!4OZwobt0`iV(Vbox|xtH7RK=Cvt5UATEcoC-r?!RAZM3OFVg*FD)ftFOlg zrd?c|omWl;>$E8As(zOa5_glk)d#ZCgNy+l>;cNuT{>3+luZJZ6~U;RNGsGaP-JY+ z+W``38*y!$ZkzGK@I1M3uU2QrmSOtVw*2A8-2+f4)C|k3Ws2^D@l0#42t0%6!<3L6 zA~)Xg>r^I8M||=%D8(J_jh`F*HmV3X2Et^Jld~(UJZ+t;)fB=!p%%MF1)~Pid;#lh zkubaGU^?4*SY+>AHjL0Lq#`l7&whdIl|Zg|k&89r$tnL{C3bYQtOI^sW0d0`FdV0w zFC!u-f@f&z7aN&1CoA(tMuBzi{zyvkId;9_Vl>?8ejb6?BmI9O9?J%bm@+@vw&&2c z!4EvH)C#ZD@!ttx*TJ@B^$G>4gdTp|_Br%8IV6W}RH&U%{CQn~&MT&s{!<5=gUoB( zUr*NIJI8?2-0NCO(W&!T>ABOrE^;TXNJ2wEonc=wxw+@E=bYJjD4QsPsx0?{Sp?w| zXj26a`F^9dkjBa!mJ2g$Umgu&Bp1TZW3DEZN@Cw*BwBeE6SiBv?odbq-~PaF-y`pZ zcL>jQ!k!dp7hRi(XS+rEMhUnDM;sS=eNlm#Knf2jV1H|%Zo9G&O5}$n;S5OB9#Aw7 z5o?ztM|0ROBtR^AF>#hR1o`w17uPe+544-WU+%OEr@f^NJ-_b5DSJ(jkKu^);h)1B z-e+KuJCp6;XhT!c+dMt(Ce5FM9YNin8~qE;;NJL7rc`)eC7n+8m$)o0DBIUh|FRBa z!XYkx_{TzmDfQ0le_wU&ah|)3R{$JdP`iY8jWWuqF@oMx^8xtx@M_rKphtDN&?XBb zGAL{|ebUJ=7cHq4>04+L9vhQ+){LyZxPNqb6;_0frcaNw*Be2*enBq7lv-qvJOu~m zenA3}npdcw4)h%lyO)xYw}mCqoO24mNY7FRwgCR9Ty26Y369U=o2u*Ih|e}qPVbxh>1&3r6fa@Rt(M!FmE@^x9C*l38Y;5*^I?K1tN>n%Z` z6#{F}Tha>3XSc07V|zRFqAWJ>{p>8s#t38bE|gMhX`+>VL@>m|#sj-%7p2kH;+7ZT zNO!zvEQI>~SE&NYW$PiH*uD1LCwAwGnQf1Jci<#>5tUv~-^)=Uh2oqax!GJ` zrDvx>^Yhhpi)J!`a2z7*L$upm{01igU`-`F$b7+T)$7Mynbvgz<4=u=b`BE{vmSfN z)89lSwY*0pkEGWccZdv`DJi?5BngH#-Psm+g;+<|zdr-Hg(TO~NH*flWof~|num;$ zOb?QmBAqqUvwrxsc^UJkeeqH>(r5@>-C}g>&XSmJUQGXC%I;Sbb+#76dNNA+2teS-6(Md zul?R1?JgUVFp4wjtBT&CcZmQ-{kCgyv1sM@w1zv(nL>8fK#2~%<1|&fw4~5(srqL% zVWGIp?^k1B9ckmK|C=7_;Z&}Gqr5_C!{kD5XD~`}Mb#)e^Qo*|^3tO6&B11>(vHhc zJCQW}ag)7=xTtC+AgD%vj?ei3|9P`hE?gr}#WyTB7(%+f#x6Vkx4G6?#!z9aLl$+> z#=(<1p3Vp+$)=xDK}-+Zzl)>C6Qx!C?q#Xwc$xXeSZ(#$bGZHT<8o_!`$nWOEi^Na zB}0+k?4kRj@@$&so&&$=v3TKnn(CHWezQQ~xb9EF7grAXCoJy!pkdM@yxxY0k}k^X zSDNaVLuLnsO>*?p!qoz?NtdwIf=>;r+ z%XKXb1V_FoED;r$w1qYUbfdcxx~1vb8m&{X#wl2{6lA(E5+#gm5)OC z@A&h!rgk{=9)~EuPq@~ZOo+YT0&L$RC3Lv46=u4Fa62sh!XA$#S<3Cu)4~?~Bfxif zpZIS)e3`EW^;G5#;qU-{MN042GwW1$P~W3ReBXt>0jh+`TX*x56`} zaS%)46VIqq|46d(1*(uF10?B8mo=%kq1kC>?~CMY$BRrR&a^G>tV3?BKhHV0CHldv zr9Rf;_Ds~U|K${F`v;E@{k*_ePmiv4DXi^fRvy>id3pp!&By^ALb<+rhFNOAxmQ9k z!=GHP?zLkKx$O_|H*@bbyy&Yi=N%}rsGds9Ng)atQUZ&pOhwetBI*N&ki!y{cR`@^ zrQ(WKRHVu1tRXoID0$R2PRjWJ4oqdE9lcsB=zNWwjs#5$2d!EDxoNQeeTD*3c-JJ|0hH5ybR zf#|MeOlviZ_@jKEm{O{o{CbiF2uow~fdJq$k2VxN6Vw++?&s;3S~UMi{&kmy*I@Od3df?4ps&e zJ)jOiCSp8J5_M+;)PWZmIs>hNA}hXX|6~(WuDudO_NB}N4WR!FfkLo~V~gcKUwQi| zMvh~Sc=bDIsnF>|;r6OoP}_`?0;4f;Z!+b`M4Ge0_8yP3&n z^9DyG;=Rb(e(nv;n0v%UU3GEccW7uv0#{l`$zGG$BI^DkrF;3E+Ow>WTO#KU?w>7U z5rhp_f`$%m38qwF&!Sj=smuG*QVEmyRj3&~z5$&tIZDWTjFcyuc%4{wWeN@jim19&_FbWWWfrqK>4M(hSNI2sc0YYthxI_+EfClB?HP!o z$Z5UsvQ;W!8=gY=^$hp{y05g|P=DsG9P2*)&pj;{fGfby0e(qr2Mt)3riflPV5SH~8lJyolSQ~w*Xb>H$&To3^ zrveu+!T?bfVhag`@r!Z+ePml*^uLCRbcGpEAKSg!GejS`xKgnOlyA{1v$2~4&70NP zn}vJva$HKq8_X$wUl0#jJ&-py!F*hP2eUUwd~@Pji&OMk6Z|~nfxNaBE^M&cc|oJ$jpeaHE}TA zrP^7^*j3wZ9pom~X&F6pghnwv6UtJ_z^V~>DV?lndBBq>wy#}~4@91Fbi44n4ZF@r z+U{qn&%s@nRon_BUV`af?}%_uJRe2k;YsQX(4O~;n91x{U*eLDHRJ(mI_5f(oXR_& z=i;;nZUu-xyT0=wt_cLU|MKMu=v!958(WmjN0bx!E{?si!X7S$P5t9hs7Ls0_9v-( zFdD=@iC}87r%g!uT^N&OG}#4{(Q*Rq%p=q7LHZ{~8CdV*znB~pm{PN5zKzIUa+}=mMllG_>V)C|rEriQWZl11Sn)9u1B z>L|%lZKmlNo+vc$GsXczvBoHU4wx1sXF%`7 XSj>`qvZn83JNwIIoSw#wI{5z=(2Gnk literal 0 HcmV?d00001 From 19251e84f6033e859a3a514e4674510e8cd193e4 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 11 Jun 2022 22:37:06 -0500 Subject: [PATCH 026/101] add yet another demo song by Laagy --- demos/going_up_a_step_at_time.fur | Bin 0 -> 7710 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/going_up_a_step_at_time.fur diff --git a/demos/going_up_a_step_at_time.fur b/demos/going_up_a_step_at_time.fur new file mode 100644 index 0000000000000000000000000000000000000000..7d52d155aa1735f1343056be174d1d9044509d30 GIT binary patch literal 7710 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 Date: Sat, 11 Jun 2022 22:42:30 -0500 Subject: [PATCH 027/101] GUI: find and replace, part 11 lax mode done now replace time... --- src/gui/findReplace.cpp | 36 ++++++++++++++++++++++++++++++++++-- src/gui/gui.h | 1 + 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 77c1a7e3a..3f877242f 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -126,8 +126,37 @@ void FurnaceGUI::doFind() { } } break; - case 1: // lax + case 1: { // lax + // locate first effect + int posOfFirst=-1; + for (int m=0; mcurPat[k].effectCols; m++) { + if (!checkCondition(l.effectMode[0],l.effect[0],l.effectMax[0],p->data[j][4+m*2])) continue; + if (!checkCondition(l.effectValMode[0],l.effectVal[0],l.effectValMax[0],p->data[j][5+m*2])) continue; + posOfFirst=m; + break; + } + if (posOfFirst<0) { + notMatched=true; + break; + } + // make sure we aren't too far to the right + if ((posOfFirst+l.effectCount)>e->curPat[k].effectCols) { + notMatched=true; + break; + } + // search from first effect location + for (int m=0; mdata[j][4+(m+posOfFirst)*2])) { + notMatched=true; + break; + } + if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->data[j][5+(m+posOfFirst)*2])) { + notMatched=true; + break; + } + } break; + } case 2: // strict int effectMax=l.effectCount; if (effectMax>e->curPat[k].effectCols) { @@ -160,6 +189,9 @@ void FurnaceGUI::doFind() { queryViewingResults=true; } +void FurnaceGUI::doReplace() { +} + #define FIRST_VISIBLE(x) (x==GUI_QUERY_MATCH || x==GUI_QUERY_MATCH_NOT || x==GUI_QUERY_RANGE || x==GUI_QUERY_RANGE_NOT) #define SECOND_VISIBLE(x) (x==GUI_QUERY_RANGE || x==GUI_QUERY_RANGE_NOT) @@ -754,7 +786,7 @@ void FurnaceGUI::drawFindReplace() { queryReplaceEffectPos=3; } if (ImGui::Button("Replace##QueryReplace")) { - // TODO + doReplace(); } ImGui::EndTabItem(); } diff --git a/src/gui/gui.h b/src/gui/gui.h index 300fa8fca..55ea989c8 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1492,6 +1492,7 @@ class FurnaceGUI { void doUndo(); void doRedo(); void doFind(); + void doReplace(); void editOptions(bool topMenu); void noteInput(int num, int key, int vol=-1); void valueInput(int num, bool direct=false, int target=-1); From 74b524a912387a83cd985350c97163f2cae93146 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 12 Jun 2022 03:50:05 -0500 Subject: [PATCH 028/101] GUI: find and replace, part 12 replace is almost complete - some refinements left to do though --- TODO.md | 1 - src/gui/findReplace.cpp | 201 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 198 insertions(+), 4 deletions(-) diff --git a/TODO.md b/TODO.md index 5bd4e8925..12a7e47ec 100644 --- a/TODO.md +++ b/TODO.md @@ -3,7 +3,6 @@ - rewrite the system name detection function anyway - add another FM editor layout - add ability to move selection by dragging -- find and replace - implement Defle slide bug when using E1xy/E2xy and repeating origin note (requires format change) # to-do for 0.6pre2 (as this requires new data structures) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 3f877242f..9ab75f6fb 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -31,13 +31,13 @@ int queryNote(int note, int octave) { } else if (note==102) { // envelope release only return 130; } else if (octave==0 && note==0) { - return -1; + return -61; } else if (note==0 && octave!=0) { - return -1; // bug note? + return -61; // bug note? } int seek=(note+(signed char)octave*12); if (seek<-60 || seek>=120) { - return -1; // out of range note + return -61; // out of range note } return seek; } @@ -190,6 +190,201 @@ void FurnaceGUI::doFind() { } void FurnaceGUI::doReplace() { + doFind(); + queryViewingResults=false; + + for (FurnaceGUIQueryResult& i: curQueryResults) { + DivPattern* p=e->song.subsong[i.subsong]->pat[i.x].getPattern(e->song.subsong[i.subsong]->orders.ord[i.x][i.order],true); + if (queryReplaceNoteDo) { + switch (queryReplaceNoteMode) { + case GUI_QUERY_REPLACE_SET: + if (queryReplaceNote==130) { // macro release + p->data[i.y][0]=102; + p->data[i.y][1]=0; + } else if (queryReplaceNote==129) { // note release + p->data[i.y][0]=101; + p->data[i.y][1]=0; + } else if (queryReplaceNote==128) { // note off + p->data[i.y][0]=100; + p->data[i.y][1]=0; + } else if (queryReplaceNote>=-60 && queryReplaceNote<120) { // note + p->data[i.y][0]=(queryReplaceNote+60)%12; + if (p->data[i.y][0]==0) p->data[i.y][0]=12; + p->data[i.y][1]=(unsigned char)((queryReplaceNote-1)/12); + } else { // invalid + p->data[i.y][0]=0; + p->data[i.y][1]=0; + } + break; + case GUI_QUERY_REPLACE_ADD: + if (p->data[i.y][0]<100) { + int note=queryNote(p->data[i.y][0],p->data[i.y][1]); + if (note>=-60 && note<120) { + note+=queryReplaceNote; + if (note<-60) note=-60; + if (note>119) note=119; + + p->data[i.y][0]=(note+60)%12; + if (p->data[i.y][0]==0) p->data[i.y][0]=12; + p->data[i.y][1]=(unsigned char)((note-1)/12); + } + } + break; + case GUI_QUERY_REPLACE_ADD_OVERFLOW: + if (p->data[i.y][0]<100) { + int note=queryNote(p->data[i.y][0],p->data[i.y][1]); + if (note>=-60 && note<120) { + note+=queryReplaceNote; + if (note<-60) { + while (note<-60) note+=180; + } else if (note>119) { + while (note>119) note-=180; + } + + p->data[i.y][0]=(note+60)%12; + if (p->data[i.y][0]==0) p->data[i.y][0]=12; + p->data[i.y][1]=(unsigned char)((note-1)/12); + } + } + break; + case GUI_QUERY_REPLACE_CLEAR: + p->data[i.y][0]=0; + p->data[i.y][1]=0; + break; + } + } + + if (queryReplaceInsDo) { + switch (queryReplaceInsMode) { + case GUI_QUERY_REPLACE_SET: + p->data[i.y][2]=queryReplaceIns; + break; + case GUI_QUERY_REPLACE_ADD: + if (p->data[i.y][2]>=0) { + p->data[i.y][2]+=queryReplaceIns; + if (p->data[i.y][2]<0) p->data[i.y][2]=0; + if (p->data[i.y][2]>255) p->data[i.y][2]=255; + } + break; + case GUI_QUERY_REPLACE_ADD_OVERFLOW: + if (p->data[i.y][2]>=0) p->data[i.y][2]=(p->data[i.y][2]+queryReplaceIns)&0xff; + break; + case GUI_QUERY_REPLACE_CLEAR: + p->data[i.y][2]=-1; + break; + } + } + + if (queryReplaceVolDo) { + switch (queryReplaceVolMode) { + case GUI_QUERY_REPLACE_SET: + p->data[i.y][3]=queryReplaceVol; + break; + case GUI_QUERY_REPLACE_ADD: + if (p->data[i.y][3]>=0) { + p->data[i.y][3]+=queryReplaceVol; + if (p->data[i.y][3]<0) p->data[i.y][3]=0; + if (p->data[i.y][3]>255) p->data[i.y][3]=255; + } + break; + case GUI_QUERY_REPLACE_ADD_OVERFLOW: + if (p->data[i.y][3]>=0) p->data[i.y][3]=(p->data[i.y][3]+queryReplaceVol)&0xff; + break; + case GUI_QUERY_REPLACE_CLEAR: + p->data[i.y][3]=-1; + break; + } + } + + signed char effectOrder[8]; + memset(effectOrder,-1,8); + + switch (queryReplaceEffectPos) { + case 0: // clear + for (int j=0; jsong.subsong[i.subsong]->pat[i.x].effectCols; j++) { + effectOrder[j]=j; + } + break; + case 1: { // replace matches + int placementIndex=0; + for (int j=0; jsong.subsong[i.subsong]->pat[i.x].effectCols; j++) { + if (p->data[i.y][4+j*2]!=-1 || p->data[i.y][5+j*2]!=-1) { + effectOrder[placementIndex++]=j; + } + } + break; + } + case 2: { // replace matches then free spaces + int placementIndex=0; + for (int j=0; jsong.subsong[i.subsong]->pat[i.x].effectCols; j++) { + if (p->data[i.y][4+j*2]!=-1 || p->data[i.y][5+j*2]!=-1) { + effectOrder[placementIndex++]=j; + } + } + for (int j=0; jsong.subsong[i.subsong]->pat[i.x].effectCols; j++) { + if (p->data[i.y][4+j*2]==-1 && p->data[i.y][5+j*2]==-1) { + effectOrder[placementIndex++]=j; + } + } + break; + } + case 3: { // insert in free spaces + int placementIndex=0; + for (int j=0; jsong.subsong[i.subsong]->pat[i.x].effectCols; j++) { + if (p->data[i.y][4+j*2]==-1 && p->data[i.y][5+j*2]==-1) { + effectOrder[placementIndex++]=j; + } + } + break; + } + } + + for (int j=0; jdata[i.y][4+pos*2]=queryReplaceEffect[j]; + break; + case GUI_QUERY_REPLACE_ADD: + if (p->data[i.y][4+pos*2]>=0) { + p->data[i.y][4+pos*2]+=queryReplaceEffect[j]; + if (p->data[i.y][4+pos*2]<0) p->data[i.y][4+pos*2]=0; + if (p->data[i.y][4+pos*2]>255) p->data[i.y][4+pos*2]=255; + } + break; + case GUI_QUERY_REPLACE_ADD_OVERFLOW: + if (p->data[i.y][4+pos*2]>=0) p->data[i.y][4+pos*2]=(p->data[i.y][4+pos*2]+queryReplaceEffect[j])&0xff; + break; + case GUI_QUERY_REPLACE_CLEAR: + p->data[i.y][4+pos*2]=-1; + break; + } + } + + if (queryReplaceEffectValDo[j]) { + switch (queryReplaceEffectValMode[j]) { + case GUI_QUERY_REPLACE_SET: + p->data[i.y][5+pos*2]=queryReplaceEffectVal[j]; + break; + case GUI_QUERY_REPLACE_ADD: + if (p->data[i.y][5+pos*2]>=0) { + p->data[i.y][5+pos*2]+=queryReplaceEffectVal[j]; + if (p->data[i.y][5+pos*2]<0) p->data[i.y][5+pos*2]=0; + if (p->data[i.y][5+pos*2]>255) p->data[i.y][5+pos*2]=255; + } + break; + case GUI_QUERY_REPLACE_ADD_OVERFLOW: + if (p->data[i.y][5+pos*2]>=0) p->data[i.y][5+pos*2]=(p->data[i.y][5+pos*2]+queryReplaceEffectVal[j])&0xff; + break; + case GUI_QUERY_REPLACE_CLEAR: + p->data[i.y][5+pos*2]=-1; + break; + } + } + } + } } #define FIRST_VISIBLE(x) (x==GUI_QUERY_MATCH || x==GUI_QUERY_MATCH_NOT || x==GUI_QUERY_RANGE || x==GUI_QUERY_RANGE_NOT) From f3f8804f47995956f8a1f69c869bece471032e69 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 12 Jun 2022 14:39:08 -0500 Subject: [PATCH 029/101] GUI: find and replace, part 13 one more part coming or maybe not --- src/gui/findReplace.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 9ab75f6fb..d5548c0fb 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -193,8 +193,18 @@ void FurnaceGUI::doReplace() { doFind(); queryViewingResults=false; + bool* touched[DIV_MAX_CHANS]; + memset(touched,0,DIV_MAX_CHANS*sizeof(bool*)); + for (FurnaceGUIQueryResult& i: curQueryResults) { - DivPattern* p=e->song.subsong[i.subsong]->pat[i.x].getPattern(e->song.subsong[i.subsong]->orders.ord[i.x][i.order],true); + int patIndex=e->song.subsong[i.subsong]->orders.ord[i.x][i.order]; + DivPattern* p=e->song.subsong[i.subsong]->pat[i.x].getPattern(patIndex,true); + if (touched[i.x]==NULL) { + touched[i.x]=new bool[256*256]; + memset(touched[i.x],0,256*256*sizeof(bool)); + } + if (touched[i.x][(patIndex<<8)|i.y]) continue; + touched[i.x][(patIndex<<8)|i.y]=true; if (queryReplaceNoteDo) { switch (queryReplaceNoteMode) { case GUI_QUERY_REPLACE_SET: @@ -385,6 +395,10 @@ void FurnaceGUI::doReplace() { } } } + + for (int i=0; i Date: Sun, 12 Jun 2022 23:22:45 -0500 Subject: [PATCH 030/101] OPL: fix 4-op channel muting --- src/engine/platform/opl.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index fbf914484..e6f730c26 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -677,6 +677,9 @@ void DivPlatformOPL::muteChannel(int ch, bool mute) { fm.channel[outChanMap[ch]].muted=mute; } int ops=(slots[3][ch]!=255 && chan[ch].state.ops==4 && oplType==3)?4:2; + if (ch&1 && ch<12) { + if (chan[ch-1].fourOp) return; + } chan[ch].fourOp=(ops==4); update4OpMask=true; for (int i=0; i Date: Mon, 13 Jun 2022 03:54:42 -0500 Subject: [PATCH 031/101] GUI: work on alternate FM layout --- TODO.md | 4 +- src/gui/insEdit.cpp | 555 ++++++++++++++++++++++++++++++++++++++++++- src/gui/settings.cpp | 11 +- 3 files changed, 567 insertions(+), 3 deletions(-) diff --git a/TODO.md b/TODO.md index 12a7e47ec..d667201ec 100644 --- a/TODO.md +++ b/TODO.md @@ -1,11 +1,13 @@ # to-do for 0.6pre1 -- rewrite the system name detection function anyway - add another FM editor layout - add ability to move selection by dragging - implement Defle slide bug when using E1xy/E2xy and repeating origin note (requires format change) # to-do for 0.6pre2 (as this requires new data structures) +- rewrite the system name detection function anyway + - this involves the addition of a new "system" field in the song (which solves the problem) + - songs made in older versions will go through old system name detection for compatibility - Game Boy envelope macro/sequence - volume commands should work on Game Boy diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 7d7fa050b..81edbfe19 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1345,6 +1345,9 @@ void FurnaceGUI::drawMacros(std::vector& macros) { #define CENTER_VSLIDER \ ImGui::SetCursorPosX(ImGui::GetCursorPosX()+0.5f*ImGui::GetContentRegionAvail().x-10.0f*dpiScale); +#define CENTER_TEXT_20(text) \ + ImGui::SetCursorPosX(ImGui::GetCursorPosX()+0.5*(20.0f*dpiScale-ImGui::CalcTextSize(text).x)); + void FurnaceGUI::drawInsEdit() { if (nextWindow==GUI_WINDOW_INS_EDIT) { insEditOpen=true; @@ -2016,7 +2019,557 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTable(); } - } else { + } else if (settings.fmLayout>=4 && settings.fmLayout<=6) { // alternate + int columns=2; + switch (settings.fmLayout) { + case 4: // 2x2 + columns=2; + break; + case 5: // 1x4 + columns=1; + break; + case 6: // 4x1 + columns=opCount; + break; + } + char tempID[1024]; + if (ImGui::BeginTable("KGE93BSIEO3NOWBDJZBA",columns,ImGuiTableFlags_SizingStretchSame)) { + for (int i=0; ifm.op[(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS)?opOrder[i]:i]; + if ((settings.fmLayout!=3 && ((i+1)&1)) || i==0 || settings.fmLayout==2) ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Separator(); + ImGui::PushID(fmt::sprintf("op%d",i).c_str()); + + // push colors + if (settings.separateFMColors) { + bool mod=true; + if (ins->type==DIV_INS_OPL_DRUMS) { + mod=false; + } else if (opCount==4) { + if (ins->type==DIV_INS_OPL) { + if (opIsOutputOPL[ins->fm.alg&3][i]) mod=false; + } else { + if (opIsOutput[ins->fm.alg&7][i]) mod=false; + } + } else { + if (i==1 || (ins->type==DIV_INS_OPL && (ins->fm.alg&1))) mod=false; + } + if (mod) { + pushAccentColors( + uiColors[GUI_COLOR_FM_PRIMARY_MOD], + uiColors[GUI_COLOR_FM_SECONDARY_MOD], + uiColors[GUI_COLOR_FM_BORDER_MOD], + uiColors[GUI_COLOR_FM_BORDER_SHADOW_MOD] + ); + } else { + pushAccentColors( + uiColors[GUI_COLOR_FM_PRIMARY_CAR], + uiColors[GUI_COLOR_FM_SECONDARY_CAR], + uiColors[GUI_COLOR_FM_BORDER_CAR], + uiColors[GUI_COLOR_FM_BORDER_SHADOW_CAR] + ); + } + } + + ImGui::Dummy(ImVec2(dpiScale,dpiScale)); + if (ins->type==DIV_INS_OPL_DRUMS) { + ImGui::Text("%s",oplDrumNames[i]); + } else if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) { + if (i==1) { + ImGui::Text("Envelope 2 (kick only)"); + } else { + ImGui::Text("Envelope"); + } + } else { + ImGui::Text("OP%d",i+1); + } + + float sliderHeight=200.0f*dpiScale; + float waveWidth=140.0*dpiScale; + float waveHeight=sliderHeight-ImGui::GetFrameHeightWithSpacing()*5.5f; + + int maxTl=127; + if (ins->type==DIV_INS_OPLL) { + if (i==1) { + maxTl=15; + } else { + maxTl=63; + } + } + if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { + maxTl=63; + } + int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; + + bool ssgOn=op.ssgEnv&8; + bool ksrOn=op.ksr; + bool vibOn=op.vib; + bool egtOn=op.egt; + bool susOn=op.sus; // don't you make fun of this one + unsigned char ssgEnv=op.ssgEnv&7; + + if (ImGui::BeginTable("opParams",ins->type==DIV_INS_OPLL?3:4,ImGuiTableFlags_BordersInnerV)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + if (ins->type!=DIV_INS_OPLL) { + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed); + } + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + float textY=ImGui::GetCursorPosY(); + CENTER_TEXT_20(FM_SHORT_NAME(FM_AR)); + ImGui::TextUnformatted(FM_SHORT_NAME(FM_AR)); + if (ins->type!=DIV_INS_OPLL) { + ImGui::TableNextColumn(); + if (ins->type==DIV_INS_FM) { + ImGui::Text("SSG-EG"); + } else { + ImGui::Text("Waveform"); + } + } + ImGui::TableNextColumn(); + ImGui::Text("Envelope"); + ImGui::TableNextColumn(); + CENTER_TEXT(FM_SHORT_NAME(FM_TL)); + ImGui::Text("TL"); + + // A/D/S/R + ImGui::TableNextColumn(); + + op.ar&=maxArDr; + P(CWVSliderScalar("##AR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO)); + + ImGui::SameLine(); + op.dr&=maxArDr; + float textX_DR=ImGui::GetCursorPosX(); + P(CWVSliderScalar("##DR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO)); + + float textX_SL=0.0f; + if (settings.susPosition==0) { + ImGui::SameLine(); + op.sl&=15; + textX_SL=ImGui::GetCursorPosX(); + P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); + } + + float textX_D2R=0.0f; + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + ImGui::SameLine(); + op.d2r&=31; + textX_D2R=ImGui::GetCursorPosX(); + P(CWVSliderScalar("##D2R",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO)); + } + + ImGui::SameLine(); + op.rr&=15; + float textX_RR=ImGui::GetCursorPosX(); + P(CWVSliderScalar("##RR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO)); + + if (settings.susPosition==1) { + ImGui::SameLine(); + op.sl&=15; + textX_SL=ImGui::GetCursorPosX(); + P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); + } + + ImVec2 prevCurPos=ImGui::GetCursorPos(); + + // labels + ImGui::SetCursorPos(ImVec2(textX_DR,textY)); + CENTER_TEXT_20(FM_SHORT_NAME(FM_DR)); + ImGui::TextUnformatted(FM_SHORT_NAME(FM_DR)); + + ImGui::SetCursorPos(ImVec2(textX_SL,textY)); + CENTER_TEXT_20(FM_SHORT_NAME(FM_SL)); + ImGui::TextUnformatted(FM_SHORT_NAME(FM_SL)); + + ImGui::SetCursorPos(ImVec2(textX_RR,textY)); + CENTER_TEXT_20(FM_SHORT_NAME(FM_RR)); + ImGui::TextUnformatted(FM_SHORT_NAME(FM_RR)); + + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + ImGui::SetCursorPos(ImVec2(textX_D2R,textY)); + CENTER_TEXT_20(FM_SHORT_NAME(FM_D2R)); + ImGui::TextUnformatted(FM_SHORT_NAME(FM_D2R)); + } + + ImGui::SetCursorPos(prevCurPos); + + if (ins->type!=DIV_INS_OPLL) { + ImGui::TableNextColumn(); + switch (ins->type) { + case DIV_INS_FM: { + // SSG + ImGui::BeginDisabled(!ssgOn); + drawSSGEnv(op.ssgEnv&7,ImVec2(waveWidth,waveHeight)); + ImGui::EndDisabled(); + if (ImGui::Checkbox("##SSGOn",&ssgOn)) { PARAMETER + op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Only for OPN family chips"); + } + + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER + op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); + } + + // params + ImGui::Separator(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); + P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable + + int detune=(op.dt&7)-3; + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT)); + if (CWSliderInt("##DT",&detune,-3,4,tempID)) { PARAMETER + op.dt=detune+3; + } rightClickable + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT2)); + P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE,tempID)); rightClickable + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Only on YM2151 (OPM)"); + } + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS)); + P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable + + break; + } + case DIV_INS_OPL: + // waveform + drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight)); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable + if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { + ImGui::SetTooltip("OPL2/3 only (last 4 waveforms are OPL3 only)"); + } + + // params + ImGui::Separator(); + if (ImGui::BeginTable("FMParamsInner",2)) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + bool amOn=op.am; + if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER + op.am=amOn; + } + ImGui::TableNextColumn(); + if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER + op.ksr=ksrOn; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER + op.vib=vibOn; + } + ImGui::TableNextColumn(); + if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER + op.sus=susOn; + } + + ImGui::EndTable(); + } + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); + P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_KSL)); + P(CWSliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE,tempID)); rightClickable + + break; + case DIV_INS_OPZ: { + // waveform + drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight)); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable + if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { + ImGui::SetTooltip("OPL2/3 only (last 4 waveforms are OPL3 only)"); + } + + // params + ImGui::Separator(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); + P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable + + int detune=(op.dt&7)-3; + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT)); + if (CWSliderInt("##DT",&detune,-3,4,tempID)) { PARAMETER + op.dt=detune+3; + } rightClickable + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT2)); + P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE,tempID)); rightClickable + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Only on YM2151 (OPM)"); + } + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS)); + P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable + break; + } + default: + break; + } + } + + ImGui::TableNextColumn(); + float envHeight=sliderHeight-ImGui::GetStyle().ItemSpacing.y*2.0f; + if (ins->type==DIV_INS_OPZ) { + envHeight-=ImGui::GetFrameHeightWithSpacing()*2.0f; + } + drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,ImVec2(ImGui::GetContentRegionAvail().x,envHeight),ins->type); + + if (ins->type==DIV_INS_OPZ) { + ImGui::Separator(); + if (ImGui::BeginTable("FMParamsInnerOPZ",2)) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_FINE)); + P(CWSliderScalar("##FINE",ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN,tempID)); rightClickable + + ImGui::TableNextColumn(); + bool amOn=op.am; + if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER + op.am=amOn; + } + ImGui::SameLine(); + if (ImGui::Checkbox("Fixed",&egtOn)) { PARAMETER + op.egt=egtOn; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_EGSHIFT)); + P(CWSliderScalar("##EGShift",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE,tempID)); rightClickable + + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_REV)); + P(CWSliderScalar("##REV",ImGuiDataType_U8,&op.dam,&_ZERO,&_SEVEN,tempID)); rightClickable + + ImGui::TableNextColumn(); + + + ImGui::EndTable(); + } + } + + ImGui::TableNextColumn(); + op.tl&=maxTl; + P(CWVSliderScalar("##TL",ImVec2(20.0f*dpiScale,sliderHeight-(ins->type==DIV_INS_FM?(ImGui::GetFrameHeightWithSpacing()+ImGui::CalcTextSize(FM_SHORT_NAME(FM_AM)).y+ImGui::GetStyle().ItemSpacing.y):0.0f)),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); + + if (ins->type==DIV_INS_FM) { + CENTER_TEXT(FM_SHORT_NAME(FM_AM)); + ImGui::TextUnformatted(FM_SHORT_NAME(FM_AM)); + bool amOn=op.am; + if (ImGui::Checkbox("##AM",&amOn)) { PARAMETER + op.am=amOn; + } + } + + ImGui::EndTable(); + } + + /* + ImGui::SameLine(); + + bool amOn=op.am; + if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER + op.am=amOn; + } + + if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_OPZ) { + ImGui::SameLine(); + if (ImGui::Checkbox((ins->type==DIV_INS_OPLL)?FM_NAME(FM_EGS):"SSG On",&ssgOn)) { PARAMETER + op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); + } + if (ins->type==DIV_INS_FM) { + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Only for OPN family chips"); + } + } + } + + if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { + ImGui::SameLine(); + if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER + op.sus=susOn; + } + } + + //52.0 controls vert scaling; default 96 + drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,ImVec2(ImGui::GetContentRegionAvail().x,52.0*dpiScale),ins->type); + //P(CWSliderScalar(FM_NAME(FM_AR),ImGuiDataType_U8,&op.ar,&_ZERO,&_THIRTY_ONE)); rightClickable + if (ImGui::BeginTable("opParams",2,ImGuiTableFlags_SizingStretchProp)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); \ + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,0.0); \ + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + op.ar&=maxArDr; + P(CWSliderScalar("##AR",ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_AR)); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + op.dr&=maxArDr; + P(CWSliderScalar("##DR",ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_DR)); + + if (settings.susPosition==0) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##SL",ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_SL)); + } + + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##D2R",ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_D2R)); + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##RR",ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_RR)); + + if (settings.susPosition==1) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##SL",ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_SL)); + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + op.tl&=maxTl; + P(CWSliderScalar("##TL",ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_TL)); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Separator(); + ImGui::TableNextColumn(); + ImGui::Separator(); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_RS)); + } else { + P(CWSliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_KSL)); + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_MULT)); + + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + int detune=(op.dt&7)-3; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##DT",&detune,-3,4)) { PARAMETER + op.dt=detune+3; + } rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_DT)); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable + if (ImGui::IsItemHovered() && ins->type==DIV_INS_FM) { + ImGui::SetTooltip("Only on YM2151 (OPM)"); + } + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_DT2)); + + if (ins->type==DIV_INS_FM) { // OPN only + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER + op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); + } rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_SSG)); + } + } + + if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_WS)); + } + + ImGui::EndTable(); + } + + if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { + if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER + op.vib=vibOn; + } + ImGui::SameLine(); + if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER + op.ksr=ksrOn; + } + } + */ + + if (settings.separateFMColors) { + popAccentColors(); + } + + ImGui::PopID(); + } + ImGui::EndTable(); + } + } else { // classic int columns=2; switch (settings.fmLayout) { case 1: // 2x2 diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index ea1d92748..da3b0f277 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1117,6 +1117,15 @@ void FurnaceGUI::drawSettings() { if (ImGui::RadioButton("Compact (4x1)##fml3",settings.fmLayout==3)) { settings.fmLayout=3; } + if (ImGui::RadioButton("Alternate (2x2)##fml4",settings.fmLayout==4)) { + settings.fmLayout=4; + } + if (ImGui::RadioButton("Alternate (1x4)##fml5",settings.fmLayout==5)) { + settings.fmLayout=5; + } + if (ImGui::RadioButton("Alternate (4x1)##fml5",settings.fmLayout==6)) { + settings.fmLayout=6; + } ImGui::Text("Position of Sustain in FM editor:"); if (ImGui::RadioButton("Between Decay and Sustain Rate##susp0",settings.susPosition==0)) { @@ -2077,7 +2086,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.roundedMenus,0,1); clampSetting(settings.loadJapanese,0,1); clampSetting(settings.loadChinese,0,1); - clampSetting(settings.fmLayout,0,3); + clampSetting(settings.fmLayout,0,6); clampSetting(settings.susPosition,0,1); clampSetting(settings.effectCursorDir,0,2); clampSetting(settings.cursorPastePos,0,1); From bd7710991b58e72bd0c40d17d8a64bb2371b9891 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 13 Jun 2022 03:57:31 -0500 Subject: [PATCH 032/101] GUI: a bit more to it --- src/gui/insEdit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 81edbfe19..681ae10d4 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2036,7 +2036,7 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::BeginTable("KGE93BSIEO3NOWBDJZBA",columns,ImGuiTableFlags_SizingStretchSame)) { for (int i=0; ifm.op[(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS)?opOrder[i]:i]; - if ((settings.fmLayout!=3 && ((i+1)&1)) || i==0 || settings.fmLayout==2) ImGui::TableNextRow(); + if ((settings.fmLayout!=6 && ((i+1)&1)) || i==0 || settings.fmLayout==5) ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Separator(); ImGui::PushID(fmt::sprintf("op%d",i).c_str()); From 327a013186358c17162863ecfaf66fc571bf828f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 13 Jun 2022 23:22:17 -0500 Subject: [PATCH 033/101] GUI: finish alternate FM layout --- TODO.md | 2 +- src/gui/insEdit.cpp | 505 ++++++++++++++++++-------------------------- 2 files changed, 201 insertions(+), 306 deletions(-) diff --git a/TODO.md b/TODO.md index d667201ec..b0fc02d37 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,5 @@ # to-do for 0.6pre1 -- add another FM editor layout - add ability to move selection by dragging - implement Defle slide bug when using E1xy/E2xy and repeating origin note (requires format change) @@ -11,3 +10,4 @@ - songs made in older versions will go through old system name detection for compatibility - Game Boy envelope macro/sequence - volume commands should work on Game Boy +- ability to customize `OFF`, `===` and `REL` diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 681ae10d4..be09eb6d6 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2033,12 +2033,13 @@ void FurnaceGUI::drawInsEdit() { break; } char tempID[1024]; - if (ImGui::BeginTable("KGE93BSIEO3NOWBDJZBA",columns,ImGuiTableFlags_SizingStretchSame)) { + ImVec2 oldPadding=ImGui::GetStyle().CellPadding; + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(8.0f*dpiScale,4.0f*dpiScale)); + if (ImGui::BeginTable("KGE93BSIEO3NOWBDJZBA",columns,ImGuiTableFlags_SizingStretchSame|ImGuiTableFlags_BordersInner)) { for (int i=0; ifm.op[(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS)?opOrder[i]:i]; if ((settings.fmLayout!=6 && ((i+1)&1)) || i==0 || settings.fmLayout==5) ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Separator(); ImGui::PushID(fmt::sprintf("op%d",i).c_str()); // push colors @@ -2074,20 +2075,22 @@ void FurnaceGUI::drawInsEdit() { ImGui::Dummy(ImVec2(dpiScale,dpiScale)); if (ins->type==DIV_INS_OPL_DRUMS) { - ImGui::Text("%s",oplDrumNames[i]); + snprintf(tempID,1024,"%s",oplDrumNames[i]); } else if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) { if (i==1) { - ImGui::Text("Envelope 2 (kick only)"); + snprintf(tempID,1024,"Envelope 2 (kick only)"); } else { - ImGui::Text("Envelope"); + snprintf(tempID,1024,"Envelope"); } } else { - ImGui::Text("OP%d",i+1); + snprintf(tempID,1024,"Operator %d",i+1); } + CENTER_TEXT(tempID); + ImGui::TextUnformatted(tempID); float sliderHeight=200.0f*dpiScale; float waveWidth=140.0*dpiScale; - float waveHeight=sliderHeight-ImGui::GetFrameHeightWithSpacing()*5.5f; + float waveHeight=sliderHeight-ImGui::GetFrameHeightWithSpacing()*(ins->type==DIV_INS_OPLL?4.5f:5.5f); int maxTl=127; if (ins->type==DIV_INS_OPLL) { @@ -2106,14 +2109,13 @@ void FurnaceGUI::drawInsEdit() { bool ksrOn=op.ksr; bool vibOn=op.vib; bool egtOn=op.egt; - bool susOn=op.sus; // don't you make fun of this one + bool susOn=op.sus; // yawn unsigned char ssgEnv=op.ssgEnv&7; - if (ImGui::BeginTable("opParams",ins->type==DIV_INS_OPLL?3:4,ImGuiTableFlags_BordersInnerV)) { + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,oldPadding); + if (ImGui::BeginTable("opParams",4,ImGuiTableFlags_BordersInnerV)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); - if (ins->type!=DIV_INS_OPLL) { - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed); - } + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,waveWidth); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed); @@ -2122,13 +2124,11 @@ void FurnaceGUI::drawInsEdit() { float textY=ImGui::GetCursorPosY(); CENTER_TEXT_20(FM_SHORT_NAME(FM_AR)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_AR)); - if (ins->type!=DIV_INS_OPLL) { - ImGui::TableNextColumn(); - if (ins->type==DIV_INS_FM) { - ImGui::Text("SSG-EG"); - } else { - ImGui::Text("Waveform"); - } + ImGui::TableNextColumn(); + if (ins->type==DIV_INS_FM) { + ImGui::Text("SSG-EG"); + } else { + ImGui::Text("Waveform"); } ImGui::TableNextColumn(); ImGui::Text("Envelope"); @@ -2198,29 +2198,172 @@ void FurnaceGUI::drawInsEdit() { ImGui::SetCursorPos(prevCurPos); - if (ins->type!=DIV_INS_OPLL) { - ImGui::TableNextColumn(); - switch (ins->type) { - case DIV_INS_FM: { - // SSG - ImGui::BeginDisabled(!ssgOn); - drawSSGEnv(op.ssgEnv&7,ImVec2(waveWidth,waveHeight)); - ImGui::EndDisabled(); - if (ImGui::Checkbox("##SSGOn",&ssgOn)) { PARAMETER + ImGui::TableNextColumn(); + switch (ins->type) { + case DIV_INS_FM: { + // SSG + ImGui::BeginDisabled(!ssgOn); + drawSSGEnv(op.ssgEnv&7,ImVec2(waveWidth,waveHeight)); + ImGui::EndDisabled(); + if (ImGui::Checkbox("##SSGOn",&ssgOn)) { PARAMETER + op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Only for OPN family chips"); + } + + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER + op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); + } + + // params + ImGui::Separator(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); + P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable + + int detune=(op.dt&7)-3; + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT)); + if (CWSliderInt("##DT",&detune,-3,4,tempID)) { PARAMETER + op.dt=detune+3; + } rightClickable + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT2)); + P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE,tempID)); rightClickable + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Only on YM2151 (OPM)"); + } + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS)); + P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable + + break; + } + case DIV_INS_OPLL: + // waveform + drawWaveform(i==0?(ins->fm.ams&1):(ins->fm.fms&1),ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight)); + + // params + ImGui::Separator(); + if (ImGui::BeginTable("FMParamsInner",2)) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + bool amOn=op.am; + if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER + op.am=amOn; + } + ImGui::TableNextColumn(); + if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER + op.ksr=ksrOn; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER + op.vib=vibOn; + } + ImGui::TableNextColumn(); + if (ImGui::Checkbox(FM_NAME(FM_EGS),&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Only for OPN family chips"); + + ImGui::EndTable(); + } + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); + P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_KSL)); + P(CWSliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE,tempID)); rightClickable + + break; + case DIV_INS_OPL: + // waveform + drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight)); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable + if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { + ImGui::SetTooltip("OPL2/3 only (last 4 waveforms are OPL3 only)"); + } + + // params + ImGui::Separator(); + if (ImGui::BeginTable("FMParamsInner",2)) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + bool amOn=op.am; + if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER + op.am=amOn; + } + ImGui::TableNextColumn(); + if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER + op.ksr=ksrOn; } - ImGui::SameLine(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER - op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER + op.vib=vibOn; + } + ImGui::TableNextColumn(); + if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER + op.sus=susOn; } - // params - ImGui::Separator(); + ImGui::EndTable(); + } + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); + P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_KSL)); + P(CWSliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE,tempID)); rightClickable + + break; + case DIV_INS_OPZ: { + // waveform + drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight)); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable + if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { + ImGui::SetTooltip("OPL2/3 only (last 4 waveforms are OPL3 only)"); + } + + // params + ImGui::Separator(); + if (egtOn) { + int block=op.dt; + int freqNum=(op.mult<<4)|(op.dvb&15); + ImGui::Text("Block"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImVec2 cursorAlign=ImGui::GetCursorPos(); + if (ImGui::InputInt("##Block",&block,1,1)) { + if (block<0) block=0; + if (block>7) block=7; + op.dt=block; + } + + ImGui::Text("Freq"); + ImGui::SameLine(); + ImGui::SetCursorPos(ImVec2(cursorAlign.x,ImGui::GetCursorPosY())); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##FreqNum",&freqNum,1,16)) { + if (freqNum<0) freqNum=0; + if (freqNum>255) freqNum=255; + op.mult=freqNum>>4; + op.dvb=freqNum&15; + } + } else { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable @@ -2231,106 +2374,26 @@ void FurnaceGUI::drawInsEdit() { if (CWSliderInt("##DT",&detune,-3,4,tempID)) { PARAMETER op.dt=detune+3; } rightClickable - - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT2)); - P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE,tempID)); rightClickable - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Only on YM2151 (OPM)"); - } - - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS)); - P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable - - break; } - case DIV_INS_OPL: - // waveform - drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight)); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable - if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { - ImGui::SetTooltip("OPL2/3 only (last 4 waveforms are OPL3 only)"); - } - // params - ImGui::Separator(); - if (ImGui::BeginTable("FMParamsInner",2)) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - bool amOn=op.am; - if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER - op.am=amOn; - } - ImGui::TableNextColumn(); - if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER - op.ksr=ksrOn; - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER - op.vib=vibOn; - } - ImGui::TableNextColumn(); - if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER - op.sus=susOn; - } - - ImGui::EndTable(); - } - - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); - P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable - - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_KSL)); - P(CWSliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE,tempID)); rightClickable - - break; - case DIV_INS_OPZ: { - // waveform - drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight)); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable - if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { - ImGui::SetTooltip("OPL2/3 only (last 4 waveforms are OPL3 only)"); - } - - // params - ImGui::Separator(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); - P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable - - int detune=(op.dt&7)-3; - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT)); - if (CWSliderInt("##DT",&detune,-3,4,tempID)) { PARAMETER - op.dt=detune+3; - } rightClickable - - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT2)); - P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE,tempID)); rightClickable - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Only on YM2151 (OPM)"); - } - - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS)); - P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable - break; + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT2)); + P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE,tempID)); rightClickable + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Only on YM2151 (OPM)"); } - default: - break; + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS)); + P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable + break; } + default: + break; } ImGui::TableNextColumn(); - float envHeight=sliderHeight-ImGui::GetStyle().ItemSpacing.y*2.0f; + float envHeight=sliderHeight;//-ImGui::GetStyle().ItemSpacing.y*2.0f; if (ins->type==DIV_INS_OPZ) { envHeight-=ImGui::GetFrameHeightWithSpacing()*2.0f; } @@ -2341,9 +2404,11 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::BeginTable("FMParamsInnerOPZ",2)) { ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_FINE)); - P(CWSliderScalar("##FINE",ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN,tempID)); rightClickable + if (!egtOn) { + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_FINE)); + P(CWSliderScalar("##FINE",ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN,tempID)); rightClickable + } ImGui::TableNextColumn(); bool amOn=op.am; @@ -2375,7 +2440,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); op.tl&=maxTl; - P(CWVSliderScalar("##TL",ImVec2(20.0f*dpiScale,sliderHeight-(ins->type==DIV_INS_FM?(ImGui::GetFrameHeightWithSpacing()+ImGui::CalcTextSize(FM_SHORT_NAME(FM_AM)).y+ImGui::GetStyle().ItemSpacing.y):0.0f)),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); + P(CWVSliderScalar("##TL",ImVec2(ImGui::GetFrameHeight(),sliderHeight-(ins->type==DIV_INS_FM?(ImGui::GetFrameHeightWithSpacing()+ImGui::CalcTextSize(FM_SHORT_NAME(FM_AM)).y+ImGui::GetStyle().ItemSpacing.y):0.0f)),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); if (ins->type==DIV_INS_FM) { CENTER_TEXT(FM_SHORT_NAME(FM_AM)); @@ -2388,178 +2453,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTable(); } - - /* - ImGui::SameLine(); - - bool amOn=op.am; - if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER - op.am=amOn; - } - - if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_OPZ) { - ImGui::SameLine(); - if (ImGui::Checkbox((ins->type==DIV_INS_OPLL)?FM_NAME(FM_EGS):"SSG On",&ssgOn)) { PARAMETER - op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); - } - if (ins->type==DIV_INS_FM) { - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Only for OPN family chips"); - } - } - } - - if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { - ImGui::SameLine(); - if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER - op.sus=susOn; - } - } - - //52.0 controls vert scaling; default 96 - drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,ImVec2(ImGui::GetContentRegionAvail().x,52.0*dpiScale),ins->type); - //P(CWSliderScalar(FM_NAME(FM_AR),ImGuiDataType_U8,&op.ar,&_ZERO,&_THIRTY_ONE)); rightClickable - if (ImGui::BeginTable("opParams",2,ImGuiTableFlags_SizingStretchProp)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); \ - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,0.0); \ - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - op.ar&=maxArDr; - P(CWSliderScalar("##AR",ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO)); rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_AR)); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - op.dr&=maxArDr; - P(CWSliderScalar("##DR",ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO)); rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_DR)); - - if (settings.susPosition==0) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - P(CWSliderScalar("##SL",ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_SL)); - } - - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - P(CWSliderScalar("##D2R",ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO)); rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_D2R)); - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - P(CWSliderScalar("##RR",ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO)); rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_RR)); - - if (settings.susPosition==1) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - P(CWSliderScalar("##SL",ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_SL)); - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - op.tl&=maxTl; - P(CWSliderScalar("##TL",ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_TL)); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Separator(); - ImGui::TableNextColumn(); - ImGui::Separator(); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { - P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE)); rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_RS)); - } else { - P(CWSliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE)); rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_KSL)); - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_MULT)); - - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { - int detune=(op.dt&7)-3; - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##DT",&detune,-3,4)) { PARAMETER - op.dt=detune+3; - } rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_DT)); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable - if (ImGui::IsItemHovered() && ins->type==DIV_INS_FM) { - ImGui::SetTooltip("Only on YM2151 (OPM)"); - } - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_DT2)); - - if (ins->type==DIV_INS_FM) { // OPN only - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER - op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); - } rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_SSG)); - } - } - - if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_WS)); - } - - ImGui::EndTable(); - } - - if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { - if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER - op.vib=vibOn; - } - ImGui::SameLine(); - if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER - op.ksr=ksrOn; - } - } - */ + ImGui::PopStyleVar(); if (settings.separateFMColors) { popAccentColors(); @@ -2569,6 +2463,7 @@ void FurnaceGUI::drawInsEdit() { } ImGui::EndTable(); } + ImGui::PopStyleVar(); } else { // classic int columns=2; switch (settings.fmLayout) { From 500e73b2a8e3cd91b70673b34305e0c42f4359b8 Mon Sep 17 00:00:00 2001 From: LoKiToon <98922449+LoKiToon@users.noreply.github.com> Date: Tue, 14 Jun 2022 11:58:43 +0300 Subject: [PATCH 034/101] Add files via upload --- demos/FDS TEST.fur | Bin 1574 -> 1587 bytes demos/Fake Gameboy.fur | Bin 0 -> 1255 bytes demos/c64 ring test.fur | Bin 0 -> 961 bytes demos/game boy thing.fur | Bin 0 -> 1204 bytes demos/thick bass test.fur | Bin 0 -> 17608 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/Fake Gameboy.fur create mode 100644 demos/c64 ring test.fur create mode 100644 demos/game boy thing.fur create mode 100644 demos/thick bass test.fur diff --git a/demos/FDS TEST.fur b/demos/FDS TEST.fur index 54b6d3b40607fd0367a5de8f511989df758bb900..54bdd36cd1ff9a0592b9072fff0960ea4336ce18 100644 GIT binary patch literal 1587 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 YJxxZG{!Y`=WEZ8s)AUsNUy`BxAD+J{f&c&j diff --git a/demos/Fake Gameboy.fur b/demos/Fake Gameboy.fur new file mode 100644 index 0000000000000000000000000000000000000000..50d7e36d90ecb33bde6b355e27588de842d1de79 GIT binary patch literal 1255 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 literal 0 HcmV?d00001 diff --git a/demos/thick bass test.fur b/demos/thick bass test.fur new file mode 100644 index 0000000000000000000000000000000000000000..13268e48bccb66cf5215b095a12af357a1f7361f GIT binary patch literal 17608 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%0Ad+f=45MvJpCdz5>I_YD8gu=$~%eP@a8V)qG! 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 Date: Tue, 14 Jun 2022 04:41:31 -0500 Subject: [PATCH 035/101] GUI: slight visualizer tweaks --- src/engine/engine.h | 3 ++- src/engine/playback.cpp | 4 +++ src/gui/gui.h | 2 ++ src/gui/pattern.cpp | 55 ++++++++++++++++++++++++++++++++++++++--- 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index dc16584de..1fa88a915 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -83,7 +83,7 @@ struct DivChannelState { int note, oldNote, lastIns, pitch, portaSpeed, portaNote; int volume, volSpeed, cut, rowDelay, volMax; int delayOrder, delayRow, retrigSpeed, retrigTick; - int vibratoDepth, vibratoRate, vibratoPos, vibratoDir, vibratoFine; + int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoDir, vibratoFine; int tremoloDepth, tremoloRate, tremoloPos; unsigned char arp, arpStage, arpTicks, panL, panR; bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff; @@ -112,6 +112,7 @@ struct DivChannelState { vibratoDepth(0), vibratoRate(0), vibratoPos(0), + vibratoPosGiant(0), vibratoDir(0), vibratoFine(15), tremoloDepth(0), diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index ed70da94b..f8cb79ac0 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -988,6 +988,10 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { if (chan[i].vibratoDepth>0) { chan[i].vibratoPos+=chan[i].vibratoRate; if (chan[i].vibratoPos>=64) chan[i].vibratoPos-=64; + + chan[i].vibratoPosGiant+=chan[i].vibratoRate; + if (chan[i].vibratoPos>=512) chan[i].vibratoPos-=512; + switch (chan[i].vibratoDir) { case 1: // up dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(MAX(0,(chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15))); diff --git a/src/gui/gui.h b/src/gui/gui.h index 55ea989c8..e5ad4a943 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1539,6 +1539,8 @@ class FurnaceGUI { void addScroll(int amount); void setFileName(String name); void runBackupThread(); + void pushPartBlend(); + void popPartBlend(); int processEvent(SDL_Event* ev); bool loop(); bool finish(); diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index fa00243c3..1d220795a 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -17,6 +17,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include +#include #include #define _USE_MATH_DEFINES #include "gui.h" @@ -31,6 +33,30 @@ inline float randRange(float min, float max) { return min+((float)rand()/(float)RAND_MAX)*(max-min); } +void _pushPartBlend(const ImDrawList* drawList, const ImDrawCmd* cmd) { + if (cmd!=NULL) { + if (cmd->UserCallbackData!=NULL) { + ((FurnaceGUI*)cmd->UserCallbackData)->pushPartBlend(); + } + } +} + +void _popPartBlend(const ImDrawList* drawList, const ImDrawCmd* cmd) { + if (cmd!=NULL) { + if (cmd->UserCallbackData!=NULL) { + ((FurnaceGUI*)cmd->UserCallbackData)->popPartBlend(); + } + } +} + +void FurnaceGUI::pushPartBlend() { + SDL_SetRenderDrawBlendMode(sdlRend,SDL_BLENDMODE_ADD); +} + +void FurnaceGUI::popPartBlend() { + SDL_SetRenderDrawBlendMode(sdlRend,SDL_BLENDMODE_BLEND); +} + // draw a pattern row inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache, bool inhibitSel) { static char id[32]; @@ -692,11 +718,14 @@ void FurnaceGUI::drawPattern() { ImU32* color=noteGrad; switch (i.cmd) { - case DIV_CMD_NOTE_ON: + case DIV_CMD_NOTE_ON: { + float strength=CLAMP(i.value,0,119); partIcon=ICON_FA_ASTERISK; - life=96.0f; + life=80.0f+((i.value==DIV_NOTE_NULL)?0.0f:(strength*0.3f)); lifeSpeed=3.0f; + num=6+(strength/16); break; + } case DIV_CMD_LEGATO: partIcon=ICON_FA_COG; color=insGrad; @@ -794,7 +823,7 @@ void FurnaceGUI::drawPattern() { float frameTime=ImGui::GetIO().DeltaTime*60.0f; - // note slides + // note slides and vibrato ImVec2 arrowPoints[7]; if (e->isPlaying()) for (int i=0; icurSubSong->chanShow[i]) continue; @@ -849,11 +878,30 @@ void FurnaceGUI::drawPattern() { } } } + if (ch->vibratoDepth>0) { + ImVec4 col=uiColors[GUI_COLOR_PATTERN_EFFECT_PITCH]; + col.w*=0.2; + float width=patChanX[i+1]-patChanX[i]; + + particles.push_back(Particle( + pitchGrad, + ICON_FA_GLASS, + off.x+patChanX[i]+(width*0.5+0.5*sin(M_PI*(float)ch->vibratoPosGiant/64.0f)*width)-scrollX, + off.y+(ImGui::GetWindowHeight()*0.5f)+randRange(0,patFont->FontSize), + randRange(-4.0f,4.0f), + 2.0f*(3.0f+(rand()%5)+ch->vibratoRate), + 0.4f, + 1.0f, + 128.0f, + 4.0f + )); + } } // particle simulation ImDrawList* fdl=ImGui::GetForegroundDrawList(); if (!particles.empty()) WAKE_UP; + fdl->AddCallback(_pushPartBlend,this); for (size_t i=0; iAddCallback(_popPartBlend,this); } ImGui::PopStyleColor(3); From cc06f36c92b8535c93a72e58bc3adc048a94b146 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 14 Jun 2022 14:08:28 -0500 Subject: [PATCH 036/101] GUI: fix dumb header insertion --- src/gui/pattern.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index 1d220795a..b7940a9e8 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -17,9 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include -#include -#include #define _USE_MATH_DEFINES #include "gui.h" #include "../ta-log.h" From dc9f1112d15f45168a388de6bae475dab9060aa6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 14 Jun 2022 23:00:20 -0500 Subject: [PATCH 037/101] MSM6258: fix rate being twice #541 --- src/engine/platform/msm6258.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index db1848cfa..731bf8f28 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -380,7 +380,7 @@ void DivPlatformMSM6258::setFlags(unsigned int flags) { chipClock=4000000; break; } - rate=chipClock/128; + rate=chipClock/256; for (int i=0; i<1; i++) { oscBuf[i]->rate=rate; } From 64f534328924013a93bda360bc0682315546b023 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 15 Jun 2022 02:03:20 -0500 Subject: [PATCH 038/101] I give up trying to fix this file dialog for now --- extern/igfd/ImGuiFileDialog.cpp | 10 ++++++---- src/gui/gui.cpp | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/extern/igfd/ImGuiFileDialog.cpp b/extern/igfd/ImGuiFileDialog.cpp index f7a2be5b1..776ad3738 100644 --- a/extern/igfd/ImGuiFileDialog.cpp +++ b/extern/igfd/ImGuiFileDialog.cpp @@ -1287,8 +1287,6 @@ namespace IGFD std::sort(prFileList.begin(), prFileList.end(), [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool { - if (a==NULL || b==NULL) - return false; if (!a.use_count() || !b.use_count()) return false; @@ -1760,7 +1758,7 @@ namespace IGFD struct stat statInfos = {}; char timebuf[100]; int result = stat(fpn.c_str(), &statInfos); - if (!result) + if (result!=-1) { if (vInfos->fileType != 'd') { @@ -1781,7 +1779,11 @@ namespace IGFD { vInfos->fileModifDate = std::string(timebuf, len); } - } + } else { + vInfos->fileSize=0; + vInfos->formatedFileSize = prFormatFileSize(vInfos->fileSize); + vInfos->fileModifDate="???"; + } } } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index b982987c3..fd904649c 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4105,6 +4105,7 @@ bool FurnaceGUI::init() { #ifndef __APPLE__ if (settings.dpiScale<0.5f) { + // TODO: replace with a function to actually detect the display scaling factor as it's unreliable. SDL_GetDisplayDPI(SDL_GetWindowDisplayIndex(sdlWin),&dpiScaleF,NULL,NULL); dpiScale=round(dpiScaleF/96.0f); if (dpiScale<1) dpiScale=1; From 491109e765812e725995087d2b3e606f0f35a8c9 Mon Sep 17 00:00:00 2001 From: LoKiToon <98922449+LoKiToon@users.noreply.github.com> Date: Wed, 15 Jun 2022 23:38:18 +0300 Subject: [PATCH 039/101] Add files via upload --- demos/Fusion.fur | Bin 0 -> 1881 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/Fusion.fur diff --git a/demos/Fusion.fur b/demos/Fusion.fur new file mode 100644 index 0000000000000000000000000000000000000000..a69f26e815e1ada047d94f642a76a8c0e204c657 GIT binary patch literal 1881 zcmZ8ec{tPwA7_wZS|mq~oDE@wMJzJ8k}G9%6;?!M3a^gO+Pe~$0x^ZDK-v3zDTbWB4M;1~~|dK?oj(({hG+ z70g6e0Uoni0X!0f_{ig?!?)hS=M6AkPlCb$LC%gjdsDD8VjKh1@jc1H2!@09%?0pr zN7|wx#{1C74XwG}@y^s)9%_d`2TdEF>PztlXZq?lWTT@Qk1jATu8h2V99XPqCUvCY zucJmy5&1is zzMTak@|(UTEoN=N*LRnVIsjkeXBSQHVnq7y)uYrVnzwQrE=*4IJB-+d?Tj*PKQ}hw zBtndHgOStPE6=YklpEVcd5&qU2)DUXr~cG8JH1~)UHW;}d|(zu?5t#2U12FyNfJ@HqatHN;C7T`weY8dVm^cZRT$2YWr6~ zku}W4#AIP^W~Pv|DNN0ARLShPrW(faXnv&LqbX=wdm&fBz@C`1+w}VX+AiaARiKoq zl`JcAC=GZ%(io8LO@^zEX!HNL9jQBGu;hVf6<)b*CS!Tk=|gdXPf5fN`6X;`Upnby zrrlw5u52EatWhu{ef0`!3N4m*iuH7%-fkxZi*{nbaZfj84AHLLNT+!?&LMky= z30`a}^zebPNwLA99}W7ZCz}lsm>(adyv)&^C;KAA;sPGVx+DpGPJV?ItEb&`PS>4p z)71eZ#INAhU?;jvHz>W?P1SoDEK0}4F4aCjZJ<&7L*24YbKjndKo*Q!mGrBW!zeN| zZ_7!)h{6d=Lt71hhcAmozp*An0!s8)NQ=4+Are85w&p;8m0d+Hhu&ZRLecCfJX4*r zVeRdBwT z!fBe;&o#SaY9wh9h$V+_>ANe^%AhTF z?2C}>Od-S&%}_tA*|kxSxy00wNRsgqtC4#7oE` Date: Thu, 16 Jun 2022 01:26:19 -0500 Subject: [PATCH 040/101] GUI: prepare for replace undo --- src/gui/editing.cpp | 8 +++++++- src/gui/findReplace.cpp | 10 ++++++++++ src/gui/gui.h | 3 ++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index ea12eb591..f299b1af2 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -66,6 +66,8 @@ void FurnaceGUI::prepareUndo(ActionType action) { e->curPat[i].getPattern(e->curOrders->ord[i][curOrder],false)->copyOn(oldPat[i]); } break; + case GUI_UNDO_REPLACE: // this is handled by doReplace() + break; } } @@ -86,7 +88,7 @@ void FurnaceGUI::makeUndo(ActionType action) { if (oldOrders.ord[i][j]!=e->curOrders->ord[i][j]) { s.ord.push_back(UndoOrderData(subSong,i,j,oldOrders.ord[i][j],e->curOrders->ord[i][j])); } - } + }SATGDIOPTASDIOKP;ASDTG } s.oldOrdersLen=oldOrdersLen; s.newOrdersLen=e->curSubSong->ordersLen; @@ -126,6 +128,8 @@ void FurnaceGUI::makeUndo(ActionType action) { doPush=true; } break; + case GUI_UNDO_REPLACE: // this is handled by doReplace() + break; } if (doPush) { MARK_MODIFIED; @@ -943,6 +947,7 @@ void FurnaceGUI::doUndo() { case GUI_UNDO_PATTERN_FLIP: case GUI_UNDO_PATTERN_COLLAPSE: case GUI_UNDO_PATTERN_EXPAND: + case GUI_UNDO_REPLACE: for (UndoPatternData& i: us.pat) { e->changeSongP(i.subSong); DivPattern* p=e->curPat[i.chan].getPattern(i.pat,true); @@ -991,6 +996,7 @@ void FurnaceGUI::doRedo() { case GUI_UNDO_PATTERN_FLIP: case GUI_UNDO_PATTERN_COLLAPSE: case GUI_UNDO_PATTERN_EXPAND: + case GUI_UNDO_REPLACE: for (UndoPatternData& i: us.pat) { e->changeSongP(i.subSong); DivPattern* p=e->curPat[i.chan].getPattern(i.pat,true); diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index d5548c0fb..5dae95bc5 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -189,6 +189,12 @@ void FurnaceGUI::doFind() { queryViewingResults=true; } +/* issues with the find and replace function: + - doesn't mark the module as modified + - can't undo + - replace notes to anything starting from C-0 to lower notes will have an octave higher, so set it to replace to C-0 it will becom C-1, b_1 will become B-0 and so on +*/ + void FurnaceGUI::doReplace() { doFind(); queryViewingResults=false; @@ -399,6 +405,10 @@ void FurnaceGUI::doReplace() { for (int i=0; i Date: Thu, 16 Jun 2022 02:09:57 -0500 Subject: [PATCH 041/101] fix build --- src/gui/editing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index f299b1af2..8b30d2514 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -88,7 +88,7 @@ void FurnaceGUI::makeUndo(ActionType action) { if (oldOrders.ord[i][j]!=e->curOrders->ord[i][j]) { s.ord.push_back(UndoOrderData(subSong,i,j,oldOrders.ord[i][j],e->curOrders->ord[i][j])); } - }SATGDIOPTASDIOKP;ASDTG + } } s.oldOrdersLen=oldOrdersLen; s.newOrdersLen=e->curSubSong->ordersLen; From c44ca95b92277578661f9d317b4ae80f4fc9bf07 Mon Sep 17 00:00:00 2001 From: Natt Akuma Date: Fri, 17 Jun 2022 03:06:07 +0700 Subject: [PATCH 042/101] Make volume command handling consistent For WonderSwan and VIC-20 --- src/engine/platform/swan.cpp | 2 +- src/engine/platform/vic20.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 73dc79281..905fa82a5 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -347,7 +347,7 @@ int DivPlatformSwan::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.vol.had) { + if (!chan[c.chan].std.vol.has) { calcAndWriteOutVol(c.chan,15); } } diff --git a/src/engine/platform/vic20.cpp b/src/engine/platform/vic20.cpp index a766ba443..8475b0e53 100644 --- a/src/engine/platform/vic20.cpp +++ b/src/engine/platform/vic20.cpp @@ -195,7 +195,7 @@ int DivPlatformVIC20::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.vol.had) { + if (!chan[c.chan].std.vol.has) { calcAndWriteOutVol(c.chan,15); } } From 7d78b393fb69619045c4d1cfb83999a31f29cde8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 16 Jun 2022 21:25:06 -0500 Subject: [PATCH 043/101] update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 06576ee52..566a3c3fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .vscode/ build/ +clangbuild/ nosdl/ release/ t/ From ed6a110d4493cbad3efc8852d74bf4739b4c12ec Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 16 Jun 2022 21:25:21 -0500 Subject: [PATCH 044/101] initialize SF_INFO before loading sample --- src/engine/engine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 76b2cd11a..dfac034cd 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2183,6 +2183,7 @@ int DivEngine::addSampleFromFile(const char* path) { return -1; #else SF_INFO si; + memset(&si,0,sizeof(SF_INFO)); SNDFILE* f=sf_open(path,SFM_READ,&si); if (f==NULL) { BUSY_END; From 327952f3f448591075516cc32844f9c52480845f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 16 Jun 2022 22:07:12 -0500 Subject: [PATCH 045/101] finally support loading floating-point samples --- src/engine/engine.cpp | 58 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index dfac034cd..b7a96209f 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2201,8 +2201,22 @@ int DivEngine::addSampleFromFile(const char* path) { BUSY_END; return -1; } - short* buf=new short[si.channels*si.frames]; - if (sf_readf_short(f,buf,si.frames)!=si.frames) { + void* buf=NULL; + sf_count_t sampleLen=sizeof(short); + if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) { + logD("sample is 8-bit unsigned"); + buf=new unsigned char[si.channels*si.frames]; + sampleLen=sizeof(unsigned char); + } else if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_FLOAT) { + logD("sample is 32-bit float"); + buf=new float[si.channels*si.frames]; + sampleLen=sizeof(float); + } else { + logD("sample is 16-bit signed"); + buf=new short[si.channels*si.frames]; + sampleLen=sizeof(short); + } + if (sf_read_raw(f,buf,si.frames*si.channels*sampleLen)!=(si.frames*si.channels*sampleLen)) { logW("sample read size mismatch!"); } DivSample* sample=new DivSample; @@ -2216,19 +2230,41 @@ int DivEngine::addSampleFromFile(const char* path) { sample->depth=16; } sample->init(si.frames); - for (int i=0; idata8[index++]=averaged; } - averaged/=si.channels; - if (((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8)) { - sample->data8[index++]=averaged>>8; - } else { + delete[] (unsigned char*)buf; + } else if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_FLOAT) { + for (int i=0; i32767.0) averaged=32767.0; sample->data16[index++]=averaged; } + delete[] (float*)buf; + } else { + for (int i=0; idata16[index++]=averaged; + } + delete[] (short*)buf; } - delete[] buf; + sample->rate=si.samplerate; if (sample->rate<4000) sample->rate=4000; if (sample->rate>96000) sample->rate=96000; From cdbcf7fcd3789dbd77997a657d4ece2595cc3cdf Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 16 Jun 2022 22:10:57 -0500 Subject: [PATCH 046/101] fix loading 8-bit samples --- src/engine/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index b7a96209f..ecd095de0 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2234,7 +2234,7 @@ int DivEngine::addSampleFromFile(const char* path) { for (int i=0; idata8[index++]=averaged; From 4d44c577e734507a4e65b0e0898a6f9138fc8e15 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 16 Jun 2022 23:22:40 -0500 Subject: [PATCH 047/101] support saving 8-bit samples as-is --- src/engine/sample.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 534410953..36886856c 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -51,7 +51,14 @@ bool DivSample::save(const char* path) { si.channels=1; si.samplerate=rate; - si.format=SF_FORMAT_PCM_16|SF_FORMAT_WAV; + switch (depth) { + case 8: // 8-bit + si.format=SF_FORMAT_PCM_U8|SF_FORMAT_WAV; + break; + default: // 16-bit + si.format=SF_FORMAT_PCM_16|SF_FORMAT_WAV; + break; + } f=sf_open(path,SFM_WRITE,&si); @@ -77,7 +84,21 @@ bool DivSample::save(const char* path) { } sf_command(f, SFC_SET_INSTRUMENT, &inst, sizeof(inst)); - sf_writef_short(f,data16,samples); + switch (depth) { + case 8: { + // convert from signed to unsigned + unsigned char* buf=new unsigned char[length8]; + for (size_t i=0; i Date: Thu, 16 Jun 2022 23:39:38 -0500 Subject: [PATCH 048/101] harden sample movement --- src/engine/engine.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index ecd095de0..0812535c6 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2067,6 +2067,8 @@ int DivEngine::addSample() { sample->name=fmt::sprintf("Sample %d",sampleCount); song.sample.push_back(sample); song.sampleLen=sampleCount+1; + sPreview.sample=-1; + sPreview.pos=0; saveLock.unlock(); renderSamples(); BUSY_END; @@ -2302,6 +2304,8 @@ int DivEngine::addSampleFromFile(const char* path) { void DivEngine::delSample(int index) { BUSY_BEGIN; + sPreview.sample=-1; + sPreview.pos=0; saveLock.lock(); if (index>=0 && index<(int)song.sample.size()) { delete song.sample[index]; @@ -2516,6 +2520,8 @@ bool DivEngine::moveWaveUp(int which) { bool DivEngine::moveSampleUp(int which) { if (which<1 || which>=(int)song.sample.size()) return false; BUSY_BEGIN; + sPreview.sample=-1; + sPreview.pos=0; DivSample* prev=song.sample[which]; saveLock.lock(); song.sample[which]=song.sample[which-1]; @@ -2553,6 +2559,8 @@ bool DivEngine::moveWaveDown(int which) { bool DivEngine::moveSampleDown(int which) { if (which<0 || which>=((int)song.sample.size())-1) return false; BUSY_BEGIN; + sPreview.sample=-1; + sPreview.pos=0; DivSample* prev=song.sample[which]; saveLock.lock(); song.sample[which]=song.sample[which+1]; From ad5072dad675199ec11d02c5158c310724c8e775 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 16 Jun 2022 23:55:17 -0500 Subject: [PATCH 049/101] more MIDI debugging messages --- src/audio/abstract.cpp | 2 ++ src/engine/engine.cpp | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/audio/abstract.cpp b/src/audio/abstract.cpp index e44fdf7eb..942e31438 100644 --- a/src/audio/abstract.cpp +++ b/src/audio/abstract.cpp @@ -92,10 +92,12 @@ bool TAMidiOut::closeDevice() { } std::vector TAMidiIn::listDevices() { + logW("attempting to list devices of abstract TAMidiIn!"); return std::vector(); } std::vector TAMidiOut::listDevices() { + logW("attempting to list devices of abstract TAMidiOut!"); return std::vector(); } diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 0812535c6..8ce31a604 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -3025,6 +3025,8 @@ bool DivEngine::initAudioBackend() { if (!output->midiIn->openDevice(inName)) { logW("could not open MIDI input device!"); } + } else { + logV("no MIDI input device selected."); } } if (output->midiOut) { @@ -3035,6 +3037,8 @@ bool DivEngine::initAudioBackend() { if (!output->midiOut->openDevice(outName)) { logW("could not open MIDI output device!"); } + } else { + logV("no MIDI output device selected."); } } From d5d381328bddc84262dbd61c2c83c4f3174a5c8f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 17 Jun 2022 00:02:29 -0500 Subject: [PATCH 050/101] add modified version of Native File Dialog it will replace portable-file-dialogs on Windows, and perhaps in the rest of operating systems (maybe not Linux) as well. --- extern/nfd-modified/.gitignore | 181 +++++ extern/nfd-modified/LICENSE | 16 + extern/nfd-modified/MODIFIED.md | 7 + extern/nfd-modified/README.md | 182 +++++ extern/nfd-modified/docs/build.md | 39 + extern/nfd-modified/docs/contributing.md | 25 + extern/nfd-modified/src/common.h | 21 + extern/nfd-modified/src/include/nfd.h | 74 ++ extern/nfd-modified/src/nfd_cocoa.m | 286 +++++++ extern/nfd-modified/src/nfd_common.c | 142 ++++ extern/nfd-modified/src/nfd_common.h | 39 + extern/nfd-modified/src/nfd_gtk.c | 379 +++++++++ extern/nfd-modified/src/nfd_win.cpp | 762 ++++++++++++++++++ extern/nfd-modified/src/nfd_zenity.c | 307 +++++++ extern/nfd-modified/src/simple_exec.h | 218 +++++ extern/nfd-modified/test/test_opendialog.c | 29 + .../test/test_opendialogmultiple.c | 32 + extern/nfd-modified/test/test_pickfolder.c | 29 + extern/nfd-modified/test/test_savedialog.c | 28 + 19 files changed, 2796 insertions(+) create mode 100644 extern/nfd-modified/.gitignore create mode 100644 extern/nfd-modified/LICENSE create mode 100644 extern/nfd-modified/MODIFIED.md create mode 100644 extern/nfd-modified/README.md create mode 100644 extern/nfd-modified/docs/build.md create mode 100644 extern/nfd-modified/docs/contributing.md create mode 100644 extern/nfd-modified/src/common.h create mode 100644 extern/nfd-modified/src/include/nfd.h create mode 100644 extern/nfd-modified/src/nfd_cocoa.m create mode 100644 extern/nfd-modified/src/nfd_common.c create mode 100644 extern/nfd-modified/src/nfd_common.h create mode 100644 extern/nfd-modified/src/nfd_gtk.c create mode 100644 extern/nfd-modified/src/nfd_win.cpp create mode 100644 extern/nfd-modified/src/nfd_zenity.c create mode 100644 extern/nfd-modified/src/simple_exec.h create mode 100644 extern/nfd-modified/test/test_opendialog.c create mode 100644 extern/nfd-modified/test/test_opendialogmultiple.c create mode 100644 extern/nfd-modified/test/test_pickfolder.c create mode 100644 extern/nfd-modified/test/test_savedialog.c diff --git a/extern/nfd-modified/.gitignore b/extern/nfd-modified/.gitignore new file mode 100644 index 000000000..5f144cbee --- /dev/null +++ b/extern/nfd-modified/.gitignore @@ -0,0 +1,181 @@ +.sconsign.dblite +# Object files +*.o +*.ko +*.obj +*.elf +# Precompiled Headers +*.gch +*.pch +# Libraries +*.lib +*.a +*.la +*.lo +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates +# User-specific folders +*.sln.ide/ +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +# Roslyn cache directories +*.ide/ +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* +#NUNIT +*.VisualState.xml +TestResult.xml +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc +# Chutzpah Test files +_Chutzpah* +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile +# Visual Studio profiler +*.psess +*.vsp +*.vspx +# TFS 2012 Local Workspace +$tf/ +# Guidance Automation Toolkit +*.gpState +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user +# JustCode is a .NET coding addin-in +.JustCode +# TeamCity is a build add-in +_TeamCity* +# DotCover is a Code Coverage Tool +*.dotCover +# NCrunch +_NCrunch_* +.*crunch*.local.xml +# MightyMoose +*.mm.* +AutoTest.Net/ +# Web workbench (sass) +.sass-cache/ +# Installshield output folder +[Ee]xpress/ +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html +# Click-Once directory +publish/ +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# If using the old MSBuild-Integrated Package Restore, uncomment this: +#!**/packages/repositories.config +# Windows Azure Build Output +csx/ +*.build.csdef +# Windows Store app package directory +AppPackages/ +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +bower_components/ +# RIA/Silverlight projects +Generated_Code/ +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +# SQL Server files +*.mdf +*.ldf +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +# Microsoft Fakes +FakesAssemblies/ diff --git a/extern/nfd-modified/LICENSE b/extern/nfd-modified/LICENSE new file mode 100644 index 000000000..3ab103c55 --- /dev/null +++ b/extern/nfd-modified/LICENSE @@ -0,0 +1,16 @@ +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + diff --git a/extern/nfd-modified/MODIFIED.md b/extern/nfd-modified/MODIFIED.md new file mode 100644 index 000000000..bb542f8bb --- /dev/null +++ b/extern/nfd-modified/MODIFIED.md @@ -0,0 +1,7 @@ +# MODIFIED + +this is a modified, altered, edited and revised version of the Native File Dialog library used to display native-feeling, original and operating-system specific file archive dialog picker selectors, which is done by the Native File Dialog library. + +it should not and shall NOT be mistaken for the original, authentic or actual version and revision of the library. + +this is a version tailored for Furnace. diff --git a/extern/nfd-modified/README.md b/extern/nfd-modified/README.md new file mode 100644 index 000000000..fd7a97832 --- /dev/null +++ b/extern/nfd-modified/README.md @@ -0,0 +1,182 @@ +# Native File Dialog Modified Version!!! # + +A tiny, neat C library that portably invokes native file open, folder select and save dialogs. Write dialog code once and have it pop up native dialogs on all supported platforms. Avoid linking large dependencies like wxWidgets and qt. + +This is a modified version of Native File Dialog, tailored for Furnace. + +Features: + + - Lean C API, static library -- no ObjC, no C++, no STL. + - Zlib licensed. + - Consistent UTF-8 support on all platforms. + - Simple universal file filter syntax. + - Paid support available. + - Multiple file selection support. + - 64-bit and 32-bit friendly. + - GCC, Clang, Xcode, Mingw and Visual Studio supported. + - No third party dependencies for building or linking. + - Support for Vista's modern `IFileDialog` on Windows. + - Support for non-deprecated Cocoa APIs on OS X. + - GTK3 dialog on Linux. + - Optional Zenity support on Linux to avoid linking GTK. + - Tested, works alongside [http://www.libsdl.org](SDL2) on all platforms, for the game developers out there. + +# Example Usage # + +```C +#include +#include +#include + +int main( void ) +{ + nfdchar_t *outPath = NULL; + nfdresult_t result = NFD_OpenDialog( NULL, NULL, &outPath ); + + if ( result == NFD_OKAY ) { + puts("Success!"); + puts(outPath); + free(outPath); + } + else if ( result == NFD_CANCEL ) { + puts("User pressed cancel."); + } + else { + printf("Error: %s\n", NFD_GetError() ); + } + + return 0; +} +``` + +See self-documenting API [NFD.h](src/include/nfd.h) for more options. + +# Screenshots # + +![Windows rendering a dialog](screens/open_win.png?raw=true) +![GTK3 on Linux rendering a dialog](screens/open_gtk3.png?raw=true) +![Cocoa on MacOS rendering a dialog](screens/open_cocoa.png?raw=true) + +## Changelog ## + + - **Major** version increments denote API or ABI departure. + - **Minor** version increments denote build or trivial departures. + - **Micro** version increments just recompile and drop-in. + +release | what's new | date +--------|-----------------------------|--------- +1.0.0 | initial | oct 2014 +1.1.0 | premake5; scons deprecated | aug 2016 +1.1.1 | mingw support, build fixes | aug 2016 +1.1.2 | test_pickfolder() added | aug 2016 +1.1.3 | zenity linux backend added | nov 2017 + | fix char type in decls | nov 2017 +1.1.4 | fix win32 memleaks | dec 2018 + | improve win32 errorhandling | dec 2018 + | macos fix focus bug | dec 2018 +1.1.5 | win32 fix com reinitialize | aug 2019 +1.1.6 | fix osx filter bug | aug 2019 + | remove deprecated scons | aug 2019 + | fix mingw compilation | aug 2019 + | -Wextra warning cleanup | aug 2019 + +## Building ## + +NFD uses [Premake5](https://premake.github.io/download.html) generated Makefiles and IDE project files. The generated project files are checked in under `build/` so you don't have to download and use Premake in most cases. + +If you need to run Premake5 directly, further [build documentation](docs/build.md) is available. + +Previously, NFD used SCons to build. As of 1.1.6, SCons support has been removed entirely. + +`nfd.a` will be built for release builds, and `nfd_d.a` will be built for debug builds. + +### Makefiles ### + +The makefile offers up to four options, with `release_x64` as the default. + + make config=release_x86 + make config=release_x64 + make config=debug_x86 + make config=debug_x64 + +### Compiling Your Programs ### + + 1. Add `src/include` to your include search path. + 2. Add `nfd.lib` or `nfd_d.lib` to the list of list of static libraries to link against (for release or debug, respectively). + 3. Add `build//` to the library search path. + +#### Linux GTK #### + +`apt-get libgtk-3-dev` installs the gtk dependency for library compilation. + +On Linux, you have the option of compiling and linking against GTK. If you use it, the recommended way to compile is to include the arguments of `pkg-config --cflags --libs gtk+-3.0`. + +#### Linux Zenity #### + +Alternatively, you can use the Zenity backend by running the Makefile in `build/gmake_linux_zenity`. Zenity runs the dialog in its own address space, but requires the user to have Zenity correctly installed and configured on their system. + +#### MacOS #### + +On Mac OS, add `AppKit` to the list of frameworks. + +#### Windows #### + +On Windows, ensure you are linking against `comctl32.lib`. + +## Usage ## + +See `NFD.h` for API calls. See `tests/*.c` for example code. + +After compiling, `build/bin` contains compiled test programs. The appropriate subdirectory under `build/lib` contains the built library. + +## File Filter Syntax ## + +There is a form of file filtering in every file dialog API, but no consistent means of supporting it. NFD provides support for filtering files by groups of extensions, providing its own descriptions (where applicable) for the extensions. + +A wildcard filter is always added to every dialog. + +### Separators ### + + - `;` Begin a new filter. + - `,` Add a separate type to the filter. + +#### Examples #### + +`txt` The default filter is for text files. There is a wildcard option in a dropdown. + +`png,jpg;psd` The default filter is for png and jpg files. A second filter is available for psd files. There is a wildcard option in a dropdown. + +`NULL` Wildcard only. + +## Iterating Over PathSets ## + +See [test_opendialogmultiple.c](test/test_opendialogmultiple.c). + +# Known Limitations # + +I accept quality code patches, or will resolve these and other matters through support. See [contributing](docs/contributing.md) for details. + + - No support for Windows XP's legacy dialogs such as `GetOpenFileName`. + - No support for file filter names -- ex: "Image Files" (*.png, *.jpg). Nameless filters are supported, however. + - GTK Zenity implementation's process exec error handling does not gracefully handle numerous error cases, choosing to abort rather than cleanup and return. + - GTK 3 spams one warning per dialog created. + +# Copyright and Credit # + +Copyright © 2014-2019 [Frogtoss Games](http://www.frogtoss.com), Inc. +File [LICENSE](LICENSE) covers all files in this repo. + +Native File Dialog by Michael Labbe + + +Tomasz Konojacki for [microutf8](http://puszcza.gnu.org.ua/software/microutf8/) + +[Denis Kolodin](https://github.com/DenisKolodin) for mingw support. + +[Tom Mason](https://github.com/wheybags) for Zenity support. + +## Support ## + +Directed support for this work is available from the original author under a paid agreement. + +[Contact Frogtoss Games](http://www.frogtoss.com/pages/contact.html). diff --git a/extern/nfd-modified/docs/build.md b/extern/nfd-modified/docs/build.md new file mode 100644 index 000000000..a1f732719 --- /dev/null +++ b/extern/nfd-modified/docs/build.md @@ -0,0 +1,39 @@ +# Building NFD # + +Most of the building instructions are included in [README.md](/README.md). This file just contains apocrypha. + +## Running Premake5 Directly ## + +*You shouldn't have to run Premake5 directly to build Native File Dialog. This is for package maintainers or people with exotic demands only!* + +1. [Clone premake-core](https://github.com/premake/premake-core) +2. [Follow instructions on how to build premake](https://github.com/premake/premake-core/wiki/Building-Premake) +3. `cd` to `build` +4. Type `premake5 `, where is the build you want to create. + +### Package Maintainer Only ### + +I support a custom Premake action: `premake5 dist`, which generates all of the checked in project types in subdirectories. It is useful to run this command if you are submitting a pull request to test all of the supported premake configurations. Do not check in the built projects; I will do so while accepting your pull request. + +## SCons build (deprecated) ## + +As of 1.1.6, the deprecated and unmaintained SCons support is removed. + +## Compiling with Mingw ## + +Use the Makefile in `build/gmake_windows` to build Native File Dialog with mingw. Mingw has many distributions and not all of them are reliable. Here is what worked for me, the primary author of Native File Dialog: + +1. Use mingw64, not mingw32. Downloaded from [sourceforge.net](https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/installer/mingw-w64-install.exe/download). +2. When prompted in the intsaller, install the basic compiler and g++. +3. Add the installed bin dir to command prompt path. +4. Run `set CC=g++` to enforce `g++` instead of the default, `cc` for compiling and linking. +5. In `build/gmake_windows`, run `mingw32-make config=release_x64 clean`. Running clean ensures no Visual Studio build products conflict which can cause link errors. +6. Now run `mingw32-make config=release_x64`. + +The author has not attempted to build or even install an x86 toolchain for mingw. + +If you report an issue, be sure to run make with `verbose=1` so commands are visible. + +## Adding NFD source directly to your project ## + +Lots of developers add NFD source directly to their projects instead of using the included build scripts. As of 1.1.6, this is an acknowledged approach to building. Of course, everyone has a slightly different toolchain with various warnings and linters enabled. If you run a linter or catch a warning, please consider submitting a pull request to help NFD build cleanly for everyone. diff --git a/extern/nfd-modified/docs/contributing.md b/extern/nfd-modified/docs/contributing.md new file mode 100644 index 000000000..f6c3b54cc --- /dev/null +++ b/extern/nfd-modified/docs/contributing.md @@ -0,0 +1,25 @@ +# Pull Requests # + +I have had to turn away a number of pull requests due to avoidable circumstances. Please read this file before submitting a pull request. Also look at existing, rejected pull requests which state the reason for rejection. + +Here are the rules: + +- **Submit pull requests to the devel branch**. The library must be tested on every compiler and OS, so there is no way I am going to just put your change in the master before it has been sync'd and tested on a number of machines. Master branch is depended upon by hundreds of projects. + +- **Test your changes on all platforms and compilers that you can.** Also, state which platforms you have tested your code on. 32-bit or 64-bit. Clang or GCC. Visual Studio or Mingw. I have to test all these to accept pull requests, so I prioritize changes that respect my time. + +- **Submit Premake build changes only**. As of 1.1, SCons is deprecated. Also, do not submit altered generated projects. I will re-run Premake to re-generate them to ensure that I can still generate the project prior to admitting your pull request. + +- **Do not alter existing behavior to support your desired behavior**. For instance, rewriting file open dialogs to behave differently, while trading off functionality for compatibility, will get you rejected. Consider creating an additional code path. Instead of altering `nfd_win.cpp` to support Windows XP, create `nfd_win_legacy.cpp`, which exists alongside the newer file dialog. + +- **Do not submit anything I can't verify or maintain**. If you add support for a compiler, include from-scratch install instructions that you have tested yourself. Accepting a pull request means I am now the maintainer of your code, so I must understand what it does and how to test it. + +- **Do not change the externally facing API**. NFD needs to maintain ABI compatibility. + +## Submitting Cloud Autobuild systems ## + +I have received a few pull requests for Travis and AppVeyor-based autobuilding which I have not accepted. NativeFileDialog is officially covered by my private BuildBot network which supports all three target OSes, both CPU architectures and four compilers. I take the view that having a redundant, lesser autobuild system does not improve coverage: it gives a false positive when partial building succeeds. Please do not invest time into cloud-based building with the hope of a pull request being accepted. + +## Contact Me ## + +Despite all of the "do nots" above, I am happy to recieve new pull requests! If you have any questions about style, or what I would need to accept your specific request, please contact me ahead of submitting the pull request by opening an issue on Github with your question. I will do my best to answer you. diff --git a/extern/nfd-modified/src/common.h b/extern/nfd-modified/src/common.h new file mode 100644 index 000000000..7745d323b --- /dev/null +++ b/extern/nfd-modified/src/common.h @@ -0,0 +1,21 @@ +/* + Native File Dialog + + Internal, common across platforms + + http://www.frogtoss.com/labs + */ + + +#ifndef _NFD_COMMON_H +#define _NFD_COMMON_H + +#define NFD_MAX_STRLEN 256 +#define _NFD_UNUSED(x) ((void)x) + +void *NFDi_Malloc( size_t bytes ); +void NFDi_Free( void *ptr ); +void NFDi_SetError( const char *msg ); +void NFDi_SafeStrncpy( char *dst, const char *src, size_t maxCopy ); + +#endif diff --git a/extern/nfd-modified/src/include/nfd.h b/extern/nfd-modified/src/include/nfd.h new file mode 100644 index 000000000..74c92743f --- /dev/null +++ b/extern/nfd-modified/src/include/nfd.h @@ -0,0 +1,74 @@ +/* + Native File Dialog + + User API + + http://www.frogtoss.com/labs + */ + + +#ifndef _NFD_H +#define _NFD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* denotes UTF-8 char */ +typedef char nfdchar_t; + +/* opaque data structure -- see NFD_PathSet_* */ +typedef struct { + nfdchar_t *buf; + size_t *indices; /* byte offsets into buf */ + size_t count; /* number of indices into buf */ +}nfdpathset_t; + +typedef enum { + NFD_ERROR, /* programmatic error */ + NFD_OKAY, /* user pressed okay, or successful return */ + NFD_CANCEL /* user pressed cancel */ +}nfdresult_t; + + +/* nfd_.c */ + +/* single file open dialog */ +nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ); + +/* multiple file open dialog */ +nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdpathset_t *outPaths ); + +/* save dialog */ +nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ); + + +/* select folder dialog */ +nfdresult_t NFD_PickFolder( const nfdchar_t *defaultPath, + nfdchar_t **outPath); + +/* nfd_common.c */ + +/* get last error -- set when nfdresult_t returns NFD_ERROR */ +const char *NFD_GetError( void ); +/* get the number of entries stored in pathSet */ +size_t NFD_PathSet_GetCount( const nfdpathset_t *pathSet ); +/* Get the UTF-8 path at offset index */ +nfdchar_t *NFD_PathSet_GetPath( const nfdpathset_t *pathSet, size_t index ); +/* Free the pathSet */ +void NFD_PathSet_Free( nfdpathset_t *pathSet ); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extern/nfd-modified/src/nfd_cocoa.m b/extern/nfd-modified/src/nfd_cocoa.m new file mode 100644 index 000000000..776152d41 --- /dev/null +++ b/extern/nfd-modified/src/nfd_cocoa.m @@ -0,0 +1,286 @@ +/* + Native File Dialog + + http://www.frogtoss.com/labs + */ + +#include +#include "nfd.h" +#include "nfd_common.h" + +static NSArray *BuildAllowedFileTypes( const char *filterList ) +{ + // Commas and semicolons are the same thing on this platform + + NSMutableArray *buildFilterList = [[NSMutableArray alloc] init]; + + char typebuf[NFD_MAX_STRLEN] = {0}; + + size_t filterListLen = strlen(filterList); + char *p_typebuf = typebuf; + for ( size_t i = 0; i < filterListLen+1; ++i ) + { + if ( filterList[i] == ',' || filterList[i] == ';' || filterList[i] == '\0' ) + { + if (filterList[i] != '\0') + ++p_typebuf; + *p_typebuf = '\0'; + + NSString *thisType = [NSString stringWithUTF8String: typebuf]; + [buildFilterList addObject:thisType]; + p_typebuf = typebuf; + *p_typebuf = '\0'; + } + else + { + *p_typebuf = filterList[i]; + ++p_typebuf; + + } + } + + NSArray *returnArray = [NSArray arrayWithArray:buildFilterList]; + + [buildFilterList release]; + return returnArray; +} + +static void AddFilterListToDialog( NSSavePanel *dialog, const char *filterList ) +{ + if ( !filterList || strlen(filterList) == 0 ) + return; + + NSArray *allowedFileTypes = BuildAllowedFileTypes( filterList ); + if ( [allowedFileTypes count] != 0 ) + { + [dialog setAllowedFileTypes:allowedFileTypes]; + } +} + +static void SetDefaultPath( NSSavePanel *dialog, const nfdchar_t *defaultPath ) +{ + if ( !defaultPath || strlen(defaultPath) == 0 ) + return; + + NSString *defaultPathString = [NSString stringWithUTF8String: defaultPath]; + NSURL *url = [NSURL fileURLWithPath:defaultPathString isDirectory:YES]; + [dialog setDirectoryURL:url]; +} + + +/* fixme: pathset should be pathSet */ +static nfdresult_t AllocPathSet( NSArray *urls, nfdpathset_t *pathset ) +{ + assert(pathset); + assert([urls count]); + + pathset->count = (size_t)[urls count]; + pathset->indices = NFDi_Malloc( sizeof(size_t)*pathset->count ); + if ( !pathset->indices ) + { + return NFD_ERROR; + } + + // count the total space needed for buf + size_t bufsize = 0; + for ( NSURL *url in urls ) + { + NSString *path = [url path]; + bufsize += [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1; + } + + pathset->buf = NFDi_Malloc( sizeof(nfdchar_t) * bufsize ); + if ( !pathset->buf ) + { + return NFD_ERROR; + } + + // fill buf + nfdchar_t *p_buf = pathset->buf; + size_t count = 0; + for ( NSURL *url in urls ) + { + NSString *path = [url path]; + const nfdchar_t *utf8Path = [path UTF8String]; + size_t byteLen = [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1; + memcpy( p_buf, utf8Path, byteLen ); + + ptrdiff_t index = p_buf - pathset->buf; + assert( index >= 0 ); + pathset->indices[count] = (size_t)index; + + p_buf += byteLen; + ++count; + } + + return NFD_OKAY; +} + +/* public */ + + +nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; + NSOpenPanel *dialog = [NSOpenPanel openPanel]; + [dialog setAllowsMultipleSelection:NO]; + + // Build the filter list + AddFilterListToDialog(dialog, filterList); + + // Set the starting directory + SetDefaultPath(dialog, defaultPath); + + nfdresult_t nfdResult = NFD_CANCEL; + if ( [dialog runModal] == NSModalResponseOK ) + { + NSURL *url = [dialog URL]; + const char *utf8Path = [[url path] UTF8String]; + + // byte count, not char count + size_t len = strlen(utf8Path);//NFDi_UTF8_Strlen(utf8Path); + + *outPath = NFDi_Malloc( len+1 ); + if ( !*outPath ) + { + [pool release]; + [keyWindow makeKeyAndOrderFront:nil]; + return NFD_ERROR; + } + memcpy( *outPath, utf8Path, len+1 ); /* copy null term */ + nfdResult = NFD_OKAY; + } + [pool release]; + + [keyWindow makeKeyAndOrderFront:nil]; + return nfdResult; +} + + +nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdpathset_t *outPaths ) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; + + NSOpenPanel *dialog = [NSOpenPanel openPanel]; + [dialog setAllowsMultipleSelection:YES]; + + // Build the fiter list. + AddFilterListToDialog(dialog, filterList); + + // Set the starting directory + SetDefaultPath(dialog, defaultPath); + + nfdresult_t nfdResult = NFD_CANCEL; + if ( [dialog runModal] == NSModalResponseOK ) + { + NSArray *urls = [dialog URLs]; + + if ( [urls count] == 0 ) + { + [pool release]; + [keyWindow makeKeyAndOrderFront:nil]; + return NFD_CANCEL; + } + + if ( AllocPathSet( urls, outPaths ) == NFD_ERROR ) + { + [pool release]; + [keyWindow makeKeyAndOrderFront:nil]; + return NFD_ERROR; + } + + nfdResult = NFD_OKAY; + } + [pool release]; + + [keyWindow makeKeyAndOrderFront:nil]; + return nfdResult; +} + + +nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; + + NSSavePanel *dialog = [NSSavePanel savePanel]; + [dialog setExtensionHidden:NO]; + + // Build the filter list. + AddFilterListToDialog(dialog, filterList); + + // Set the starting directory + SetDefaultPath(dialog, defaultPath); + + nfdresult_t nfdResult = NFD_CANCEL; + if ( [dialog runModal] == NSModalResponseOK ) + { + NSURL *url = [dialog URL]; + const char *utf8Path = [[url path] UTF8String]; + + size_t byteLen = [url.path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1; + + *outPath = NFDi_Malloc( byteLen ); + if ( !*outPath ) + { + [pool release]; + [keyWindow makeKeyAndOrderFront:nil]; + return NFD_ERROR; + } + memcpy( *outPath, utf8Path, byteLen ); + nfdResult = NFD_OKAY; + } + + [pool release]; + [keyWindow makeKeyAndOrderFront:nil]; + return nfdResult; +} + +nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, + nfdchar_t **outPath) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; + NSOpenPanel *dialog = [NSOpenPanel openPanel]; + [dialog setAllowsMultipleSelection:NO]; + [dialog setCanChooseDirectories:YES]; + [dialog setCanCreateDirectories:YES]; + [dialog setCanChooseFiles:NO]; + + // Set the starting directory + SetDefaultPath(dialog, defaultPath); + + nfdresult_t nfdResult = NFD_CANCEL; + if ( [dialog runModal] == NSModalResponseOK ) + { + NSURL *url = [dialog URL]; + const char *utf8Path = [[url path] UTF8String]; + + // byte count, not char count + size_t len = strlen(utf8Path);//NFDi_UTF8_Strlen(utf8Path); + + *outPath = NFDi_Malloc( len+1 ); + if ( !*outPath ) + { + [pool release]; + [keyWindow makeKeyAndOrderFront:nil]; + return NFD_ERROR; + } + memcpy( *outPath, utf8Path, len+1 ); /* copy null term */ + nfdResult = NFD_OKAY; + } + [pool release]; + + [keyWindow makeKeyAndOrderFront:nil]; + return nfdResult; +} diff --git a/extern/nfd-modified/src/nfd_common.c b/extern/nfd-modified/src/nfd_common.c new file mode 100644 index 000000000..55517f5dd --- /dev/null +++ b/extern/nfd-modified/src/nfd_common.c @@ -0,0 +1,142 @@ +/* + Native File Dialog + + http://www.frogtoss.com/labs + */ + +#include +#include +#include +#include "nfd_common.h" + +static char g_errorstr[NFD_MAX_STRLEN] = {0}; + +/* public routines */ + +const char *NFD_GetError( void ) +{ + return g_errorstr; +} + +size_t NFD_PathSet_GetCount( const nfdpathset_t *pathset ) +{ + assert(pathset); + return pathset->count; +} + +nfdchar_t *NFD_PathSet_GetPath( const nfdpathset_t *pathset, size_t num ) +{ + assert(pathset); + assert(num < pathset->count); + + return pathset->buf + pathset->indices[num]; +} + +void NFD_PathSet_Free( nfdpathset_t *pathset ) +{ + assert(pathset); + NFDi_Free( pathset->indices ); + NFDi_Free( pathset->buf ); +} + +/* internal routines */ + +void *NFDi_Malloc( size_t bytes ) +{ + void *ptr = malloc(bytes); + if ( !ptr ) + NFDi_SetError("NFDi_Malloc failed."); + + return ptr; +} + +void NFDi_Free( void *ptr ) +{ + assert(ptr); + free(ptr); +} + +void NFDi_SetError( const char *msg ) +{ + int bTruncate = NFDi_SafeStrncpy( g_errorstr, msg, NFD_MAX_STRLEN ); + assert( !bTruncate ); _NFD_UNUSED(bTruncate); +} + + +int NFDi_SafeStrncpy( char *dst, const char *src, size_t maxCopy ) +{ + size_t n = maxCopy; + char *d = dst; + + assert( src ); + assert( dst ); + + while ( n > 0 && *src != '\0' ) + { + *d++ = *src++; + --n; + } + + /* Truncation case - + terminate string and return true */ + if ( n == 0 ) + { + dst[maxCopy-1] = '\0'; + return 1; + } + + /* No truncation. Append a single NULL and return. */ + *d = '\0'; + return 0; +} + + +/* adapted from microutf8 */ +int32_t NFDi_UTF8_Strlen( const nfdchar_t *str ) +{ + /* This function doesn't properly check validity of UTF-8 character + sequence, it is supposed to use only with valid UTF-8 strings. */ + + int32_t character_count = 0; + int32_t i = 0; /* Counter used to iterate over string. */ + nfdchar_t maybe_bom[4]; + + /* If there is UTF-8 BOM ignore it. */ + if (strlen(str) > 2) + { + strncpy(maybe_bom, str, 3); + maybe_bom[3] = 0; + if (strcmp(maybe_bom, (nfdchar_t*)NFD_UTF8_BOM) == 0) + i += 3; + } + + while(str[i]) + { + if (str[i] >> 7 == 0) + { + /* If bit pattern begins with 0 we have ascii character. */ + ++character_count; + } + else if (str[i] >> 6 == 3) + { + /* If bit pattern begins with 11 it is beginning of UTF-8 byte sequence. */ + ++character_count; + } + else if (str[i] >> 6 == 2) + ; /* If bit pattern begins with 10 it is middle of utf-8 byte sequence. */ + else + { + /* In any other case this is not valid UTF-8. */ + return -1; + } + ++i; + } + + return character_count; +} + +int NFDi_IsFilterSegmentChar( char ch ) +{ + return (ch==','||ch==';'||ch=='\0'); +} + diff --git a/extern/nfd-modified/src/nfd_common.h b/extern/nfd-modified/src/nfd_common.h new file mode 100644 index 000000000..1a9ab1625 --- /dev/null +++ b/extern/nfd-modified/src/nfd_common.h @@ -0,0 +1,39 @@ +/* + Native File Dialog + + Internal, common across platforms + + http://www.frogtoss.com/labs + */ + + +#ifndef _NFD_COMMON_H +#define _NFD_COMMON_H + +#include "nfd.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NFD_MAX_STRLEN 256 +#define _NFD_UNUSED(x) ((void)x) + +#define NFD_UTF8_BOM "\xEF\xBB\xBF" + + +void *NFDi_Malloc( size_t bytes ); +void NFDi_Free( void *ptr ); +void NFDi_SetError( const char *msg ); +int NFDi_SafeStrncpy( char *dst, const char *src, size_t maxCopy ); +int32_t NFDi_UTF8_Strlen( const nfdchar_t *str ); +int NFDi_IsFilterSegmentChar( char ch ); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/extern/nfd-modified/src/nfd_gtk.c b/extern/nfd-modified/src/nfd_gtk.c new file mode 100644 index 000000000..7a9958ed1 --- /dev/null +++ b/extern/nfd-modified/src/nfd_gtk.c @@ -0,0 +1,379 @@ +/* + Native File Dialog + + http://www.frogtoss.com/labs +*/ + +#include +#include +#include +#include +#include "nfd.h" +#include "nfd_common.h" + + +const char INIT_FAIL_MSG[] = "gtk_init_check failed to initilaize GTK+"; + + +static void AddTypeToFilterName( const char *typebuf, char *filterName, size_t bufsize ) +{ + const char SEP[] = ", "; + + size_t len = strlen(filterName); + if ( len != 0 ) + { + strncat( filterName, SEP, bufsize - len - 1 ); + len += strlen(SEP); + } + + strncat( filterName, typebuf, bufsize - len - 1 ); +} + +static void AddFiltersToDialog( GtkWidget *dialog, const char *filterList ) +{ + GtkFileFilter *filter; + char typebuf[NFD_MAX_STRLEN] = {0}; + const char *p_filterList = filterList; + char *p_typebuf = typebuf; + char filterName[NFD_MAX_STRLEN] = {0}; + + if ( !filterList || strlen(filterList) == 0 ) + return; + + filter = gtk_file_filter_new(); + while ( 1 ) + { + + if ( NFDi_IsFilterSegmentChar(*p_filterList) ) + { + char typebufWildcard[NFD_MAX_STRLEN]; + /* add another type to the filter */ + assert( strlen(typebuf) > 0 ); + assert( strlen(typebuf) < NFD_MAX_STRLEN-1 ); + + snprintf( typebufWildcard, NFD_MAX_STRLEN, "*.%s", typebuf ); + AddTypeToFilterName( typebuf, filterName, NFD_MAX_STRLEN ); + + gtk_file_filter_add_pattern( filter, typebufWildcard ); + + p_typebuf = typebuf; + memset( typebuf, 0, sizeof(char) * NFD_MAX_STRLEN ); + } + + if ( *p_filterList == ';' || *p_filterList == '\0' ) + { + /* end of filter -- add it to the dialog */ + + gtk_file_filter_set_name( filter, filterName ); + gtk_file_chooser_add_filter( GTK_FILE_CHOOSER(dialog), filter ); + + filterName[0] = '\0'; + + if ( *p_filterList == '\0' ) + break; + + filter = gtk_file_filter_new(); + } + + if ( !NFDi_IsFilterSegmentChar( *p_filterList ) ) + { + *p_typebuf = *p_filterList; + p_typebuf++; + } + + p_filterList++; + } + + /* always append a wildcard option to the end*/ + + filter = gtk_file_filter_new(); + gtk_file_filter_set_name( filter, "*.*" ); + gtk_file_filter_add_pattern( filter, "*" ); + gtk_file_chooser_add_filter( GTK_FILE_CHOOSER(dialog), filter ); +} + +static void SetDefaultPath( GtkWidget *dialog, const char *defaultPath ) +{ + if ( !defaultPath || strlen(defaultPath) == 0 ) + return; + + /* GTK+ manual recommends not specifically setting the default path. + We do it anyway in order to be consistent across platforms. + + If consistency with the native OS is preferred, this is the line + to comment out. -ml */ + gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(dialog), defaultPath ); +} + +static nfdresult_t AllocPathSet( GSList *fileList, nfdpathset_t *pathSet ) +{ + size_t bufSize = 0; + GSList *node; + nfdchar_t *p_buf; + size_t count = 0; + + assert(fileList); + assert(pathSet); + + pathSet->count = (size_t)g_slist_length( fileList ); + assert( pathSet->count > 0 ); + + pathSet->indices = NFDi_Malloc( sizeof(size_t)*pathSet->count ); + if ( !pathSet->indices ) + { + return NFD_ERROR; + } + + /* count the total space needed for buf */ + for ( node = fileList; node; node = node->next ) + { + assert(node->data); + bufSize += strlen( (const gchar*)node->data ) + 1; + } + + pathSet->buf = NFDi_Malloc( sizeof(nfdchar_t) * bufSize ); + + /* fill buf */ + p_buf = pathSet->buf; + for ( node = fileList; node; node = node->next ) + { + nfdchar_t *path = (nfdchar_t*)(node->data); + size_t byteLen = strlen(path)+1; + ptrdiff_t index; + + memcpy( p_buf, path, byteLen ); + g_free(node->data); + + index = p_buf - pathSet->buf; + assert( index >= 0 ); + pathSet->indices[count] = (size_t)index; + + p_buf += byteLen; + ++count; + } + + g_slist_free( fileList ); + + return NFD_OKAY; +} + +static void WaitForCleanup(void) +{ + while (gtk_events_pending()) + gtk_main_iteration(); +} + +/* public */ + +nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ) +{ + GtkWidget *dialog; + nfdresult_t result; + + if ( !gtk_init_check( NULL, NULL ) ) + { + NFDi_SetError(INIT_FAIL_MSG); + return NFD_ERROR; + } + + dialog = gtk_file_chooser_dialog_new( "Open File", + NULL, + GTK_FILE_CHOOSER_ACTION_OPEN, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Open", GTK_RESPONSE_ACCEPT, + NULL ); + + /* Build the filter list */ + AddFiltersToDialog(dialog, filterList); + + /* Set the default path */ + SetDefaultPath(dialog, defaultPath); + + result = NFD_CANCEL; + if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) + { + char *filename; + + filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog) ); + + { + size_t len = strlen(filename); + *outPath = NFDi_Malloc( len + 1 ); + memcpy( *outPath, filename, len + 1 ); + if ( !*outPath ) + { + g_free( filename ); + gtk_widget_destroy(dialog); + return NFD_ERROR; + } + } + g_free( filename ); + + result = NFD_OKAY; + } + + WaitForCleanup(); + gtk_widget_destroy(dialog); + WaitForCleanup(); + + return result; +} + + +nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdpathset_t *outPaths ) +{ + GtkWidget *dialog; + nfdresult_t result; + + if ( !gtk_init_check( NULL, NULL ) ) + { + NFDi_SetError(INIT_FAIL_MSG); + return NFD_ERROR; + } + + dialog = gtk_file_chooser_dialog_new( "Open Files", + NULL, + GTK_FILE_CHOOSER_ACTION_OPEN, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Open", GTK_RESPONSE_ACCEPT, + NULL ); + gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER(dialog), TRUE ); + + /* Build the filter list */ + AddFiltersToDialog(dialog, filterList); + + /* Set the default path */ + SetDefaultPath(dialog, defaultPath); + + result = NFD_CANCEL; + if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) + { + GSList *fileList = gtk_file_chooser_get_filenames( GTK_FILE_CHOOSER(dialog) ); + if ( AllocPathSet( fileList, outPaths ) == NFD_ERROR ) + { + gtk_widget_destroy(dialog); + return NFD_ERROR; + } + + result = NFD_OKAY; + } + + WaitForCleanup(); + gtk_widget_destroy(dialog); + WaitForCleanup(); + + return result; +} + +nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ) +{ + GtkWidget *dialog; + nfdresult_t result; + + if ( !gtk_init_check( NULL, NULL ) ) + { + NFDi_SetError(INIT_FAIL_MSG); + return NFD_ERROR; + } + + dialog = gtk_file_chooser_dialog_new( "Save File", + NULL, + GTK_FILE_CHOOSER_ACTION_SAVE, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Save", GTK_RESPONSE_ACCEPT, + NULL ); + gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(dialog), TRUE ); + + /* Build the filter list */ + AddFiltersToDialog(dialog, filterList); + + /* Set the default path */ + SetDefaultPath(dialog, defaultPath); + + result = NFD_CANCEL; + if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) + { + char *filename; + filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog) ); + + { + size_t len = strlen(filename); + *outPath = NFDi_Malloc( len + 1 ); + memcpy( *outPath, filename, len + 1 ); + if ( !*outPath ) + { + g_free( filename ); + gtk_widget_destroy(dialog); + return NFD_ERROR; + } + } + g_free(filename); + + result = NFD_OKAY; + } + + WaitForCleanup(); + gtk_widget_destroy(dialog); + WaitForCleanup(); + + return result; +} + +nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, + nfdchar_t **outPath) +{ + GtkWidget *dialog; + nfdresult_t result; + + if (!gtk_init_check(NULL, NULL)) + { + NFDi_SetError(INIT_FAIL_MSG); + return NFD_ERROR; + } + + dialog = gtk_file_chooser_dialog_new( "Select folder", + NULL, + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Select", GTK_RESPONSE_ACCEPT, + NULL ); + gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(dialog), TRUE ); + + + /* Set the default path */ + SetDefaultPath(dialog, defaultPath); + + result = NFD_CANCEL; + if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) + { + char *filename; + filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog) ); + + { + size_t len = strlen(filename); + *outPath = NFDi_Malloc( len + 1 ); + memcpy( *outPath, filename, len + 1 ); + if ( !*outPath ) + { + g_free( filename ); + gtk_widget_destroy(dialog); + return NFD_ERROR; + } + } + g_free(filename); + + result = NFD_OKAY; + } + + WaitForCleanup(); + gtk_widget_destroy(dialog); + WaitForCleanup(); + + return result; +} diff --git a/extern/nfd-modified/src/nfd_win.cpp b/extern/nfd-modified/src/nfd_win.cpp new file mode 100644 index 000000000..949da2b53 --- /dev/null +++ b/extern/nfd-modified/src/nfd_win.cpp @@ -0,0 +1,762 @@ +/* + Native File Dialog + + http://www.frogtoss.com/labs + */ + + +#ifdef __MINGW32__ +// Explicitly setting NTDDI version, this is necessary for the MinGW compiler +#define NTDDI_VERSION NTDDI_VISTA +#define _WIN32_WINNT _WIN32_WINNT_VISTA +#endif + +#define _CRTDBG_MAP_ALLOC +#include +#include + +/* only locally define UNICODE in this compilation unit */ +#ifndef UNICODE +#define UNICODE +#endif + +#include +#include +#include +#include +#include +#include "nfd_common.h" + + +#define COM_INITFLAGS ::COINIT_APARTMENTTHREADED | ::COINIT_DISABLE_OLE1DDE + +static BOOL COMIsInitialized(HRESULT coResult) +{ + if (coResult == RPC_E_CHANGED_MODE) + { + // If COM was previously initialized with different init flags, + // NFD still needs to operate. Eat this warning. + return TRUE; + } + + return SUCCEEDED(coResult); +} + +static HRESULT COMInit(void) +{ + return ::CoInitializeEx(NULL, COM_INITFLAGS); +} + +static void COMUninit(HRESULT coResult) +{ + // do not uninitialize if RPC_E_CHANGED_MODE occurred -- this + // case does not refcount COM. + if (SUCCEEDED(coResult)) + ::CoUninitialize(); +} + +// allocs the space in outPath -- call free() +static void CopyWCharToNFDChar( const wchar_t *inStr, nfdchar_t **outStr ) +{ + int inStrCharacterCount = static_cast(wcslen(inStr)); + int bytesNeeded = WideCharToMultiByte( CP_UTF8, 0, + inStr, inStrCharacterCount, + NULL, 0, NULL, NULL ); + assert( bytesNeeded ); + bytesNeeded += 1; + + *outStr = (nfdchar_t*)NFDi_Malloc( bytesNeeded ); + if ( !*outStr ) + return; + + int bytesWritten = WideCharToMultiByte( CP_UTF8, 0, + inStr, -1, + *outStr, bytesNeeded, + NULL, NULL ); + assert( bytesWritten ); _NFD_UNUSED( bytesWritten ); +} + +/* includes NULL terminator byte in return */ +static size_t GetUTF8ByteCountForWChar( const wchar_t *str ) +{ + size_t bytesNeeded = WideCharToMultiByte( CP_UTF8, 0, + str, -1, + NULL, 0, NULL, NULL ); + assert( bytesNeeded ); + return bytesNeeded+1; +} + +// write to outPtr -- no free() necessary. +static int CopyWCharToExistingNFDCharBuffer( const wchar_t *inStr, nfdchar_t *outPtr ) +{ + int bytesNeeded = static_cast(GetUTF8ByteCountForWChar( inStr )); + + /* invocation copies null term */ + int bytesWritten = WideCharToMultiByte( CP_UTF8, 0, + inStr, -1, + outPtr, bytesNeeded, + NULL, 0 ); + assert( bytesWritten ); + + return bytesWritten; + +} + + +// allocs the space in outStr -- call free() +static void CopyNFDCharToWChar( const nfdchar_t *inStr, wchar_t **outStr ) +{ + int inStrByteCount = static_cast(strlen(inStr)); + int charsNeeded = MultiByteToWideChar(CP_UTF8, 0, + inStr, inStrByteCount, + NULL, 0 ); + assert( charsNeeded ); + assert( !*outStr ); + charsNeeded += 1; // terminator + + *outStr = (wchar_t*)NFDi_Malloc( charsNeeded * sizeof(wchar_t) ); + if ( !*outStr ) + return; + + int ret = MultiByteToWideChar(CP_UTF8, 0, + inStr, inStrByteCount, + *outStr, charsNeeded); + (*outStr)[charsNeeded-1] = '\0'; + +#ifdef _DEBUG + int inStrCharacterCount = static_cast(NFDi_UTF8_Strlen(inStr)); + assert( ret == inStrCharacterCount ); +#else + _NFD_UNUSED(ret); +#endif +} + + +/* ext is in format "jpg", no wildcards or separators */ +static int AppendExtensionToSpecBuf( const char *ext, char *specBuf, size_t specBufLen ) +{ + const char SEP[] = ";"; + assert( specBufLen > strlen(ext)+3 ); + + if ( strlen(specBuf) > 0 ) + { + strncat( specBuf, SEP, specBufLen - strlen(specBuf) - 1 ); + specBufLen += strlen(SEP); + } + + char extWildcard[NFD_MAX_STRLEN]; + int bytesWritten = sprintf_s( extWildcard, NFD_MAX_STRLEN, "*.%s", ext ); + assert( bytesWritten == (int)(strlen(ext)+2) ); + _NFD_UNUSED(bytesWritten); + + strncat( specBuf, extWildcard, specBufLen - strlen(specBuf) - 1 ); + + return NFD_OKAY; +} + +static nfdresult_t AddFiltersToDialog( ::IFileDialog *fileOpenDialog, const char *filterList ) +{ + const wchar_t WILDCARD[] = L"*.*"; + + if ( !filterList || strlen(filterList) == 0 ) + return NFD_OKAY; + + // Count rows to alloc + UINT filterCount = 1; /* guaranteed to have one filter on a correct, non-empty parse */ + const char *p_filterList; + for ( p_filterList = filterList; *p_filterList; ++p_filterList ) + { + if ( *p_filterList == ';' ) + ++filterCount; + } + + assert(filterCount); + if ( !filterCount ) + { + NFDi_SetError("Error parsing filters."); + return NFD_ERROR; + } + + /* filterCount plus 1 because we hardcode the *.* wildcard after the while loop */ + COMDLG_FILTERSPEC *specList = (COMDLG_FILTERSPEC*)NFDi_Malloc( sizeof(COMDLG_FILTERSPEC) * ((size_t)filterCount + 1) ); + if ( !specList ) + { + return NFD_ERROR; + } + for (UINT i = 0; i < filterCount+1; ++i ) + { + specList[i].pszName = NULL; + specList[i].pszSpec = NULL; + } + + size_t specIdx = 0; + p_filterList = filterList; + char typebuf[NFD_MAX_STRLEN] = {0}; /* one per comma or semicolon */ + char *p_typebuf = typebuf; + + char specbuf[NFD_MAX_STRLEN] = {0}; /* one per semicolon */ + + while ( 1 ) + { + if ( NFDi_IsFilterSegmentChar(*p_filterList) ) + { + /* append a type to the specbuf (pending filter) */ + AppendExtensionToSpecBuf( typebuf, specbuf, NFD_MAX_STRLEN ); + + p_typebuf = typebuf; + memset( typebuf, 0, sizeof(char)*NFD_MAX_STRLEN ); + } + + if ( *p_filterList == ';' || *p_filterList == '\0' ) + { + /* end of filter -- add it to specList */ + + CopyNFDCharToWChar( specbuf, (wchar_t**)&specList[specIdx].pszName ); + CopyNFDCharToWChar( specbuf, (wchar_t**)&specList[specIdx].pszSpec ); + + memset( specbuf, 0, sizeof(char)*NFD_MAX_STRLEN ); + ++specIdx; + if ( specIdx == filterCount ) + break; + } + + if ( !NFDi_IsFilterSegmentChar( *p_filterList )) + { + *p_typebuf = *p_filterList; + ++p_typebuf; + } + + ++p_filterList; + } + + /* Add wildcard */ + specList[specIdx].pszSpec = WILDCARD; + specList[specIdx].pszName = WILDCARD; + + fileOpenDialog->SetFileTypes( filterCount+1, specList ); + + /* free speclist */ + for ( size_t i = 0; i < filterCount; ++i ) + { + NFDi_Free( (void*)specList[i].pszSpec ); + } + NFDi_Free( specList ); + + return NFD_OKAY; +} + +static nfdresult_t AllocPathSet( IShellItemArray *shellItems, nfdpathset_t *pathSet ) +{ + const char ERRORMSG[] = "Error allocating pathset."; + + assert(shellItems); + assert(pathSet); + + // How many items in shellItems? + DWORD numShellItems; + HRESULT result = shellItems->GetCount(&numShellItems); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError(ERRORMSG); + return NFD_ERROR; + } + + pathSet->count = static_cast(numShellItems); + assert( pathSet->count > 0 ); + + pathSet->indices = (size_t*)NFDi_Malloc( sizeof(size_t)*pathSet->count ); + if ( !pathSet->indices ) + { + return NFD_ERROR; + } + + /* count the total bytes needed for buf */ + size_t bufSize = 0; + for ( DWORD i = 0; i < numShellItems; ++i ) + { + ::IShellItem *shellItem; + result = shellItems->GetItemAt(i, &shellItem); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError(ERRORMSG); + return NFD_ERROR; + } + + // Confirm SFGAO_FILESYSTEM is true for this shellitem, or ignore it. + SFGAOF attribs; + result = shellItem->GetAttributes( SFGAO_FILESYSTEM, &attribs ); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError(ERRORMSG); + return NFD_ERROR; + } + if ( !(attribs & SFGAO_FILESYSTEM) ) + continue; + + LPWSTR name; + shellItem->GetDisplayName(SIGDN_FILESYSPATH, &name); + + // Calculate length of name with UTF-8 encoding + bufSize += GetUTF8ByteCountForWChar( name ); + + CoTaskMemFree(name); + } + + assert(bufSize); + + pathSet->buf = (nfdchar_t*)NFDi_Malloc( sizeof(nfdchar_t) * bufSize ); + memset( pathSet->buf, 0, sizeof(nfdchar_t) * bufSize ); + + /* fill buf */ + nfdchar_t *p_buf = pathSet->buf; + for (DWORD i = 0; i < numShellItems; ++i ) + { + ::IShellItem *shellItem; + result = shellItems->GetItemAt(i, &shellItem); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError(ERRORMSG); + return NFD_ERROR; + } + + // Confirm SFGAO_FILESYSTEM is true for this shellitem, or ignore it. + SFGAOF attribs; + result = shellItem->GetAttributes( SFGAO_FILESYSTEM, &attribs ); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError(ERRORMSG); + return NFD_ERROR; + } + if ( !(attribs & SFGAO_FILESYSTEM) ) + continue; + + LPWSTR name; + shellItem->GetDisplayName(SIGDN_FILESYSPATH, &name); + + int bytesWritten = CopyWCharToExistingNFDCharBuffer(name, p_buf); + CoTaskMemFree(name); + + ptrdiff_t index = p_buf - pathSet->buf; + assert( index >= 0 ); + pathSet->indices[i] = static_cast(index); + + p_buf += bytesWritten; + } + + return NFD_OKAY; +} + + +static nfdresult_t SetDefaultPath( IFileDialog *dialog, const char *defaultPath ) +{ + if ( !defaultPath || strlen(defaultPath) == 0 ) + return NFD_OKAY; + + wchar_t *defaultPathW = {0}; + CopyNFDCharToWChar( defaultPath, &defaultPathW ); + + IShellItem *folder; + HRESULT result = SHCreateItemFromParsingName( defaultPathW, NULL, IID_PPV_ARGS(&folder) ); + + // Valid non results. + if ( result == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || result == HRESULT_FROM_WIN32(ERROR_INVALID_DRIVE) ) + { + NFDi_Free( defaultPathW ); + return NFD_OKAY; + } + + if ( !SUCCEEDED(result) ) + { + NFDi_SetError("Error creating ShellItem"); + NFDi_Free( defaultPathW ); + return NFD_ERROR; + } + + // Could also call SetDefaultFolder(), but this guarantees defaultPath -- more consistency across API. + dialog->SetFolder( folder ); + + NFDi_Free( defaultPathW ); + folder->Release(); + + return NFD_OKAY; +} + +/* public */ + + +nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ) +{ + nfdresult_t nfdResult = NFD_ERROR; + + + HRESULT coResult = COMInit(); + if (!COMIsInitialized(coResult)) + { + NFDi_SetError("Could not initialize COM."); + return nfdResult; + } + + // Create dialog + ::IFileOpenDialog *fileOpenDialog(NULL); + HRESULT result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL, + CLSCTX_ALL, ::IID_IFileOpenDialog, + reinterpret_cast(&fileOpenDialog) ); + + if ( !SUCCEEDED(result) ) + { + NFDi_SetError("Could not create dialog."); + goto end; + } + + // Build the filter list + if ( !AddFiltersToDialog( fileOpenDialog, filterList ) ) + { + goto end; + } + + // Set the default path + if ( !SetDefaultPath( fileOpenDialog, defaultPath ) ) + { + goto end; + } + + // Show the dialog. + result = fileOpenDialog->Show(NULL); + if ( SUCCEEDED(result) ) + { + // Get the file name + ::IShellItem *shellItem(NULL); + result = fileOpenDialog->GetResult(&shellItem); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError("Could not get shell item from dialog."); + goto end; + } + wchar_t *filePath(NULL); + result = shellItem->GetDisplayName(::SIGDN_FILESYSPATH, &filePath); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError("Could not get file path for selected."); + shellItem->Release(); + goto end; + } + + CopyWCharToNFDChar( filePath, outPath ); + CoTaskMemFree(filePath); + if ( !*outPath ) + { + /* error is malloc-based, error message would be redundant */ + shellItem->Release(); + goto end; + } + + nfdResult = NFD_OKAY; + shellItem->Release(); + } + else if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED) ) + { + nfdResult = NFD_CANCEL; + } + else + { + NFDi_SetError("File dialog box show failed."); + nfdResult = NFD_ERROR; + } + +end: + if (fileOpenDialog) + fileOpenDialog->Release(); + + COMUninit(coResult); + + return nfdResult; +} + +nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdpathset_t *outPaths ) +{ + nfdresult_t nfdResult = NFD_ERROR; + + + HRESULT coResult = COMInit(); + if (!COMIsInitialized(coResult)) + { + NFDi_SetError("Could not initialize COM."); + return nfdResult; + } + + // Create dialog + ::IFileOpenDialog *fileOpenDialog(NULL); + HRESULT result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL, + CLSCTX_ALL, ::IID_IFileOpenDialog, + reinterpret_cast(&fileOpenDialog) ); + + if ( !SUCCEEDED(result) ) + { + fileOpenDialog = NULL; + NFDi_SetError("Could not create dialog."); + goto end; + } + + // Build the filter list + if ( !AddFiltersToDialog( fileOpenDialog, filterList ) ) + { + goto end; + } + + // Set the default path + if ( !SetDefaultPath( fileOpenDialog, defaultPath ) ) + { + goto end; + } + + // Set a flag for multiple options + DWORD dwFlags; + result = fileOpenDialog->GetOptions(&dwFlags); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError("Could not get options."); + goto end; + } + result = fileOpenDialog->SetOptions(dwFlags | FOS_ALLOWMULTISELECT); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError("Could not set options."); + goto end; + } + + // Show the dialog. + result = fileOpenDialog->Show(NULL); + if ( SUCCEEDED(result) ) + { + IShellItemArray *shellItems; + result = fileOpenDialog->GetResults( &shellItems ); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError("Could not get shell items."); + goto end; + } + + if ( AllocPathSet( shellItems, outPaths ) == NFD_ERROR ) + { + shellItems->Release(); + goto end; + } + + shellItems->Release(); + nfdResult = NFD_OKAY; + } + else if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED) ) + { + nfdResult = NFD_CANCEL; + } + else + { + NFDi_SetError("File dialog box show failed."); + nfdResult = NFD_ERROR; + } + +end: + if ( fileOpenDialog ) + fileOpenDialog->Release(); + + COMUninit(coResult); + + return nfdResult; +} + +nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ) +{ + nfdresult_t nfdResult = NFD_ERROR; + + HRESULT coResult = COMInit(); + if (!COMIsInitialized(coResult)) + { + NFDi_SetError("Could not initialize COM."); + return nfdResult; + } + + // Create dialog + ::IFileSaveDialog *fileSaveDialog(NULL); + HRESULT result = ::CoCreateInstance(::CLSID_FileSaveDialog, NULL, + CLSCTX_ALL, ::IID_IFileSaveDialog, + reinterpret_cast(&fileSaveDialog) ); + + if ( !SUCCEEDED(result) ) + { + fileSaveDialog = NULL; + NFDi_SetError("Could not create dialog."); + goto end; + } + + // Build the filter list + if ( !AddFiltersToDialog( fileSaveDialog, filterList ) ) + { + goto end; + } + + // Set the default path + if ( !SetDefaultPath( fileSaveDialog, defaultPath ) ) + { + goto end; + } + + // Show the dialog. + result = fileSaveDialog->Show(NULL); + if ( SUCCEEDED(result) ) + { + // Get the file name + ::IShellItem *shellItem; + result = fileSaveDialog->GetResult(&shellItem); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError("Could not get shell item from dialog."); + goto end; + } + wchar_t *filePath(NULL); + result = shellItem->GetDisplayName(::SIGDN_FILESYSPATH, &filePath); + if ( !SUCCEEDED(result) ) + { + shellItem->Release(); + NFDi_SetError("Could not get file path for selected."); + goto end; + } + + CopyWCharToNFDChar( filePath, outPath ); + CoTaskMemFree(filePath); + if ( !*outPath ) + { + /* error is malloc-based, error message would be redundant */ + shellItem->Release(); + goto end; + } + + nfdResult = NFD_OKAY; + shellItem->Release(); + } + else if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED) ) + { + nfdResult = NFD_CANCEL; + } + else + { + NFDi_SetError("File dialog box show failed."); + nfdResult = NFD_ERROR; + } + +end: + if ( fileSaveDialog ) + fileSaveDialog->Release(); + + COMUninit(coResult); + + return nfdResult; +} + + + +nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, + nfdchar_t **outPath) +{ + nfdresult_t nfdResult = NFD_ERROR; + DWORD dwOptions = 0; + + HRESULT coResult = COMInit(); + if (!COMIsInitialized(coResult)) + { + NFDi_SetError("CoInitializeEx failed."); + return nfdResult; + } + + // Create dialog + ::IFileOpenDialog *fileDialog(NULL); + HRESULT result = CoCreateInstance(CLSID_FileOpenDialog, + NULL, + CLSCTX_ALL, + IID_PPV_ARGS(&fileDialog)); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError("CoCreateInstance for CLSID_FileOpenDialog failed."); + goto end; + } + + // Set the default path + if (SetDefaultPath(fileDialog, defaultPath) != NFD_OKAY) + { + NFDi_SetError("SetDefaultPath failed."); + goto end; + } + + // Get the dialogs options + if (!SUCCEEDED(fileDialog->GetOptions(&dwOptions))) + { + NFDi_SetError("GetOptions for IFileDialog failed."); + goto end; + } + + // Add in FOS_PICKFOLDERS which hides files and only allows selection of folders + if (!SUCCEEDED(fileDialog->SetOptions(dwOptions | FOS_PICKFOLDERS))) + { + NFDi_SetError("SetOptions for IFileDialog failed."); + goto end; + } + + // Show the dialog to the user + result = fileDialog->Show(NULL); + if ( SUCCEEDED(result) ) + { + // Get the folder name + ::IShellItem *shellItem(NULL); + + result = fileDialog->GetResult(&shellItem); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError("Could not get file path for selected."); + shellItem->Release(); + goto end; + } + + wchar_t *path = NULL; + result = shellItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &path); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError("GetDisplayName for IShellItem failed."); + shellItem->Release(); + goto end; + } + + CopyWCharToNFDChar(path, outPath); + CoTaskMemFree(path); + if ( !*outPath ) + { + shellItem->Release(); + goto end; + } + + nfdResult = NFD_OKAY; + shellItem->Release(); + } + else if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED) ) + { + nfdResult = NFD_CANCEL; + } + else + { + NFDi_SetError("Show for IFileDialog failed."); + nfdResult = NFD_ERROR; + } + + end: + + if (fileDialog) + fileDialog->Release(); + + COMUninit(coResult); + + return nfdResult; +} diff --git a/extern/nfd-modified/src/nfd_zenity.c b/extern/nfd-modified/src/nfd_zenity.c new file mode 100644 index 000000000..5f9313371 --- /dev/null +++ b/extern/nfd-modified/src/nfd_zenity.c @@ -0,0 +1,307 @@ +/* + Native File Dialog + + http://www.frogtoss.com/labs +*/ + +#include +#include +#include +#include "nfd.h" +#include "nfd_common.h" + +#define SIMPLE_EXEC_IMPLEMENTATION +#include "simple_exec.h" + + +const char NO_ZENITY_MSG[] = "zenity not installed"; + + +static void AddTypeToFilterName( const char *typebuf, char *filterName, size_t bufsize ) +{ + size_t len = strlen(filterName); + if( len > 0 ) + strncat( filterName, " *.", bufsize - len - 1 ); + else + strncat( filterName, "--file-filter=*.", bufsize - len - 1 ); + + len = strlen(filterName); + strncat( filterName, typebuf, bufsize - len - 1 ); +} + +static void AddFiltersToCommandArgs(char** commandArgs, int commandArgsLen, const char *filterList ) +{ + char typebuf[NFD_MAX_STRLEN] = {0}; + const char *p_filterList = filterList; + char *p_typebuf = typebuf; + char filterName[NFD_MAX_STRLEN] = {0}; + int i; + + if ( !filterList || strlen(filterList) == 0 ) + return; + + while ( 1 ) + { + + if ( NFDi_IsFilterSegmentChar(*p_filterList) ) + { + char typebufWildcard[NFD_MAX_STRLEN]; + /* add another type to the filter */ + assert( strlen(typebuf) > 0 ); + assert( strlen(typebuf) < NFD_MAX_STRLEN-1 ); + + snprintf( typebufWildcard, NFD_MAX_STRLEN, "*.%s", typebuf ); + + AddTypeToFilterName( typebuf, filterName, NFD_MAX_STRLEN ); + + p_typebuf = typebuf; + memset( typebuf, 0, sizeof(char) * NFD_MAX_STRLEN ); + } + + if ( *p_filterList == ';' || *p_filterList == '\0' ) + { + /* end of filter -- add it to the dialog */ + + for(i = 0; commandArgs[i] != NULL && i < commandArgsLen; i++); + + commandArgs[i] = strdup(filterName); + + filterName[0] = '\0'; + + if ( *p_filterList == '\0' ) + break; + } + + if ( !NFDi_IsFilterSegmentChar( *p_filterList ) ) + { + *p_typebuf = *p_filterList; + p_typebuf++; + } + + p_filterList++; + } + + /* always append a wildcard option to the end*/ + + for(i = 0; commandArgs[i] != NULL && i < commandArgsLen; i++); + + commandArgs[i] = strdup("--file-filter=*.*"); +} + +static nfdresult_t ZenityCommon(char** command, int commandLen, const char* defaultPath, const char* filterList, char** stdOut) +{ + if(defaultPath != NULL) + { + char* prefix = "--filename="; + int len = strlen(prefix) + strlen(defaultPath) + 1; + + char* tmp = (char*) calloc(len, 1); + strcat(tmp, prefix); + strcat(tmp, defaultPath); + + int i; + for(i = 0; command[i] != NULL && i < commandLen; i++); + + command[i] = tmp; + } + + AddFiltersToCommandArgs(command, commandLen, filterList); + + int byteCount = 0; + int exitCode = 0; + int processInvokeError = runCommandArray(stdOut, &byteCount, &exitCode, 0, command); + + for(int i = 0; command[i] != NULL && i < commandLen; i++) + free(command[i]); + + nfdresult_t result = NFD_OKAY; + + if(processInvokeError == COMMAND_NOT_FOUND) + { + NFDi_SetError(NO_ZENITY_MSG); + result = NFD_ERROR; + } + else + { + if(exitCode == 1) + result = NFD_CANCEL; + } + + return result; +} + + +static nfdresult_t AllocPathSet(char* zenityList, nfdpathset_t *pathSet ) +{ + assert(zenityList); + assert(pathSet); + + size_t len = strlen(zenityList) + 1; + pathSet->buf = NFDi_Malloc(len); + + int numEntries = 1; + + for(size_t i = 0; i < len; i++) + { + char ch = zenityList[i]; + + if(ch == '|') + { + numEntries++; + ch = '\0'; + } + + pathSet->buf[i] = ch; + } + + pathSet->count = numEntries; + assert( pathSet->count > 0 ); + + pathSet->indices = NFDi_Malloc( sizeof(size_t)*pathSet->count ); + + int entry = 0; + pathSet->indices[0] = 0; + for(size_t i = 0; i < len; i++) + { + char ch = zenityList[i]; + + if(ch == '|') + { + entry++; + pathSet->indices[entry] = i + 1; + } + } + + return NFD_OKAY; +} + +/* public */ + +nfdresult_t NFD_OpenDialog( const char *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ) +{ + int commandLen = 100; + char* command[commandLen]; + memset(command, 0, commandLen * sizeof(char*)); + + command[0] = strdup("zenity"); + command[1] = strdup("--file-selection"); + command[2] = strdup("--title=Open File"); + + char* stdOut = NULL; + nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut); + + if(stdOut != NULL) + { + size_t len = strlen(stdOut); + *outPath = NFDi_Malloc(len); + memcpy(*outPath, stdOut, len); + (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator + free(stdOut); + } + else + { + *outPath = NULL; + } + + return result; +} + + +nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdpathset_t *outPaths ) +{ + int commandLen = 100; + char* command[commandLen]; + memset(command, 0, commandLen * sizeof(char*)); + + command[0] = strdup("zenity"); + command[1] = strdup("--file-selection"); + command[2] = strdup("--title=Open Files"); + command[3] = strdup("--multiple"); + + char* stdOut = NULL; + nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut); + + if(stdOut != NULL) + { + size_t len = strlen(stdOut); + stdOut[len-1] = '\0'; // remove trailing newline + + if ( AllocPathSet( stdOut, outPaths ) == NFD_ERROR ) + result = NFD_ERROR; + + free(stdOut); + } + else + { + result = NFD_ERROR; + } + + return result; +} + +nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ) +{ + int commandLen = 100; + char* command[commandLen]; + memset(command, 0, commandLen * sizeof(char*)); + + command[0] = strdup("zenity"); + command[1] = strdup("--file-selection"); + command[2] = strdup("--title=Save File"); + command[3] = strdup("--save"); + + char* stdOut = NULL; + nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut); + + if(stdOut != NULL) + { + size_t len = strlen(stdOut); + *outPath = NFDi_Malloc(len); + memcpy(*outPath, stdOut, len); + (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator + free(stdOut); + } + else + { + *outPath = NULL; + } + + return result; +} + +nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, + nfdchar_t **outPath) +{ + int commandLen = 100; + char* command[commandLen]; + memset(command, 0, commandLen * sizeof(char*)); + + command[0] = strdup("zenity"); + command[1] = strdup("--file-selection"); + command[2] = strdup("--directory"); + command[3] = strdup("--title=Select folder"); + + char* stdOut = NULL; + nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, "", &stdOut); + + if(stdOut != NULL) + { + size_t len = strlen(stdOut); + *outPath = NFDi_Malloc(len); + memcpy(*outPath, stdOut, len); + (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator + free(stdOut); + } + else + { + *outPath = NULL; + } + + return result; +} diff --git a/extern/nfd-modified/src/simple_exec.h b/extern/nfd-modified/src/simple_exec.h new file mode 100644 index 000000000..6308dfe0f --- /dev/null +++ b/extern/nfd-modified/src/simple_exec.h @@ -0,0 +1,218 @@ +// copied from: https://github.com/wheybags/simple_exec/blob/5a74c507c4ce1b2bb166177ead4cca7cfa23cb35/simple_exec.h + +// simple_exec.h, single header library to run external programs + retrieve their status code and output (unix only for now) +// +// do this: +// #define SIMPLE_EXEC_IMPLEMENTATION +// before you include this file in *one* C or C++ file to create the implementation. +// i.e. it should look like this: +// #define SIMPLE_EXEC_IMPLEMENTATION +// #include "simple_exec.h" + +#ifndef SIMPLE_EXEC_H +#define SIMPLE_EXEC_H + +int runCommand(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* command, ...); +int runCommandArray(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* const* allArgs); + +#endif // SIMPLE_EXEC_H + +#ifdef SIMPLE_EXEC_IMPLEMENTATION + +#include +#include +#include +#include +#include +#include +#include +#include + +#define release_assert(exp) { if (!(exp)) { abort(); } } + +enum PIPE_FILE_DESCRIPTORS +{ + READ_FD = 0, + WRITE_FD = 1 +}; + +enum RUN_COMMAND_ERROR +{ + COMMAND_RAN_OK = 0, + COMMAND_NOT_FOUND = 1 +}; + +int runCommandArray(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* const* allArgs) +{ + // adapted from: https://stackoverflow.com/a/479103 + + int bufferSize = 256; + char buffer[bufferSize + 1]; + + int dataReadFromChildDefaultSize = bufferSize * 5; + int dataReadFromChildSize = dataReadFromChildDefaultSize; + int dataReadFromChildUsed = 0; + char* dataReadFromChild = (char*)malloc(dataReadFromChildSize); + + + int parentToChild[2]; + release_assert(pipe(parentToChild) == 0); + + int childToParent[2]; + release_assert(pipe(childToParent) == 0); + + int errPipe[2]; + release_assert(pipe(errPipe) == 0); + + pid_t pid; + switch( pid = fork() ) + { + case -1: + { + release_assert(0 && "Fork failed"); + break; + } + + case 0: // child + { + release_assert(dup2(parentToChild[READ_FD ], STDIN_FILENO ) != -1); + release_assert(dup2(childToParent[WRITE_FD], STDOUT_FILENO) != -1); + + if(includeStdErr) + { + release_assert(dup2(childToParent[WRITE_FD], STDERR_FILENO) != -1); + } + else + { + int devNull = open("/dev/null", O_WRONLY); + release_assert(dup2(devNull, STDERR_FILENO) != -1); + } + + // unused + release_assert(close(parentToChild[WRITE_FD]) == 0); + release_assert(close(childToParent[READ_FD ]) == 0); + release_assert(close(errPipe[READ_FD]) == 0); + + const char* command = allArgs[0]; + execvp(command, allArgs); + + char err = 1; + ssize_t result = write(errPipe[WRITE_FD], &err, 1); + release_assert(result != -1); + + close(errPipe[WRITE_FD]); + close(parentToChild[READ_FD]); + close(childToParent[WRITE_FD]); + + exit(0); + } + + + default: // parent + { + // unused + release_assert(close(parentToChild[READ_FD]) == 0); + release_assert(close(childToParent[WRITE_FD]) == 0); + release_assert(close(errPipe[WRITE_FD]) == 0); + + while(1) + { + ssize_t bytesRead = 0; + switch(bytesRead = read(childToParent[READ_FD], buffer, bufferSize)) + { + case 0: // End-of-File, or non-blocking read. + { + int status = 0; + release_assert(waitpid(pid, &status, 0) == pid); + + // done with these now + release_assert(close(parentToChild[WRITE_FD]) == 0); + release_assert(close(childToParent[READ_FD]) == 0); + + char errChar = 0; + ssize_t result = read(errPipe[READ_FD], &errChar, 1); + release_assert(result != -1); + close(errPipe[READ_FD]); + + if(errChar) + { + free(dataReadFromChild); + return COMMAND_NOT_FOUND; + } + + // free any un-needed memory with realloc + add a null terminator for convenience + dataReadFromChild = (char*)realloc(dataReadFromChild, dataReadFromChildUsed + 1); + dataReadFromChild[dataReadFromChildUsed] = '\0'; + + if(stdOut != NULL) + *stdOut = dataReadFromChild; + else + free(dataReadFromChild); + + if(stdOutByteCount != NULL) + *stdOutByteCount = dataReadFromChildUsed; + if(returnCode != NULL) + *returnCode = WEXITSTATUS(status); + + return COMMAND_RAN_OK; + } + case -1: + { + release_assert(0 && "read() failed"); + break; + } + + default: + { + if(dataReadFromChildUsed + bytesRead + 1 >= dataReadFromChildSize) + { + dataReadFromChildSize += dataReadFromChildDefaultSize; + dataReadFromChild = (char*)realloc(dataReadFromChild, dataReadFromChildSize); + } + + memcpy(dataReadFromChild + dataReadFromChildUsed, buffer, bytesRead); + dataReadFromChildUsed += bytesRead; + break; + } + } + } + } + } +} + +int runCommand(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* command, ...) +{ + va_list vl; + va_start(vl, command); + + char* currArg = NULL; + + int allArgsInitialSize = 16; + int allArgsSize = allArgsInitialSize; + char** allArgs = (char**)malloc(sizeof(char*) * allArgsSize); + allArgs[0] = command; + + int i = 1; + do + { + currArg = va_arg(vl, char*); + allArgs[i] = currArg; + + i++; + + if(i >= allArgsSize) + { + allArgsSize += allArgsInitialSize; + allArgs = (char**)realloc(allArgs, sizeof(char*) * allArgsSize); + } + + } while(currArg != NULL); + + va_end(vl); + + int retval = runCommandArray(stdOut, stdOutByteCount, returnCode, includeStdErr, allArgs); + free(allArgs); + return retval; +} + +#endif //SIMPLE_EXEC_IMPLEMENTATION diff --git a/extern/nfd-modified/test/test_opendialog.c b/extern/nfd-modified/test/test_opendialog.c new file mode 100644 index 000000000..54bf37423 --- /dev/null +++ b/extern/nfd-modified/test/test_opendialog.c @@ -0,0 +1,29 @@ +#include "nfd.h" + +#include +#include + + +/* this test should compile on all supported platforms */ + +int main( void ) +{ + nfdchar_t *outPath = NULL; + nfdresult_t result = NFD_OpenDialog( "png,jpg;pdf", NULL, &outPath ); + if ( result == NFD_OKAY ) + { + puts("Success!"); + puts(outPath); + free(outPath); + } + else if ( result == NFD_CANCEL ) + { + puts("User pressed cancel."); + } + else + { + printf("Error: %s\n", NFD_GetError() ); + } + + return 0; +} diff --git a/extern/nfd-modified/test/test_opendialogmultiple.c b/extern/nfd-modified/test/test_opendialogmultiple.c new file mode 100644 index 000000000..45db6b65e --- /dev/null +++ b/extern/nfd-modified/test/test_opendialogmultiple.c @@ -0,0 +1,32 @@ +#include "nfd.h" + +#include +#include + +/* this test should compile on all supported platforms */ + +int main( void ) +{ + nfdpathset_t pathSet; + nfdresult_t result = NFD_OpenDialogMultiple( "png,jpg;pdf", NULL, &pathSet ); + if ( result == NFD_OKAY ) + { + size_t i; + for ( i = 0; i < NFD_PathSet_GetCount(&pathSet); ++i ) + { + nfdchar_t *path = NFD_PathSet_GetPath(&pathSet, i); + printf("Path %i: %s\n", (int)i, path ); + } + NFD_PathSet_Free(&pathSet); + } + else if ( result == NFD_CANCEL ) + { + puts("User pressed cancel."); + } + else + { + printf("Error: %s\n", NFD_GetError() ); + } + + return 0; +} diff --git a/extern/nfd-modified/test/test_pickfolder.c b/extern/nfd-modified/test/test_pickfolder.c new file mode 100644 index 000000000..708fee859 --- /dev/null +++ b/extern/nfd-modified/test/test_pickfolder.c @@ -0,0 +1,29 @@ +#include "nfd.h" + +#include +#include + + +/* this test should compile on all supported platforms */ + +int main( void ) +{ + nfdchar_t *outPath = NULL; + nfdresult_t result = NFD_PickFolder( NULL, &outPath ); + if ( result == NFD_OKAY ) + { + puts("Success!"); + puts(outPath); + free(outPath); + } + else if ( result == NFD_CANCEL ) + { + puts("User pressed cancel."); + } + else + { + printf("Error: %s\n", NFD_GetError() ); + } + + return 0; +} diff --git a/extern/nfd-modified/test/test_savedialog.c b/extern/nfd-modified/test/test_savedialog.c new file mode 100644 index 000000000..7ec37f089 --- /dev/null +++ b/extern/nfd-modified/test/test_savedialog.c @@ -0,0 +1,28 @@ +#include "nfd.h" + +#include +#include + +/* this test should compile on all supported platforms */ + +int main( void ) +{ + nfdchar_t *savePath = NULL; + nfdresult_t result = NFD_SaveDialog( "png,jpg;pdf", NULL, &savePath ); + if ( result == NFD_OKAY ) + { + puts("Success!"); + puts(savePath); + free(savePath); + } + else if ( result == NFD_CANCEL ) + { + puts("User pressed cancel."); + } + else + { + printf("Error: %s\n", NFD_GetError() ); + } + + return 0; +} From 25af023dc6c1ce63907766824a82871c6754748b Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 17 Jun 2022 14:30:18 +0900 Subject: [PATCH 051/101] Various corrections and fixes Fix SN PSG pitch corrections Revive YM2612 from dead Add Game Gear stereo function finally Add OPN/A prescaler config --- src/engine/platform/ay.cpp | 7 +++ src/engine/platform/ay.h | 1 + src/engine/platform/fmshared_OPM.h | 20 ++++---- src/engine/platform/fmshared_OPN.h | 28 +++++------ src/engine/platform/genesis.h | 7 --- src/engine/platform/sms.cpp | 67 +++++++++------------------ src/engine/platform/sms.h | 3 +- src/engine/platform/sound/sn76496.cpp | 2 +- src/engine/platform/ym2203.cpp | 35 +++++++++++++- src/engine/platform/ym2203.h | 4 +- src/engine/platform/ym2608.cpp | 38 +++++++++++++-- src/engine/platform/ym2608.h | 6 +-- src/engine/song.h | 4 +- src/gui/presets.cpp | 16 ++++++- src/gui/sysConf.cpp | 8 +--- 15 files changed, 147 insertions(+), 99 deletions(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 83de1fa13..52ac6e57a 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -593,6 +593,13 @@ void DivPlatformAY8910::poke(std::vector& wlist) { for (DivRegWrite& i: wlist) immWrite(i.addr,i.val); } +void DivPlatformAY8910::setExtClockDiv(unsigned int eclk, unsigned char ediv) { + if (extMode) { + extClock=eclk; + extDiv=ediv; + } +} + void DivPlatformAY8910::setFlags(unsigned int flags) { if (extMode) { chipClock=extClock; diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index a1f35d1b6..f67a2ad97 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -91,6 +91,7 @@ class DivPlatformAY8910: public DivDispatch { friend void putDispatchChan(void*,int,int); public: + void setExtClockDiv(unsigned int eclk=COLOR_NTSC, unsigned char ediv=8); void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); diff --git a/src/engine/platform/fmshared_OPM.h b/src/engine/platform/fmshared_OPM.h index 97844656d..9b838c196 100644 --- a/src/engine/platform/fmshared_OPM.h +++ b/src/engine/platform/fmshared_OPM.h @@ -26,16 +26,16 @@ class DivPlatformOPM: public DivPlatformFMBase { protected: - const unsigned char ADDR_MULT_DT=0x40; - const unsigned char ADDR_TL=0x60; - const unsigned char ADDR_RS_AR=0x80; - const unsigned char ADDR_AM_DR=0xa0; - const unsigned char ADDR_DT2_D2R=0xc0; - const unsigned char ADDR_SL_RR=0xe0; - const unsigned char ADDR_NOTE=0x28; - const unsigned char ADDR_KF=0x30; - const unsigned char ADDR_FMS_AMS=0x38; - const unsigned char ADDR_LR_FB_ALG=0x20; + const unsigned short ADDR_MULT_DT=0x40; + const unsigned short ADDR_TL=0x60; + const unsigned short ADDR_RS_AR=0x80; + const unsigned short ADDR_AM_DR=0xa0; + const unsigned short ADDR_DT2_D2R=0xc0; + const unsigned short ADDR_SL_RR=0xe0; + const unsigned short ADDR_NOTE=0x28; + const unsigned short ADDR_KF=0x30; + const unsigned short ADDR_FMS_AMS=0x38; + const unsigned short ADDR_LR_FB_ALG=0x20; const unsigned short opOffs[4]={ 0x00, 0x08, 0x10, 0x18 diff --git a/src/engine/platform/fmshared_OPN.h b/src/engine/platform/fmshared_OPN.h index 74e13219f..0aaad16d4 100644 --- a/src/engine/platform/fmshared_OPN.h +++ b/src/engine/platform/fmshared_OPN.h @@ -85,27 +85,27 @@ class DivPlatformOPN: public DivPlatformFMBase { protected: - const unsigned char ADDR_MULT_DT=0x30; - const unsigned char ADDR_TL=0x40; - const unsigned char ADDR_RS_AR=0x50; - const unsigned char ADDR_AM_DR=0x60; - const unsigned char ADDR_DT2_D2R=0x70; - const unsigned char ADDR_SL_RR=0x80; - const unsigned char ADDR_SSG=0x90; - const unsigned char ADDR_FREQ=0xa0; - const unsigned char ADDR_FREQH=0xa4; - const unsigned char ADDR_FB_ALG=0xb0; - const unsigned char ADDR_LRAF=0xb4; + const unsigned short ADDR_MULT_DT=0x30; + const unsigned short ADDR_TL=0x40; + const unsigned short ADDR_RS_AR=0x50; + const unsigned short ADDR_AM_DR=0x60; + const unsigned short ADDR_DT2_D2R=0x70; + const unsigned short ADDR_SL_RR=0x80; + const unsigned short ADDR_SSG=0x90; + const unsigned short ADDR_FREQ=0xa0; + const unsigned short ADDR_FREQH=0xa4; + const unsigned short ADDR_FB_ALG=0xb0; + const unsigned short ADDR_LRAF=0xb4; const unsigned short opOffs[4]={ 0x00, 0x04, 0x08, 0x0c }; double fmFreqBase; - double fmDivBase; - unsigned char ayDiv; + unsigned int fmDivBase; + unsigned int ayDiv; - DivPlatformOPN(double f=9440540.0, double d=72, unsigned char a=32): + DivPlatformOPN(double f=9440540.0, unsigned int d=72, unsigned int a=32): DivPlatformFMBase(), fmFreqBase(f), fmDivBase(d), diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 7d2004f33..c46a992d3 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -99,13 +99,6 @@ class DivPlatformGenesis: public DivPlatformOPN { Channel chan[10]; DivDispatchOscBuffer* oscBuf[10]; bool isMuted[10]; - struct QueuedWrite { - unsigned short addr; - unsigned char val; - bool addrOrVal; - QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} - }; - std::deque writes; ym3438_t fm; ymfm::ym2612* fm_ymfm; diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 35bb9c40c..71e9b0bc0 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -35,7 +35,7 @@ const char* regCheatSheetGG[]={ }; const char** DivPlatformSMS::getRegisterSheet() { - return isStereo()?regCheatSheetGG:regCheatSheetSN; + return stereo?regCheatSheetGG:regCheatSheetSN; } const char* DivPlatformSMS::getEffectName(unsigned char effect) { @@ -74,7 +74,7 @@ void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_ o=YMPSG_GetOutput(&sn_nuked); if (o<-32768) o=-32768; if (o>32767) o=32767; - bufL[h]=o; + bufL[h]=bufR[h]=o; for (int i=0; i<4; i++) { if (isMuted[i]) { oscBuf[i]->data[oscBuf[i]->needle++]=0; @@ -86,13 +86,6 @@ void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_ } void DivPlatformSMS::acquire_mame(short* bufL, short* bufR, size_t start, size_t len) { - if (snBufLenwrite(w.val); writes.pop(); } - for (size_t h=0; hsound_stream_update(outs,1); for (int i=0; i<4; i++) { @@ -115,17 +108,6 @@ void DivPlatformSMS::acquire_mame(short* bufL, short* bufR, size_t start, size_t } } } - if (stereo) { - for (size_t i=0; i>1)&1)<>1)&1)<<(i+4)); rWrite(1,lastPan); } } @@ -204,7 +186,7 @@ void DivPlatformSMS::tick(bool sysTick) { } for (int i=0; i<3; i++) { if (chan[i].freqChanged) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,64); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,toneDivider); if (chan[i].freq>1023) chan[i].freq=1023; if (chan[i].freq<8) chan[i].freq=1; //if (chan[i].actualNote>0x5d) chan[i].freq=0x01; @@ -263,7 +245,7 @@ void DivPlatformSMS::tick(bool sysTick) { } int DivPlatformSMS::dispatch(DivCommand c) { - int CHIP_DIVIDER=64; + int CHIP_DIVIDER=toneDivider; if (c.chan==3) CHIP_DIVIDER=noiseDivider; switch (c.cmd) { case DIV_CMD_NOTE_ON: @@ -340,11 +322,12 @@ int DivPlatformSMS::dispatch(DivCommand c) { updateSNMode=true; break; case DIV_CMD_PANNING: { - if (isStereo()) { + if (stereo) { + if (c.chan>3) c.chan=3; lastPan&=~(0x11<0) pan|=0x01; - if (c.value2>0) pan|=0x10; + if (c.value>0) pan|=0x10; + if (c.value2>0) pan|=0x01; if (pan==0) pan=0x11; lastPan|=pan<reset(); ay->getRegisterWrites().clear(); ay->flushWrites(); @@ -1013,7 +1017,8 @@ void DivPlatformYM2203::setSkipRegisterWrites(bool value) { } void DivPlatformYM2203::setFlags(unsigned int flags) { - switch (flags&0x3f) { + // Clock flags + switch (flags&0x1f) { default: case 0x00: chipClock=COLOR_NTSC; @@ -1034,10 +1039,36 @@ void DivPlatformYM2203::setFlags(unsigned int flags) { chipClock=3000000.0/2.0; break; } + // Prescaler flags + switch ((flags>>5)&0x3) { + default: + case 0x00: // /6 + prescale=0x2d; + fmFreqBase=4720270.0, + fmDivBase=36, + ayDiv=16; + break; + case 0x01: // /3 + prescale=0x2e; + fmFreqBase=4720270.0/2.0, + fmDivBase=18, + ayDiv=8; + break; + case 0x02: // /2 + prescale=0x2f; + fmFreqBase=4720270.0/3.0, + fmDivBase=12, + ayDiv=4; + break; + } rate=fm->sample_rate(chipClock); for (int i=0; i<6; i++) { oscBuf[i]->rate=rate; } + immWrite(0x2d,0xff); + immWrite(prescale,0xff); + ay->setExtClockDiv(chipClock,ayDiv); + ay->setFlags(16); } int DivPlatformYM2203::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { @@ -1050,11 +1081,11 @@ int DivPlatformYM2203::init(DivEngine* p, int channels, int sugRate, unsigned in } fm=new ymfm::ym2203(iface); fm->set_fidelity(ymfm::OPN_FIDELITY_MIN); - setFlags(flags); // YM2149, 2MHz ay=new DivPlatformAY8910(true,chipClock,ayDiv); ay->init(p,3,sugRate,16); ay->toggleRegisterDump(true); + setFlags(flags); reset(); return 6; diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index 6d7bc4207..d406e2f28 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -90,6 +90,7 @@ class DivPlatformYM2203: public DivPlatformOPN { unsigned char sampleBank; bool extMode; + unsigned char prescale; friend void putDispatchChan(void*,int,int); @@ -118,7 +119,8 @@ class DivPlatformYM2203: public DivPlatformOPN { int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); DivPlatformYM2203(): - DivPlatformOPN(4720270.0, 36, 16) {} + DivPlatformOPN(4720270.0, 36, 16), + prescale(0x2d) {} ~DivPlatformYM2203(); }; #endif diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 46b8b0ad1..733f04812 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -1325,6 +1325,10 @@ void DivPlatformYM2608::reset() { // enable 6 channel mode immWrite(0x29,0x80); + // set prescaler + immWrite(0x2d,0xff); + immWrite(prescale,0xff); + ay->reset(); ay->getRegisterWrites().clear(); ay->flushWrites(); @@ -1395,7 +1399,8 @@ void DivPlatformYM2608::renderSamples() { } void DivPlatformYM2608::setFlags(unsigned int flags) { - switch (flags&0x3f) { + // Clock flags + switch (flags&0x1f) { default: case 0x00: chipClock=8000000.0; @@ -1404,10 +1409,36 @@ void DivPlatformYM2608::setFlags(unsigned int flags) { chipClock=38400*13*16; // 31948800/4 break; } + // Prescaler flags + switch ((flags>>5)&0x3) { + default: + case 0x00: // /6 + prescale=0x2d; + fmFreqBase=9440540.0, + fmDivBase=72, + ayDiv=32; + break; + case 0x01: // /3 + prescale=0x2e; + fmFreqBase=9440540.0/2.0, + fmDivBase=36, + ayDiv=16; + break; + case 0x02: // /2 + prescale=0x2f; + fmFreqBase=9440540.0/3.0, + fmDivBase=24, + ayDiv=8; + break; + } rate=fm->sample_rate(chipClock); for (int i=0; i<16; i++) { oscBuf[i]->rate=rate; } + immWrite(0x2d,0xff); + immWrite(prescale,0xff); + ay->setExtClockDiv(chipClock,ayDiv); + ay->setFlags(16); } int DivPlatformYM2608::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { @@ -1423,11 +1454,12 @@ int DivPlatformYM2608::init(DivEngine* p, int channels, int sugRate, unsigned in oscBuf[i]=new DivDispatchOscBuffer; } fm=new ymfm::ym2608(iface); - setFlags(flags); + fm->set_fidelity(ymfm::OPN_FIDELITY_MIN); // YM2149, 2MHz - ay=new DivPlatformAY8910(true,chipClock,32); + ay=new DivPlatformAY8910(true,chipClock,ayDiv); ay->init(p,3,sugRate,16); ay->toggleRegisterDump(true); + setFlags(flags); reset(); return 16; } diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index c1f43f4df..ac38a8c08 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -101,8 +101,7 @@ class DivPlatformYM2608: public DivPlatformOPN { unsigned char writeRSSOff, writeRSSOn; bool extMode; - double fmFreqBase; - unsigned char ayDiv; + unsigned char prescale; double NOTE_OPNB(int ch, int note); double NOTE_ADPCMB(int note); @@ -137,7 +136,8 @@ class DivPlatformYM2608: public DivPlatformOPN { int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); DivPlatformYM2608(): - DivPlatformOPN(9440540.0, 72, 32) {} + DivPlatformOPN(9440540.0, 72, 32), + prescale(0x2d) {} ~DivPlatformYM2608(); }; #endif diff --git a/src/engine/song.h b/src/engine/song.h index 6bbb00cf8..df622d866 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -357,7 +357,7 @@ struct DivSong { // - 3: 3MHz // - 4: 3.9936MHz (PC-88, PC-98) // - 5: 1.5MHz - // - bit 5-6: output rate (TODO) + // - bit 5-6: output rate // - 0: FM: clock / 72, SSG: clock / 16 // - 1: FM: clock / 36, SSG: clock / 8 // - 2: FM: clock / 24, SSG: clock / 4 @@ -365,7 +365,7 @@ struct DivSong { // - bit 0-4: clock rate // - 0: 8MHz // - 1: 7.987MHz (PC-88, PC-98) - // - bit 5-6: output rate (TODO) + // - bit 5-6: output rate // - 0: FM: clock / 144, SSG: clock / 32 // - 1: FM: clock / 72, SSG: clock / 16 // - 2: FM: clock / 48, SSG: clock / 8 diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index d0e63c111..5056de747 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -56,13 +56,13 @@ void FurnaceGUI::initSystemPresets() { )); cat.systems.push_back(FurnaceGUISysDef( "Yamaha YM2608 (OPNA)", { - DIV_SYSTEM_PC98, 64, 0, 3, + DIV_SYSTEM_PC98, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "Yamaha YM2608 (extended channel 3)", { - DIV_SYSTEM_PC98_EXT, 64, 0, 3, + DIV_SYSTEM_PC98_EXT, 64, 0, 0, 0 } )); @@ -258,6 +258,18 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "TI SN94624", { + DIV_SYSTEM_SMS, 64, 0, 0x80, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "TI SN76494", { + DIV_SYSTEM_SMS, 64, 0, 0x84, + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "AY-3-8910", { DIV_SYSTEM_AY8910, 64, 0, 0, diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 02d06db30..21fef35d1 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -397,8 +397,7 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::RadioButton("1.5MHz",(flags&31)==5)) { copyOfFlags=(flags&(~31))|5; } - /* - ImGui::Text("Output rate: (DOES NOT WORK YET!)"); + ImGui::Text("Output rate:"); if (ImGui::RadioButton("FM: clock / 72, SSG: clock / 16",(flags&96)==0)) { copyOfFlags=(flags&(~96))|0; } @@ -408,7 +407,6 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::RadioButton("FM: clock / 24, SSG: clock / 4",(flags&96)==64)) { copyOfFlags=(flags&(~96))|64; } - */ break; } case DIV_SYSTEM_PC98: @@ -420,8 +418,7 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::RadioButton("7.987MHz (PC-88/PC-98)",(flags&31)==1)) { copyOfFlags=(flags&(~31))|1; } - /* - ImGui::Text("Output rate: (DOES NOT WORK YET!)"); + ImGui::Text("Output rate:"); if (ImGui::RadioButton("FM: clock / 144, SSG: clock / 32",(flags&96)==0)) { copyOfFlags=(flags&(~96))|0; } @@ -431,7 +428,6 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::RadioButton("FM: clock / 48, SSG: clock / 8",(flags&96)==64)) { copyOfFlags=(flags&(~96))|64; } - */ break; } case DIV_SYSTEM_RF5C68: { From 66f3f0e67810fff5a7abfccecd98828f5820f239 Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 17 Jun 2022 14:34:00 +0900 Subject: [PATCH 052/101] Input clock is too high for these chips --- src/gui/presets.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 5056de747..53ef7d429 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -260,13 +260,13 @@ void FurnaceGUI::initSystemPresets() { )); cat.systems.push_back(FurnaceGUISysDef( "TI SN94624", { - DIV_SYSTEM_SMS, 64, 0, 0x80, + DIV_SYSTEM_SMS, 64, 0, 0x182, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "TI SN76494", { - DIV_SYSTEM_SMS, 64, 0, 0x84, + DIV_SYSTEM_SMS, 64, 0, 0x186, 0 } )); From d8513e0856174a980c021ca91dcf91eeba83a092 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 17 Jun 2022 01:28:22 -0500 Subject: [PATCH 053/101] GUI: use Native File Dialog on Windows/macOS latter is untested --- CMakeLists.txt | 14 +++++++ src/gui/fileDialog.cpp | 84 ++++++++++++++++++++++++++++++++++++++++++ src/gui/fileDialog.h | 16 ++++++++ 3 files changed, 114 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8491b455..25c3c9040 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -520,8 +520,17 @@ src/gui/volMeter.cpp src/gui/gui.cpp ) +if (WIN32 OR APPLE) + list(APPEND GUI_SOURCES extern/nfd-modified/src/nfd_common.c) +endif() + +if (WIN32) + list(APPEND GUI_SOURCES extern/nfd-modified/src/nfd_win.cpp) +endif() + if (APPLE) list(APPEND GUI_SOURCES src/gui/macstuff.m) + list(APPEND GUI_SOURCES extern/nfd-modified/src/nfd_cocoa.m) endif() if (NOT WIN32 AND NOT APPLE) @@ -549,6 +558,11 @@ if (BUILD_GUI) extern/IconFontCppHeaders extern/igfd ) + if (WIN32 OR APPLE) + list(APPEND DEPENDENCIES_INCLUDE_DIRS + extern/nfd-modified/src/include + ) + endif() list(APPEND DEPENDENCIES_DEFINES HAVE_GUI) message(STATUS "Building GUI") else() diff --git a/src/gui/fileDialog.cpp b/src/gui/fileDialog.cpp index e50298c1a..c88a04275 100644 --- a/src/gui/fileDialog.cpp +++ b/src/gui/fileDialog.cpp @@ -2,7 +2,62 @@ #include "ImGuiFileDialog.h" #include "../ta-log.h" +#ifdef USE_NFD +#include +#else #include "../../extern/pfd-fixed/portable-file-dialogs.h" +#endif + +#ifdef USE_NFD +struct NFDState { + bool isSave; + String header; + std::vector filter; + String path; + FileDialogSelectCallback clickCallback; + NFDState(bool save, String h, std::vector filt, String pa, FileDialogSelectCallback cc): + isSave(save), + header(h), + filter(filt), + path(pa), + clickCallback(cc) { + } +}; + +// TODO: filter +void _nfdThread(const NFDState state, std::atomic* ok, String* result) { + nfdchar_t* out=NULL; + nfdresult_t ret=NFD_CANCEL; + + if (state.isSave) { + ret=NFD_SaveDialog(NULL,state.path.c_str(),&out); + } else { + ret=NFD_OpenDialog(NULL,state.path.c_str(),&out); + } + + switch (ret) { + case NFD_OKAY: + if (out!=NULL) { + (*result)=out; + } else { + (*result)=""; + } + break; + case NFD_CANCEL: + (*result)=""; + break; + case NFD_ERROR: + (*result)=""; + logE("NFD error! %s\n",NFD_GetError()); + break; + default: + logE("NFD unknown return code %d!\n",ret); + (*result)=""; + break; + } + (*ok)=true; +} +#endif bool FurnaceGUIFileDialog::openLoad(String header, std::vector filter, const char* noSysFilter, String path, double dpiScale, FileDialogSelectCallback clickCallback) { if (opened) return false; @@ -10,7 +65,12 @@ bool FurnaceGUIFileDialog::openLoad(String header, std::vector filter, c curPath=path; logD("opening load file dialog with curPath %s",curPath.c_str()); if (sysDialog) { +#ifdef USE_NFD + dialogOK=false; + dialogO=new std::thread(_nfdThread,NFDState(false,header,filter,path,clickCallback),&dialogOK,&nfdResult); +#else dialogO=new pfd::open_file(header,path,filter); +#endif } else { ImGuiFileDialog::Instance()->DpiScale=dpiScale; ImGuiFileDialog::Instance()->OpenModal("FileDialog",header,noSysFilter,path,1,nullptr,0,clickCallback); @@ -25,7 +85,12 @@ bool FurnaceGUIFileDialog::openSave(String header, std::vector filter, c curPath=path; logD("opening save file dialog with curPath %s",curPath.c_str()); if (sysDialog) { +#ifdef USE_NFD + dialogOK=false; + dialogS=new std::thread(_nfdThread,NFDState(true,header,filter,path,NULL),&dialogOK,&nfdResult); +#else dialogS=new pfd::save_file(header,path,filter); +#endif } else { ImGuiFileDialog::Instance()->DpiScale=dpiScale; ImGuiFileDialog::Instance()->OpenModal("FileDialog",header,noSysFilter,path,1,nullptr,ImGuiFileDialogFlags_ConfirmOverwrite); @@ -46,15 +111,24 @@ void FurnaceGUIFileDialog::close() { if (sysDialog) { if (saving) { if (dialogS!=NULL) { +#ifdef USE_NFD + dialogS->join(); +#endif delete dialogS; dialogS=NULL; } } else { if (dialogO!=NULL) { +#ifdef USE_NFD + dialogO->join(); +#endif delete dialogO; dialogO=NULL; } } +#ifdef USE_NFD + dialogOK=false; +#endif } else { ImGuiFileDialog::Instance()->Close(); } @@ -63,6 +137,15 @@ void FurnaceGUIFileDialog::close() { bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) { if (sysDialog) { +#ifdef USE_NFD + if (dialogOK) { + fileName=nfdResult; + logD("returning %s",fileName.c_str()); + dialogOK=false; + return true; + } + return false; +#else if (saving) { if (dialogS!=NULL) { if (dialogS->ready(0)) { @@ -90,6 +173,7 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) { } } return false; +#endif } else { return ImGuiFileDialog::Instance()->Display("FileDialog",ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove,min,max); } diff --git a/src/gui/fileDialog.h b/src/gui/fileDialog.h index 5eb67d853..6131f56b2 100644 --- a/src/gui/fileDialog.h +++ b/src/gui/fileDialog.h @@ -3,10 +3,19 @@ #include #include +#if defined(_WIN32) || defined(__APPLE__) +#define USE_NFD +#endif + +#ifdef USE_NFD +#include +#include +#else namespace pfd { class open_file; class save_file; } +#endif typedef std::function FileDialogSelectCallback; @@ -16,8 +25,15 @@ class FurnaceGUIFileDialog { bool saving; String curPath; String fileName; +#ifdef USE_NFD + std::thread* dialogO; + std::thread* dialogS; + std::atomic dialogOK; + String nfdResult; +#else pfd::open_file* dialogO; pfd::save_file* dialogS; +#endif public: bool openLoad(String header, std::vector filter, const char* noSysFilter, String path, double dpiScale, FileDialogSelectCallback clickCallback=NULL); bool openSave(String header, std::vector filter, const char* noSysFilter, String path, double dpiScale); From 02d4712e9c7e2844d99d681eef6dbf1a82b2ea70 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 17 Jun 2022 02:21:07 -0500 Subject: [PATCH 054/101] implement undo in find and replace --- src/gui/findReplace.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 5dae95bc5..c0d59c493 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -190,7 +190,6 @@ void FurnaceGUI::doFind() { } /* issues with the find and replace function: - - doesn't mark the module as modified - can't undo - replace notes to anything starting from C-0 to lower notes will have an octave higher, so set it to replace to C-0 it will becom C-1, b_1 will become B-0 and so on */ @@ -202,6 +201,12 @@ void FurnaceGUI::doReplace() { bool* touched[DIV_MAX_CHANS]; memset(touched,0,DIV_MAX_CHANS*sizeof(bool*)); + UndoStep us; + us.type=GUI_UNDO_REPLACE; + + short prevVal[32]; + memset(prevVal,0,32*sizeof(short)); + for (FurnaceGUIQueryResult& i: curQueryResults) { int patIndex=e->song.subsong[i.subsong]->orders.ord[i.x][i.order]; DivPattern* p=e->song.subsong[i.subsong]->pat[i.x].getPattern(patIndex,true); @@ -211,6 +216,9 @@ void FurnaceGUI::doReplace() { } if (touched[i.x][(patIndex<<8)|i.y]) continue; touched[i.x][(patIndex<<8)|i.y]=true; + + memcpy(prevVal,p->data[i.y],32*sizeof(short)); + if (queryReplaceNoteDo) { switch (queryReplaceNoteMode) { case GUI_QUERY_REPLACE_SET: @@ -400,6 +408,13 @@ void FurnaceGUI::doReplace() { } } } + + // issue undo step + for (int j=0; j<32; j++) { + if (p->data[i.y][j]!=prevVal[j]) { + us.pat.push_back(UndoPatternData(i.subsong,i.x,patIndex,i.y,j,prevVal[j],p->data[i.y][j])); + } + } } for (int i=0; isettings.maxUndoSteps) undoHist.pop_front(); + } } #define FIRST_VISIBLE(x) (x==GUI_QUERY_MATCH || x==GUI_QUERY_MATCH_NOT || x==GUI_QUERY_RANGE || x==GUI_QUERY_RANGE_NOT) From a8ae8f6e5465143b981f396f9fa2c884bb46ded0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 17 Jun 2022 02:40:34 -0500 Subject: [PATCH 055/101] address the final find and replace issue --- src/gui/findReplace.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index c0d59c493..10fd12534 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -43,6 +43,7 @@ int queryNote(int note, int octave) { } bool checkCondition(int mode, int arg, int argMax, int val, bool noteMode=false) { + const int emptyVal=noteMode?-61:-1; switch (mode) { case GUI_QUERY_IGNORE: return true; @@ -51,19 +52,19 @@ bool checkCondition(int mode, int arg, int argMax, int val, bool noteMode=false) return (val==arg); break; case GUI_QUERY_MATCH_NOT: - return (val!=-1 && val!=arg); + return (val!=emptyVal && val!=arg); break; case GUI_QUERY_RANGE: return (val>=arg && val<=argMax); break; case GUI_QUERY_RANGE_NOT: - return (val!=-1 && (valargMax) && (!noteMode || val<120)); + return (val!=emptyVal && (valargMax) && (!noteMode || val<120)); break; case GUI_QUERY_ANY: - return (val!=-1); + return (val!=emptyVal); break; case GUI_QUERY_NONE: - return (val==-1); + return (val==emptyVal); break; } return false; @@ -249,8 +250,11 @@ void FurnaceGUI::doReplace() { if (note>119) note=119; p->data[i.y][0]=(note+60)%12; - if (p->data[i.y][0]==0) p->data[i.y][0]=12; - p->data[i.y][1]=(unsigned char)((note-1)/12); + p->data[i.y][1]=(unsigned char)(((note+60)/12)-5); + if (p->data[i.y][0]==0) { + p->data[i.y][0]=12; + p->data[i.y][1]=(unsigned char)(p->data[i.y][1]-1); + } } } break; @@ -266,8 +270,11 @@ void FurnaceGUI::doReplace() { } p->data[i.y][0]=(note+60)%12; - if (p->data[i.y][0]==0) p->data[i.y][0]=12; - p->data[i.y][1]=(unsigned char)((note-1)/12); + p->data[i.y][1]=(unsigned char)(((note+60)/12)-5); + if (p->data[i.y][0]==0) { + p->data[i.y][0]=12; + p->data[i.y][1]=(unsigned char)(p->data[i.y][1]-1); + } } } break; From 56b56ebdde69df343e9a4e0bc7644cf4e385077a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 17 Jun 2022 02:41:40 -0500 Subject: [PATCH 056/101] GUI: fix cursor moving on undo replace --- src/gui/editing.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index 8b30d2514..ef63ab261 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -953,13 +953,15 @@ void FurnaceGUI::doUndo() { DivPattern* p=e->curPat[i.chan].getPattern(i.pat,true); p->data[i.row][i.col]=i.oldVal; } - if (!e->isPlaying() || !followPattern) { - cursor=us.cursor; - selStart=us.selStart; - selEnd=us.selEnd; - curNibble=us.nibble; - updateScroll(cursor.y); - setOrder(us.order); + if (us.type!=GUI_UNDO_REPLACE) { + if (!e->isPlaying() || !followPattern) { + cursor=us.cursor; + selStart=us.selStart; + selEnd=us.selEnd; + curNibble=us.nibble; + updateScroll(cursor.y); + setOrder(us.order); + } } break; } @@ -1002,13 +1004,15 @@ void FurnaceGUI::doRedo() { DivPattern* p=e->curPat[i.chan].getPattern(i.pat,true); p->data[i.row][i.col]=i.newVal; } - if (!e->isPlaying()) { - cursor=us.cursor; - selStart=us.selStart; - selEnd=us.selEnd; - curNibble=us.nibble; - updateScroll(cursor.y); - setOrder(us.order); + if (us.type!=GUI_UNDO_REPLACE) { + if (!e->isPlaying() || !followPattern) { + cursor=us.cursor; + selStart=us.selStart; + selEnd=us.selEnd; + curNibble=us.nibble; + updateScroll(cursor.y); + setOrder(us.order); + } } break; From d911c8eeabde83b593aeb43f2175de9f6f90e1b4 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 17 Jun 2022 02:42:55 -0500 Subject: [PATCH 057/101] GUI: remove pointless comment in find/replace --- src/gui/findReplace.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 10fd12534..f16ccd7ae 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -190,11 +190,6 @@ void FurnaceGUI::doFind() { queryViewingResults=true; } -/* issues with the find and replace function: - - can't undo - - replace notes to anything starting from C-0 to lower notes will have an octave higher, so set it to replace to C-0 it will becom C-1, b_1 will become B-0 and so on -*/ - void FurnaceGUI::doReplace() { doFind(); queryViewingResults=false; From 5025c489775867731947fbafb700e39121f7b16e Mon Sep 17 00:00:00 2001 From: Bassian <67491162+Bassian@users.noreply.github.com> Date: Fri, 17 Jun 2022 04:46:10 -0500 Subject: [PATCH 058/101] Add files via upload --- ..._thing_the_Metallix_fear_is_you_Forte....fur | Bin 0 -> 59895 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/The_only_thing_the_Metallix_fear_is_you_Forte....fur diff --git a/demos/The_only_thing_the_Metallix_fear_is_you_Forte....fur b/demos/The_only_thing_the_Metallix_fear_is_you_Forte....fur new file mode 100644 index 0000000000000000000000000000000000000000..123381d8dc27c50307fcc76664ca1fc82d92b8dd GIT binary patch literal 59895 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 literal 0 HcmV?d00001 From 753458f8983ae83e6a32c8bfe2a572ca0043fdfc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 17 Jun 2022 04:51:39 -0500 Subject: [PATCH 059/101] LOL --- src/engine/platform/nes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 50e548ea3..67ad28521 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -65,7 +65,7 @@ const char** DivPlatformNES::getRegisterSheet() { const char* DivPlatformNES::getEffectName(unsigned char effect) { switch (effect) { case 0x11: - return "Write to delta modulation counter (0 to 7F)"; + return "11xx: Write to delta modulation counter (0 to 7F)"; break; case 0x12: return "12xx: Set duty cycle/noise mode (pulse: 0 to 3; noise: 0 or 1)"; From ab7c2acd564bec9fb4aa4d6e890de96bfa95f03a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 17 Jun 2022 04:51:45 -0500 Subject: [PATCH 060/101] GUI: try --- src/gui/sampleEdit.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 19fd75963..7264baed5 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -765,16 +765,16 @@ void FurnaceGUI::drawSampleEdit() { float highP=sampleFilterH*100.0f; float resP=sampleFilterRes*100.0f; ImGui::Text("Cutoff:"); - if (ImGui::SliderFloat("From",&sampleFilterCutStart,0.0f,sample->rate*0.5,"%.0fHz")) { + if (CWSliderFloat("From",&sampleFilterCutStart,0.0f,sample->rate*0.5,"%.0fHz")) { if (sampleFilterCutStart<0.0) sampleFilterCutStart=0.0; if (sampleFilterCutStart>sample->rate*0.5) sampleFilterCutStart=sample->rate*0.5; } - if (ImGui::SliderFloat("To",&sampleFilterCutEnd,0.0f,sample->rate*0.5,"%.0fHz")) { + if (CWSliderFloat("To",&sampleFilterCutEnd,0.0f,sample->rate*0.5,"%.0fHz")) { if (sampleFilterCutEnd<0.0) sampleFilterCutEnd=0.0; if (sampleFilterCutEnd>sample->rate*0.5) sampleFilterCutEnd=sample->rate*0.5; } ImGui::Separator(); - if (ImGui::SliderFloat("Resonance",&resP,0.0f,99.0f,"%.1f%%")) { + if (CWSliderFloat("Resonance",&resP,0.0f,99.0f,"%.1f%%")) { sampleFilterRes=resP/100.0f; if (sampleFilterRes<0.0f) sampleFilterRes=0.0f; if (sampleFilterRes>0.99f) sampleFilterRes=0.99f; @@ -793,17 +793,17 @@ void FurnaceGUI::drawSampleEdit() { sampleFilterPower=3; } ImGui::Separator(); - if (ImGui::SliderFloat("Low-pass",&lowP,0.0f,100.0f,"%.1f%%")) { + if (CWSliderFloat("Low-pass",&lowP,0.0f,100.0f,"%.1f%%")) { sampleFilterL=lowP/100.0f; if (sampleFilterL<0.0f) sampleFilterL=0.0f; if (sampleFilterL>1.0f) sampleFilterL=1.0f; } - if (ImGui::SliderFloat("Band-pass",&bandP,0.0f,100.0f,"%.1f%%")) { + if (CWSliderFloat("Band-pass",&bandP,0.0f,100.0f,"%.1f%%")) { sampleFilterB=bandP/100.0f; if (sampleFilterB<0.0f) sampleFilterB=0.0f; if (sampleFilterB>1.0f) sampleFilterB=1.0f; } - if (ImGui::SliderFloat("High-pass",&highP,0.0f,100.0f,"%.1f%%")) { + if (CWSliderFloat("High-pass",&highP,0.0f,100.0f,"%.1f%%")) { sampleFilterH=highP/100.0f; if (sampleFilterH<0.0f) sampleFilterH=0.0f; if (sampleFilterH>1.0f) sampleFilterH=1.0f; From 6dc81c7af1f1f5d9c596c334e0d8e08e64f7f36f Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 18 Jun 2022 10:38:48 +0900 Subject: [PATCH 061/101] Pitch correction (again), Fix compatibility issue --- src/engine/platform/sms.cpp | 24 +++++++++++++++--------- src/engine/platform/sms.h | 4 ++-- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 71e9b0bc0..3dc7afc44 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -120,7 +120,7 @@ void DivPlatformSMS::acquire(short* bufL, short* bufR, size_t start, size_t len) void DivPlatformSMS::tick(bool sysTick) { for (int i=0; i<4; i++) { - int CHIP_DIVIDER=toneDivider; + double CHIP_DIVIDER=toneDivider; if (i==3) CHIP_DIVIDER=noiseDivider; chan[i].std.next(); if (chan[i].std.vol.had) { @@ -245,7 +245,7 @@ void DivPlatformSMS::tick(bool sysTick) { } int DivPlatformSMS::dispatch(DivCommand c) { - int CHIP_DIVIDER=toneDivider; + double CHIP_DIVIDER=toneDivider; if (c.chan==3) CHIP_DIVIDER=noiseDivider; switch (c.cmd) { case DIV_CMD_NOTE_ON: @@ -465,8 +465,8 @@ void DivPlatformSMS::setFlags(unsigned int flags) { } resetPhase=!(flags&16); divider=16; - toneDivider=64; - noiseDivider=64; + toneDivider=64.0; + noiseDivider=64.0; if (sn!=NULL) delete sn; switch (flags&0xcc) { default: // Sega @@ -479,11 +479,13 @@ void DivPlatformSMS::setFlags(unsigned int flags) { sn=new sn76489_device(); isRealSN=true; stereo=false; + noiseDivider=60.0; // 64 for match to tone frequency on non-Sega PSG but compatibility break; case 0x08: // TI+Atari - sn=new sn76496_base_device(0x4000, 0x0f35, 0x01, 0x02, true, false, 8, false, true); + sn=new sn76496_base_device(0x4000, 0x0f35, 0x01, 0x02, true, false, 1/*8*/, false, true); isRealSN=true; stereo=false; + noiseDivider=60.0; break; case 0x0c: // Game Gear (not fully emulated yet!) sn=new gamegear_device(); @@ -494,37 +496,41 @@ void DivPlatformSMS::setFlags(unsigned int flags) { sn=new sn76489a_device(); isRealSN=false; // TODO stereo=false; + noiseDivider=60.0; break; case 0x44: // TI SN76496 sn=new sn76496_device(); isRealSN=false; // TODO stereo=false; + noiseDivider=60.0; break; case 0x48: // NCR 8496 sn=new ncr8496_device(); isRealSN=false; stereo=false; + noiseDivider=60.0; break; case 0x4c: // Tandy PSSJ 3-voice sound sn=new pssj3_device(); isRealSN=false; stereo=false; + noiseDivider=60.0; break; case 0x80: // TI SN94624 sn=new sn94624_device(); isRealSN=true; stereo=false; divider=2; - toneDivider=8; - noiseDivider=8; + toneDivider=8.0; + noiseDivider=7.5; break; case 0x84: // TI SN76494 sn=new sn76494_device(); isRealSN=false; // TODO stereo=false; divider=2; - toneDivider=8; - noiseDivider=8; + toneDivider=8.0; + noiseDivider=7.5; break; } rate=chipClock/divider; diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index 589bb9b88..35bb44bab 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -62,8 +62,8 @@ class DivPlatformSMS: public DivDispatch { unsigned char oldValue; unsigned char snNoiseMode; int divider=16; - int toneDivider=64; - int noiseDivider=64; + double toneDivider=64.0; + double noiseDivider=64.0; bool updateSNMode; bool resetPhase; bool isRealSN; From 9cad9077738657572588a6815c2b1d69d165d7fb Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 18 Jun 2022 11:07:36 +0900 Subject: [PATCH 062/101] Fix potential register related issue --- src/engine/platform/sms.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 3dc7afc44..0556d2e45 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -52,7 +52,9 @@ void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_ for (size_t h=start; hstereo_w(w.val); - else + else if (w.addr==0) { sn->write(w.val); + } writes.pop(); } for (size_t h=start; h Date: Sat, 18 Jun 2022 11:42:14 +0900 Subject: [PATCH 063/101] More presets Dynax/Nakanihon 3rd generation hardware: Naming reference is MAME source (https://github.com/mamedev/mame/blob/master/src/mame/drivers/ddenlovr.cpp), It's sound system combined with AY PSG(optional), OPLL, MSM6295 and mostly used in their mahjong, hanafuda, and something else. Dynax/Nakanihon Real Break: This sound system is used in Billard Academy Real Break (MAME source: https://github.com/mamedev/mame/blob/master/src/mame/drivers/realbrk.cpp), MSM6295 is replaced to YMZ280B but entire music is still drived in OPLL. --- src/gui/presets.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 53ef7d429..463352272 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1859,7 +1859,7 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_AY8910, 64, 0, 13, 0 } - )); + )); cat.systems.push_back(FurnaceGUISysDef( "Namco (3-channel WSG)", { // Pac-Man, Galaga, Xevious, etc DIV_SYSTEM_NAMCO, 64, 0, 0, @@ -1957,6 +1957,21 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Dynax/Nakanihon 3rd generation hardware", { + DIV_SYSTEM_AY8910, 64, 0, 0, // AY or YM, optional - 1.79MHz or 3.58MHz; various per game + DIV_SYSTEM_OPLL, 64, 0, 0, + DIV_SYSTEM_MSM6295, 64, 0, 6, // 1.023MHz mostly + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Dynax/Nakanihon Real Break", { + DIV_SYSTEM_OPLL, 64, 0, 0, + DIV_SYSTEM_YMZ280B, 64, 0, 0, + 0 + } + )); sysCategories.push_back(cat); cat=FurnaceGUISysCategory("DefleMask-compatible","these configurations are compatible with DefleMask.\nselect this if you need to save as .dmf or work with that program."); From 0e163baffcbb45450e3f5f79aea6e33b3b70ddfa Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 18 Jun 2022 02:00:10 -0500 Subject: [PATCH 064/101] GUI: update credits --- src/gui/about.cpp | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/gui/about.cpp b/src/gui/about.cpp index 76fc80ad2..1b257af1f 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -48,6 +48,7 @@ const char* aboutLine[]={ "-- graphics/UI design --", "tildearrow", "BlastBrothers", + "Mahbod Karamoozian", "Raijin", "", "-- documentation --", @@ -59,18 +60,38 @@ const char* aboutLine[]={ "", "-- demo songs --", "0x5066", + "Abstract 64", "ActualNK358", + "akumanatt", + "AmigaX", + "AURORA*FIELDS", + "BlueElectric05", "breakthetargets", "CaptainMalware", + "DeMOSic", + "DevEd", + "Dippy", + "Forte", + "Fragmare", + "freq-mod", + "iyatemu", "kleeder", + "jaezu", + "Laggy", + "LunaMoth", "Mahbod Karamoozian", + "Miker", "nicco1690", "NikonTeen", "SuperJet Spade", "TheDuccinator", + "theloredev", "TheRealHedgehogSonic", "tildearrow", "Ultraprogramer", + "Weeppiko", + "WitchyValeria", + "ZoomTen (Zumi)", "", "-- additional feedback/fixes --", "fd", @@ -85,7 +106,9 @@ const char* aboutLine[]={ "and Mark Adler", "libsndfile by Erik de Castro Lopo", "Portable File Dialogs by Sam Hocevar", + "Native File Dialog by Frogtoss Games", "RtMidi by Gary P. Scavone", + "backward-cpp by Google", "adpcm by superctr", "Nuked-OPL3/OPLL/OPM/OPN2 by Nuke.YKT", "ymfm by Aaron Giles", @@ -93,21 +116,31 @@ const char* aboutLine[]={ "MAME AY-3-8910 by Couriersud", "with AY8930 fixes by Eulous, cam900 and Grauw", "MAME SAA1099 by Juergen Buchmueller and Manuel Abadia", + "MAME Namco WSG by Nicola Salmoria and Aaron Giles", + "MAME RF5C68 core by Olivier Galibert and Aaron Giles", + "MAME MSM6258 core by Barry Rodewald", + "MAME YMZ280B core by Aaron Giles", "SAASound by Dave Hooper and Simon Owen", "SameBoy by Lior Halphon", "Mednafen PCE and WonderSwan audio cores", "puNES (NES, MMC5 and FDS) by FHorse", + "NSFPlay (NES and FDS) by Brad Smith and Brezza", "reSID by Dag Lem", "Stella by Stella Team", - "QSound emulator by Ian Karlsson and Valley Bell", + "QSound emulator by superctr and Valley Bell", "VICE VIC-20 sound core by Rami Rasanen and viznut", "VERA sound core by Frank van den Hoef", "K005289 emulator by cam900", "Namco 163 emulator by cam900", "Seta X1-010 emulator by cam900", "Konami VRC6 emulator by cam900", + "Konami SCC emulator by cam900", + "MSM6295 emulator by cam900", "", - "greetings to all members of Deflers of Noice!", + "greetings to:", + "Fractal Sound team", + "NEOART Costa Rica", + "all members of Deflers of Noice!", "", "copyright © 2021-2022 tildearrow", "(and contributors).", From af8c6313dfbf942b39cbdba57673ce49f5e0b6c9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 18 Jun 2022 02:01:44 -0500 Subject: [PATCH 065/101] update demo song authors --- demos/AY-3-8910_Jam.fur | Bin 1230 -> 1274 bytes demos/UNATCOPCM.fur | Bin 205937 -> 205943 bytes demos/ecolove.fur | Bin 57851 -> 57812 bytes demos/su_memory.fur | Bin 20139 -> 20220 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/demos/AY-3-8910_Jam.fur b/demos/AY-3-8910_Jam.fur index b249c5bfde36c68fc322ab07c8cc702aa4dfe7b7..dad4f190ef7439917a0b0aff3174700a11e1efd4 100644 GIT binary patch literal 1274 zcmVap$*15JgU5wFLM(%O;zE9 zA*72|5)$=N7nLFA&z15AjIxpx_R^(%0Fwk47RLeU&afy+rA?hw{fSq-+cu1Yzs5G3 zNS5i#w5{#Zbu3Nsou4K@y(g_pR+82S#qs^D)XiF(c}RsXrNJ3mc+dQVE9 zSV>CyeYw{qrB!SlI-=WrU#4wsm#$-Jitqe1`RNbQ?OeO}6@5L<@4#iZXcwKnczsO1 zZ?F#i*;G9t*ZGKE^JPM)yh>a`bgI*Ma+5&oV;BEU^_YpXmp_6lJs>(s2(=n<46$0> zr<1b={V~-;OZv~=_{)S)Plk>mR;vq3E+|g7C81d+)(N2(BI9g8qQ-EHpthdVIeUlS zgzp*o&@cB*@p~%Xo#N>oDsz=6GE>c%99CkGOPQH-p1ave$o9|X8-Fa zf!4<}dhi!lvmwB>LdzQbP!{NsesZ}82WT!Ux5zUeOh%h9{DXF!M+fBC<9i=z9Qd>OB%XIHrgi8ucd>J0S#(01#*n+Q(fS#-C=)_`hbUnf kA~C#!bM_onIeaC8tv9>SIQvE8+w#a4bB|2_15wZEx&`u+YXATM literal 1230 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

$`*X+gux|NcR2ccVn9${QQR;}v73rJc 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 Vum_Qr(aQ8E) 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�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 R0DaNt-{KH~6r&JN_CG!NIpF{R literal 205937 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 z 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 diff --git a/demos/ecolove.fur b/demos/ecolove.fur index 9f287ec6111aa5ab1cc09ec19b6382ab8818163c..4fe641c9e29228d90502eae208785ca0f0105550 100644 GIT binary patch literal 57812 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 A0ssI2 literal 57851 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 NbXMy3|3B-z$LQA7Jc$4R delta 19020 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 From ea082b255c914e1ac1127f404c2b58baea2f16bb Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 18 Jun 2022 03:52:03 -0500 Subject: [PATCH 066/101] GUI: prepare for drag selection to move --- src/gui/cursor.cpp | 59 ++++++++++++++++++++++++++++++++++++++------ src/gui/editing.cpp | 26 +++++++++++++++++++ src/gui/gui.cpp | 5 ++++ src/gui/gui.h | 10 +++++--- src/gui/settings.cpp | 9 +++++++ 5 files changed, 98 insertions(+), 11 deletions(-) diff --git a/src/gui/cursor.cpp b/src/gui/cursor.cpp index e47dfd629..4b75a26ad 100644 --- a/src/gui/cursor.cpp +++ b/src/gui/cursor.cpp @@ -42,6 +42,22 @@ void FurnaceGUI::startSelection(int xCoarse, int xFine, int y, bool fullRow) { return; } } + + if (settings.dragMovesSelection && !fullRow) { + if (xCoarse>=selStart.xCoarse && (xFine>=selStart.xFine || xCoarse>selStart.xCoarse) && y>=selStart.y && + xCoarse<=selEnd.xCoarse && (xFine<=selEnd.xFine || xCoarsecurPat[selEnd.xCoarse].effectCols*2; - selEnd.y=y; + if (dragging) { + dragDestinationX=xCoarse; + dragDestinationY=y; + cursorDrag.xCoarse=xCoarse; + cursorDrag.xFine=xFine; + cursorDrag.y=y; + + selStart.xCoarse=dragStart.xCoarse+(dragDestinationX-dragSourceX); + selStart.xFine=dragStart.xFine; + selStart.y=dragStart.y+(dragDestinationY-dragSourceY); + selEnd.xCoarse=dragEnd.xCoarse+(dragDestinationX-dragSourceX); + selEnd.xFine=dragEnd.xFine; + selEnd.y=dragEnd.y+(dragDestinationY-dragSourceY); } else { - selEnd.xCoarse=xCoarse; - selEnd.xFine=xFine; - selEnd.y=y; + if (selectingFull) { + DETERMINE_LAST; + selEnd.xCoarse=lastChannel-1; + selEnd.xFine=2+e->curPat[selEnd.xCoarse].effectCols*2; + selEnd.y=y; + } else { + selEnd.xCoarse=xCoarse; + selEnd.xFine=xFine; + selEnd.y=y; + } } } @@ -103,6 +134,18 @@ void FurnaceGUI::finishSelection() { selecting=false; selectingFull=false; + if (dragging) { + if (dragSourceX==dragDestinationX && dragSourceY==dragDestinationY) { + cursor=cursorDrag; + selStart=cursorDrag; + selEnd=cursorDrag; + } else { // perform drag + doDrag(); + } + + dragging=false; + } + // boundary check int chanCount=e->getTotalChannelCount(); diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index ef63ab261..2f2757c2b 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -918,6 +918,32 @@ void FurnaceGUI::doExpand(int multiplier) { makeUndo(GUI_UNDO_PATTERN_EXPAND); } +// 1. COPY +// 2. CLEAR +// 3. PASTE +void FurnaceGUI::doDrag() { + int iCoarse=selStart.xCoarse; + int iFine=selStart.xFine; + for (; iCoarse<=selEnd.xCoarse; iCoarse++) { + if (!e->curSubSong->chanShow[iCoarse]) continue; + DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true); + for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarsedata[j][iFine]=0; + if (selStart.y==selEnd.y) pat->data[j][2]=-1; + } + pat->data[j][iFine+1]=(iFine<1)?0:-1; + + if (selStart.y==selEnd.y && iFine>2 && iFine&1 && settings.effectDeletionAltersValue) { + pat->data[j][iFine+2]=-1; + } + } + } + iFine=0; + } +} + void FurnaceGUI::doUndo() { if (undoHist.empty()) return; UndoStep& us=undoHist.back(); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index fd904649c..5717f3910 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4372,6 +4372,10 @@ FurnaceGUI::FurnaceGUI(): latchTarget(0), wheelX(0), wheelY(0), + dragSourceX(0), + dragSourceY(0), + dragDestinationX(0), + dragDestinationY(0), exportFadeOut(5.0), editControlsOpen(true), ordersOpen(true), @@ -4403,6 +4407,7 @@ FurnaceGUI::FurnaceGUI(): findOpen(false), selecting(false), selectingFull(false), + dragging(false), curNibble(false), orderNibble(false), followOrders(true), diff --git a/src/gui/gui.h b/src/gui/gui.h index 9381bab09..b9a550ed6 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1024,6 +1024,7 @@ class FurnaceGUI { int effectValCellSpacing; int doubleClickColumn; int blankIns; + int dragMovesSelection; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -1124,6 +1125,7 @@ class FurnaceGUI { effectValCellSpacing(0), doubleClickColumn(1), blankIns(0), + dragMovesSelection(1), maxUndoSteps(100), mainFontPath(""), patFontPath(""), @@ -1138,7 +1140,7 @@ class FurnaceGUI { int curIns, curWave, curSample, curOctave, curOrder, prevIns, oldRow, oldOrder, oldOrder1, editStep, exportLoops, soloChan, soloTimeout, orderEditMode, orderCursor; int loopOrder, loopRow, loopEnd, isClipping, extraChannelButtons, patNameTarget, newSongCategory, latchTarget; - int wheelX, wheelY; + int wheelX, wheelY, dragSourceX, dragSourceY, dragDestinationX, dragDestinationY; double exportFadeOut; @@ -1148,8 +1150,8 @@ class FurnaceGUI { bool pianoOpen, notesOpen, channelsOpen, regViewOpen, logOpen, effectListOpen, chanOscOpen; bool subSongsOpen, findOpen; - SelectionPoint selStart, selEnd, cursor; - bool selecting, selectingFull, curNibble, orderNibble, followOrders, followPattern, changeAllOrders, mobileUI; + SelectionPoint selStart, selEnd, cursor, cursorDrag, dragStart, dragEnd; + bool selecting, selectingFull, dragging, curNibble, orderNibble, followOrders, followPattern, changeAllOrders, mobileUI; bool collapseWindow, demandScrollX, fancyPattern, wantPatName, firstFrame, tempoView, waveHex, lockLayout, editOptsVisible, latchNibble, nonLatchNibble; FurnaceGUIWindows curWindow, nextWindow, curWindowLast; float peak[2]; @@ -1465,6 +1467,7 @@ class FurnaceGUI { void startSelection(int xCoarse, int xFine, int y, bool fullRow=false); void updateSelection(int xCoarse, int xFine, int y, bool fullRow=false); void finishSelection(); + void finishDrag(); void moveCursor(int x, int y, bool select); void moveCursorPrevChannel(bool overflow); @@ -1494,6 +1497,7 @@ class FurnaceGUI { void doRedo(); void doFind(); void doReplace(); + void doDrag(); void editOptions(bool topMenu); void noteInput(int num, int key, int vol=-1); void valueInput(int num, bool direct=false, int target=-1); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index da3b0f277..cae24ec02 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -411,6 +411,11 @@ void FurnaceGUI::drawSettings() { if (ImGui::Checkbox("Double click selects entire column",&doubleClickColumnB)) { settings.doubleClickColumn=doubleClickColumnB; } + + bool dragMovesSelectionB=settings.dragMovesSelection; + if (ImGui::Checkbox("Allow dragging selection",&dragMovesSelectionB)) { + settings.dragMovesSelection=dragMovesSelectionB; + } bool allowEditDockingB=settings.allowEditDocking; if (ImGui::Checkbox("Allow docking editors",&allowEditDockingB)) { @@ -2037,6 +2042,8 @@ void FurnaceGUI::syncSettings() { settings.effectValCellSpacing=e->getConfInt("effectValCellSpacing",0); settings.doubleClickColumn=e->getConfInt("doubleClickColumn",1); settings.blankIns=e->getConfInt("blankIns",0); + // SET TO 1 AFTER YOU ARE DONE + settings.dragMovesSelection=e->getConfInt("dragMovesSelection",0); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -2121,6 +2128,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.effectValCellSpacing,0,32); clampSetting(settings.doubleClickColumn,0,1); clampSetting(settings.blankIns,0,1); + clampSetting(settings.dragMovesSelection,0,1); settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys","")); if (settings.initialSys.size()<4) { @@ -2254,6 +2262,7 @@ void FurnaceGUI::commitSettings() { e->setConf("effectValCellSpacing",settings.effectValCellSpacing); e->setConf("doubleClickColumn",settings.doubleClickColumn); e->setConf("blankIns",settings.blankIns); + e->setConf("dragMovesSelection",settings.dragMovesSelection); // colors for (int i=0; i Date: Sat, 18 Jun 2022 23:18:34 -0500 Subject: [PATCH 067/101] GUI: add ability to move selection by dragging --- TODO.md | 1 - src/gui/editing.cpp | 84 ++++++++++++++++++++++++++++++++++---------- src/gui/gui.h | 1 + src/gui/settings.cpp | 3 +- 4 files changed, 68 insertions(+), 21 deletions(-) diff --git a/TODO.md b/TODO.md index b0fc02d37..cca5ffdb9 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,5 @@ # to-do for 0.6pre1 -- add ability to move selection by dragging - implement Defle slide bug when using E1xy/E2xy and repeating origin note (requires format change) # to-do for 0.6pre2 (as this requires new data structures) diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index 2f2757c2b..9bd827951 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -62,6 +62,7 @@ void FurnaceGUI::prepareUndo(ActionType action) { case GUI_UNDO_PATTERN_FLIP: case GUI_UNDO_PATTERN_COLLAPSE: case GUI_UNDO_PATTERN_EXPAND: + case GUI_UNDO_PATTERN_DRAG: for (int i=0; igetTotalChannelCount(); i++) { e->curPat[i].getPattern(e->curOrders->ord[i][curOrder],false)->copyOn(oldPat[i]); } @@ -114,6 +115,7 @@ void FurnaceGUI::makeUndo(ActionType action) { case GUI_UNDO_PATTERN_FLIP: case GUI_UNDO_PATTERN_COLLAPSE: case GUI_UNDO_PATTERN_EXPAND: + case GUI_UNDO_PATTERN_DRAG: for (int i=0; igetTotalChannelCount(); i++) { DivPattern* p=e->curPat[i].getPattern(e->curOrders->ord[i][curOrder],false); for (int j=0; jcurSubSong->patLen; j++) { @@ -918,30 +920,74 @@ void FurnaceGUI::doExpand(int multiplier) { makeUndo(GUI_UNDO_PATTERN_EXPAND); } -// 1. COPY -// 2. CLEAR -// 3. PASTE void FurnaceGUI::doDrag() { - int iCoarse=selStart.xCoarse; - int iFine=selStart.xFine; - for (; iCoarse<=selEnd.xCoarse; iCoarse++) { - if (!e->curSubSong->chanShow[iCoarse]) continue; - DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true); - for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarsedata[j][iFine]=0; - if (selStart.y==selEnd.y) pat->data[j][2]=-1; - } - pat->data[j][iFine+1]=(iFine<1)?0:-1; + DivPattern* patBuffer=NULL; + int len=dragEnd.xCoarse-dragStart.xCoarse+1; - if (selStart.y==selEnd.y && iFine>2 && iFine&1 && settings.effectDeletionAltersValue) { - pat->data[j][iFine+2]=-1; + DETERMINE_FIRST_LAST; + + if (len<1) return; + + patBuffer=new DivPattern[len]; + prepareUndo(GUI_UNDO_PATTERN_DRAG); + + // copy and clear + { + int iCoarse=dragStart.xCoarse; + int iFine=dragStart.xFine; + int iCoarseP=0; + for (; iCoarse<=dragEnd.xCoarse; iCoarse++) { + if (!e->curSubSong->chanShow[iCoarse]) continue; + DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true); + for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarsedata[j][iFine]; + pat->data[j][iFine]=0; + if (dragStart.y==dragEnd.y) pat->data[j][2]=-1; + } + patBuffer[iCoarseP].data[row][iFine+1]=pat->data[j][iFine+1]; + pat->data[j][iFine+1]=(iFine<1)?0:-1; + + if (dragStart.y==dragEnd.y && iFine>2 && iFine&1 && settings.effectDeletionAltersValue) { + pat->data[j][iFine+2]=-1; + } + row++; } } + iFine=0; + iCoarseP++; } - iFine=0; } + + // replace + { + int iCoarse=selStart.xCoarse; + int iFine=selStart.xFine; + int iCoarseP=0; + for (; iCoarse<=selEnd.xCoarse && iCoarsePlastChannel) continue; + if (!e->curSubSong->chanShow[iCoarse]) continue; + DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true); + for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse=e->curSubSong->patLen) continue; + if (iFine==0) { + pat->data[j][iFine]=patBuffer[iCoarseP].data[row][iFine]; + } + pat->data[j][iFine+1]=patBuffer[iCoarseP].data[row][iFine+1]; + } + } + iFine=0; + iCoarseP++; + } + } + + delete[] patBuffer; + makeUndo(GUI_UNDO_PATTERN_DRAG); } void FurnaceGUI::doUndo() { @@ -973,6 +1019,7 @@ void FurnaceGUI::doUndo() { case GUI_UNDO_PATTERN_FLIP: case GUI_UNDO_PATTERN_COLLAPSE: case GUI_UNDO_PATTERN_EXPAND: + case GUI_UNDO_PATTERN_DRAG: case GUI_UNDO_REPLACE: for (UndoPatternData& i: us.pat) { e->changeSongP(i.subSong); @@ -1024,6 +1071,7 @@ void FurnaceGUI::doRedo() { case GUI_UNDO_PATTERN_FLIP: case GUI_UNDO_PATTERN_COLLAPSE: case GUI_UNDO_PATTERN_EXPAND: + case GUI_UNDO_PATTERN_DRAG: case GUI_UNDO_REPLACE: for (UndoPatternData& i: us.pat) { e->changeSongP(i.subSong); diff --git a/src/gui/gui.h b/src/gui/gui.h index b9a550ed6..ac15d5a8a 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -567,6 +567,7 @@ enum ActionType { GUI_UNDO_PATTERN_FLIP, GUI_UNDO_PATTERN_COLLAPSE, GUI_UNDO_PATTERN_EXPAND, + GUI_UNDO_PATTERN_DRAG, GUI_UNDO_REPLACE }; diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index cae24ec02..a6f45e20c 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -2042,8 +2042,7 @@ void FurnaceGUI::syncSettings() { settings.effectValCellSpacing=e->getConfInt("effectValCellSpacing",0); settings.doubleClickColumn=e->getConfInt("doubleClickColumn",1); settings.blankIns=e->getConfInt("blankIns",0); - // SET TO 1 AFTER YOU ARE DONE - settings.dragMovesSelection=e->getConfInt("dragMovesSelection",0); + settings.dragMovesSelection=e->getConfInt("dragMovesSelection",1); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); From 03e31c441e990142702f7fafdb612d435e2b8cf2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 19 Jun 2022 00:11:18 -0500 Subject: [PATCH 068/101] prepare for ins preview in system file picker --- CMakeLists.txt | 4 +- extern/nfd-modified/src/include/nfd.h | 9 ---- .../src/{nfd_cocoa.m => nfd_cocoa.mm} | 6 +++ .../src/{nfd_common.c => nfd_common.cpp} | 0 extern/nfd-modified/src/nfd_common.h | 8 --- .../src/{nfd_gtk.c => nfd_gtk.cpp} | 0 extern/nfd-modified/src/nfd_win.cpp | 1 + .../src/{nfd_zenity.c => nfd_zenity.cpp} | 0 papers/newIns.md | 49 +++++++++++++++++++ 9 files changed, 58 insertions(+), 19 deletions(-) rename extern/nfd-modified/src/{nfd_cocoa.m => nfd_cocoa.mm} (97%) rename extern/nfd-modified/src/{nfd_common.c => nfd_common.cpp} (100%) rename extern/nfd-modified/src/{nfd_gtk.c => nfd_gtk.cpp} (100%) rename extern/nfd-modified/src/{nfd_zenity.c => nfd_zenity.cpp} (100%) create mode 100644 papers/newIns.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 25c3c9040..c7c076a27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -521,7 +521,7 @@ src/gui/gui.cpp ) if (WIN32 OR APPLE) - list(APPEND GUI_SOURCES extern/nfd-modified/src/nfd_common.c) + list(APPEND GUI_SOURCES extern/nfd-modified/src/nfd_common.cpp) endif() if (WIN32) @@ -530,7 +530,7 @@ endif() if (APPLE) list(APPEND GUI_SOURCES src/gui/macstuff.m) - list(APPEND GUI_SOURCES extern/nfd-modified/src/nfd_cocoa.m) + list(APPEND GUI_SOURCES extern/nfd-modified/src/nfd_cocoa.mm) endif() if (NOT WIN32 AND NOT APPLE) diff --git a/extern/nfd-modified/src/include/nfd.h b/extern/nfd-modified/src/include/nfd.h index 74c92743f..c88e4c857 100644 --- a/extern/nfd-modified/src/include/nfd.h +++ b/extern/nfd-modified/src/include/nfd.h @@ -10,10 +10,6 @@ #ifndef _NFD_H #define _NFD_H -#ifdef __cplusplus -extern "C" { -#endif - #include /* denotes UTF-8 char */ @@ -66,9 +62,4 @@ nfdchar_t *NFD_PathSet_GetPath( const nfdpathset_t *pathSet, size_t index ); /* Free the pathSet */ void NFD_PathSet_Free( nfdpathset_t *pathSet ); - -#ifdef __cplusplus -} -#endif - #endif diff --git a/extern/nfd-modified/src/nfd_cocoa.m b/extern/nfd-modified/src/nfd_cocoa.mm similarity index 97% rename from extern/nfd-modified/src/nfd_cocoa.m rename to extern/nfd-modified/src/nfd_cocoa.mm index 776152d41..45beab902 100644 --- a/extern/nfd-modified/src/nfd_cocoa.m +++ b/extern/nfd-modified/src/nfd_cocoa.mm @@ -8,6 +8,12 @@ #include "nfd.h" #include "nfd_common.h" +// this language is a mess! +// who thought it was a good idea to combine Objective-C and C++ together +// when you could just have used C++ and call it a day!!! +// +// might as well make Objective-Ruswift++... + static NSArray *BuildAllowedFileTypes( const char *filterList ) { // Commas and semicolons are the same thing on this platform diff --git a/extern/nfd-modified/src/nfd_common.c b/extern/nfd-modified/src/nfd_common.cpp similarity index 100% rename from extern/nfd-modified/src/nfd_common.c rename to extern/nfd-modified/src/nfd_common.cpp diff --git a/extern/nfd-modified/src/nfd_common.h b/extern/nfd-modified/src/nfd_common.h index 1a9ab1625..a1dd74b51 100644 --- a/extern/nfd-modified/src/nfd_common.h +++ b/extern/nfd-modified/src/nfd_common.h @@ -14,10 +14,6 @@ #include -#ifdef __cplusplus -extern "C" { -#endif - #define NFD_MAX_STRLEN 256 #define _NFD_UNUSED(x) ((void)x) @@ -30,10 +26,6 @@ void NFDi_SetError( const char *msg ); int NFDi_SafeStrncpy( char *dst, const char *src, size_t maxCopy ); int32_t NFDi_UTF8_Strlen( const nfdchar_t *str ); int NFDi_IsFilterSegmentChar( char ch ); - -#ifdef __cplusplus -} -#endif #endif diff --git a/extern/nfd-modified/src/nfd_gtk.c b/extern/nfd-modified/src/nfd_gtk.cpp similarity index 100% rename from extern/nfd-modified/src/nfd_gtk.c rename to extern/nfd-modified/src/nfd_gtk.cpp diff --git a/extern/nfd-modified/src/nfd_win.cpp b/extern/nfd-modified/src/nfd_win.cpp index 949da2b53..9ef6446b0 100644 --- a/extern/nfd-modified/src/nfd_win.cpp +++ b/extern/nfd-modified/src/nfd_win.cpp @@ -423,6 +423,7 @@ nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, } // Show the dialog. + // TODO: pass the Furnace window here result = fileOpenDialog->Show(NULL); if ( SUCCEEDED(result) ) { diff --git a/extern/nfd-modified/src/nfd_zenity.c b/extern/nfd-modified/src/nfd_zenity.cpp similarity index 100% rename from extern/nfd-modified/src/nfd_zenity.c rename to extern/nfd-modified/src/nfd_zenity.cpp diff --git a/papers/newIns.md b/papers/newIns.md new file mode 100644 index 000000000..fcc5f966f --- /dev/null +++ b/papers/newIns.md @@ -0,0 +1,49 @@ +# possible new Furnace instrument format + +the main issue with Furnace instrument files is that they are too big, even if the instrument is nothing more than the FM setup... + +the aim of this new format is to greatly reduce the size of a resulting instrument. + +``` +size | description +-----|------------------------------------ + 6 | "FURINS" format magic + 2 | format version + 1 | instrument type + ??? | feature bits + 4 | instrument length (if wave/sample bits are on) +``` + +the "feature bits" field is a variable length bitfield. bit 7 in a byte indicates "read one more byte". + +the feature bits are: + +- 0: has wavetables +- 1: has samples +- 2: has name +- 3: FM data +- 4: FM data size (1: 2-op, 0: 4-op) +- 5: FM data includes OPL/OPZ data + - if off, only read an op until ssgEnv. + - if on, read everything else. +- 6: Game Boy data +- 7: (continue in next byte) +- 8: C64 data +- 9: Amiga data +- 10: standard data (macros) +- 11: operator macros +- 12: release points +- 13: op release points +- 14: extended op macros +- 15: (continue in next byte) +- 16: OPL drums mode data +- 17: Amiga sample map data +- 18: Namco 163 data +- 19: extra macros +- 20: FDS data +- 21: OPZ data +- 22: wavetable synth data +- 23: (continue in next byte) +- 24: additional macro modes +- 25: extra C64 data +- 26: MultiPCM data From 52328df8c3a9464b5a041fbb8f56606202de0385 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 19 Jun 2022 01:36:36 -0500 Subject: [PATCH 069/101] GUI: system file picker ins preview! (Windows) --- extern/nfd-modified/src/include/nfd.h | 12 +++- extern/nfd-modified/src/nfd_cocoa.mm | 9 ++- extern/nfd-modified/src/nfd_win.cpp | 97 +++++++++++++++++++++++++-- src/gui/fileDialog.cpp | 4 +- 4 files changed, 108 insertions(+), 14 deletions(-) diff --git a/extern/nfd-modified/src/include/nfd.h b/extern/nfd-modified/src/include/nfd.h index c88e4c857..4e4ddcf7b 100644 --- a/extern/nfd-modified/src/include/nfd.h +++ b/extern/nfd-modified/src/include/nfd.h @@ -11,10 +11,13 @@ #define _NFD_H #include +#include /* denotes UTF-8 char */ typedef char nfdchar_t; +typedef std::function nfdselcallback_t; + /* opaque data structure -- see NFD_PathSet_* */ typedef struct { nfdchar_t *buf; @@ -34,17 +37,20 @@ typedef enum { /* single file open dialog */ nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, const nfdchar_t *defaultPath, - nfdchar_t **outPath ); + nfdchar_t **outPath, + nfdselcallback_t selCallback = NULL ); /* multiple file open dialog */ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, const nfdchar_t *defaultPath, - nfdpathset_t *outPaths ); + nfdpathset_t *outPaths, + nfdselcallback_t selCallback = NULL ); /* save dialog */ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, const nfdchar_t *defaultPath, - nfdchar_t **outPath ); + nfdchar_t **outPath, + nfdselcallback_t selCallback = NULL ); /* select folder dialog */ diff --git a/extern/nfd-modified/src/nfd_cocoa.mm b/extern/nfd-modified/src/nfd_cocoa.mm index 45beab902..ff9522601 100644 --- a/extern/nfd-modified/src/nfd_cocoa.mm +++ b/extern/nfd-modified/src/nfd_cocoa.mm @@ -127,7 +127,8 @@ static nfdresult_t AllocPathSet( NSArray *urls, nfdpathset_t *pathset ) nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, const nfdchar_t *defaultPath, - nfdchar_t **outPath ) + nfdchar_t **outPath, + nfdselcallback_t selCallback ) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; @@ -169,7 +170,8 @@ nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, const nfdchar_t *defaultPath, - nfdpathset_t *outPaths ) + nfdpathset_t *outPaths, + nfdselcallback_t selCallback ) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; @@ -213,7 +215,8 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, const nfdchar_t *defaultPath, - nfdchar_t **outPath ) + nfdchar_t **outPath, + nfdselcallback_t selCallback ) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; diff --git a/extern/nfd-modified/src/nfd_win.cpp b/extern/nfd-modified/src/nfd_win.cpp index 9ef6446b0..ea18d72b3 100644 --- a/extern/nfd-modified/src/nfd_win.cpp +++ b/extern/nfd-modified/src/nfd_win.cpp @@ -27,6 +27,72 @@ #include #include "nfd_common.h" +// hack I know +#include "../../../src/utfutils.h" + +class NFDWinEvents: public IFileDialogEvents { + nfdselcallback_t selCallback; + size_t refCount; + + virtual ~NFDWinEvents() { + } + public: + IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) { + printf("QueryInterface called DAMN IT\n"); + *ppv=NULL; + return E_NOTIMPL; + } + + IFACEMETHODIMP_(ULONG) AddRef() { + printf("AddRef() called\n"); + return InterlockedIncrement(&refCount); + } + + IFACEMETHODIMP_(ULONG) Release() { + printf("Release() called\n"); + LONG ret=InterlockedDecrement(&refCount); + if (ret==0) { + printf("Destroying the final object.\n"); + delete this; + } + return ret; + } + + IFACEMETHODIMP OnFileOk(IFileDialog*) { return E_NOTIMPL; } + IFACEMETHODIMP OnFolderChange(IFileDialog*) { return E_NOTIMPL; } + IFACEMETHODIMP OnFolderChanging(IFileDialog*, IShellItem*) { return E_NOTIMPL; } + IFACEMETHODIMP OnOverwrite(IFileDialog*, IShellItem*, FDE_OVERWRITE_RESPONSE*) { return E_NOTIMPL; } + IFACEMETHODIMP OnShareViolation(IFileDialog*, IShellItem*, FDE_SHAREVIOLATION_RESPONSE*) { return E_NOTIMPL; } + IFACEMETHODIMP OnTypeChange(IFileDialog*) { return E_NOTIMPL; } + + IFACEMETHODIMP OnSelectionChange(IFileDialog* dialog) { + // Get the file name + ::IShellItem *shellItem(NULL); + HRESULT result = dialog->GetCurrentSelection(&shellItem); + if ( !SUCCEEDED(result) ) + { + printf("failure!\n"); + return S_OK; + } + wchar_t *filePath(NULL); + result = shellItem->GetDisplayName(::SIGDN_FILESYSPATH, &filePath); + if ( !SUCCEEDED(result) ) + { + printf("GDN failure!\n"); + shellItem->Release(); + return S_OK; + } + std::string utf8FilePath=utf16To8(filePath); + if (selCallback!=NULL) selCallback(utf8FilePath.c_str()); + printf("I got you for a value of %s\n",utf8FilePath.c_str()); + shellItem->Release(); + return S_OK; + } + NFDWinEvents(nfdselcallback_t callback): + selCallback(callback), + refCount(1) { + } +}; #define COM_INITFLAGS ::COINIT_APARTMENTTHREADED | ::COINIT_DISABLE_OLE1DDE @@ -386,10 +452,13 @@ static nfdresult_t SetDefaultPath( IFileDialog *dialog, const char *defaultPath nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, const nfdchar_t *defaultPath, - nfdchar_t **outPath ) + nfdchar_t **outPath, + nfdselcallback_t selCallback ) { nfdresult_t nfdResult = NFD_ERROR; - + NFDWinEvents* winEvents; + bool hasEvents=true; + DWORD eventID=0; HRESULT coResult = COMInit(); if (!COMIsInitialized(coResult)) @@ -420,7 +489,17 @@ nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, if ( !SetDefaultPath( fileOpenDialog, defaultPath ) ) { goto end; - } + } + + // Pass the callback + winEvents=new NFDWinEvents(selCallback); + if ( !SUCCEEDED(fileOpenDialog->Advise(winEvents,&eventID)) ) { + // error... ignore + hasEvents=false; + winEvents->Release(); + } else { + winEvents->Release(); + } // Show the dialog. // TODO: pass the Furnace window here @@ -467,8 +546,12 @@ nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, } end: - if (fileOpenDialog) + if (fileOpenDialog) { + if (hasEvents) { + fileOpenDialog->Unadvise(eventID); + } fileOpenDialog->Release(); + } COMUninit(coResult); @@ -477,7 +560,8 @@ end: nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, const nfdchar_t *defaultPath, - nfdpathset_t *outPaths ) + nfdpathset_t *outPaths, + nfdselcallback_t selCallback ) { nfdresult_t nfdResult = NFD_ERROR; @@ -571,7 +655,8 @@ end: nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, const nfdchar_t *defaultPath, - nfdchar_t **outPath ) + nfdchar_t **outPath, + nfdselcallback_t selCallback ) { nfdresult_t nfdResult = NFD_ERROR; diff --git a/src/gui/fileDialog.cpp b/src/gui/fileDialog.cpp index c88a04275..5be3bdb1a 100644 --- a/src/gui/fileDialog.cpp +++ b/src/gui/fileDialog.cpp @@ -30,9 +30,9 @@ void _nfdThread(const NFDState state, std::atomic* ok, String* result) { nfdresult_t ret=NFD_CANCEL; if (state.isSave) { - ret=NFD_SaveDialog(NULL,state.path.c_str(),&out); + ret=NFD_SaveDialog(NULL,state.path.c_str(),&out,state.clickCallback); } else { - ret=NFD_OpenDialog(NULL,state.path.c_str(),&out); + ret=NFD_OpenDialog(NULL,state.path.c_str(),&out,state.clickCallback); } switch (ret) { From 9b71dae4d92652371438ff503d816bd11f195a9a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 19 Jun 2022 01:39:07 -0500 Subject: [PATCH 070/101] fix macOS build (hopefully) --- extern/nfd-modified/src/nfd_cocoa.mm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/extern/nfd-modified/src/nfd_cocoa.mm b/extern/nfd-modified/src/nfd_cocoa.mm index ff9522601..ac5fa36c4 100644 --- a/extern/nfd-modified/src/nfd_cocoa.mm +++ b/extern/nfd-modified/src/nfd_cocoa.mm @@ -81,7 +81,7 @@ static nfdresult_t AllocPathSet( NSArray *urls, nfdpathset_t *pathset ) assert([urls count]); pathset->count = (size_t)[urls count]; - pathset->indices = NFDi_Malloc( sizeof(size_t)*pathset->count ); + pathset->indices = (size_t*)NFDi_Malloc( sizeof(size_t)*pathset->count ); if ( !pathset->indices ) { return NFD_ERROR; @@ -95,7 +95,7 @@ static nfdresult_t AllocPathSet( NSArray *urls, nfdpathset_t *pathset ) bufsize += [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1; } - pathset->buf = NFDi_Malloc( sizeof(nfdchar_t) * bufsize ); + pathset->buf = (nfdchar_t*)NFDi_Malloc( sizeof(nfdchar_t) * bufsize ); if ( !pathset->buf ) { return NFD_ERROR; @@ -151,7 +151,7 @@ nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, // byte count, not char count size_t len = strlen(utf8Path);//NFDi_UTF8_Strlen(utf8Path); - *outPath = NFDi_Malloc( len+1 ); + *outPath = (nfdchar_t*)NFDi_Malloc( len+1 ); if ( !*outPath ) { [pool release]; @@ -238,7 +238,7 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, size_t byteLen = [url.path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1; - *outPath = NFDi_Malloc( byteLen ); + *outPath = (nfdchar_t*)NFDi_Malloc( byteLen ); if ( !*outPath ) { [pool release]; @@ -278,7 +278,7 @@ nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, // byte count, not char count size_t len = strlen(utf8Path);//NFDi_UTF8_Strlen(utf8Path); - *outPath = NFDi_Malloc( len+1 ); + *outPath = (nfdchar_t*)NFDi_Malloc( len+1 ); if ( !*outPath ) { [pool release]; From 2313e4fcc358fcf087dbb0279e6c97b9d033aa15 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 19 Jun 2022 14:03:36 -0500 Subject: [PATCH 071/101] GUI: temporarily remove freqs in sample map --- src/gui/insEdit.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 8199767cf..df62a87e3 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3006,7 +3006,8 @@ void FurnaceGUI::drawInsEdit() { ImGui::BeginDisabled(ins->amiga.useWave); P(ImGui::Checkbox("Use sample map (does not work yet!)",&ins->amiga.useNoteMap)); if (ins->amiga.useNoteMap) { - if (ImGui::BeginTable("NoteMap",3,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { + // TODO: frequency map? + if (ImGui::BeginTable("NoteMap",2,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); @@ -3017,8 +3018,8 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); ImGui::TableNextColumn(); ImGui::Text("Sample"); - ImGui::TableNextColumn(); - ImGui::Text("Frequency"); + /*ImGui::TableNextColumn(); + ImGui::Text("Frequency");*/ for (int i=0; i<120; i++) { ImGui::TableNextRow(); ImGui::PushID(fmt::sprintf("NM_%d",i).c_str()); @@ -3046,12 +3047,12 @@ void FurnaceGUI::drawInsEdit() { } ImGui::EndCombo(); } - ImGui::TableNextColumn(); + /*ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::InputInt("##SF",&ins->amiga.noteFreq[i],50,500)) { PARAMETER if (ins->amiga.noteFreq[i]<0) ins->amiga.noteFreq[i]=0; if (ins->amiga.noteFreq[i]>262144) ins->amiga.noteFreq[i]=262144; - } + }*/ ImGui::PopID(); } ImGui::EndTable(); From d47c50edaf4182e3cbee1c2d0516d254f9ea2cdb Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 19 Jun 2022 18:23:44 -0500 Subject: [PATCH 072/101] GUI: fix drag to move --- src/gui/cursor.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/gui/cursor.cpp b/src/gui/cursor.cpp index 4b75a26ad..ee681c77a 100644 --- a/src/gui/cursor.cpp +++ b/src/gui/cursor.cpp @@ -91,6 +91,19 @@ void FurnaceGUI::updateSelection(int xCoarse, int xFine, int y, bool fullRow) { cursorDrag.xFine=xFine; cursorDrag.y=y; + int len=dragEnd.xCoarse-dragStart.xCoarse+1; + if (len<0) len=0; + + DETERMINE_FIRST_LAST; + + if (dragStart.xCoarse+(dragDestinationX-dragSourceX)lastChannel) { + + } + selStart.xCoarse=dragStart.xCoarse+(dragDestinationX-dragSourceX); selStart.xFine=dragStart.xFine; selStart.y=dragStart.y+(dragDestinationY-dragSourceY); From 35bc757adfe693c0d8c356fe675bce91203905cc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 19 Jun 2022 18:51:51 -0500 Subject: [PATCH 073/101] GUI: fix macOS system file picker crash --- extern/nfd-modified/src/nfd_cocoa.mm | 5 +++++ src/gui/fileDialog.cpp | 8 ++++++++ src/gui/fileDialog.h | 5 +++++ src/gui/gui.cpp | 2 ++ 4 files changed, 20 insertions(+) diff --git a/extern/nfd-modified/src/nfd_cocoa.mm b/extern/nfd-modified/src/nfd_cocoa.mm index ac5fa36c4..8eac6f795 100644 --- a/extern/nfd-modified/src/nfd_cocoa.mm +++ b/extern/nfd-modified/src/nfd_cocoa.mm @@ -18,6 +18,8 @@ static NSArray *BuildAllowedFileTypes( const char *filterList ) { // Commas and semicolons are the same thing on this platform + // like what about THIS INSTEAD! + // NSMutableArray *buildFilterList = NSMutableArray::alloc()->init(); NSMutableArray *buildFilterList = [[NSMutableArray alloc] init]; char typebuf[NFD_MAX_STRLEN] = {0}; @@ -32,6 +34,9 @@ static NSArray *BuildAllowedFileTypes( const char *filterList ) ++p_typebuf; *p_typebuf = '\0'; + // or this: NSString::stringWithUTF8String(typebuf); + // buildFilterList->addObject(thisType); + // really? did you have to make this mess?! NSString *thisType = [NSString stringWithUTF8String: typebuf]; [buildFilterList addObject:thisType]; p_typebuf = typebuf; diff --git a/src/gui/fileDialog.cpp b/src/gui/fileDialog.cpp index 5be3bdb1a..64f9e989e 100644 --- a/src/gui/fileDialog.cpp +++ b/src/gui/fileDialog.cpp @@ -67,7 +67,11 @@ bool FurnaceGUIFileDialog::openLoad(String header, std::vector filter, c if (sysDialog) { #ifdef USE_NFD dialogOK=false; +#ifdef NFD_NON_THREADED + _nfdThread(NFDState(false,header,filter,path,clickCallback),&dialogOK,&nfdResult); +#else dialogO=new std::thread(_nfdThread,NFDState(false,header,filter,path,clickCallback),&dialogOK,&nfdResult); +#endif #else dialogO=new pfd::open_file(header,path,filter); #endif @@ -87,7 +91,11 @@ bool FurnaceGUIFileDialog::openSave(String header, std::vector filter, c if (sysDialog) { #ifdef USE_NFD dialogOK=false; +#ifdef NFD_NON_THREADED + _nfdThread(NFDState(true,header,filter,path,NULL),&dialogOK,&nfdResult); +#else dialogS=new std::thread(_nfdThread,NFDState(true,header,filter,path,NULL),&dialogOK,&nfdResult); +#endif #else dialogS=new pfd::save_file(header,path,filter); #endif diff --git a/src/gui/fileDialog.h b/src/gui/fileDialog.h index 6131f56b2..6724eb951 100644 --- a/src/gui/fileDialog.h +++ b/src/gui/fileDialog.h @@ -10,6 +10,11 @@ #ifdef USE_NFD #include #include + +#ifdef __APPLE__ +#define NFD_NON_THREADED +#endif + #else namespace pfd { class open_file; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 5717f3910..dc45acf49 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3138,6 +3138,7 @@ bool FurnaceGUI::loop() { #endif } +#ifndef NFD_NON_THREADED if (fileDialog->isOpen() && settings.sysFileDialog) { ImGui::OpenPopup("System File Dialog Pending"); } @@ -3150,6 +3151,7 @@ bool FurnaceGUI::loop() { dl->AddRectFilled(ImVec2(0.0f,0.0f),ImVec2(scrW*dpiScale,scrH*dpiScale),ImGui::ColorConvertFloat4ToU32(uiColors[GUI_COLOR_MODAL_BACKDROP])); ImGui::EndPopup(); } +#endif if (fileDialog->render(ImVec2(600.0f*dpiScale,400.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale))) { bool openOpen=false; From d66ff353bae0109162b0fe5af0ec50c1cf855d95 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 19 Jun 2022 19:07:38 -0500 Subject: [PATCH 074/101] GUI: more fixes to drag to move --- src/gui/cursor.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/gui/cursor.cpp b/src/gui/cursor.cpp index ee681c77a..19526268d 100644 --- a/src/gui/cursor.cpp +++ b/src/gui/cursor.cpp @@ -100,8 +100,16 @@ void FurnaceGUI::updateSelection(int xCoarse, int xFine, int y, bool fullRow) { dragDestinationX=dragSourceX-dragStart.xCoarse; } - if (dragEnd.xCoarse+(dragDestinationX-dragSourceX)>lastChannel) { - + if (dragEnd.xCoarse+(dragDestinationX-dragSourceX)>=lastChannel) { + dragDestinationX=lastChannel-(dragEnd.xCoarse-dragSourceX)-1; + } + + if (dragStart.y+(dragDestinationY-dragSourceY)<0) { + dragDestinationY=dragSourceY-dragStart.y; + } + + if (dragEnd.y+(dragDestinationY-dragSourceY)>=e->curSubSong->patLen) { + dragDestinationY=e->curSubSong->patLen-(dragEnd.y-dragSourceY)-1; } selStart.xCoarse=dragStart.xCoarse+(dragDestinationX-dragSourceX); From 337e2183cd38794d300d91e27b1fd09ac4927448 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 20 Jun 2022 04:55:28 -0500 Subject: [PATCH 075/101] fix build on GCC < 8 --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c7c076a27..3d064ac07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -584,7 +584,11 @@ endif() if (NOT MSVC) set(WARNING_FLAGS -Wall -Wextra -Wno-unused-parameter) if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - list(APPEND WARNING_FLAGS -Wno-cast-function-type) + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0.0) + # nothing + else() + list(APPEND WARNING_FLAGS -Wno-cast-function-type) + endif() endif() if (WARNINGS_ARE_ERRORS) list(APPEND WARNING_FLAGS -Werror) From 6772159d5f4ffed3f013cc2b89e5a445dec15258 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 20 Jun 2022 04:58:03 -0500 Subject: [PATCH 076/101] one more GCC < 8 fix --- src/engine/platform/sound/ymfm/ymfm_opn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/sound/ymfm/ymfm_opn.h b/src/engine/platform/sound/ymfm/ymfm_opn.h index 34dc065d7..00fd61adf 100644 --- a/src/engine/platform/sound/ymfm/ymfm_opn.h +++ b/src/engine/platform/sound/ymfm/ymfm_opn.h @@ -784,7 +784,7 @@ public: protected: // simulate the DAC discontinuity - constexpr int32_t dac_discontinuity(int32_t value) const { return (value < 0) ? (value - 2) : (value + 3); } + int32_t dac_discontinuity(int32_t value) const { return (value < 0) ? (value - 2) : (value + 3); } // internal state uint16_t m_address; // address register From 60334fb03cfbe47bfe2e278daaa89200a7b5fcf6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 20 Jun 2022 15:20:02 -0500 Subject: [PATCH 077/101] GUI: add spoiler window --- CMakeLists.txt | 1 + src/gui/debugWindow.cpp | 3 +++ src/gui/findReplace.cpp | 19 +++++++++++++++++++ src/gui/gui.cpp | 4 ++++ src/gui/gui.h | 6 ++++-- src/gui/spoiler.cpp | 37 +++++++++++++++++++++++++++++++++++++ 6 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 src/gui/spoiler.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d064ac07..74d622bea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -510,6 +510,7 @@ src/gui/sampleEdit.cpp src/gui/settings.cpp src/gui/songInfo.cpp src/gui/songNotes.cpp +src/gui/spoiler.cpp src/gui/stats.cpp src/gui/subSongs.cpp src/gui/sysConf.cpp diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 7d6d057f1..22527a7b8 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -369,6 +369,9 @@ void FurnaceGUI::drawDebug() { if (ImGui::Button("Inspect")) { inspectorOpen=!inspectorOpen; } + if (ImGui::Button("Spoiler")) { + spoilerOpen=!spoilerOpen; + } ImGui::TreePop(); } if (ImGui::TreeNode("Performance")) { diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index f16ccd7ae..78abce7cb 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -1,3 +1,22 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2022 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + #include "gui.h" #include "imgui.h" #include "IconsFontAwesome4.h" diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index dc45acf49..9b37f987c 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3006,6 +3006,7 @@ bool FurnaceGUI::loop() { if (ImGui::MenuItem("register view",BIND_FOR(GUI_ACTION_WINDOW_REGISTER_VIEW),regViewOpen)) regViewOpen=!regViewOpen; if (ImGui::MenuItem("log viewer",BIND_FOR(GUI_ACTION_WINDOW_LOG),logOpen)) logOpen=!logOpen; if (ImGui::MenuItem("statistics",BIND_FOR(GUI_ACTION_WINDOW_STATS),statsOpen)) statsOpen=!statsOpen; + if (spoilerOpen) if (ImGui::MenuItem("spoiler",NULL,spoilerOpen)) spoilerOpen=!spoilerOpen; ImGui::EndMenu(); } @@ -4035,6 +4036,7 @@ bool FurnaceGUI::init() { effectListOpen=e->getConfBool("effectListOpen",false); subSongsOpen=e->getConfBool("subSongsOpen",true); findOpen=e->getConfBool("findOpen",false); + spoilerOpen=e->getConfBool("spoilerOpen",false); tempoView=e->getConfBool("tempoView",true); waveHex=e->getConfBool("waveHex",false); @@ -4258,6 +4260,7 @@ bool FurnaceGUI::finish() { e->setConf("effectListOpen",effectListOpen); e->setConf("subSongsOpen",subSongsOpen); e->setConf("findOpen",findOpen); + e->setConf("spoilerOpen",spoilerOpen); // commit last window size e->setConf("lastWindowWidth",scrW); @@ -4407,6 +4410,7 @@ FurnaceGUI::FurnaceGUI(): chanOscOpen(false), subSongsOpen(true), findOpen(false), + spoilerOpen(false), selecting(false), selectingFull(false), dragging(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index ac15d5a8a..271b8eaa4 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -246,7 +246,8 @@ enum FurnaceGUIWindows { GUI_WINDOW_EFFECT_LIST, GUI_WINDOW_CHAN_OSC, GUI_WINDOW_SUBSONGS, - GUI_WINDOW_FIND + GUI_WINDOW_FIND, + GUI_WINDOW_SPOILER }; enum FurnaceGUIFileDialogs { @@ -1149,7 +1150,7 @@ class FurnaceGUI { bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen; bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen; bool pianoOpen, notesOpen, channelsOpen, regViewOpen, logOpen, effectListOpen, chanOscOpen; - bool subSongsOpen, findOpen; + bool subSongsOpen, findOpen, spoilerOpen; SelectionPoint selStart, selEnd, cursor, cursorDrag, dragStart, dragEnd; bool selecting, selectingFull, dragging, curNibble, orderNibble, followOrders, followPattern, changeAllOrders, mobileUI; @@ -1445,6 +1446,7 @@ class FurnaceGUI { void drawEffectList(); void drawSubSongs(); void drawFindReplace(); + void drawSpoiler(); void parseKeybinds(); void promptKey(int which); diff --git a/src/gui/spoiler.cpp b/src/gui/spoiler.cpp new file mode 100644 index 000000000..dc64b14ce --- /dev/null +++ b/src/gui/spoiler.cpp @@ -0,0 +1,37 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2022 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "gui.h" +#include "imgui.h" + +void FurnaceGUI::drawSpoiler() { + if (nextWindow==GUI_WINDOW_SPOILER) { + spoilerOpen=true; + ImGui::SetNextWindowFocus(); + nextWindow=GUI_WINDOW_NOTHING; + } + if (!spoilerOpen) return; + if (ImGui::Begin("Spoiler",&spoilerOpen,globalWinFlags|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::PushFont(bigFont); + ImGui::Text("SPOILER"); + ImGui::PopFont(); + } + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SPOILER; + ImGui::End(); +} From 57fab1626966c8de64ab6d29f1f7e5ee1593297b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 20 Jun 2022 16:24:14 -0500 Subject: [PATCH 078/101] GUI: add ability to drag to move when holding Ctrl --- src/gui/cursor.cpp | 2 +- src/gui/settings.cpp | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/gui/cursor.cpp b/src/gui/cursor.cpp index 19526268d..5a98a78c6 100644 --- a/src/gui/cursor.cpp +++ b/src/gui/cursor.cpp @@ -43,7 +43,7 @@ void FurnaceGUI::startSelection(int xCoarse, int xFine, int y, bool fullRow) { } } - if (settings.dragMovesSelection && !fullRow) { + if ((settings.dragMovesSelection==1 || (settings.dragMovesSelection==2 && (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)))) && !fullRow) { if (xCoarse>=selStart.xCoarse && (xFine>=selStart.xFine || xCoarse>selStart.xCoarse) && y>=selStart.y && xCoarse<=selEnd.xCoarse && (xFine<=selEnd.xFine || xCoarsegetConfInt("effectValCellSpacing",0); settings.doubleClickColumn=e->getConfInt("doubleClickColumn",1); settings.blankIns=e->getConfInt("blankIns",0); - settings.dragMovesSelection=e->getConfInt("dragMovesSelection",1); + settings.dragMovesSelection=e->getConfInt("dragMovesSelection",2); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -2127,7 +2133,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.effectValCellSpacing,0,32); clampSetting(settings.doubleClickColumn,0,1); clampSetting(settings.blankIns,0,1); - clampSetting(settings.dragMovesSelection,0,1); + clampSetting(settings.dragMovesSelection,0,2); settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys","")); if (settings.initialSys.size()<4) { From 41135f4a954646f7dfa3e18ac39b0f6443f11bb0 Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 21 Jun 2022 06:35:11 +0900 Subject: [PATCH 079/101] Add extended channel 3 preset for here --- src/gui/presets.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 463352272..5fa4d75e1 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1910,6 +1910,13 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Seta 1 + FM addon (extended channel 3)", { + DIV_SYSTEM_X1_010, 64, 0, 0, + DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // Discrete YM3438 + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "Seta 2", { DIV_SYSTEM_X1_010, 64, 0, 1, From df21621ce7b5b74054e6c4a8bb349e257f7990f5 Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 21 Jun 2022 06:36:41 +0900 Subject: [PATCH 080/101] Add drums mode in here, too --- src/gui/presets.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 5fa4d75e1..d85865f7c 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1972,6 +1972,14 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Dynax/Nakanihon 3rd generation hardware (drums mode)", { + DIV_SYSTEM_AY8910, 64, 0, 0, // AY or YM, optional - 1.79MHz or 3.58MHz; various per game + DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, + DIV_SYSTEM_MSM6295, 64, 0, 6, // 1.023MHz mostly + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "Dynax/Nakanihon Real Break", { DIV_SYSTEM_OPLL, 64, 0, 0, @@ -1979,6 +1987,13 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Dynax/Nakanihon Real Break (drums mode)", { + DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, + DIV_SYSTEM_YMZ280B, 64, 0, 0, + 0 + } + )); sysCategories.push_back(cat); cat=FurnaceGUISysCategory("DefleMask-compatible","these configurations are compatible with DefleMask.\nselect this if you need to save as .dmf or work with that program."); From b3201853bc5256605d6f1e932df4f36cddd96dcf Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 21 Jun 2022 06:54:18 +0900 Subject: [PATCH 081/101] Fix YM2151 clock in CPS-1 --- src/gui/presets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index d85865f7c..67acca82a 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1405,7 +1405,7 @@ void FurnaceGUI::initSystemPresets() { )); cat.systems.push_back(FurnaceGUISysDef( "Capcom CPS-1", { - DIV_SYSTEM_YM2151, 64, 0, 2, + DIV_SYSTEM_YM2151, 64, 0, 0, // 3.58MHz DIV_SYSTEM_MSM6295, 64, 0, 0, 0 } From ee709b85c2bbdc7b7e3aedb41c19426852df565b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 20 Jun 2022 18:20:49 -0500 Subject: [PATCH 082/101] Namco WSG: per-channel oscilloscope --- src/engine/platform/namcowsg.cpp | 13 +++++++++---- src/engine/platform/sound/namco.cpp | 9 +++++---- src/engine/platform/sound/namco.h | 3 ++- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/engine/platform/namcowsg.cpp b/src/engine/platform/namcowsg.cpp index 1e8ff46d1..43136d91a 100644 --- a/src/engine/platform/namcowsg.cpp +++ b/src/engine/platform/namcowsg.cpp @@ -164,9 +164,6 @@ const char* DivPlatformNamcoWSG::getEffectName(unsigned char effect) { } void DivPlatformNamcoWSG::acquire(short* bufL, short* bufR, size_t start, size_t len) { - short* buf[2]={ - bufL+start, bufR+start - }; while (!writes.empty()) { QueuedWrite w=writes.front(); switch (devType) { @@ -186,7 +183,15 @@ void DivPlatformNamcoWSG::acquire(short* bufL, short* bufR, size_t start, size_t regPool[w.addr&0x3f]=w.val; writes.pop(); } - namco->sound_stream_update(buf,len); + for (size_t h=start; hsound_stream_update(buf,1); + for (int i=0; idata[oscBuf[i]->needle++]=namco->m_channel_list[i].last_out*chans; + } + } } void DivPlatformNamcoWSG::updateWave(int ch) { diff --git a/src/engine/platform/sound/namco.cpp b/src/engine/platform/sound/namco.cpp index 82141301f..811c34ab8 100644 --- a/src/engine/platform/sound/namco.cpp +++ b/src/engine/platform/sound/namco.cpp @@ -172,10 +172,11 @@ void namco_audio_device::build_decoded_waveform(uint8_t *rgnbase) /* generate sound by oversampling */ -uint32_t namco_audio_device::namco_update_one(short* buffer, int size, const int16_t *wave, uint32_t counter, uint32_t freq) +uint32_t namco_audio_device::namco_update_one(short* buffer, int size, const int16_t *wave, uint32_t counter, uint32_t freq, int16_t& last_out) { for (int sampindex = 0; sampindex < size; sampindex++) { + last_out=wave[WAVEFORM_POSITION(counter)]; buffer[sampindex]+=wave[WAVEFORM_POSITION(counter)]; counter += freq; } @@ -700,7 +701,7 @@ void namco_audio_device::sound_stream_update(short** outputs, int len) const int16_t *lw = &m_waveform[lv][voice->waveform_select * 32]; /* generate sound into the buffer */ - c = namco_update_one(lmix, len, lw, voice->counter, voice->frequency); + c = namco_update_one(lmix, len, lw, voice->counter, voice->frequency, voice->last_out); } /* only update if we have non-zero right volume */ @@ -709,7 +710,7 @@ void namco_audio_device::sound_stream_update(short** outputs, int len) const int16_t *rw = &m_waveform[rv][voice->waveform_select * 32]; /* generate sound into the buffer */ - c = namco_update_one(rmix, len, rw, voice->counter, voice->frequency); + c = namco_update_one(rmix, len, rw, voice->counter, voice->frequency, voice->last_out); } /* update the counter for this voice */ @@ -789,7 +790,7 @@ void namco_audio_device::sound_stream_update(short** outputs, int len) const int16_t *w = &m_waveform[v][voice->waveform_select * 32]; /* generate sound into buffer and update the counter for this voice */ - voice->counter = namco_update_one(buffer, len, w, voice->counter, voice->frequency); + voice->counter = namco_update_one(buffer, len, w, voice->counter, voice->frequency, voice->last_out); } } } diff --git a/src/engine/platform/sound/namco.h b/src/engine/platform/sound/namco.h index 507eaed29..d3844abc1 100644 --- a/src/engine/platform/sound/namco.h +++ b/src/engine/platform/sound/namco.h @@ -31,6 +31,7 @@ public: uint32_t noise_counter; int32_t noise_hold; int32_t waveform_select; + int16_t last_out; }; namco_audio_device(uint32_t clock); @@ -43,7 +44,7 @@ public: void build_decoded_waveform( uint8_t *rgnbase ); void update_namco_waveform(int offset, uint8_t data); - uint32_t namco_update_one(short* buffer, int size, const int16_t *wave, uint32_t counter, uint32_t freq); + uint32_t namco_update_one(short* buffer, int size, const int16_t *wave, uint32_t counter, uint32_t freq, int16_t& last_out); /* waveform region */ uint8_t* m_wave_ptr; From b697694c0d37decee804dd7727213d6fec10b1ed Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 20 Jun 2022 18:41:23 -0500 Subject: [PATCH 083/101] GUI: per-channel osc DC offset centering --- src/gui/chanOsc.cpp | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index 5bd945f16..964af6f10 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -135,6 +135,9 @@ void FurnaceGUI::drawChanOsc() { waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f)); } } else { + float minLevel=1.0f; + float maxLevel=-1.0f; + float dcOff=0.0f; unsigned short needlePos=buf->needle; if (chanOscWaveCorr) { /* @@ -195,20 +198,32 @@ void FurnaceGUI::drawChanOsc() { needlePos-=displaySize; for (unsigned short i=0; i<512; i++) { - float x=(float)i/512.0f; float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; - if (y<-0.5f) y=-0.5f; - if (y>0.5f) y=0.5f; - waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-y)); + if (minLevel>y) minLevel=y; + if (maxLeveldata[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; if (y<-0.5f) y=-0.5f; if (y>0.5f) y=0.5f; - waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-y)); + waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-(y-dcOff))); + } + } else { + needlePos-=displaySize; + for (unsigned short i=0; i<512; i++) { + float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; + if (minLevel>y) minLevel=y; + if (maxLeveldata[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; + if (y<-0.5f) y=-0.5f; + if (y>0.5f) y=0.5f; + waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-(y-dcOff))); } } } From fd61e0e9f8ccafc55b0d0e25e34101cac6343cd2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 20 Jun 2022 18:48:10 -0500 Subject: [PATCH 084/101] ZX beeper: per-"channel" osc there's only one --- src/engine/platform/zxbeeper.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/zxbeeper.cpp b/src/engine/platform/zxbeeper.cpp index 34265f8a0..524d3c117 100644 --- a/src/engine/platform/zxbeeper.cpp +++ b/src/engine/platform/zxbeeper.cpp @@ -59,6 +59,7 @@ void DivPlatformZXBeeper::acquire(short* bufL, short* bufR, size_t start, size_t } o=sampleOut; bufL[h]=o?16384:0; + oscBuf[0]->data[oscBuf[0]->needle++]=o?16384:-16384; continue; } @@ -76,6 +77,7 @@ void DivPlatformZXBeeper::acquire(short* bufL, short* bufR, size_t start, size_t if (++curChan>=6) curChan=0; bufL[h]=o?16384:0; + oscBuf[0]->data[oscBuf[0]->needle++]=o?16384:-16384; } } @@ -256,7 +258,7 @@ DivMacroInt* DivPlatformZXBeeper::getChanMacroInt(int ch) { } DivDispatchOscBuffer* DivPlatformZXBeeper::getOscBuffer(int ch) { - return oscBuf[ch]; + return (ch<1)?oscBuf[ch]:NULL; } unsigned char* DivPlatformZXBeeper::getRegisterPool() { From 5a1a583ab02c5540754667212faded79e6d7e192 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 20 Jun 2022 18:53:39 -0500 Subject: [PATCH 085/101] AY: finally fix unmuting --- src/engine/platform/ay.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 52ac6e57a..073776105 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -489,9 +489,9 @@ void DivPlatformAY8910::muteChannel(int ch, bool mute) { isMuted[ch]=mute; if (isMuted[ch]) { rWrite(0x08+ch,0); - } else if (intellivision && (chan[ch].psgMode&4)) { + } else if (intellivision && (chan[ch].psgMode&4) && chan[ch].active) { rWrite(0x08+ch,(chan[ch].vol&0xc)<<2); - } else { + } else if (chan[ch].active) { rWrite(0x08+ch,(chan[ch].outVol&15)|((chan[ch].psgMode&4)<<2)); } } From 4ca64cc66c46bc78652b778146e0e7ef1e15811f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 20 Jun 2022 18:56:20 -0500 Subject: [PATCH 086/101] GUI: hide hidden channels in per-chan osc --- src/gui/chanOsc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index 964af6f10..0626c3552 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -81,7 +81,7 @@ void FurnaceGUI::drawChanOsc() { for (int i=0; igetOscBuffer(i); - if (buf!=NULL) { + if (buf!=NULL && e->curSubSong->chanShow[i]) { oscBufs.push_back(buf); oscFFTs.push_back(&chanOscChan[i]); oscChans.push_back(i); From 69ea1d02276aa64b0dd753c3106c2361a96560bd Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 21 Jun 2022 11:06:26 +0900 Subject: [PATCH 087/101] Fix AY8930 unmuting --- src/engine/platform/ay8930.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index a92f185ca..0fad4025b 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -521,7 +521,7 @@ void DivPlatformAY8930::muteChannel(int ch, bool mute) { isMuted[ch]=mute; if (isMuted[ch]) { rWrite(0x08+ch,0); - } else { + } else if (chan[ch].active) { rWrite(0x08+ch,(chan[ch].outVol&31)|((chan[ch].psgMode&4)<<3)); } } From af4a3598016f44214b10d40967478298552aaa4e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 20 Jun 2022 21:11:03 -0500 Subject: [PATCH 088/101] GUI: make spoiler actually visible --- src/gui/gui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 9b37f987c..bb33073a3 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3100,6 +3100,7 @@ bool FurnaceGUI::loop() { drawSubSongs(); drawFindReplace(); + drawSpoiler(); drawPattern(); drawEditControls(); drawSongInfo(); From e3686c2e3437589f7e4b0a26b2d525a9f1f16bf0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 20 Jun 2022 22:14:16 -0500 Subject: [PATCH 089/101] fix song playing from begin if stopped on last row --- src/engine/engine.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 8ce31a604..e8a766b38 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1431,7 +1431,10 @@ void DivEngine::stop() { freelance=false; playing=false; extValuePresent=false; + endOfSong=false; // what? stepPlay=0; + curOrder=prevOrder; + curRow=prevRow; remainingLoops=-1; sPreview.sample=-1; sPreview.wave=-1; From 6372f279fa1f1c5816c8460d966ed22ec96d9461 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 20 Jun 2022 22:35:34 -0500 Subject: [PATCH 090/101] update to-do list --- TODO.md | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO.md b/TODO.md index cca5ffdb9..da090151d 100644 --- a/TODO.md +++ b/TODO.md @@ -10,3 +10,4 @@ - Game Boy envelope macro/sequence - volume commands should work on Game Boy - ability to customize `OFF`, `===` and `REL` +- stereo separation control for AY From e0bccc8c14137cbc4d2d1567a9000b3dd906dbbd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 21 Jun 2022 18:01:53 -0500 Subject: [PATCH 091/101] GUI: prepare for colors in the per-chan osc --- CMakeLists.txt | 1 + src/gui/chanOsc.cpp | 107 +++++++++++++++++++++++++++++++++---------- src/gui/gradient.cpp | 70 ++++++++++++++++++++++++++++ src/gui/gui.cpp | 6 +++ src/gui/gui.h | 44 +++++++++++++++++- 5 files changed, 204 insertions(+), 24 deletions(-) create mode 100644 src/gui/gradient.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 74d622bea..82094ce00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -495,6 +495,7 @@ src/gui/editing.cpp src/gui/editControls.cpp src/gui/effectList.cpp src/gui/findReplace.cpp +src/gui/gradient.cpp src/gui/insEdit.cpp src/gui/log.cpp src/gui/mixer.cpp diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index 0626c3552..d9d3ddd49 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -34,36 +34,93 @@ void FurnaceGUI::drawChanOsc() { } if (!chanOscOpen) return; ImGui::SetNextWindowSizeConstraints(ImVec2(64.0f*dpiScale,32.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); - if (ImGui::Begin("Oscilloscope (per-channel)",&chanOscOpen,globalWinFlags)) { + if (ImGui::Begin("Oscilloscope (per-channel)",&chanOscOpen,globalWinFlags|((chanOscOptions)?0:ImGuiWindowFlags_NoTitleBar))) { bool centerSettingReset=false; - if (ImGui::BeginTable("ChanOscSettings",3)) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Columns"); - ImGui::SameLine(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##COSColumns",&chanOscCols,1,1)) { - if (chanOscCols<1) chanOscCols=1; - if (chanOscCols>64) chanOscCols=64; + if (chanOscOptions) { + if (ImGui::BeginTable("ChanOscSettings",3)) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Columns"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##COSColumns",&chanOscCols,1,1)) { + if (chanOscCols<1) chanOscCols=1; + if (chanOscCols>64) chanOscCols=64; + } + + ImGui::TableNextColumn(); + ImGui::Text("Size (ms)"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputFloat("##COSWinSize",&chanOscWindowSize,1.0f,1.0f)) { + if (chanOscWindowSize<1.0f) chanOscWindowSize=1.0f; + if (chanOscWindowSize>50.0f) chanOscWindowSize=50.0f; + } + + ImGui::TableNextColumn(); + if (ImGui::Checkbox("Center waveform",&chanOscWaveCorr)) { + centerSettingReset=true; + } + + ImGui::EndTable(); } - ImGui::TableNextColumn(); - ImGui::Text("Size (ms)"); - ImGui::SameLine(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputFloat("##COSWinSize",&chanOscWindowSize,1.0f,1.0f)) { - if (chanOscWindowSize<1.0f) chanOscWindowSize=1.0f; - if (chanOscWindowSize>50.0f) chanOscWindowSize=50.0f; + ImGui::Text("Gradient"); + + if (chanOscGradTex==NULL) { + chanOscGradTex=SDL_CreateTexture(sdlRend,SDL_PIXELFORMAT_ABGR8888,SDL_TEXTUREACCESS_STREAMING,chanOscGrad.width,chanOscGrad.height); + + if (chanOscGradTex==NULL) { + logE("error while creating gradient texture! %s",SDL_GetError()); + } else { + updateChanOscGradTex=true; + } } - ImGui::TableNextColumn(); - if (ImGui::Checkbox("Center waveform",&chanOscWaveCorr)) { - centerSettingReset=true; - } + if (ImGui::BeginTable("ChanOscGradSet",2)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); - ImGui::EndTable(); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (chanOscGradTex!=NULL) { + if (updateChanOscGradTex) { + chanOscGrad.render(); + if (SDL_UpdateTexture(chanOscGradTex,NULL,chanOscGrad.grad.get(),chanOscGrad.width*4)==0) { + updateChanOscGradTex=false; + } else { + logE("error while updating gradient texture! %s",SDL_GetError()); + } + } + + ImGui::ImageButton(chanOscGradTex,ImVec2(400.0f*dpiScale,400.0f*dpiScale)); + ImVec2 gradLeft=ImGui::GetItemRectMin(); + ImVec2 gradSize=ImGui::GetItemRectSize(); + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + chanOscGrad.points.push_back(Gradient2DPoint( + (ImGui::GetMousePos().x-gradLeft.x)/gradSize.x, + (ImGui::GetMousePos().y-gradLeft.y)/gradSize.y + )); + updateChanOscGradTex=true; + logI("a point inserted"); + } + + ImVec2 oldCurPos=ImGui::GetCursorPos(); + for (Gradient2DPoint& i: chanOscGrad.points) { + ImGui::SetCursorPos(ImVec2(gradLeft.x+i.x*gradSize.x,gradLeft.y+i.y*gradSize.y)); + ImGui::Text("Here"); + } + ImGui::SetCursorPos(oldCurPos); + } + + ImGui::TableNextColumn(); + if (ImGui::ColorEdit4("Background",(float*)&chanOscGrad.bgColor)) { + updateChanOscGradTex=true; + } + + ImGui::EndTable(); + } } - ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(0.0f,0.0f)); float availY=ImGui::GetContentRegionAvail().y; @@ -232,6 +289,10 @@ void FurnaceGUI::drawChanOsc() { } } ImGui::EndTable(); + + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + chanOscOptions=!chanOscOptions; + } } ImGui::PopStyleVar(); } diff --git a/src/gui/gradient.cpp b/src/gui/gradient.cpp new file mode 100644 index 000000000..c9b26fb80 --- /dev/null +++ b/src/gui/gradient.cpp @@ -0,0 +1,70 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2022 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "gui.h" +#include "imgui.h" +#include + +void Gradient2D::render() { + ImU32* g=grad.get(); + ImU32 bgColorU=ImGui::ColorConvertFloat4ToU32(bgColor); + + // 1. fill with background color + for (size_t i=0; i=pDistSquared) continue; + + float dist=(1.0-(sqrt(distSquared)/i.distance))-i.spread; + if (dist<0) dist=0; + if (dist>1) dist=1; + + ImU32 shadeColor=ImGui::ColorConvertFloat4ToU32( + ImVec4( + i.color.x*i.color.w*dist, + i.color.y*i.color.w*dist, + i.color.z*i.color.w*dist, + 1.0f + ) + ); + + ImU32 origColor=g[j*width+k]; + g[j*width+k]=( + (MIN( 0xff, (origColor&0xff) + (shadeColor&0xff) )) | // R + (MIN( 0xff00, (origColor&0xff00) + (shadeColor&0xff00) )) | // G + (MIN(0xff0000,(origColor&0xff0000)+(shadeColor&0xff0000))) | // B + (origColor&0xff000000) // A + ); + } + } + } +} \ No newline at end of file diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index bb33073a3..fbfc2b4d9 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4575,6 +4575,10 @@ FurnaceGUI::FurnaceGUI(): chanOscCols(3), chanOscWindowSize(20.0f), chanOscWaveCorr(true), + chanOscOptions(false), + updateChanOscGradTex(true), + chanOscGrad(64,64), + chanOscGradTex(NULL), followLog(true), #ifdef IS_MOBILE pianoOctaves(7), @@ -4664,4 +4668,6 @@ FurnaceGUI::FurnaceGUI(): memset(queryReplaceEffectVal,0,sizeof(int)*8); memset(queryReplaceEffectDo,0,sizeof(bool)*8); memset(queryReplaceEffectValDo,0,sizeof(bool)*8); + + chanOscGrad.bgColor=ImVec4(0.0f,0.0f,0.0f,1.0f); } diff --git a/src/gui/gui.h b/src/gui/gui.h index 271b8eaa4..a538c5ba5 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -757,6 +758,45 @@ struct TouchPoint { z(pressure) {} }; +struct Gradient2DPoint { + ImVec4 color; + float x, y; + float spread, distance; + bool selected, grab; + Gradient2DPoint(float xPos, float yPos): + color(1,1,1,1), + x(xPos), + y(yPos), + spread(0.0f), + distance(0.5f), + selected(false), + grab(false) {} + Gradient2DPoint(): + color(1,1,1,1), + x(0.0f), + y(0.0f), + spread(0.0f), + distance(0.5f), + selected(false), + grab(false) {} +}; + +struct Gradient2D { + ImVec4 bgColor; + std::vector points; + std::unique_ptr grad; + size_t width, height; + + void render(); + ImU32 get(float x, float y); + Gradient2D(size_t w, size_t h): + bgColor(0.0f,0.0f,0.0f,0.0f), + width(w), + height(h) { + grad=std::make_unique(width*height); + } +}; + struct FurnaceGUISysDef { const char* name; std::vector definition; @@ -1344,7 +1384,9 @@ class FurnaceGUI { // per-channel oscilloscope int chanOscCols; float chanOscWindowSize; - bool chanOscWaveCorr; + bool chanOscWaveCorr, chanOscOptions, updateChanOscGradTex; + Gradient2D chanOscGrad; + SDL_Texture* chanOscGradTex; float chanOscLP0[DIV_MAX_CHANS]; float chanOscLP1[DIV_MAX_CHANS]; unsigned short lastNeedlePos[DIV_MAX_CHANS]; From 22dd22ca3303a4f8369436b1a7fabb920663c785 Mon Sep 17 00:00:00 2001 From: Natt Akuma Date: Wed, 22 Jun 2022 19:38:29 +0700 Subject: [PATCH 092/101] Allow accessing all 256 waves in macros --- src/gui/insEdit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index df62a87e3..275a34f92 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3483,7 +3483,7 @@ void FurnaceGUI::drawInsEdit() { } const char* waveLabel="Waveform"; - int waveMax=(ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_VERA)?3:63; + int waveMax=(ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_VERA)?3:255; bool bitMode=false; if (ins->type==DIV_INS_C64 || ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_SAA1099) { bitMode=true; @@ -3520,7 +3520,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_X1_010) { dutyMax=0; ex1Max=7; - ex2Max=63; + ex2Max=255; ex2Bit=false; } if (ins->type==DIV_INS_N163) { From 4bf4be1ea26c3da3cc914e29f667a99fc35bdadd Mon Sep 17 00:00:00 2001 From: Natt Akuma Date: Wed, 22 Jun 2022 21:55:31 +0700 Subject: [PATCH 093/101] Fix 16-bit samples in YMZ280B VGM export --- src/engine/sample.h | 1 + src/engine/vgmOps.cpp | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/engine/sample.h b/src/engine/sample.h index d9ad633c9..70f8418cf 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -248,6 +248,7 @@ struct DivSample { offQSound(0), offX1_010(0), offSU(0), + offYMZ280B(0), offRF5C68(0), samples(0) {} ~DivSample(); diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index 6e2bc82cf..0d1ad4f52 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -1653,13 +1653,34 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { w->write(writeX1010[i]->getSampleMem(),writeX1010[i]->getSampleMemUsage()); } if (writeZ280[i]!=NULL && writeZ280[i]->getSampleMemUsage()>0) { + // In VGM, YMZ280B's 16-bit PCM has an endianness swapped + // which have been fixed in the upstream MAME since 2013 + // in order to get Konami FireBeat working + // The reason given for VGM not applying this change was + // "It matches OPL4 and MAME probably did an endianness optimization" + size_t sampleMemLen=writeZ280[i]->getSampleMemUsage(); + unsigned char* sampleMem=new unsigned char[sampleMemLen]; + memcpy(sampleMem,writeZ280[i]->getSampleMem(),sampleMemLen); + for (int i=0; idepth==16) { + unsigned int pos=s->offYMZ280B; + for (unsigned int j=0; jsamples; j++) { + unsigned char lo=sampleMem[pos+j*2]; + unsigned char hi=sampleMem[pos+j*2+1]; + sampleMem[pos+j*2]=hi; + sampleMem[pos+j*2+1]=lo; + } + } + } w->writeC(0x67); w->writeC(0x66); w->writeC(0x86); w->writeI((writeZ280[i]->getSampleMemUsage()+8)|(i*0x80000000)); w->writeI(writeZ280[i]->getSampleMemCapacity()); w->writeI(0); - w->write(writeZ280[i]->getSampleMem(),writeZ280[i]->getSampleMemUsage()); + w->write(sampleMem,sampleMemLen); + delete[] sampleMem; } } From 8dc143af7b774eedefc4daec0532a02fc0484f64 Mon Sep 17 00:00:00 2001 From: Natt Akuma Date: Thu, 23 Jun 2022 02:42:11 +0700 Subject: [PATCH 094/101] PET: Support full 16-bit period range Fix #500 --- src/engine/platform/pet.cpp | 69 +++++++++++++++++++++++-------------- src/engine/platform/pet.h | 4 ++- 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/engine/platform/pet.cpp b/src/engine/platform/pet.cpp index 0decd909d..9b3c99886 100644 --- a/src/engine/platform/pet.cpp +++ b/src/engine/platform/pet.cpp @@ -21,15 +21,15 @@ #include "../engine.h" #include -#define rWrite(a,v) {regPool[(a)]=(v)&0xff; if((a)==10) {chan.sreg=(v); chan.cnt=2;}} - #define CHIP_DIVIDER 16 #define SAMP_DIVIDER 4 const char* regCheatSheet6522[]={ "T2L", "08", + "T2H", "09", "SR", "0A", "ACR", "0B", + "PCR", "0C", NULL }; @@ -46,26 +46,45 @@ const char* DivPlatformPET::getEffectName(unsigned char effect) { return NULL; } +// high-level emulation of 6522 shift register and driver software for now +void DivPlatformPET::rWrite(unsigned int addr, unsigned char val) { + bool hwSROutput=((regPool[11]>>2)&7)==4; + switch (addr) { + case 9: + // simulate phase reset from switching between hw/sw shift registers + if ((regPool[9]==0)^(val==0)) { + chan.sreg=chan.wave; + } + break; + case 10: + chan.sreg=val; + if (hwSROutput) chan.cnt=2; + break; + } + regPool[addr]=val; +} + void DivPlatformPET::acquire(short* bufL, short* bufR, size_t start, size_t len) { - // high-level emulation of 6522 shift register for now - int t2=regPool[8]*2+4; - if (((regPool[11]>>2)&7)==4) { + bool hwSROutput=((regPool[11]>>2)&7)==4; + if (chan.enable) { + int reload=regPool[8]*2+4; + if (!hwSROutput) { + reload+=regPool[9]*512; + } for (size_t h=start; h0) { - int adv=MIN(cycs,chan.cnt); - chan.cnt-=adv; - cycs-=adv; - if (chan.cnt==0) { - chan.out=(chan.sreg&1)*32767; - chan.sreg=(chan.sreg>>1)|((chan.sreg&1)<<7); - chan.cnt=t2; - } + if (SAMP_DIVIDER>chan.cnt) { + chan.out=(chan.sreg&1)*32767; + chan.sreg=(chan.sreg>>1)|((chan.sreg&1)<<7); + chan.cnt+=reload-SAMP_DIVIDER; + } else { + chan.cnt-=SAMP_DIVIDER; } bufL[h]=chan.out; bufR[h]=chan.out; oscBuf->data[oscBuf->needle++]=chan.out; } + // emulate driver writes to PCR + if (!hwSROutput) regPool[12]=chan.out?0xe0:0xc0; } else { chan.out=0; for (size_t h=start; h0) { - if (regPool[11]!=16) { - rWrite(11,16); - rWrite(10,chan.wave); - } + chan.enable=true; + rWrite(11,regPool[9]==0?16:0); } else { + chan.enable=false; rWrite(11,0); } } @@ -118,21 +136,22 @@ void DivPlatformPET::tick(bool sysTick) { chan.freqChanged=true; } if (chan.freqChanged || chan.keyOn || chan.keyOff) { - chan.freq=parent->calcFreq(chan.baseFreq,chan.pitch,true,0,chan.pitch2,chipClock,CHIP_DIVIDER); - if (chan.freq>257) chan.freq=257; - if (chan.freq<2) chan.freq=2; - rWrite(8,chan.freq-2); + chan.freq=parent->calcFreq(chan.baseFreq,chan.pitch,true,0,chan.pitch2,chipClock,CHIP_DIVIDER)-2; + if (chan.freq>65535) chan.freq=65535; + if (chan.freq<0) chan.freq=0; + rWrite(8,chan.freq&0xff); + rWrite(9,chan.freq>>8); if (chan.keyOn) { if (!chan.std.vol.will) { chan.outVol=chan.vol; - writeOutVol(); } chan.keyOn=false; } if (chan.keyOff) { - rWrite(11,0); chan.keyOff=false; } + // update mode setting and channel enable + writeOutVol(); chan.freqChanged=false; } } diff --git a/src/engine/platform/pet.h b/src/engine/platform/pet.h index a50370453..06c7e736a 100644 --- a/src/engine/platform/pet.h +++ b/src/engine/platform/pet.h @@ -26,7 +26,7 @@ class DivPlatformPET: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2, note, ins; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, enable; int vol, outVol, wave; unsigned char sreg; int cnt; @@ -49,6 +49,7 @@ class DivPlatformPET: public DivDispatch { keyOn(false), keyOff(false), inPorta(false), + enable(false), vol(1), outVol(1), wave(0b00001111), @@ -85,6 +86,7 @@ class DivPlatformPET: public DivDispatch { ~DivPlatformPET(); private: void writeOutVol(); + void rWrite(unsigned int addr, unsigned char val); }; #endif From 4731dad9170250dac50de1725f8057b6549b53fc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 22 Jun 2022 15:10:53 -0500 Subject: [PATCH 095/101] GUI: colors --- src/gui/chanOsc.cpp | 350 +++++++++++++++++++++++++++---------------- src/gui/gradient.cpp | 16 +- src/gui/gui.cpp | 7 + src/gui/gui.h | 29 +++- 4 files changed, 268 insertions(+), 134 deletions(-) diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index d9d3ddd49..57fa99dac 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -26,6 +26,49 @@ #define FURNACE_FFT_RATE 80.0 #define FURNACE_FFT_CUTOFF 0.1 +const char* chanOscRefs[]={ + "None (0%)", + "None (50%)", + "None (100%)", + + "Frequency", + "Volume", + "Channel", + "Brightness", + + "Note Trigger" +}; + +float FurnaceGUI::computeGradPos(int type, int chan) { + switch (type) { + case GUI_OSCREF_NONE: + return 0.0f; + break; + case GUI_OSCREF_CENTER: + return 0.5f; + break; + case GUI_OSCREF_MAX: + return 1.0f; + break; + case GUI_OSCREF_FREQUENCY: + return chanOscPitch[chan]; + break; + case GUI_OSCREF_VOLUME: + return chanOscVol[chan]; + break; + case GUI_OSCREF_CHANNEL: + return (float)chan/(float)(e->getTotalChannelCount()-1); + break; + case GUI_OSCREF_BRIGHT: + return chanOscBright[chan]; + break; + case GUI_OSCREF_NOTE_TRIGGER: + return keyHit[chan]*5.0f; + break; + } + return 0.0f; +} + void FurnaceGUI::drawChanOsc() { if (nextWindow==GUI_WINDOW_CHAN_OSC) { chanOscOpen=true; @@ -36,6 +79,7 @@ void FurnaceGUI::drawChanOsc() { ImGui::SetNextWindowSizeConstraints(ImVec2(64.0f*dpiScale,32.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); if (ImGui::Begin("Oscilloscope (per-channel)",&chanOscOpen,globalWinFlags|((chanOscOptions)?0:ImGuiWindowFlags_NoTitleBar))) { bool centerSettingReset=false; + ImDrawList* dl=ImGui::GetWindowDrawList(); if (chanOscOptions) { if (ImGui::BeginTable("ChanOscSettings",3)) { ImGui::TableNextRow(); @@ -65,60 +109,142 @@ void FurnaceGUI::drawChanOsc() { ImGui::EndTable(); } - ImGui::Text("Gradient"); - - if (chanOscGradTex==NULL) { - chanOscGradTex=SDL_CreateTexture(sdlRend,SDL_PIXELFORMAT_ABGR8888,SDL_TEXTUREACCESS_STREAMING,chanOscGrad.width,chanOscGrad.height); + ImGui::Checkbox("Gradient",&chanOscUseGrad); + if (chanOscUseGrad) { if (chanOscGradTex==NULL) { - logE("error while creating gradient texture! %s",SDL_GetError()); - } else { - updateChanOscGradTex=true; + chanOscGradTex=SDL_CreateTexture(sdlRend,SDL_PIXELFORMAT_ABGR8888,SDL_TEXTUREACCESS_STREAMING,chanOscGrad.width,chanOscGrad.height); + + if (chanOscGradTex==NULL) { + logE("error while creating gradient texture! %s",SDL_GetError()); + } else { + updateChanOscGradTex=true; + } } - } - if (ImGui::BeginTable("ChanOscGradSet",2)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); + if (ImGui::BeginTable("ChanOscGradSet",2)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - if (chanOscGradTex!=NULL) { - if (updateChanOscGradTex) { - chanOscGrad.render(); - if (SDL_UpdateTexture(chanOscGradTex,NULL,chanOscGrad.grad.get(),chanOscGrad.width*4)==0) { - updateChanOscGradTex=false; - } else { - logE("error while updating gradient texture! %s",SDL_GetError()); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (chanOscGradTex!=NULL) { + if (updateChanOscGradTex) { + chanOscGrad.render(); + if (SDL_UpdateTexture(chanOscGradTex,NULL,chanOscGrad.grad.get(),chanOscGrad.width*4)==0) { + updateChanOscGradTex=false; + } else { + logE("error while updating gradient texture! %s",SDL_GetError()); + } + } + + ImVec2 gradLeft=ImGui::GetCursorPos(); + ImVec2 gradSize=ImVec2(400.0f*dpiScale,400.0f*dpiScale); + ImGui::Image(chanOscGradTex,gradSize); + ImVec2 gradLeftAbs=ImGui::GetItemRectMin(); + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + chanOscGrad.points.push_back(Gradient2DPoint( + (ImGui::GetMousePos().x-gradLeftAbs.x)/gradSize.x, + (ImGui::GetMousePos().y-gradLeftAbs.y)/gradSize.y + )); + updateChanOscGradTex=true; + } + + ImVec2 oldCurPos=ImGui::GetCursorPos(); + int index=0; + int removePoint=-1; + for (Gradient2DPoint& i: chanOscGrad.points) { + ImGui::PushID(index+16); + ImGui::SetCursorPos(ImVec2(gradLeft.x+i.x*gradSize.x-8.0*dpiScale,gradLeft.y+i.y*gradSize.y-8.0*dpiScale)); + if (ImGui::InvisibleButton("gradPoint",ImVec2(16.0*dpiScale,16.0*dpiScale))) { + if (!i.grab) { + ImGui::OpenPopup("gradPointSettings"); + } + } + if (ImGui::IsItemHovered() || ImGui::IsItemActive()) { + ImGui::SetTooltip("(%.1f, %.1f)",i.x*100.0f,(1.0f-i.y)*100.0f); + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Middle)) { + removePoint=index; + } + if (ImGui::IsItemActive()) { + float mX=(ImGui::GetMousePos().x-gradLeftAbs.x)/gradSize.x; + float mY=(ImGui::GetMousePos().y-gradLeftAbs.y)/gradSize.y; + + if (i.grab || (fabs(i.x-mX)>0.015 || fabs(i.y-mY)>0.015)) { + i.x=mX; + i.y=mY; + i.grab=true; + + if (i.x<0) i.x=0; + if (i.x>1) i.x=1; + if (i.y<0) i.y=0; + if (i.y>1) i.y=1; + updateChanOscGradTex=true; + } + } else { + i.grab=false; + i.prevX=i.x; + i.prevY=i.y; + } + if (ImGui::BeginPopup("gradPointSettings",ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize)) { + if (ImGui::ColorPicker4("Color",(float*)&i.color)) { + updateChanOscGradTex=true; + } + ImGui::Text("Distance"); + ImGui::SameLine(); + float pDist=i.distance*100.0f; + if (ImGui::SliderFloat("##PDistance",&pDist,0.0f,150.0f,"%.1f%%")) { + i.distance=pDist/100.0f; + updateChanOscGradTex=true; + } + + ImGui::Text("Spread"); + ImGui::SameLine(); + float pSpread=i.spread*100.0f; + if (ImGui::SliderFloat("##PSpread",&pSpread,0.0f,150.0f,"%.1f%%")) { + i.spread=pSpread/100.0f; + updateChanOscGradTex=true; + } + + if (ImGui::Button("Remove")) { + removePoint=index; + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } + + dl->AddCircle(ImVec2(gradLeftAbs.x+i.x*gradSize.x,gradLeftAbs.y+i.y*gradSize.y),8.0*dpiScale,ImGui::ColorConvertFloat4ToU32(ImVec4(0.5,0.5,0.5,1.0)),6,2.0f*dpiScale); + dl->AddCircle(ImVec2(gradLeftAbs.x+i.x*gradSize.x,gradLeftAbs.y+i.y*gradSize.y),5.0*dpiScale,ImGui::ColorConvertFloat4ToU32(ImVec4(0.1,0.1,0.1,1.0)),6,2.0f*dpiScale); + + ImGui::PopID(); + index++; + } + ImGui::SetCursorPos(oldCurPos); + + if (removePoint>=0) { + chanOscGrad.points.erase(chanOscGrad.points.begin()+removePoint); + updateChanOscGradTex=true; } } - ImGui::ImageButton(chanOscGradTex,ImVec2(400.0f*dpiScale,400.0f*dpiScale)); - ImVec2 gradLeft=ImGui::GetItemRectMin(); - ImVec2 gradSize=ImGui::GetItemRectSize(); - if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { - chanOscGrad.points.push_back(Gradient2DPoint( - (ImGui::GetMousePos().x-gradLeft.x)/gradSize.x, - (ImGui::GetMousePos().y-gradLeft.y)/gradSize.y - )); + ImGui::TableNextColumn(); + if (ImGui::ColorEdit4("Background",(float*)&chanOscGrad.bgColor)) { updateChanOscGradTex=true; - logI("a point inserted"); } + ImGui::Combo("X Axis##AxisX",&chanOscColorX,chanOscRefs,GUI_OSCREF_MAX); + ImGui::Combo("Y Axis##AxisY",&chanOscColorY,chanOscRefs,GUI_OSCREF_MAX); - ImVec2 oldCurPos=ImGui::GetCursorPos(); - for (Gradient2DPoint& i: chanOscGrad.points) { - ImGui::SetCursorPos(ImVec2(gradLeft.x+i.x*gradSize.x,gradLeft.y+i.y*gradSize.y)); - ImGui::Text("Here"); - } - ImGui::SetCursorPos(oldCurPos); + ImGui::EndTable(); } + } else { + ImGui::SetNextItemWidth(400.0f*dpiScale); + ImGui::ColorPicker4("Color",(float*)&chanOscColor); + } - ImGui::TableNextColumn(); - if (ImGui::ColorEdit4("Background",(float*)&chanOscGrad.bgColor)) { - updateChanOscGradTex=true; - } - - ImGui::EndTable(); + if (ImGui::Button("OK")) { + chanOscOptions=false; } } @@ -129,12 +255,10 @@ void FurnaceGUI::drawChanOsc() { std::vector oscFFTs; std::vector oscChans; int chans=e->getTotalChannelCount(); - ImDrawList* dl=ImGui::GetWindowDrawList(); ImGuiWindow* window=ImGui::GetCurrentWindow(); ImVec2 waveform[512]; ImGuiStyle& style=ImGui::GetStyle(); - ImU32 color=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_WAVE]); for (int i=0; igetOscBuffer(i); @@ -196,93 +320,63 @@ void FurnaceGUI::drawChanOsc() { float maxLevel=-1.0f; float dcOff=0.0f; unsigned short needlePos=buf->needle; - if (chanOscWaveCorr) { - /* - double fftDataRate=(FURNACE_FFT_SIZE*FURNACE_FFT_RATE)/((double)buf->rate); - while (buf->readNeedle!=needlePos) { - fft->inBufPosFrac+=fftDataRate; - while (fft->inBufPosFrac>=1.0) { - chanOscLP0[ch]+=FURNACE_FFT_CUTOFF*((float)buf->data[buf->readNeedle]-chanOscLP0[ch]); - chanOscLP1[ch]+=FURNACE_FFT_CUTOFF*(chanOscLP0[ch]-chanOscLP1[ch]); - fft->inBuf[fft->inBufPos]=(double)chanOscLP1[ch]/32768.0; - if (++fft->inBufPos>=FURNACE_FFT_SIZE) { - fftw_execute(fft->plan); - fft->inBufPos=0; - fft->needle=buf->readNeedle; - } - fft->inBufPosFrac-=1.0; - } - buf->readNeedle++; - }*/ - - for (int i=0; iinBuf[i]=(double)buf->data[(unsigned short)(needlePos-displaySize*2+((i*displaySize*2)/FURNACE_FFT_SIZE))]/32768.0; - } - fftw_execute(fft->plan); - - // find origin frequency - int point=1; - double candAmp=0.0; - for (unsigned short i=1; i<512; i++) { - fftw_complex& f=fft->outBuf[i]; - // AMPLITUDE - double amp=sqrt(pow(f[0],2.0)+pow(f[1],2.0))/pow((double)i,0.8); - if (amp>candAmp) { - point=i; - candAmp=amp; - } - } - - // PHASE - fftw_complex& candPoint=fft->outBuf[point]; - double phase=((double)(displaySize*2)/(double)point)*(0.5+(atan2(candPoint[1],candPoint[0])/(M_PI*2))); - - //needlePos=fft->needle; - needlePos-=phase; - - /* - int alignment=0; - for (unsigned short i=0; idata[(unsigned short)(needlePos-i)])>fabs(buf->data[(unsigned short)(needlePos-alignment)])) { - alignment=i; - } - } - needlePos-=alignment; - */ - - //String cPhase=fmt::sprintf("%d cphase: %f",point,phase); - //dl->AddText(inRect.Min,0xffffffff,cPhase.c_str()); - - needlePos-=displaySize; - for (unsigned short i=0; i<512; i++) { - float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; - if (minLevel>y) minLevel=y; - if (maxLeveldata[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; - if (y<-0.5f) y=-0.5f; - if (y>0.5f) y=0.5f; - waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-(y-dcOff))); - } - } else { - needlePos-=displaySize; - for (unsigned short i=0; i<512; i++) { - float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; - if (minLevel>y) minLevel=y; - if (maxLeveldata[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; - if (y<-0.5f) y=-0.5f; - if (y>0.5f) y=0.5f; - waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-(y-dcOff))); + for (int i=0; iinBuf[i]=(double)buf->data[(unsigned short)(needlePos-displaySize*2+((i*displaySize*2)/FURNACE_FFT_SIZE))]/32768.0; + } + fftw_execute(fft->plan); + + // find origin frequency + int point=1; + double candAmp=0.0; + for (unsigned short i=1; i<512; i++) { + fftw_complex& f=fft->outBuf[i]; + // AMPLITUDE + double amp=sqrt(pow(f[0],2.0)+pow(f[1],2.0))/pow((double)i,0.8); + if (amp>candAmp) { + point=i; + candAmp=amp; } } + + // PHASE + fftw_complex& candPoint=fft->outBuf[point]; + double phase=((double)(displaySize*2)/(double)point)*(0.5+(atan2(candPoint[1],candPoint[0])/(M_PI*2))); + + if (chanOscWaveCorr) { + needlePos-=phase; + } + chanOscPitch[ch]=(float)point/32.0f; + + /* + String cPhase=fmt::sprintf("%d cphase: %f vol: %f",point,phase,chanOscVol[ch]); + dl->AddText(inRect.Min,0xffffffff,cPhase.c_str()); + */ + + needlePos-=displaySize; + for (unsigned short i=0; i<512; i++) { + float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; + if (minLevel>y) minLevel=y; + if (maxLeveldata[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; + if (y<-0.5f) y=-0.5f; + if (y>0.5f) y=0.5f; + waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-(y-dcOff))); + } + } + ImU32 color=ImGui::GetColorU32(chanOscColor); + if (chanOscUseGrad) { + float xVal=computeGradPos(chanOscColorX,ch); + float yVal=computeGradPos(chanOscColorY,ch); + + xVal=CLAMP(xVal,0.0f,1.0f); + yVal=CLAMP(yVal,0.0f,1.0f); + + color=chanOscGrad.get(xVal,1.0f-yVal); } dl->AddPolyline(waveform,512,color,ImDrawFlags_None,dpiScale); } diff --git a/src/gui/gradient.cpp b/src/gui/gradient.cpp index c9b26fb80..510f2ad53 100644 --- a/src/gui/gradient.cpp +++ b/src/gui/gradient.cpp @@ -21,6 +21,16 @@ #include "imgui.h" #include +ImU32 Gradient2D::get(float x, float y) { + int xi=round(x*width); + int yi=round(y*height); + if (xi<0) xi=0; + if (xi>=(int)width) xi=width-1; + if (yi<0) yi=0; + if (yi>=(int)height) yi=height-1; + return grad[yi*width+xi]; +} + void Gradient2D::render() { ImU32* g=grad.get(); ImU32 bgColorU=ImGui::ColorConvertFloat4ToU32(bgColor); @@ -33,18 +43,18 @@ void Gradient2D::render() { // 2. insert points for (Gradient2DPoint& i: points) { float pDistSquared=i.distance*i.distance; - printf("shading this point %f %f\n",i.x,i.y); for (size_t j=0; j=pDistSquared) continue; - float dist=(1.0-(sqrt(distSquared)/i.distance))-i.spread; + float dist=(1.0-(sqrt(distSquared)/i.distance)); if (dist<0) dist=0; if (dist>1) dist=1; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index fbfc2b4d9..f3f246cd8 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4573,10 +4573,14 @@ FurnaceGUI::FurnaceGUI(): oscWindowSize(20.0f), oscZoomSlider(false), chanOscCols(3), + chanOscColorX(GUI_OSCREF_CENTER), + chanOscColorY(GUI_OSCREF_CENTER), chanOscWindowSize(20.0f), chanOscWaveCorr(true), chanOscOptions(false), updateChanOscGradTex(true), + chanOscUseGrad(false), + chanOscColor(1.0f,1.0f,1.0f,1.0f), chanOscGrad(64,64), chanOscGradTex(NULL), followLog(true), @@ -4655,6 +4659,9 @@ FurnaceGUI::FurnaceGUI(): memset(chanOscLP0,0,sizeof(float)*DIV_MAX_CHANS); memset(chanOscLP1,0,sizeof(float)*DIV_MAX_CHANS); + memset(chanOscVol,0,sizeof(float)*DIV_MAX_CHANS); + memset(chanOscPitch,0,sizeof(float)*DIV_MAX_CHANS); + memset(chanOscBright,0,sizeof(float)*DIV_MAX_CHANS); memset(lastCorrPos,0,sizeof(short)*DIV_MAX_CHANS); memset(acedData,0,23); diff --git a/src/gui/gui.h b/src/gui/gui.h index a538c5ba5..ddda9d53a 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -525,6 +525,21 @@ enum FurnaceGUIActions { GUI_ACTION_MAX }; +enum FurnaceGUIChanOscRef { + GUI_OSCREF_NONE=0, + GUI_OSCREF_CENTER, + GUI_OSCREF_FULL, + + GUI_OSCREF_FREQUENCY, + GUI_OSCREF_VOLUME, + GUI_OSCREF_CHANNEL, + GUI_OSCREF_BRIGHT, + + GUI_OSCREF_NOTE_TRIGGER, + + GUI_OSCREF_MAX +}; + enum PasteMode { GUI_PASTE_MODE_NORMAL=0, GUI_PASTE_MODE_MIX_FG, @@ -760,13 +775,15 @@ struct TouchPoint { struct Gradient2DPoint { ImVec4 color; - float x, y; + float x, y, prevX, prevY; float spread, distance; bool selected, grab; Gradient2DPoint(float xPos, float yPos): color(1,1,1,1), x(xPos), y(yPos), + prevX(0.0f), + prevY(0.0f), spread(0.0f), distance(0.5f), selected(false), @@ -1382,13 +1399,17 @@ class FurnaceGUI { bool oscZoomSlider; // per-channel oscilloscope - int chanOscCols; + int chanOscCols, chanOscColorX, chanOscColorY; float chanOscWindowSize; - bool chanOscWaveCorr, chanOscOptions, updateChanOscGradTex; + bool chanOscWaveCorr, chanOscOptions, updateChanOscGradTex, chanOscUseGrad; + ImVec4 chanOscColor; Gradient2D chanOscGrad; SDL_Texture* chanOscGradTex; float chanOscLP0[DIV_MAX_CHANS]; float chanOscLP1[DIV_MAX_CHANS]; + float chanOscVol[DIV_MAX_CHANS]; + float chanOscPitch[DIV_MAX_CHANS]; + float chanOscBright[DIV_MAX_CHANS]; unsigned short lastNeedlePos[DIV_MAX_CHANS]; unsigned short lastCorrPos[DIV_MAX_CHANS]; struct ChanOscStatus { @@ -1501,6 +1522,8 @@ class FurnaceGUI { bool importLayout(String path); bool exportLayout(String path); + float computeGradPos(int type, int chan); + void resetColors(); void resetKeybinds(); From a65b4ded00fe708a1de443d8b283bfd8bb9ea2b1 Mon Sep 17 00:00:00 2001 From: 20Enderdude20 Date: Wed, 22 Jun 2022 13:14:23 -0700 Subject: [PATCH 096/101] Added "c" in "channel" typo and added a TI-99 bit (#551) --- papers/doc/7-systems/sms.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/papers/doc/7-systems/sms.md b/papers/doc/7-systems/sms.md index 53560a976..882085f16 100644 --- a/papers/doc/7-systems/sms.md +++ b/papers/doc/7-systems/sms.md @@ -6,10 +6,13 @@ surely had better graphics than NES, but its sound (fairly weak, 4ch PSG with A- this console is powered by a derivative of the Texas Instruments SN76489. +the original iteration of the SN76489 used in the TI-99/4A computers was clocked much lower at 447 kHz, being able to play as low as 13.670 Hz (A -1). consequentially, pitch accuracy for higher notes is compromised. + + # effects - `20xy`: set noise mode. - - `x` controls whether to inherit frequency from hannel 3. + - `x` controls whether to inherit frequency from channel 3. - 0: use one of 3 preset frequencies (C: A-2; C#: A-3; D: A-4). - 1: use frequency of channel 3. - `y` controls whether to select noise or thin pulse. From 2ffec02e26561ebaf2d0390983c7e64095473bf8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 22 Jun 2022 15:15:24 -0500 Subject: [PATCH 097/101] Revert "Added "c" in "channel" typo and added a TI-99 bit (#551)" This reverts commit a65b4ded00fe708a1de443d8b283bfd8bb9ea2b1. --- papers/doc/7-systems/sms.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/papers/doc/7-systems/sms.md b/papers/doc/7-systems/sms.md index 882085f16..53560a976 100644 --- a/papers/doc/7-systems/sms.md +++ b/papers/doc/7-systems/sms.md @@ -6,13 +6,10 @@ surely had better graphics than NES, but its sound (fairly weak, 4ch PSG with A- this console is powered by a derivative of the Texas Instruments SN76489. -the original iteration of the SN76489 used in the TI-99/4A computers was clocked much lower at 447 kHz, being able to play as low as 13.670 Hz (A -1). consequentially, pitch accuracy for higher notes is compromised. - - # effects - `20xy`: set noise mode. - - `x` controls whether to inherit frequency from channel 3. + - `x` controls whether to inherit frequency from hannel 3. - 0: use one of 3 preset frequencies (C: A-2; C#: A-3; D: A-4). - 1: use frequency of channel 3. - `y` controls whether to select noise or thin pulse. From c7ea30dda1688ecfd44164760139b27f9536aa1b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 22 Jun 2022 15:16:19 -0500 Subject: [PATCH 098/101] Revert "Revert "Added "c" in "channel" typo and added a TI-99 bit (#551)"" This reverts commit 2ffec02e26561ebaf2d0390983c7e64095473bf8. --- papers/doc/7-systems/sms.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/papers/doc/7-systems/sms.md b/papers/doc/7-systems/sms.md index 53560a976..882085f16 100644 --- a/papers/doc/7-systems/sms.md +++ b/papers/doc/7-systems/sms.md @@ -6,10 +6,13 @@ surely had better graphics than NES, but its sound (fairly weak, 4ch PSG with A- this console is powered by a derivative of the Texas Instruments SN76489. +the original iteration of the SN76489 used in the TI-99/4A computers was clocked much lower at 447 kHz, being able to play as low as 13.670 Hz (A -1). consequentially, pitch accuracy for higher notes is compromised. + + # effects - `20xy`: set noise mode. - - `x` controls whether to inherit frequency from hannel 3. + - `x` controls whether to inherit frequency from channel 3. - 0: use one of 3 preset frequencies (C: A-2; C#: A-3; D: A-4). - 1: use frequency of channel 3. - `y` controls whether to select noise or thin pulse. From 142b8b2bb0839ce1a07e3cdc076c1cffe43b644e Mon Sep 17 00:00:00 2001 From: Natt Akuma Date: Thu, 23 Jun 2022 09:03:20 +0700 Subject: [PATCH 099/101] safeReader: Copy a value instead of direct casting This fix crashes on architectures with forced alignments such as ARM --- src/engine/safeReader.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/engine/safeReader.cpp b/src/engine/safeReader.cpp index 173ffd235..3cb1f4b1f 100644 --- a/src/engine/safeReader.cpp +++ b/src/engine/safeReader.cpp @@ -82,7 +82,8 @@ short SafeReader::readS() { logD("SR: reading short %x:",curSeek); #endif if (curSeek+2>len) throw EndOfFileException(this,len); - short ret=*(short*)(&buf[curSeek]); + short ret; + memcpy(&ret,&buf[curSeek],2); #ifdef READ_DEBUG logD("SR: %.4x",ret); #endif @@ -92,7 +93,8 @@ short SafeReader::readS() { short SafeReader::readS_BE() { if (curSeek+2>len) throw EndOfFileException(this,len); - short ret=*(short*)(&buf[curSeek]); + short ret; + memcpy(&ret,&buf[curSeek],2); curSeek+=2; return ((ret>>8)&0xff)|(ret<<8); } @@ -102,7 +104,8 @@ int SafeReader::readI() { logD("SR: reading int %x:",curSeek); #endif if (curSeek+4>len) throw EndOfFileException(this,len); - int ret=*(int*)(&buf[curSeek]); + int ret; + memcpy(&ret,&buf[curSeek],4); curSeek+=4; #ifdef READ_DEBUG logD("SR: %.8x",ret); @@ -112,28 +115,32 @@ int SafeReader::readI() { int SafeReader::readI_BE() { if (curSeek+4>len) throw EndOfFileException(this,len); - unsigned int ret=*(unsigned int*)(&buf[curSeek]); + unsigned int ret; + memcpy(&ret,&buf[curSeek],4); curSeek+=4; return (int)((ret>>24)|((ret&0xff0000)>>8)|((ret&0xff00)<<8)|((ret&0xff)<<24)); } int64_t SafeReader::readL() { if (curSeek+8>len) throw EndOfFileException(this,len); - int64_t ret=*(int64_t*)(&buf[curSeek]); + int64_t ret; + memcpy(&ret,&buf[curSeek],8); curSeek+=8; return ret; } float SafeReader::readF() { if (curSeek+4>len) throw EndOfFileException(this,len); - float ret=*(float*)(&buf[curSeek]); + float ret; + memcpy(&ret,&buf[curSeek],4); curSeek+=4; return ret; } double SafeReader::readD() { if (curSeek+8>len) throw EndOfFileException(this,len); - double ret=*(double*)(&buf[curSeek]); + double ret; + memcpy(&ret,&buf[curSeek],8); curSeek+=8; return ret; } From abbd6e7274821e6ab036035514f6ed8e63d7a101 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 23 Jun 2022 02:48:28 -0500 Subject: [PATCH 100/101] potentially fix #550 --- extern/imgui_patched/imgui_widgets.cpp | 65 ++++++++++++++++++-------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/extern/imgui_patched/imgui_widgets.cpp b/extern/imgui_patched/imgui_widgets.cpp index c6fec68bc..93dfd5343 100644 --- a/extern/imgui_patched/imgui_widgets.cpp +++ b/extern/imgui_patched/imgui_widgets.cpp @@ -4545,27 +4545,52 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size // of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used // without any storage on user's side. - IM_ASSERT(apply_new_text_length >= 0); - if (is_resizable) - { - ImGuiInputTextCallbackData callback_data; - callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize; - callback_data.Flags = flags; - callback_data.Buf = buf; - callback_data.BufTextLen = apply_new_text_length; - callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1); - callback_data.UserData = callback_user_data; - callback(&callback_data); - buf = callback_data.Buf; - buf_size = callback_data.BufSize; - apply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1); - IM_ASSERT(apply_new_text_length <= buf_size); - } - //IMGUI_DEBUG_LOG("InputText(\"%s\"): apply_new_text length %d\n", label, apply_new_text_length); - // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size. - ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size)); - value_changed = true; + // don't assert because maybe the user passes an invalid UTF-8 string... + if (apply_new_text_length >= 0) { + if (is_resizable) + { + ImGuiInputTextCallbackData callback_data; + callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize; + callback_data.Flags = flags; + callback_data.Buf = buf; + callback_data.BufTextLen = apply_new_text_length; + callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1); + callback_data.UserData = callback_user_data; + callback(&callback_data); + buf = callback_data.Buf; + buf_size = callback_data.BufSize; + apply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1); + IM_ASSERT(apply_new_text_length <= buf_size); + } + //IMGUI_DEBUG_LOG("InputText(\"%s\"): apply_new_text length %d\n", label, apply_new_text_length); + + // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size. + ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size)); + value_changed = true; + } else { + printf("invalid buffer!\n"); + if (is_resizable) + { + ImGuiInputTextCallbackData callback_data; + callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize; + callback_data.Flags = flags; + callback_data.Buf = buf; + callback_data.BufTextLen = 0; + callback_data.BufSize = ImMax(buf_size, 1); + callback_data.UserData = callback_user_data; + callback(&callback_data); + buf = callback_data.Buf; + buf_size = callback_data.BufSize; + apply_new_text_length = 0; + IM_ASSERT(apply_new_text_length <= buf_size); + } + //IMGUI_DEBUG_LOG("InputText(\"%s\"): apply_new_text length %d\n", label, apply_new_text_length); + + // clear the buffer + ImStrncpy(buf, "", 1); + value_changed = true; + } } // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value) From 1b5396e814b6c3f9dfb971474267f9e55796abf8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 23 Jun 2022 04:02:41 -0500 Subject: [PATCH 101/101] GUI: save per-chan osc state --- src/gui/chanOsc.cpp | 12 +++++++----- src/gui/gradient.cpp | 14 ++++++++++++++ src/gui/gui.cpp | 27 +++++++++++++++++++++++++++ src/gui/gui.h | 2 ++ 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index 57fa99dac..da82de277 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -143,11 +143,13 @@ void FurnaceGUI::drawChanOsc() { ImGui::Image(chanOscGradTex,gradSize); ImVec2 gradLeftAbs=ImGui::GetItemRectMin(); if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { - chanOscGrad.points.push_back(Gradient2DPoint( - (ImGui::GetMousePos().x-gradLeftAbs.x)/gradSize.x, - (ImGui::GetMousePos().y-gradLeftAbs.y)/gradSize.y - )); - updateChanOscGradTex=true; + if (chanOscGrad.points.size()<32) { + chanOscGrad.points.push_back(Gradient2DPoint( + (ImGui::GetMousePos().x-gradLeftAbs.x)/gradSize.x, + (ImGui::GetMousePos().y-gradLeftAbs.y)/gradSize.y + )); + updateChanOscGradTex=true; + } } ImVec2 oldCurPos=ImGui::GetCursorPos(); diff --git a/src/gui/gradient.cpp b/src/gui/gradient.cpp index 510f2ad53..ac69bf866 100644 --- a/src/gui/gradient.cpp +++ b/src/gui/gradient.cpp @@ -19,6 +19,7 @@ #include "gui.h" #include "imgui.h" +#include #include ImU32 Gradient2D::get(float x, float y) { @@ -31,6 +32,19 @@ ImU32 Gradient2D::get(float x, float y) { return grad[yi*width+xi]; } +String Gradient2D::toString() { + String ret=fmt::sprintf("GRAD #%.2X%.2X%.2X%.2X",(unsigned char)(bgColor.x*255.0f),(unsigned char)(bgColor.y*255.0f),(unsigned char)(bgColor.z*255.0f),(unsigned char)(bgColor.w*255.0f)); + for (Gradient2DPoint& i: points) { + ret+=fmt::sprintf(" %f,%f:%f,%f:#%.2X%.2X%.2X%.2X",i.x,i.y,i.distance,i.spread,(unsigned char)(i.color.x*255.0f),(unsigned char)(i.color.y*255.0f),(unsigned char)(i.color.z*255.0f),(unsigned char)(i.color.w*255.0f)); + } + return ret; +} + +// TODO: this one please +bool Gradient2D::fromString(String val) { + return false; +} + void Gradient2D::render() { ImU32* g=grad.get(); ImU32 bgColorU=ImGui::ColorConvertFloat4ToU32(bgColor); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index f3f246cd8..3de09f8e1 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4070,6 +4070,19 @@ bool FurnaceGUI::init() { pianoView=e->getConfInt("pianoView",pianoView); pianoInputPadMode=e->getConfInt("pianoInputPadMode",pianoInputPadMode); + chanOscCols=e->getConfInt("chanOscCols",3); + chanOscColorX=e->getConfInt("chanOscColorX",GUI_OSCREF_CENTER); + chanOscColorY=e->getConfInt("chanOscColorY",GUI_OSCREF_CENTER); + chanOscWindowSize=e->getConfFloat("chanOscWindowSize",20.0f); + chanOscWaveCorr=e->getConfBool("chanOscWaveCorr",true); + chanOscOptions=e->getConfBool("chanOscOptions",false); + chanOscColor.x=e->getConfFloat("chanOscColorR",1.0f); + chanOscColor.y=e->getConfFloat("chanOscColorG",1.0f); + chanOscColor.z=e->getConfFloat("chanOscColorB",1.0f); + chanOscColor.w=e->getConfFloat("chanOscColorA",1.0f); + chanOscUseGrad=e->getConfBool("chanOscUseGrad",false); + chanOscGrad.fromString(e->getConfString("chanOscGrad","")); + syncSettings(); if (settings.dpiScale>=0.5f) { @@ -4294,6 +4307,20 @@ bool FurnaceGUI::finish() { e->setConf("pianoView",pianoView); e->setConf("pianoInputPadMode",pianoInputPadMode); + // commit per-chan osc state + e->setConf("chanOscCols",chanOscCols); + e->setConf("chanOscColorX",chanOscColorX); + e->setConf("chanOscColorY",chanOscColorY); + e->setConf("chanOscWindowSize",chanOscWindowSize); + e->setConf("chanOscWaveCorr",chanOscWaveCorr); + e->setConf("chanOscOptions",chanOscOptions); + e->setConf("chanOscColorR",chanOscColor.x); + e->setConf("chanOscColorG",chanOscColor.y); + e->setConf("chanOscColorB",chanOscColor.z); + e->setConf("chanOscColorA",chanOscColor.w); + e->setConf("chanOscUseGrad",chanOscUseGrad); + e->setConf("chanOscGrad",chanOscGrad.toString()); + for (int i=0; i grad; size_t width, height; + String toString(); + bool fromString(String val); void render(); ImU32 get(float x, float y); Gradient2D(size_t w, size_t h):