From f0e51f6e885af2f89d207b17eaa1b78488836654 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 5 Nov 2023 17:00:02 -0500 Subject: [PATCH 01/16] Amiga: improve accuracy don't stop DMA until sample is done playing do not update output if PM/AM is on --- src/engine/export/amigaValidation.cpp | 2 +- src/engine/platform/amiga.cpp | 175 ++++++++++++++------------ src/engine/platform/amiga.h | 13 ++ 3 files changed, 111 insertions(+), 79 deletions(-) diff --git a/src/engine/export/amigaValidation.cpp b/src/engine/export/amigaValidation.cpp index 56d3814a7..e1aa4dfdb 100644 --- a/src/engine/export/amigaValidation.cpp +++ b/src/engine/export/amigaValidation.cpp @@ -149,7 +149,7 @@ std::vector DivExportAmigaValidation::go(DivEngine* e) { } else if (waveNum<65536) { seq->writeC((i<<4)|4); seq->writeS_BE(waveNum); - } else{ + } else { seq->writeC((i<<4)|1); seq->writeC(waves[waveNum].pos>>16); seq->writeC(waves[waveNum].pos>>8); diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index a4e279dad..67853d902 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -81,7 +81,18 @@ const char** DivPlatformAmiga::getRegisterSheet() { void DivPlatformAmiga::acquire(short** buf, size_t len) { thread_local int outL, outR, output; + for (size_t h=0; h>1]=val; - - if (!skipRegisterWrites && dumpWrites) { - addWrite(addr,val); - } - switch (addr&0x1fe) { case 0x96: { // DMACON if (val&32768) { - if (val&1) amiga.audEn[0]=true; - if (val&2) amiga.audEn[1]=true; - if (val&4) amiga.audEn[2]=true; - if (val&8) amiga.audEn[3]=true; - if (val&512) amiga.dmaEn=true; + if (val&1) audEn[0]=true; + if (val&2) audEn[1]=true; + if (val&4) audEn[2]=true; + if (val&8) audEn[3]=true; + if (val&512) dmaEn=true; } else { if (val&1) { - amiga.audEn[0]=false; - UPDATE_DMA(0); + audEn[0]=false; } if (val&2) { - amiga.audEn[1]=false; - UPDATE_DMA(1); + audEn[1]=false; } if (val&4) { - amiga.audEn[2]=false; - UPDATE_DMA(2); + audEn[2]=false; } if (val&8) { - amiga.audEn[3]=false; - UPDATE_DMA(3); + audEn[3]=false; } if (val&512) { - amiga.dmaEn=false; + dmaEn=false; } } break; } case 0x9a: { // INTENA if (val&32768) { - if (val&128) amiga.audInt[0]=true; - if (val&256) amiga.audInt[1]=true; - if (val&512) amiga.audInt[2]=true; - if (val&1024) amiga.audInt[3]=true; + if (val&128) audInt[0]=true; + if (val&256) audInt[1]=true; + if (val&512) audInt[2]=true; + if (val&1024) audInt[3]=true; } else { - if (val&128) amiga.audInt[0]=false; - if (val&256) amiga.audInt[1]=false; - if (val&512) amiga.audInt[2]=false; - if (val&1024) amiga.audInt[3]=false; + if (val&128) audInt[0]=false; + if (val&256) audInt[1]=false; + if (val&512) audInt[2]=false; + if (val&1024) audInt[3]=false; } break; } case 0x9c: { // INTREQ if (val&32768) { if (val&128) { - amiga.audIr[0]=true; - irq(0); + audIr[0]=true; } if (val&256) { - amiga.audIr[1]=true; - irq(1); + audIr[1]=true; } if (val&512) { - amiga.audIr[2]=true; - irq(2); + audIr[2]=true; } if (val&1024) { - amiga.audIr[3]=true; - irq(3); + audIr[3]=true; } } else { - if (val&128) amiga.audIr[0]=false; - if (val&256) amiga.audIr[1]=false; - if (val&512) amiga.audIr[2]=false; - if (val&1024) amiga.audIr[3]=false; + if (val&128) audIr[0]=false; + if (val&256) audIr[1]=false; + if (val&512) audIr[2]=false; + if (val&1024) audIr[3]=false; } break; } case 0x9e: { // ADKCON if (val&32768) { - if (val&1) amiga.useV[0]=true; - if (val&2) amiga.useV[1]=true; - if (val&4) amiga.useV[2]=true; - if (val&8) amiga.useV[3]=true; - if (val&16) amiga.useP[0]=true; - if (val&32) amiga.useP[1]=true; - if (val&64) amiga.useP[2]=true; - if (val&128) amiga.useP[3]=true; + if (val&1) useV[0]=true; + if (val&2) useV[1]=true; + if (val&4) useV[2]=true; + if (val&8) useV[3]=true; + if (val&16) useP[0]=true; + if (val&32) useP[1]=true; + if (val&64) useP[2]=true; + if (val&128) useP[3]=true; } else { - if (val&1) amiga.useV[0]=false; - if (val&2) amiga.useV[1]=false; - if (val&4) amiga.useV[2]=false; - if (val&8) amiga.useV[3]=false; - if (val&16) amiga.useP[0]=false; - if (val&32) amiga.useP[1]=false; - if (val&64) amiga.useP[2]=false; - if (val&128) amiga.useP[3]=false; + if (val&1) useV[0]=false; + if (val&2) useV[1]=false; + if (val&4) useV[2]=false; + if (val&8) useV[3]=false; + if (val&16) useP[0]=false; + if (val&32) useP[1]=false; + if (val&64) useP[2]=false; + if (val&128) useP[3]=false; } break; } @@ -316,31 +315,31 @@ void DivPlatformAmiga::rWrite(unsigned short addr, unsigned short val) { bool updateDMA=false; switch (addr&15) { case 0: // LCH - amiga.audLoc[ch]&=0xffff; - amiga.audLoc[ch]|=val<<16; + audLoc[ch]&=0xffff; + audLoc[ch]|=val<<16; updateDMA=true; break; case 2: // LCL - amiga.audLoc[ch]&=0xffff0000; - amiga.audLoc[ch]|=val&0xfffe; + audLoc[ch]&=0xffff0000; + audLoc[ch]|=val&0xfffe; updateDMA=true; break; case 4: // LEN - amiga.audLen[ch]=val; + audLen[ch]=val; updateDMA=true; break; case 6: // PER - amiga.audPer[ch]=val; + audPer[ch]=val; break; case 8: // VOL - amiga.audVol[ch]=val; + audVol[ch]=val; break; case 10: // DAT - amiga.audDat[0][ch]=val&0xff; - amiga.audDat[1][ch]=val>>8; + audDat[0][ch]=val&0xff; + audDat[1][ch]=val>>8; break; } - if (updateDMA && !amiga.audEn[ch]) { + if (updateDMA && !mustDMA[ch]) { UPDATE_DMA(ch); } } @@ -349,6 +348,20 @@ void DivPlatformAmiga::rWrite(unsigned short addr, unsigned short val) { } } +void DivPlatformAmiga::rWrite(unsigned short addr, unsigned short val) { + if (addr&1) return; + + //logV("%.3x = %.4x",addr,val); + if (!skipRegisterWrites) { + writes.push(QueuedWrite(addr,val)); + regPool[addr>>1]=val; + + if (dumpWrites) { + addWrite(addr,val); + } + } +} + void DivPlatformAmiga::updateWave(int ch) { for (int i=0; i=0 && chan[i].samplesong.sampleLen) { @@ -520,10 +540,6 @@ void DivPlatformAmiga::tick(bool sysTick) { chan[i].writeVol=false; chWrite(i,8,chan[i].outVol); } - if (chan[i].updateWave) { - chan[i].updateWave=false; - updateWave(i); - } } if (updateADKCon) { @@ -717,6 +733,7 @@ void DivPlatformAmiga::muteChannel(int ch, bool mute) { } void DivPlatformAmiga::forceIns() { + logV("at time of clear: %d",writes.size()); for (int i=0; i<4; i++) { chan[i].insChanged=true; chan[i].freqChanged=true; @@ -738,6 +755,7 @@ DivDispatchOscBuffer* DivPlatformAmiga::getOscBuffer(int ch) { } void DivPlatformAmiga::reset() { + writes.clear(); memset(regPool,0,256*sizeof(unsigned short)); for (int i=0; i<4; i++) { chan[i]=DivPlatformAmiga::Channel(); @@ -750,6 +768,7 @@ void DivPlatformAmiga::reset() { filterOn=false; filtConst=filterOn?filtConstOn:filtConstOff; updateADKCon=true; + delay=0; amiga=Amiga(); // enable DMA diff --git a/src/engine/platform/amiga.h b/src/engine/platform/amiga.h index a05a5994d..903d7bd31 100644 --- a/src/engine/platform/amiga.h +++ b/src/engine/platform/amiga.h @@ -21,6 +21,7 @@ #define _AMIGA_H #include "../dispatch.h" +#include "../../fixedQueue.h" #include "../waveSynth.h" class DivPlatformAmiga: public DivDispatch { @@ -59,12 +60,14 @@ class DivPlatformAmiga: public DivDispatch { bool amigaModel; bool filterOn; bool updateADKCon; + short delay; struct Amiga { // register state bool audInt[4]; // interrupt on bool audIr[4]; // interrupt request bool audEn[4]; // audio DMA on + bool mustDMA[4]; // audio DMA must run bool useP[4]; // period modulation bool useV[4]; // volume modulation @@ -91,6 +94,8 @@ class DivPlatformAmiga: public DivDispatch { unsigned short hPos; // horizontal position of beam unsigned char state[4]; // current channel state + void write(unsigned short addr, unsigned short val); + Amiga() { memset(this,0,sizeof(*this)); } @@ -113,6 +118,14 @@ class DivPlatformAmiga: public DivDispatch { int sep1, sep2; + struct QueuedWrite { + unsigned short addr; + unsigned short val; + QueuedWrite(): addr(0), val(9) {} + QueuedWrite(unsigned short a, unsigned short v): addr(a), val(v) {} + }; + FixedQueue writes; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); friend class DivExportAmigaValidation; From 20537d5af01ff4551ec5712c10ec6968fa8da189 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 5 Nov 2023 18:06:01 -0500 Subject: [PATCH 02/16] Amiga: one more accuracy fix --- src/engine/platform/amiga.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 67853d902..c9fd0e2a2 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -168,12 +168,12 @@ void DivPlatformAmiga::acquire(short** buf, size_t len) { // output if (!isMuted[i]) { - if (amiga.audVol[i]>=64) { + if ((amiga.audVol[i]&127)>=64) { output=amiga.nextOut[i]<<6; - } else if (amiga.audVol[i]<=0) { + } else if ((amiga.audVol[i]&127)==0) { output=0; } else { - output=amiga.nextOut[i]*volTable[amiga.audVol[i]][amiga.volPos]; + output=amiga.nextOut[i]*volTable[amiga.audVol[i]&63][amiga.volPos]; } if (i==0 || i==3) { outL+=(output*sep1)>>7; @@ -182,7 +182,7 @@ void DivPlatformAmiga::acquire(short** buf, size_t len) { outL+=(output*sep2)>>7; outR+=(output*sep1)>>7; } - oscBuf[i]->data[oscBuf[i]->needle++]=(amiga.nextOut[i]*MIN(64,amiga.audVol[i]))<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=(amiga.nextOut[i]*MIN(64,amiga.audVol[i]&127))<<1; } else { oscBuf[i]->data[oscBuf[i]->needle++]=0; } From 76dec5f42647963f406fcd84efe7f1163fa5e5dd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 5 Nov 2023 18:06:13 -0500 Subject: [PATCH 03/16] update doc with Amiga vol/period mod info --- doc/7-systems/amiga.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/doc/7-systems/amiga.md b/doc/7-systems/amiga.md index af6bfb67f..981edf771 100644 --- a/doc/7-systems/amiga.md +++ b/doc/7-systems/amiga.md @@ -6,6 +6,28 @@ in this very computer music trackers were born... imported MOD files use this chip, and will set A-4 tuning to 436. +## amplitude/period modulation + +Amiga has support for (rather primitive) amplitude and period (frequency) modulation. +however, nobody has used this feature as it is rather useless, not well-documented and works in a complicated way. + +Amiga sample playback is done by two chips: Paula (the one that you probably know) and Agnus (the one that actually feeds Paula with samples). +Agnus has several DMA (direct memory access) units which read from chip memory independent of the CPU. four of these DMA units are used for samples. + +when DMA is enabled, Paula requests sample data from Agnus, and then plays these samples back. +there's a catch though. since the data bus is 16-bit, Paula requests **two** 8-bit samples at once! this explains why: +- the sample length registers are in words rather than bytes (thereby allowing samples up to 131070 in length) +- the maximum playback rate (31250Hz PAL; ~31469Hz NTSC) is two times the HBlank rate (Agnus fetches samples on HBlank, around 15625Hz on PAL or ~15734Hz on NTSC) + +during normal sample playback, the first sample is output and then the second. afterwards, two more samples are fetched, and so on. + +now, when amplitude or period modulation are enabled, things work differently. +the channel is silenced, and the two 8-bit samples are **treated as a big-endian 16-bit number**, which is then written to the next channel's volume or period. + +in the case of amplitude modulation, only the second sample is significant because the volume register uses 7 bits (to represent 0 to 64 (65 to 127 are treated as 64)) and the other bits are ignored. + +in the case of period modulation, both samples are significant. the first sample is the upper byte, and the second is the lower byte. + ## effects - `10xx`: **toggle low-pass filter.** `0` turns it off and `1` turns it on. From 7361160f3175ec2469d1d37775996e376b5a716b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 5 Nov 2023 18:26:00 -0500 Subject: [PATCH 04/16] GUI: wait what? --- src/gui/findReplace.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index f6bf5eedd..5f0d63218 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -103,6 +103,8 @@ void FurnaceGUI::doFind() { int lastRow=e->curSubSong->patLen-1; if (curQueryRangeY==1) { + finishSelection(); + firstRow=selStart.y; lastRow=selEnd.y; } From 4213bbb8139f4090e9072aa8402ff9376da165bb Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 5 Nov 2023 18:28:47 -0500 Subject: [PATCH 05/16] update to-do list --- TODO.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/TODO.md b/TODO.md index 523d5e171..af6e0f6c3 100644 --- a/TODO.md +++ b/TODO.md @@ -4,11 +4,8 @@ # THE REAL TO-DO LIST -- Amiga's Period Modulation not working - Song is silent after playing an order after loop point - Select loaded instrument on open - rewrite because I want a setting... -- re-engineer volume handling? Sound Unit cries at me -- finish status view - finish auto-clone once you have done all of this (maybe not the first one) and merged the two or so pending pull requests, release 0.6.1 From eedf6659bd9834b2e46f44faccbe8870d21e3b7f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 5 Nov 2023 18:36:26 -0500 Subject: [PATCH 06/16] update components.md --- doc/2-interface/components.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/2-interface/components.md b/doc/2-interface/components.md index 4ed6e6a44..695ecf1e4 100644 --- a/doc/2-interface/components.md +++ b/doc/2-interface/components.md @@ -21,7 +21,8 @@ the following keyboard shortcuts work while on a text field: these work similar to text fields, but you may only input numbers. -they also usually have `+` and `-` buttons which allow you to increase/decrease the amount when clicked (and rapidly do so when click-holding). +they also usually have `+` and `-` buttons which allow you to increase/decrease the value when clicked (and rapidly do so when holding). +additionally, Ctrl-clicking these buttons may increase/decrease the value by a coarse amount. ## sliders @@ -29,7 +30,8 @@ sliders are used for controlling values in a quick manner by being dragged. using the scroll wheel while holding Ctrl will change the slider's value by small amounts. -right-clicking or Ctrl-clicking or a slider (Command-click on macOS) will turn it into a number input field for a short period of time, allowing you to input precise values. +right-clicking or Ctrl-clicking or a slider (Command-click on macOS) will turn it into a number input field, allowing you to input precise values. +once you click away it will become a slider again. ## windows @@ -37,13 +39,13 @@ right-clicking or Ctrl-clicking or a slider (Command-click on macOS) will turn i windows may be moved, collapsed, closed or even docked around the workspace. -to move a window, press and hold the mouse button while on title bar or any empty space on it. +to move a window, press and hold the left mouse button while on the title bar or any empty space on it. then drag your mouse, and release it to stop moving. to resize a window, drag the bottom right corner (marked by a triangular tab) or the borders. to collapse a window, click on the triangle in the title bar. -clicking again expands it. +clicking again expands the window. to close a window, click on the `X` at the top right corner, or select it from the "window" menu. From 01f731ef653df6e1070e26c2bd847d24091f4d3b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 5 Nov 2023 19:31:39 -0500 Subject: [PATCH 07/16] prepare for built-in assembler --- src/divasm/divasm.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/divasm/divasm.h diff --git a/src/divasm/divasm.h b/src/divasm/divasm.h new file mode 100644 index 000000000..2846c98f8 --- /dev/null +++ b/src/divasm/divasm.h @@ -0,0 +1,30 @@ +struct DivASMResult { + int line, err; + DivASMResult(): + line(-1), + err(0) {} +}; + +struct DivASMFile { + String name; + SafeReader* data; +}; + +enum DivASMTarget { + DIV_ASM_TARGET_DUMMY=0, + DIV_ASM_TARGET_6502, + DIV_ASM_TARGET_SPC700 +}; + +class DivASM { + std::vector files; + SafeWriter* result; + + public: + DivASMResult getError(); + SafeWriter* assemble(String name); + void addFile(String name, SafeReader* data); + + DivASM(DivASMTarget target); + ~DivASM(); +}; From a3ea20bfeca311fcb7699ee6bd0e7c6dfba344f6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 6 Nov 2023 04:21:48 -0500 Subject: [PATCH 08/16] Amiga: fix loop --- src/engine/platform/amiga.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index c9fd0e2a2..e490937b4 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -204,11 +204,6 @@ void DivPlatformAmiga::irq(int ch) { if (chan[ch].irLocL==0x400 && chan[ch].irLocH==0 && chan[ch].irLen==1) { // turn off DMA rWrite(0x96,1< Date: Mon, 6 Nov 2023 04:25:27 -0500 Subject: [PATCH 09/16] Amiga: yet another fix... --- src/engine/platform/amiga.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index e490937b4..a884c21ce 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -738,6 +738,7 @@ void DivPlatformAmiga::forceIns() { for (int i=0; i<4; i++) { chan[i].insChanged=true; chan[i].freqChanged=true; + chan[i].writeVol=true; /*chan[i].keyOn=false; chan[i].keyOff=false; chan[i].sample=-1;*/ From 42d8de671a297c9e9c2050d33283dc1cdde1c48e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 6 Nov 2023 21:58:20 -0500 Subject: [PATCH 10/16] GUI: why is this setting in appearance --- src/gui/settings.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index de5fc62e1..86be7e547 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -2325,6 +2325,15 @@ void FurnaceGUI::drawSettings() { } ImGui::Unindent(); + // SUBSECTION ASSETS + CONFIG_SUBSECTION("Assets"); + + bool insTypeMenuB=settings.insTypeMenu; + if (ImGui::Checkbox("Display instrument type menu when adding instrument",&insTypeMenuB)) { + settings.insTypeMenu=insTypeMenuB; + settingsChanged=true; + } + END_SECTION; } CONFIG_SECTION("Appearance") { @@ -2888,12 +2897,6 @@ void FurnaceGUI::drawSettings() { settingsChanged=true; } - bool insTypeMenuB=settings.insTypeMenu; - if (ImGui::Checkbox("Display instrument type menu when adding instrument",&insTypeMenuB)) { - settings.insTypeMenu=insTypeMenuB; - settingsChanged=true; - } - // SUBSECTION MACRO EDITOR CONFIG_SUBSECTION("Macro Editor"); ImGui::Text("Macro editor layout:"); From 28cc26407f11a5162ced170d64200fb9e282009f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 7 Nov 2023 04:48:21 -0500 Subject: [PATCH 11/16] sfd;kljsdfkj;l --- doc/7-systems/c219.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/7-systems/c219.md b/doc/7-systems/c219.md index 44d0cafd0..3c27f6f7e 100644 --- a/doc/7-systems/c219.md +++ b/doc/7-systems/c219.md @@ -7,6 +7,12 @@ this chip features: - stereo soft panning - accepts either 8-bit PCM or proprietary 8-bit µ-law compressed PCM samples +## sample memory notice + +this chip is rather unique when it comes to sample memory. be sure to read this notice. + +the channels are PLEASE FINISH THIS LATER! + ## effects - `11xx`: **set noise mode.** From 10f48216e49aabbe9ab1ba7364b8a6e9da1a06ad Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 7 Nov 2023 05:34:40 -0500 Subject: [PATCH 12/16] finish C219 doc --- doc/7-systems/c219.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/7-systems/c219.md b/doc/7-systems/c219.md index 3c27f6f7e..89cffc7d6 100644 --- a/doc/7-systems/c219.md +++ b/doc/7-systems/c219.md @@ -11,7 +11,8 @@ this chip features: this chip is rather unique when it comes to sample memory. be sure to read this notice. -the channels are PLEASE FINISH THIS LATER! +the channels are in groups of four. a sample bank (128KB) may be selected for each group. +if a sample that is on a different bank plays in a group, the group is switched to that bank, and other channels will be silenced. ## effects From d6fd5df2c26192dafb03656f9247bf799f13f64d Mon Sep 17 00:00:00 2001 From: Electric Keet Date: Sun, 12 Nov 2023 19:08:49 -0800 Subject: [PATCH 13/16] OscXY doc. --- doc/8-advanced/README.md | 3 ++- doc/8-advanced/oscxy.md | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 doc/8-advanced/oscxy.md diff --git a/doc/8-advanced/README.md b/doc/8-advanced/README.md index 97ecd6f2c..9eba96fa2 100644 --- a/doc/8-advanced/README.md +++ b/doc/8-advanced/README.md @@ -18,7 +18,8 @@ as listed in the "Window" menu: - [piano](piano.md) - [oscilloscope](osc.md) -- [oscilloscopes (per-channel)](chanosc.md) +- [oscilloscope (per-channel)](chanosc.md) +- [oscilloscope (X-Y)](oscxy.md) - [clock](clock.md) - [register view](regview.md) - [log viewer](log-viewer.md) diff --git a/doc/8-advanced/oscxy.md b/doc/8-advanced/oscxy.md new file mode 100644 index 000000000..06b5e2f89 --- /dev/null +++ b/doc/8-advanced/oscxy.md @@ -0,0 +1,16 @@ +# oscilloscope (X-Y) + +the "Oscilloscope (X-Y)" dialog shows an oscilloscope that plots two sound channels at once, each on their own axis. this can be used to visualize stereo separation. + +right-clicking the view will change it to a configuration dialog: +- **X channel**: sound channel to draw on the horizontal axis. default is 1 (left channel). + - **Invert**: flips it horizontally. +- **Y channel**: sets the sound channel to draw on the vertical axis. default is 2 (right channel). + - **Invert**: flips it vertically. +- **Zoom**: size of the plot. +- **Samples**: number of samples drawn each frame. +- **Decay Time (ms)**: duration before drawn lines disappear. +- **Intensity**: brightness of the drawn lines. +- **Line Thickness**: width of the drawn lines. + +click **OK** to return to the oscilloscope view. \ No newline at end of file From a7befd2e180e9cc2964e7afe339fce2b36ba2bfc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 12 Nov 2023 22:52:22 -0500 Subject: [PATCH 14/16] fix osc.md --- doc/8-advanced/osc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/8-advanced/osc.md b/doc/8-advanced/osc.md index db625e71c..de58d70f4 100644 --- a/doc/8-advanced/osc.md +++ b/doc/8-advanced/osc.md @@ -1,6 +1,6 @@ # oscilloscope -the Oscilloscope shows the waveform of the mix of all currently playing sounds. +the Oscilloscope shows the audio output as a waveform. ![oscilloscope view](osc.png) From 5c199315e0cf5fa88361e9347030cc4b4eb0f533 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 12 Nov 2023 23:01:44 -0500 Subject: [PATCH 15/16] X-Y osc documentation --- doc/8-advanced/README.md | 1 + doc/8-advanced/xyosc.md | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 doc/8-advanced/xyosc.md diff --git a/doc/8-advanced/README.md b/doc/8-advanced/README.md index 97ecd6f2c..4a9512823 100644 --- a/doc/8-advanced/README.md +++ b/doc/8-advanced/README.md @@ -18,6 +18,7 @@ as listed in the "Window" menu: - [piano](piano.md) - [oscilloscope](osc.md) +- [oscilloscope (X-Y)](xyosc.md) - [oscilloscopes (per-channel)](chanosc.md) - [clock](clock.md) - [register view](regview.md) diff --git a/doc/8-advanced/xyosc.md b/doc/8-advanced/xyosc.md new file mode 100644 index 000000000..5c8608243 --- /dev/null +++ b/doc/8-advanced/xyosc.md @@ -0,0 +1,17 @@ +# oscilloscope (X-Y) + +also called "vectorscope", this is similar to the normal oscilloscope in that it draws audio output as a waveform, but instead of being one-dimensional and going from left to right, it is plotted in two dimensions (usually X represents left output and Y represents right output). + +(TODO: image) + +right-clicking the X-Y oscilloscope window displays settings: +- **X Channel**: the output channel which will affect the X (left-right) axis. 1 is left. + - **Invert**: flips the axis. +- **Y Channel**: the output channel which will affect the Y (up-down) axis. 2 is right. + - **Invert**: flips the axis. +- **Zoom**: changes amplitude, making the plot bigger or smaller. +- **Samples**: the maximum number of samples to use for plotting. + - this setting may be replaced by another or removed in a future version. +- **Decay Time (ms)**: sets how long it takes for the points/lines to fade away. +- **Intensity**: changes the brightness of the dots/lines. +- **Line Thickness**: sets how thick lines are. From bb1cbbc403f6759aa7c70d8b1e6bc7f514e703bc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 12 Nov 2023 23:49:20 -0500 Subject: [PATCH 16/16] doc de-awkwardization --- doc/8-advanced/channels.md | 8 ++--- doc/8-advanced/chanosc.md | 60 ++++++++++++++++++---------------- doc/8-advanced/chip-manager.md | 12 +++---- doc/8-advanced/comments.md | 2 +- doc/8-advanced/compat-flags.md | 2 +- doc/8-advanced/grooves.md | 14 +++----- doc/8-advanced/osc.md | 6 ++-- 7 files changed, 52 insertions(+), 52 deletions(-) diff --git a/doc/8-advanced/channels.md b/doc/8-advanced/channels.md index a57698559..5b70f00dd 100644 --- a/doc/8-advanced/channels.md +++ b/doc/8-advanced/channels.md @@ -5,8 +5,8 @@ the "Channels" dialog allows manipulation of the song's channels. ![channels dialog](channels.png) each channel has the following options: -- **Visible**: uncheck the box to hide the channel from view. pattern data will be kept. +- **Visible**: uncheck the box to hide the channel from the pattern view. pattern data will be kept. - crossed-arrows button: click and drag to rearrange pattern data throughout the song. - - note: this does _not_ move channels around within a chip! it only affects pattern data. -- **Name** is the name displayed at the top of each channel in the tracker view. -- to the right of that is the abbreviation used above each channel in the order view. + - note: this does **not** move channels around! it only moves the channel's pattern data. +- **Name**: the name displayed at the top of each channel in the pattern view. +- the next setting is "short name", which is displayed in the orders view and/or when a channel is collapsed. diff --git a/doc/8-advanced/chanosc.md b/doc/8-advanced/chanosc.md index b811add81..8521c099f 100644 --- a/doc/8-advanced/chanosc.md +++ b/doc/8-advanced/chanosc.md @@ -1,25 +1,24 @@ # oscilloscope (per-channel) -the "Oscilloscope (per-channel)" dialog shows an individual oscilloscope for each channel during playback. +the "Oscilloscope (per-channel)" windows displays several oscilloscope views (one per channel). ![oscilloscope per-channel configuration view](chanosc.png) -right-clicking within the view will change it to the configuration view shown above: -- **Columns**: arranges oscilloscopes into this many columns. -- **Size (ms)**: sets what length of audio is visible in each oscilloscope. -- **Center waveform**: does its best to latch the waveform to the channel's note frequency and centers the display. +right-clicking the view will display the configuration view shown above: +- **Columns**: sets the amount of columns for the oscilloscope views. +- **Size (ms)**: sets how much of a channel's output is captured for the oscilloscope view. +- **Center waveform**: when enabled, the displayed waveforms will be centered using an auto-correlation algorithm. - **Automatic columns**: sets the number of columns based on the number of channels. - **Off**: use the Columns setting. - **Mode 1**: always fewer columns than rows. - **Mode 2**: bias slightly toward more columns. - **Mode 3**: always more columns than rows. -- **Amplitude**: scales amplitude for all oscilloscopes. -- **Gradient**: see below. -- the color selector sets the color for all waveforms. right-clicking on it pops up an option dialog: - - select between the square selector and the color wheel selector. - - **Alpha bar**: adds a transparency selector. -- the boxes below that are for selecting colors numerically by red-green-blue-alpha, hue-saturation-value-alpha, and HTML-style RGBA in hex. -- **Text format**: this string determins what text is shown in the top-left of each oscilloscope. it can be any text, and the following shortcodes will be replaced with information about the channel: +- **Amplitude**: scales amplitude for all oscilloscope views. +- **Gradient**: this allows you to use a gradient for determining the waveforms' colors instead of a single color. see the gradient section for more information. + - if this option is off, a color selector will be displayed. right-click on it for some options: + - select between the square selector and the color wheel selector. + - **Alpha bar**: display an opacity bar. +- **Text format**: this allows you to display some text on each oscilloscope view. the following codes may be used: - `%c`: channel name - `%C`: channel short name - `%d`: channel number (starting from 0) @@ -35,27 +34,32 @@ right-clicking within the view will change it to the configuration view shown ab - `%V`: volume (percentage) - `%b`: volume (hex) - `%%`: percent sign -- the OK button returns from options view to the oscilloscopes. + +click on OK to return to the main view. ## gradient ![oscilloscope per-channel gradient configuration view](chanosc-gradient.png) -in this mode, the color selector is replaced by a square field onto which circular "stops" can be placed. each stop adds a soft circle of color. the resulting image is used to look up the oscilloscope color as determined by each axis. +when enabling the Gradient setting, a gradient view is displayed in where circular "points" can be placed. +each point adds a color spot. +the resulting image is used to look up the waveform's color as determined by each axis. -- right-click to place a stop. -- left-click on a stop to change its color. the color selector is the same as above, with two additions: +- right-click to place a point. +- left-click on a point to change its color: + - a color picker is displayed, alongside two settings. - **Distance**: the size of the circle. - - **Spread**: the size of the solid center of the circle. increasing it fills more of the circle with the target color. + - **Spread**: the size of the solid center of the circle. increasing it fills more of the circle with the color. +- middle-click on a point to delete it. -- **Background**: sets background color for entire field. -- **X Axis**: determines what the horizontal maps to, from left to right. -- **Y Axis**: determines what the vertical maps to. from bottom to top. these can be set to the following: - - **None (0%)**: stays at the left or bottom. - - **None (50%)**: stays at the center. - - **None (100%)**: stays at the right or top. - - **Frequency**: changes color with note frequency. - - **Volume**: changes color with volume. - - **Channel**: changes color based on channel number. - - **Brightness**: currently does nothing. - - **Note Trigger**: changes color when a new note is played. +- **Background**: sets the gradient's background color. +- **X Axis**: determines what the horizontal axis maps to. +- **Y Axis**: determines what the vertical axis maps to. these can be set to the following: + - **None (0%)**: always left or bottom + - **None (50%)**: always center + - **None (100%)**: always right or top + - **Frequency**: changes color with frequency + - **Volume**: changes color with volume + - **Channel**: changes color based on channel number (first channel is 0% and last is 100%) + - **Brightness**: currently does nothing + - **Note Trigger**: changes color when a new note is played diff --git a/doc/8-advanced/chip-manager.md b/doc/8-advanced/chip-manager.md index bcfb6006d..72d8ff66a 100644 --- a/doc/8-advanced/chip-manager.md +++ b/doc/8-advanced/chip-manager.md @@ -1,15 +1,15 @@ # chip manager -the **chip manager** window does exactly what it says. +the **chip manager** window allows you to manage chips, including adding, changing, moving or removing them. ![chip manager](chip-manager.png) -**Preserve channel order**: make existing pattern data stay in place even when chips are rearranged. if turned off, pattern data will rearrange to match (the default, and usually the desired behavior). +**Preserve channel order**: make existing pattern data stay in place even when chips are rearranged. when turned off, pattern data will be arranged to match (the default, and usually desired behavior). -to move a chip around, click and drag the ![crossed-arrows](chip-manager-move.png) button to its left. +to move a chip around, click and drag the ![crossed-arrows](chip-manager-move.png) button to the left. -to replace a chip with a different one, click the **Change** button and select the replacement. +to replace a chip with a different one, click the **Change** button. this will display the chip selector. -to remove a chip entirely, click the ![X](chip-manager-remove.png) button. +to remove a chip, click the ![X](chip-manager-remove.png) button. -click a chip's name to open its options, where one can set clock rate, chip variant, and other specifics. \ No newline at end of file +click on a chip's name to open chip configuration. this allows you to change chip options, such as clock rate, chip type and so on. diff --git a/doc/8-advanced/comments.md b/doc/8-advanced/comments.md index ebb05d700..eb0fae144 100644 --- a/doc/8-advanced/comments.md +++ b/doc/8-advanced/comments.md @@ -4,4 +4,4 @@ comments, credits, or any arbitrary text may be entered here. it has no effect on the song. -there is no word wrap; long lines must be broken manually with the Enter key. +there is no word wrap; long lines must be broken manually with the Enter/Return key. diff --git a/doc/8-advanced/compat-flags.md b/doc/8-advanced/compat-flags.md index 6e050a410..e5ab02826 100644 --- a/doc/8-advanced/compat-flags.md +++ b/doc/8-advanced/compat-flags.md @@ -1,5 +1,5 @@ # compatibility flags -the **Compatibility Flags** window contains several tabs full of settings that change aspects of tracking and playback. a new Furnace song will have these disabled, while opening a DefleMask module, .mod, or earlier Furnace file will automatically set the appropriate options. +the **Compatibility Flags** window contains several tabs full of settings that change playback behavior. a new Furnace song will have these disabled, while opening a DefleMask module, .mod, or earlier Furnace file will automatically set the appropriate options. hovering over most options will bring up additional info about them. it is not recommended to change any of these, especially the ones in the DefleMask and Old Furnace sections. diff --git a/doc/8-advanced/grooves.md b/doc/8-advanced/grooves.md index 38775c5ab..3f566a7de 100644 --- a/doc/8-advanced/grooves.md +++ b/doc/8-advanced/grooves.md @@ -1,9 +1,6 @@ # grooves -grooves are macros for speed. - -a **groove** is the equivalent of repeating `0Fxx` commands on each row to get a cycle of speeds. for example, a groove of "6 4 5 3" makes the first row 6 ticks long, the next row 4 ticks, then 5, 3, 6, 4, 5, 3... - +a **groove** is the equivalent of repeating `0Fxx` effects on each row to get a cycle of speeds. for example, a groove of "6 4 5 3" makes the first row 6 ticks long, the next row 4 ticks, then 5, 3, 6, 4, 5, 3... ![groove](groove.png) @@ -13,18 +10,17 @@ to set the song's groove: - click again so it becomes "Groove". - enter a sequence of up to 16 speeds. - ![groove patterns](grooves.png) -the "Grooves" window is for entering preset groove patterns. -- the **`+`** button adds a new groove pattern; click in the pattern to edit it. +the "Grooves" window displays the list of groove patterns in the song. +- the **`+`** button adds a new groove pattern; click in the groove pattern to edit it. - the **`×`** buttons remove them. a single `09xx` command will switch to the matching numbered groove pattern. -## BPM +## tempo -this is a non-exhaustive list of grooves and their equivalent BPM. +this is a non-exhaustive list of grooves and their equivalent tempo in BPM. note: this table assumes a song's tick rate setting is left at its default value for the chosen engine speed: 60 for NTSC, or 50 for PAL. diff --git a/doc/8-advanced/osc.md b/doc/8-advanced/osc.md index de58d70f4..145a26e39 100644 --- a/doc/8-advanced/osc.md +++ b/doc/8-advanced/osc.md @@ -4,6 +4,6 @@ the Oscilloscope shows the audio output as a waveform. ![oscilloscope view](osc.png) -right-clicking on the oscilloscope toggles the adjustment sliders: -- waveform height zoom -- width of viewed audio (window size) in milliseconds. +right-clicking on the oscilloscope toggles adjustment sliders: +- waveform height (zoom) +- window size (how much of the output to display) in milliseconds.