diff --git a/Makefile b/Makefile index fc575b4..c2ee968 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,9 @@ FQBN = adafruit:samd:adafruit_trellis_m4 +UF2_MOUNT = /mnt/chromeos/removable/TRELM4BOOT default: build/uilleann.ino.uf2 +install: build/uilleann.ino.uf2 + ./install.sh $< $(UF2_MOUNT) # uf2conv.py is covered by an MIT license. build/uf2conv.py: diff --git a/dx9.h b/algorithms.h similarity index 67% rename from dx9.h rename to algorithms.h index f52434e..e4cf919 100644 --- a/dx9.h +++ b/algorithms.h @@ -1,4 +1,4 @@ -// FM Algorithms used by the DX9 +// Various FM Algorithms // Excellent write-up: // https://gist.github.com/bryc/e997954473940ad97a825da4e7a496fa @@ -7,8 +7,37 @@ // Each operator has 4 input gains and one output gain: // { 1→, 2→, 3→, 4→, →out} +// 1→ +#define ALG_SIMPLE \ + { \ + {0, 0, 0, 0, 1}, \ + {0}, \ + {0}, \ + {0}, \ + } + +// ⮎2→1→ +#define ALG_OPL2_1(feedback) \ + { \ + {0, 1, 0, 0, 1}, \ + {0, feedback, 0, 0, 0}, \ + {0}, \ + {0}, \ + } + +// ⮎2→ +// 1→ +#define ALG_OPL2_2(feedback) \ + { \ + {0, 0, 0, 0, 1} \ + {0, feedback, 0, 0, 1} \ + {0}, \ + {0}, \ + } + + // ⮎4→3→2→1→ -#define DX9_ALG_1(feedback) \ +#define ALG_DX9_1(feedback) \ { \ {0, 1, 0, 0, 1}, \ {0, 0, 1, 0, 0}, \ @@ -18,7 +47,7 @@ // ⮎4⬎ // 3→2→1→ -#define DX9_ALG_2(feedback) \ +#define ALG_DX9_2(feedback) \ { \ {0, 1, 0, 0, 1}, \ {0, 0, 1, 1, 0}, \ @@ -28,7 +57,7 @@ // ⮎4⬎ // 3→2→1→ -#define DX9_ALG_3(feedback) \ +#define ALG_DX9_3(feedback) \ { \ {0, 1, 0, 1, 1}, \ {0, 0, 1, 0, 0}, \ @@ -38,7 +67,7 @@ // ⮎4→3⬎ // 2→1→ -#define DX9_ALG_4(feedback) \ +#define ALG_DX9_4(feedback) \ { \ {0, 1, 0, 1, 1}, \ {0, 0, 1, 0, 0}, \ @@ -48,7 +77,7 @@ // ⮎4→3→ // 2→1→ -#define DX9_ALG_5(feedback) \ +#define ALG_DX9_5(feedback) \ { \ {0, 1, 0, 0, 1}, \ {0, 0, 0, 0, 0}, \ @@ -59,7 +88,7 @@ // 1→ // ⮎4→2→ // 3→ -#define DX9_ALG_6(feedback) \ +#define ALG_DX9_6(feedback) \ { \ {0, 0, 0, 0, 1}, \ {0, 0, 0, 1, 1}, \ @@ -70,7 +99,7 @@ // 1→ // 2→ // ⮎4→3→ -#define DX9_ALG_7(feedback) \ +#define ALG_DX9_7(feedback) \ { \ {0, 0, 0, 0, 1}, \ {0, 0, 0, 0, 1}, \ @@ -82,7 +111,7 @@ // 2→ // 3→ // ⮎4→ -#define DX9_ALG_8(feedback) \ +#define ALG_DX9_8(feedback) \ { \ {0, 0, 0, 0, 1}, \ {0, 0, 0, 0, 1}, \ diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..3ca4683 --- /dev/null +++ b/install.sh @@ -0,0 +1,15 @@ +#! /bin/sh + +src=$1 +dst=$2 + +info=$dst/INFO_UF2.txt +echo -n "Waiting for $info to appear..." +while ! [ -f $info ]; do + echo -n "." + sleep 1 +done +echo "👍" + +cp $src $dst +echo "Installed!" diff --git a/notes.cpp b/notes.cpp index 6732035..e562074 100644 --- a/notes.cpp +++ b/notes.cpp @@ -19,12 +19,9 @@ void setupJustPitches(uint8_t baseNote, float basePitch) { JustPitches[baseNote + 7] = basePitch * 3 / 2; // A JustPitches[baseNote + 8] = basePitch * 8 / 5; // Bb JustPitches[baseNote + 9] = basePitch * 5 / 3; // B - JustPitches[baseNote + 10] = basePitch * 9 / 5; // C + JustPitches[baseNote + 10] = basePitch * 16 / 9; // C (fourth up from G) JustPitches[baseNote + 11] = basePitch * 15 / 8; // C# - // Two fourths up from the base pitch, so G major scale sounds right - JustPitches[baseNote + 11] = basePitch * 8 / 3; // C# - // Octaves for (int note = baseNote; note < baseNote + 12; note++) { for (int i = 1; i < 9; i++) { diff --git a/patches.h b/patches.h index 1c80285..be528c7 100644 --- a/patches.h +++ b/patches.h @@ -1,39 +1,45 @@ // "Factory" patches #pragma once -#include "dx9.h" +#include "algorithms.h" // Waveform, offset, multiplier, delay, attack, holdAmp, hold, decay, sustainAmp, release FMPatch Bank[] = { { - "Venus Oboe", - DX9_ALG_5(0), + "Square", + ALG_SIMPLE, { - // Waveform off mult del att hldA hld dec susA rel - {WAVEFORM_SINE, 0, 1.00, 0, 10.5, 1.0, 10.5, 0, 0.75, 5}, - {WAVEFORM_SINE, 0, 4.00, 0, 10.5, 1.0, 10.5, 0, 0.80, 5}, - {WAVEFORM_SINE, 0, 8.00, 0, 10.5, 1.0, 10.5, 0, 0.50, 5}, - {WAVEFORM_SINE, 0, 16.00, 0, 10.5, 1.0, 50.0, 0, 0.75, 5}, + // Waveform offs mult dely attk hldA hld decy susA rels + {WAVEFORM_SQUARE, 0, 1.00, 0, 10.5, 0.8, 10.5, 10, 0.50, 5}, + }, + }, + { + "Tubey", + ALG_OPL2_1(0), + { + // Waveform offs mult dely attk hldA hld decy susA rels + {WAVEFORM_SINE, 0, 1.00, 0, 10.5, 1.0, 10.5, 10, 0.80, 5}, + {WAVEFORM_SINE, 0, 8.00, 0, 10.5, 0.2, 10.5, 10, 0.10, 5}, }, }, { "IWantPizza", - DX9_ALG_1(0), + ALG_DX9_1(0), { - {WAVEFORM_SINE, 0, 4.00, 0, 10.5, 1.0, 10.5, 0, 0.35, 20}, - {WAVEFORM_SINE, 0, 1.00, 0, 10.5, 1.0, 10.5, 0, 0.30, 20}, - {WAVEFORM_SINE, 0, 8.00, 0, 10.5, 1.0, 10.5, 0, 0.50, 20}, - {WAVEFORM_SINE, 0, 16.00, 0, 10.5, 1.0, 50, 0, 0.25, 20}, + {WAVEFORM_SINE, 0, 4.00, 0, 10.5, 1.0, 10.5, 0, 0.35, 20}, + {WAVEFORM_SINE, 0, 1.00, 0, 10.5, 1.0, 10.5, 0, 0.30, 20}, + {WAVEFORM_SINE, 0, 8.00, 0, 10.5, 1.0, 10.5, 0, 0.50, 20}, + {WAVEFORM_SINE, 0, 16.00, 0, 10.5, 1.0, 50, 0, 0.25, 20}, }, }, { "Ray Gun", - DX9_ALG_1(0), + ALG_DX9_1(0), { - {WAVEFORM_SINE, 0, 1.00, 0, 10.5, 1.0, 10.5, 0, 0.35, 20}, - {WAVEFORM_SINE, 0, 1.00, 0, 10.5, 1.0, 10.5, 0, 0.30, 20}, - {WAVEFORM_SINE, 0, 9.00, 0, 10.5, 1.0, 10.5, 0, 0.00, 20}, - {WAVEFORM_SINE, 0, 1.00, 0, 10.5, 1.0, 50, 0, 0.25, 8}, + {WAVEFORM_SINE, 0, 1.00, 0, 10.5, 1.0, 10.5, 0, 0.35, 20}, + {WAVEFORM_SINE, 0, 1.00, 0, 10.5, 1.0, 10.5, 0, 0.30, 20}, + {WAVEFORM_SINE, 0, 9.00, 0, 10.5, 1.0, 10.5, 0, 0.00, 20}, + {WAVEFORM_SINE, 0, 1.00, 0, 10.5, 1.0, 50, 0, 0.25, 8}, }, }, }; diff --git a/synth.cpp b/synth.cpp index 8fa147d..f72bf09 100644 --- a/synth.cpp +++ b/synth.cpp @@ -20,6 +20,7 @@ void FMVoiceLoadPatch(FMVoice *v, FMPatch *p) { } v->outputMixer.gain(i, p->gains[i][NUM_OPERATORS]); } + v->patch = p; } void FMVoiceSetPitch(FMVoice *v, float freq) { diff --git a/synth.h b/synth.h index 21eb2db..c2eb72b 100644 --- a/synth.h +++ b/synth.h @@ -93,11 +93,11 @@ typedef struct FMVoice { #define FMOperatorWiring(name, i) \ {name.mixers[i], 0, name.oscillators[i], 0}, \ {name.oscillators[i], 0, name.envelopes[i], 0}, \ - {name.envelopes[i], 0, name.outputMixer, i}, \ {name.envelopes[i], 0, name.mixers[0], i}, \ {name.envelopes[i], 0, name.mixers[1], i}, \ {name.envelopes[i], 0, name.mixers[2], i}, \ - {name.envelopes[i], 0, name.mixers[3], i} + {name.envelopes[i], 0, name.mixers[3], i}, \ + {name.envelopes[i], 0, name.outputMixer, i} /** FMVoiceWiring outputs AudioConnection initializer to wire one FMVoice */ diff --git a/uilleann.ino b/uilleann.ino index 96e1d0e..46b96bd 100644 --- a/uilleann.ino +++ b/uilleann.ino @@ -9,6 +9,7 @@ #include "notes.h" #include "fingering.h" +#define DEBUG #define KNEE_OFFSET 0 #define KEY_OFFSET 2 @@ -23,7 +24,16 @@ AudioMixer4 mixL; AudioMixer4 mixR; AudioOutputAnalogStereo dacs1; +#ifdef DEBUG +AudioSynthNoiseWhite debug; +#endif + AudioConnection FMVoicePatchCords[] = { +#ifdef DEBUG + {debug, 0, mixL, 3}, + {debug, 0, mixR, 3}, +#endif + {Chanter.outputMixer, 0, biquad1, 0}, {biquad1, 0, mixL, 0}, {biquad1, 0, mixR, 0}, @@ -61,7 +71,6 @@ Adafruit_NeoTrellisM4 trellis = Adafruit_NeoTrellisM4(); MicroOLED oled(9, 1); QwiicButton bag; - void setup() { setupJustPitches(NOTE_D4, PITCH_D4); pinMode(LED_BUILTIN, OUTPUT); @@ -102,6 +111,12 @@ void setup() { // Initialize processor and memory measurements AudioProcessorUsageMaxReset(); AudioMemoryUsageMaxReset(); + +#ifdef DEBUG + debug.amplitude(0.1); + mixL.gain(3, 0.1); + mixR.gain(3, 0.1); +#endif } #define BUTTON_UP 0 @@ -152,8 +167,10 @@ void updateTunables(uint8_t buttons, int note) { } } - mixL.gain(0, gain); - mixR.gain(0, gain); + for (int i=0; i<3; i++) { + mixL.gain(i, gain); + mixR.gain(i, gain); + } trellis.setPixelColor(BUTTON_VOLUME, trellis.ColorHSV(uint16_t(gain * 65535), 255, 80)); if (!note || (note == NOTE_CS5)) {