From 5df6ebd6cc422569fe89588ae3ae7148337b2c49 Mon Sep 17 00:00:00 2001 From: eh2k Date: Sun, 27 Oct 2024 16:25:42 +0100 Subject: [PATCH] devsync 2cd9d0a --- .github/workflows/build.yml | 8 +- README.md | 102 +++- app/CV/EnvGen_ADSR.bin | Bin 0 -> 5404 bytes app/CV/EnvGen_ADSR.cpp | 117 ++++ app/DRUMS/Djembe.bin | Bin 6532 -> 6476 bytes app/DRUMS/TR707-HiHat.bin | Bin 1412 -> 0 bytes app/DRUMS/TR707-HiHat.cpp | 33 -- app/DRUMS/TR707.bin | Bin 2156 -> 3012 bytes app/DRUMS/TR707.cpp | 113 +++- app/DRUMS/TR909-HiHat.bin | Bin 1412 -> 1620 bytes app/DRUMS/TR909-HiHat.cpp | 14 +- app/DRUMS/TR909-Ride.bin | Bin 1404 -> 1628 bytes app/DRUMS/TR909-Ride.cpp | 15 +- app/DRUMS/resources/braids_lut_env.hpp | 105 ++++ app/DRUMS/resources/peaks_lut_env.hpp | 271 +++++++++ app/DRUMS/resources/peaks_lut_osc.hpp | 548 ++++++++++++++++++ app/DRUMS/resources/peaks_lut_svf.hpp | 203 +++++++ app/FX/Delay.bin | Bin 3108 -> 3056 bytes app/FX/Gated-Reverb.bin | Bin 5704 -> 5536 bytes app/FX/JU60_chorus.bin | Bin 7840 -> 8004 bytes app/FX/Rev-Dattorro.bin | Bin 3984 -> 3928 bytes app/FX/Reverb-HP-LP.bin | Bin 5272 -> 5104 bytes app/FX/Reverb.bin | Bin 2652 -> 2596 bytes app/FX/ReverbSC.bin | Bin 3108 -> 3052 bytes app/GND/FFT.bin | Bin 12040 -> 12520 bytes app/GND/FFT.cpp | 4 +- app/GND/Scope.bin | Bin 1692 -> 1692 bytes app/M-OSC/Waveforms.bin | Bin 0 -> 104392 bytes app/M-OSC/Waveforms.cpp | 189 ++++++ app/MIDI/Clock.bin | Bin 2100 -> 2052 bytes app/MIDI/Monitor.bin | Bin 2276 -> 2240 bytes app/MIDI/VAx6.bin | Bin 17376 -> 17324 bytes app/MIDI/VAx6.cpp | 1 - app/NOISE/808_squares.bin | Bin 2152 -> 2096 bytes app/NOISE/808_squares.cpp | 2 +- app/NOISE/NES.bin | Bin 2120 -> 2068 bytes app/NOISE/NES.cpp | 2 +- app/NOISE/WhitePink.bin | Bin 1944 -> 1892 bytes app/NOISE/WhitePink.cpp | 3 +- app/SEQ/EuclidArp.bin | Bin 0 -> 8724 bytes app/SEQ/EuclidArp.cpp | 385 ++++++++++++ app/SEQ/EuclidRythm.bin | Bin 0 -> 3768 bytes app/SEQ/EuclidRythm.cpp | 302 ++++++++++ app/SPEECH/LPC.bin | Bin 21328 -> 21276 bytes app/SPEECH/LPC.cpp | 2 - app/SPEECH/SAM.bin | Bin 27700 -> 27644 bytes app/SYNTH/Open303.bin | Bin 37120 -> 34952 bytes app/SYNTH/Open303.cpp | 2 - app/SYNTH/Resonator.bin | Bin 57756 -> 57712 bytes app/SYNTH/Resonator.cpp | 3 +- app/build.sh | 30 +- app/index.json | 13 +- app/squares-and-circles-api.h | 174 +++--- app/upload.py | 169 ++++++ build.py | 97 +--- doc/.conv.sh | 2 +- doc/engines.png | Bin 13442 -> 14518 bytes doc/mod_seq.png | Bin 0 -> 1678 bytes lib/bbd/bbd_line.cc | 26 +- lib/bbd/bbd_line.h | 11 +- lib/braids/settings.cc | 1 + lib/misc/euclidean.h | 118 ++++ .../rosic_FourierTransformerRadix2.cpp | 9 +- .../rosic_FourierTransformerRadix2.h | 8 + .../rosic_MipMappedWaveTable.cpp | 4 +- lib/peaks/modulations/multistage_envelope.cc | 8 +- lib/plaits/dsp/chords/chord_bank.cc | 4 +- lib/rings/resources.cc | 10 - lib/stmlib/dsp/units.h | 46 ++ lib/udynlink | 2 +- platformio.ini | 7 +- test/test_midi.sh | 15 +- 72 files changed, 2854 insertions(+), 324 deletions(-) create mode 100644 app/CV/EnvGen_ADSR.bin create mode 100644 app/CV/EnvGen_ADSR.cpp delete mode 100644 app/DRUMS/TR707-HiHat.bin delete mode 100644 app/DRUMS/TR707-HiHat.cpp create mode 100644 app/DRUMS/resources/braids_lut_env.hpp create mode 100644 app/DRUMS/resources/peaks_lut_env.hpp create mode 100644 app/DRUMS/resources/peaks_lut_osc.hpp create mode 100644 app/DRUMS/resources/peaks_lut_svf.hpp create mode 100644 app/M-OSC/Waveforms.bin create mode 100644 app/M-OSC/Waveforms.cpp create mode 100644 app/SEQ/EuclidArp.bin create mode 100644 app/SEQ/EuclidArp.cpp create mode 100644 app/SEQ/EuclidRythm.bin create mode 100644 app/SEQ/EuclidRythm.cpp create mode 100755 app/upload.py create mode 100644 doc/mod_seq.png create mode 100644 lib/misc/euclidean.h diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 10535ad..be7d553 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,13 +25,11 @@ jobs: export GCC_PATH=/$(realpath .)/xpack-arm-none-eabi-gcc-10.3.1-2.1/bin/ export PATH="${PATH}:/$(realpath .)/xpack-arm-none-eabi-gcc-10.3.1-2.1/bin/" arm-none-eabi-gcc --version - pip install intelhex subprocess32 pyelftools Jinja2 + pip install intelhex subprocess32 pyelftools Jinja2 platformio find ./app -type f -name *.bin -exec touch {} + git submodule update --init sh ./app/build.sh git status - pip install --upgrade platformio mido python-rtmidi intelhex - pio run -v --environment squares-and-circles - name: pack_artifacts run: | export hash=$(git rev-parse --short HEAD) @@ -42,6 +40,6 @@ jobs: mv -v "$f" $HEX_FILE zip -j -9 $ZIP_FILE $HEX_FILE .github/workflows/LICENSE.txt $(dirname ${f%.*})/loader.sha sha256sum $ZIP_FILE - curl -fs -X PUT -u ${{ secrets.UPLOAD_KEY }} ${{ secrets.LATEST_DROP_FOLDER }}/${FIRMWARE}_engines_latest.zip --upload-file $ZIP_FILE || true - curl -fs -X PUT -u ${{ secrets.UPLOAD_KEY }} ${{ secrets.LATEST_DROP_FOLDER }}/${FIRMWARE}_engines_latest.sha -d "$hash" + curl -fs -X PUT -u ${{ secrets.UPLOAD_KEY }} ${{ secrets.LATEST_DROP_FOLDER }}/$ZIP_FILE --upload-file $ZIP_FILE || true + curl -fs -X PUT -u ${{ secrets.UPLOAD_KEY }} ${{ secrets.LATEST_DROP_FOLDER }}/${FIRMWARE}_latest.sha -d "$hash" done \ No newline at end of file diff --git a/README.md b/README.md index 2b7a9d7..c08bc05 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,25 @@ ChangeLog ```` -== 2025-07-02 - * Bugfix: DSM0 "CRC32:0x63F R:1" -== 2024-06-15 +== 2024-09-27 + * Enhancement: + * Mod/SEQ - 4-step sequencer modulation #91 + * Multitrigs (TR707 etc) #29 + * TR707 - midi mapping (GM Standard Drum Map) #29 + * Mod/LFO - New paramter: Waveform #89 + * CV/LFO - New paramter: Scale, Offset, Waveform #89 + * IO-PAGE - Listing of modulation trig/cv inputs + * Bugfix: + * M-OSC/Waveforms - display correct waveform instead of "shape" + * out of memory handling / memory fragmentation - no new/delete usings in open303 + * crash-reporting improvment + * Sporadic midi stops working while update with webflasher + * New Engines: + * SEQ/EuclidRythm + * SEQ/EuclidArp + * DSM: + * One-Engine-Mode +== 2024-06-14 * Enhancement: * T1 Clock - resets to begin after 200milis silence * internal crc32 checks for debugging @@ -157,9 +173,9 @@ E.g you can chain the mono audio signal from an oscillator machine to the neighb ->[Long press [LEFT]] enters the machine-selection-page.
->[Short press [R-ENCODER]] loads the selected engine.
->[Long press [R-ENCODER]] loads the selected engine - extended mode.
+* [Long press [LEFT]] enters the machine-selection-page.
+* [Short press [R-ENCODER]] loads the selected engine.
+* [Long press [R-ENCODER]] loads the selected engine - extended mode.
* Load & reset I/O settings * Load & keep IO settings * Copy #1-4 (parameter values + modulations + I/O settings) @@ -175,50 +191,69 @@ E.g you can chain the mono audio signal from an oscillator machine to the neighb ## Engines * **GND** * `---` - * Scope - * FFT + * [Scope](https://github.com/eh2k/squares-and-circles/wiki/Scope) + * [FFT](https://github.com/eh2k/squares-and-circles/wiki/FFT) * **CV** * [V/OCT](https://github.com/eh2k/squares-and-circles/wiki/V_OCT) - * EnvGen_AD - * EnvGen_ADSR - * LFO - * EnvFollower + * [EnvGen_AD](https://github.com/eh2k/squares-and-circles/wiki/EnvGen_AD) + * [EnvGen_ADSR](https://github.com/eh2k/squares-and-circles/wiki/EnvGen_ADSR) + * [LFO](https://github.com/eh2k/squares-and-circles/wiki/LFO) + * [EnvFollower](https://github.com/eh2k/squares-and-circles/wiki/EnvFollower) * **Drums** - * Analog-BD, Analog SD, Analog HH, Analog HH2 - * 909ish-BD, 909ish-SD, [TR909-HiHat, TR909-Ride](https://github.com/eh2k/squares-and-circles/wiki/TR909_HiHats) - * 808ish-BD, 808ish-SD, 808ish-HiHat - * TR707, TR707-HiHat + * [Analog-BD](https://github.com/eh2k/squares-and-circles/wiki/Analog-BD), + * [Analog-SD](https://github.com/eh2k/squares-and-circles/wiki/Analog-SD), + * [Analog-HH](https://github.com/eh2k/squares-and-circles/wiki/Analog-HH), + * [Analog-HH2](https://github.com/eh2k/squares-and-circles/wiki/Analog-HH2), + * [909ish-BD](https://github.com/eh2k/squares-and-circles/wiki/909ish-BD), + * [909ish-SD](https://github.com/eh2k/squares-and-circles/wiki/909ish-SD), + * [TR909-HiHat, TR909-Ride](https://github.com/eh2k/squares-and-circles/wiki/TR909_HiHats) + * [808ish-BD](https://github.com/eh2k/squares-and-circles/wiki/808ish-BD), + * [808ish-SD](https://github.com/eh2k/squares-and-circles/wiki/808ish-SD), + * [808ish-HiHat](https://github.com/eh2k/squares-and-circles/wiki/808ish-HiHat), + * [TR707](https://github.com/eh2k/squares-and-circles/wiki/TR707), + * [DMX](https://github.com/eh2k/squares-and-circles/wiki/DMX), + * [Linn](https://github.com/eh2k/squares-and-circles/wiki/Linn), * [FM-Drum](https://github.com/eh2k/squares-and-circles/wiki/FM-Drum) - * Djembe + * [Djembe](https://github.com/eh2k/squares-and-circles/wiki/Djembe) * [Claps](https://github.com/eh2k/squares-and-circles/wiki/Claps) * **M-OSC** * [Waveforms](https://github.com/eh2k/squares-and-circles/wiki/Waveforms) - * Virt.Analog, Waveshaping, FM, Grain, Additive, Wavetable, Chord + * [Virt.Analog](https://github.com/eh2k/squares-and-circles/wiki/Virt.Analog) + * [Waveshaping](https://github.com/eh2k/squares-and-circles/wiki/Waveshaping) + * [2-OP-FM](https://github.com/eh2k/squares-and-circles/wiki/2-OP-FM) + * [Formant/PD](https://github.com/eh2k/squares-and-circles/wiki/Formant-PD) + * [Harmonic](https://github.com/eh2k/squares-and-circles/wiki/Harmonic) + * [Wavetable](https://github.com/eh2k/squares-and-circles/wiki/Waveforms) + * [Chord](https://github.com/eh2k/squares-and-circles/wiki/Waveforms) * **SYNTH** - * Resonator + * [Resonator](https://github.com/eh2k/squares-and-circles/wiki/Resonator) * [DxFM](https://github.com/eh2k/squares-and-circles/wiki/DxFM) * [DxFM_BNK1-3](lib/plaits/resources.cc#L41) * [Open303](https://github.com/eh2k/squares-and-circles/wiki/Open303) * [ClassicVAVCF](lib/plaits/dsp/engine2/virtual_analog_vcf_engine.cc) * **Stereo-FX** * [Reverb](https://github.com/eh2k/squares-and-circles/wiki/clouds_reverb) - * ReverbSC - * Rev-Dattorro - * Delay - * Gated-Reverb - * Reverb-HP-LP + * [ReverbSC](https://github.com/eh2k/squares-and-circles/wiki/ReverbSC) + * [Rev-Dattorro](https://github.com/eh2k/squares-and-circles/wiki/Rev-Dattorro) + * [Delay](https://github.com/eh2k/squares-and-circles/wiki/Delay) + * [Gated-Reverb](https://github.com/eh2k/squares-and-circles/wiki/Gated-Reverb) + * [Reverb-HP-LP](https://github.com/eh2k/squares-and-circles/wiki/Reverb-HP-LP) * [JU60_chorus](https://github.com/eh2k/squares-and-circles/wiki/JU60_chorus) * **NOISE** * [White/Pink](https://github.com/eh2k/squares-and-circles/wiki/White_Pink_noise) * [NES_noise](https://github.com/eh2k/squares-and-circles/wiki/NES_noise) * [808_squares](https://github.com/eh2k/squares-and-circles/wiki/808_squares) * **SPEECH** - * LPC + * [LPC](https://github.com/eh2k/squares-and-circles/wiki/LPC) * [SAM](https://github.com/eh2k/squares-and-circles/wiki/SAM) * **MIDI** - * Monitor - * Clock - * VAx6 + * [Monitor](https://github.com/eh2k/squares-and-circles/wiki/Monitor) + * [Clock](https://github.com/eh2k/squares-and-circles/wiki/Clock) + * [VAx6](https://github.com/eh2k/squares-and-circles/wiki/VAx6) +* **SEQ** + * [EuclidRythm](https://github.com/eh2k/squares-and-circles/wiki/EuclidRythm) + * [EuclidArp](https://github.com/eh2k/squares-and-circles/wiki/EuclidArp) + ## Machine/Engine @@ -257,16 +292,21 @@ For each parameter a modulation can be assigned: * DECAY * **LFO**: Free/Triggered Sine-LFO * TRIG: `-`, `!`, `T1`, `T2`, `T3`, `T4`, `C1`, `C2`, `C3`, `C4` - * SHAPE - * FREQUENCY + * SHAPE: `SIN`, `TRI`, `SQR`, `STEPS`, `NOISE` + * FREQUENCY: `0-127` + * WAVEFORM: `0-127` * **EF**: Envelope Follower * SRC: `C1`, `C2`, `C3`, `C4` * ATTACK * RELEASE * **TM**: Turing Machine - * TRIG: `!`, `CLK`, `T1`, `T2`, `T3`, `T4` + * TRIG: `!`, `CLK`, `T1`, `T2`, `T3`, `T4`, `C1`, `C2`, `C3`, `C4` * PROB: `0-9` (0-100%) * STEPS: `1-16` + * **SEQ**: 4-Step Sequencer + * TRIG: `!`, `T1`, `T2`, `T3`, `T4`, `C1`, `C2`, `C3`, `C4`, `CLK/1`, `CLK/4`, `CLK/16`, `CLK/32`, `CLK/96` + * RESET: `-`, `T1`, `T2`, `T3`, `T4`, `C1`, `C2`, `C3`, `C4` + * 4-STEPS: `-64..64` >`!` = current engine trigger
>`CLK` = internal clock
All modulations have an attenuverter parameter (-/+). diff --git a/app/CV/EnvGen_ADSR.bin b/app/CV/EnvGen_ADSR.bin new file mode 100644 index 0000000000000000000000000000000000000000..a957d2eb9745a76fa30a3ec04dafbfef96e1f237 GIT binary patch literal 5404 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 127) + i = 0; + } +} _scope; + +void engine::setup() +{ + _processor.Init(); + + engine::addParam("Attack", &_attack, 0, UINT16_MAX); + engine::addParam("Decay", &_decay, 0, UINT16_MAX); + engine::addParam("Sustain", &_sustain, 0, UINT16_MAX); + engine::addParam("Release", &_release, 0, UINT16_MAX); + engine::setMode(ENGINE_MODE_COMPACT | ENGINE_MODE_CV_OUT); +} + +void engine::process() +{ + uint16_t params[4]; + params[0] = _attack; + params[1] = _decay; + params[2] = _sustain; + params[3] = _release; + _processor.Configure(params, peaks::CONTROL_MODE_FULL); + + if (engine::trig()) + { + flags[0] = peaks::GATE_FLAG_RISING; + std::fill(&flags[1], &flags[FRAME_BUFFER_SIZE], peaks::GATE_FLAG_HIGH); + } + else if (engine::gate()) + { + std::fill(&flags[0], &flags[FRAME_BUFFER_SIZE], peaks::GATE_FLAG_HIGH); + } + else + { + flags[0] = flags[0] == peaks::GATE_FLAG_HIGH ? peaks::GATE_FLAG_FALLING : peaks::GATE_FLAG_LOW; + std::fill(&flags[1], &flags[FRAME_BUFFER_SIZE], peaks::GATE_FLAG_LOW); + } + + _processor.Process(flags, buffer, FRAME_BUFFER_SIZE); + + static float y = 0; + if ((engine::t() % 50) == 0) + { + _scope.push(y); + y = 0; + } + else + y = std::max(y, buffer[0] / (INT16_MAX / 16)); + + for (int i = 0; i < FRAME_BUFFER_SIZE; i++) + engine::outputBuffer<0>()[i] = (float)buffer[i] / -INT16_MIN * 8.f; +} + +void engine::draw() +{ + _scope.draw(56); +} \ No newline at end of file diff --git a/app/DRUMS/Djembe.bin b/app/DRUMS/Djembe.bin index 33a93dd9552618d8a61070d67bea3b8ebe17e83f..df3e3c53d84b5608d28fe5cf81fb1c9178e9ca85 100644 GIT binary patch delta 462 zcmZoMK4TOZ>f+-o#3015gOP#ZiWmcf1Oo#D4-=380yZFKhhh#O4Z@sI%m<{ofS4bM zxq(;!hWd ogJA;Go`2sjP3D)BWd8U47Lb-^iu*TNKvIgS=0Avf+-o%plBgf{}sYix>lg1Oo#D4-=380yZG#0Ah9^=7h4jplp614Ppxb zF*gtk0x=H|3r!3(XJnt)DR0RKm+9fE|H(1|gaxvo`j+COra-Yn+)X92GhLaPR5+nt--2WkRAo2%~1C!el zH*UAsA1vMp?hN|{Chui3R}=v{huPcz3qxV#4`u^K1qq-G$P0|#AijjV%w|#Ma8^c< z&AA-bjJyg!8Blns0I|mAt(=cpS#^L+gUxgKqd8&~fK0e7kj=1F0Avb7b4K%q;EjA< zkw2IegffIG*xyai`tdHk>hN2JDo&6J0nQ8trL!*?gtFau3?vl)f8X~a$zZv#} zj4=UXi^+i!?kYAwmIDyG0I>%U>%L@gVgmY4K;YsJh6zl2{(V36XR?5#1k1ngr$7uT PrkH;qim_@kzoaby64-P6 diff --git a/app/DRUMS/TR707-HiHat.bin b/app/DRUMS/TR707-HiHat.bin deleted file mode 100644 index 372a93351ce97c86d354033167c00386c1b990c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1412 zcmaKrOK1~e5XWaXF~->H+E(qu!fHIEXtBPqplHyz86`}P%+pqP7e(=kGznR&Y`Lgr%$5MSQ zw3a?fMB_5iE+T3LyaIydP$no?0cAphmC#k70jvg%Kmlx91K8FC*oHEm4W&Gr584d; zpam=gYXRq62RP??z&W`uj%@=fXa^nO4N(t-J`tr&B>oOi_w?-Pju+x)g$$!mDpU;9am;hr6bre6VGUcQijg-%m}gUkl0~_)ZIsQTJ!BcxUQ|6(t=QFyF=PzdRJ4j{&;p`Da@s3U{Pvl&iOExAnF}Tk=-D zIfQ&^j#!_(TK8e+i*{*WKT+tm-kiL-V4<$g1&gv|;r+7NpcK~p6SWyT+A7Y6Hodv! zd%|bq*;N6bjps80lqn^l;LNhZ|71fxyNNcc+L+#uY)r5P9(A-Xx4*7Sq0u^pg2`7O zd=h&$X|)-}tHpPQ?*r%O#dpD8%$r4Qdbs1E5_mzI`(6KDY1f#3_u#jep+t!5{?l*Q zdXZ-zh=LgC{y+z1d=o`^>C!d%@%-1hx!Md}f=m6|7nuLIPyLT?_&>huOTOS#Ai*;y z6aN=uy5F0dv23tL({VJE0t@Tnf#=Us`|*6>P`o>34HH3Q)&S8_p}5b+kwZIob3EVk EAMFZYE&u=k diff --git a/app/DRUMS/TR707-HiHat.cpp b/app/DRUMS/TR707-HiHat.cpp deleted file mode 100644 index 96f6bc2..0000000 --- a/app/DRUMS/TR707-HiHat.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "../squares-and-circles-api.h" - -// #include "eproms/tr707/IC35_TR707_SNDROM.h" -const uint8_t *IC35_TR707_SNDROM_bin = machine::fs_read("707_IC35"); - -constexpr static int ch_start = 24576; - -static float _ch_vol = 1.f; -static float _ch_dec = 0.2f; -static float _oh_dec = 0.5f; - -int32_t _select = 0; -void *_ch; -void *_oh; - -void engine::setup() -{ - const uint8_t *HH = &IC35_TR707_SNDROM_bin[0x2000]; - _ch = dsp_sample_u8(HH, 0x2000, 25000, 0); - _oh = dsp_sample_u8(HH, 0x2000, 25000, 0); - - engine::addParam("", &_select, 0, 0); // . = hidden - engine::addParam("CH-Lev", &_ch_vol); - engine::addParam("CH-Dec", &_ch_dec); - engine::addParam("OH-Dec", &_oh_dec); -} - -void engine::process() -{ - auto outputL = engine::outputBuffer<0>(); - memset(outputL, 0, sizeof(float) * FRAME_BUFFER_SIZE); - dsp_process_hihats(_ch, _oh, _ch_vol, _ch_dec, _oh_dec, outputL); -} \ No newline at end of file diff --git a/app/DRUMS/TR707.bin b/app/DRUMS/TR707.bin index 4a2d6c4a9fb91f7d9d1185bbd2dbc7d3065249dc..366a5fe396cfac1f007d6b6c9b4b608adc43db67 100644 GIT binary patch literal 3012 zcma)8ZERCz6h61TbX_;3Yz zMZpEc5C>*}hQ%R_C~=FR#JHgRoRUENh(RMpfAHm&f)EO#_?+8!9gYuulV{I4?|I&H z&VAo|-)>FWii(*ulYY_>8PkYDM6?y)0heUJ2pE8LfagrY&JcDcnC+1O+fNC5l(5ZU zwnqbOX9+u7*kizKj|JEsC+zXU&H=MM0bn~<*m+>aL?9oS1XzKmfdb$eUU*ehvM)FDyjK5Xo9@D%VFa60%q@MiD@@H+6X;H6+5d_Fw5A0E74JS^JZ8J zJ@eq+cyJFq<|T<7f)@#P3N8~|E_j9DO2LD)S{N@14hXJKva<*MUY5wr{oWItrAzu& z!3a5z^9F-^1RoRprA#zmmwc?Hf}a;$Be+)Z%YtKq-xR!0aF^hZ1fLOnR&d#>H5FB} zSFb9z6_eLn*H{S|0l{eTJcxWyX^@pRFeMt7e#Gq!dCiw$_N`Khj;H|UI9dg#gSs(F+gZ=;o zA|Y?Y-w>(~dYc_cA8g!E*BC@UO`!|!iY4sm<-^9& zl3t6~sQR89C8W@4o;RP+uc%JQ&cm*C3EAUQ_#KxtU5=6oyXZ=M*$3_qF{2~Yac=MK zP>y-hT(GG_>2h~*#K|4Jr^?s1ncjEzB{FT8t2DUi7Oj=6t{YuhD{sbLaJagZPPH%L zB*`vcd)3tGJE+xRy<|<~4C;of+EOZ3NLJ33c8e;9>vnp0mOJ5$Lt4o;Tp4>rM#HTy zoWpgSJUsh|&d58MhQ5xfRUWDMDAcc~agTrc z_?eSReiBE(=6Y$O$8!XV9R^nXF-&0#XeVLl^p$GW9*jG+(;8AN6bh${QYXq)=DQE| zTTQmWRF`B|62>KV=yX0*qq&~l{dyCu%G(2EnuC0^Jo5ES9mk41^wt6w<--nTT2Cot z?etCeyqnaMd_5}hnl5EZYHrS?{Y>doTrc@6QN9;;*QwCo=)UZ!|WX{~2r zRdz;phBd>Qmz9^5m1WPGX~UlBEp1JuH>tL5Lr5u1`LPK5(}sL4UXb!hi(3Z$cuddw zi7DTr`8g@ytodV7zE1PaDPPw7%#?4`eC___{^FA6%c;0i^ONr+-?u58G`l&g_MKF2 z%=^S_I7bCI(}jG7M@sITH@QtujE8z#v3G9(dw{(_(G@Duow%4Vo6jd`kM8sPw{P6* zy-eE>vOFBS`-GU`ug9-z{rmAT)BVTCcBEp)liGgT^3>cG{fu;+yDmO%lrBBPy}xB` z3--j;t{8jM-9vVo`{O(O+mnpQ?yHyD@lfvo9l&9r3&6m;7+Zq>C%nr`?elm-*w3+D zQf33@P!+feT#65TbwvrSsvs&Y!8eZ=wgM;zO3R5>0+n^qS`}*-uU@rWsUoV<{&yf+ IhW{)60k-KwL;wH) literal 2156 zcmaKsO>7%Q6vyA%#xYLXZc2c(NvIR2X+?=}le9G-BCg|lTiX$CJ|rSqtylF%Udc{Z z>vbs-NKt7~E)n75&7vR_nfMWr`F$r)C%c29o4FUj5q;9}#>j9iQ z2sn2y;M@lRKhpL_fzAj49Nktx;S;!Gq~SI-n{@c1w%+Stpo5;V-L zH0W9Rz#G(Fb-q|p+sqTjUT<{_2uBn4=-*lT6JM-$`OWO1xHPC#<>43kduH%u=x}m= z)$KOtRZ4t}dpFsL0!eqQsF=aDV(Gi9Y?Bj)7j zIuiHXtSmn~*)Gl>j*(NlxNgJOXozCm7g==%4JOKJ-}_&xzaFt!_ioXqOqei4jqS%;KNLeMrmx6Xe5g7g%30e pPBYlhv|(T1y?A5Xsem-@6j`EED8Q)g>Y0(jAxSample", &_select, 0, LEN_OF(sample_names) - 1, sample_names); // . = hidden + engine::addParam(MULTI_TRIGS, &_select, 0, LEN_OF(sample_names) - 1, sample_names); // . = hidden _select = 0; engine::addParam("Start", &_start); engine::addParam("End", &_end); + + engine::setMode(ENGINE_MODE_MIDI_IN); } void engine::process() { auto outputL = engine::outputBuffer<0>(); memset(outputL, 0, sizeof(float) * FRAME_BUFFER_SIZE); - dsp_process_sample(sample_ptr[_select], _start, _end, _pitch, outputL); + + for (uint32_t i = 0; i < LEN_OF(sample_ptr); i++) + { + if (engine::trig() & (1 << i) || _midi_trigs & (1 << i)) + { + if (i == 11) // CH + { + if (!(engine::trig() & (1 << (i + 1)))) // OH + { + dsp_set_sample_pos(sample_ptr[i], _start, 0.7f, 0.2f); + dsp_set_sample_pos(sample_ptr[i + 1], _start, 0, 1.0f); + } + } + else + { + dsp_set_sample_pos(sample_ptr[i], _start, 1.f, 1.f); + } + + _midi_trigs &= ~(1 << i); + } + + dsp_process_sample(sample_ptr[i], _start, _end, -2.f + (_pitch * 4), outputL); + } +} + +void engine::draw() +{ + gfx::drawSample(sample_ptr[_select]); +} + +void engine::onMidiNote(uint8_t key, uint8_t velocity) // NoteOff: velocity == 0 +{ + if (velocity > 0) + { + switch (key) + { + case 35: // BD0 + _midi_trigs |= (1 << 0); + break; + case 36: // BD1 + _midi_trigs |= (1 << 1); + break; + case 38: // SD0 + _midi_trigs |= (1 << 2); + break; + case 40: // SD1 + _midi_trigs |= (1 << 3); + break; + case 39: // CP + _midi_trigs |= (1 << 4); + break; + case 54: // TMB + _midi_trigs |= (1 << 5); + break; + case 37: // RM + _midi_trigs |= (1 << 6); + break; + case 56: // CB + _midi_trigs |= (1 << 7); + break; + case 41: // LT + case 43: // LT + _midi_trigs |= (1 << 8); + break; + case 45: // MT + case 47: // MT + _midi_trigs |= (1 << 9); + break; + case 48: // HT + case 50: // HT + _midi_trigs |= (1 << 10); + break; + case 42: // CH + case 44: // CH + case 46: // OH + _midi_trigs |= (1 << 11); + break; + } + } + else + { + } +} + +void engine::onMidiPitchbend(int16_t pitch) +{ +} + +void engine::onMidiCC(uint8_t ccc, uint8_t value) +{ + // nothing implemented.. +} + +void engine::onMidiSysex(uint8_t byte) +{ } \ No newline at end of file diff --git a/app/DRUMS/TR909-HiHat.bin b/app/DRUMS/TR909-HiHat.bin index 9b6156065a98cf4549e3297b2ddfe16bbbe18a8f..b16aab75c977d428040686eea60144aac47294d5 100644 GIT binary patch delta 818 zcmX|5t+~2`(zQE!-HWe5 z^Mcvapr`7^JwzB-Z$(5eMnrF;C+EX81HnOveSh=Nh0p!`&bhzyJNNuqX#3t?x-~g- z<2dzDSSAX)h(?IeI(S+j4`>A(9}@9l5i2mqZJ-mhgCoETx_}RKgAQ;M_<;mC7t?WW zxzs5sc6N7Or2j|bkFPU(v;sljNht$y2?iMLkeblU*b_pF7M^!>o z(PsDi`u2E_-WyYS!W5SY#FrdN{o#X4{2Zs@VSmOuN#7k;4jvB#4!Sx5C*iuD74;IoA*J2__tA|h|Moo!OY{-h9WIcHD zWSB$y2jo_IYfn{_-g;}*qu{}df)PA*X`%M};tYKF@ZRjaH}m$)+6{XP$@FZL+UUk0 zstBSnB5DV`f|`1mY0xynOh^-k9{~$Afe4U*bIpKrEr4@qQ_GZvn=R#YtLl$fj>#_)0LZU$My4{pkQqNPY!#MzsM~fvPFtzS3}>)otEz~fR*jIVQm7$yavi9B z+v6Nw$wWIkJw_cK7}w{;!zw=1RbA$@-U-B$AOVu#$u+$YxV4nOeA*WW_rL!s&+HJv cd$nW6h5ew-n$)e?Z@$E#w2B4C>v&H80gm);*Z=?k diff --git a/app/DRUMS/TR909-HiHat.cpp b/app/DRUMS/TR909-HiHat.cpp index c6a50f7..e489e52 100644 --- a/app/DRUMS/TR909-HiHat.cpp +++ b/app/DRUMS/TR909-HiHat.cpp @@ -27,5 +27,17 @@ void engine::process() { auto outputL = engine::outputBuffer<0>(); memset(outputL, 0, sizeof(float) * FRAME_BUFFER_SIZE); - dsp_process_hihats(_ch, _oh, _ch_vol, _ch_dec, _oh_dec, outputL); + + if (engine::accent()) // OH + { + dsp_set_sample_pos(_oh, 0, 1.f, _oh_dec); + } + else if (engine::trig()) // CH + { + dsp_set_sample_pos(_ch, 0, _ch_vol, _ch_dec); + dsp_set_sample_pos(_oh, 0, 0, _oh_dec); + } + + dsp_process_sample(_ch, 0, 1, engine::cv(), outputL); + dsp_process_sample(_oh, 0, 1, engine::cv(), outputL); } \ No newline at end of file diff --git a/app/DRUMS/TR909-Ride.bin b/app/DRUMS/TR909-Ride.bin index 9bc37670a8e54cf1276be326f9dfc7186e683b47..57d87b6df89041e56616e3fae31f1b989519da72 100644 GIT binary patch delta 821 zcmX|=!E4h{9LHahX1eF*)@_|zt6esWcDRi~#mQ7`bu^=$u!DjHAuU}s1?NIj1W!Hq z7t~-CFV&-$QEyZ6;zzq6Y>m0rwb_hc=*r^Es#o6gNdQxEkx z#*|pd44Lf2`H!*x+3)8I6ekukZ4Ss)?~mr;1tNvexJ75~RSzI3ae delta 612 zcmXYuK}Z`x6o%hSvKrToPHKc03nn47MT7<{)I$Ri!dgrOvGuS8i9u5$g2rrXZ|2-% z94H>V#iK{P2&MMcTS2cvp{EMwD%(-r{>2HPk> zSL$2!>N}s_`juv_x~YH5jR|%3BZyymfm4v~i977B1>w^A0)0{13w2s?ROes8V}A%z zfJe*^cmmY9T2v)3kje`}Ij6p!p>)bUT5w9yMb2O+rMohD-4(X(k{u~s-G&73WZcic zR3U**GpNG@(); memset(outputL, 0, sizeof(float) * FRAME_BUFFER_SIZE); - dsp_process_hihats(_ch, _oh, _ch_vol, _ch_dec, _oh_dec, outputL); + + if (engine::accent()) //OH + { + dsp_set_sample_pos(_ch, 0, 0, _oh_dec); + dsp_set_sample_pos(_oh, 0, 1.f, _oh_dec); + } + else if (engine::trig()) // CH + { + dsp_set_sample_pos(_ch, 0, _ch_vol, _ch_dec); + dsp_set_sample_pos(_oh, 0, 0, _oh_dec); + } + + dsp_process_sample(_ch, 0, 1, engine::cv(), outputL); + dsp_process_sample(_oh, 0, 1, engine::cv(), outputL); } \ No newline at end of file diff --git a/app/DRUMS/resources/braids_lut_env.hpp b/app/DRUMS/resources/braids_lut_env.hpp new file mode 100644 index 0000000..83a20bf --- /dev/null +++ b/app/DRUMS/resources/braids_lut_env.hpp @@ -0,0 +1,105 @@ +namespace braids { + const uint16_t lut_env_expo[] FLASHMEM = { + 0, 1034, 2053, 3057, + 4044, 5016, 5974, 6916, + 7844, 8757, 9656, 10542, + 11413, 12271, 13116, 13948, + 14766, 15572, 16366, 17147, + 17916, 18673, 19419, 20153, + 20875, 21587, 22287, 22976, + 23655, 24323, 24981, 25629, + 26267, 26894, 27512, 28121, + 28720, 29310, 29890, 30462, + 31024, 31578, 32124, 32661, + 33189, 33710, 34222, 34727, + 35223, 35712, 36193, 36667, + 37134, 37593, 38045, 38490, + 38928, 39360, 39785, 40203, + 40615, 41020, 41419, 41812, + 42198, 42579, 42954, 43323, + 43686, 44044, 44396, 44743, + 45084, 45420, 45751, 46077, + 46397, 46713, 47024, 47330, + 47631, 47927, 48219, 48507, + 48790, 49068, 49342, 49612, + 49878, 50140, 50398, 50651, + 50901, 51147, 51389, 51627, + 51862, 52092, 52320, 52544, + 52764, 52981, 53195, 53405, + 53612, 53816, 54016, 54214, + 54408, 54600, 54788, 54974, + 55156, 55336, 55513, 55688, + 55859, 56028, 56195, 56358, + 56520, 56678, 56835, 56988, + 57140, 57289, 57436, 57580, + 57723, 57863, 58001, 58136, + 58270, 58402, 58531, 58659, + 58784, 58908, 59029, 59149, + 59267, 59383, 59498, 59610, + 59721, 59830, 59937, 60043, + 60147, 60250, 60351, 60450, + 60548, 60644, 60739, 60832, + 60924, 61014, 61103, 61191, + 61277, 61362, 61446, 61528, + 61609, 61689, 61768, 61845, + 61921, 61996, 62070, 62143, + 62214, 62285, 62354, 62422, + 62490, 62556, 62621, 62685, + 62748, 62810, 62871, 62932, + 62991, 63049, 63107, 63163, + 63219, 63274, 63328, 63381, + 63434, 63485, 63536, 63586, + 63635, 63683, 63731, 63778, + 63824, 63870, 63914, 63958, + 64002, 64045, 64087, 64128, + 64169, 64209, 64248, 64287, + 64326, 64363, 64400, 64437, + 64473, 64508, 64543, 64577, + 64611, 64645, 64677, 64710, + 64741, 64773, 64803, 64834, + 64863, 64893, 64922, 64950, + 64978, 65006, 65033, 65060, + 65086, 65112, 65137, 65162, + 65187, 65212, 65236, 65259, + 65282, 65305, 65328, 65350, + 65372, 65393, 65414, 65435, + 65456, 65476, 65496, 65515, + 65535, +}; + +const uint32_t lut_env_portamento_increments[] FLASHMEM = { + 1431655765, 1208633567, 1025339217, 873854034, + 747996982, 642910145, 554750639, 480459775, + 417588783, 364166300, 318596895, 279582889, + 246063710, 217168604, 192179528, 170501890, + 151641346, 135185326, 120788231, 108159539, + 97054201, 87264844, 78615425, 70956050, + 64158714, 58113796, 52727166, 47917783, + 43615697, 39760385, 36299356, 33186980, + 30383504, 27854220, 25568762, 23500507, + 21626072, 19924877, 18378778, 16971748, + 15689604, 14519780, 13451115, 12473688, + 11578663, 10758156, 10005128, 9313280, + 8676970, 8091136, 7551232, 7053169, + 6593263, 6168194, 5774964, 5410864, + 5073442, 4760475, 4469950, 4200037, + 3949073, 3715547, 3498079, 3295415, + 3106409, 2930012, 2765269, 2611303, + 2467313, 2332562, 2206377, 2088136, + 1977272, 1873260, 1775618, 1683902, + 1597702, 1516641, 1440370, 1368566, + 1300932, 1237191, 1177088, 1120388, + 1066869, 1016330, 968580, 923445, + 880761, 840376, 802150, 765951, + 731657, 699152, 668331, 639094, + 611349, 585008, 559991, 536221, + 513628, 492146, 471711, 452267, + 433757, 416131, 399341, 383341, + 368089, 353545, 339672, 326434, + 313798, 301733, 290209, 279199, + 268677, 258617, 248997, 239795, + 230990, 222562, 214494, 206767, + 199365, 192272, 185474, 178956, +}; + +} \ No newline at end of file diff --git a/app/DRUMS/resources/peaks_lut_env.hpp b/app/DRUMS/resources/peaks_lut_env.hpp new file mode 100644 index 0000000..4825475 --- /dev/null +++ b/app/DRUMS/resources/peaks_lut_env.hpp @@ -0,0 +1,271 @@ +namespace peaks { +const uint16_t lut_env_linear[] FLASHMEM = { + 0, 257, 514, 771, + 1028, 1285, 1542, 1799, + 2056, 2313, 2570, 2827, + 3084, 3341, 3598, 3855, + 4112, 4369, 4626, 4883, + 5140, 5397, 5654, 5911, + 6168, 6425, 6682, 6939, + 7196, 7453, 7710, 7967, + 8224, 8481, 8738, 8995, + 9252, 9509, 9766, 10023, + 10280, 10537, 10794, 11051, + 11308, 11565, 11822, 12079, + 12336, 12593, 12850, 13107, + 13364, 13621, 13878, 14135, + 14392, 14649, 14906, 15163, + 15420, 15677, 15934, 16191, + 16448, 16705, 16962, 17219, + 17476, 17733, 17990, 18247, + 18504, 18761, 19018, 19275, + 19532, 19789, 20046, 20303, + 20560, 20817, 21074, 21331, + 21588, 21845, 22102, 22359, + 22616, 22873, 23130, 23387, + 23644, 23901, 24158, 24415, + 24672, 24929, 25186, 25443, + 25700, 25957, 26214, 26471, + 26728, 26985, 27242, 27499, + 27756, 28013, 28270, 28527, + 28784, 29041, 29298, 29555, + 29812, 30069, 30326, 30583, + 30840, 31097, 31354, 31611, + 31868, 32125, 32382, 32639, + 32896, 33153, 33410, 33667, + 33924, 34181, 34438, 34695, + 34952, 35209, 35466, 35723, + 35980, 36237, 36494, 36751, + 37008, 37265, 37522, 37779, + 38036, 38293, 38550, 38807, + 39064, 39321, 39578, 39835, + 40092, 40349, 40606, 40863, + 41120, 41377, 41634, 41891, + 42148, 42405, 42662, 42919, + 43176, 43433, 43690, 43947, + 44204, 44461, 44718, 44975, + 45232, 45489, 45746, 46003, + 46260, 46517, 46774, 47031, + 47288, 47545, 47802, 48059, + 48316, 48573, 48830, 49087, + 49344, 49601, 49858, 50115, + 50372, 50629, 50886, 51143, + 51400, 51657, 51914, 52171, + 52428, 52685, 52942, 53199, + 53456, 53713, 53970, 54227, + 54484, 54741, 54998, 55255, + 55512, 55769, 56026, 56283, + 56540, 56797, 57054, 57311, + 57568, 57825, 58082, 58339, + 58596, 58853, 59110, 59367, + 59624, 59881, 60138, 60395, + 60652, 60909, 61166, 61423, + 61680, 61937, 62194, 62451, + 62708, 62965, 63222, 63479, + 63736, 63993, 64250, 64507, + 64764, 65021, 65278, 65535, + 65535, +}; +const uint16_t lut_env_expo[] FLASHMEM = { + 0, 1035, 2054, 3057, + 4045, 5018, 5975, 6918, + 7846, 8760, 9659, 10545, + 11416, 12275, 13120, 13952, + 14771, 15577, 16371, 17152, + 17921, 18679, 19425, 20159, + 20881, 21593, 22294, 22983, + 23662, 24331, 24989, 25637, + 26274, 26902, 27520, 28129, + 28728, 29318, 29899, 30471, + 31034, 31588, 32133, 32670, + 33199, 33720, 34232, 34737, + 35233, 35722, 36204, 36678, + 37145, 37604, 38056, 38502, + 38940, 39371, 39796, 40215, + 40626, 41032, 41431, 41824, + 42211, 42592, 42967, 43336, + 43699, 44057, 44409, 44756, + 45097, 45434, 45764, 46090, + 46411, 46727, 47037, 47344, + 47645, 47941, 48233, 48521, + 48804, 49083, 49357, 49627, + 49893, 50155, 50412, 50666, + 50916, 51162, 51404, 51642, + 51877, 52108, 52335, 52559, + 52780, 52997, 53210, 53421, + 53628, 53831, 54032, 54230, + 54424, 54616, 54804, 54990, + 55173, 55353, 55530, 55704, + 55876, 56045, 56211, 56375, + 56536, 56695, 56851, 57005, + 57157, 57306, 57453, 57597, + 57740, 57880, 58018, 58153, + 58287, 58419, 58548, 58676, + 58801, 58925, 59047, 59167, + 59285, 59401, 59515, 59628, + 59739, 59848, 59955, 60061, + 60165, 60267, 60368, 60468, + 60566, 60662, 60757, 60850, + 60942, 61032, 61121, 61209, + 61295, 61380, 61464, 61546, + 61628, 61707, 61786, 61863, + 61939, 62014, 62088, 62161, + 62233, 62303, 62372, 62441, + 62508, 62574, 62639, 62703, + 62767, 62829, 62890, 62950, + 63010, 63068, 63125, 63182, + 63238, 63293, 63347, 63400, + 63452, 63504, 63554, 63604, + 63654, 63702, 63750, 63797, + 63843, 63888, 63933, 63977, + 64021, 64063, 64105, 64147, + 64188, 64228, 64267, 64306, + 64344, 64382, 64419, 64456, + 64492, 64527, 64562, 64596, + 64630, 64664, 64696, 64729, + 64760, 64792, 64822, 64853, + 64883, 64912, 64941, 64969, + 64997, 65025, 65052, 65079, + 65105, 65131, 65157, 65182, + 65206, 65231, 65255, 65278, + 65302, 65324, 65347, 65369, + 65391, 65412, 65434, 65454, + 65475, 65495, 65515, 65535, + 65535, +}; +const uint16_t lut_env_quartic[] FLASHMEM = { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 1, 1, + 2, 3, 4, 5, + 6, 8, 9, 11, + 14, 16, 19, 22, + 25, 29, 33, 37, + 42, 48, 53, 59, + 66, 73, 81, 89, + 98, 107, 117, 128, + 139, 151, 164, 177, + 191, 206, 222, 238, + 256, 274, 293, 313, + 334, 355, 378, 402, + 427, 453, 480, 508, + 537, 567, 599, 631, + 665, 700, 737, 775, + 814, 854, 896, 939, + 984, 1030, 1077, 1127, + 1177, 1230, 1283, 1339, + 1396, 1455, 1515, 1577, + 1641, 1707, 1775, 1844, + 1916, 1989, 2064, 2141, + 2220, 2302, 2385, 2470, + 2557, 2647, 2739, 2833, + 2929, 3027, 3128, 3231, + 3336, 3444, 3554, 3667, + 3782, 3899, 4019, 4142, + 4267, 4395, 4525, 4658, + 4794, 4933, 5074, 5218, + 5365, 5515, 5668, 5824, + 5983, 6144, 6309, 6477, + 6648, 6822, 6999, 7179, + 7363, 7550, 7740, 7933, + 8130, 8330, 8534, 8741, + 8951, 9165, 9383, 9604, + 9829, 10057, 10289, 10525, + 10765, 11008, 11255, 11507, + 11761, 12020, 12283, 12550, + 12821, 13096, 13375, 13658, + 13945, 14237, 14532, 14832, + 15137, 15445, 15758, 16076, + 16397, 16724, 17054, 17390, + 17730, 18074, 18423, 18777, + 19136, 19499, 19868, 20241, + 20618, 21001, 21389, 21781, + 22179, 22582, 22990, 23403, + 23821, 24244, 24672, 25106, + 25545, 25990, 26440, 26895, + 27355, 27821, 28293, 28770, + 29253, 29742, 30236, 30735, + 31241, 31752, 32270, 32793, + 33321, 33856, 34397, 34944, + 35497, 36056, 36621, 37192, + 37769, 38353, 38943, 39539, + 40142, 40751, 41366, 41988, + 42617, 43251, 43893, 44541, + 45196, 45857, 46526, 47201, + 47882, 48571, 49267, 49969, + 50678, 51395, 52118, 52849, + 53587, 54332, 55084, 55843, + 56610, 57384, 58165, 58954, + 59750, 60553, 61364, 62183, + 63010, 63843, 64685, 65535, + 65535, +}; + +const uint32_t lut_env_increments[] FLASHMEM = { + 178956970, 162203921, 147263779, 133914742, + 121965179, 111249129, 101622525, 92960022, + 85152324, 78103929, 71731214, 65960813, + 60728233, 55976673, 51656020, 47721976, + 44135321, 40861270, 37868923, 35130786, + 32622357, 30321772, 28209484, 26268003, + 24481648, 22836346, 21319451, 19919582, + 18626484, 17430905, 16324491, 15299685, + 14349647, 13468178, 12649652, 11888959, + 11181454, 10522909, 9909470, 9337624, + 8804164, 8306157, 7840925, 7406012, + 6999170, 6618338, 6261623, 5927288, + 5613733, 5319488, 5043200, 4783621, + 4539601, 4310076, 4094068, 3890668, + 3699040, 3518407, 3348049, 3187303, + 3035548, 2892213, 2756766, 2628711, + 2507588, 2392971, 2284460, 2181685, + 2084301, 1991984, 1904435, 1821372, + 1742534, 1667676, 1596567, 1528995, + 1464759, 1403670, 1345553, 1290243, + 1237585, 1187435, 1139655, 1094119, + 1050706, 1009303, 969803, 932108, + 896122, 861758, 828932, 797565, + 767584, 738918, 711503, 685274, + 660174, 636148, 613143, 591109, + 569999, 549770, 530379, 511787, + 493956, 476850, 460436, 444683, + 429558, 415035, 401085, 387683, + 374804, 362424, 350523, 339078, + 328069, 317479, 307287, 297478, + 288035, 278942, 270184, 261748, + 253620, 245786, 238236, 230956, + 223936, 217166, 210635, 204334, + 198253, 192383, 186717, 181245, + 175961, 170858, 165927, 161162, + 156558, 152107, 147805, 143644, + 139621, 135729, 131964, 128321, + 124796, 121384, 118081, 114883, + 111787, 108788, 105883, 103069, + 100343, 97700, 95139, 92657, + 90250, 87917, 85654, 83459, + 81330, 79265, 77261, 75316, + 73428, 71596, 69817, 68090, + 66413, 64784, 63202, 61666, + 60173, 58722, 57312, 55942, + 54610, 53315, 52056, 50832, + 49641, 48484, 47357, 46262, + 45196, 44159, 43149, 42167, + 41211, 40280, 39374, 38492, + 37632, 36796, 35981, 35187, + 34414, 33660, 32926, 32211, + 31513, 30834, 30172, 29526, + 28896, 28282, 27684, 27100, + 26531, 25975, 25434, 24905, + 24390, 23886, 23395, 22916, + 22449, 21992, 21546, 21111, + 20687, 20272, 19867, 19471, + 19085, 18708, 18339, 17979, + 17627, 17283, 16947, 16619, + 16298, 15985, 15678, 15378, + 15085, 14799, 14519, 14245, + 13977, 13716, 13459, 13209, + 12964, 12724, 12490, 12260, + 12036, 11816, 11601, 11390, + 11184, +}; +} \ No newline at end of file diff --git a/app/DRUMS/resources/peaks_lut_osc.hpp b/app/DRUMS/resources/peaks_lut_osc.hpp new file mode 100644 index 0000000..90c2822 --- /dev/null +++ b/app/DRUMS/resources/peaks_lut_osc.hpp @@ -0,0 +1,548 @@ +namespace peaks { +const int16_t wav_sine[] FLASHMEM = { + 0, 201, 402, 603, + 804, 1005, 1206, 1406, + 1607, 1808, 2009, 2209, + 2410, 2610, 2811, 3011, + 3211, 3411, 3611, 3811, + 4011, 4210, 4409, 4608, + 4807, 5006, 5205, 5403, + 5601, 5799, 5997, 6195, + 6392, 6589, 6786, 6982, + 7179, 7375, 7571, 7766, + 7961, 8156, 8351, 8545, + 8739, 8932, 9126, 9319, + 9511, 9703, 9895, 10087, + 10278, 10469, 10659, 10849, + 11038, 11227, 11416, 11604, + 11792, 11980, 12166, 12353, + 12539, 12724, 12909, 13094, + 13278, 13462, 13645, 13827, + 14009, 14191, 14372, 14552, + 14732, 14911, 15090, 15268, + 15446, 15623, 15799, 15975, + 16150, 16325, 16499, 16672, + 16845, 17017, 17189, 17360, + 17530, 17699, 17868, 18036, + 18204, 18371, 18537, 18702, + 18867, 19031, 19194, 19357, + 19519, 19680, 19840, 20000, + 20159, 20317, 20474, 20631, + 20787, 20942, 21096, 21249, + 21402, 21554, 21705, 21855, + 22004, 22153, 22301, 22448, + 22594, 22739, 22883, 23027, + 23169, 23311, 23452, 23592, + 23731, 23869, 24006, 24143, + 24278, 24413, 24546, 24679, + 24811, 24942, 25072, 25201, + 25329, 25456, 25582, 25707, + 25831, 25954, 26077, 26198, + 26318, 26437, 26556, 26673, + 26789, 26905, 27019, 27132, + 27244, 27355, 27466, 27575, + 27683, 27790, 27896, 28001, + 28105, 28208, 28309, 28410, + 28510, 28608, 28706, 28802, + 28897, 28992, 29085, 29177, + 29268, 29358, 29446, 29534, + 29621, 29706, 29790, 29873, + 29955, 30036, 30116, 30195, + 30272, 30349, 30424, 30498, + 30571, 30643, 30713, 30783, + 30851, 30918, 30984, 31049, + 31113, 31175, 31236, 31297, + 31356, 31413, 31470, 31525, + 31580, 31633, 31684, 31735, + 31785, 31833, 31880, 31926, + 31970, 32014, 32056, 32097, + 32137, 32176, 32213, 32249, + 32284, 32318, 32350, 32382, + 32412, 32441, 32468, 32495, + 32520, 32544, 32567, 32588, + 32609, 32628, 32646, 32662, + 32678, 32692, 32705, 32717, + 32727, 32736, 32744, 32751, + 32757, 32761, 32764, 32766, + 32767, 32766, 32764, 32761, + 32757, 32751, 32744, 32736, + 32727, 32717, 32705, 32692, + 32678, 32662, 32646, 32628, + 32609, 32588, 32567, 32544, + 32520, 32495, 32468, 32441, + 32412, 32382, 32350, 32318, + 32284, 32249, 32213, 32176, + 32137, 32097, 32056, 32014, + 31970, 31926, 31880, 31833, + 31785, 31735, 31684, 31633, + 31580, 31525, 31470, 31413, + 31356, 31297, 31236, 31175, + 31113, 31049, 30984, 30918, + 30851, 30783, 30713, 30643, + 30571, 30498, 30424, 30349, + 30272, 30195, 30116, 30036, + 29955, 29873, 29790, 29706, + 29621, 29534, 29446, 29358, + 29268, 29177, 29085, 28992, + 28897, 28802, 28706, 28608, + 28510, 28410, 28309, 28208, + 28105, 28001, 27896, 27790, + 27683, 27575, 27466, 27355, + 27244, 27132, 27019, 26905, + 26789, 26673, 26556, 26437, + 26318, 26198, 26077, 25954, + 25831, 25707, 25582, 25456, + 25329, 25201, 25072, 24942, + 24811, 24679, 24546, 24413, + 24278, 24143, 24006, 23869, + 23731, 23592, 23452, 23311, + 23169, 23027, 22883, 22739, + 22594, 22448, 22301, 22153, + 22004, 21855, 21705, 21554, + 21402, 21249, 21096, 20942, + 20787, 20631, 20474, 20317, + 20159, 20000, 19840, 19680, + 19519, 19357, 19194, 19031, + 18867, 18702, 18537, 18371, + 18204, 18036, 17868, 17699, + 17530, 17360, 17189, 17017, + 16845, 16672, 16499, 16325, + 16150, 15975, 15799, 15623, + 15446, 15268, 15090, 14911, + 14732, 14552, 14372, 14191, + 14009, 13827, 13645, 13462, + 13278, 13094, 12909, 12724, + 12539, 12353, 12166, 11980, + 11792, 11604, 11416, 11227, + 11038, 10849, 10659, 10469, + 10278, 10087, 9895, 9703, + 9511, 9319, 9126, 8932, + 8739, 8545, 8351, 8156, + 7961, 7766, 7571, 7375, + 7179, 6982, 6786, 6589, + 6392, 6195, 5997, 5799, + 5601, 5403, 5205, 5006, + 4807, 4608, 4409, 4210, + 4011, 3811, 3611, 3411, + 3211, 3011, 2811, 2610, + 2410, 2209, 2009, 1808, + 1607, 1406, 1206, 1005, + 804, 603, 402, 201, + 0, -201, -402, -603, + -804, -1005, -1206, -1406, + -1607, -1808, -2009, -2209, + -2410, -2610, -2811, -3011, + -3211, -3411, -3611, -3811, + -4011, -4210, -4409, -4608, + -4807, -5006, -5205, -5403, + -5601, -5799, -5997, -6195, + -6392, -6589, -6786, -6982, + -7179, -7375, -7571, -7766, + -7961, -8156, -8351, -8545, + -8739, -8932, -9126, -9319, + -9511, -9703, -9895, -10087, + -10278, -10469, -10659, -10849, + -11038, -11227, -11416, -11604, + -11792, -11980, -12166, -12353, + -12539, -12724, -12909, -13094, + -13278, -13462, -13645, -13827, + -14009, -14191, -14372, -14552, + -14732, -14911, -15090, -15268, + -15446, -15623, -15799, -15975, + -16150, -16325, -16499, -16672, + -16845, -17017, -17189, -17360, + -17530, -17699, -17868, -18036, + -18204, -18371, -18537, -18702, + -18867, -19031, -19194, -19357, + -19519, -19680, -19840, -20000, + -20159, -20317, -20474, -20631, + -20787, -20942, -21096, -21249, + -21402, -21554, -21705, -21855, + -22004, -22153, -22301, -22448, + -22594, -22739, -22883, -23027, + -23169, -23311, -23452, -23592, + -23731, -23869, -24006, -24143, + -24278, -24413, -24546, -24679, + -24811, -24942, -25072, -25201, + -25329, -25456, -25582, -25707, + -25831, -25954, -26077, -26198, + -26318, -26437, -26556, -26673, + -26789, -26905, -27019, -27132, + -27244, -27355, -27466, -27575, + -27683, -27790, -27896, -28001, + -28105, -28208, -28309, -28410, + -28510, -28608, -28706, -28802, + -28897, -28992, -29085, -29177, + -29268, -29358, -29446, -29534, + -29621, -29706, -29790, -29873, + -29955, -30036, -30116, -30195, + -30272, -30349, -30424, -30498, + -30571, -30643, -30713, -30783, + -30851, -30918, -30984, -31049, + -31113, -31175, -31236, -31297, + -31356, -31413, -31470, -31525, + -31580, -31633, -31684, -31735, + -31785, -31833, -31880, -31926, + -31970, -32014, -32056, -32097, + -32137, -32176, -32213, -32249, + -32284, -32318, -32350, -32382, + -32412, -32441, -32468, -32495, + -32520, -32544, -32567, -32588, + -32609, -32628, -32646, -32662, + -32678, -32692, -32705, -32717, + -32727, -32736, -32744, -32751, + -32757, -32761, -32764, -32766, + -32767, -32766, -32764, -32761, + -32757, -32751, -32744, -32736, + -32727, -32717, -32705, -32692, + -32678, -32662, -32646, -32628, + -32609, -32588, -32567, -32544, + -32520, -32495, -32468, -32441, + -32412, -32382, -32350, -32318, + -32284, -32249, -32213, -32176, + -32137, -32097, -32056, -32014, + -31970, -31926, -31880, -31833, + -31785, -31735, -31684, -31633, + -31580, -31525, -31470, -31413, + -31356, -31297, -31236, -31175, + -31113, -31049, -30984, -30918, + -30851, -30783, -30713, -30643, + -30571, -30498, -30424, -30349, + -30272, -30195, -30116, -30036, + -29955, -29873, -29790, -29706, + -29621, -29534, -29446, -29358, + -29268, -29177, -29085, -28992, + -28897, -28802, -28706, -28608, + -28510, -28410, -28309, -28208, + -28105, -28001, -27896, -27790, + -27683, -27575, -27466, -27355, + -27244, -27132, -27019, -26905, + -26789, -26673, -26556, -26437, + -26318, -26198, -26077, -25954, + -25831, -25707, -25582, -25456, + -25329, -25201, -25072, -24942, + -24811, -24679, -24546, -24413, + -24278, -24143, -24006, -23869, + -23731, -23592, -23452, -23311, + -23169, -23027, -22883, -22739, + -22594, -22448, -22301, -22153, + -22004, -21855, -21705, -21554, + -21402, -21249, -21096, -20942, + -20787, -20631, -20474, -20317, + -20159, -20000, -19840, -19680, + -19519, -19357, -19194, -19031, + -18867, -18702, -18537, -18371, + -18204, -18036, -17868, -17699, + -17530, -17360, -17189, -17017, + -16845, -16672, -16499, -16325, + -16150, -15975, -15799, -15623, + -15446, -15268, -15090, -14911, + -14732, -14552, -14372, -14191, + -14009, -13827, -13645, -13462, + -13278, -13094, -12909, -12724, + -12539, -12353, -12166, -11980, + -11792, -11604, -11416, -11227, + -11038, -10849, -10659, -10469, + -10278, -10087, -9895, -9703, + -9511, -9319, -9126, -8932, + -8739, -8545, -8351, -8156, + -7961, -7766, -7571, -7375, + -7179, -6982, -6786, -6589, + -6392, -6195, -5997, -5799, + -5601, -5403, -5205, -5006, + -4807, -4608, -4409, -4210, + -4011, -3811, -3611, -3411, + -3211, -3011, -2811, -2610, + -2410, -2209, -2009, -1808, + -1607, -1406, -1206, -1005, + -804, -603, -402, -201, + 0, +}; + +const uint32_t lut_oscillator_increments[] FLASHMEM = { + 594570139, 598878640, 603218361, 607589530, + 611992374, 616427123, 620894008, 625393262, + 629925120, 634489817, 639087591, 643718683, + 648383334, 653081787, 657814287, 662581081, + 667382416, 672218544, 677089717, 681996188, + 686938214, 691916051, 696929960, 701980202, + 707067040, 712190739, 717351567, 722549792, + 727785686, 733059521, 738371572, 743722117, + 749111434, 754539804, 760007511, 765514839, + 771062075, 776649508, 782277431, 787946136, + 793655918, 799407076, 805199909, 811034720, + 816911812, 822831491, 828794068, 834799851, + 840849155, 846942294, 853079587, 859261354, + 865487916, 871759598, 878076727, 884439633, + 890848647, 897304104, 903806339, 910355693, + 916952505, 923597121, 930289887, 937031151, + 943821265, 950660583, 957549461, 964488259, + 971477339, 978517064, 985607802, 992749922, + 999943798, 1007189803, 1014488315, 1021839716, + 1029244387, 1036702717, 1044215092, 1051781905, + 1059403550, 1067080425, 1074812930, 1082601467, + 1090446444, 1098348268, 1106307352, 1114324111, + 1122398963, 1130532329, 1138724632, 1146976300, + 1155287763, 1163659455, 1172091811, 1180585271, + 1189140279, +}; +const int16_t wav_overdrive[] FLASHMEM = { + -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, + -32766, -32766, -32766, -32766, + -32766, -32766, -32766, -32766, + -32766, -32766, -32766, -32766, + -32766, -32765, -32765, -32765, + -32765, -32765, -32765, -32765, + -32765, -32765, -32765, -32765, + -32764, -32764, -32764, -32764, + -32764, -32764, -32764, -32764, + -32763, -32763, -32763, -32763, + -32763, -32763, -32763, -32763, + -32762, -32762, -32762, -32762, + -32762, -32762, -32761, -32761, + -32761, -32761, -32761, -32761, + -32760, -32760, -32760, -32760, + -32760, -32759, -32759, -32759, + -32759, -32759, -32758, -32758, + -32758, -32758, -32757, -32757, + -32757, -32757, -32756, -32756, + -32756, -32756, -32755, -32755, + -32755, -32754, -32754, -32754, + -32753, -32753, -32753, -32752, + -32752, -32752, -32751, -32751, + -32751, -32750, -32750, -32749, + -32749, -32749, -32748, -32748, + -32747, -32747, -32746, -32746, + -32745, -32745, -32744, -32744, + -32743, -32743, -32742, -32742, + -32741, -32741, -32740, -32740, + -32739, -32738, -32738, -32737, + -32736, -32736, -32735, -32734, + -32734, -32733, -32732, -32732, + -32731, -32730, -32729, -32728, + -32728, -32727, -32726, -32725, + -32724, -32723, -32722, -32721, + -32720, -32719, -32718, -32717, + -32716, -32715, -32714, -32713, + -32712, -32711, -32710, -32709, + -32707, -32706, -32705, -32704, + -32702, -32701, -32700, -32698, + -32697, -32695, -32694, -32692, + -32691, -32689, -32688, -32686, + -32684, -32683, -32681, -32679, + -32678, -32676, -32674, -32672, + -32670, -32668, -32666, -32664, + -32662, -32660, -32658, -32655, + -32653, -32651, -32649, -32646, + -32644, -32641, -32639, -32636, + -32633, -32631, -32628, -32625, + -32622, -32619, -32617, -32614, + -32610, -32607, -32604, -32601, + -32597, -32594, -32591, -32587, + -32584, -32580, -32576, -32572, + -32568, -32564, -32560, -32556, + -32552, -32548, -32543, -32539, + -32534, -32530, -32525, -32520, + -32515, -32510, -32505, -32500, + -32495, -32489, -32484, -32478, + -32473, -32467, -32461, -32455, + -32448, -32442, -32436, -32429, + -32422, -32416, -32409, -32402, + -32394, -32387, -32380, -32372, + -32364, -32356, -32348, -32340, + -32331, -32323, -32314, -32305, + -32296, -32287, -32277, -32268, + -32258, -32248, -32237, -32227, + -32216, -32206, -32195, -32183, + -32172, -32160, -32148, -32136, + -32124, -32111, -32098, -32085, + -32072, -32058, -32044, -32030, + -32016, -32001, -31986, -31971, + -31955, -31939, -31923, -31907, + -31890, -31873, -31855, -31838, + -31819, -31801, -31782, -31763, + -31743, -31723, -31703, -31682, + -31661, -31640, -31618, -31596, + -31573, -31550, -31526, -31502, + -31478, -31453, -31427, -31401, + -31375, -31348, -31320, -31293, + -31264, -31235, -31205, -31175, + -31145, -31113, -31082, -31049, + -31016, -30983, -30948, -30913, + -30878, -30842, -30805, -30767, + -30729, -30690, -30650, -30610, + -30569, -30527, -30484, -30440, + -30396, -30351, -30305, -30258, + -30211, -30162, -30113, -30063, + -30012, -29959, -29906, -29853, + -29798, -29742, -29685, -29627, + -29568, -29508, -29447, -29385, + -29321, -29257, -29191, -29125, + -29057, -28988, -28918, -28846, + -28774, -28700, -28625, -28548, + -28470, -28391, -28311, -28229, + -28146, -28061, -27975, -27887, + -27798, -27708, -27616, -27522, + -27427, -27331, -27232, -27132, + -27031, -26928, -26823, -26717, + -26609, -26499, -26387, -26274, + -26158, -26041, -25923, -25802, + -25679, -25555, -25428, -25300, + -25170, -25038, -24904, -24767, + -24629, -24489, -24346, -24202, + -24056, -23907, -23756, -23603, + -23448, -23291, -23131, -22970, + -22806, -22640, -22471, -22301, + -22128, -21952, -21775, -21595, + -21413, -21228, -21041, -20852, + -20660, -20466, -20270, -20071, + -19870, -19666, -19460, -19252, + -19041, -18828, -18613, -18395, + -18174, -17951, -17726, -17499, + -17269, -17036, -16802, -16565, + -16325, -16083, -15839, -15593, + -15344, -15093, -14840, -14584, + -14327, -14067, -13805, -13540, + -13274, -13005, -12735, -12462, + -12187, -11910, -11632, -11351, + -11068, -10784, -10498, -10210, + -9920, -9628, -9335, -9040, + -8744, -8446, -8146, -7845, + -7543, -7239, -6934, -6628, + -6320, -6012, -5702, -5391, + -5079, -4766, -4453, -4138, + -3823, -3507, -3190, -2873, + -2555, -2237, -1918, -1599, + -1279, -960, -640, -320, + 0, 320, 640, 960, + 1279, 1599, 1918, 2237, + 2555, 2873, 3190, 3507, + 3823, 4138, 4453, 4766, + 5079, 5391, 5702, 6012, + 6320, 6628, 6934, 7239, + 7543, 7845, 8146, 8446, + 8744, 9040, 9335, 9628, + 9920, 10210, 10498, 10784, + 11068, 11351, 11632, 11910, + 12187, 12462, 12735, 13005, + 13274, 13540, 13805, 14067, + 14327, 14584, 14840, 15093, + 15344, 15593, 15839, 16083, + 16325, 16565, 16802, 17036, + 17269, 17499, 17726, 17951, + 18174, 18395, 18613, 18828, + 19041, 19252, 19460, 19666, + 19870, 20071, 20270, 20466, + 20660, 20852, 21041, 21228, + 21413, 21595, 21775, 21952, + 22128, 22301, 22471, 22640, + 22806, 22970, 23131, 23291, + 23448, 23603, 23756, 23907, + 24056, 24202, 24346, 24489, + 24629, 24767, 24904, 25038, + 25170, 25300, 25428, 25555, + 25679, 25802, 25923, 26041, + 26158, 26274, 26387, 26499, + 26609, 26717, 26823, 26928, + 27031, 27132, 27232, 27331, + 27427, 27522, 27616, 27708, + 27798, 27887, 27975, 28061, + 28146, 28229, 28311, 28391, + 28470, 28548, 28625, 28700, + 28774, 28846, 28918, 28988, + 29057, 29125, 29191, 29257, + 29321, 29385, 29447, 29508, + 29568, 29627, 29685, 29742, + 29798, 29853, 29906, 29959, + 30012, 30063, 30113, 30162, + 30211, 30258, 30305, 30351, + 30396, 30440, 30484, 30527, + 30569, 30610, 30650, 30690, + 30729, 30767, 30805, 30842, + 30878, 30913, 30948, 30983, + 31016, 31049, 31082, 31113, + 31145, 31175, 31205, 31235, + 31264, 31293, 31320, 31348, + 31375, 31401, 31427, 31453, + 31478, 31502, 31526, 31550, + 31573, 31596, 31618, 31640, + 31661, 31682, 31703, 31723, + 31743, 31763, 31782, 31801, + 31819, 31838, 31855, 31873, + 31890, 31907, 31923, 31939, + 31955, 31971, 31986, 32001, + 32016, 32030, 32044, 32058, + 32072, 32085, 32098, 32111, + 32124, 32136, 32148, 32160, + 32172, 32183, 32195, 32206, + 32216, 32227, 32237, 32248, + 32258, 32268, 32277, 32287, + 32296, 32305, 32314, 32323, + 32331, 32340, 32348, 32356, + 32364, 32372, 32380, 32387, + 32394, 32402, 32409, 32416, + 32422, 32429, 32436, 32442, + 32448, 32455, 32461, 32467, + 32473, 32478, 32484, 32489, + 32495, 32500, 32505, 32510, + 32515, 32520, 32525, 32530, + 32534, 32539, 32543, 32548, + 32552, 32556, 32560, 32564, + 32568, 32572, 32576, 32580, + 32584, 32587, 32591, 32594, + 32597, 32601, 32604, 32607, + 32610, 32614, 32617, 32619, + 32622, 32625, 32628, 32631, + 32633, 32636, 32639, 32641, + 32644, 32646, 32649, 32651, + 32653, 32655, 32658, 32660, + 32662, 32664, 32666, 32668, + 32670, 32672, 32674, 32676, + 32678, 32679, 32681, 32683, + 32684, 32686, 32688, 32689, + 32691, 32692, 32694, 32695, + 32697, 32698, 32700, 32701, + 32702, 32704, 32705, 32706, + 32707, 32709, 32710, 32711, + 32712, 32713, 32714, 32715, + 32716, 32717, 32718, 32719, + 32720, 32721, 32722, 32723, + 32724, 32725, 32726, 32727, + 32728, 32728, 32729, 32730, + 32731, 32732, 32732, 32733, + 32734, 32734, 32735, 32736, + 32736, 32737, 32738, 32738, + 32739, 32740, 32740, 32741, + 32741, 32742, 32742, 32743, + 32743, 32744, 32744, 32745, + 32745, 32746, 32746, 32747, + 32747, 32748, 32748, 32749, + 32749, 32749, 32750, 32750, + 32751, 32751, 32751, 32752, + 32752, 32752, 32753, 32753, + 32753, 32754, 32754, 32754, + 32755, 32755, 32755, 32756, + 32756, 32756, 32756, 32757, + 32757, 32757, 32757, 32758, + 32758, 32758, 32758, 32759, + 32759, 32759, 32759, 32759, + 32760, 32760, 32760, 32760, + 32760, 32761, 32761, 32761, + 32761, 32761, 32761, 32762, + 32762, 32762, 32762, 32762, + 32762, 32763, 32763, 32763, + 32763, 32763, 32763, 32763, + 32763, 32764, 32764, 32764, + 32764, 32764, 32764, 32764, + 32764, 32765, 32765, 32765, + 32765, 32765, 32765, 32765, + 32765, 32765, 32765, 32765, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32766, 32766, 32766, + 32766, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, + 32767, +}; +} \ No newline at end of file diff --git a/app/DRUMS/resources/peaks_lut_svf.hpp b/app/DRUMS/resources/peaks_lut_svf.hpp new file mode 100644 index 0000000..d652143 --- /dev/null +++ b/app/DRUMS/resources/peaks_lut_svf.hpp @@ -0,0 +1,203 @@ +namespace peaks { + const uint16_t lut_svf_cutoff[] FLASHMEM = { + 35, 37, 39, 41, + 44, 46, 49, 52, + 55, 58, 62, 66, + 70, 74, 78, 83, + 88, 93, 99, 105, + 111, 117, 124, 132, + 140, 148, 157, 166, + 176, 187, 198, 210, + 222, 235, 249, 264, + 280, 297, 314, 333, + 353, 374, 396, 420, + 445, 471, 499, 529, + 561, 594, 629, 667, + 706, 748, 793, 840, + 890, 943, 999, 1059, + 1122, 1188, 1259, 1334, + 1413, 1497, 1586, 1681, + 1781, 1886, 1999, 2117, + 2243, 2377, 2518, 2668, + 2826, 2994, 3172, 3361, + 3560, 3772, 3996, 4233, + 4485, 4751, 5033, 5332, + 5648, 5983, 6337, 6713, + 7111, 7532, 7978, 8449, + 8949, 9477, 10037, 10628, + 11254, 11916, 12616, 13356, + 14138, 14964, 15837, 16758, + 17730, 18756, 19837, 20975, + 22174, 23435, 24761, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, 25078, 25078, 25078, + 25078, +}; +const uint16_t lut_svf_damp[] FLASHMEM = { + 65534, 49166, 46069, 43993, + 42386, 41058, 39917, 38910, + 38007, 37184, 36427, 35726, + 35070, 34454, 33873, 33322, + 32798, 32299, 31820, 31361, + 30920, 30496, 30086, 29690, + 29306, 28935, 28574, 28224, + 27883, 27551, 27228, 26912, + 26605, 26304, 26010, 25723, + 25441, 25166, 24896, 24631, + 24371, 24116, 23866, 23620, + 23379, 23141, 22908, 22678, + 22452, 22229, 22010, 21794, + 21581, 21371, 21164, 20960, + 20759, 20560, 20365, 20171, + 19980, 19791, 19605, 19421, + 19239, 19059, 18882, 18706, + 18532, 18360, 18190, 18022, + 17856, 17691, 17528, 17367, + 17207, 17049, 16892, 16737, + 16583, 16431, 16280, 16131, + 15982, 15836, 15690, 15546, + 15403, 15261, 15120, 14981, + 14843, 14705, 14569, 14434, + 14300, 14167, 14036, 13905, + 13775, 13646, 13518, 13391, + 13265, 13140, 13015, 12892, + 12769, 12648, 12527, 12407, + 12287, 12169, 12051, 11934, + 11818, 11703, 11588, 11474, + 11361, 11249, 11137, 11026, + 10915, 10805, 10696, 10588, + 10480, 10373, 10266, 10160, + 10055, 9950, 9846, 9742, + 9639, 9537, 9435, 9333, + 9233, 9132, 9033, 8933, + 8835, 8737, 8639, 8542, + 8445, 8349, 8253, 8158, + 8063, 7969, 7875, 7782, + 7689, 7596, 7504, 7413, + 7321, 7231, 7140, 7050, + 6961, 6872, 6783, 6695, + 6607, 6519, 6432, 6346, + 6259, 6173, 6088, 6003, + 5918, 5833, 5749, 5665, + 5582, 5499, 5416, 5334, + 5251, 5170, 5088, 5007, + 4926, 4846, 4766, 4686, + 4607, 4527, 4449, 4370, + 4292, 4214, 4136, 4059, + 3982, 3905, 3828, 3752, + 3676, 3601, 3525, 3450, + 3375, 3301, 3226, 3152, + 3078, 3005, 2932, 2859, + 2786, 2713, 2641, 2569, + 2497, 2426, 2355, 2284, + 2213, 2142, 2072, 2002, + 1932, 1862, 1793, 1724, + 1655, 1586, 1518, 1449, + 1381, 1313, 1246, 1178, + 1111, 1044, 977, 911, + 844, 778, 712, 647, + 581, 516, 450, 385, + 321, 256, 192, 127, + 63, +}; +const uint16_t lut_svf_scale[] FLASHMEM = { + 32767, 28381, 27473, 26846, + 26352, 25936, 25573, 25248, + 24953, 24682, 24429, 24193, + 23970, 23759, 23557, 23365, + 23181, 23003, 22832, 22667, + 22507, 22352, 22201, 22055, + 21912, 21772, 21636, 21503, + 21373, 21245, 21120, 20998, + 20877, 20759, 20643, 20528, + 20416, 20305, 20196, 20088, + 19982, 19877, 19774, 19672, + 19571, 19471, 19373, 19275, + 19179, 19083, 18989, 18896, + 18803, 18712, 18621, 18531, + 18442, 18353, 18266, 18179, + 18092, 18007, 17922, 17837, + 17754, 17671, 17588, 17506, + 17424, 17343, 17263, 17183, + 17103, 17024, 16946, 16868, + 16790, 16713, 16636, 16559, + 16483, 16407, 16331, 16256, + 16181, 16107, 16033, 15959, + 15885, 15812, 15739, 15666, + 15594, 15522, 15450, 15378, + 15306, 15235, 15164, 15093, + 15022, 14952, 14882, 14812, + 14742, 14672, 14602, 14533, + 14464, 14395, 14326, 14257, + 14188, 14120, 14051, 13983, + 13915, 13847, 13779, 13711, + 13643, 13575, 13508, 13440, + 13372, 13305, 13238, 13170, + 13103, 13036, 12969, 12902, + 12835, 12768, 12701, 12634, + 12567, 12500, 12433, 12366, + 12299, 12232, 12165, 12098, + 12031, 11964, 11897, 11830, + 11762, 11695, 11628, 11561, + 11493, 11426, 11359, 11291, + 11223, 11156, 11088, 11020, + 10952, 10884, 10816, 10747, + 10679, 10610, 10542, 10473, + 10404, 10335, 10266, 10196, + 10127, 10057, 9987, 9917, + 9846, 9776, 9705, 9634, + 9563, 9491, 9420, 9348, + 9276, 9203, 9130, 9057, + 8984, 8910, 8836, 8762, + 8687, 8613, 8537, 8461, + 8385, 8309, 8232, 8155, + 8077, 7998, 7920, 7841, + 7761, 7680, 7600, 7518, + 7436, 7354, 7270, 7187, + 7102, 7017, 6931, 6844, + 6756, 6668, 6578, 6488, + 6397, 6305, 6211, 6117, + 6021, 5925, 5827, 5727, + 5626, 5524, 5420, 5315, + 5207, 5098, 4987, 4873, + 4758, 4639, 4518, 4394, + 4267, 4137, 4002, 3864, + 3720, 3571, 3417, 3255, + 3086, 2907, 2717, 2514, + 2293, 2049, 1774, 1447, + 1022, +}; +} \ No newline at end of file diff --git a/app/FX/Delay.bin b/app/FX/Delay.bin index beb6f05a788e086b86040bb70d7662ec5db9298e..e75b10052139210fe17486690621d06e4f647454 100644 GIT binary patch delta 552 zcmZ9Izb`{k6vxkfeJy>Z-YeCLmI{M`RQw2ogh>5LD%ymk#zt)X0TM}@Sj42clfh;n zY}L&m4AMy&HiH-p7BTqIrK#`XOkVPNpL5Usb?!M1zlUazDH`hUYTW)gsJ oSkR}|d~Xs_3ao$(7<{D}xByYpWW2KkKh09o_pWt?!!~|=2v3Ll$X2|R*1?bq7x!Yzhi=7 z1bTqwPBzPIfkn0gk!`>Zxg2P5XH8kcr~6CwE-Y% z2Eh>cCW=6$XOuoeGY;4XkH9}@at7YVd=AdQ33v(?L)<6DNUd@oo5-vpiIqL+g7k&- zHKQQ5=~lWX{UlwNZb-LyiFxcso~c4u)~YWI)77gKJ~7tIUll` zEvm%Jacg{2(=Fu^bg%NouA6{(FfZ@}(R&bxhYf*I?$Vv=!$|&0Nmpm~PQ+ARk|LFY zp{=;YS@E4oFb!rwlwX=31OE@iu(JTfACmmYk_e@dmcbg>0AsH-ub^X9eb(q)skT40 QFW$2BGvZCl0C!s(zmoM+9RL6T diff --git a/app/FX/Gated-Reverb.bin b/app/FX/Gated-Reverb.bin index 91e9048d9ec2451ab43520154c8f23f27036d55c..b1acd91e557340ac546ead9a56331d24d1cbac92 100644 GIT binary patch delta 471 zcmXYtF-rqM5JqSBPCYQuyPT&93MM3ikOU%Hh*$)Po*@y^Sezi(i=drWVj)(7aVt9u z1+~2tf)+M{q9Aq_f>`DUh=+*!jqJkPH#;!H&fFD_^TowVeZeJ{UIfv1f@p|{)&(9o zoxlWLI<}gb>~=36abSZU-~i5{_CLp^oRd0dz%J+jeV`k7AO`vY_Zk4)D+yBIk*EaG zD^cSejoa`({DW4F4Fry$#x0zJ&lAnBsbE-;&3_-)u4*r7uL(+X%T4WF?L+M&?F;QI z?R#}9&Qu^r)SjFTALK_|Sx%0JAybVxZiXYfWz>VnET7CRM`mrsw~!OHATmlxKNjvd zt0Kee;_>K^o-1Xc%|%k{3q>z~fJVNmcdy>@=b>sDOD;Y}1Tvy+yYD9MOTi P{{6gEPu`%o!M*hdK!rgK delta 674 zcmaKpO(+Cm7{{M^XMNOKWjyR1SQg0{DRj_;CXTaIXru*8#Y<2yicl2S6#P1e_HF zoK*!ls~RAyi)v8t$)1SXA$lW93?dZ=O}yeS0r(bz%Fm@v1h$YA&qy&q|?$_ z=}m>goVYEWlirg)l0KI%NMA|cNk2=!OY388Mta4xHk4iGLOPRKnxdJkX<8xCSUR0e zug2#VO{-7n`7QD0GL%@-R@;LHpX9HahxfbwPi?Jf4Wm3zz9{u4b9`1k2^z}=6?k1c zQ{ze75k1r=Y)33*@Q{CV`EsxIR3O!{%UdhBdgy( F`3)OaYJLC! diff --git a/app/FX/JU60_chorus.bin b/app/FX/JU60_chorus.bin index 520979eea006c69fa1a00ffd299645d2a6a588e2..d6627de568cf7e0026333b84dfdc5a9167fa2804 100644 GIT binary patch delta 1602 zcmYk6eN0D0;Th~I%$|wa&DU@|ED*}a0gNYz6^|o6_Y~s+duuv6Zv%p*&qKh-d zIFcDRKXNwH#Ko|YC7QS;q*=B&jr;-XKN>b?Vxlv$C3X!uM+}08omvOBc1YcsV_&_wie1yM>6B{VY1I$W*50t(f=4K4t7)m8*^8>Sj*i}F_GV{jul4w?XuKP-rc)7ye#Zk!mQkImp8oP$4sr{KHrHzG-~IoxnLCGw6a z=W9g$sy?X9c|+-Zh(iIl;4gnCsQ3i>ZzwOrobLiH-_8Tu_=3XuMCsg%5LP8Mie(Y& zF#MJ|-_efP^=jnf+6&6V%5NwiReneL1LcpDKUe-%`4{Eil~R0ne`&QZ1&Cgp~)MGtCbh#&p66{3~WD7JtIHJ3awp6$yG@TVA)64epnapKO_&|+irez9tE8s1b8-=NV=f-Ppx4mZew5< z*bRC?9B^dI6W=e>_*B;Fzql~k_muQI9}!Q;y-u&#FJE)kh==8e&VXo;GtOpFBNv^G z&y?<{KnS#;5kcg~F*^}&nsh{4jKKK3sW3;qKJL?zg|6IE(`VGQID0#DbKkGe`6nxM zGlFBn>^A-5@Y&4T+4|+{rQxCkPBjP)fMI#1)TKrKkv>bkq5Gx4$K$I>S&pA_yRm=*y?!7;$0eh-|GcRe1FlJ2TZ2e)zdiAEn2xW@36 q-UWI=KYy`N?gOj%ieCdfhU=f={)ju>;Vltzw7N>hs)J^Jo&Ezpia*i- delta 1474 zcmYk6Uu;uV9LIm>wu5!++}+l)mTq!Ox50#M9bsW0;uU7MxXtx}B@QI*q%{NgFKmpF zEa^;Uq6sK^c&G^^TO`JiK(btniHhBW526o3M19hsLa-RMXb6RA>i1X9;!g7E=lr|B z-|0E$-p_Z+0S}TgbE#86KjfAR5ppUsmClS*<998Hb_>c7bBx22QXBlz>X` z7(hrW1zw;71C)XFpqv#zr2^Cd4ps{|SRLSC8{VF4N^quXz?mKgoM|24Oa|age!!VH zGH2qzoQVS?Q$8>!;=pUc2H*o5K^3S6oZ|_=IW_^#v6(2558i+V4`Q39d6134ym^e< zLFH!Ut;#LRC*el$CTIdYe@5g*Qc(B+Rz3?m;1A*7@sGX`uTc0IbX-M8EzIQ%&S_=o zQ0=fXpA(9C{Ly^#DE9U{LHcQo-%%!wbUyDgnESa*%4V%HF^7$-(I{MxjqQQ2;C7&x zui|848X4ReQJzwML-`%$ca_g8f1-Rv`FrIbm2WElrqRB9f{g08r~FVkr@YGcXd%VQ z70NzkzcSWpdig%WEtc0-C`w~T`j2%T8jjOYd}u5_F8ABVT&NC>OvEX&FE$vSI1CRT zlRNE(^|k$i&8uHp%(@o(vQASAoeLF*4rJ|}(RNDdve)sJa9Ot;IU&B4w~CL8q>MO! zve(_Dlx!>MDC0MP?-$=$1Jqb&OO{0Wo~0ks+FzEnZL zmxrI`(rV4?e`=d{qH2OR&;hzY7&N3a-IW91WNCIGT^RW2?sR0Y{HkKR5$f#A+JedU zkI}O=)pO^|)jgTqw${)G=n+LD*X8rBHI82n-*_o7?+I;_dtCKmvmA0Y2}7QBHSBjk z=Lz*?H3Ybx7F*-9NDoW(jAG#U+zCTI3DRA9gPq3 IR`HGg52Mcx^Z)<= diff --git a/app/FX/Rev-Dattorro.bin b/app/FX/Rev-Dattorro.bin index 9b8a5ac2c35918fc983646ce3ba66cf066141ed4..d88ba96a7c75661c135bbc9e06273ffde6ceffbe 100644 GIT binary patch delta 486 zcmXYtu}eZx6o=1wPct*$drHMP$c1y;9y|AN&|@sqlT9LfEwDuXlYF@?d{Pd z4F%!W(hvqh(CFMI6fO0;d4}(Pzk4qCym!x4`aRXyDOWdLa>+4>N~1(MBC38dR-z#= z3_>6*c|>vq))`kw=cr^$vJLAz26RpU2aJOlm;iC2W~0DP^C7*M!oENFJO!9)(`X!n zJ7_)w-@^qsjQTSC8BuZGX!uNy{^fn~vG_uK&E(;jZp3%uM{!&HEPfHciF@L{*f0kD zR_hB}N2l|u$8B|M?5coysLsuNMnBQ480&lAW{y4AFJqK?1YFS-*LPc8^Orf<>IPqV z(!+@!U>3}RIiO#YZ#{)BgS@0xq90sT8LJX2p?tGrFO{-S{s2O-LG1tl delta 522 zcmXYtJxGE<7{{M`&HR3QEmL0#H8N@k0DRPHYc~U<@_omO_aVZeJFh*U1t=+Hl0adN#9F9O20_I zN`LTk=ChfV?(G5oz@Dr-<*P$rMv` ztMPlu^=o!xUj5e=3d!iw3ZaNc^ecM%~n5EYzr*pP3%Uj%e>Vm;mBm(_pr7 zWH~mo1@3aavnX%5GVVCyC6EO<5akIqHM)k`CMbX+m~7Faf&w+IX;4+U>9kdTp$;*x J82Oi4{sR-$RA~SJ diff --git a/app/FX/Reverb-HP-LP.bin b/app/FX/Reverb-HP-LP.bin index 89904d8b1462c2bfee8aafd8b492e5710f690174..d25e2c183ff7e91a783f0976433dcd5425b035d1 100644 GIT binary patch delta 560 zcmXYtKS)AR6o=2fPwk)OGtE>Q6fBDh914mYM5GsJU_*gKAVLr{-IbNL80J#QP2sr5h+?<<^0WKB+Tx=Y0 zu_)kTF%SpOL>Y)ah{{P+{e~aW#iyv;gk!K5`$@Pf-MI&^-bFGIHC0P1vUz(&ydkcM z4;3Z&%8~e3Y{ci{D{)8sAbwHiMqQf&J!#Ig(|Xs7ep3ykmU(1;PpepQt<3hG)r>lI zhwgaaZd;{_>&acN?zo;})#2w*y>n5=ZoLNfRg!<1UxbfOfCS(nQ(zj*wRVHEI>>1r ub^$Dbthop|sT`sLSOX<6-=(~6zqz*kpafnq_)5L^S7!yz~gcL_5k6VAPt?o6*B zjn@w;rO?Nt6O?(si9KLkz;?Z#5jvKZ<899zvBa?*9&l(QXaPLN zkI(@+v)5X)bn@pO&w0 zM{8arnj_0g^a?4EB3ULSqO~&78o!yCI%f}%c}<|Ff&c_2vH#+CWb?9C76C-cPo>~H18p9dX3 z3NCy)H?8VAI`AU&a^hR)zk*G)?!76f)yPc6gt#WqhQ1$bZ{tG)WM~oVBM@vE+U2- zUGohpPJ(^`m4ch1lY^+U+4OnK1%CM_c>}qNZ@=2DYS~@0$);~XblyvpCnEO*Cmdl2 z0UmcnP-bd`I4I<>%9-CCwQOMS?v4DV|g zMj;FQizXol`F5vgN+fv1+nj@WD753Dbz`E4%QCEh3)7!elK7TobppDSw|~D))iTrK Kn9u6QZ2SYQ-$GOX diff --git a/app/FX/ReverbSC.bin b/app/FX/ReverbSC.bin index 4e77236e832e1a525171c4e8f5f8e9773b90aac7..ab477dca05daf627059084ab15cd7a8803d929ad 100644 GIT binary patch delta 350 zcmZ1?@kX3C)WyeFgh7Pi0V4y$j)}a|6IC=M1sE6@c!5|Di1~n62#EQCSa@QlJ|oY> znev8GK;9Jw1_L0)@PL6KU@iv(!&@Nj38a}A83J^Hv?!2n1k$oVI(6bl>qKQn27x(1 z4dzhV7fQ!L=|V;Z1)wxT4V3PL($k>yTqwN=N^geJN1*hj$x|6mPEKd?+PsCyhjFtE z%MnJ#^2rZbyBS3`=d!(LWVDmCb>;uHQFBzPew%q?AAaL;q!vv;1|G$S#=I54Xj02IA I-MH@o0Dr7MQvd(} delta 376 zcmaDOzC?mI)WyeFltGl?3nK%=m5IF46LnN%c^DWN1c8_rh=qWd4~T_-BmCT8k0 zvQL~TZz%xeNdd7m5Z_^7FaS~vFBljCc5*N7B+^Pu!{D7|iSE~7Z-RVeTAFhf3SEbxHIe*+5C|CI3r`` zILs(B`6b7EQIIQCfLH^FK|a<2VuQ(ZId==109h75Yy-p& oK&&x2lgpde1<3LMVjmz5n0$~+l*!}IWC3m|rT{QCnUDJ(04*FySO5S3 diff --git a/app/GND/FFT.bin b/app/GND/FFT.bin index a3e20e60a26131255f83885c0acf5845eeee2295..753c111b3f8b028ae2718fb030923521c9d86deb 100644 GIT binary patch delta 1601 zcmaKsZAe>J7{|}K-fLpw%dKr}-mKARZPYkvyH#Dw)RmiVY0-@p+O4#fZIFVn4TO!* zk+{h!>14JChQ@#vTGk3Hj;z~|Nok?9AMDnwAI5MZ+lNK%a?ycnSds1j#M^GAuuFdV zo%5XMocr8!Pcm?H;dtcW-u(w^*fwU)W9&!+WB9O(ui^`r8OWdjD8K^pffblQA)uTh zKsm*La!LT@sDN@d0Lm!^6x#?Wwu!Nqb3vOCEL#t<%`nC6fZ7hD?Sx$hm9QIBfpXvl zTR`=hRE3W!p#W7<4QSySKnraJv`{T@3kR=_Pz28&r3iVOVL#l%Srf#1IqPc2=Jdf= z>KXeK9)T~x1&CjUGw6Q>*PwqLPN7d1y6hJEXHd@f@CY9KNB9~x;aAQ&x}HXTO9$qvhLeV`8@_A!mvy_?f)U6V{?qW9l>AP5o(rdZRJ{lt*CP;HLsPT?&8iPg ziM9r3(Nb(u55^K5k=e1#3!<~mX06llXEZt-XwjqMt-6ZW+k-wt)=!jIyOC}~rMpn+ zuDEixbD3LZp=zusna(jFvJwmsQ7=dmoy11YNjQR-cJ~qu+{QmF_R}P@Gk- z{?5Z8{j;z~Ythr9ASH@kfxT`g{KY6+R zc`AM0JpCMF(LJ=&uZ`bqyFD|rXWltTvE8kMqcF>jy^TgMcn_RRj`$w%qQ^t$>aCJ3 zicz{A8xq(2f$Dxl2f)W*2>2IShxFxqR#j73HY9z!cE9c~5pA@~YxlQP!zoog$SFbU Rww%PzAPV{$#8Tsye*n;5XM6wv delta 1253 zcmaKrQAkr!7{|}Ocbn5~dUdXC&gp78n{75BBSb<*DA(S9YQ%J!F z^#)l{B1rTS%x?A|O$&OG9uyxUOneElA}~RmkkS9sQxrl6e*1mreBU`c=j?2`x%Yg$ zp{BOZ$NbD8G1gMbSb#D1I0+ZPYdBXi>{bQQ8xM#~ep|^{1sT6f6&WW!4AU0sxm&s0x%)+i^%=X%J;puG zJ;^=I{f2v<`{TB~Y?TjeaR1~^leWJgQ_`lyqk^&Jdh?Cii&riT>6+A-E*6)cFQsx{ zHKxqfqB5qKlyfOvBo=1V^y{rm6ezCN?nL5icb0KP7}6;g#rHuMur9KoaNqFVD0mck z!4YXpNulAeJtEwrs8aDLQX;v$Qtb%aXQjkSGMiV(J1Y)`&5=rlrj;w5@^E|>>VlfTF!iW6*AS7RqLz|^jkgcn{~vXufgCkZ7^>{ z;9*6+%jB=cXcQQM8BjX~PJ^=`23kOs)?RX3aJC}61ZY|eP>R}B)#-20ZtYtYEN$rC z1RbDL>k67gTMt5N|D@E>{b6q}M*G14xC4Tp*%1+MLzd@KY(RXux$aY&LQZLOy$p7V ZfgfrtlqWtW#WH&Euj>WF_8^1kQO^nziykB-l+oS^&u{#G@cO;)?sptN?ylr2xl)rx z{ED00L^4rDAsQs2HQ=KSRA>hWbbu4~feZG71_z)U__c%335TEydWtE()K*+Nah2b7 z1o&z%@KrDPV4Em{&~Ku|Dt57p_M@6ai4HV~-bV+}>u3ZWDcWZWQHeCZwZ@I1iJ3d>iS(LH%fq1?+0@;5W-d*O>0Ban zFMXR9=d+o)+$`~xi5!k^vZwMi>sPM1`8(?Y{zmxlfRC*z-wFYKiV*^S*8u1{^%1=$ zFP|P8jwKs%BH2*p_3@Pog${51ycIBg#*9y?7ZkN#P)`|y25WjEkDDIttsPcI%{O*f zs#;aM(AD|gFrB;VpBMJz1=W_?w?6q}0TWM)g!|U4&)+v{s+#x4e5|SZ-R{d2Og5yc zy`4AgzBjuNSO{cB zKqnafXQNo-!4LVk<* zntCnxYSXjcq`l@Ll|5rk?24x+##~x6d8c-@)j}^pAg)cU4&d;j_Px;Cc*bb3I3=cv zY*o)iD(YVW1x>FO^jLf#&g;SGd_8Es ztA(|r>}@TqEW3qB;8Q>I|I@c$)<)0jHO2V09uD=eHs-Kp_sg$xMW43Sgw1#Ku2yS= zLTOJ)^{^lt>|S)s6=T}u$BfRtMb}(f{iDvV{;tko9NF&kQmG_<-2gZRPV?J_8yZ3u t2j@W&M7C&H#l@KBXOHI8mED~zKjE{Ld?P+;#IlI0v&*BtcAoVO{s*K=kum@P diff --git a/app/M-OSC/Waveforms.bin b/app/M-OSC/Waveforms.bin new file mode 100644 index 0000000000000000000000000000000000000000..1fed948b362c6b2f795011ee473d6170e2c31edd GIT binary patch literal 104392 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 literal 0 HcmV?d00001 diff --git a/app/M-OSC/Waveforms.cpp b/app/M-OSC/Waveforms.cpp new file mode 100644 index 0000000..ba3fbb0 --- /dev/null +++ b/app/M-OSC/Waveforms.cpp @@ -0,0 +1,189 @@ +// Copyright (C)2021 - E.Heidt +// +// Author: E.Heidt (eh2k@gmx.de) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// + +#include "../squares-and-circles-api.h" + +#include "stmlib/stmlib.h" +#include "stmlib/dsp/dsp.h" + +#define private public +#include "braids/macro_oscillator.h" +#include "braids/envelope.h" +#include "braids/settings.h" + +#include "braids/vco_jitter_source.h" + +#include "braids/analog_oscillator.cc" +#define kHighestNote kHighestNote2 +#define kPitchTableStart kPitchTableStart2 +#define kOctave kOctave2 +#include "braids/digital_oscillator.cc" +#include "braids/settings.cc" +#include "braids/macro_oscillator.cc" +#include "braids/resources.cc" +#include "stmlib/utils/random.cc" + +using namespace braids; + +MacroOscillator osc1; +MacroOscillator osc2; +Envelope envelope; +VcoJitterSource jitter_source; + +uint8_t sync_samples[FRAME_BUFFER_SIZE]; + +float _pitch = 0; +int32_t _shape = 0; +int32_t _timbre = UINT16_MAX / 2; +int32_t _color = UINT16_MAX / 2; +int32_t _attack = 0; +int32_t _decay = UINT16_MAX / 2; + +float buffer[FRAME_BUFFER_SIZE]; +float bufferR[FRAME_BUFFER_SIZE]; + +void engine::setup() +{ + settings.Init(); + osc1.Init(); + osc2.Init(); + jitter_source.Init(); + envelope.Init(); + + std::fill(&sync_samples[0], &sync_samples[FRAME_BUFFER_SIZE], 0); + + // settings.SetValue(SETTING_AD_VCA, true); + settings.SetValue(SETTING_SAMPLE_RATE, 5); + settings.SetValue(SETTING_PITCH_OCTAVE, 4); + settings.SetValue(SETTING_PITCH_RANGE, PITCH_RANGE_EXTERNAL); + + engine::addParam(V_OCT, &_pitch); + engine::addParam("Shape", &_shape, braids::MACRO_OSC_SHAPE_CSAW, braids::MACRO_OSC_SHAPE_LAST - 1, (const char **)braids::settings.metadata(braids::Setting::SETTING_OSCILLATOR_SHAPE).strings); + engine::addParam("Timbre", &_timbre, 0, UINT16_MAX); + engine::addParam("Color", &_color, 0, UINT16_MAX); + engine::addParam("Decay", &_decay, 0, UINT16_MAX); + engine::addParam("Attack", &_attack, 0, UINT16_MAX); +} + +void engine::process() +{ + envelope.Update(_attack / 512, _decay / 512); + + if (engine::trig()) + { + osc1.Strike(); + osc2.Strike(); + envelope.Trigger(braids::ENV_SEGMENT_ATTACK); + } + + if (engine::gate()) + { + // Not working witch Attack > 0 + // envelope.Trigger(braids::ENV_SEGMENT_DECAY); + } + + uint32_t ad_value = envelope.Render(); + + float pitchV = engine::cv(); + int32_t pitch = (pitchV * 12.f + DEFAULT_NOTE + 12) * 128; + + // if (!settings.meta_modulation()) + // { + // pitch += settings.adc_to_fm(adc_3); + // } + + pitch += jitter_source.Render(settings.vco_drift()); + pitch += ad_value * settings.GetValue(SETTING_AD_FM) >> 7; + + CONSTRAIN(pitch, 0, 16383); + + if (settings.vco_flatten()) + pitch = stmlib::Interpolate88(braids::lut_vco_detune, pitch << 2); + + uint32_t gain = _decay < UINT16_MAX ? ad_value : UINT16_MAX; + + if (!__io->tr) + gain = _decay; // No Trigger patched - use Decay as VCA... + + if ((engine::t() % 12) != 0) + osc1.set_shape((braids::MacroOscillatorShape)_shape); + else if ((engine::t() % 12) != 6) + osc2.set_shape((braids::MacroOscillatorShape)_shape); + + osc1.set_parameters(_timbre >> 1, _color >> 1); + osc1.set_pitch(pitch + settings.pitch_transposition()); + + auto audio_samples = engine::outputBuffer_i16<0>(); + osc1.Render(sync_samples, audio_samples, FRAME_BUFFER_SIZE); + + for (int i = 0; i < FRAME_BUFFER_SIZE; i++) + audio_samples[i] = (gain * audio_samples[i]) / UINT16_MAX; + + if (engine::is_stereo() && __io->stereo > 0) // Stereo + { + const float f = (float)__io->stereo / 255.f; + uint8_t stereo = f * f * f * 255; + + int32_t timbre = _timbre + stereo; + if (timbre > UINT16_MAX) + timbre = _timbre - stereo; + + int32_t color = _color + stereo; + if (color > UINT16_MAX) + color = _color - stereo; + + osc2.set_parameters((timbre >> 1), (color >> 1)); + osc2.set_pitch(pitch + settings.pitch_transposition() + stereo); + + auto audio_samples = engine::outputBuffer_i16<1>(); + osc2.Render(sync_samples, audio_samples, FRAME_BUFFER_SIZE); + + for (int i = 0; i < FRAME_BUFFER_SIZE; i++) + audio_samples[i] = (gain * audio_samples[i]) / UINT16_MAX; + } + else + { + memcpy(engine::outputBuffer_i16<1>(), engine::outputBuffer_i16<0>(), FRAME_BUFFER_SIZE * sizeof(int16_t)); + } +} + +void engine::draw() +{ + if (!__io->tr) + { + setParamName(&_decay, "Level"); + setParamName(&_attack, nullptr); + } + else if (_decay < UINT16_MAX) + { + setParamName(&_decay, "Decay"); + setParamName(&_attack, "Attack"); + } + else + { + setParamName(&_decay, "VCA-off"); + setParamName(&_attack, nullptr); + } +} \ No newline at end of file diff --git a/app/MIDI/Clock.bin b/app/MIDI/Clock.bin index 2b66bb1228eddbd8b1434bc625fb4fd487f673c9..c33cef8ea1b6cf3c203f396f7704bb7ddfc86201 100644 GIT binary patch delta 680 zcmX|2*u>}LH*bgfAnS7S8^SW!WWPzx3ok@}Me3Kh&jjNn0qLZBBtNIZDy zp`eTvT0D3W6cj4vrXoFg@=)l(gP=XMnu-Tc35B}8UmP5G_Sx^9S@xTq&033AW~3)E zXj7O18qtzYlp>-K5WoZmC;?tj3OFkRoRtI4e1J1Q;H(00RtY$>0B2QzvnPPFY9hNB z22>b)2!D+CshZbLB?ZC#W5wXM%k^@K@FIu1Lb4opUS_K ze=FZ8{}<#fKIoT0?M(jDUhcJcriI+rZEfdLZtC@(jmv<{=~1yS{YJEZ%eCUo;bZ|j zSuvs_;^x;~-#{jsEZ`VdB5%F7KH=t9UH#kPRoc1z!zWq?_$9ob7me-OG0`@3C4})v1xf zcsC^|Es54Fq7o5BfdB#E2W_0sa6Sv0+zw0*a_-<9f=xaLOjevbIiH73?jnkjnS@&t zig3OFM{2A6!mfSouf{Oz0||f@mwVW~>?9l(l!2&6(8M)dV-Vi)5#4~_!jo_u^&%|b zX?P!XGfK@TId4!uJ%^;v7pnPpG0@3Wu4cLk{u4m@Pn*ss_h1@&T?w%Om< zyX+(OG5a6;L{O-CFeFuh^g zZIp6h{lJR*ULHi7UWGqdDe+GKuu`MXJ(a&4FS_^+bvq@JUZd^>$EvBKi=UyM%=-TZ zh1Xc|toNIT6=(m~B{XjuNdt550Wb(Mder`XaTv+$xC+ebb>M&zJ?_t^Zy^=H1egR@ zj_9T|{i^RSJ(U|?3Qx3X5M%?grJ>?7 zK$>gfNqtL3pb9lchJcAI3=Gylx)ezJ0qLheIv7Zw1k%w!dM%I!0gwei;2=BMkTG16 z6C&y$3#ETD!(AhRMhXYx~~#>q|0PVoXj zRU$wv0mKFF4EuFoe(?46_VbGT!JH8JgGr%l1A{V;B9p=fcP}pnWsnGuq7#tk?hRBC zz@VbwCZx!0vckPl=jTOdkeC6(Waf`kxE(=k1;@$iEVlfPZVn0@ADKB;xbOIA!~cD9 rIm<#`P%tO}u?i4tY*uCMWMbSic|E%{;}I}<0ZhIEllLaea~uT#60=i` delta 418 zcmX>g_(ae!)WyeFib0A&hKYe;1}g)D2Ll7c93Tb(b|7X0Vh$kYgkr9VhV6ntbqvx# z3{oHi#2gb(>RYM;Mb#J?0=BX+FjxcWnLyePNOJWpSuQ_p=6WRI1^o&U+bty#Q0iu+f z$PIX?zzKNj0v=ESDgk#@fV*nIT@Bz)1KiaD&UD}dUQiF}Km$P5N`4s{GHil53xGxt z%pWy-_zNb`^2Lr(PFq2QLqR9=)8^>?^cz=o)r4OZRqC^EjVJ`2aAEn=p(3`f#8uvS#&}3jwc=#;&WDM&$7<5%WMTUEAVP2~t z+#?NxIG2DgfJXvM*v}E4Ul`Ws;C9W~Ct&&~1@O?O^K7F3^ea>_0J@4_Bc-;~k6aC52AO$I=5yiTQvKAr> z;AI9Tz}qrl1)P-w&ME+BHo%!3a8?O8bEw)0dw>ggK^5=;H&G*1qu{0=aI+S0GXS_( zmp`bt8o2=W{B6@P#xO@z141Co2x@_-Sy1Y>lc)!tf>UrWJO>xxES!gP@TzPTV;k?- ztqF4Shi@zIE1xRk;`mz!-%s&(Nn3%&$g A)Bpeg diff --git a/app/MIDI/VAx6.cpp b/app/MIDI/VAx6.cpp index 55e298b..130bb20 100644 --- a/app/MIDI/VAx6.cpp +++ b/app/MIDI/VAx6.cpp @@ -24,7 +24,6 @@ // #include "../squares-and-circles-api.h" -#define FLASHMEM __attribute__((section(".text"))) // #include "../lib/plaits/dsp/engine/virtual_analog_engine.h" // no virtual functions hack diff --git a/app/NOISE/808_squares.bin b/app/NOISE/808_squares.bin index 2f535227df5d996ab6e5a2a1b38e809a20a989e5..398ce46634b9b95591b715a545ecb21988deeca8 100644 GIT binary patch delta 361 zcmXZXF-ikb5XSNEy(F${T%AHRieiKm76z19SeQmqC@Q20V&{4Rn+O(Zassow^j<+s zu(A|e4IaQYp1^>Jej~H+9{J90uw%BsezWIn&Y@Y)Mzy2ZL3E`x zYt7oQo;j5Dz)S0uwPWpCZ$rzyhN>@xLw^yT{f(1BJy&$g!k_iNx_^oEKC4t7r1?9a uRQS3{TO=Wgjw`zVF744iRX=gyhaVG>(F8sJ^!wHR32)Jg@BAk`M2~-BGc*wZ delta 429 zcmdlW@IoLl)WyeFkU@}P1tSB)8de5|5(Wka5g-NuHXsHHF|b3~98fkVkOr~2fEdK) z24Y?y<^f_pD4QS37MPeQ&&V>dQQQ(FD+a{kK)i>6!2n1xoMT`Jm-DN#~j%l#iB2O@v) zI54>_apQK2{lVg$;LfmLU~(r@HKWL8R%UKSNl>Us05Qm)GC&LpAq5~-*{sPjpNUrk z$kYL1kiSJHUuE-FHUY9MfY=6z9e`N(C4&hFh#&N)WyeFfI*O94I=|X3M&vZFfil*F$k~&F$)lL05MRCffI=qwVPG%-QVi!97y@nrO}GuDGlBF6AngmJnHd=Z_5x`R zAiWSs3jpcXi4V2o#26U_5`Y@DptJ*!P66@*p?n|{?4lG#1_cm1A4=Ci=}ss;9ZD~N z(mF&>}n#H2JinJIDd1Ev&F0id`D5Q97j0wA}`Y>s5MW@J?WG6gozWVy`9 zsRCqzfX3ufHg{zmAPeL<6Ckz#V%?VvPE1?w{}2$k_=8~r)1Lp|FHFAACe3&QL{1iC QKgDP>`5}8U%U7U30Z=76)&Kwi delta 442 zcmXYty-Pw-7>D0;yMATEF>a_KA!J}!6wy#rV3C?+CP;%rsB|SRh=T+Y4HeYh?KZUq z4K);mjYiQF(h@=76x7ro5Zxu}ci_D6oaa67`93H7iBGRBW>$REOD#sU=OEIFs0u{5 z07~QrPT&Ee)(za|T+Gx%Of~oYX)g+XFbo192%d??A$lXqeXB&D@F8r&2JB^&>%bho zg9GrH*@^8AFybXFoRD6Eb@U6ekCZT78=oc+0IEC{U dn~s#$-_PUkv8!Kci`M#ZwprY|a&4&M>i-o4PtyPZ diff --git a/app/NOISE/NES.cpp b/app/NOISE/NES.cpp index 1e456d4..416b2c6 100644 --- a/app/NOISE/NES.cpp +++ b/app/NOISE/NES.cpp @@ -42,7 +42,7 @@ void engine::setup() _nes_noise.init(1); _dc_blocker.Init(0.999f); -}; +} void engine::process() { diff --git a/app/NOISE/WhitePink.bin b/app/NOISE/WhitePink.bin index 6da466387bbf9cef247f34712f741c6c521f2f68..32bad21b959830ee9730301ba55054e6306fa775 100644 GIT binary patch delta 397 zcmXYtze~eF7>3_#)6{CxAGQIDf(0E~bm-uuLmdPMt+)tAkbsa*7ON(EM%QqQe?&Wo ztM1m(&Be+70gf)#_ak@kU2dG3P`HPO}armGS1G%3vfE+sZ%&5d=HxkF3$yJp^3XmN^jls5dVNZsKSZN5OS47-1L= z@52bXm%GxhxucqNE#1mBSIF9PGryNFwHReI^re01ZZfrrbk@~Rwx{0p++I~5^3{L# Tz|CGa>9ysx^=)y(n(2())1g8^mw~ zf57MPH~b1SM(z73UfeerSxYFaD6hiu77aD-FsfomUF8$yOXX|jNEu7(EG4$tOZxCE zyzq}tkA%(3!sVeecuPvpL6WO;@6OA52Z^@RZPAk@Zup)pZ{`5`46~s6IOZD@nR!In z9I>FcYA%vI?f*M3e^P^ETg!?Qy5+;4uc3I*D{O@R%3PO))Z1#}H~3=HsA&x87evuN A!vFvP diff --git a/app/NOISE/WhitePink.cpp b/app/NOISE/WhitePink.cpp index 2b01077..6dcd4f3 100644 --- a/app/NOISE/WhitePink.cpp +++ b/app/NOISE/WhitePink.cpp @@ -38,8 +38,7 @@ void engine::setup() { engine::addParam("Level", &gain); engine::addParam("@Mode", &mode, 0, LEN_OF(modes) - 1, modes); -}; - +} void engine::process() { auto buffer = engine::outputBuffer<0>(); diff --git a/app/SEQ/EuclidArp.bin b/app/SEQ/EuclidArp.bin new file mode 100644 index 0000000000000000000000000000000000000000..2f142c8bbfce03757b8605e8fb1a2d3fa3477521 GIT binary patch literal 8724 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 literal 0 HcmV?d00001 diff --git a/app/SEQ/EuclidArp.cpp b/app/SEQ/EuclidArp.cpp new file mode 100644 index 0000000..b4a4ca0 --- /dev/null +++ b/app/SEQ/EuclidArp.cpp @@ -0,0 +1,385 @@ + +// Copyright (C)2021 - Eduard Heidt +// +// Author: Eduard Heidt (eh2k@gmx.de) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// + +#include "../squares-and-circles-api.h" +#include "../lib/misc/euclidean.h" +#include +#include + +#include "../lib/plaits/dsp/engine2/arpeggiator.h" +#define private public +#define SemitonesToRatioFast +#include "../lib/plaits/dsp/chords/chord_bank.cc" +#include "stmlib/utils/random.cc" + +#include "../lib/stmlib/utils/dsp.h" +#include "../DRUMS/resources/peaks_lut_env.hpp" + +// This app is copiled with soft-fpu - for running on teensy3.2 & teensy 4.x + +/* +https://www.nullhardware.com/blog/fixed-point-sine-and-cosine-for-embedded-systems/ + +Implements the 5-order polynomial approximation to sin(x). +@param i angle (with 2^15 units/circle) +@return 16 bit fixed point Sine value (4.12) (ie: +4096 = +1 & -4096 = -1) + +The result is accurate to within +- 1 count. ie: +/-2.44e-4. +*/ + +int16_t fpsin(int16_t i) +{ + /* Convert (signed) input to a value between 0 and 8192. (8192 is pi/2, which is the region of the curve fit). */ + /* ------------------------------------------------------------------- */ + i <<= 1; + uint8_t c = i < 0; // set carry for output pos/neg + + if (i == (i | 0x4000)) // flip input value to corresponding value in range [0..8192) + i = (1 << 15) - i; + i = (i & 0x7FFF) >> 1; + /* ------------------------------------------------------------------- */ + + /* The following section implements the formula: + = y * 2^-n * ( A1 - 2^(q-p)* y * 2^-n * y * 2^-n * [B1 - 2^-r * y * 2^-n * C1 * y]) * 2^(a-q) + Where the constants are defined as follows: + */ + uint32_t A1 = 3370945099UL, B1 = 2746362156UL, C1 = 292421UL; + uint32_t n = 13, p = 32, q = 31, r = 3, a = 12; + + uint32_t y = (C1 * ((uint32_t)i)) >> n; + y = B1 - (((uint32_t)i * y) >> r); + y = (uint32_t)i * (y >> n); + y = (uint32_t)i * (y >> n); + y = A1 - (y >> (p - q)); + y = (uint32_t)i * (y >> n); + y = (y + (1UL << (q - a - 1))) >> (q - a); // Rounding + + return c ? -y : y; +} + +// Cos(x) = sin(x + pi/2) +inline int16_t fpcos(int16_t i) { return fpsin((int16_t)(((uint16_t)(i)) + 8192U)); } + +// https://xbm.jazzychad.net/ +const uint8_t xmb_note_6x8[8] = {0xc8, 0xd8, 0xe8, 0xd8, 0xe8, 0xce, 0xcf, 0xc6}; +const uint8_t xmb_rest_6x8[8] = {0xd6, 0xde, 0xd0, 0xd6, 0xde, 0xd0, 0xd0, 0xd0}; + +const uint8_t xmb_arrow_up_5x6[6] = {0xe4, 0xee, 0xff, 0xe4, 0xe4, 0xe4}; +const uint8_t xmb_arrow_dn_5x6[6] = {0xe4, 0xe4, 0xe4, 0xf5, 0xee, 0xe4}; +const uint8_t xmb_circle_7x7[7] = {0x9c, 0xa2, 0xc1, 0xc1, 0xc1, 0xa2, 0x9c}; +const uint8_t xmb_filled_circle_7x7[7] = {0x9c, 0xa2, 0xdd, 0xdd, 0xdd, 0xa2, 0x9c}; +const uint8_t xbm_play_11x11[] = {0x03, 0xf8, 0x0d, 0xf8, 0x31, 0xf8, 0xc1, 0xf8, 0x01, 0xfb, 0x01, 0xfc, 0x01, 0xfb, 0xc1, 0xf8, 0x31, 0xf8, 0x0d, 0xf8, 0x03, 0xf8}; +const uint8_t xbm_stop_7x11[] = {0x80, 0xf7, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xf7, 0x80}; + +int32_t len = 16; +int32_t pulses = 4; +int32_t rotate = 0; +int32_t swing = 128; + +int32_t seq_pos = UINT8_MAX; +bool playing = true; +bool pre_start = false; + +void draw_eclid_cyrcle(int x, int y, uint8_t pattern[64], int _len, int rot) +{ + auto pattern2 = pattern; + + int xx = x; + int yy = y; + + if ((fpsin((INT16_MAX / (_len))) / 194) > 6) + { + gfx::drawCircle(xx + 3, 31 + 3, 21); + + for (int i = 0; i < _len; i++) + { + int a = (INT16_MAX / (_len)) * i; + + if (MOD(i, 2) == 1) + a += (-128 + swing) * (INT16_MAX / _len) / 6; + + int x = fpsin(a) / 194; + int y = -fpcos(a) / 194; + x += xx; + y += yy; + + gfx::clearCircle(x + 3, y + 3, 3); + } + } + + for (int i = 0; i < _len; i++) + { + int a = (INT16_MAX / (_len)) * i; + + if (MOD(i, 2) == 1) + a += (-128 + swing) * (INT16_MAX / _len) / 6; + + int dx = fpsin(a); + int dy = -fpcos(a); + + int x = xx + dx / 194; + int y = yy + dy / 194; + + if (pattern[i] || pattern2[i]) + gfx::fillRect(x + 2, y + 2, 3, 3); // gfx::drawXbm(x, y, 7, 7, xmb_filled_circle_7x7); + + if (i == rot) + gfx::drawRect(x, y, 7, 7); + else + gfx::drawCircle(x + 3, y + 3, 3); // + + bool cursor = i == MOD(seq_pos, _len); + + if (cursor && !pre_start) + gfx::drawRect(x + 1, y + 1, 5, 5); + } + + if (playing && pre_start && MOD(millis(), 300) > 150) + { + } + else + { + int x = xx - 2; + int y = 40 - 7; + if (pattern[seq_pos % _len] && (engine::clock() % 6) < 3) + { + if (x < 64) + gfx::fillRect(x - 3, y - 7, 17, 17); + else + gfx::fillCircle(x + 5, y + 1, 8); + } + else + { + if (x < 64) + gfx::drawRect(x - 2, y - 7, 16, 16); + else + gfx::drawCircle(x + 5, y + 1, 8); + } + } +} + +float arp_root = 0; +int32_t mode = 0; + +int32_t chord = 0; +plaits::Arpeggiator arpeggiator_; +plaits::ChordBank chords_; +int32_t chords_mem[(plaits::kChordNumChords * plaits::kChordNumNotes) + plaits::kChordNumChords + plaits::kChordNumNotes]; + +int32_t octaves = 1; +int32_t _slide = 0; + +const char *smodes[] = { + "UP", + "DOWN", + "CYCLE", + "RAND", +}; + +const char *soctaves[] = { + "1-OCT", + "2-OCT", + "3-OCT", + "4-OCT", +}; + +void engine::setup() +{ + arpeggiator_.Init(); + stmlib::BufferAllocator allocator; + allocator.Init(chords_mem, sizeof(chords_mem)); + chords_.Init(&allocator); + chords_.chord_index_quantizer_.hysteresis_ = 0; // input => output + chords_.Reset(); + + engine::addParam("#LEN", &len, 1, 20); + engine::addParam(V_OCT, &arp_root); // arp_root ist automatically added to engine::cv() + engine::addParam("#HIT", &pulses, 0, 16); + engine::addParam("Mode", &mode, 0, LEN_OF(smodes) - 1, smodes); + engine::addParam("#ROT", &rotate, 0, 32); + engine::addParam("CHRD", &chord, 0, plaits::kChordNumChords - 1, (const char **)plaits::chord_names); + engine::addParam("RNGE", &octaves, 0, LEN_OF(soctaves) - 1, soctaves); + engine::addParam("SLIDE", &_slide, 0, 1); + engine::setMode(ENGINE_MODE_CV_OUT); +} + +uint8_t pattern[64] = {}; + +int32_t gate_until_t = 0; +static int32_t key = 1; + +int32_t _len = len; // for mod vizualization +int32_t _swing = swing; // for mod vizualization + +char debug[128] = {}; + +static int32_t _last_len = -1; +static auto _last_pulses = pulses; +static auto _last_rotate = rotate; +static auto _last_mode = mode; +static uint32_t _slide_phase = UINT32_MAX; +static uint32_t _slide_phase_inc = 0; + +uint32_t _t = 0; +float _last_cv = 0; +float _cv = 0; +float _cv_out = 0; + +void update_seq_pattern() +{ + CONSTRAIN(pulses, pulses, len); + rotate %= len; + _swing = swing; + + if (_last_len != len || _last_pulses != pulses || _last_rotate != rotate || _last_mode != mode) + { + if (_last_len != len && _last_len == _last_pulses) + pulses = len; + + _last_len = len; + _last_pulses = pulses; + _last_rotate = rotate; + _last_mode = mode; + pre_start = false; + _len = len; + + make_pattern(pattern, len, pulses, rotate); + + for (int i = len; i < 64; i++) + pattern[i] = pattern[i - len]; + } + + if (engine::stepChanged()) + { + seq_pos = engine::step() % len; + if (seq_pos == 0) + arpeggiator_.Reset(); + + bool trig = pattern[seq_pos]; + + if (trig) + { + uint32_t n = 1 + (engine::t() - _t) / 2; + + if (_slide > 0) + { + int m = n * 2; + for (int i = seq_pos; !pattern[(i + 1) % _len]; i++) + m += n * 2; + + _slide_phase = 0; + _slide_phase_inc = UINT32_MAX / n; + gate_until_t = 2 + m; + } + else + gate_until_t = 2 + n; // 10ms trigger + + arpeggiator_.Clock(chords_.num_notes()); + const float ratio = chords_.sorted_ratio(arpeggiator_.note()); + _last_cv = _cv; + _cv = engine::cv() + arpeggiator_.octave() + log2f(ratio); + + key++; + } + + _t = engine::t(); + } +} + +void engine::process() +{ + if (!playing) + { + gate_until_t = 0; + seq_pos = len - 1; + pre_start = true; + return; + } + + update_seq_pattern(); + + arpeggiator_.set_mode((plaits::ArpeggiatorMode)(mode % plaits::ARPEGGIATOR_MODE_LAST)); + arpeggiator_.set_range(1 + octaves); + + chords_.set_chord((float)chord / (plaits::kChordNumChords - 1)); + chords_.Sort(); + + int32_t trig = 0; + + if (gate_until_t > 0) + { + --gate_until_t; + trig = 5 * PITCH_PER_OCTAVE; // 5V + } + + if (_slide_phase < (UINT32_MAX - _slide_phase_inc)) + { + float e = stmlib::Interpolate824(peaks::lut_env_expo, _slide_phase); + _slide_phase += _slide_phase_inc; + _cv_out = _last_cv + ((_cv - _last_cv) * (e / UINT16_MAX)); + } + else + { + _cv_out = _cv; + } + + std::fill_n(engine::outputBuffer<1>(), FRAME_BUFFER_SIZE, _cv_out); + + std::fill_n(engine::outputBuffer_i16<0>(), FRAME_BUFFER_SIZE, trig); +} + +void engine::draw() +{ + // for (int i = 0; i < chords_.num_notes(); i++) + // { + // const float ratio = chords_.sorted_ratio(i); + // float notef = engine::cv() + arpeggiator_.octave() + log2f(ratio); + + // float delta = 10.f; + // int note = 0; + + // int n = 0; + // for (float i = -4.f; i < 4.f; i += 1.f / 12) + // { + // float d = std::fabs(i - notef); + // if (d < delta) + // { + // delta = d; + // note = n; + // } + + // ++n; + // } + // bool now = fabsf(_cv - notef) < 0.001f; + + // int key = note % 12; + // if (key == 1 || key == 3 || key == 6 || key == 8 || key == 10) + // gfx::invertRect((key < 5 ? 87 : 89) + (key * 2), (now ? 20 : 21) - 5, 1, now ? 3 : 1); + // else + // gfx::clearRect((key < 5 ? 87 : 89) + (key * 2), now ? 20 : 21, 1, now ? 3 : 1); + // } + draw_eclid_cyrcle(36, 31, pattern, _last_len, _last_rotate); +} \ No newline at end of file diff --git a/app/SEQ/EuclidRythm.bin b/app/SEQ/EuclidRythm.bin new file mode 100644 index 0000000000000000000000000000000000000000..6be4a4d5664a0419419f7f5f92113debefa7afa8 GIT binary patch literal 3768 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 Kw4;pw4gL#s?Yt@g literal 0 HcmV?d00001 diff --git a/app/SEQ/EuclidRythm.cpp b/app/SEQ/EuclidRythm.cpp new file mode 100644 index 0000000..e4c901f --- /dev/null +++ b/app/SEQ/EuclidRythm.cpp @@ -0,0 +1,302 @@ + +// Copyright (C)2021 - Eduard Heidt +// +// Author: Eduard Heidt (eh2k@gmx.de) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// + +#include "../squares-and-circles-api.h" +#include "../lib/misc/euclidean.h" +#include +#include + +// build_flags: -fno-inline -mfloat-abi=soft -mfpu=fpv5-d16 + +// This app is copiled with soft-fpu - for running on teensy3.2 & teensy 4.x + +/* +https://www.nullhardware.com/blog/fixed-point-sine-and-cosine-for-embedded-systems/ + +Implements the 5-order polynomial approximation to sin(x). +@param i angle (with 2^15 units/circle) +@return 16 bit fixed point Sine value (4.12) (ie: +4096 = +1 & -4096 = -1) + +The result is accurate to within +- 1 count. ie: +/-2.44e-4. +*/ + +int16_t fpsin(int16_t i) +{ + /* Convert (signed) input to a value between 0 and 8192. (8192 is pi/2, which is the region of the curve fit). */ + /* ------------------------------------------------------------------- */ + i <<= 1; + uint8_t c = i < 0; // set carry for output pos/neg + + if (i == (i | 0x4000)) // flip input value to corresponding value in range [0..8192) + i = (1 << 15) - i; + i = (i & 0x7FFF) >> 1; + /* ------------------------------------------------------------------- */ + + /* The following section implements the formula: + = y * 2^-n * ( A1 - 2^(q-p)* y * 2^-n * y * 2^-n * [B1 - 2^-r * y * 2^-n * C1 * y]) * 2^(a-q) + Where the constants are defined as follows: + */ + uint32_t A1 = 3370945099UL, B1 = 2746362156UL, C1 = 292421UL; + uint32_t n = 13, p = 32, q = 31, r = 3, a = 12; + + uint32_t y = (C1 * ((uint32_t)i)) >> n; + y = B1 - (((uint32_t)i * y) >> r); + y = (uint32_t)i * (y >> n); + y = (uint32_t)i * (y >> n); + y = A1 - (y >> (p - q)); + y = (uint32_t)i * (y >> n); + y = (y + (1UL << (q - a - 1))) >> (q - a); // Rounding + + return c ? -y : y; +} + +// Cos(x) = sin(x + pi/2) +inline int16_t fpcos(int16_t i) { return fpsin((int16_t)(((uint16_t)(i)) + 8192U)); } + +// https://xbm.jazzychad.net/ +const uint8_t xmb_note_6x8[8] = {0xc8, 0xd8, 0xe8, 0xd8, 0xe8, 0xce, 0xcf, 0xc6}; +const uint8_t xmb_rest_6x8[8] = {0xd6, 0xde, 0xd0, 0xd6, 0xde, 0xd0, 0xd0, 0xd0}; + +const uint8_t xmb_arrow_up_5x6[6] = {0xe4, 0xee, 0xff, 0xe4, 0xe4, 0xe4}; +const uint8_t xmb_arrow_dn_5x6[6] = {0xe4, 0xe4, 0xe4, 0xf5, 0xee, 0xe4}; +const uint8_t xmb_circle_7x7[7] = {0x9c, 0xa2, 0xc1, 0xc1, 0xc1, 0xa2, 0x9c}; +const uint8_t xmb_filled_circle_7x7[7] = {0x9c, 0xa2, 0xdd, 0xdd, 0xdd, 0xa2, 0x9c}; +const uint8_t xbm_play_11x11[] = {0x03, 0xf8, 0x0d, 0xf8, 0x31, 0xf8, 0xc1, 0xf8, 0x01, 0xfb, 0x01, 0xfc, 0x01, 0xfb, 0xc1, 0xf8, 0x31, 0xf8, 0x0d, 0xf8, 0x03, 0xf8}; +const uint8_t xbm_stop_7x11[] = {0x80, 0xf7, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xf7, 0x80}; + +bool playing = true; +bool pre_start = false; +uint8_t seq_pos = UINT8_MAX; +int32_t swing = 128; + +void draw_eclid_cyrcle(int x, int y, uint8_t pattern[64], int _len, int rot) +{ + auto pattern2 = pattern; + + int xx = x; + int yy = y; + + if ((fpsin((INT16_MAX / (_len))) / 194) > 6) + { + gfx::drawCircle(xx + 3, 31 + 3, 21); + + for (int i = 0; i < _len; i++) + { + int a = (INT16_MAX / (_len)) * i; + + if (MOD(i, 2) == 1) + a += (-128 + swing) * (INT16_MAX / _len) / 6; + + int x = fpsin(a) / 194; + int y = -fpcos(a) / 194; + x += xx; + y += yy; + + gfx::clearCircle(x + 3, y + 3, 3); + } + } + + for (int i = 0; i < _len; i++) + { + int a = (INT16_MAX / (_len)) * i; + + if (MOD(i, 2) == 1) + a += (-128 + swing) * (INT16_MAX / _len) / 6; + + int dx = fpsin(a); + int dy = -fpcos(a); + + int x = xx + dx / 194; + int y = yy + dy / 194; + + if (pattern[i] || pattern2[i]) + gfx::fillRect(x + 2, y + 2, 3, 3); // gfx::drawXbm(x, y, 7, 7, xmb_filled_circle_7x7); + + if (i == rot) + gfx::drawRect(x, y, 7, 7); + else + gfx::drawCircle(x + 3, y + 3, 3); // + + bool cursor = i == MOD(seq_pos, _len); + + if (cursor && !pre_start) + gfx::drawRect(x + 1, y + 1, 5, 5); + } + + if (playing && pre_start && MOD(millis(), 300) > 150) + { + } + else + { + int x = xx - 2; + int y = 40 - 7; + if (pattern[seq_pos % _len]) + { + if (x < 64) + gfx::fillRect(x - 3, y - 7, 17, 17); + else + gfx::fillCircle(x + 5, y + 1, 8); + } + else + { + if (x < 64) + gfx::drawRect(x - 2, y - 7, 16, 16); + else + gfx::drawCircle(x + 5, y + 1, 8); + } + } +} + +int32_t len = 16; +int32_t pulses = 4; +int32_t rotate = 0; + +int32_t lenB = 16; +int32_t pulsesB = 4; +int32_t rotateB = 0; + +void engine::setup() +{ + engine::addParam("#LEN", &len, 1, 20); + engine::addParam("#LEN", &lenB, 1, 20); + engine::addParam("#HIT", &pulses, 0, 16); + engine::addParam("#HIT", &pulsesB, 0, 16); + engine::addParam("#ROT", &rotate, 0, 32); + engine::addParam("#ROT", &rotateB, 0, 32); + engine::setMode(ENGINE_MODE_CV_OUT); +} + +uint8_t pattern[64] = {}; +uint8_t pattern2[64] = {}; + +uint8_t gate_until_t = 0; +uint8_t gate_until2_t = 0; +uint8_t next_clock = 1; + +int hit1 = 0; +int hit2 = 0; + +char debug[128] = {}; + +static int32_t _last_len = -1; +static auto _last_pulses = pulses; +static auto _last_rotate = rotate; + +static int32_t _last_lenB = -1; +static auto _last_pulsesB = pulsesB; +static auto _last_rotateB = rotateB; + +void update_seq_pattern() +{ + CONSTRAIN(pulses, pulses, len); + rotate %= len; + + if (_last_len != len || _last_pulses != pulses || _last_rotate != rotate || + _last_lenB != lenB || _last_pulsesB != pulsesB || _last_rotateB != rotateB) + { + _last_len = len; + _last_pulses = pulses; + _last_rotate = rotate; + + _last_lenB = lenB; + _last_pulsesB = pulsesB; + _last_rotateB = rotateB; + + pre_start = false; + + make_pattern(pattern, len, pulses, rotate); + make_pattern(pattern2, lenB, pulsesB, rotateB); + } + + if (engine::stepChanged()) + { + seq_pos = engine::step(); + + bool trig = pattern[seq_pos % len]; + + if (trig) + { + hit1 = 64; + gate_until_t += 2; // 10ms trigger + } + + bool trig2 = pattern2[seq_pos % lenB]; + if (trig2) + { + hit2 = 64; + gate_until2_t += 2; + } + } +} + +void engine::process() +{ + if (!playing) + { + gate_until_t = gate_until2_t = 0; + seq_pos = len - 1; + next_clock = 1; + pre_start = true; + return; + } + + update_seq_pattern(); + + int32_t trig = 0; + + if (gate_until_t > 0) + { + --gate_until_t; + trig = 5 * PITCH_PER_OCTAVE; // 5V + } + + std::fill_n(engine::outputBuffer_i16<0>(), FRAME_BUFFER_SIZE, trig); + + trig = 0; + if (gate_until2_t > 0) + { + --gate_until2_t; + trig = 5 * PITCH_PER_OCTAVE; // 5V + } + + std::fill_n(engine::outputBuffer_i16<1>(), FRAME_BUFFER_SIZE, trig); +} + +void engine::draw() +{ + char tmp[16]; + sprintf(tmp, "%02d", engine::step()); + gfx::drawStringCenter(64, 12, tmp, 0); + draw_eclid_cyrcle(36, 31, pattern, _last_len, _last_rotate); + draw_eclid_cyrcle(36 + 49, 31, pattern2, _last_lenB, _last_rotateB); +} + +void engine::screensaver() +{ + gfx::clearRect(0, 0, 128, 64); + draw_eclid_cyrcle(36 - 4, 31, pattern, _last_len, _last_rotate); + draw_eclid_cyrcle(36 + 49 + 4, 31, pattern2, _last_lenB, _last_rotateB); +} \ No newline at end of file diff --git a/app/SPEECH/LPC.bin b/app/SPEECH/LPC.bin index 31ceb996403a8e39c6440dff499606c5e56fe0a3..665ca4ff55bbe2498c25a6afd3b79eed9cad851f 100644 GIT binary patch delta 678 zcmXw%Pe>F|9LIle{;ch$?AWe0GrH}VN(ug{s0eX$Wha`zVgm&Qu>`?AcoMw{YAg|S zXonYprB^!z!UUcKqf5|5!9#~S1_d3W4(p*>zd!f&;4`1^d-LAB$M4Plme|-5*T((P zyAGYBWsS(bMYNhAdRw5A7Q@p74S@40mE+;%g42S|8PEz+;4DZ3I}9(xd8P}R!*|)0 z3_@1n!5xZD_&n$aoVyr7mmnGtR9wO*hu{wQK5W9X@FYAB=U{GpWNtU=`v1&V>hI;8 z$gM00vUuKOOho0t;XpY6M(Kz6oA@6>x!YCd$ihXIhkG+4<1!qt7h> zqo4?QKJOxb-u9cu5GKGBcqm7Ll<}{+_(xU(8)3N~YSmwVc|@;OHTf)X8f(?(wcT&@ u2y48kYlHoD>zF=z0m=#UTY5{kcLPMDalcrI&p0 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 delta 7062 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 diff --git a/app/SYNTH/Open303.cpp b/app/SYNTH/Open303.cpp index 584bb93..9678897 100644 --- a/app/SYNTH/Open303.cpp +++ b/app/SYNTH/Open303.cpp @@ -42,8 +42,6 @@ #include "open303/src/rosic_BlendOscillator.cpp" #include "open303/src/rosic_BiquadFilter.cpp" #include "open303/src/rosic_NumberManipulations.cpp" -#include "open303/src/sequencer/rosic_AcidSequencer.cpp" -#include "open303/src/sequencer/rosic_AcidPattern.cpp" #include "open303/src/rosic_OnePoleFilter.cpp" #include "open303/src/rosic_MidiNoteEvent.cpp" #include "open303/src/rosic_TeeBeeFilter.cpp" diff --git a/app/SYNTH/Resonator.bin b/app/SYNTH/Resonator.bin index 622a75656a4bf51591a33971b181292da009811b..c6325480e5638f58719d924e982b087bcf2a862a 100644 GIT binary patch delta 984 zcmXYvTSyd97{|XeJLXz$u4UzVDc7{tb!`iUjKtOukx<+f1qCBPp$kPBLP~`S8Tb%s zCqpo(*T6tKimcRwB@vXw7Ic9^lX{SP2r5?CZvSuQ4E*NzpEKW?%XiN0Cywur9j@l; zy83(ykkdgF8gXU!B@>Yoq-fT|%mz&=%xnZMkfyU+=X99!Cct^K&KWvyfjMsloVV$m zY3D53j=&c?fCuD(EZ`lP52o{%c>%vUA9$n?yZd}dp+)L1()Mc?YX`JTVE(T?fae4O z&)Exj&OX3%xV}?Z!_+M(JQX1tfRDnr;41hYJPJ<gKD z%l37w+4iDcAIfc&E25@vw9OtK?6hp1o(ppGW0tgkX|FTvagSkjhP>K7?NaTKcD;6^ zcB}R&?H+?l^Z1Qd^}sdl8wQ0Z&k#+(<-J5tVg8?Gc)Clj7+>WZ$DF!uesQW{*P0=6 z)R4QuOyP&+fCBX?W6%^nb=>nv;AUa=ft|uHk5zibfEuVQ7A{@_ZZ)^ROhpg96@}%9 z6@WKD2vh^!Ew!Kygh7*>sR|~wAhoI0s#(+3j_3p?Xi@iTf~IIwACHVDiCozm_KI#b z9xf7A87i!@G8v0_#ftn985OV9P-BB3&dT>qck*}zP5}OpRB#%c1KofR8HiRF^dMXU z{oo2HS*63q^wOH!9b2Pe<6$B`mXMRtOfwO`Ylpw_h2Pf5zxdBT93ITIB#Q#oI)A|d z#TG6)lDKK@D)Ou&8Qq$Bx!+J@%{M#bw^-(`g%3n8z&o%EJ_FuUygs}(ye`vS%Kz$o F+J9puxXAzj delta 1021 zcmXYvZAep57{{M;H*w~s*Rq;RYEvuc3ra7f7&b$fl;R8*3R`Trq8G8Sz(7NVg8UF9 z*QhA$L-jF8juMjMdV&1n2PqJus1HF!A5us*&7%KvcP{+y?>YZ-IQQIh&eAK(gVz>E zu)e9ekjltuAqtH+whh>bh}i%#K&Gngs&>F!X9KQvkOgu8XBz=$n*e9IfV0hjvn_zL zt$;Hp;4BXybI}eJx>e|bU7%p(WkpUp3J!Q>1t7~1Vt3_sRK>sxLi03OqFkz6rd+OU zM1*r-4;tLTVV9svi24NuqLW0!umc{0mnVqE;Rdv)U@y#%&wLX-KB?TPd``JfqZ)IfVHMm_9#ej#QNSJ~nt?|nM2j&01mQS(7&-(7EcWE)@C3-dc~iB!ji3!oerRN3#!9$(x53#m<8$eSmLHJ!k}cqnbbf zw1IYGxUM2CgeoFu>YiI2d?f}2r-^K%Ip7he<%NJ(n8Pr_99CsK zY4wQr#@p80!jR$PEt-fLPum{4&tO0o;Dy-1MQ|Bh0sP3a?$J)8D_CFDkJcc#25x}z zA9Ps54(a+rl5T0!D~b53u@rP#R}yonBAHlQGn3Us$vPL(ccMLA6w7 $X.log touch -d "$(date -R -r $X.cpp)" $X.bin -cat $X.log | arm-none-eabi-c++filt -t > ${X}2.log +#cat $X.log | arm-none-eabi-c++filt -t > ${X}2.log -arm-none-eabi-objdump -g -Dztr --source $X.elf | arm-none-eabi-c++filt -t > $X.elf.txt +arm-none-eabi-objdump -Dztr --source $X.elf | arm-none-eabi-c++filt -t > $X.elf.txt #arm-none-eabi-nm -l -t d -S -C --size-sort --synthetic --special-syms --with-symbol-versions --reverse-sort ./$X.elf > $X.log which elf-size-analyze >/dev/null && elf-size-analyze -t arm-none-eabi- ./$X.elf -F -R --no-color >> $X.log md5sum $X.bin | tee -a $X.log @@ -52,9 +55,9 @@ echo "BIN_SIZE $(stat -c %s -- $X.bin)" | tee -a $X.log grep "__aeabi_" $X.log && exit 1 -xxd -i $X.bin > ./$X.bin.h -sed -i "s/unsigned char/const uint8_t/g" ./$X.bin.h -sed -i "s/\[\]/\[\] FLASHMEM __attribute__((aligned(32)))/g" ./$X.bin.h +#xxd -i $X.bin > ./$X.bin.h +#sed -i "s/unsigned char/const uint8_t/g" ./$X.bin.h +#sed -i "s/\[\]/\[\] FLASHMEM __attribute__((aligned(32)))/g" ./$X.bin.h # arm-none-eabi-gcc -fPIE -msingle-pic-base -mcpu=cortex-m4 -mthumb -Wl,--unresolved-symbols=ignore-in-object-files -fdump-lang-class -I. -I../lib/ $X.cpp # arm-none-eabi-objdump --disassemble-all --no-addresses ./$X.elf > $X.s @@ -65,5 +68,8 @@ done find . -type f -name '*.o' -delete find . -type f -name '*.bin' -exec stat --printf="%-20n\t%6s\n" -- {} \; -du -ch */*.bin | grep total +du -ch $(dirname $0)/*/*.bin | grep total #find . -type f -name '*.bin' -delete + +pio --version || alias pio=~/.platformio/penv/bin/pio +pio run -v --environment squares-and-circles \ No newline at end of file diff --git a/app/index.json b/app/index.json index c4174ce..aaebc5b 100644 --- a/app/index.json +++ b/app/index.json @@ -1,17 +1,21 @@ { "apps": [ + "CV/EnvGen_ADSR.bin", "NOISE/WhitePink.bin", "NOISE/NES.bin", "NOISE/808_squares.bin", "MIDI/Monitor.bin", "MIDI/Clock.bin", + "DRUMS/FM-Drum.bin", + "DRUMS/808ish-BD.bin", + "DRUMS/808ish-SD.bin", + "DRUMS/808ish-HiHat.bin", "DRUMS/TR909-HiHat.bin", "DRUMS/TR909-Ride.bin", "DRUMS/TR707.bin", - "DRUMS/TR707-HiHat.bin", - - "DRUMS/Vint.Samples.bin", + + "M-OSC/Waveforms.bin", "FX/Reverb.bin", "FX/ReverbSC.bin", @@ -26,6 +30,9 @@ "FX/Delay.bin", "FX/Gated-Reverb.bin", "FX/Reverb-HP-LP.bin", + + "SEQ/EuclidRythm.bin", + "SEQ/EuclidArp.bin", "MIDI/VAx6.bin", diff --git a/app/squares-and-circles-api.h b/app/squares-and-circles-api.h index 00a615f..fceaffc 100644 --- a/app/squares-and-circles-api.h +++ b/app/squares-and-circles-api.h @@ -35,29 +35,20 @@ #include #include -#ifndef MACHINE_INTERNAL +#define V_OCT "V_OCT" +#define V_QTZ "V_QTZ" +#define SEQ_SWING "$SWING" +#define MULTI_TRIGS ">TRIGS" -#if 0 -#define WASM_EXPORT extern "C" __attribute__((used)) __attribute__((visibility("default"))) -#define WASM_EXPORT_AS(NAME) WASM_EXPORT __attribute__((export_name(NAME))) -#define WASM_IMPORT(MODULE, NAME) __attribute__((import_module(MODULE))) __attribute__((import_name(NAME))) -#define WASM_CONSTRUCTOR __attribute__((constructor)) -#else -#define WASM_EXPORT extern "C" -#define WASM_EXPORT_AS(NAME) WASM_EXPORT -#define WASM_IMPORT(MODULE, NAME) -#define WASM_CONSTRUCTOR +#ifndef EXTERN_C +#define EXTERN_C extern "C" #endif -#ifndef FLASHMEM -#define FLASHMEM __attribute__((section(".text"))) -#endif +#ifndef MACHINE_INTERNAL + #define LEN_OF(x) (sizeof(x) / sizeof(x[0])) #define MOD(x, y) ((x) % (y)) -#ifndef ONE_POLE -#define ONE_POLE(out, in, coefficient) out += (coefficient) * ((in)-out); -#endif #ifndef CONSTRAIN #define CONSTRAIN(var, min, max) \ if (var < (min)) \ @@ -71,7 +62,6 @@ #endif -#define V_OCT "V_OCT" #define IO_STEREOLIZE ".IO_STEREO" #ifdef __cplusplus @@ -83,13 +73,10 @@ // # pragma GCC poison virtual #endif -#ifndef EMSCRIPTEN - -extern "C" uint32_t micros(); -extern "C" uint32_t millis(); -extern "C" uint32_t crc32(uint32_t crc, const void *buf, size_t size); +EXTERN_C uint32_t micros(); +EXTERN_C uint32_t millis(); +EXTERN_C uint32_t crc32(uint32_t crc, const void *buf, size_t size); -#endif #endif #ifndef DEFAULT_NOTE @@ -107,13 +94,15 @@ extern "C" uint32_t crc32(uint32_t crc, const void *buf, size_t size); #ifndef engine -extern "C" +EXTERN_C { extern uint32_t *__t; extern uint8_t *__clock; - extern uint8_t *__trig; - extern uint8_t *__gate; - extern uint8_t *__accent; + extern uint8_t *__step; + extern bool *__step_changed; + extern uint32_t *__trig; + extern uint32_t *__gate; + extern uint32_t *__accent; extern float *__cv; extern float *__output_l_fp; @@ -163,6 +152,23 @@ extern "C" if (__midi_event_handler_ptr) __midi_event_handler_ptr(); } + + extern struct + { + uint8_t tr; + uint8_t ac; + uint8_t cv; + uint8_t qz; + int8_t transpose; + uint8_t aux; + uint8_t ext[4] = {0, 0, 0, 0}; + uint8_t midi_channel; + uint8_t dac; + uint8_t level; + uint8_t pan; // 128 == center + uint8_t stereo; + uint8_t aux_dry; + } *__io; } namespace engine @@ -171,11 +177,15 @@ namespace engine inline uint32_t t() { return *__t; } inline uint8_t clock() { return *__clock; } - inline uint8_t trig() { return *__trig; } - inline uint8_t gate() { return *__gate; } - inline uint8_t accent() { return *__accent; } + inline uint8_t step() { return *__step; } + inline bool stepChanged() { return *__step_changed; } + inline uint32_t trig() { return *__trig; } + inline uint32_t gate() { return *__gate; } + inline uint32_t accent() { return *__accent; } inline float cv() { return *__cv; } + inline bool is_stereo() { return (__io->dac == 2 || __io->dac == 5); } + template inline float *outputBuffer(); @@ -203,10 +213,10 @@ namespace engine template <> inline float *inputBuffer<1>() { return *__audio_in_r_fpp; } - extern "C" void setup(); - extern "C" void process(); - extern "C" void draw(); - extern "C" void screensaver(); + EXTERN_C void setup(); + EXTERN_C void process(); + EXTERN_C void draw(); + EXTERN_C void screensaver(); ///// typedef bool (*uiHandler)(uint16_t type, uint16_t control, int16_t value, uint16_t mask); @@ -223,8 +233,8 @@ namespace engine void __attribute__((weak)) onMidiCC(uint8_t ccc, uint8_t value); void __attribute__((weak)) onMidiSysex(uint8_t byte); - extern "C" void addParam_f32(const char *name, float *value, float min = 0.f, float max = 1.f); // min...max - extern "C" void addParam_i32(const char *name, int32_t *value, int32_t min, int32_t max, const char **valueMap); // 0...max + EXTERN_C void addParam_f32(const char *name, float *value, float min = 0.f, float max = 1.f); // min...max + EXTERN_C void addParam_i32(const char *name, int32_t *value, int32_t min, int32_t max, const char **valueMap); // 0...max void addParam(const char *name, int32_t *value, int32_t min, int32_t max, const char **valueMap = nullptr) // 0...max { @@ -270,19 +280,18 @@ namespace engine constexpr uint32_t PARAM_SELECTED = 0x1; constexpr uint32_t PARAM_MODULATION = 0x2; - extern "C" uint32_t getParamFlags(const void *valuePtr); + EXTERN_C uint32_t getParamFlags(const void *valuePtr); inline uint32_t isParamSelected(const void *valuePtr) { return getParamFlags(valuePtr) & PARAM_SELECTED; } - extern "C" - { - void *dsp_sample_u8(const uint8_t *data, int len, int sample_rate, int addr_shift); - void *dsp_sample_Am6070(const uint8_t *data, int len, int sample_rate, int amp_mul); - void dsp_process_sample(void *smpl, float start, float end, float pitch, float output[FRAME_BUFFER_SIZE]); - void dsp_process_hihats(void *ch, void *oh, float ch_vol, float ch_dec, float oh_dec, float output[FRAME_BUFFER_SIZE]); - } + EXTERN_C void setParamName(const void *valuePtr, const char *name); + + EXTERN_C void *dsp_sample_u8(const uint8_t *data, int len, int sample_rate, int addr_shift); + EXTERN_C void *dsp_sample_Am6070(const uint8_t *data, int len, int sample_rate, int amp_mul); + EXTERN_C void dsp_set_sample_pos(void *smpl, float pos, float amplitude, float decay); + EXTERN_C void dsp_process_sample(void *smpl, float start, float end, float pitch, float output[FRAME_BUFFER_SIZE]); } enum EventType : uint16_t @@ -300,7 +309,7 @@ constexpr uint16_t ENCODER_R = (1 << 9); namespace machine { - extern "C" const uint8_t *fs_read(const char *blobName); + EXTERN_C const uint8_t *fs_read(const char *blobName); inline uint32_t clk_bpm() { @@ -330,53 +339,53 @@ namespace machine else return nullptr; } -}; +} #else using namespace ui; using namespace UI; #endif +#ifndef GFX_API namespace gfx { - extern "C" void drawCircle(int x, int y, int r); - extern "C" void fillCircle(int x, int y, int r); - extern "C" void clearCircle(int x, int y, int r); - extern "C" void drawRect(int x, int y, int w, int h); - extern "C" void fillRect(int x, int y, int w, int h); - extern "C" void clearRect(int x, int y, int w, int h); - extern "C" void invertRect(int x, int y, int w, int h); - extern "C" void drawString(int32_t x, int32_t y, const char *s, int32_t font = 1); - extern "C" void drawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2); - extern "C" void setPixel(int x, int y) - { - drawLine(x, y, x, y); - } - extern "C" void drawXbm(int x, int y, int width, int height, const uint8_t *xbm); - extern "C" void message(const char *msg); + EXTERN_C void drawCircle(int x, int y, int r); + EXTERN_C void fillCircle(int x, int y, int r); + EXTERN_C void clearCircle(int x, int y, int r); + EXTERN_C void drawRect(int x, int y, int w, int h); + EXTERN_C void fillRect(int x, int y, int w, int h); + EXTERN_C void clearRect(int x, int y, int w, int h); + EXTERN_C void invertRect(int x, int y, int w, int h); + EXTERN_C void drawString(int x, int y, const char *s, uint8_t font = 1); + EXTERN_C void drawStringCenter(int x, int y, const char *s, uint8_t font = 1); + EXTERN_C void drawLine(int x1, int y1, int x2, int y2); + EXTERN_C void setPixel(int x, int y); + EXTERN_C void drawXbm(int x, int y, int width, int height, const uint8_t *xbm); + EXTERN_C void drawSample(void *smpl); + EXTERN_C void message(const char *msg); inline uint8_t *displayBuffer() { return __display_buffer_u8_p; } } +#endif +#ifndef SERIAL_API namespace machine { - extern "C" - { - extern void serial_write(void const *buffer, uint32_t bufsiz); - extern uint32_t serial_read(void *buffer, uint32_t length); - extern uint32_t serial_available(); + EXTERN_C void serial_write(void const *buffer, uint32_t bufsiz); + EXTERN_C uint32_t serial_read(void *buffer, uint32_t length); + EXTERN_C uint32_t serial_available(); - extern void get_device_id(uint8_t *mac); + EXTERN_C void get_device_id(uint8_t *mac); - extern float cpu_load_percent(); + EXTERN_C float cpu_load_percent(); - extern uint8_t *engine_malloc(uint32_t size); - extern void engine_start(uint32_t args); - extern void engine_stop(uint32_t result); - } + EXTERN_C uint8_t *engine_malloc(uint32_t size); + EXTERN_C void engine_start(uint32_t args); + EXTERN_C void engine_stop(uint32_t result); } +#endif #endif // MACHINE_INTERNAL @@ -410,14 +419,11 @@ typedef DWORD FSIZE_t; #define FA_OPEN_ALWAYS 0x10 #define FA_OPEN_APPEND 0x30 -extern "C" -{ - FRESULT f_open(FIL *f, const char *name, uint32_t mode); - FRESULT f_read(FIL *f, void *p, UINT size, UINT *bytes_read); - FSIZE_t f_tell(FIL *fp); - FSIZE_t f_size(FIL *fp); - FRESULT f_truncate(FIL *fp); - FRESULT f_lseek(FIL *fp, FSIZE_t ofs); - FRESULT f_close(FIL *f); - FRESULT f_write(FIL *fp, const void *buff, UINT btw, UINT *bw); -} \ No newline at end of file +EXTERN_C FRESULT f_open(FIL *f, const char *name, uint32_t mode); +EXTERN_C FRESULT f_read(FIL *f, void *p, UINT size, UINT *bytes_read); +EXTERN_C FSIZE_t f_tell(FIL *fp); +EXTERN_C FSIZE_t f_size(FIL *fp); +EXTERN_C FRESULT f_truncate(FIL *fp); +EXTERN_C FRESULT f_lseek(FIL *fp, FSIZE_t ofs); +EXTERN_C FRESULT f_close(FIL *f); +EXTERN_C FRESULT f_write(FIL *fp, const void *buff, UINT btw, UINT *bw); \ No newline at end of file diff --git a/app/upload.py b/app/upload.py new file mode 100755 index 0000000..78caba1 --- /dev/null +++ b/app/upload.py @@ -0,0 +1,169 @@ +#!/bin/python3 + +import rtmidi +import json +import os +import zlib +import time +import intelhex # pip install intelhex - #https://python-intelhex.readthedocs.io/en/latest/part2-2.html +import os, io + +midiout = rtmidi.MidiOut() + +for i in range(0, midiout.get_port_count()): + if midiout.get_port_name(i).startswith("S&C"): + midiout.open_port(i) + +midiin = rtmidi.MidiIn(queue_size_limit=1024 * 8) + +for i in range(0, midiin.get_port_count()): + if midiin.get_port_name(i).startswith("S&C"): + midiin.open_port(i) + +while True: + msg = midiin.get_message() + if not msg: + break + + +def flush(midiin): + while True: + msg = midiin.get_message() + if not msg: + break + + +def chunk_bytes(bytes_object, chunk_size): + chunks = ( + bytes_object[i : i + chunk_size] + for i in range(0, len(bytes_object), chunk_size) + ) + return chunks + + +def sendFLASHDATA(name, data0): + flush(midiin) + data = bytes(name, "utf-8")[:8] + data0 + crc32 = zlib.crc32(data) + print(" Flashing", name, crc32) + midiout.send_message( + [0xF3, 0x7E] + ) # midi_out.send(mido.Message('song_select', song=0x7e)) + flush(midiin) + vlen = len(data) + ch = 0 + ((vlen & 0xF000) >> 12) + rawValue = [0b11100000 | ch, vlen & 0x7F, vlen >> 7 & 0x7F] + + midiout.send_message(rawValue) + + while True: + msg = midiin.get_message() + if msg: + ack, t = msg + print(" ACK:", ack) + break + + print(" sending blob...", len(data)) + i = 0 + time.sleep(1 / 10000) + while i < len(data) - 1: + int16 = data[i] | data[i + 1] << 8 + ch = 0 + ((data[i + 1] & 0xF0) >> 4) + rawValue = [0b11100000 | ch, int16 & 0x7F, int16 >> 7 & 0x7F] + midiout.send_message(rawValue) + time.sleep(1 / 10000) + i += 2 + + flush(midiin) + time.sleep(1 / 10000) + + rawValue = [0b11100000, crc32 & 0x7F, crc32 >> 7 & 0x7F] + midiout.send_message(rawValue) + + while True: + msg = midiin.get_message() + if msg: + data, t = msg + print(" CRC_CHECK:", data) + break + + +midiout.send_message([0xF3, ord("E")]) + +engines = "" + +try: + while True: + msg = midiin.get_message() + if msg: + data, t = msg + c = (data[2] << 7 | data[1]) - 8192 + if c == 0: + break + engines += chr(c) +except KeyboardInterrupt: + print("") +finally: + print("OK") + +engines = json.loads(engines) + +apps_json = os.path.dirname(__file__) + "/index.json" +with open(apps_json) as f: + apps = json.load(f) + j = 0 + for file in apps["apps"]: + bin_file = os.path.dirname(apps_json) + "/" + str(file) + if not os.path.exists(bin_file): + continue + bin_size = os.path.getsize(bin_file) + with open(bin_file, "rb") as f: + crc32sum = zlib.crc32(f.read()) + engine = next( + (e for e in engines if e["id"] == os.path.splitext(file)[0]), None + ) + if engine != None and engine["crc32"] == "%x" % crc32sum: + print( + os.path.splitext(file)[0], + "%x" % crc32sum, + "OK!", + bin_size - int(engine["size"]), + ) + continue + + print("->", file, engine) + + if engine == None: + print("TODO - add new engine...") + continue + + print( + os.path.splitext(file)[0], "%x" % crc32sum, bin_size - int(engine["size"]) + ) + + offset = 0 + ih = intelhex.IntelHex() + ih.loadbin(bin_file, offset=offset) + offset += bin_size + ih.puts(offset, crc32sum.to_bytes(4, "little")) + offset += 4 + + with io.BytesIO() as w: + ih.tofile(w, format="bin") + abx = w.getvalue() + offset = int(engine["addr"], 16) # (1024 * 1024) + for chunk in chunk_bytes(abx, 4096): + sendFLASHDATA(f"0x%6x" % offset, chunk) + offset += len(chunk) + + j += 1 + + offset += 4 - (offset % 4) + + if j > 0: + midiout.send_message([0xF3, 0x7F]) #reset + +midiin.close_port() +midiout.close_port() +del midiin +del midiout diff --git a/build.py b/build.py index 25a9ff3..7079b7f 100644 --- a/build.py +++ b/build.py @@ -3,7 +3,6 @@ import json import shutil import io -import mido #~/.platformio/penv/bin/pip install mido python-rtmidi import zlib import time import intelhex #pip install intelhex - #https://python-intelhex.readthedocs.io/en/latest/part2-2.html @@ -29,6 +28,7 @@ def make_engines_hex(apps_json, ih = intelhex.IntelHex(), offset= 0): else: with open(apps_json) as f: apps = json.load(f) + i = 1 for file in apps["apps"]: bin_file=os.path.dirname(apps_json)+'/'+str(file) if not os.path.exists(bin_file): @@ -43,16 +43,16 @@ def make_engines_hex(apps_json, ih = intelhex.IntelHex(), offset= 0): ih.puts(offset, crc32sum.to_bytes(4, 'little') ) offset += 4 - print("0x%x" % bin_offset, bin_file, bin_size, udynlink_size(bin_file) % 4, "CRC32: %x" % crc32sum) - - offset += 4 - (offset % 4) + print(i, "0x%x" % bin_offset, bin_file, bin_size, udynlink_size(bin_file) % 4, "CRC32: %x" % crc32sum) + i+=1 + offset += 4096 - (offset % 4096) ih.puts(offset, 0xffff.to_bytes(4, 'little') ) return ih env = DefaultEnvironment() #print(env.Dump()) -env.Execute(f"bash $PROJECT_DIR/app/build.sh") +#env.Execute(f"bash $PROJECT_DIR/app/build.sh") env.Append( LINKFLAGS=[ @@ -61,70 +61,6 @@ def make_engines_hex(apps_json, ih = intelhex.IntelHex(), offset= 0): ] ) -midi_out = None -midi_in = None - -def midi_init(): - global midi_in, midi_out - try: - for mo in mido.get_output_names(): - if "S&C" in mo or "Squares&Circles" in mo or "Teensy MIDI" in mo: - midi_out = mido.open_output(mo) - break - - for mi in mido.get_input_names(): - print(mi) - if "S&C" in mi or "Squares&Circles" in mi or "Teensy MIDI" in mi: - midi_in = mido.open_input(mi) - break - except: - pass - - -def chunk_bytes(bytes_object, chunk_size): - chunks = (bytes_object[i:i+chunk_size] for i in range(0, len(bytes_object), chunk_size)) - return chunks - -def flush(input): - for m in input.iter_pending(): - m #print("FLUSH", m) - -def sendFLASHDATA(name, data0): - flush(midi_in) - data = bytes(name, 'utf-8')[:8] + data0 - crc32=zlib.crc32(data) - print("Flashing", name, crc32) - midi_out.send(mido.Message('song_select', song=0x7e)) - flush(midi_in) - vlen = len(data) - ch = 0 + ((vlen & 0xF000) >> 12) - rawValue = [0b11100000 | ch, vlen & 0x7f, vlen >> 7 & 0x7f] - msg0 = mido.Message.from_bytes(rawValue) - midi_out.send(msg0) - msg1 = midi_in.receive(block=True) - if msg1.pitch != 1: - print("INIT FAILED", msg1.pitch, msg1) - exit(-1) #no memory - i=0 - time.sleep(1/10000) - while i < len(data): - int16 = data[i] | data[i + 1] << 8 - ch = 0 + ((data[i + 1] & 0xF0) >> 4) - rawValue = [0b11100000 | ch, int16 & 0x7f, int16 >> 7 & 0x7f] - midi_out.send(mido.Message.from_bytes(rawValue)) - time.sleep(2/10000) - i += 2 - - flush(midi_in) - time.sleep(1/10000) - - rawValue = [0b11100000, crc32 & 0x7f, crc32 >> 7 & 0x7f] - midi_out.send(mido.Message.from_bytes(rawValue)) - msg1 = midi_in.receive(block=True) - if msg1.pitch != 1: - print("CRC CHECK FAILED", msg1.pitch, msg1) - exit(-1) #crc failed - def post_program_action(source, target, env): os.remove(target[0].get_abspath()) apps_json=env.GetProjectOption("apps_json") @@ -137,28 +73,7 @@ def post_program_action(source, target, env): print(program_path, len(ahx)) def upload_hex(source, target, env): - - midi_init() - - print(midi_in) - print(midi_out) - - if midi_out == None: - exit(-1) - - program_path = env.GetBuildPath("$PROJECT_DIR/.pio/build/$PIOENV/engines.hex") - ahx = intelhex.IntelHex(program_path) - - with io.BytesIO() as w: - ahx.tofile(w, format='bin') - abx=w.getvalue() - offset = (1024 * 1024) - for chunk in chunk_bytes(abx, 4096): - sendFLASHDATA(f"0x%6x" % offset, chunk) - offset += len(chunk) - print(len(abx)) - midi_out.send(mido.Message('song_select', song=0x7f)) - + print("not implemented!") exit(0) env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex", post_program_action) diff --git a/doc/.conv.sh b/doc/.conv.sh index c06a7bb..eb2d679 100644 --- a/doc/.conv.sh +++ b/doc/.conv.sh @@ -1,5 +1,5 @@ -montage -background '#25282c' -tile 5x -geometry +10+10 gnd_*.png cv_*.png drums_*.png mosc_*.png synth_*.png noise_*.png fx_*.png midi_*.png engines.png +montage -background '#25282c' -tile 5x -geometry +10+10 gnd_*.png cv_*.png drums_*.png mosc_*.png synth_*.png noise_*.png fx_*.png midi_*.png seq_*.png engines.png for f in $1; do convert $f -sample 256x128 ${f%.*}.png diff --git a/doc/engines.png b/doc/engines.png index 5f2c27bc3ab0bfcb2319d66ddea6fd45d8486e1b..fef02e1ec64d48473d03a2f9c42f86239fddc9bb 100644 GIT binary patch literal 14518 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 0) - { + if (fclk > 0) { auto pclk_old = pclk; pclk += fclk; unsigned tick_count = (unsigned)pclk; pclk -= tick_count; - for (unsigned tick = 0; tick < tick_count; ++tick) - { + for (unsigned tick = 0; tick < tick_count; ++tick) { auto d = (1 - pclk_old + tick) * (1 / fclk); d -= (unsigned)d; - if ((ptick & 1) == 0) - { + if ((ptick & 1) == 0) { fin.interpolate_G(d, Gin); cdouble s = 0; for (unsigned m = 0; m < Min; ++m) @@ -77,8 +81,7 @@ void BBD_Line::process(unsigned n, const float *input, float *output, const floa mem[imem] = s.real(); imem = ((imem + 1) < ns) ? (imem + 1) : 0; } - else - { + else { fout.interpolate_G(d, Gout); auto ybbd = mem[imem]; auto delta = ybbd - ybbd_old; @@ -94,8 +97,7 @@ void BBD_Line::process(unsigned n, const float *input, float *output, const floa Xin[m] = Pin[m] * Xin[m] + cdouble(input[i]); cdouble y = fout.H * ybbd_old; - for (unsigned m = 0; m < Mout; ++m) - { + for (unsigned m = 0; m < Mout; ++m) { cdouble xout = Pout[m] * Xout_mem[m] + Xout[m]; Xout_mem[m] = xout; y += xout; diff --git a/lib/bbd/bbd_line.h b/lib/bbd/bbd_line.h index 8bd188d..c604155 100644 --- a/lib/bbd/bbd_line.h +++ b/lib/bbd/bbd_line.h @@ -7,10 +7,6 @@ class BBD_Line { public: - - BBD_Line():mem_(0) - {} - /** * Initialize a delay line with the specified parameters. (non-RT) * @param fs audio sampling rate @@ -20,6 +16,13 @@ class BBD_Line { */ void setup(unsigned ns, const BBD_Filter_Coef &fin, const BBD_Filter_Coef &fout); + /** + * Change the number of stages. (RT?) + * @note It guarantees not to reallocate the buffer for \f$ns \leq 8192\f$. + * @param ns number of stages / length of the virtual capacitor array + */ + void set_delay_size(unsigned ns); + /** * Reinitialize all the internal state to zero. (RT) */ diff --git a/lib/braids/settings.cc b/lib/braids/settings.cc index f61d795..df3b3ca 100644 --- a/lib/braids/settings.cc +++ b/lib/braids/settings.cc @@ -191,6 +191,7 @@ const char* const algo_values[] = { "CLOU", "PRTC", "QPSK", + "****" // "NAME" // For your algorithm }; diff --git a/lib/misc/euclidean.h b/lib/misc/euclidean.h new file mode 100644 index 0000000..2a8c155 --- /dev/null +++ b/lib/misc/euclidean.h @@ -0,0 +1,118 @@ + +// Copyright (C)2023 - Eduard Heidt +// +// Author: Eduard Heidt (eh2k@gmx.de) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// + +#include +#include + +// found here: +// https://louridas.github.io/rwa/assignments/musical-rhythms/#toussaint:2005 +// https://cgm.cs.mcgill.ca/~godfried/publications/banff.pdf + +// https://github.com/grindcode/rhythms/blob/main/src/lib.rs#L129 +// https://github.com/computermusicdesign/euclidean-rhythm/blob/master/max-example/euclidSimple.js + +void simple_pattern(uint8_t *pattern, int len, int pulses, int rotate) +{ + pulses = std::min(pulses, len); + uint8_t bucket = 0; + uint8_t offset = 2 + rotate; + + if (len > 0 && pulses > 0) + offset += len / pulses - 1; + + for (uint8_t i = 0; i < len; i++) + { + uint8_t pos = (offset + i) % len; + bucket += pulses; + if (bucket >= len) + { + bucket -= len; + pattern[pos] = 1; + } + else + { + pattern[pos] = 0; + } + } +} + +// based on https://bitbucket.org/sjcastroe/bjorklunds-algorithm/src/master/Bjorklund's%20Algorithm/bjorklund.cpp + +void bjorklund_pattern(uint8_t *pattern, int len, int pulses, int rotate) +{ + struct Pattern + { + uint32_t hits; + size_t len; + void append(const Pattern &second) + { + hits |= (second.hits << len); + len += second.len; + } + }; + + if (pulses > len) + pulses = len; + + Pattern x = {0x1, 1}; + int x_amount = pulses; + Pattern y = {0x0, 1}; + int y_amount = len - pulses; + + do + { + int x_temp = x_amount; + int y_temp = y_amount; + Pattern y_copy = y; + + if (x_temp >= y_temp) + { + x_amount = y_temp; + y_amount = x_temp - y_temp; + + y = x; + } + else + { + x_amount = x_temp; + y_amount = y_temp - x_temp; + } + + x.append(y_copy); + } while (x_amount > 1 && y_amount > 1); + + int k = 0; + for (int i = 1; i <= x_amount; i++) + for (auto j = 0; j < x.len; j++) + pattern[(k++ + rotate) % len] = (x.hits & (0x1 << j)); + for (int i = 1; i <= y_amount; i++) + for (auto j = 0; j < y.len; j++) + pattern[(k++ + rotate) % len] = (y.hits & (0x1 << j)); +} + +#ifndef make_pattern +#define make_pattern bjorklund_pattern +#endif \ No newline at end of file diff --git a/lib/open303/src/wavetable_gen/rosic_FourierTransformerRadix2.cpp b/lib/open303/src/wavetable_gen/rosic_FourierTransformerRadix2.cpp index fd12952..08898a8 100644 --- a/lib/open303/src/wavetable_gen/rosic_FourierTransformerRadix2.cpp +++ b/lib/open303/src/wavetable_gen/rosic_FourierTransformerRadix2.cpp @@ -16,22 +16,25 @@ FourierTransformerRadix2::FourierTransformerRadix2() direction = FORWARD; normalizationMode = NORMALIZE_ON_INVERSE_TRAFO; normalizationFactor = 1.0; +#ifndef STATIC_N w = NULL; ip = NULL; tmpBuffer = NULL; - +#endif setBlockSize(256); } FourierTransformerRadix2::~FourierTransformerRadix2() { // free dynamically allocated memory: +#ifndef STATIC_N if( w != NULL ) delete[] w; if( ip != NULL ) delete[] ip; if( tmpBuffer != NULL ) delete[] tmpBuffer; +#endif } //------------------------------------------------------------------------------------------------- @@ -50,6 +53,7 @@ void FourierTransformerRadix2::setBlockSize(int newBlockSize) logN = (int) floor( log2((real_t) N + 0.5 ) ); updateNormalizationFactor(); +#ifndef STATIC_N if( w != NULL ) delete[] w; w = new real_t[2*N]; @@ -62,6 +66,9 @@ void FourierTransformerRadix2::setBlockSize(int newBlockSize) if( tmpBuffer != NULL ) delete[] tmpBuffer; tmpBuffer = new Complex[N]; +#else + ip[0] = 0; +#endif } } else if( !isPowerOfTwo(newBlockSize) || newBlockSize <= 1 ) diff --git a/lib/open303/src/wavetable_gen/rosic_FourierTransformerRadix2.h b/lib/open303/src/wavetable_gen/rosic_FourierTransformerRadix2.h index f456ded..9ece96e 100644 --- a/lib/open303/src/wavetable_gen/rosic_FourierTransformerRadix2.h +++ b/lib/open303/src/wavetable_gen/rosic_FourierTransformerRadix2.h @@ -8,6 +8,8 @@ #include "rosic_Complex.h" #include "../rosic_RealFunctions.h" +#define STATIC_N 256 //[eh2k] remove this, to use the original implementation (with new/delete) + namespace rosic { @@ -148,12 +150,18 @@ namespace rosic int normalizationMode; /**< The normalization mode (@see: normalizationModes. */ real_t normalizationFactor; /**< The normalization factor (can be 1, 1/N or 1/sqrt(N)). */ +#ifndef STATIC_N // work-area stuff for Ooura's fft-routines: real_t *w; /**< Table of the twiddle-factors. */ int *ip; /**< Work area for bit-reversal (index pointer?). */ // our own temporary storage area: Complex* tmpBuffer; +#else + real_t w[2*STATIC_N]; + int ip[4+16]; //ceil(4.0+sqrt(STATIC_N))]; + Complex tmpBuffer[STATIC_N]; +#endif }; diff --git a/lib/open303/src/wavetable_gen/rosic_MipMappedWaveTable.cpp b/lib/open303/src/wavetable_gen/rosic_MipMappedWaveTable.cpp index c36f6f1..0ca7b41 100644 --- a/lib/open303/src/wavetable_gen/rosic_MipMappedWaveTable.cpp +++ b/lib/open303/src/wavetable_gen/rosic_MipMappedWaveTable.cpp @@ -1,4 +1,5 @@ #include "rosic_MipMappedWaveTable.h" +#include using namespace rosic; MipMappedWaveTable::MipMappedWaveTable() @@ -244,7 +245,8 @@ void MipMappedWaveTable::fillWithSquare303() // do a circular shift to phase-align with the saw-wave, when both waveforms are mixed: int nShift = roundToInt(N*squarePhaseShift/360.0); - circularShift(prototypeTable, N, nShift); + + std::rotate(&prototypeTable[0], &prototypeTable[0] + nShift, &prototypeTable[N]); //[eh2k] circularShift(prototypeTable, N, nShift); } void MipMappedWaveTable::fillWithSaw303() diff --git a/lib/peaks/modulations/multistage_envelope.cc b/lib/peaks/modulations/multistage_envelope.cc index d09dba0..34fc805 100644 --- a/lib/peaks/modulations/multistage_envelope.cc +++ b/lib/peaks/modulations/multistage_envelope.cc @@ -78,8 +78,12 @@ void MultistageEnvelope::Process( int32_t a = start_value_; int32_t b = level_[segment_ + 1]; - uint16_t t = Interpolate824( - lookup_table_table[LUT_ENV_LINEAR + shape_[segment_]], phase_); + + //eh2k >>> + const uint16_t * lutt[] = { lut_env_linear, lut_env_expo, lut_env_quartic }; + //<<< + + uint16_t t = Interpolate824(lutt[shape_[segment_]], phase_); value_ = a + ((b - a) * (t >> 1) >> 15); phase_ += phase_increment_; *out++ = value_; diff --git a/lib/plaits/dsp/chords/chord_bank.cc b/lib/plaits/dsp/chords/chord_bank.cc index 96f1efe..53628b4 100644 --- a/lib/plaits/dsp/chords/chord_bank.cc +++ b/lib/plaits/dsp/chords/chord_bank.cc @@ -41,7 +41,7 @@ using namespace stmlib; #ifdef JON_CHORDS //[eh2k] -const char* const chord_names[kChordNumChords] FLASHMEM = { +const char* const chord_names[kChordNumChords] = { "OCT", "Fifth", "m", @@ -63,7 +63,7 @@ const char* const chord_names[kChordNumChords] FLASHMEM = { // Alternative chord table by Jon Butler jonbutler88@gmail.com /* static */ -const float ChordBank::chords_[kChordNumChords][kChordNumNotes] FLASHMEM = { +const float ChordBank::chords_[kChordNumChords][kChordNumNotes] = { // Fixed Intervals { 0.00f, 0.01f, 11.99f, 12.00f }, // Octave { 0.00f, 7.00f, 7.01f, 12.00f }, // Fifth diff --git a/lib/rings/resources.cc b/lib/rings/resources.cc index 193445f..47e9fbb 100644 --- a/lib/rings/resources.cc +++ b/lib/rings/resources.cc @@ -38,16 +38,6 @@ namespace rings { - - -const int16_t* lookup_table_int16_table[] = { -}; - - - -const uint32_t* lookup_table_uint32_table[] = { -}; - const float FLASHMEM lut_sine[] = { 0.000000000e+00, 1.533980186e-03, 3.067956763e-03, 4.601926120e-03, 6.135884649e-03, 7.669828740e-03, 9.203754782e-03, 1.073765917e-02, diff --git a/lib/stmlib/dsp/units.h b/lib/stmlib/dsp/units.h index 41ddbaf..bd3f28d 100644 --- a/lib/stmlib/dsp/units.h +++ b/lib/stmlib/dsp/units.h @@ -34,6 +34,50 @@ namespace stmlib { +// https://pichenettes.github.io/mutable-instruments-documentation/tech_notes/exponential_conversion_in_digital_oscillators/ + +// Computes 2^x by using a polynomial approximation of 2^frac(x) and directly +// incrementing the exponent of the IEEE 754 representation of the result +// by int(x). Depending on the use case, the order of the polynomial +// approximation can be chosen. +template +inline float Pow2Fast(float x) { + union { + float f; + int32_t w; + } r; + + + if (order == 1) { + r.w = float(1 << 23) * (127.0f + x); + return r.f; + } + + int32_t x_integral = static_cast(x); + if (x < 0.0f) { + --x_integral; + } + x -= static_cast(x_integral); + + if (order == 1) { + r.f = 1.0f + x; + } else if (order == 2) { + r.f = 1.0f + x * (0.6565f + x * 0.3435f); + } else if (order == 3) { + r.f = 1.0f + x * (0.6958f + x * (0.2251f + x * 0.0791f)); + } + r.w += x_integral << 23; + return r.f; +} + +#ifdef SemitonesToRatioFast + +inline float SemitonesToRatio(float semitones){ + return Pow2Fast<1>(semitones / 12.f); +} + +#else + extern const float lut_pitch_ratio_high[257]; extern const float lut_pitch_ratio_low[257]; @@ -45,6 +89,8 @@ inline float SemitonesToRatio(float semitones) { lut_pitch_ratio_low[static_cast(pitch_fractional * 256.0f)]; } +#endif + inline float SemitonesToRatioSafe(float semitones) { float scale = 1.0f; while (semitones > 120.0f) { diff --git a/lib/udynlink b/lib/udynlink index 7ad890c..7337f22 160000 --- a/lib/udynlink +++ b/lib/udynlink @@ -1 +1 @@ -Subproject commit 7ad890c70ba8ac0a9500c9b6c1aaec5380ff717a +Subproject commit 7337f22fd7995540b102cbe44fe6b4ffccd58200 diff --git a/platformio.ini b/platformio.ini index abd09b5..947bbd2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,7 +10,6 @@ [env:squares-and-circles] apps_json = ./app/index.json extra_scripts = build.py -squares_and_circles_loader = a751cf7 ; minimum loader version -platform = teensy@5.0.0 ; https://github.com/platformio/platform-teensy/releases -board = teensy41 ; fake setting - the engines are compatibe with all targets - +squares_and_circles_loader = 2cd9d0a ; minimum loader version +platform = teensy@5.0.0 ; https://github.com/platformio/platform-teensy/releases +board = teensy41 ; fake setting - the engines are compatibe with all targets diff --git a/test/test_midi.sh b/test/test_midi.sh index ba38544..eb9132c 100644 --- a/test/test_midi.sh +++ b/test/test_midi.sh @@ -6,15 +6,20 @@ amidi -p $int -S "F34D" # set CH 1,2,3,4 RANDOM=1 I=0 -N=44 +N=52 while true; do for i in $(seq 0 100); do - C=$(($RANDOM % 4)) - PROG=$((1 + $RANDOM % $N)) + PROG1=$((1 + $RANDOM % $N)) + PROG2=$((1 + $RANDOM % $N)) + PROG3=$((1 + $RANDOM % $N)) + PROG4=$((1 + $RANDOM % $N)) #if [[ $PROG == "x35" || $PROG == "33" || $PROG == "39" || $PROG == "40" || $PROG == "x41" ]]; then continue; fi - echo "$I: $C -> $PROG" - amidi -p $int -S "$(printf "C%x%02x" $C $PROG)" + echo "$I: $C -> $PROG1, $PROG2, $PROG3, $PROG4" + amidi -p $int -S "$(printf "C%x%02x" 0 $PROG1)" + amidi -p $int -S "$(printf "C%x%02x" 1 $PROG2)" + amidi -p $int -S "$(printf "C%x%02x" 2 $PROG3)" + amidi -p $int -S "$(printf "C%x%02x" 3 $PROG4)" I=$(($I + 1)) #sleep 0.001