From f13cea6a8eea786b1b56cff448d8ac9a234b9270 Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 11 Apr 2023 09:19:12 +0900 Subject: [PATCH 01/40] pv1000: Add XORing features --- src/engine/platform/pv1000.cpp | 23 +++++++++++--- src/engine/platform/pv1000.h | 2 +- src/engine/platform/sound/d65modified.c | 41 ++++++++++++++++++++++--- src/engine/platform/sound/d65modified.h | 2 ++ src/engine/sysDef.cpp | 6 +++- 5 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/engine/platform/pv1000.cpp b/src/engine/platform/pv1000.cpp index d5f54e6a..af4cae0c 100644 --- a/src/engine/platform/pv1000.cpp +++ b/src/engine/platform/pv1000.cpp @@ -29,6 +29,7 @@ const char* regCheatSheetPV1000[]={ "CH1_Pitch", "00", "CH2_Pitch", "01", "CH3_Pitch", "02", + "Control", "03", NULL }; @@ -42,7 +43,7 @@ void DivPlatformPV1000::acquire(short** buf, size_t len) { samp=d65010g031_sound_tick(&d65010g031,1); buf[0][h]=samp; for (int i=0; i<3; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(d65010g031.square[i].out<<12); + oscBuf[i]->data[oscBuf[i]->needle++]=(d65010g031.out[i]); } } } @@ -73,7 +74,7 @@ void DivPlatformPV1000::tick(bool sysTick) { } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=0x3f-parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); - if (chan[i].freq<1) chan[i].freq=1; + if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>62) chan[i].freq=62; if (isMuted[i]) chan[i].keyOn=false; if (chan[i].keyOn) { @@ -83,7 +84,7 @@ void DivPlatformPV1000::tick(bool sysTick) { rWrite(i,(isMuted[i] || (chan[i].outVol<=0)) ? 0 : chan[i].freq); } if (chan[i].keyOff) { - rWrite(i,0); + rWrite(i,0x3f); chan[i].keyOff=false; } chan[i].freqChanged=false; @@ -137,6 +138,13 @@ int DivPlatformPV1000::dispatch(DivCommand c) { chan[c.chan].pitch=c.value; chan[c.chan].freqChanged=true; break; + case DIV_CMD_WAVE: + if (c.value&1) { + rWrite(3,3); + } else { + rWrite(3,2); + } + break; case DIV_CMD_NOTE_PORTA: { int destFreq=NOTE_PERIODIC(c.value2); bool return2=false; @@ -224,16 +232,21 @@ unsigned char* DivPlatformPV1000::getRegisterPool() { } int DivPlatformPV1000::getRegisterPoolSize() { - return 3; + return 4; } void DivPlatformPV1000::reset() { - memset(regPool,0,3); + memset(regPool,0,4); for (int i=0; i<3; i++) { chan[i]=Channel(); chan[i].std.setEngine(parent); } d65010g031_reset(&d65010g031); + // mute + rWrite(0,0x3f); + rWrite(1,0x3f); + rWrite(2,0x3f); + rWrite(3,2); } int DivPlatformPV1000::getOutputCount() { diff --git a/src/engine/platform/pv1000.h b/src/engine/platform/pv1000.h index c3254076..852bf120 100644 --- a/src/engine/platform/pv1000.h +++ b/src/engine/platform/pv1000.h @@ -33,7 +33,7 @@ class DivPlatformPV1000: public DivDispatch { DivDispatchOscBuffer* oscBuf[3]; bool isMuted[3]; - unsigned char regPool[3]; + unsigned char regPool[4]; d65010g031_t d65010g031; friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); diff --git a/src/engine/platform/sound/d65modified.c b/src/engine/platform/sound/d65modified.c index 8f53b34c..5cd49f2f 100644 --- a/src/engine/platform/sound/d65modified.c +++ b/src/engine/platform/sound/d65modified.c @@ -67,7 +67,7 @@ int d65010g031_square_tick(struct d65010g031_square_t *square, const int cycle) { if (square->period > 0) { - int period = d65010g031_max(1, (0x3f - square->period)); + const int period = square->period; square->counter += cycle; while (square->counter >= period) { @@ -92,7 +92,29 @@ int d65010g031_sound_tick(struct d65010g031_t *d65010g031, const int cycle) int out = 0; for (int i = 0; i < 3; i++) { - out += d65010g031_square_tick(&d65010g031->square[i], cycle)?d65Volumes[i]:-d65Volumes[i]; + d65010g031->out[i] = 0; + } + if (d65010g031->ctrl & 2) + { + if (d65010g031->ctrl & 1) + { + int sout[3] = { + d65010g031_square_tick(&d65010g031->square[0], cycle), + d65010g031_square_tick(&d65010g031->square[1], cycle), + d65010g031_square_tick(&d65010g031->square[2], cycle), + }; + d65010g031->out[0] = (sout[0] ^ sout[1]) ? d65Volumes[0] : -d65Volumes[0]; + d65010g031->out[1] = (sout[1] ^ sout[2]) ? d65Volumes[1] : -d65Volumes[1]; + d65010g031->out[2] = (sout[2] ? d65Volumes[2] : -d65Volumes[2]); + } + else + { + for (int i = 0; i < 3; i++) + { + d65010g031->out[i] = d65010g031_square_tick(&d65010g031->square[i], cycle)?d65Volumes[i]:-d65Volumes[i]; + } + } + out = d65010g031->out[0] + d65010g031->out[1] + d65010g031->out[2]; } return out; } @@ -105,12 +127,23 @@ void d65010g031_reset(struct d65010g031_t *d65010g031) d65010g031->square[i].counter = 0; d65010g031->square[i].out = 0; } + d65010g031->ctrl = 0; } void d65010g031_write(struct d65010g031_t *d65010g031, const unsigned char a, const unsigned char d) { - if (a < 3) + switch (a) { - d65010g031->square[a].period = d & 0x3f; + case 3: + d65010g031->ctrl = d; + break; + default: + const unsigned char period = ~d & 0x3f; + if ((period == 0) && (d65010g031->square[a].period != 0)) + { + d65010g031->square[a].out ^= 1; + } + d65010g031->square[a].period = period; + break; } } diff --git a/src/engine/platform/sound/d65modified.h b/src/engine/platform/sound/d65modified.h index 49dc13a1..eae0f898 100644 --- a/src/engine/platform/sound/d65modified.h +++ b/src/engine/platform/sound/d65modified.h @@ -54,6 +54,8 @@ struct d65010g031_square_t struct d65010g031_t { struct d65010g031_square_t square[3]; + signed short out[3]; + unsigned char ctrl; }; int d65010g031_square_tick(struct d65010g031_square_t *square, const int cycle); diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index fbb718cb..c9aef95e 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1839,7 +1839,11 @@ void DivEngine::registerSystems() { {"Square 1", "Square 2", "Square 3"}, {"S1", "S2", "S3"}, {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE}, - {DIV_INS_PV1000, DIV_INS_PV1000, DIV_INS_PV1000} + {DIV_INS_PV1000, DIV_INS_PV1000, DIV_INS_PV1000}, + {}, + { + {0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}} + } ); sysDefs[DIV_SYSTEM_SFX_BEEPER_QUADTONE]=new DivSysDef( From cb340544730eef282091c62740b27fbe8365e022 Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 11 Apr 2023 12:50:24 +0900 Subject: [PATCH 02/40] Fix compile --- src/engine/platform/sound/d65modified.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/sound/d65modified.c b/src/engine/platform/sound/d65modified.c index 5cd49f2f..1002ede0 100644 --- a/src/engine/platform/sound/d65modified.c +++ b/src/engine/platform/sound/d65modified.c @@ -138,7 +138,7 @@ void d65010g031_write(struct d65010g031_t *d65010g031, const unsigned char a, co d65010g031->ctrl = d; break; default: - const unsigned char period = ~d & 0x3f; + unsigned char period = ~d & 0x3f; if ((period == 0) && (d65010g031->square[a].period != 0)) { d65010g031->square[a].out ^= 1; From f66b703a8139aa1f8d035566762b08833d946fa5 Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 11 Apr 2023 12:55:09 +0900 Subject: [PATCH 03/40] Fix compile again --- src/engine/platform/sound/d65modified.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/sound/d65modified.c b/src/engine/platform/sound/d65modified.c index 1002ede0..edbb21a9 100644 --- a/src/engine/platform/sound/d65modified.c +++ b/src/engine/platform/sound/d65modified.c @@ -138,12 +138,12 @@ void d65010g031_write(struct d65010g031_t *d65010g031, const unsigned char a, co d65010g031->ctrl = d; break; default: - unsigned char period = ~d & 0x3f; - if ((period == 0) && (d65010g031->square[a].period != 0)) + unsigned char per = (unsigned char)(~d) & 0x3f; + if ((per == 0) && (d65010g031->square[a].period != 0)) { d65010g031->square[a].out ^= 1; } - d65010g031->square[a].period = period; + d65010g031->square[a].period = per; break; } } From fe0ba4e530f7e43428316b93106b0e998afa661d Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 11 Apr 2023 13:11:54 +0900 Subject: [PATCH 04/40] Fix muting --- src/engine/platform/pv1000.cpp | 4 ++-- src/engine/platform/sound/d65modified.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/pv1000.cpp b/src/engine/platform/pv1000.cpp index af4cae0c..903748b6 100644 --- a/src/engine/platform/pv1000.cpp +++ b/src/engine/platform/pv1000.cpp @@ -78,10 +78,10 @@ void DivPlatformPV1000::tick(bool sysTick) { if (chan[i].freq>62) chan[i].freq=62; if (isMuted[i]) chan[i].keyOn=false; if (chan[i].keyOn) { - rWrite(i,(isMuted[i] || (chan[i].outVol<=0)) ? 0 : chan[i].freq); + rWrite(i,(isMuted[i] || (chan[i].outVol<=0)) ? 0x3f : chan[i].freq); chan[i].keyOn=false; } else if (chan[i].freqChanged && chan[i].active && !isMuted[i]) { - rWrite(i,(isMuted[i] || (chan[i].outVol<=0)) ? 0 : chan[i].freq); + rWrite(i,(isMuted[i] || (chan[i].outVol<=0)) ? 0x3f : chan[i].freq); } if (chan[i].keyOff) { rWrite(i,0x3f); diff --git a/src/engine/platform/sound/d65modified.c b/src/engine/platform/sound/d65modified.c index edbb21a9..ff5a84da 100644 --- a/src/engine/platform/sound/d65modified.c +++ b/src/engine/platform/sound/d65modified.c @@ -138,12 +138,14 @@ void d65010g031_write(struct d65010g031_t *d65010g031, const unsigned char a, co d65010g031->ctrl = d; break; default: - unsigned char per = (unsigned char)(~d) & 0x3f; + { + const unsigned char per = (unsigned char)(~d) & 0x3f; if ((per == 0) && (d65010g031->square[a].period != 0)) { d65010g031->square[a].out ^= 1; } d65010g031->square[a].period = per; break; + } } } From 52e6246570036a9cb45300e00554ed5f615396af Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 13 Apr 2023 11:56:34 +0900 Subject: [PATCH 05/40] Add notes for ring modulation (XORing) --- src/engine/platform/pv1000.cpp | 2 +- src/engine/platform/sound/d65modified.c | 8 ++++---- src/engine/sysDef.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/engine/platform/pv1000.cpp b/src/engine/platform/pv1000.cpp index 903748b6..4d9597c9 100644 --- a/src/engine/platform/pv1000.cpp +++ b/src/engine/platform/pv1000.cpp @@ -138,7 +138,7 @@ int DivPlatformPV1000::dispatch(DivCommand c) { chan[c.chan].pitch=c.value; chan[c.chan].freqChanged=true; break; - case DIV_CMD_WAVE: + case DIV_CMD_STD_NOISE_MODE: // ring modulation if (c.value&1) { rWrite(3,3); } else { diff --git a/src/engine/platform/sound/d65modified.c b/src/engine/platform/sound/d65modified.c index ff5a84da..4a0ec1ed 100644 --- a/src/engine/platform/sound/d65modified.c +++ b/src/engine/platform/sound/d65modified.c @@ -82,9 +82,9 @@ int d65010g031_square_tick(struct d65010g031_square_t *square, const int cycle) // this is the bit I altered // THIS IS **NOT** THE ORIGINAL SOFTWARE! I am plainly marking it as such! const int d65Volumes[3]={ - 3840, - 5120, - 8192 + 3840, // -6dB + 5120, // -3dB + 8192 // 0dB }; int d65010g031_sound_tick(struct d65010g031_t *d65010g031, const int cycle) @@ -96,7 +96,7 @@ int d65010g031_sound_tick(struct d65010g031_t *d65010g031, const int cycle) } if (d65010g031->ctrl & 2) { - if (d65010g031->ctrl & 1) + if (d65010g031->ctrl & 1) // ring modulation { int sout[3] = { d65010g031_square_tick(&d65010g031->square[0], cycle), diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index c9aef95e..d92573bb 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1842,7 +1842,7 @@ void DivEngine::registerSystems() { {DIV_INS_PV1000, DIV_INS_PV1000, DIV_INS_PV1000}, {}, { - {0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}} + {0x10, {DIV_CMD_STD_NOISE_MODE, "10xx: Set ring modulation (0: disable, 1: enable)"}} } ); From 1f60d6bdc60be71c28e176fcdd9b7ad37cbbb172 Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 13 Apr 2023 12:03:30 +0900 Subject: [PATCH 06/40] Simplify --- src/engine/platform/pv1000.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/engine/platform/pv1000.cpp b/src/engine/platform/pv1000.cpp index 4d9597c9..4d32fc5a 100644 --- a/src/engine/platform/pv1000.cpp +++ b/src/engine/platform/pv1000.cpp @@ -39,8 +39,7 @@ const char** DivPlatformPV1000::getRegisterSheet() { void DivPlatformPV1000::acquire(short** buf, size_t len) { for (size_t h=0; hdata[oscBuf[i]->needle++]=(d65010g031.out[i]); From 3542a6c22f76b6968e126af0a8e6f805af0f3543 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 15 Apr 2023 15:31:02 -0500 Subject: [PATCH 07/40] GUI: settings window size constraints --- src/gui/settings.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 9e291a43..e08d5e1d 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -276,6 +276,8 @@ void FurnaceGUI::drawSettings() { ImVec2 setWindowSize=ImVec2(canvasW,canvasH); ImGui::SetNextWindowPos(setWindowPos); ImGui::SetNextWindowSize(setWindowSize); + } else { + ImGui::SetNextWindowSizeConstraints(ImVec2(200.0f*dpiScale,100.0f*dpiScale),ImVec2(canvasW,canvasH)); } if (ImGui::Begin("Settings",&settingsOpen,ImGuiWindowFlags_NoDocking|globalWinFlags)) { if (!settingsOpen) { From f7f1734c7db4bc14fc47182fa294cd54eca5bd98 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 15 Apr 2023 16:08:38 -0500 Subject: [PATCH 08/40] GUI: rename a few things --- src/gui/gui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 1f1ce052..76214fae 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3838,11 +3838,11 @@ bool FurnaceGUI::loop() { } ImGui::Checkbox("loop",&vgmExportLoop); if (vgmExportLoop && e->song.loopModality==2) { - ImGui::Text("trailing ticks:"); + ImGui::Text("loop trail:"); if (ImGui::RadioButton("auto-detect",vgmExportTrailingTicks==-1)) { vgmExportTrailingTicks=-1; } - if (ImGui::RadioButton("one loop",vgmExportTrailingTicks==-2)) { + if (ImGui::RadioButton("add one loop",vgmExportTrailingTicks==-2)) { vgmExportTrailingTicks=-2; } if (ImGui::RadioButton("custom",vgmExportTrailingTicks>=0)) { From 73204b5378dc161255cc5b35b6369548f8885b08 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 16 Apr 2023 01:11:20 -0500 Subject: [PATCH 09/40] blip_buf clockgetOutputCount(); + int rate=dispatch->rate; + rateMul=0; + while (rateMul<8 && raterate,gotRate); + blip_set_rates(bb[i],rate,gotRate); } rateMemory=gotRate; } @@ -120,7 +127,13 @@ void DivDispatchContainer::grow(size_t size) { logE("not enough memory!"); \ return; \ } \ - blip_set_rates(bb[i],dispatch->rate,rateMemory); \ + int rate=dispatch->rate; \ + rateMul=0; \ + while (rateMul<8 && rate=outs) { bbInMapped[i]=NULL; @@ -160,6 +175,8 @@ void DivDispatchContainer::flush(size_t count) { void DivDispatchContainer::fillBuf(size_t runtotal, size_t offset, size_t size) { CHECK_MISSING_BUFS; + int step=1<0) { dcOffCompensation=false; for (int i=0; i Date: Sun, 16 Apr 2023 02:10:22 -0500 Subject: [PATCH 10/40] Y8950: fix missing ADPCM chan osc --- src/engine/platform/opl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 6fea25c3..a54667a7 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -1558,7 +1558,7 @@ DivMacroInt* DivPlatformOPL::getChanMacroInt(int ch) { } DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) { - if (oplType==759) { + if (oplType==759 || chipType==8950) { if (ch>=totalChans+1) return NULL; } else { if (ch>=totalChans) return NULL; From eeffb47ab74b9085469af789db2e2ecaf967891c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 16 Apr 2023 02:22:16 -0500 Subject: [PATCH 11/40] X1-010: why is the per-chan osc so quiet? --- src/engine/platform/x1_010.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index 63800174..44f94d99 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -222,7 +222,8 @@ void DivPlatformX1_010::acquire(short** buf, size_t len) { if (stereo) buf[1][h]=tempR; for (int i=0; i<16; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(x1_010.voice_out(i,0)+x1_010.voice_out(i,1))>>1; + int vo=(x1_010.voice_out(i,0)+x1_010.voice_out(i,1))<<3; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(vo,-32768,32767); } } } From 082ea94ca9b78fb654922c890d3ea223cf9d152c Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Sun, 16 Apr 2023 17:04:35 +0200 Subject: [PATCH 12/40] update the wavedoc a little welp --- papers/doc/5-wave/README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/papers/doc/5-wave/README.md b/papers/doc/5-wave/README.md index e04834cc..19a07b10 100644 --- a/papers/doc/5-wave/README.md +++ b/papers/doc/5-wave/README.md @@ -1,8 +1,14 @@ # wavetable editor -Wavetable synthesizers, in context of Furnace, are sound sources that operate on extremely short n-bit PCM streams. By extremely short, no more than 256 bytes. This amount of space is nowhere near enough to store an actual sampled sound, it allows certain amount of freedom to define a waveform shape. As of Furnace 0.5.8, wavetable editor affects PC Engine, WonderSwan and channel 3 of Game Boy. +Wavetable synthesizers, in context of Furnace, are sound sources that operate on extremely short n-bit PCM streams. By extremely short, no more than 256 bytes. This amount of space is nowhere near enough to store an actual sampled sound, it allows certain amount of freedom to define a waveform shape. As of Furnace 0.6pre4, wavetable editor affects PC Engine, WonderSwan, Namco WSGs, Virtual Boy, Game.com, SCC, FDS, Seta X1-010, Konami Bubble System WSG, SNES, Amiga and channel 3 of Game Boy. -Furnace's wavetable editor is rather simple, you can draw the waveform using mouse or by pasting an MML bit stream in the input field. Maximum wave width (length) is 256 bytes, and maximum wave height (depth) is 256. NOTE: Game Boy, PCE, WonderSwan and Bubble System can handle max 32 byte waveforms, X1-010 can handle max 128 byte waveforms as of now, with 16-level height for GB, X1-010 Envelope, WS, Bubble System and N163, and 32-level height for PCE. If a larger wave is defined for these chips, it will be squashed to fit within the constraints of the chips. +Furnace's wavetable editor is rather simple, you can draw the waveform using mouse or by pasting an MML bit stream in the input field. Maximum wave width (length) is 256 bytes, and maximum wave height (depth) is 256. NOTE: Game Boy, PCE, WonderSwan, Namco WSG, N163, Game.com, Virtual Boy and Bubble System can handle max 32 byte waveforms, X1-010 can handle max 128 byte waveforms as of now, with 16-level height for GB, X1-010 Envelope, WS, Bubble System, SNES, Namco WSG and N163, 32-level height for PCE and 64-level height for Virtual Boy. If a larger wave is defined for these chips, it will be squashed to fit within the constraints of the chips. + +Furnace's wavetable editor features multiple ways of creating desired waveform shape: + +- Shape tab allows you to select a few predefined basic shapes and indirectly edit it via "Duty", "Exponent" and "XOR Point" sliders TODO: what the last two are doing? What is amplitude/phase for?) +- FM is for creating the waveform with frequency modulation synthesis principles: One can set carrier/modulation levels, frquency multiplier, connection between operators and FM waveforms of these operators. +- WaveTools allows user to fine-tune the waveform: scale said waveform in both X and Y axes, smoothen, amplify, normalize, convert to signed/unisgned, invert or even randomize the wavetable. ## wavetable synthesizer From 149d4ce99c6f2cd28ea67ba1cd3a0d07eb9336e4 Mon Sep 17 00:00:00 2001 From: Waverider <33787286+liaminventions@users.noreply.github.com> Date: Sun, 16 Apr 2023 14:08:04 -0400 Subject: [PATCH 13/40] add 1 new c64 song (#1073) * 2 songz * add artist * whoops * that ones multichip * whoops! * Delete colab.fur * fix bass and drums * Delete collab.fur * add final (???) revision of song * Delete collab.fur * this is official (final version) * epic c64 --- demos/c64/yeah!.fur | Bin 0 -> 3257 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/c64/yeah!.fur diff --git a/demos/c64/yeah!.fur b/demos/c64/yeah!.fur new file mode 100644 index 0000000000000000000000000000000000000000..54312aff21dcd93893677d5c024e1b034f3ca0cc GIT binary patch literal 3257 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 Date: Sun, 16 Apr 2023 14:41:12 -0500 Subject: [PATCH 14/40] blip_buf clock>=rateMul; + count>>=rateMul; + + if (offset!=0 && offset!=lastCount) { + logW("Shit!"); + } + + lastCount=offset+count; + + logV("got: from %d to %d",offset,offset+count-1); + } for (int i=0; i=outs) { @@ -189,7 +206,7 @@ void DivDispatchContainer::fillBuf(size_t runtotal, size_t offset, size_t size) if (bbIn[i]==NULL) continue; if (bb[i]==NULL) continue; int s=0; - for (size_t j=0; jgetDCOffRequired()) { dcOffCompensation=true; } diff --git a/src/engine/engine.h b/src/engine/engine.h index 09809089..077daf5d 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -184,13 +184,13 @@ struct DivNoteEvent { struct DivDispatchContainer { DivDispatch* dispatch; blip_buffer_t* bb[DIV_MAX_OUTPUTS]; - size_t bbInLen, runtotal, runLeft, runPos, lastAvail; + size_t bbInLen, runtotal, runLeft, runPos, lastAvail, lastCount; int temp[DIV_MAX_OUTPUTS], prevSample[DIV_MAX_OUTPUTS]; short* bbInMapped[DIV_MAX_OUTPUTS]; short* bbIn[DIV_MAX_OUTPUTS]; short* bbOut[DIV_MAX_OUTPUTS]; bool lowQuality, dcOffCompensation; - unsigned char rateMul, runPosSub; + unsigned char rateMul, runPosSub, fillSub; double rateMemory; void setRates(double gotRate); @@ -209,10 +209,12 @@ struct DivDispatchContainer { runLeft(0), runPos(0), lastAvail(0), + lastCount(0), lowQuality(false), dcOffCompensation(false), rateMul(0), runPosSub(0), + fillSub(0), rateMemory(0.0) { memset(bb,0,DIV_MAX_OUTPUTS*sizeof(blip_buffer_t*)); memset(temp,0,DIV_MAX_OUTPUTS*sizeof(int)); From 670c681a716e972e290cb154187559ece3497c10 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 16 Apr 2023 14:45:05 -0500 Subject: [PATCH 15/40] remove debug messages --- src/engine/dispatchContainer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index d98c450e..44b58b40 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -158,12 +158,12 @@ void DivDispatchContainer::acquire(size_t offset, size_t count) { count>>=rateMul; if (offset!=0 && offset!=lastCount) { - logW("Shit!"); + logW("Shit! %d %d",offset,lastCount); } lastCount=offset+count; - logV("got: from %d to %d",offset,offset+count-1); + //logV("got: from %d to %d",offset,offset+count-1); } for (int i=0; i Date: Sun, 16 Apr 2023 14:50:53 -0500 Subject: [PATCH 16/40] opti --- src/engine/dispatchContainer.cpp | 70 +++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index 44b58b40..b73aea2f 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -201,32 +201,56 @@ void DivDispatchContainer::fillBuf(size_t runtotal, size_t offset, size_t size) prevSample[i]=bbIn[i][0]; } } - if (lowQuality) { - for (int i=0; i Date: Sun, 16 Apr 2023 14:54:58 -0500 Subject: [PATCH 17/40] RF5C68: 32 issue #1067 --- src/engine/platform/rf5c68.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index fbf8e00d..7be43801 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -151,8 +151,8 @@ void DivPlatformRF5C68::tick(bool sysTick) { if (s->isLoopable()) { loop=start+s->loopStart; } - start=MIN(start,getSampleMemCapacity()-31); - loop=MIN(loop,getSampleMemCapacity()-31); + start=MIN(start,getSampleMemCapacity()-32); + loop=MIN(loop,getSampleMemCapacity()-32); rWrite(8,keyoff); // force keyoff first chWrite(i,6,start>>8); chWrite(i,4,loop&0xff); @@ -425,7 +425,7 @@ void DivPlatformRF5C68::renderSamples(int sysID) { } int length=s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT); - int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-31,length); + int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-32,length); if (actualLength>0) { sampleOffRFC[i]=memPos; for (int j=0; j0)?(val|0x80):(0-val); } // write end of sample marker - memset(&sampleMem[memPos],0xff,31); - memPos+=31; + memset(&sampleMem[memPos],0xff,32); + memPos+=32; } if (actualLength Date: Sun, 16 Apr 2023 15:12:51 -0500 Subject: [PATCH 18/40] Revert "crash" This reverts commit 7e6a96deb54a3bd50f541bcc1b4f5dd8bf7ed246. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e85c4de7..20e26737 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ defaults: shell: bash env: - BUILD_TYPE: Debug + BUILD_TYPE: RelWithDebInfo jobs: build: From c6553f11e8093df141f7a59582a7c289cde10b37 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 16 Apr 2023 17:29:01 -0500 Subject: [PATCH 19/40] Revert "Merge branch 'blipWork'" This reverts commit 41cbdf792481cdddd42ed4abf123c1a8c6f98e44, reversing changes made to 149d4ce99c6f2cd28ea67ba1cd3a0d07eb9336e4. --- src/engine/dispatchContainer.cpp | 102 ++++++------------------------- src/engine/engine.h | 7 +-- 2 files changed, 18 insertions(+), 91 deletions(-) diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index b73aea2f..c30d7f23 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -86,16 +86,9 @@ void DivDispatchContainer::setRates(double gotRate) { int outs=dispatch->getOutputCount(); - int rate=dispatch->rate; - rateMul=0; - while (rateMul<8 && raterate,gotRate); } rateMemory=gotRate; } @@ -127,13 +120,7 @@ void DivDispatchContainer::grow(size_t size) { logE("not enough memory!"); \ return; \ } \ - int rate=dispatch->rate; \ - rateMul=0; \ - while (rateMul<8 && raterate,rateMemory); \ \ if (bbIn[i]==NULL) bbIn[i]=new short[bbInLen]; \ if (bbOut[i]==NULL) bbOut[i]=new short[bbInLen]; \ @@ -147,25 +134,6 @@ void DivDispatchContainer::grow(size_t size) { void DivDispatchContainer::acquire(size_t offset, size_t count) { CHECK_MISSING_BUFS; - if (rateMul) { - //logV("req: from %d to %d",offset,offset+count-1); - offset+=runPosSub; - size_t oldCount=count; - runPosSub=(runPosSub+oldCount)&((1<>=rateMul; - count>>=rateMul; - - if (offset!=0 && offset!=lastCount) { - logW("Shit! %d %d",offset,lastCount); - } - - lastCount=offset+count; - - //logV("got: from %d to %d",offset,offset+count-1); - } - for (int i=0; i=outs) { bbInMapped[i]=NULL; @@ -192,8 +160,6 @@ void DivDispatchContainer::flush(size_t count) { void DivDispatchContainer::fillBuf(size_t runtotal, size_t offset, size_t size) { CHECK_MISSING_BUFS; - int step=1<0) { dcOffCompensation=false; for (int i=0; igetDCOffRequired()) { dcOffCompensation=true; } diff --git a/src/engine/engine.h b/src/engine/engine.h index 077daf5d..d31de903 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -184,13 +184,12 @@ struct DivNoteEvent { struct DivDispatchContainer { DivDispatch* dispatch; blip_buffer_t* bb[DIV_MAX_OUTPUTS]; - size_t bbInLen, runtotal, runLeft, runPos, lastAvail, lastCount; + size_t bbInLen, runtotal, runLeft, runPos, lastAvail; int temp[DIV_MAX_OUTPUTS], prevSample[DIV_MAX_OUTPUTS]; short* bbInMapped[DIV_MAX_OUTPUTS]; short* bbIn[DIV_MAX_OUTPUTS]; short* bbOut[DIV_MAX_OUTPUTS]; bool lowQuality, dcOffCompensation; - unsigned char rateMul, runPosSub, fillSub; double rateMemory; void setRates(double gotRate); @@ -209,12 +208,8 @@ struct DivDispatchContainer { runLeft(0), runPos(0), lastAvail(0), - lastCount(0), lowQuality(false), dcOffCompensation(false), - rateMul(0), - runPosSub(0), - fillSub(0), rateMemory(0.0) { memset(bb,0,DIV_MAX_OUTPUTS*sizeof(blip_buffer_t*)); memset(temp,0,DIV_MAX_OUTPUTS*sizeof(int)); From b661a6f9cf67acb3b957a093d0bcc03127b4a125 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 17 Apr 2023 00:22:37 -0500 Subject: [PATCH 20/40] disable console now --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d405d472..78a68aa8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -792,7 +792,7 @@ endif() if(ANDROID AND NOT TERMUX) add_library(furnace SHARED ${USED_SOURCES}) elseif(WIN32) - add_executable(furnace ${USED_SOURCES}) + add_executable(furnace WIN32 ${USED_SOURCES}) else() add_executable(furnace ${USED_SOURCES}) endif() From c0c3d03dd1f42eb2f07ef4d5bfaae06bb747902b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 17 Apr 2023 19:08:14 -0500 Subject: [PATCH 21/40] understand EDxx in one tick gap issue #1071 --- src/engine/playback.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 808e2b15..fbbd1302 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1125,11 +1125,23 @@ void DivEngine::nextRow() { bool wantPreNote=false; if (disCont[dispatchOfChan[i]].dispatch!=NULL) { wantPreNote=disCont[dispatchOfChan[i]].dispatch->getWantPreNote(); - if (wantPreNote) dispatchCmd(DivCommand(DIV_CMD_PRE_NOTE,i,ticks)); + if (wantPreNote) { + int addition=0; + for (int j=0; jdata[curRow][4+(j<<1)]==0xed) { + if (pat->data[curRow][5+(j<<1)]>0) { + addition=pat->data[curRow][5+(j<<1)]; + break; + } + } + } + dispatchCmd(DivCommand(DIV_CMD_PRE_NOTE,i,ticks+addition)); + } } if (song.oneTickCut) { bool doPrepareCut=true; + int addition=0; for (int j=0; jdata[curRow][4+(j<<1)]==0x03) { @@ -1142,8 +1154,14 @@ void DivEngine::nextRow() { break; } } + if (pat->data[curRow][4+(j<<1)]==0xed) { + if (pat->data[curRow][5+(j<<1)]>0) { + addition=pat->data[curRow][5+(j<<1)]; + break; + } + } } - if (doPrepareCut && !wantPreNote && chan[i].cut<=0) chan[i].cut=ticks; + if (doPrepareCut && !wantPreNote && chan[i].cut<=0) chan[i].cut=ticks+addition; } } } From 8b39f00d730b4cc1da091b72801521e741ac17ac Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 20 Apr 2023 02:32:20 -0500 Subject: [PATCH 22/40] fix crash when resampling using BLEP algo if data16 had nothing --- src/engine/sample.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index f882a3d0..d46ced4f 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -892,10 +892,10 @@ bool DivSample::resampleBlep(double r) { } } for (int i=0; i127) result=127; - data16[i]=round(result); + data8[i]=round(result); } } delete[] floatData; From dab3a9573482c71fa0af53a05cd94fb5a2faa61d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 20 Apr 2023 02:41:41 -0500 Subject: [PATCH 23/40] but QSound ADPCM is already there... --- papers/doc/7-systems/qsound.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/doc/7-systems/qsound.md b/papers/doc/7-systems/qsound.md index 7089ec0e..81bfe4b9 100644 --- a/papers/doc/7-systems/qsound.md +++ b/papers/doc/7-systems/qsound.md @@ -8,7 +8,7 @@ because the chip lacks sample interpolation, it is recommended that you try to p the QSound chip also has a small echo buffer, somewhat similar to the SNES, although with a very basic (and non-adjustable) filter. it is however possible to adjust the feedback and length of the echo buffer (the initial values can be set in the "configure chip" option in the file menu or the chip manager). -there are also 3 ADPCM channels, however they cannot be used in Furnace yet. they have been reserved in case this feature is added later. ADPCM samples are limited to 8012 Hz. +there are also 3 ADPCM channels. ADPCM samples are fixed to 8012 Hz. # effects From 381147fc1f541ff2f7de42f20067b00e327cbb7c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 20 Apr 2023 03:43:35 -0500 Subject: [PATCH 24/40] GUI: fix some sliders not being right-clickable issue #1065 --- src/gui/insEdit.cpp | 34 +++++++++++++++++----------------- src/gui/waveEdit.cpp | 16 ++++++++-------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 6ab5b23c..8ecadcb4 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1592,7 +1592,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail if (CWSliderInt("##MAAR",&i.macro->val[2],0,255)) { PARAMETER if (i.macro->val[2]<0) i.macro->val[2]=0; if (i.macro->val[2]>255) i.macro->val[2]=255; - } + } rightClickable ImGui::TableNextColumn(); ImGui::Text("Sustain"); @@ -1601,7 +1601,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail if (CWSliderInt("##MASL",&i.macro->val[5],0,255)) { PARAMETER if (i.macro->val[5]<0) i.macro->val[5]=0; if (i.macro->val[5]>255) i.macro->val[5]=255; - } + } rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -1611,7 +1611,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail if (CWSliderInt("##MAHT",&i.macro->val[3],0,255)) { PARAMETER if (i.macro->val[3]<0) i.macro->val[3]=0; if (i.macro->val[3]>255) i.macro->val[3]=255; - } + } rightClickable ImGui::TableNextColumn(); ImGui::Text("SusTime"); @@ -1620,7 +1620,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail if (CWSliderInt("##MAST",&i.macro->val[6],0,255)) { PARAMETER if (i.macro->val[6]<0) i.macro->val[6]=0; if (i.macro->val[6]>255) i.macro->val[6]=255; - } + } rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -1630,7 +1630,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail if (CWSliderInt("##MADR",&i.macro->val[4],0,255)) { PARAMETER if (i.macro->val[4]<0) i.macro->val[4]=0; if (i.macro->val[4]>255) i.macro->val[4]=255; - } + } rightClickable ImGui::TableNextColumn(); ImGui::Text("SusDecay"); @@ -1639,7 +1639,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail if (CWSliderInt("##MASR",&i.macro->val[7],0,255)) { PARAMETER if (i.macro->val[7]<0) i.macro->val[7]=0; if (i.macro->val[7]>255) i.macro->val[7]=255; - } + } rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -1652,7 +1652,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail if (CWSliderInt("##MARR",&i.macro->val[8],0,255)) { PARAMETER if (i.macro->val[8]<0) i.macro->val[8]=0; if (i.macro->val[8]>255) i.macro->val[8]=255; - } + } rightClickable ImGui::EndTable(); } @@ -1695,7 +1695,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail if (CWSliderInt("##MLSpeed",&i.macro->val[11],0,255)) { PARAMETER if (i.macro->val[11]<0) i.macro->val[11]=0; if (i.macro->val[11]>255) i.macro->val[11]=255; - } + } rightClickable ImGui::TableNextColumn(); ImGui::Text("Phase"); @@ -1704,7 +1704,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail if (CWSliderInt("##MLPhase",&i.macro->val[13],0,1023)) { PARAMETER if (i.macro->val[13]<0) i.macro->val[13]=0; if (i.macro->val[13]>1023) i.macro->val[13]=1023; - } + } rightClickable ImGui::TableNextColumn(); ImGui::Text("Shape"); @@ -1713,7 +1713,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail if (CWSliderInt("##MLShape",&i.macro->val[12],0,2,macroLFOShapes[i.macro->val[12]&3])) { PARAMETER if (i.macro->val[12]<0) i.macro->val[12]=0; if (i.macro->val[12]>2) i.macro->val[12]=2; - } + } rightClickable ImGui::EndTable(); } @@ -4799,7 +4799,7 @@ void FurnaceGUI::drawInsEdit() { // filter ImGui::TableNextRow(); ImGui::TableNextColumn(); - P(CWSliderScalar("Filter 4,3 Mode",ImGuiDataType_U8,&ins->es5506.filter.mode,&_ZERO,&_THREE,es5506FilterModes[ins->es5506.filter.mode&3])); rightClickable + P(CWSliderScalar("Filter Mode",ImGuiDataType_U8,&ins->es5506.filter.mode,&_ZERO,&_THREE,es5506FilterModes[ins->es5506.filter.mode&3])); ImGui::TableNextRow(); ImGui::TableNextColumn(); P(CWSliderScalar("Filter K1",ImGuiDataType_U16,&ins->es5506.filter.k1,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable @@ -4883,17 +4883,17 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextRow(); ImGui::TableNextColumn(); - P(CWVSliderScalar("##Attack Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.ar,&_ZERO,&_FIFTEEN)); + P(CWVSliderScalar("##Attack Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.ar,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); - P(CWVSliderScalar("##Decay 1 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d1r,&_ZERO,&_FIFTEEN)); + P(CWVSliderScalar("##Decay 1 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d1r,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); - P(CWVSliderScalar("##Decay Level",sliderSize,ImGuiDataType_U8,&ins->multipcm.dl,&_ZERO,&_FIFTEEN)); + P(CWVSliderScalar("##Decay Level",sliderSize,ImGuiDataType_U8,&ins->multipcm.dl,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); - P(CWVSliderScalar("##Decay 2 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d2r,&_ZERO,&_FIFTEEN)); + P(CWVSliderScalar("##Decay 2 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d2r,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); - P(CWVSliderScalar("##Release Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.rr,&_ZERO,&_FIFTEEN)); + P(CWVSliderScalar("##Release Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.rr,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); - P(CWVSliderScalar("##Rate Correction",sliderSize,ImGuiDataType_U8,&ins->multipcm.rc,&_ZERO,&_FIFTEEN)); + P(CWVSliderScalar("##Rate Correction",sliderSize,ImGuiDataType_U8,&ins->multipcm.rc,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); drawFMEnv(0,ins->multipcm.ar,ins->multipcm.d1r,ins->multipcm.d2r,ins->multipcm.rr,ins->multipcm.dl,0,0,0,127,15,15,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); ImGui::EndTable(); diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 0530a2d2..dce89bc9 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -598,7 +598,7 @@ void FurnaceGUI::drawWaveEdit() { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderFloat("##WGDuty",&waveGenDuty,0.0f,1.0f)) { doGenerateWave(); - } + } rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -607,7 +607,7 @@ void FurnaceGUI::drawWaveEdit() { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderInt("##WGExp",&waveGenPower,1,8)) { doGenerateWave(); - } + } rightClickable ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -616,7 +616,7 @@ void FurnaceGUI::drawWaveEdit() { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderFloat("##WGXOR",&waveGenInvertPoint,0.0f,1.0f)) { doGenerateWave(); - } + } rightClickable ImGui::EndTable(); } @@ -636,7 +636,7 @@ void FurnaceGUI::drawWaveEdit() { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderFloat("##WGAmp",&waveGenAmp[i],-1.0f,1.0f)) { doGenerateWave(); - } + } rightClickable if (ImGui::IsItemClicked(ImGuiMouseButton_Middle)) { waveGenAmp[i]=0.0f; doGenerateWave(); @@ -647,7 +647,7 @@ void FurnaceGUI::drawWaveEdit() { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (CWSliderFloat("##WGPhase",&waveGenPhase[i],0.0f,1.0f)) { doGenerateWave(); - } + } rightClickable if (ImGui::IsItemClicked(ImGuiMouseButton_Middle)) { waveGenPhase[i]=0.0f; doGenerateWave(); @@ -690,7 +690,7 @@ void FurnaceGUI::drawWaveEdit() { ImGui::PushID(i); if (CWSliderFloat("##WGTL",&waveGenTL[i],0.0f,1.0f)) { doGenerateWave(); - } + } rightClickable ImGui::PopID(); ImGui::TableNextColumn(); @@ -698,7 +698,7 @@ void FurnaceGUI::drawWaveEdit() { ImGui::PushID(i); if (CWSliderInt("##WGMULT",&waveGenMult[i],1,16)) { doGenerateWave(); - } + } rightClickable ImGui::PopID(); ImGui::TableNextColumn(); @@ -706,7 +706,7 @@ void FurnaceGUI::drawWaveEdit() { ImGui::PushID(i); if (CWSliderInt("##WGFB",&waveGenFB[i],0,7)) { doGenerateWave(); - } + } rightClickable ImGui::PopID(); } From 6ec9696a505fdbc07e1120e66af9e2c786d293ae Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 20 Apr 2023 04:01:00 -0500 Subject: [PATCH 25/40] GUI: allow right-clicking vertical sliders! --- extern/imgui_patched/imgui_widgets.cpp | 30 +++++++++--- src/gui/insEdit.cpp | 64 +++++++++++++------------- src/gui/osc.cpp | 4 +- 3 files changed, 58 insertions(+), 40 deletions(-) diff --git a/extern/imgui_patched/imgui_widgets.cpp b/extern/imgui_patched/imgui_widgets.cpp index 737c6e09..45bfd82c 100644 --- a/extern/imgui_patched/imgui_widgets.cpp +++ b/extern/imgui_patched/imgui_widgets.cpp @@ -3112,8 +3112,9 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; ItemSize(bb, style.FramePadding.y); - if (!ItemAdd(frame_bb, id, NULL, ImGuiItemFlags_NoInertialScroll)) + if (!ItemAdd(frame_bb, id, NULL, (temp_input_allowed ? ImGuiItemFlags_Inputable : 0) | ImGuiItemFlags_NoInertialScroll)) return false; // Default format string when passing NULL @@ -3122,13 +3123,29 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) // (FIXME-LEGACY: Patch old "%.0f" format string to use "%d", read function more details.) format = PatchFormatStringFloatToInt(format); + // Tabbing or CTRL-clicking on Slider turns it into an input box const bool hovered = ItemHoverable(frame_bb, id); - if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavActivateInputId == id) + bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); + if (!temp_input_is_active) { - SetActiveID(id, window); - SetFocusID(id, window); - FocusWindow(window); - g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + const bool input_requested_by_tabbing = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; + const bool clicked = (hovered && g.IO.MouseClicked[0]); + if (input_requested_by_tabbing || clicked || g.NavActivateId == id || g.NavActivateInputId == id) + { + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + if (temp_input_allowed && (input_requested_by_tabbing || (clicked && g.IO.KeyCtrl) || g.NavActivateInputId == id)) + temp_input_is_active = true; + } + } + + if (temp_input_is_active) + { + // Only clamp CTRL+Click input when ImGuiSliderFlags_AlwaysClamp is set + const bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 0; + return TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL); } // Draw frame @@ -3154,6 +3171,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); return value_changed; } diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 8ecadcb4..6f6839a7 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1464,7 +1464,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail if (!i.isBitfield) { if (settings.oldMacroVSlider) { ImGui::SameLine(0.0f); - if (ImGui::VSliderInt("IMacroVScroll",ImVec2(20.0f*dpiScale,i.height*dpiScale),&i.macro->vScroll,0,(i.max-i.min)-i.macro->vZoom,"")) { + if (ImGui::VSliderInt("IMacroVScroll",ImVec2(20.0f*dpiScale,i.height*dpiScale),&i.macro->vScroll,0,(i.max-i.min)-i.macro->vZoom,"",ImGuiSliderFlags_NoInput)) { if (i.macro->vScroll<0) i.macro->vScroll=0; if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; } @@ -2839,37 +2839,37 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); op.ar&=maxArDr; CENTER_VSLIDER; - P(CWVSliderScalar("##AR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO)); + P(CWVSliderScalar("##AR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO)); rightClickable ImGui::TableNextColumn(); op.dr&=maxArDr; CENTER_VSLIDER; - P(CWVSliderScalar("##DR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO)); + P(CWVSliderScalar("##DR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO)); rightClickable if (settings.susPosition==0) { ImGui::TableNextColumn(); op.sl&=15; CENTER_VSLIDER; - P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); + P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable } if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableNextColumn(); op.d2r&=31; CENTER_VSLIDER; - P(CWVSliderScalar("##D2R",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO)); + P(CWVSliderScalar("##D2R",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO)); rightClickable } ImGui::TableNextColumn(); op.rr&=15; CENTER_VSLIDER; - P(CWVSliderScalar("##RR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO)); + P(CWVSliderScalar("##RR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO)); rightClickable if (settings.susPosition==1) { ImGui::TableNextColumn(); op.sl&=15; CENTER_VSLIDER; - P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); + P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable } ImGui::TableNextColumn(); @@ -2878,38 +2878,38 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); op.tl&=maxTl; CENTER_VSLIDER; - P(CWVSliderScalar("##TL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); + P(CWVSliderScalar("##TL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); rightClickable ImGui::TableNextColumn(); CENTER_VSLIDER; if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { - P(CWVSliderScalar("##RS",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE)); + P(CWVSliderScalar("##RS",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE)); rightClickable } else { int ksl=ins->type==DIV_INS_OPLL?op.ksl:kslMap[op.ksl&3]; if (CWVSliderInt("##KSL",ImVec2(20.0f*dpiScale,sliderHeight),&ksl,0,3)) { op.ksl=(ins->type==DIV_INS_OPLL?ksl:kslMap[ksl&3]); PARAMETER; - } + } rightClickable } if (ins->type==DIV_INS_OPZ) { ImGui::TableNextColumn(); CENTER_VSLIDER; - P(CWVSliderScalar("##EGS",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE)); + P(CWVSliderScalar("##EGS",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); CENTER_VSLIDER; - P(CWVSliderScalar("##REV",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dam,&_ZERO,&_SEVEN)); + P(CWVSliderScalar("##REV",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dam,&_ZERO,&_SEVEN)); rightClickable } ImGui::TableNextColumn(); CENTER_VSLIDER; - P(CWVSliderScalar("##MULT",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN)); + P(CWVSliderScalar("##MULT",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN)); rightClickable if (ins->type==DIV_INS_OPZ) { ImGui::TableNextColumn(); CENTER_VSLIDER; - P(CWVSliderScalar("##FINE",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN)); + P(CWVSliderScalar("##FINE",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN)); rightClickable } if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { @@ -2920,7 +2920,7 @@ void FurnaceGUI::drawInsEdit() { if (detune<-3) detune=-3; if (detune>7) detune=7; op.dt=detuneUnmap[settings.unsignedDetune?1:0][detune+3]; - } + } rightClickable if (ins->type!=DIV_INS_FM) { ImGui::TableNextColumn(); @@ -3169,19 +3169,19 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); op.ar&=maxArDr; - P(CWVSliderScalar("##AR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO)); + P(CWVSliderScalar("##AR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO)); rightClickable ImGui::SameLine(); op.dr&=maxArDr; float textX_DR=ImGui::GetCursorPosX(); - P(CWVSliderScalar("##DR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO)); + P(CWVSliderScalar("##DR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO)); rightClickable 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)); + P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable } float textX_D2R=0.0f; @@ -3189,19 +3189,19 @@ void FurnaceGUI::drawInsEdit() { ImGui::SameLine(); op.d2r&=31; textX_D2R=ImGui::GetCursorPosX(); - P(CWVSliderScalar("##D2R",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO)); + P(CWVSliderScalar("##D2R",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO)); rightClickable } ImGui::SameLine(); op.rr&=15; float textX_RR=ImGui::GetCursorPosX(); - P(CWVSliderScalar("##RR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO)); + P(CWVSliderScalar("##RR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO)); rightClickable 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)); + P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable } ImVec2 prevCurPos=ImGui::GetCursorPos(); @@ -3500,7 +3500,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); op.tl&=maxTl; - P(CWVSliderScalar("##TL",ImVec2(ImGui::GetFrameHeight(),sliderHeight-((ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM)?(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 || ins->type==DIV_INS_OPM)?(ImGui::GetFrameHeightWithSpacing()+ImGui::CalcTextSize(FM_SHORT_NAME(FM_AM)).y+ImGui::GetStyle().ItemSpacing.y):0.0f)),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); rightClickable if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_AM)); @@ -4299,13 +4299,13 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextRow(); ImGui::TableNextColumn(); - P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->c64.a,&_ZERO,&_FIFTEEN)); + P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->c64.a,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); - P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->c64.d,&_ZERO,&_FIFTEEN)); + P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->c64.d,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); - P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->c64.s,&_ZERO,&_FIFTEEN)); + P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->c64.s,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); - P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->c64.r,&_ZERO,&_FIFTEEN)); + P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->c64.r,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); drawFMEnv(0,16-ins->c64.a,16-ins->c64.d,15-ins->c64.r,15-ins->c64.r,15-ins->c64.s,0,0,0,15,16,15,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); @@ -4951,17 +4951,17 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextRow(); ImGui::TableNextColumn(); - P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->snes.a,&_ZERO,&_FIFTEEN)); + P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->snes.a,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); - P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->snes.d,&_ZERO,&_SEVEN)); + P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->snes.d,&_ZERO,&_SEVEN)); rightClickable ImGui::TableNextColumn(); - P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->snes.s,&_ZERO,&_SEVEN)); + P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->snes.s,&_ZERO,&_SEVEN)); rightClickable if (ins->snes.sus) { ImGui::TableNextColumn(); - P(CWVSliderScalar("##Decay2",sliderSize,ImGuiDataType_U8,&ins->snes.d2,&_ZERO,&_THIRTY_ONE)); + P(CWVSliderScalar("##Decay2",sliderSize,ImGuiDataType_U8,&ins->snes.d2,&_ZERO,&_THIRTY_ONE)); rightClickable } ImGui::TableNextColumn(); - P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->snes.r,&_ZERO,&_THIRTY_ONE)); + P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->snes.r,&_ZERO,&_THIRTY_ONE)); rightClickable ImGui::TableNextColumn(); drawFMEnv(0,ins->snes.a+1,1+ins->snes.d*2,ins->snes.sus?ins->snes.d2:ins->snes.r,ins->snes.sus?ins->snes.r:31,(14-ins->snes.s*2),(ins->snes.r==0 || (ins->snes.sus && ins->snes.d2==0)),0,0,7,16,31,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); @@ -5023,7 +5023,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); unsigned char gainMax=(ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)?127:31; if (ins->snes.gain>gainMax) ins->snes.gain=gainMax; - P(CWVSliderScalar("##Gain",sliderSize,ImGuiDataType_U8,&ins->snes.gain,&_ZERO,&gainMax)); + P(CWVSliderScalar("##Gain",sliderSize,ImGuiDataType_U8,&ins->snes.gain,&_ZERO,&gainMax)); rightClickable ImGui::TableNextColumn(); ImGui::Text("Envelope goes here..."); diff --git a/src/gui/osc.cpp b/src/gui/osc.cpp index e5bc09e4..7f783dde 100644 --- a/src/gui/osc.cpp +++ b/src/gui/osc.cpp @@ -100,7 +100,7 @@ void FurnaceGUI::drawOsc() { if (ImGui::VSliderFloat("##OscZoom",ImVec2(20.0f*dpiScale,ImGui::GetContentRegionAvail().y),&oscZoom,0.5,2.0)) { if (oscZoom<0.5) oscZoom=0.5; if (oscZoom>2.0) oscZoom=2.0; - } + } rightClickable if (ImGui::IsItemHovered()) { ImGui::SetTooltip("zoom: %.2fx (%.1fdB)",oscZoom,20.0*log10(oscZoom*2.0)); } @@ -111,7 +111,7 @@ void FurnaceGUI::drawOsc() { if (ImGui::VSliderFloat("##OscWinSize",ImVec2(20.0f*dpiScale,ImGui::GetContentRegionAvail().y),&oscWindowSize,5.0,100.0)) { if (oscWindowSize<5.0) oscWindowSize=5.0; if (oscWindowSize>100.0) oscWindowSize=100.0; - } + } rightClickable if (ImGui::IsItemHovered()) { ImGui::SetTooltip("window size: %.1fms",oscWindowSize); } From c8df7084f4cffcb7db348b288f734c2be0645bbc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 20 Apr 2023 04:16:56 -0500 Subject: [PATCH 26/40] VGM export: write Hz when appropriate --- src/engine/vgmOps.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index 01833d26..1960b9a3 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -1068,6 +1068,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p bool trailing=false; bool beenOneLoopAlready=false; + bool mayWriteRate=(fmod(curSubSong->hz,1.0)<0.00001 || fmod(curSubSong->hz,1.0)>0.99999); int countDown=MAX(0,trailingTicks)+1; for (int i=0; iwriteI(0); w->writeI(0); } + if (mayWriteRate) { + w->writeI(round(curSubSong->hz)); + } w->seek(0x34,SEEK_SET); w->writeI(songOff-0x34); if (version>=0x170) { From f3a71c6eba3a8cb6ddf00ee9d39d352676195c65 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 24 Apr 2023 05:25:56 -0500 Subject: [PATCH 27/40] loooool --- papers/doc/3-pattern/effects.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/papers/doc/3-pattern/effects.md b/papers/doc/3-pattern/effects.md index 9d784d38..54d18000 100644 --- a/papers/doc/3-pattern/effects.md +++ b/papers/doc/3-pattern/effects.md @@ -121,8 +121,8 @@ ID | macro 33 | KSR ---|----------------------------- 40 | operator 2 macros -60 | operator 2 macros -80 | operator 2 macros +60 | operator 3 macros +80 | operator 4 macros the interpretation of duty, wave and extra macros depends on chip/instrument type: From 24487936de9058a18d589d930d1eb33fb13a0858 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 27 Apr 2023 01:23:54 -0500 Subject: [PATCH 28/40] GUI: collapse/expand pattern/song --- src/engine/pattern.cpp | 14 ++- src/engine/pattern.h | 5 + src/gui/doAction.cpp | 26 +++- src/gui/editing.cpp | 272 +++++++++++++++++++++++++++++++++++------ src/gui/gui.cpp | 28 +++-- src/gui/gui.h | 29 ++++- 6 files changed, 315 insertions(+), 59 deletions(-) diff --git a/src/engine/pattern.cpp b/src/engine/pattern.cpp index f7b833e1..ea0cca7e 100644 --- a/src/engine/pattern.cpp +++ b/src/engine/pattern.cpp @@ -23,11 +23,7 @@ static DivPattern emptyPat; DivPattern::DivPattern() { - memset(data,-1,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short)); - for (int i=0; idata,data,sizeof(data)); } +void DivPattern::clear() { + memset(data,-1,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short)); + for (int i=0; igetTotalChannelCount()-1; + selEndPat.xFine=2+e->curPat[selEndPat.xCoarse].effectCols*2; + selEndPat.y=e->curSubSong->patLen-1; + doCollapse(2,SelectionPoint(0,0,0),selEndPat); break; - case GUI_ACTION_PAT_EXPAND_PAT: // TODO + } + case GUI_ACTION_PAT_EXPAND_PAT: { + SelectionPoint selEndPat; + selEndPat.xCoarse=e->getTotalChannelCount()-1; + selEndPat.xFine=2+e->curPat[selEndPat.xCoarse].effectCols*2; + selEndPat.y=e->curSubSong->patLen-1; + doExpand(2,SelectionPoint(0,0,0),selEndPat); break; - case GUI_ACTION_PAT_COLLAPSE_SONG: // TODO + } + case GUI_ACTION_PAT_COLLAPSE_SONG: + doCollapseSong(2); break; - case GUI_ACTION_PAT_EXPAND_SONG: // TODO + case GUI_ACTION_PAT_EXPAND_SONG: + doExpandSong(2); break; case GUI_ACTION_PAT_LATCH: // TODO break; diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index 77d76da2..1a2b1b11 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -67,6 +67,9 @@ void FurnaceGUI::prepareUndo(ActionType action) { e->curPat[i].getPattern(e->curOrders->ord[i][curOrder],false)->copyOn(oldPat[i]); } break; + case GUI_UNDO_PATTERN_COLLAPSE_SONG: + case GUI_UNDO_PATTERN_EXPAND_SONG: // TODO + break; case GUI_UNDO_REPLACE: // this is handled by doReplace() break; } @@ -130,6 +133,9 @@ void FurnaceGUI::makeUndo(ActionType action) { doPush=true; } break; + case GUI_UNDO_PATTERN_COLLAPSE_SONG: + case GUI_UNDO_PATTERN_EXPAND_SONG: // TODO + break; case GUI_UNDO_REPLACE: // this is handled by doReplace() break; } @@ -839,50 +845,56 @@ void FurnaceGUI::doFlip() { makeUndo(GUI_UNDO_PATTERN_FLIP); } -void FurnaceGUI::doCollapse(int divider) { +void FurnaceGUI::doCollapse(int divider, const SelectionPoint& sStart, const SelectionPoint& sEnd) { + if (divider<2) return; + if (e->curSubSong->patLencurSubSong->chanShow[iCoarse]) continue; DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true); - for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarsecurPat[iCoarse].effectCols*2 && (iCoarsedata[j][0]; } patBuffer.data[j][iFine+1]=pat->data[j][iFine+1]; } - for (int j=0; j<=selEnd.y-selStart.y; j++) { - if (j*divider>=selEnd.y-selStart.y) { + for (int j=0; j<=sEnd.y-sStart.y; j++) { + if (j*divider>=sEnd.y-sStart.y) { if (iFine==0) { - pat->data[j+selStart.y][0]=0; - pat->data[j+selStart.y][1]=0; + pat->data[j+sStart.y][0]=0; + pat->data[j+sStart.y][1]=0; } else { - pat->data[j+selStart.y][iFine+1]=-1; + pat->data[j+sStart.y][iFine+1]=-1; } } else { if (iFine==0) { - pat->data[j+selStart.y][0]=patBuffer.data[j*divider+selStart.y][0]; + pat->data[j+sStart.y][0]=patBuffer.data[j*divider+sStart.y][0]; } - pat->data[j+selStart.y][iFine+1]=patBuffer.data[j*divider+selStart.y][iFine+1]; + pat->data[j+sStart.y][iFine+1]=patBuffer.data[j*divider+sStart.y][iFine+1]; if (iFine==0) { for (int k=1; k=selEnd.y-selStart.y) break; - if (!(pat->data[j+selStart.y][0]==0 && pat->data[j+selStart.y][1]==0)) break; - pat->data[j+selStart.y][0]=patBuffer.data[j*divider+selStart.y+k][0]; - pat->data[j+selStart.y][1]=patBuffer.data[j*divider+selStart.y+k][1]; + if ((j*divider+k)>=sEnd.y-sStart.y) break; + if (!(pat->data[j+sStart.y][0]==0 && pat->data[j+sStart.y][1]==0)) break; + pat->data[j+sStart.y][0]=patBuffer.data[j*divider+sStart.y+k][0]; + pat->data[j+sStart.y][1]=patBuffer.data[j*divider+sStart.y+k][1]; } } else { for (int k=1; k=selEnd.y-selStart.y) break; - if (pat->data[j+selStart.y][iFine+1]!=-1) break; - pat->data[j+selStart.y][iFine+1]=patBuffer.data[j*divider+selStart.y+k][iFine+1]; + if ((j*divider+k)>=sEnd.y-sStart.y) break; + if (pat->data[j+sStart.y][iFine+1]!=-1) break; + pat->data[j+sStart.y][iFine+1]=patBuffer.data[j*divider+sStart.y+k][iFine+1]; } } } @@ -894,41 +906,41 @@ void FurnaceGUI::doCollapse(int divider) { makeUndo(GUI_UNDO_PATTERN_COLLAPSE); } -void FurnaceGUI::doExpand(int multiplier) { - if (multiplier<1) return; +void FurnaceGUI::doExpand(int multiplier, const SelectionPoint& sStart, const SelectionPoint& sEnd) { + if (multiplier<2) return; finishSelection(); prepareUndo(GUI_UNDO_PATTERN_EXPAND); DivPattern patBuffer; - int iCoarse=selStart.xCoarse; - int iFine=selStart.xFine; - for (; iCoarse<=selEnd.xCoarse; iCoarse++) { + int iCoarse=sStart.xCoarse; + int iFine=sStart.xFine; + for (; iCoarse<=sEnd.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 && (iCoarsecurPat[iCoarse].effectCols*2 && (iCoarsedata[j][0]; } patBuffer.data[j][iFine+1]=pat->data[j][iFine+1]; } - for (int j=0; j<=(selEnd.y-selStart.y)*multiplier; j++) { - if ((j+selStart.y)>=e->curSubSong->patLen) break; + for (int j=0; j<=(sEnd.y-sStart.y)*multiplier; j++) { + if ((j+sStart.y)>=e->curSubSong->patLen) break; if ((j%multiplier)!=0) { if (iFine==0) { - pat->data[j+selStart.y][0]=0; - pat->data[j+selStart.y][1]=0; + pat->data[j+sStart.y][0]=0; + pat->data[j+sStart.y][1]=0; } else { - pat->data[j+selStart.y][iFine+1]=-1; + pat->data[j+sStart.y][iFine+1]=-1; } continue; } if (iFine==0) { - pat->data[j+selStart.y][0]=patBuffer.data[j/multiplier+selStart.y][0]; + pat->data[j+sStart.y][0]=patBuffer.data[j/multiplier+sStart.y][0]; } - pat->data[j+selStart.y][iFine+1]=patBuffer.data[j/multiplier+selStart.y][iFine+1]; + pat->data[j+sStart.y][iFine+1]=patBuffer.data[j/multiplier+sStart.y][iFine+1]; } } iFine=0; @@ -937,6 +949,162 @@ void FurnaceGUI::doExpand(int multiplier) { makeUndo(GUI_UNDO_PATTERN_EXPAND); } +void FurnaceGUI::doCollapseSong(int divider) { + if (divider<2) return; + finishSelection(); + + UndoStep us; + us.type=GUI_UNDO_PATTERN_COLLAPSE_SONG; + + DivPattern patCopy; + + size_t subSong=e->getCurrentSubSong(); + for (int i=0; igetTotalChannelCount(); i++) { + for (int j=0; jcurPat[i].data[j]==NULL) continue; + + DivPattern* pat=e->curPat[i].getPattern(j,true); + pat->copyOn(&patCopy); + pat->clear(); + for (int k=0; kdata[k/divider][0]==0 && pat->data[k/divider][1]==0)) continue; + } else { + if (pat->data[k/divider][l+1]!=-1) continue; + } + + if (l==0) { + pat->data[k/divider][l]=patCopy.data[k][l]; + } + pat->data[k/divider][l+1]=patCopy.data[k][l+1]; + + if (l>3 && !(l&1)) { // scale effects as needed + switch (pat->data[k/divider][l]) { + case 0x0d: + pat->data[k/divider][l+1]/=divider; + break; + case 0x0f: + pat->data[k/divider][l+1]=CLAMP(pat->data[k/divider][l+1]*divider,1,255); + break; + } + } + } + } + + // put undo + for (int k=0; kdata[k][l]!=patCopy.data[k][l]) { + us.pat.push_back(UndoPatternData(subSong,i,j,k,l,patCopy.data[k][l],pat->data[k][l])); + } + } + } + } + } + // magic + unsigned char* subSongInfoCopy=new unsigned char[1024]; + memcpy(subSongInfoCopy,e->curSubSong,1024); + e->curSubSong->patLen/=divider; + for (int i=0; icurSubSong->speeds.len; i++) { + e->curSubSong->speeds.val[i]=CLAMP(e->curSubSong->speeds.val[i]*divider,1,255); + } + unsigned char* newSubSongInfo=(unsigned char*)e->curSubSong; + for (int i=0; i<1024; i++) { + if (subSongInfoCopy[i]!=newSubSongInfo[i]) { + us.other.push_back(UndoOtherData(GUI_UNDO_TARGET_SUBSONG,subSong,i,subSongInfoCopy[i],newSubSongInfo[i])); + } + } + + if (!us.pat.empty()) { + undoHist.push_back(us); + redoHist.clear(); + if (undoHist.size()>settings.maxUndoSteps) undoHist.pop_front(); + } + + if (e->isPlaying()) e->play(); +} + +void FurnaceGUI::doExpandSong(int multiplier) { + if (multiplier<2) return; + if (e->curSubSong->patLen>(256/multiplier)) { + showError("can't expand any further!"); + return; + } + finishSelection(); + + UndoStep us; + us.type=GUI_UNDO_PATTERN_EXPAND_SONG; + + DivPattern patCopy; + + size_t subSong=e->getCurrentSubSong(); + for (int i=0; igetTotalChannelCount(); i++) { + for (int j=0; jcurPat[i].data[j]==NULL) continue; + + DivPattern* pat=e->curPat[i].getPattern(j,true); + pat->copyOn(&patCopy); + pat->clear(); + for (int k=0; k<(256/multiplier); k++) { + for (int l=0; ldata[k*multiplier][0]==0 && pat->data[k*multiplier][1]==0)) continue; + } else { + if (pat->data[k*multiplier][l+1]!=-1) continue; + } + + if (l==0) { + pat->data[k*multiplier][l]=patCopy.data[k][l]; + } + pat->data[k*multiplier][l+1]=patCopy.data[k][l+1]; + + if (l>3 && !(l&1)) { // scale effects as needed + switch (pat->data[k*multiplier][l]) { + case 0x0d: + pat->data[k*multiplier][l+1]/=multiplier; + break; + case 0x0f: + pat->data[k*multiplier][l+1]=CLAMP(pat->data[k*multiplier][l+1]/multiplier,1,255); + break; + } + } + } + } + + // put undo + for (int k=0; kdata[k][l]!=patCopy.data[k][l]) { + us.pat.push_back(UndoPatternData(subSong,i,j,k,l,patCopy.data[k][l],pat->data[k][l])); + } + } + } + } + } + // magic + unsigned char* subSongInfoCopy=new unsigned char[1024]; + memcpy(subSongInfoCopy,e->curSubSong,1024); + e->curSubSong->patLen*=multiplier; + for (int i=0; icurSubSong->speeds.len; i++) { + e->curSubSong->speeds.val[i]=CLAMP(e->curSubSong->speeds.val[i]/multiplier,1,255); + } + unsigned char* newSubSongInfo=(unsigned char*)e->curSubSong; + for (int i=0; i<1024; i++) { + if (subSongInfoCopy[i]!=newSubSongInfo[i]) { + us.other.push_back(UndoOtherData(GUI_UNDO_TARGET_SUBSONG,subSong,i,subSongInfoCopy[i],newSubSongInfo[i])); + } + } + + if (!us.pat.empty()) { + undoHist.push_back(us); + redoHist.clear(); + if (undoHist.size()>settings.maxUndoSteps) undoHist.pop_front(); + } + + if (e->isPlaying()) e->play(); +} + void FurnaceGUI::doDrag() { int len=dragEnd.xCoarse-dragStart.xCoarse+1; @@ -985,6 +1153,8 @@ void FurnaceGUI::doUndo() { case GUI_UNDO_PATTERN_FLIP: case GUI_UNDO_PATTERN_COLLAPSE: case GUI_UNDO_PATTERN_EXPAND: + case GUI_UNDO_PATTERN_COLLAPSE_SONG: + case GUI_UNDO_PATTERN_EXPAND_SONG: case GUI_UNDO_PATTERN_DRAG: case GUI_UNDO_REPLACE: for (UndoPatternData& i: us.pat) { @@ -1005,6 +1175,22 @@ void FurnaceGUI::doUndo() { break; } + bool shallReplay=false; + for (UndoOtherData& i: us.other) { + switch (i.target) { + case GUI_UNDO_TARGET_SONG: + ((unsigned char*)(&e->song))[i.off]=i.oldVal; + shallReplay=true; + break; + case GUI_UNDO_TARGET_SUBSONG: + if (i.subtarget<0 || i.subtarget>=(int)e->song.subsong.size()) break; + ((unsigned char*)(e->song.subsong[i.subtarget]))[i.off]=i.oldVal; + shallReplay=true; + break; + } + } + if (shallReplay && e->isPlaying()) play(); + if (curOrder>=e->curSubSong->ordersLen) { curOrder=e->curSubSong->ordersLen-1; oldOrder=curOrder; @@ -1045,6 +1231,8 @@ void FurnaceGUI::doRedo() { case GUI_UNDO_PATTERN_COLLAPSE: case GUI_UNDO_PATTERN_EXPAND: case GUI_UNDO_PATTERN_DRAG: + case GUI_UNDO_PATTERN_COLLAPSE_SONG: + case GUI_UNDO_PATTERN_EXPAND_SONG: case GUI_UNDO_REPLACE: for (UndoPatternData& i: us.pat) { e->changeSongP(i.subSong); @@ -1065,6 +1253,22 @@ void FurnaceGUI::doRedo() { break; } + bool shallReplay=false; + for (UndoOtherData& i: us.other) { + switch (i.target) { + case GUI_UNDO_TARGET_SONG: + ((unsigned char*)(&e->song))[i.off]=i.newVal; + shallReplay=true; + break; + case GUI_UNDO_TARGET_SUBSONG: + if (i.subtarget<0 || i.subtarget>=(int)e->song.subsong.size()) break; + ((unsigned char*)(e->song.subsong[i.subtarget]))[i.off]=i.newVal; + shallReplay=true; + break; + } + } + if (shallReplay && e->isPlaying()) play(); + if (curOrder>=e->curSubSong->ordersLen) { curOrder=e->curSubSong->ordersLen-1; oldOrder=curOrder; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 76214fae..39a7b1cd 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2842,9 +2842,23 @@ void FurnaceGUI::editOptions(bool topMenu) { ImGui::Separator(); if (ImGui::MenuItem("flip selection",BIND_FOR(GUI_ACTION_PAT_FLIP_SELECTION))) doFlip(); - if (ImGui::MenuItem("collapse",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_ROWS))) doCollapse(2); - if (ImGui::MenuItem("expand",BIND_FOR(GUI_ACTION_PAT_EXPAND_ROWS))) doExpand(2); + if (ImGui::MenuItem("collapse",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_ROWS))) doCollapse(2,selStart,selEnd); + if (ImGui::MenuItem("expand",BIND_FOR(GUI_ACTION_PAT_EXPAND_ROWS))) doExpand(2,selStart,selEnd); + if (topMenu) { + ImGui::Separator(); + if (ImGui::MenuItem("collapse pattern",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_PAT))) doAction(GUI_ACTION_PAT_COLLAPSE_PAT); + if (ImGui::MenuItem("expand pattern",BIND_FOR(GUI_ACTION_PAT_EXPAND_PAT))) doAction(GUI_ACTION_PAT_EXPAND_PAT); + } + } + + if (topMenu) { + ImGui::Separator(); + if (ImGui::MenuItem("collapse song",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_SONG))) doAction(GUI_ACTION_PAT_COLLAPSE_SONG); + if (ImGui::MenuItem("expand song",BIND_FOR(GUI_ACTION_PAT_EXPAND_SONG))) doAction(GUI_ACTION_PAT_EXPAND_SONG); + } + + if (!basicMode) { if (topMenu) { ImGui::Separator(); if (ImGui::MenuItem("find/replace",BIND_FOR(GUI_ACTION_WINDOW_FIND),findOpen)) { @@ -2856,16 +2870,6 @@ void FurnaceGUI::editOptions(bool topMenu) { } } } - - /*if (topMenu) { - ImGui::Separator(); - ImGui::MenuItem("collapse pattern",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_PAT)); - ImGui::MenuItem("expand pattern",BIND_FOR(GUI_ACTION_PAT_EXPAND_PAT)); - - ImGui::Separator(); - ImGui::MenuItem("collapse song",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_SONG)); - ImGui::MenuItem("expand song",BIND_FOR(GUI_ACTION_PAT_EXPAND_SONG)); - }*/ } void FurnaceGUI::toggleMobileUI(bool enable, bool force) { diff --git a/src/gui/gui.h b/src/gui/gui.h index fe44ea26..df6700a8 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -721,6 +721,8 @@ enum NoteCtrl { struct SelectionPoint { int xCoarse, xFine; int y; + SelectionPoint(int xc, int xf, int yp): + xCoarse(xc), xFine(xf), y(yp) {} SelectionPoint(): xCoarse(0), xFine(0), y(0) {} }; @@ -742,10 +744,17 @@ enum ActionType { GUI_UNDO_PATTERN_FLIP, GUI_UNDO_PATTERN_COLLAPSE, GUI_UNDO_PATTERN_EXPAND, + GUI_UNDO_PATTERN_COLLAPSE_SONG, + GUI_UNDO_PATTERN_EXPAND_SONG, GUI_UNDO_PATTERN_DRAG, GUI_UNDO_REPLACE }; +enum UndoOtherTarget { + GUI_UNDO_TARGET_SONG, + GUI_UNDO_TARGET_SUBSONG +}; + struct UndoPatternData { int subSong, chan, pat, row, col; short oldVal, newVal; @@ -770,6 +779,19 @@ struct UndoOrderData { newVal(v2) {} }; +struct UndoOtherData { + UndoOtherTarget target; + int subtarget; + size_t off; + unsigned char oldVal, newVal; + UndoOtherData(UndoOtherTarget t, int st, size_t o, unsigned char v1, unsigned char v2): + target(t), + subtarget(st), + off(o), + oldVal(v1), + newVal(v2) {} +}; + struct UndoStep { ActionType type; SelectionPoint cursor, selStart, selEnd; @@ -779,6 +801,7 @@ struct UndoStep { int oldPatLen, newPatLen; std::vector ord; std::vector pat; + std::vector other; }; // -1 = any @@ -2064,8 +2087,10 @@ class FurnaceGUI { void doScale(float top); void doRandomize(int bottom, int top, bool mode); void doFlip(); - void doCollapse(int divider); - void doExpand(int multiplier); + void doCollapse(int divider, const SelectionPoint& sStart, const SelectionPoint& sEnd); + void doExpand(int multiplier, const SelectionPoint& sStart, const SelectionPoint& sEnd); + void doCollapseSong(int divider); + void doExpandSong(int multiplier); void doUndo(); void doRedo(); void doFind(); From cbc059f745be19e569a321a17cc7c2df13339d3b Mon Sep 17 00:00:00 2001 From: NyaongI <100076733+kitt3n69420@users.noreply.github.com> Date: Thu, 27 Apr 2023 18:10:31 +0900 Subject: [PATCH 29/40] New AY8930 Demo song (#1082) * New AY8930 Demo song * Delete joyful.fur file change * reuploading demo lowered clock rate from 10Mhz to 5Mhz, and changed noise frequency --- demos/ay8930/joyful_.fur | Bin 0 -> 1649 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/ay8930/joyful_.fur diff --git a/demos/ay8930/joyful_.fur b/demos/ay8930/joyful_.fur new file mode 100644 index 0000000000000000000000000000000000000000..a486bfd625dc3946afb19125ec1203e18aaf7d0d GIT binary patch literal 1649 zcmV-%29Ei7ob6gYY!pWnemgsR`*;2UV;kFNdm|GNh@T5qB2a?xVQe4)LvT<+6*=bv z9BiNCpMok;M5Gk1i9|(#NRx&xWu#Q;Qb#GaPZ^p>k({@;ySHmUGbj(^2XYFb!l?3 zT7G!p-D0g-wTqM9MbAB3S-dcAiM*oqU~ciAkMGSbu2rnH^~!3c+VEnwvVugczuB{2 zW2jBgVW!jp*Ou4TS2va_%j-@NZj|N$A1Y&O%S+qH@Nl6pG&HCv{%c?%P(#2&pap>E zLXRE*#Rx%Xcxh{D#*^_aE#tl*V|2t9Ld#HNWN;tk^M(;BVWg6cx{^*P-E}aNYn6HD z>fAa^-#7xVI5>Asj2aVvV{H^i`NT`Sfd@yeiC10?jG7bw07^dUNj3w?L;XEnwyxHt zc7;-vt?QSud>!qU_KV^V{=7bT-W&X*h4MpZ>eM?DLx1WGJrWE(To@W0INaaYd#LB& zf$q+Zylt6=p3}IBwW{>^tbYG$7hc7S8fQ^f^C}CZ!gj6SH)_4PQdyQv)BB0FhJr?S z$lVL!5kft)%X6z0r!+P$A?UN@f(kzCZ1MET6UUFeJ@%F}QWzZQ@9jZq-oiYpimHam zi&48tKk#39Dtd#uD+~=B?(6M2=-nU7)N@>|%|4YPj2?XhN~tjCt*%jQQmzU+KC zs8W0;$#3`k%j$usAe5jWYLyZzB=k38Ild;~#zIjAj=E>QPVn^x&ffX5^R)@S-N1>k zN$|}E&ffWqm@gCN*ofu$I-y6*b0e1Hr~P~i1;K)X$X1A*aJEA1j9V@L(l{)L@HAyU zjX^S;;da4MK}2V)Z(P(q#@_afrT7lmYVn)J=iVpk7{7&H4Yv2Cuuu^GmWc{X1rP@m z`QE;s$MCcGS^QRxUoQw2tPt6jDZ~33M+M>uwP<~2(l5vw@o*<5>!6fq;?`K5(X62uXPvur8^C{;~k~hhM2v3=K{c_`gTCAVq z>x5sEjL#&;wFy5JhvL&Z<>JfgGzmWyhvL&Z<>Jfgr0zQvhvL&Z<4?(``O5047ex5o zocCbv{tm^33XiW$L-L(SOE7K{%o4=01q~XZCr9|H`6kI*5}YUEQ#n*gJyf3K{Ymnc z1ltMpi#eoL6xn$t$y*{E6-4$KBEuOL3L-pZl3RKxKDD%&q`x^^FKVfk<=cc#o%Am|D-kj=A3`kS-$qVm?PJX2ppQheEb)(e7XD@2AfEEa^{yuFwnS2<0>UVJ0P_}*UF zOj&>0`LR;YkKM-kPyJp*1>tX*sHI=_G)Z=eZ}(GJj-sSnsxdl z6oh}yl$|p9Ejwk}8~)#%GVx&3lzoQCa696re=(@TLA2&6lPS5Bx0-&v z&GpM}Wm`?Z^j0=12)3;tynR^?qQD{61)L}Rynz$Nq2g---z4ITel0I$mXBQPdnycCm2 literal 0 HcmV?d00001 From ff6a7c2f89d3cb77c707d2a0a6d194641ea6eefd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 27 Apr 2023 04:31:51 -0500 Subject: [PATCH 30/40] GUI: allow binding collapse/expand pat/song --- src/gui/settings.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index e08d5e1d..1cb76ef5 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -2304,10 +2304,12 @@ void FurnaceGUI::drawSettings() { UI_KEYBIND_CONFIG(GUI_ACTION_PAT_FLIP_SELECTION); UI_KEYBIND_CONFIG(GUI_ACTION_PAT_COLLAPSE_ROWS); UI_KEYBIND_CONFIG(GUI_ACTION_PAT_EXPAND_ROWS); + UI_KEYBIND_CONFIG(GUI_ACTION_PAT_COLLAPSE_PAT); + UI_KEYBIND_CONFIG(GUI_ACTION_PAT_EXPAND_PAT); + UI_KEYBIND_CONFIG(GUI_ACTION_PAT_COLLAPSE_SONG); + UI_KEYBIND_CONFIG(GUI_ACTION_PAT_EXPAND_SONG); UI_KEYBIND_CONFIG(GUI_ACTION_PAT_LATCH); - // TODO: collapse/expand pattern and song - KEYBIND_CONFIG_END; ImGui::TreePop(); } From 744ba066260a6a35b28c11418f01201e4e4d49db Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 27 Apr 2023 12:32:25 -0500 Subject: [PATCH 31/40] AY: fix #1079 --- src/engine/platform/ay.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 76637f38..c9c75f0f 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -687,6 +687,7 @@ void DivPlatformAY8910::muteChannel(int ch, bool mute) { void DivPlatformAY8910::forceIns() { for (int i=0; i<3; i++) { chan[i].insChanged=true; + chan[i].freqChanged=true; } immWrite(0x0b,ayEnvPeriod); immWrite(0x0c,ayEnvPeriod>>8); From 5af7d6771833a868b0956c49896a53ee68213e9c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 30 Apr 2023 12:24:14 -0500 Subject: [PATCH 32/40] GUI: optimize sample editor? --- src/gui/sampleEdit.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 3a8fae4b..2d0cea88 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -1171,8 +1171,12 @@ void FurnaceGUI::drawSampleEdit() { if (y1>=availY) y1=availY-1; if (y2<0) y2=0; if (y2>=availY) y2=availY-1; - for (int j=y1; j<=y2; j++) { - data[i+availX*(availY-j-1)]=lineColor; + + const int s1=i+availX*(availY-y1-1); + const int s2=i+availX*(availY-y2-1); + + for (int j=s2; j<=s1; j+=availX) { + data[j]=lineColor; } if (totalAdvance>0) xCoarse++; } while ((totalAdvance--)>0); From 78b7049d818b814f1521d81579dac0650d38e823 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 30 Apr 2023 13:06:23 -0500 Subject: [PATCH 33/40] GUI: optimize sample editor --- src/gui/sampleEdit.cpp | 67 +++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 2d0cea88..4eaae619 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -1111,23 +1111,26 @@ void FurnaceGUI::drawSampleEdit() { if (sampleTex!=NULL) { if (updateSampleTex) { - unsigned int* data=NULL; + unsigned int* dataT=NULL; int pitch=0; logD("updating sample texture."); - if (SDL_LockTexture(sampleTex,NULL,(void**)&data,&pitch)!=0) { + if (SDL_LockTexture(sampleTex,NULL,(void**)&dataT,&pitch)!=0) { logE("error while locking sample texture! %s",SDL_GetError()); } else { + unsigned int* data=new unsigned int[sampleTexW*sampleTexH]; + ImU32 bgColor=ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_BG]); ImU32 bgColorLoop=ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_LOOP]); ImU32 lineColor=ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_FG]); ImU32 centerLineColor=ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_CENTER]); + int ij=0; for (int i=0; iisLoopable() && (scaledPos>=sample->loopStart && scaledPos<=sample->loopEnd)) { - data[i*availX+j]=bgColorLoop; + data[ij++]=bgColorLoop; } else { - data[i*availX+j]=bgColor; + data[ij++]=bgColor; } } } @@ -1143,11 +1146,15 @@ void FurnaceGUI::drawSampleEdit() { for (unsigned int i=0; i<(unsigned int)availX; i++) { if (xCoarse>=sample->samples) break; int y1, y2; + int candMin=INT_MAX; + int candMax=INT_MIN; int totalAdvance=0; if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { - y1=((unsigned char)sample->data8[xCoarse]^0x80)*availY/256; + if (candMin>sample->data8[xCoarse]) candMin=sample->data8[xCoarse]; + if (candMaxdata8[xCoarse]) candMax=sample->data8[xCoarse]; } else { - y1=((unsigned short)sample->data16[xCoarse]^0x8000)*availY/65536; + if (candMin>sample->data16[xCoarse]) candMin=sample->data16[xCoarse]; + if (candMaxdata16[xCoarse]) candMax=sample->data16[xCoarse]; } xFine+=xAdvanceFine; if (xFine>=16777216) { @@ -1158,30 +1165,42 @@ void FurnaceGUI::drawSampleEdit() { if (xCoarse>=sample->samples) break; do { if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { - y2=((unsigned char)sample->data8[xCoarse]^0x80)*availY/256; + if (candMin>sample->data8[xCoarse]) candMin=sample->data8[xCoarse]; + if (candMaxdata8[xCoarse]) candMax=sample->data8[xCoarse]; } else { - y2=((unsigned short)sample->data16[xCoarse]^0x8000)*availY/65536; - } - if (y1>y2) { - y2^=y1; - y1^=y2; - y2^=y1; - } - if (y1<0) y1=0; - if (y1>=availY) y1=availY-1; - if (y2<0) y2=0; - if (y2>=availY) y2=availY-1; - - const int s1=i+availX*(availY-y1-1); - const int s2=i+availX*(availY-y2-1); - - for (int j=s2; j<=s1; j+=availX) { - data[j]=lineColor; + if (candMin>sample->data16[xCoarse]) candMin=sample->data16[xCoarse]; + if (candMaxdata16[xCoarse]) candMax=sample->data16[xCoarse]; } if (totalAdvance>0) xCoarse++; } while ((totalAdvance--)>0); + if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { + y1=(((unsigned char)candMin^0x80)*availY)>>8; + y2=(((unsigned char)candMax^0x80)*availY)>>8; + } else { + y1=(((unsigned short)candMin^0x8000)*availY)>>16; + y2=(((unsigned short)candMax^0x8000)*availY)>>16; + } + if (y1>y2) { + y2^=y1; + y1^=y2; + y2^=y1; + } + if (y1<0) y1=0; + if (y1>=availY) y1=availY-1; + if (y2<0) y2=0; + if (y2>=availY) y2=availY-1; + + const int s1=i+availX*(availY-y1-1); + const int s2=i+availX*(availY-y2-1); + + for (int j=s2; j<=s1; j+=availX) { + data[j]=lineColor; + } } + + memcpy(dataT,data,sampleTexW*sampleTexH*sizeof(unsigned int)); SDL_UnlockTexture(sampleTex); + delete[] data; } updateSampleTex=false; } From 8bc0781f5977db6db3ad4d48ca91f7a8cd8ac42b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 30 Apr 2023 13:46:09 -0500 Subject: [PATCH 34/40] implement 05xy/06xy issue #1044 --- src/engine/engine.cpp | 4 +++ src/engine/engine.h | 4 ++- src/engine/playback.cpp | 72 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 12fe249f..0eb603b7 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -55,6 +55,10 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul return "03xx: Portamento"; case 0x04: return "04xy: Vibrato (x: speed; y: depth)"; + case 0x05: + return "05xy: Volume slide + vibrato (compatibility only!)"; + case 0x06: + return "06xy: Volume slide + portamento (compatibility only!)"; case 0x07: return "07xy: Tremolo (x: speed; y: depth)"; case 0x08: diff --git a/src/engine/engine.h b/src/engine/engine.h index d31de903..7705b259 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -105,7 +105,7 @@ struct DivChannelState { int delayOrder, delayRow, retrigSpeed, retrigTick; int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoDir, vibratoFine; int tremoloDepth, tremoloRate, tremoloPos; - unsigned char arp, arpStage, arpTicks, panL, panR, panRL, panRR; + unsigned char arp, arpStage, arpTicks, panL, panR, panRL, panRR, lastVibrato, lastPorta; bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff; bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, wasShorthandPorta, noteOnInhibit, resetArp; bool wentThroughNote, goneThroughNote; @@ -146,6 +146,8 @@ struct DivChannelState { panR(255), panRL(0), panRR(0), + lastVibrato(0), + lastPorta(0), doNote(false), legato(false), portaStop(false), diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index fbbd1302..8cc2f825 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -680,6 +680,7 @@ void DivEngine::processRow(int i, bool afterDelay) { chan[i].inPorta=false; dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0)); } else { + chan[i].lastPorta=effectVal; calledPorta=true; if (chan[i].note==chan[i].oldNote && !chan[i].inPorta && song.buggyPortaAfterSlide) { chan[i].portaNote=chan[i].note; @@ -700,11 +701,78 @@ void DivEngine::processRow(int i, bool afterDelay) { } break; case 0x04: // vibrato + if (effectVal) chan[i].lastVibrato=effectVal; chan[i].vibratoDepth=effectVal&15; chan[i].vibratoRate=effectVal>>4; dispatchCmd(DivCommand(DIV_CMD_HINT_VIBRATO,i,chan[i].vibratoDepth,chan[i].vibratoRate)); dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15))); break; + case 0x05: // vol slide + vibrato + if (effectVal==0) { + chan[i].vibratoDepth=0; + chan[i].vibratoRate=0; + } else { + chan[i].vibratoDepth=chan[i].lastVibrato&15; + chan[i].vibratoRate=chan[i].lastVibrato>>4; + } + dispatchCmd(DivCommand(DIV_CMD_HINT_VIBRATO,i,chan[i].vibratoDepth,chan[i].vibratoRate)); + dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15))); + // TODO: non-0x-or-x0 value should be treated as 00 + if (effectVal!=0) { + if ((effectVal&15)!=0) { + chan[i].volSpeed=-(effectVal&15)*64; + } else { + chan[i].volSpeed=(effectVal>>4)*64; + } + // tremolo and vol slides are incompatible + chan[i].tremoloDepth=0; + chan[i].tremoloRate=0; + } else { + chan[i].volSpeed=0; + } + dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,chan[i].volSpeed)); + break; + case 0x06: // vol slide + porta + if (effectVal==0 || chan[i].lastPorta==0) { + chan[i].portaNote=-1; + chan[i].portaSpeed=-1; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0))); + chan[i].inPorta=false; + dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0)); + } else { + calledPorta=true; + if (chan[i].note==chan[i].oldNote && !chan[i].inPorta && song.buggyPortaAfterSlide) { + chan[i].portaNote=chan[i].note; + chan[i].portaSpeed=-1; + } else { + chan[i].portaNote=chan[i].note; + chan[i].portaSpeed=chan[i].lastPorta; + chan[i].inPorta=true; + chan[i].wasShorthandPorta=false; + } + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0))); + chan[i].portaStop=true; + if (chan[i].keyOn) chan[i].doNote=false; + chan[i].stopOnOff=song.stopPortaOnNoteOff; // what?! + chan[i].scheduledSlideReset=false; + dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,1)); + lastSlide=0x1337; // i hate this so much + } + // TODO: non-0x-or-x0 value should be treated as 00 + if (effectVal!=0) { + if ((effectVal&15)!=0) { + chan[i].volSpeed=-(effectVal&15)*64; + } else { + chan[i].volSpeed=(effectVal>>4)*64; + } + // tremolo and vol slides are incompatible + chan[i].tremoloDepth=0; + chan[i].tremoloRate=0; + } else { + chan[i].volSpeed=0; + } + dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,chan[i].volSpeed)); + break; case 0x07: // tremolo // TODO // this effect is really weird. i thought it would alter the tremolo depth but turns out it's completely different @@ -1148,6 +1216,10 @@ void DivEngine::nextRow() { doPrepareCut=false; break; } + if (pat->data[curRow][4+(j<<1)]==0x06) { + doPrepareCut=false; + break; + } if (pat->data[curRow][4+(j<<1)]==0xea) { if (pat->data[curRow][5+(j<<1)]>0) { doPrepareCut=false; From 4cb9970fa1f67446d59ff060c28e58144de1ffd4 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 30 Apr 2023 15:59:50 -0500 Subject: [PATCH 35/40] fix crash --- src/gui/sampleEdit.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 4eaae619..f5216db0 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -1164,6 +1164,7 @@ void FurnaceGUI::drawSampleEdit() { totalAdvance+=xAdvanceCoarse; if (xCoarse>=sample->samples) break; do { + if (xCoarse>=sample->samples) break; if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { if (candMin>sample->data8[xCoarse]) candMin=sample->data8[xCoarse]; if (candMaxdata8[xCoarse]) candMax=sample->data8[xCoarse]; From 672c440d4ef91df8c612fdb8d36bc409341f6bb9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 30 Apr 2023 16:07:46 -0500 Subject: [PATCH 36/40] GUI: prevent window from being too big issue #942 --- src/gui/gui.cpp | 24 +++++++++++++++++++----- src/gui/gui.h | 2 +- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 39a7b1cd..76cc9d55 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3249,18 +3249,18 @@ void FurnaceGUI::pointMotion(int x, int y, int xrel, int yrel) { // how many pixels should be visible at least at x/y dir #define OOB_PIXELS_SAFETY 25 -bool FurnaceGUI::detectOutOfBoundsWindow() { +bool FurnaceGUI::detectOutOfBoundsWindow(SDL_Rect& failing) { int count=SDL_GetNumVideoDisplays(); if (count<1) { - logW("bounds check: error %s",SDL_GetError()); + logW("bounds check: error: %s",SDL_GetError()); return false; } SDL_Rect rect; for (int i=0; i=scrX); @@ -3268,6 +3268,7 @@ bool FurnaceGUI::detectOutOfBoundsWindow() { logD("bounds check: display %d is at %dx%dx%dx%d: %s%s",i,rect.x+OOB_PIXELS_SAFETY,rect.y+OOB_PIXELS_SAFETY,rect.x+rect.w-OOB_PIXELS_SAFETY,rect.y+rect.h-OOB_PIXELS_SAFETY,xbound?"x":"",ybound?"y":""); if (xbound && ybound) { + failing=rect; return true; } } @@ -6007,10 +6008,23 @@ bool FurnaceGUI::init() { #ifndef IS_MOBILE // if window would spawn out of bounds, force it to be get default position - if (!detectOutOfBoundsWindow()) { + SDL_Rect bounds; + if (!detectOutOfBoundsWindow(bounds)) { scrMax=false; scrX=scrConfX=SDL_WINDOWPOS_CENTERED; scrY=scrConfY=SDL_WINDOWPOS_CENTERED; + + // make sure our window isn't big + if (bounds.w Date: Sun, 30 Apr 2023 23:52:57 +0200 Subject: [PATCH 37/40] Add MMC5 + N163 + FDS demo (#1085) * Add MMC5 + N163 + FDS demo * Add copyright info --- demos/nes/invicibility_mmc5_n163_fds.fur | Bin 0 -> 13146 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/nes/invicibility_mmc5_n163_fds.fur diff --git a/demos/nes/invicibility_mmc5_n163_fds.fur b/demos/nes/invicibility_mmc5_n163_fds.fur new file mode 100644 index 0000000000000000000000000000000000000000..ef9b05bf928a0c6bd8c28cbf33b800c9333e20ba GIT binary patch literal 13146 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 x(te}zDRKiHw9P+o9zY7G{7)e18UIvV{Mat{G Date: Sun, 30 Apr 2023 18:22:35 -0400 Subject: [PATCH 38/40] implement midi panic (#1036) * implement midi panic * do it the right way * only send all notes off for now * remove cc names at TAMidiMessageTypes * Update engine.cpp --- src/engine/engine.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 0eb603b7..55c74417 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2423,6 +2423,13 @@ void DivEngine::stepOne(int row) { void DivEngine::stop() { BUSY_BEGIN; freelance=false; + if (!playing) { + //Send midi panic + if (output) if (output->midiOut!=NULL) { + output->midiOut->send(TAMidiMessage(TA_MIDI_CONTROL,0x7B,0)); + logV("Midi panic sent"); + } + } playing=false; extValuePresent=false; endOfSong=false; // what? From 09bace37266db2803280ec68dc0dded3667abff3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 30 Apr 2023 19:45:54 -0500 Subject: [PATCH 39/40] get rid of two debug messages --- src/engine/config.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/config.cpp b/src/engine/config.cpp index 137dbdaf..d2333ab5 100644 --- a/src/engine/config.cpp +++ b/src/engine/config.cpp @@ -178,7 +178,7 @@ bool DivConfig::loadFromFile(const char* path, bool createOnFail, bool redundanc logD("config does not exist"); if (createOnFail) { logI("creating default config."); - reportError(fmt::sprintf("Creating default config: %s",strerror(errno))); + //reportError(fmt::sprintf("Creating default config: %s",strerror(errno))); return save(path,redundancy); } else { reportError(fmt::sprintf("COULD NOT LOAD CONFIG %s",strerror(errno))); @@ -191,7 +191,7 @@ bool DivConfig::loadFromFile(const char* path, bool createOnFail, bool redundanc logD("config does not exist"); if (createOnFail) { logI("creating default config."); - reportError(fmt::sprintf("Creating default config: %s",strerror(errno))); + //reportError(fmt::sprintf("Creating default config: %s",strerror(errno))); return save(path); } else { reportError(fmt::sprintf("COULD NOT LOAD CONFIG %s",strerror(errno))); From d4b77bc3dc711e211a1e9c5d0b6e0e5f8c165826 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 1 May 2023 01:36:47 -0500 Subject: [PATCH 40/40] GUI: WHAT?! --- src/gui/gui.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 76cc9d55..0c6b3254 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3268,11 +3268,11 @@ bool FurnaceGUI::detectOutOfBoundsWindow(SDL_Rect& failing) { logD("bounds check: display %d is at %dx%dx%dx%d: %s%s",i,rect.x+OOB_PIXELS_SAFETY,rect.y+OOB_PIXELS_SAFETY,rect.x+rect.w-OOB_PIXELS_SAFETY,rect.y+rect.h-OOB_PIXELS_SAFETY,xbound?"x":"",ybound?"y":""); if (xbound && ybound) { - failing=rect; return true; } } + failing=rect; return false; } @@ -6015,7 +6015,7 @@ bool FurnaceGUI::init() { scrY=scrConfY=SDL_WINDOWPOS_CENTERED; // make sure our window isn't big - if (bounds.w