From fc2389f75c207fc9a8c785deb3ac5658740098ef Mon Sep 17 00:00:00 2001 From: eh2k Date: Sat, 30 Mar 2024 13:13:47 +0100 Subject: [PATCH] devsync 66b6aea --- .github/workflows/LICENSE.txt | 13 +- .github/workflows/build.yml | 43 +- .gitignore | 3 +- .pre_build.py | 17 - README.md | 112 +- app/DRUMS/Djembe.bin | Bin 0 -> 6628 bytes app/DRUMS/Djembe.bin.h | 545 ---- app/DRUMS/TR707-HiHat.bin | Bin 0 -> 1528 bytes app/DRUMS/TR707-HiHat.cpp | 33 + app/DRUMS/TR707.bin | Bin 0 -> 2272 bytes app/DRUMS/TR707.cpp | 65 + app/DRUMS/TR909-HiHat.bin | Bin 0 -> 1528 bytes app/DRUMS/TR909-HiHat.cpp | 31 + app/DRUMS/TR909-Ride.bin | Bin 0 -> 1520 bytes app/DRUMS/TR909-Ride.cpp | 32 + app/FX/Delay.bin | Bin 0 -> 3224 bytes app/FX/Delay.bin.h | 261 -- app/FX/Delay.cpp | 7 +- app/FX/Gated-Reverb.bin | Bin 0 -> 5704 bytes app/FX/Gated-Reverb.bin.h | 468 ---- app/FX/JU60_chorus.bin | Bin 0 -> 8024 bytes .../FX/JU60_chorus.cpp | 227 +- app/FX/Rev-Dattorro.bin | Bin 0 -> 4076 bytes app/FX/Rev-Dattorro.bin.h | 332 --- app/FX/Reverb-HP-LP.bin | Bin 0 -> 5272 bytes app/FX/Reverb-HP-LP.bin.h | 432 --- app/FX/Reverb.bin | Bin 0 -> 2768 bytes app/FX/Reverb.cpp | 75 + app/FX/ReverbSC.bin | Bin 0 -> 3224 bytes app/FX/ReverbSC.cpp | 67 + app/GND/FFT.bin | Bin 0 -> 12688 bytes app/GND/FFT.cpp | 191 ++ app/GND/Scope.bin | Bin 0 -> 1808 bytes app/GND/Scope.cpp | 85 + app/MIDI/Clock.bin | Bin 0 -> 2020 bytes app/MIDI/Clock.cpp | 92 + app/MIDI/Monitor.bin | Bin 0 -> 2392 bytes app/MIDI/Monitor.cpp | 87 + app/MIDI/VAx6.bin | Bin 0 -> 17492 bytes app/MIDI/VAx6.cpp | 202 ++ app/NOISE/808_squares.bin | Bin 0 -> 2268 bytes app/NOISE/808_squares.bin.h | 181 -- app/NOISE/NES.bin | Bin 0 -> 2236 bytes app/NOISE/NES.bin.h | 179 -- app/NOISE/WhitePink.bin | Bin 0 -> 2060 bytes app/NOISE/WhitePink.bin.h | 164 -- app/SPEECH/LPC.bin | Bin 0 -> 21444 bytes app/SPEECH/LPC.cpp | 268 ++ app/SPEECH/SAM.bin | Bin 0 -> 27792 bytes app/SPEECH/SAM.bin.h | 2308 ----------------- app/SYNTH/Open303.bin | Bin 0 -> 37144 bytes app/SYNTH/Open303.cpp | 202 ++ app/SYNTH/Resonator.bin | Bin 0 -> 57872 bytes app/SYNTH/Resonator.cpp | 70 + app/build.sh | 3 +- app/index.json | 38 + app/squares-and-circles-api.h | 89 +- boards/dsm0.json | 26 - boards/imxrt1062.ld | 114 - doc/.conv.sh | 6 + doc/adc_calib.bmp | Bin 1056 -> 0 bytes doc/adc_calib.png | Bin 0 -> 736 bytes doc/blank.bmp | Bin 24630 -> 0 bytes doc/blank.png | Bin 0 -> 500 bytes doc/config_midi.bmp | Bin 1056 -> 0 bytes doc/config_midi0.png | Bin 0 -> 557 bytes doc/config_midi1.png | Bin 0 -> 2892 bytes doc/cv_envgenad.png | Bin 0 -> 633 bytes doc/cv_lfo.png | Bin 0 -> 609 bytes doc/cv_voltage.png | Bin 2647 -> 707 bytes doc/dac_calib.bmp | Bin 1056 -> 0 bytes doc/dac_calib.png | Bin 0 -> 621 bytes doc/display_setup.bmp | Bin 1056 -> 0 bytes doc/display_setup.png | Bin 0 -> 588 bytes doc/drums_707.png | Bin 0 -> 706 bytes doc/drums_909.png | Bin 0 -> 657 bytes doc/drums_claps.png | Bin 0 -> 654 bytes doc/drums_djembe.png | Bin 0 -> 650 bytes doc/encoder_setup.bmp | Bin 1056 -> 0 bytes doc/encoder_setup.png | Bin 0 -> 616 bytes doc/engine.bmp | Bin 1056 -> 0 bytes doc/engines.png | Bin 0 -> 13442 bytes doc/fx_delay.png | Bin 0 -> 645 bytes doc/fx_ju60chorus.png | Bin 0 -> 539 bytes doc/fx_rev_dattorro.png | Bin 2984 -> 720 bytes doc/gnd_fft.png | Bin 0 -> 515 bytes doc/gnd_scope.png | Bin 0 -> 722 bytes doc/inputs.png | Bin 3334 -> 840 bytes doc/inputs2.png | Bin 3115 -> 736 bytes doc/io_test.bmp | Bin 1056 -> 0 bytes doc/io_test.png | Bin 0 -> 625 bytes doc/menu.bmp | Bin 1056 -> 0 bytes doc/menu.png | Bin 0 -> 587 bytes doc/menu_engines.png | Bin 0 -> 852 bytes doc/midi_clock.png | Bin 0 -> 2956 bytes doc/midi_monitor.png | Bin 2482 -> 624 bytes doc/mod_cv.png | Bin 3498 -> 837 bytes doc/mod_ef.png | Bin 0 -> 3433 bytes doc/mod_env.bmp | Bin 1056 -> 0 bytes doc/mod_env.png | Bin 0 -> 3518 bytes doc/mod_lfo.png | Bin 0 -> 3582 bytes doc/mod_rnd.png | Bin 0 -> 3468 bytes doc/mod_tm.png | Bin 0 -> 3599 bytes doc/mosc_va.png | Bin 0 -> 805 bytes doc/mosc_waveforms.png | Bin 0 -> 3023 bytes doc/noise_808squares.png | Bin 0 -> 2406 bytes doc/noise_nes.png | Bin 1149 -> 921 bytes doc/noise_whitepink.png | Bin 0 -> 543 bytes doc/osc.bmp | Bin 1056 -> 0 bytes doc/outputs.png | Bin 2928 -> 783 bytes doc/outputs2.png | Bin 3005 -> 792 bytes doc/splash.bmp | Bin 1056 -> 0 bytes doc/splash.png | Bin 0 -> 14914 bytes doc/synth_classic_vavcf.png | Bin 0 -> 776 bytes doc/synth_dxfm.png | Bin 0 -> 2793 bytes doc/synth_open303.png | Bin 3023 -> 741 bytes doc/synth_resonator.png | Bin 0 -> 776 bytes lib/braids/resources.cc | 2 +- lib/fv1/factory.json | 16 +- platformio.ini | 58 +- src/SAM.cxx | 115 - src/base/FaustEngine.hxx | 156 -- src/base/HiHatsEngine.hxx | 105 - src/base/SampleEngine.hxx | 224 -- src/braids.cxx | 165 -- src/build.py | 150 ++ src/claps.cxx | 279 -- src/cv_peaks.cxx | 100 - src/dxfm.cxx | 385 --- src/fx_reverb.cxx | 132 - src/fx_reverbSC.cxx | 102 - src/main.cxx | 94 - src/midiClock.cxx | 123 - src/midiMonitor.cxx | 89 - src/modulations.cxx | 320 --- src/open303.cxx | 211 -- src/peaks.cxx | 138 - src/plaits.cxx | 373 --- src/polyVA.cxx | 132 - src/quantizer.cxx | 16 - src/rings.cxx | 103 - src/speech.cxx | 111 - src/tr707.cxx | 74 - src/tr909.cxx | 87 - src/voltage.cxx | 253 -- 145 files changed, 2002 insertions(+), 9179 deletions(-) delete mode 100644 .pre_build.py create mode 100644 app/DRUMS/Djembe.bin delete mode 100644 app/DRUMS/Djembe.bin.h create mode 100644 app/DRUMS/TR707-HiHat.bin create mode 100644 app/DRUMS/TR707-HiHat.cpp create mode 100644 app/DRUMS/TR707.bin create mode 100644 app/DRUMS/TR707.cpp create mode 100644 app/DRUMS/TR909-HiHat.bin create mode 100644 app/DRUMS/TR909-HiHat.cpp create mode 100644 app/DRUMS/TR909-Ride.bin create mode 100644 app/DRUMS/TR909-Ride.cpp create mode 100644 app/FX/Delay.bin delete mode 100644 app/FX/Delay.bin.h create mode 100644 app/FX/Gated-Reverb.bin delete mode 100644 app/FX/Gated-Reverb.bin.h create mode 100644 app/FX/JU60_chorus.bin rename src/fx_juno60_chorus.cxx => app/FX/JU60_chorus.cpp (59%) create mode 100644 app/FX/Rev-Dattorro.bin delete mode 100644 app/FX/Rev-Dattorro.bin.h create mode 100644 app/FX/Reverb-HP-LP.bin delete mode 100644 app/FX/Reverb-HP-LP.bin.h create mode 100644 app/FX/Reverb.bin create mode 100644 app/FX/Reverb.cpp create mode 100644 app/FX/ReverbSC.bin create mode 100644 app/FX/ReverbSC.cpp create mode 100644 app/GND/FFT.bin create mode 100644 app/GND/FFT.cpp create mode 100644 app/GND/Scope.bin create mode 100644 app/GND/Scope.cpp create mode 100644 app/MIDI/Clock.bin create mode 100644 app/MIDI/Clock.cpp create mode 100644 app/MIDI/Monitor.bin create mode 100644 app/MIDI/Monitor.cpp create mode 100644 app/MIDI/VAx6.bin create mode 100644 app/MIDI/VAx6.cpp create mode 100644 app/NOISE/808_squares.bin delete mode 100644 app/NOISE/808_squares.bin.h create mode 100644 app/NOISE/NES.bin delete mode 100644 app/NOISE/NES.bin.h create mode 100644 app/NOISE/WhitePink.bin delete mode 100644 app/NOISE/WhitePink.bin.h create mode 100644 app/SPEECH/LPC.bin create mode 100644 app/SPEECH/LPC.cpp create mode 100644 app/SPEECH/SAM.bin delete mode 100644 app/SPEECH/SAM.bin.h create mode 100644 app/SYNTH/Open303.bin create mode 100644 app/SYNTH/Open303.cpp create mode 100644 app/SYNTH/Resonator.bin create mode 100644 app/SYNTH/Resonator.cpp create mode 100644 app/index.json delete mode 100644 boards/dsm0.json delete mode 100644 boards/imxrt1062.ld create mode 100644 doc/.conv.sh delete mode 100644 doc/adc_calib.bmp create mode 100644 doc/adc_calib.png delete mode 100644 doc/blank.bmp create mode 100644 doc/blank.png delete mode 100644 doc/config_midi.bmp create mode 100644 doc/config_midi0.png create mode 100644 doc/config_midi1.png create mode 100644 doc/cv_envgenad.png create mode 100644 doc/cv_lfo.png delete mode 100644 doc/dac_calib.bmp create mode 100644 doc/dac_calib.png delete mode 100644 doc/display_setup.bmp create mode 100644 doc/display_setup.png create mode 100644 doc/drums_707.png create mode 100644 doc/drums_909.png create mode 100644 doc/drums_claps.png create mode 100644 doc/drums_djembe.png delete mode 100644 doc/encoder_setup.bmp create mode 100644 doc/encoder_setup.png delete mode 100644 doc/engine.bmp create mode 100644 doc/engines.png create mode 100644 doc/fx_delay.png create mode 100644 doc/fx_ju60chorus.png create mode 100644 doc/gnd_fft.png create mode 100644 doc/gnd_scope.png delete mode 100644 doc/io_test.bmp create mode 100644 doc/io_test.png delete mode 100644 doc/menu.bmp create mode 100644 doc/menu.png create mode 100644 doc/menu_engines.png create mode 100644 doc/midi_clock.png create mode 100644 doc/mod_ef.png delete mode 100644 doc/mod_env.bmp create mode 100644 doc/mod_env.png create mode 100644 doc/mod_lfo.png create mode 100644 doc/mod_rnd.png create mode 100644 doc/mod_tm.png create mode 100644 doc/mosc_va.png create mode 100644 doc/mosc_waveforms.png create mode 100644 doc/noise_808squares.png create mode 100644 doc/noise_whitepink.png delete mode 100644 doc/osc.bmp delete mode 100644 doc/splash.bmp create mode 100644 doc/splash.png create mode 100644 doc/synth_classic_vavcf.png create mode 100644 doc/synth_dxfm.png create mode 100644 doc/synth_resonator.png delete mode 100644 src/SAM.cxx delete mode 100644 src/base/FaustEngine.hxx delete mode 100644 src/base/HiHatsEngine.hxx delete mode 100644 src/base/SampleEngine.hxx delete mode 100644 src/braids.cxx create mode 100644 src/build.py delete mode 100644 src/claps.cxx delete mode 100644 src/cv_peaks.cxx delete mode 100644 src/dxfm.cxx delete mode 100644 src/fx_reverb.cxx delete mode 100644 src/fx_reverbSC.cxx delete mode 100644 src/midiClock.cxx delete mode 100644 src/midiMonitor.cxx delete mode 100644 src/modulations.cxx delete mode 100644 src/open303.cxx delete mode 100644 src/peaks.cxx delete mode 100644 src/plaits.cxx delete mode 100644 src/polyVA.cxx delete mode 100644 src/quantizer.cxx delete mode 100644 src/rings.cxx delete mode 100644 src/speech.cxx delete mode 100644 src/tr707.cxx delete mode 100644 src/tr909.cxx delete mode 100644 src/voltage.cxx diff --git a/.github/workflows/LICENSE.txt b/.github/workflows/LICENSE.txt index e8059f3..443dc52 100644 --- a/.github/workflows/LICENSE.txt +++ b/.github/workflows/LICENSE.txt @@ -1,5 +1,9 @@ -# End User License Agreement for squares-and-circles firmware +-------- Copyright -------- + +Copyright 2021 E.Heidt +https://github.com/eh2k/squares-and-circles +# End User License Agreement for squares-and-circles firmware ___ ## 1. USE @@ -7,20 +11,17 @@ ___ This software is licensed, not sold. The purchase of this software by a user grants the user one license for the software. -A license grants use on all operating systems on all computers owned by the user, provided the primary user is the license holder. - -Businesses and organizations must purchase a license for each user of the software. +A license grants use on all devices owned by the user, provided the primary user is the license holder. You must not remove or alter any copyright notices on any copy of this software. - You must not disassemble, decompile, or reverse engineer the software, in whole or in part. ## 2. DISTRIBUTION You must not distribute or sell licenses of this software to third parties. +You must not distribute or sell devices with this software to third parties. Licenses are revoked if distributed or sold to third parties. - ## 3. WARRANTIES THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b854bf5..10535ad 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: PlatformIO CI +name: Build on: [push] @@ -16,35 +16,32 @@ jobs: git push secondary --all --force - name: Set up Python uses: actions/setup-python@v2 - - name: Install PlatformIO - run: | - python -m pip install --upgrade pip - pip install --upgrade platformio - - name: build_SC_DSM0 + - name: build run: | set -x - git submodule update --init - pio pkg install --environment SC_DSM0 - pio run -v --environment SC_DSM0 - pio run -v --environment SC_DSM0 -t upload || true - hex=$(echo .pio/build/*/*.hex) - rm -f $hex; - mv .pio/build/*/*.eh2k $hex; - - name: build_OC_T40 - run: | - git submodule update --init - pio run --environment OC_T40 + python -m pip install --upgrade pip + curl -fLO https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v10.3.1-2.1/xpack-arm-none-eabi-gcc-10.3.1-2.1-linux-x64.tar.gz + cat xpack-arm-none-eabi-gcc-10.3.1-2.1-linux-x64.tar.gz | tar xvz -C . > /dev/null + 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 + 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) - mv .github/workflows/LICENSE.txt ./LICENSE.txt for f in .pio/build/*/*.hex; do FIRMWARE=$(basename $(dirname ${f%.*})) - HEX_FILE=./firmware_${FIRMWARE}_$hash.hex - ZIP_FILE=./firmware_${FIRMWARE}_$hash.zip + HEX_FILE=./${FIRMWARE}_engines_$hash.hex + ZIP_FILE=./${FIRMWARE}_engines_$hash.zip mv -v "$f" $HEX_FILE - zip -j $ZIP_FILE $HEX_FILE ./LICENSE.txt + 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}_latest.zip --upload-file $ZIP_FILE || true - curl -fs -X PUT -u ${{ secrets.UPLOAD_KEY }} ${{ secrets.LATEST_DROP_FOLDER }}/${FIRMWARE}_latest.sha -d "$hash" + 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" done \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8f790fd..529942d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ *.elf *.log *.txt -*.bin +*.bin.h +src/__pycache__/app_hex.cpython-310.pyc diff --git a/.pre_build.py b/.pre_build.py deleted file mode 100644 index 99ce6b7..0000000 --- a/.pre_build.py +++ /dev/null @@ -1,17 +0,0 @@ -import subprocess -from SCons.Script import DefaultEnvironment - -env = DefaultEnvironment() - -commit_sha = subprocess.run('git rev-parse --short HEAD', shell=True, capture_output=True).stdout.strip().upper().decode("utf-8") - -if subprocess.run('git diff-index --name-status --exit-code HEAD', shell=True).returncode != 0: - commit_sha = commit_sha[:6] + "~" - -print("GIT_COMMIT_SHA:", commit_sha) - -env.Append(CPPDEFINES=[ - ("GIT_COMMIT_SHA", env.StringifyMacro(commit_sha)), -]) - - diff --git a/README.md b/README.md index 11ce3e9..691378a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -> WORK-IN-PROGRESS: Feel free to leave me a message / feedback or any hints in the ["General Feedback"](https://github.com/eh2k/squares-and-circles/issues/1) issue. +> Feedback welcome: Feel free to leave me a message or any hints in the ["General Feedback"](https://github.com/eh2k/squares-and-circles/issues/1) issue. -# □︎●︎ [![CI](https://github.com/eh2k/squares-and-circles/actions/workflows/build.yml/badge.svg)](https://github.com/eh2k/squares-and-circles/actions/workflows/build.yml) [![WebFlasher](https://img.shields.io/badge/Firmware-WebFlasher-blue)](https://eh2k.github.io/□●/flash/?firmware) [![MODULAGrid](https://img.shields.io/badge/MODULAR-Grid-white)](https://www.modulargrid.net/e/modules/browser?SearchName=squares+and+circles&SearchShowothers=1) +# □︎●︎ [![WebFlasher](https://img.shields.io/badge/Web-Flasher-blue)](https://eh2k.github.io/□●/flash/?firmware) [![MODULAGrid](https://img.shields.io/badge/MODULAR-Grid-white)](https://www.modulargrid.net/e/modules/browser?SearchName=squares+and+circles&SearchShowothers=1) **squares-and-circles** is an alternate firmware for the Eurorack module O_C, targeting Teensy 4.0. @@ -9,6 +9,14 @@ ChangeLog ```` +== 2024-03-28 + * Enhancement: Turing Machine Modulation + * Enhancement: FV1emu (cleanup + 16bit delay optimization) + * Bugfix: Crash on Midi-CC + * Refactoring MIDI-Settings / Clock-Settings + * Enhancement: Midi-Channel moved to IO-Settings + * ***New Analysis Engines: GND/Scope, GND/FFT + * OC_T41 Support == 2024-02-14 * Enhancement/Bugfix: No usb midi response while 5sec startup #66 == 2024-02-12 @@ -128,55 +136,63 @@ E.g you can chain the mono audio signal from an oscillator machine to the neighb # Machines [wiki](https://github.com/eh2k/squares-and-circles/wiki/%E2%96%A1%EF%B8%8E%E2%97%8F%EF%B8%8E-Machines-&-Engines) - + >[Long press [LEFT]] enters the machine-selection-page.
->[Short press [R-ENCODER]] loads the selected engine.
+>[Short press [R-ENCODER]] loads the selected engine.
>[Long press [R-ENCODER]] loads the selected engine (default IO-settings).
-* **GND** +--- +###### Screenshots + + +--- + +## Engines +* **GND** * `---` + * Scope + * FFT * **CV** - * [V/OCT](https://github.com/eh2k/squares-and-circles/wiki/V_OCT) - + * [V/OCT](https://github.com/eh2k/squares-and-circles/wiki/V_OCT) * EnvGen_AD * EnvGen_ADSR * LFO * 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) + * 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 * [FM-Drum](https://github.com/eh2k/squares-and-circles/wiki/FM-Drum) * Djembe * [Claps](https://github.com/eh2k/squares-and-circles/wiki/Claps) -* **M-OSC** +* **M-OSC** * [Waveforms](https://github.com/eh2k/squares-and-circles/wiki/Waveforms) * Virt.Analog, Waveshaping, FM, Grain, Additive, Wavetable, Chord - * Resonator * **SYNTH** + * 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) + * [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 + * Rev-Dattorro * Delay * Gated-Reverb * 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) + * [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 * [SAM](https://github.com/eh2k/squares-and-circles/wiki/SAM) * **MIDI** - * Monitor + * Monitor * Clock * VAx6 @@ -206,23 +222,29 @@ For each parameter a modulation can be assigned: * Parameter 0 (top-left) is mainly used for V/OCT control. Thus, one single V/OCT signal / CV-Input can be shared by using modulation on parameter-0 with attenuverter = +1 (-3V..+6V) range. It is also possible to select the V/OCT input in the io-configuration page. * All other parameters can be modulated via CV-input with a assumed voltage-range of -4V..4V at 2kHz sample rate. * Be aware the CV-range is probably limited by hardware to: -3.5v..6.5V - * **RND**: Trigger generates a random voltage + * **RND**: Trigger generates a random voltage * TRIG: `!`, `T1`, `T2`, `T3`, `T4`, `C1`, `C2`, `C3`, `C4` - * **ENV**: Triggered Envelope (Attack, Decay) +
+
+ * **ENV**: Triggered Envelope (Attack, Decay) * TRIG: `!`, `T1`, `T2`, `T3`, `T4`, `C1`, `C2`, `C3`, `C4` * ATTACK * DECAY - * **LFO**: Free/Triggered Sine-LFO + * **LFO**: Free/Triggered Sine-LFO * TRIG: `-`, `!`, `T1`, `T2`, `T3`, `T4`, `C1`, `C2`, `C3`, `C4` * SHAPE * FREQUENCY - * **EF**: Envelope Follower + * **EF**: Envelope Follower * SRC: `C1`, `C2`, `C3`, `C4` * ATTACK * RELEASE - >`!` = current engine trigger - + * **TM**: Turing Machine + * TRIG: `!`, `CLK`, `T1`, `T2`, `T3`, `T4` + * PROB: `0-9` (0-100%) + * STEPS: `1-16` + >`!` = current engine trigger
+ >`CLK` = internal clock
All modulations have an attenuverter parameter (-/+). * The modulation-voltage is attenuverted/multiplied by -1..+1; @@ -251,7 +273,7 @@ The I/O-Configuration page lets you virtually patch the engine with the hardware * **Quantizer**: [Off, Semitones, Ionian, Dorian, ...](lib/braids/quantizer_scales.h) * **Transpose**: -48 to 24 (default -24) -*In case the Engine supports Accents (Closed/Open HighHat) - Accent Input is configurable:* +*In case the Engine supports Accents (Closed/Open HiHat) - Accent Input is configurable:* * **Accent-Input**: * `-` @@ -286,19 +308,33 @@ The I/O-Configuration page lets you virtually patch the engine with the hardware
-## MIDI-Settings +## MIDI/CLOCK-Settings >[Long press [LEFT] + [RIGHT]] for getting to the MIDI-Settings page. + +The MIDI&Clock-Settings page lets you select the MIDI-Control. + + + +- **MIDI-Control**: + - `-` disabled + - In case OC_T40 + - `USB+T1` [T1 input can be used as MIDI-Input](#-midi-expander) + - else + - `MIDI/USB` the USB-MIDI and/or hardware Midi-Input -The MIDI-Settings page lets you select the MIDI-Input. MIDI via USB is active by default - alternatively the [T1 input can be used as MIDI-Input](#-midi-expander). Each engine can be assigned to a MIDI-Channel - it is possible to control single mono engines together polyphonically (for this all engines have to be set to the same midi channel). [Midi-Engines](src/polyVA.cxx) consume the MIDI-Stream directly, therefore the MIDI-Messages are not converted as incoming CVs or triggers. +In case the MIDI-Control is enabled, you can setup the Midi-Channel in the engine IO-settings. +> Each engine can be assigned to a MIDI-Channel - it is possible to control single mono engines together polyphonically (for this all engines have to be set to the same midi channel). [Midi-Engines](app/MIDI/VAx6.cpp) consume the MIDI-Stream directly, therefore the MIDI-Messages are not converted as incoming CVs or triggers. - + - * **MIDI-CLK/INT-CLK**: BPM - * *In case clock is send via MIDI the internal clock is feed by midi, else the internal clock is active and can be set* - * **MIDI-Input**: USB, T1 - * *In case T1 is set - T1 is working in Midi-Mode (Serial) - Triggering is not available on T1* - * **MIDI_CH #**: 1-16, single channel on multiple engines, for polyphony + * **CLOCK-Source**: BPM + * `-` none + * `INT` Internal Clock-Source (BPM) + * `T1` T1 as Clock-Input (4ppqn) + * `MIDI` Clock received from MIDI + +> Clock-Source is used by engines like `FX/Delay` (clocked sync) or `MIDI/Clock` #### Midi-Control * Engines can be loaded/selected by midi program change @@ -317,23 +353,24 @@ The MIDI-Settings page lets you select the MIDI-Input. MIDI via USB is active by ```` # Supported Hardware - * [Ornament-and-Crime](https://github.com/eh2k/squares-and-circles/wiki/Ornament%E2%80%90and%E2%80%90Crime) + * [Ornament-and-Crime T4.0](https://github.com/eh2k/squares-and-circles/wiki/Ornament%E2%80%90and%E2%80%90Crime) * [Squares-and-Circles DSM0](https://github.com/eh2k/squares-and-circles/wiki/Squares&Circles-D_SM-Prototype) + * [O_C T4.1](https://github.com/eh2k/squares-and-circles/wiki/OC_T41) ## Hardware setup procedure - > Use [![WebFlasher](https://img.shields.io/badge/Firmware-WebFlasher-blue)](https://eh2k.github.io/□●/flash/?firmware) to enter callibration mode, or execute advanced setup commands
+ > Use [![WebFlasher](https://img.shields.io/badge/Web-Flasher-blue)](https://eh2k.github.io/□●/flash/?firmware) to enter callibration mode, or execute advanced setup commands
>Power on the module with the [LEFT] button pressed for entering the setup procedure. ### Display setup - + * Press left encoder to flip180. * Press right encoder for changing display brightness (50%, maximal). ### Encoder setup - + * Check the encoder rotation direction. * Press encoder for reversed setup. @@ -343,7 +380,7 @@ The MIDI-Settings page lets you select the MIDI-Input. MIDI via USB is active by ### DAC calibration - + To calibrate the DAC, you need a multimeter. Besides the reference voltage of `0V`, the voltages `-2V` and `+2V` should be calibrated as accurately as possible. Start with DAC1 (channel A) - connect the multimeter typically using alligator clip on a patch cable inserted in the jack. Use the right encoder to set the voltage as accurately as possible (press the encoder for coarse adjustment). Do it on all outputs - use the left encoder for channel selection. After calibrating `0V` on all outputs, press [right] to step to the `-2V` calibration. Repeat the procedure and press [right] to calibrating `+2V`. @@ -351,13 +388,13 @@ Start with DAC1 (channel A) - connect the multimeter typically using alligator c ### ADC calibration - + To calibrate the ADC `0V` reference, remove all patch cables from the module. Use the right encoder to adjust the offset (press the encoder for fast adjustment). Do it on all cv-inputs, select the channel with the left encoder. Press [right] to enter the `-2V` calibration. Now you need to connect the DAC outputs to the cv-inputs. The DAC output produces the reference voltage, that is calibrated on the input. Repeat the calibration procedure and step to the `+2V` calibration. ### I/O Test: - + * Test/Verify your TRIG or CV inputs. * The output voltage is set by the cv input voltage (DACx = ADCx). @@ -375,7 +412,7 @@ Regarding the user interface and the concept of firmware, I am a bit torn. On th The application code respectively the suite of machines/engines and the third-party source files are published under permissive software licenses. For the exact license and copyright holder - see the header of individual source code files or readme/license file in the sub folder. -The firmware as a whole and the hardware abstraction layer "libmachine" is for personal non-commercial use only. +The firmware as a whole is for personal use only. If you are considering commercial distributing hardware with this firmware, please contact me (eh2k◯gmx.de). - diff --git a/app/DRUMS/Djembe.bin b/app/DRUMS/Djembe.bin new file mode 100644 index 0000000000000000000000000000000000000000..97a345c706ca32916ad3262e46b01985b673f313 GIT binary patch literal 6628 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 literal 0 HcmV?d00001 diff --git a/app/DRUMS/TR707-HiHat.cpp b/app/DRUMS/TR707-HiHat.cpp new file mode 100644 index 0000000..96f6bc2 --- /dev/null +++ b/app/DRUMS/TR707-HiHat.cpp @@ -0,0 +1,33 @@ +#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 new file mode 100644 index 0000000000000000000000000000000000000000..365f7d10ee0e48f8b9bbd7a3a6ef526ce92fc039 GIT binary patch literal 2272 zcmaJ??@wD*7=CYCOD!-jlPL~xh0EA4iQT}hQ!~2K^|BVUQb;7u+}?06X_FRi`eV+- zB@Ir)mqj$1%nyquE~X#11k?{U><`dnOZ==RevpM=hLNoMp!0d#Q^4Xl$-J=0u2IBf?a?cVBIKmlhDmz)_VZfPYEpx-2!I4 z7hwIg(5*u61G9bxVEwGnZ9;c|S$6`@0nY>bfdfE0-~rgv4X}qBdnAB8cEAH*i_`@? z0kD_%r~tgT9)M#X1UPmtz_AYj{LEqC3~&TE3XDtS1yNk0=w$>>gO7mcz|G*#z&iLk z_#BuU=a(D5j~nNV8|Q`_=YSjUl^gGgo2T+yT_a0g3%3`lR9y)4faurACxl<{u;3{8 zD~aS3_*=n0f_Z&Ei#}V&`3EfytV`8plm-7S*k!AZ?-SfD_?Y0+f>pt<3DyN8wEuJD zCpb1S8hdek?3DKuXKbbkay_=0$TRrzP|mBV}eVn6DqQGP6@=HcMGE zm$zWBGUiqk&73iIjAe6rCWp}-wrvAdPg+l?&M6|9ir*`l0j6&8$9ImZFjp`m?zA^}h;l_(Mh2GJ2CAM5L3wI(zu3 ztS%|8RXf#ORnO%*56?;pM{#XXwCc&%d3a{)ZIZX@O4qrzA~kH>_E$Y-orh<3M!Hbv z+8(JOB8}I18a4|56KSN*#gRztt`;d+=W$_8w3*AIsw6E#>UXTZ?^N`cD<_-Px8nGa z>+Oyc!qI>n{WnTq_=~kpw`Cj(N&RYB9z4qD8OO=c;mFlByBjL{;16;iN5q2>$9k)c z=adM2aymra&{m`Jol1(LABbG9`pL1LllYmU+P*nfiP3p1qY>sbzH~zj=l--y}ba$SueGOTX+{9tj^n-psskg zCv;714)5Vnnb+@5HboZJX#brx$^9|*&rWG|&ej!*rb;WapVwy~Rs!Jfgx|+?)moCn zaxFvAi|yaY&O6jIQFgo{4O~;d4m`Z;4!d`qw@Mb`h(hALC%CmE>W0$#;yUgVtJwE2An{%iqVXi1PLPqeNIl~Ry^M6^n5k>XaxUW>e z!ma?Emw5nfkf<;i2zn_HJWeri3_OISjgJOsY?NpyfOErvjRM1rVdONKn@Zr}GqFk~ crC6nK6P-g*$Nz + +// #include "eproms/tr707/IC34_TR707_SNDROM.h" +// #include "eproms/tr707/IC35_TR707_SNDROM.h" +static auto IC34_TR707_SNDROM_bin = machine::fs_read("707_IC34"); +static auto IC35_TR707_SNDROM_bin = machine::fs_read("707_IC35"); + +static float _pitch = 0.5f; +static float _start = 0.f; +static float _end = 1.f; +static float _amp = 1.f; + +int32_t _select = 0; +const char *sample_names[12]; +void *sample_ptr[12]; +#define SETUP_SAMPLE(name, ptr) \ + sample_names[_select] = name; \ + sample_ptr[_select] = ptr; \ + ++_select + +void engine::setup() +{ + auto BD0 = &IC34_TR707_SNDROM_bin[0x0000]; + auto BD1 = &IC34_TR707_SNDROM_bin[0x0001]; + auto SD0 = &IC34_TR707_SNDROM_bin[0x2000]; + auto SD1 = &IC34_TR707_SNDROM_bin[0x2001]; + auto RM = &IC35_TR707_SNDROM_bin[0x4000]; + auto CB = &IC35_TR707_SNDROM_bin[0x4001]; + auto CP = &IC35_TR707_SNDROM_bin[0x6000]; + auto TMB = &IC35_TR707_SNDROM_bin[0x6001]; + auto LT = &IC34_TR707_SNDROM_bin[0x4000]; + auto MT = &IC34_TR707_SNDROM_bin[0x6000]; + auto HT = &IC35_TR707_SNDROM_bin[0x0000]; + auto HH = &IC35_TR707_SNDROM_bin[0x2000]; + + SETUP_SAMPLE("BD0", dsp_sample_u8(BD0, 0x1000, 25000, 1)); + SETUP_SAMPLE("BD1", dsp_sample_u8(BD1, 0x1000, 25000, 1)); + SETUP_SAMPLE("SD0", dsp_sample_u8(SD0, 0x1000, 25000, 1)); + SETUP_SAMPLE("SD1", dsp_sample_u8(SD1, 0x1000, 25000, 1)); + + SETUP_SAMPLE("CP", dsp_sample_u8(CP, 0x1000, 25000, 1)); + SETUP_SAMPLE("TMB", dsp_sample_u8(TMB, 0x1000, 25000, 1)); + SETUP_SAMPLE("RM", dsp_sample_u8(RM, 0x1000, 25000, 1)); + SETUP_SAMPLE("CB", dsp_sample_u8(CB, 0x1000, 25000, 1)); + + SETUP_SAMPLE("LT", dsp_sample_u8(LT, 0x1000, 25000, 0)); + SETUP_SAMPLE("MT", dsp_sample_u8(MT, 0x1000, 25000, 0)); + SETUP_SAMPLE("HT", dsp_sample_u8(HT, 0x1000, 25000, 0)); + SETUP_SAMPLE("HH", dsp_sample_u8(HH, 0x1000, 25000, 0)); + + engine::addParam("Pitch", &_pitch); + engine::addParam(">Sample", &_select, 0, LEN_OF(sample_names) - 1, sample_names); // . = hidden + _select = 0; + + engine::addParam("Start", &_start); + engine::addParam("End", &_end); +} + +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); +} \ No newline at end of file diff --git a/app/DRUMS/TR909-HiHat.bin b/app/DRUMS/TR909-HiHat.bin new file mode 100644 index 0000000000000000000000000000000000000000..7062416cb830b84fb128c8cc97545c750a55e89f GIT binary patch literal 1528 zcmaKsO=uHa6vs~{X^d&rdA84fSr}Uv6)Z2Pixx#=Ei*AmY5d3{$YU}zQzn?C^Cn3} za3O-wjVM&4AYvCHb*I?6GPD~Pf`T6lmx3ZxXaqrVe2ez|PkLMRsU7&`f9^SF&bjyI z-boI`2e(l(1tg+Hu#bpZ08H|O0N4OF3Ogw5dMMisfNfdWe?T{Ztza`~1Y1B8;2eH9 z#{)RW3pmFIIHwN$3Apz*z`dIR*W`I|%~rrQ+W_abgHEs=bbv*o5QLV95_hnWdJiR% zPzBlt-3z@0-4Fc-$`7xbpWQ36_RH(zhv&u*_c-h!nHwa9o`&-K=foH$?F5%Sq_BNW z=yjpDh29rBFZ8j{S3=(jT@<=36eYutFzg$PQBSwjIJzL0@bi;9s zvl!&FnXGP(nT3*W8HG&Fbl@!i-(@?a!)CEaMYB}4kzhOKw<@|>$o%9hmJH{|W+Lso z_f~T9MlLrxOe2nIe%G3eOeSGCMqbbE-ScfQfUA%{r{EC=WW%$p4~ees8#B) zlK1>IYrFM!eCDf9F~*hgX-#o@D||=zoOo;TQRIhmO(b`S7&X5mOAToO~afJk-@5rwQ)frcP^#ZQX`+5M_t98?;k{D}$Ap4)u&ZO(x@7Xu0-R}STJQxjf-`~dVN*HwpKm^1= z&wJ{Z@Sn)?bC<4250}3zEmaoi0z%5qG5_-KW6C*uBcKineym(ju literal 0 HcmV?d00001 diff --git a/app/DRUMS/TR909-HiHat.cpp b/app/DRUMS/TR909-HiHat.cpp new file mode 100644 index 0000000..c6a50f7 --- /dev/null +++ b/app/DRUMS/TR909-HiHat.cpp @@ -0,0 +1,31 @@ +#include "../squares-and-circles-api.h" + +// #include "eproms/tr909/hihats.h" +static const uint8_t *HiHats_bin = machine::fs_read("909_HIGH"); + +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() +{ + _oh = dsp_sample_u8(HiHats_bin, 24576, 32000, 0); + const int ch_start = 24576; + _ch = dsp_sample_u8(HiHats_bin + ch_start, 32768 - ch_start, 32000, 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/TR909-Ride.bin b/app/DRUMS/TR909-Ride.bin new file mode 100644 index 0000000000000000000000000000000000000000..d43aee111efbe30156ffcb25fbf7fb6b256fed1c GIT binary patch literal 1520 zcmaKsU1$?o6vxj@(rz550%|42!f;Fy8n~hRRz%{!7=WYc(U>oQLe-lL^^qwel9UD<3 z$_zojh3*5~?LS}S~|vgw!MU6J;Q zqnT4M^ZChfn(%F2+)`^YEh}UCX2Edx@B28Jz{K*+vuU?zlU4GJl3DQbwow_tcPA@l zuTnPh#)L-&yMV#F~$8ID}2jNss z=Qps_m+zE1|1@a-BOA2Eg`I?4EOCy%;}xUEvaku4GJn{IHM!=Q$2)PD7Gu{ z<{wh#^o^;jO%LtrZhF=)dwAaRDkAkJTJBUAqp{|h^4|C@Xn^;`_kAbeJ@Fgj_n|JR zNfl=ztNdHEIk_I%t|eymw$!>Ldl1oP>T=iPx}?n1Nr|K$y$nel=}A-b~pv?lqk$;4+dtA`u+YBm?CQZ0i8 rjRHOkq6(); + 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/FX/Delay.bin b/app/FX/Delay.bin new file mode 100644 index 0000000000000000000000000000000000000000..885436d838ba13cbfb4a1ee5675a1254c8cf99c8 GIT binary patch literal 3224 zcmbtVdu&tJ9X|K^+DR@Z+?en(379-ESU^L|280ew8f<2V;dLOItX=G4JI+-eo|Axf z_aG&VhE|nGqOAei1_A-Zw92q#gN=xG$~ z0cK+!z--J1m~I=e05Ef;07PbR#CHh_bHD-cO7I4-2iybR3_bwf2L3Ua{a9XJ;D~fS zIlKS2MISz|b5Q4q&QWj$3SoxjleuFf1k zuE(NtuFlJKUZ=C`xhIN4Re>Ln^76`>%KGv^ES8*9R|YG~Lpwq>_2rR3O|U8y!-Pj!5DQe7S3dRR{Ye-T=37Z+O^Co3xCWsYqtzr@yEBYopdnaU zi-^ms%EQs9)mI^|GtS-j*S`|J{h;^lW$3O)ju?soPLe zstL|xt`{`H>vyyJKVg^Md8vCy%Y3I)Gdp?LG1nCR6uH3O(nycPYxf`y=VI?q<79!M z6=R=}NF^uTWFco4ZvC#H|2nBK93%@cUO{d(M^C!@uNPI!^UQ-)-bWUY7A}X`U+h|x z?aV#wp5yIMGezhjv%RmW1~zgU6UE$ZO2otNOz)fHYs8q?sIN(rYwV0MQNrcAjPc%U zBTi)Z0@=yI)A6@$1LpxO#zg>&ZwbI2b3xDiWOn98vLa3Kk56ZLvp2!EL~=-LYIdn+ z^fl&kIVasIbiZdvwa7EQXK96k69ohGWref#sk~x{7xbokGN6YiY^Os_6G_6C^iwEk zcc&#SY#yn3*5*3sXQ$y`ALbH!~RjLs` z^ND3HuKTr34tuq6znpvN3FSkTD0|?UMu(LO`1uDlQ~8-{QND*PZ(_ME7@0KAf~qdXsmhL(PMnP4?3i$jwKTC(63$am9{kcT$rwK<)C7 zI(<@N=3n6hW);b3`YsNsGaxrZd>wj4XtE$$%jD^6$bk|2M)Bq0iCVp1M2J!xIn%lJ zw-sqll!>I*|84b0+g7i?GVPnrT1!*m)~z3|{m!Xf>wek#i^7NNx(er6ZI@mj*|by@ zUfmlXyFF#>ocA1iM+L}Ld=T}zqGrO6w-wY-W_9bO19F=>4gQ^y&tkj~QSG2^WrPlw zeNL~Iv3eOl9#W6WClEWTBOmuPsncZWv+=F`t+QX3B1ds=-zZ}%L+T-qC30xftVjo} z@-|E4PZ~M=ral&04<$$3>z0V2H6`Kaj4glBQthZlnfHsv6{}tRC-6mH?P^hp^`J@| zgR0@+plXx{RnseNYN|4*rYLP{nrBd*VjWb|9c`+3uuYx%$`y5b;iq)5+({QDBeJ8` zh^DX&w|o-|7z4?xdh#3CHvI*#1riqHaGis8Vg7#muUBguH6Q9M^9j7sn9 z`uxt@{Gr)?Q@r=4@G83QYsq(l@7m8dh#%!XjjPVCygM;xhmrL)*5k4Ow&4VdfsH`4 z=ZVQ)w~xFJe@%YF{>3gXr!jY;*V*KJ??QY<3{t+=5izv0zQ=mr zOL#x{qDbsL3HS~~@g11s$!2}X$-XVNY{UNKp5B?;-P65)Mqlhu(^)^aWqJ+m?9HJw zeY?fa^iTD&yfGPM$uXgGq94F{^n-`rc?nj10DJ3OfM}28k(dumqi@IDUrVNoByX!G ztl?I)yN?&$xg>hT$L>dapM##~0Y4A~mR=`CJigD8bV(!o`SWA9wb9;dWH+{KU)>{j zAH8RN%-*SckCw|Dd-UGk$vyVH-BMW{0{uU~br7C}D-;U8h=pfrt7>ClU!aDpt^Y 0) + uint32_t clk_bpm = machine::clk_bpm();// / 100; + if (clk_bpm > 0) { engine::addParam(time_info, &time_steps, 1, 128); - uint32_t bpm = midi_bpm; + uint32_t bpm = clk_bpm; auto t_per_beat = 6000.f / bpm; // * machine::SAMPLE_RATE t_32 = t_per_beat / 32; return true; diff --git a/app/FX/Gated-Reverb.bin b/app/FX/Gated-Reverb.bin new file mode 100644 index 0000000000000000000000000000000000000000..91e9048d9ec2451ab43520154c8f23f27036d55c GIT binary patch literal 5704 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 WP_5U6Lq%MXy`{|saXZ^Q`2GJx;Ve}E literal 0 HcmV?d00001 diff --git a/app/FX/Gated-Reverb.bin.h b/app/FX/Gated-Reverb.bin.h deleted file mode 100644 index 3ea2cc8..0000000 --- a/app/FX/Gated-Reverb.bin.h +++ /dev/null @@ -1,468 +0,0 @@ -const uint8_t __FX_Gated_Reverb_bin[] FLASHMEM __attribute__((aligned(32))) = { - 0x55, 0x44, 0x4c, 0x4d, 0x15, 0x00, 0x15, 0x00, 0xd8, 0x01, 0x00, 0x00, - 0x14, 0x13, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x01, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, - 0xe4, 0x00, 0x00, 0x50, 0xf9, 0x12, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x50, - 0xa5, 0x12, 0x00, 0x00, 0x04, 0x01, 0x00, 0x50, 0xdd, 0x12, 0x00, 0x00, - 0x0c, 0x01, 0x00, 0x50, 0xc1, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x10, 0x1c, 0x00, 0x00, 0x00, - 0x26, 0x01, 0x00, 0x10, 0x1c, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x10, - 0x1c, 0x00, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x10, 0x1c, 0x00, 0x00, 0x00, - 0x60, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x67, 0x01, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x77, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x84, 0x01, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x91, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x98, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xa9, 0x01, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0xba, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0xc8, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x46, 0x58, 0x2f, 0x47, - 0x61, 0x74, 0x65, 0x64, 0x2d, 0x52, 0x65, 0x76, 0x65, 0x72, 0x62, 0x00, - 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, - 0x00, 0x5f, 0x5f, 0x75, 0x69, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, - 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00, 0x70, 0x72, 0x6f, 0x63, - 0x65, 0x73, 0x73, 0x00, 0x73, 0x65, 0x74, 0x75, 0x70, 0x00, 0x5f, 0x5f, - 0x70, 0x72, 0x65, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, - 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x5f, 0x5f, 0x70, 0x72, 0x65, 0x69, - 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x00, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, - 0x72, 0x72, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x5f, 0x5f, 0x69, - 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x00, 0x6d, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x00, 0x66, - 0x72, 0x65, 0x65, 0x00, 0x5f, 0x5f, 0x75, 0x69, 0x5f, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x00, 0x61, 0x64, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x5f, - 0x69, 0x33, 0x32, 0x00, 0x61, 0x64, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, - 0x5f, 0x66, 0x33, 0x32, 0x00, 0x6d, 0x65, 0x6d, 0x73, 0x65, 0x74, 0x00, - 0x5f, 0x5f, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5f, 0x69, 0x6e, 0x5f, 0x6c, - 0x5f, 0x66, 0x70, 0x70, 0x00, 0x5f, 0x5f, 0x61, 0x75, 0x64, 0x69, 0x6f, - 0x5f, 0x69, 0x6e, 0x5f, 0x72, 0x5f, 0x66, 0x70, 0x70, 0x00, 0x5f, 0x5f, - 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x72, 0x5f, 0x66, 0x70, 0x00, - 0x5f, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6c, 0x5f, 0x66, - 0x70, 0x00, 0x00, 0x00, 0x2d, 0xe9, 0xf0, 0x4d, 0x00, 0xf5, 0x80, 0x35, - 0x82, 0xb0, 0x95, 0xf8, 0x48, 0x31, 0x00, 0x2b, 0x00, 0xf0, 0xdc, 0x86, - 0x00, 0x23, 0x03, 0xf3, 0x17, 0x02, 0x03, 0xf3, 0x17, 0x02, 0xd2, 0x4f, - 0x02, 0x62, 0x9c, 0x46, 0x01, 0x26, 0xc5, 0xf8, 0x30, 0x31, 0x1a, 0x46, - 0x01, 0x68, 0xc4, 0x6d, 0x4f, 0xf4, 0x00, 0x1e, 0x84, 0xfb, 0x0e, 0x38, - 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xd3, 0x53, 0x0b, 0x44, 0x03, 0xf3, - 0x17, 0x03, 0x04, 0x6e, 0x84, 0xfb, 0x0e, 0x18, 0x4f, 0xea, 0x48, 0x28, - 0x48, 0xea, 0xd1, 0x51, 0x0b, 0x44, 0x03, 0xf3, 0x17, 0x01, 0xd5, 0xf8, - 0x0c, 0x31, 0xc3, 0xf3, 0x0e, 0x04, 0x00, 0xeb, 0x44, 0x04, 0x0d, 0x12, - 0xa4, 0xf8, 0x0c, 0x51, 0x00, 0x25, 0x81, 0xfb, 0x05, 0x4e, 0x4f, 0xea, - 0x4e, 0x2e, 0x4e, 0xea, 0xd4, 0x54, 0x04, 0xf3, 0x17, 0x04, 0x03, 0xeb, - 0x0c, 0x01, 0xc1, 0xf3, 0x0e, 0x01, 0x00, 0xeb, 0x41, 0x01, 0x44, 0x60, - 0xb1, 0xf9, 0x0c, 0x11, 0x09, 0x02, 0x01, 0xf3, 0x17, 0x0c, 0x81, 0xfb, - 0x07, 0xce, 0x4f, 0xea, 0x4e, 0x2e, 0x4e, 0xea, 0xdc, 0x5c, 0x64, 0x44, - 0x04, 0xf3, 0x17, 0x04, 0x99, 0x19, 0xc1, 0xf3, 0x0e, 0x01, 0x00, 0xeb, - 0x41, 0x01, 0xb1, 0xf9, 0x0c, 0x11, 0x09, 0x02, 0x01, 0xf3, 0x17, 0x06, - 0x86, 0x60, 0x81, 0xfb, 0x02, 0x67, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, - 0xd6, 0x56, 0x34, 0x44, 0x04, 0xf3, 0x17, 0x04, 0x03, 0xf5, 0x80, 0x51, - 0x05, 0x31, 0xc1, 0xf3, 0x0e, 0x01, 0x00, 0xeb, 0x41, 0x06, 0x44, 0xf3, - 0x0f, 0x21, 0xa6, 0xf8, 0x0c, 0x11, 0x84, 0xfb, 0x05, 0x67, 0x4f, 0xea, - 0x47, 0x27, 0x47, 0xea, 0xd6, 0x56, 0x06, 0xf3, 0x17, 0x06, 0x02, 0xf3, - 0x17, 0x02, 0x9c, 0x4c, 0x06, 0x6d, 0x86, 0xfb, 0x04, 0x7c, 0x4f, 0xea, - 0x4c, 0x2c, 0x4c, 0xea, 0xd7, 0x57, 0x3a, 0x44, 0x02, 0xf3, 0x17, 0x02, - 0xc2, 0x61, 0x82, 0xfb, 0x05, 0x46, 0x4f, 0xea, 0x46, 0x26, 0x46, 0xea, - 0xd4, 0x54, 0x04, 0xf3, 0x17, 0x02, 0x4f, 0xf4, 0x00, 0x05, 0xc4, 0x6c, - 0x84, 0xfb, 0x05, 0x67, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd6, 0x56, - 0x32, 0x44, 0x02, 0xf3, 0x17, 0x02, 0x02, 0xf4, 0x70, 0x04, 0x12, 0x02, - 0x48, 0xbf, 0x44, 0xf0, 0x7f, 0x44, 0x04, 0xf3, 0x17, 0x02, 0x4f, 0xf4, - 0x00, 0x05, 0x82, 0xfb, 0x05, 0x46, 0x4f, 0xea, 0x46, 0x26, 0x46, 0xea, - 0xd4, 0x54, 0xa4, 0xf5, 0xf0, 0x04, 0x04, 0xf3, 0x17, 0x04, 0x00, 0x2c, - 0x26, 0x46, 0x00, 0xf3, 0x12, 0x81, 0x84, 0xfb, 0x05, 0x26, 0x4f, 0xea, - 0x46, 0x26, 0x46, 0xea, 0xd2, 0x52, 0x02, 0xf5, 0x00, 0x24, 0x04, 0xf3, - 0x17, 0x04, 0x00, 0x2c, 0x22, 0x46, 0x00, 0xf3, 0x1a, 0x81, 0x84, 0xfb, - 0x05, 0x26, 0x4f, 0xea, 0x46, 0x26, 0x46, 0xea, 0xd2, 0x52, 0x02, 0xf5, - 0x00, 0x22, 0x02, 0xf3, 0x17, 0x02, 0x00, 0x2a, 0x14, 0x46, 0x00, 0xf3, - 0x23, 0x81, 0x82, 0xfb, 0x05, 0x46, 0x4f, 0xea, 0x46, 0x26, 0x46, 0xea, - 0xd4, 0x54, 0x04, 0xf5, 0x00, 0x22, 0x02, 0xf3, 0x17, 0x02, 0x00, 0x2a, - 0x14, 0x46, 0x00, 0xf3, 0x2b, 0x81, 0x82, 0xfb, 0x05, 0x46, 0x4f, 0xea, - 0x46, 0x26, 0x46, 0xea, 0xd4, 0x54, 0x04, 0xf5, 0x00, 0x22, 0x02, 0xf3, - 0x17, 0x02, 0x00, 0x2a, 0x14, 0x46, 0x00, 0xf3, 0x34, 0x81, 0x82, 0xfb, - 0x05, 0x46, 0x4f, 0xea, 0x46, 0x26, 0x46, 0xea, 0xd4, 0x54, 0x04, 0xf5, - 0x00, 0x22, 0x02, 0xf3, 0x17, 0x02, 0x00, 0x2a, 0x14, 0x46, 0x00, 0xf3, - 0x3d, 0x81, 0x82, 0xfb, 0x05, 0x46, 0x4f, 0xea, 0x46, 0x26, 0x46, 0xea, - 0xd4, 0x54, 0x04, 0xf5, 0x00, 0x22, 0x02, 0xf3, 0x17, 0x02, 0x00, 0x2a, - 0x14, 0x46, 0x00, 0xf3, 0x45, 0x81, 0x82, 0xfb, 0x05, 0x46, 0x4f, 0xea, - 0x46, 0x26, 0x46, 0xea, 0xd4, 0x54, 0x04, 0xf5, 0x00, 0x22, 0x02, 0xf3, - 0x17, 0x02, 0x00, 0x2a, 0x14, 0x46, 0x00, 0xf3, 0x4e, 0x81, 0x82, 0xfb, - 0x05, 0x46, 0x4f, 0xea, 0x46, 0x26, 0x46, 0xea, 0xd4, 0x54, 0x04, 0xf5, - 0x00, 0x22, 0x02, 0xf3, 0x17, 0x02, 0x00, 0x2a, 0x14, 0x46, 0x00, 0xf3, - 0x57, 0x81, 0x82, 0xfb, 0x05, 0x46, 0x4f, 0xea, 0x46, 0x26, 0x46, 0xea, - 0xd4, 0x54, 0x04, 0xf5, 0x00, 0x24, 0x04, 0xf3, 0x17, 0x04, 0x00, 0x2c, - 0x00, 0xf3, 0x61, 0x81, 0x2e, 0x46, 0x84, 0xfb, 0x06, 0x25, 0x4f, 0xea, - 0x45, 0x25, 0x45, 0xea, 0xd2, 0x52, 0x02, 0xf5, 0x00, 0x22, 0x02, 0xf3, - 0x17, 0x02, 0x00, 0x2a, 0x14, 0x46, 0x00, 0xf3, 0x69, 0x81, 0x82, 0xfb, - 0x06, 0x45, 0x4f, 0xea, 0x45, 0x25, 0x45, 0xea, 0xd4, 0x54, 0x04, 0xf5, - 0x00, 0x22, 0x02, 0xf3, 0x17, 0x02, 0x00, 0x2a, 0x14, 0x46, 0x00, 0xf3, - 0x72, 0x81, 0x82, 0xfb, 0x06, 0x45, 0x4f, 0xea, 0x45, 0x25, 0x45, 0xea, - 0xd4, 0x54, 0x04, 0xf5, 0x00, 0x22, 0x02, 0xf3, 0x17, 0x02, 0x00, 0x2a, - 0x15, 0x46, 0x00, 0xf3, 0x7b, 0x81, 0x82, 0xfb, 0x06, 0x45, 0x4f, 0xea, - 0x45, 0x25, 0x45, 0xea, 0xd4, 0x54, 0x04, 0xf5, 0x00, 0x22, 0x02, 0xf3, - 0x17, 0x02, 0x00, 0x2a, 0x15, 0x46, 0x00, 0xf3, 0x83, 0x81, 0x82, 0xfb, - 0x06, 0x45, 0x4f, 0xea, 0x45, 0x25, 0x45, 0xea, 0xd4, 0x54, 0x04, 0xf5, - 0x00, 0x22, 0x02, 0xf3, 0x17, 0x02, 0x00, 0x2a, 0x15, 0x46, 0x00, 0xf3, - 0x8c, 0x81, 0x82, 0xfb, 0x06, 0x45, 0x4f, 0xea, 0x45, 0x25, 0x45, 0xea, - 0xd4, 0x54, 0x04, 0xf5, 0x00, 0x22, 0x02, 0xf3, 0x17, 0x02, 0x00, 0x2a, - 0x15, 0x46, 0x00, 0xf3, 0x95, 0x81, 0x82, 0xfb, 0x06, 0x45, 0x4f, 0xea, - 0x45, 0x25, 0x45, 0xea, 0xd4, 0x54, 0x04, 0xf5, 0x00, 0x22, 0x02, 0xf3, - 0x17, 0x02, 0x00, 0x2a, 0x15, 0x46, 0x00, 0xf3, 0x9d, 0x81, 0x82, 0xfb, - 0x06, 0x45, 0x4f, 0xea, 0x45, 0x25, 0x45, 0xea, 0xd4, 0x54, 0x04, 0xf5, - 0x00, 0x24, 0x04, 0xf3, 0x17, 0x04, 0x00, 0x2c, 0x25, 0x46, 0x00, 0xf3, - 0xa6, 0x81, 0x84, 0xfb, 0x06, 0x25, 0x4f, 0xea, 0x45, 0x25, 0x45, 0xea, - 0xd2, 0x52, 0x02, 0xf5, 0x00, 0x22, 0x02, 0xf3, 0x17, 0x02, 0x00, 0x2a, - 0x02, 0x60, 0x15, 0x46, 0x00, 0xf3, 0xae, 0x81, 0x04, 0xe0, 0x00, 0xbf, - 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x82, 0xfb, 0x06, 0x45, - 0x4f, 0xea, 0x45, 0x25, 0x45, 0xea, 0xd4, 0x54, 0x42, 0x60, 0x04, 0xf5, - 0x00, 0x22, 0x02, 0xf3, 0x17, 0x06, 0x00, 0x2e, 0x06, 0x60, 0x00, 0xf3, - 0xb3, 0x81, 0x03, 0xf5, 0x90, 0x42, 0x03, 0x32, 0xc2, 0xf3, 0x0e, 0x02, - 0x00, 0xeb, 0x42, 0x02, 0xb2, 0xf9, 0x0c, 0x51, 0x2d, 0x02, 0x05, 0xf3, - 0x17, 0x02, 0xd2, 0x4c, 0x85, 0xfb, 0x04, 0x27, 0x4f, 0xea, 0x47, 0x27, - 0x47, 0xea, 0xd2, 0x52, 0x32, 0x44, 0x02, 0xf3, 0x17, 0x02, 0x03, 0xf5, - 0x8d, 0x44, 0x4c, 0x34, 0xc4, 0xf3, 0x0e, 0x04, 0x00, 0xeb, 0x44, 0x04, - 0xb4, 0xf9, 0x0c, 0x51, 0x2d, 0x02, 0x05, 0xf3, 0x17, 0x04, 0x4f, 0xf4, - 0x80, 0x06, 0x85, 0xfb, 0x06, 0x47, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, - 0xd4, 0x54, 0x14, 0x44, 0x04, 0xf3, 0x17, 0x04, 0x03, 0xf5, 0x89, 0x42, - 0x49, 0x32, 0xc2, 0xf3, 0x0e, 0x02, 0x00, 0xeb, 0x42, 0x02, 0xb2, 0xf9, - 0x0c, 0x21, 0x12, 0x02, 0x02, 0xf3, 0x17, 0x05, 0xbb, 0x4e, 0x82, 0xfb, - 0x06, 0x57, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd5, 0x55, 0x2c, 0x44, - 0x04, 0xf3, 0x17, 0x04, 0x03, 0xf5, 0x86, 0x42, 0x32, 0x32, 0xc2, 0xf3, - 0x0e, 0x02, 0x00, 0xeb, 0x42, 0x02, 0xb2, 0xf9, 0x0c, 0x21, 0x12, 0x02, - 0x02, 0xf3, 0x17, 0x05, 0x4f, 0xf4, 0x80, 0x06, 0x82, 0xfb, 0x06, 0x57, - 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd5, 0x55, 0x2c, 0x44, 0x04, 0xf3, - 0x17, 0x04, 0x03, 0xf5, 0x83, 0x42, 0x5d, 0x32, 0xc2, 0xf3, 0x0e, 0x02, - 0x00, 0xeb, 0x42, 0x02, 0xb2, 0xf9, 0x0c, 0x21, 0x12, 0x02, 0x02, 0xf3, - 0x17, 0x05, 0x4f, 0xf4, 0x80, 0x06, 0x82, 0xfb, 0x06, 0x57, 0x4f, 0xea, - 0x47, 0x27, 0x47, 0xea, 0xd5, 0x55, 0x2c, 0x44, 0x04, 0xf3, 0x17, 0x04, - 0x03, 0xf5, 0x7d, 0x52, 0x1d, 0x32, 0xc2, 0xf3, 0x0e, 0x02, 0x00, 0xeb, - 0x42, 0x02, 0xb2, 0xf9, 0x0c, 0x21, 0x12, 0x02, 0x02, 0xf3, 0x17, 0x05, - 0x99, 0x4e, 0x82, 0xfb, 0x06, 0x57, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, - 0xd5, 0x55, 0x2c, 0x44, 0x04, 0xf3, 0x17, 0x04, 0x03, 0xf5, 0x77, 0x52, - 0x3a, 0x32, 0xc2, 0xf3, 0x0e, 0x02, 0x00, 0xeb, 0x42, 0x02, 0xb2, 0xf9, - 0x0c, 0x21, 0x12, 0x02, 0x02, 0xf3, 0x17, 0x05, 0x4f, 0xf4, 0x80, 0x06, - 0x82, 0xfb, 0x06, 0x57, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd5, 0x55, - 0x2c, 0x44, 0x04, 0xf3, 0x17, 0x04, 0x03, 0xf5, 0x70, 0x52, 0x35, 0x32, - 0xc2, 0xf3, 0x0e, 0x02, 0x00, 0xeb, 0x42, 0x02, 0xb2, 0xf9, 0x0c, 0x21, - 0x12, 0x02, 0x02, 0xf3, 0x17, 0x05, 0x4f, 0xf4, 0x80, 0x06, 0x82, 0xfb, - 0x06, 0x57, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd5, 0x55, 0x2c, 0x44, - 0x04, 0xf3, 0x17, 0x04, 0x03, 0xf5, 0x68, 0x52, 0x03, 0x32, 0xc2, 0xf3, - 0x0e, 0x02, 0x00, 0xeb, 0x42, 0x02, 0xb2, 0xf9, 0x0c, 0x21, 0x12, 0x02, - 0x02, 0xf3, 0x17, 0x05, 0x4f, 0xf4, 0x80, 0x06, 0x82, 0xfb, 0x06, 0x57, - 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd5, 0x55, 0x2c, 0x44, 0x04, 0xf3, - 0x17, 0x04, 0x03, 0xf5, 0x5f, 0x52, 0x29, 0x32, 0xc2, 0xf3, 0x0e, 0x02, - 0x00, 0xeb, 0x42, 0x02, 0xb2, 0xf9, 0x0c, 0x21, 0x12, 0x02, 0x02, 0xf3, - 0x17, 0x05, 0x4f, 0xf4, 0x80, 0x06, 0x82, 0xfb, 0x06, 0x57, 0x4f, 0xea, - 0x47, 0x27, 0x47, 0xea, 0xd5, 0x55, 0x2c, 0x44, 0x04, 0xf3, 0x17, 0x04, - 0x03, 0xf5, 0x57, 0x52, 0x2e, 0x32, 0xc2, 0xf3, 0x0e, 0x02, 0x00, 0xeb, - 0x42, 0x02, 0xb2, 0xf9, 0x0c, 0x21, 0x12, 0x02, 0x02, 0xf3, 0x17, 0x05, - 0x4f, 0xf4, 0x80, 0x06, 0x82, 0xfb, 0x06, 0x57, 0x4f, 0xea, 0x47, 0x27, - 0x47, 0xea, 0xd5, 0x55, 0x2a, 0x19, 0x02, 0xf3, 0x17, 0x04, 0x03, 0xf5, - 0x52, 0x52, 0x1c, 0x32, 0xc2, 0xf3, 0x0e, 0x02, 0x00, 0xeb, 0x42, 0x02, - 0xb2, 0xf9, 0x0c, 0x21, 0x12, 0x02, 0x02, 0xf3, 0x17, 0x05, 0x4f, 0xf4, - 0x80, 0x06, 0x82, 0xfb, 0x06, 0x57, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, - 0xd5, 0x55, 0x2a, 0x19, 0x02, 0xf3, 0x17, 0x05, 0x03, 0xf5, 0x4b, 0x52, - 0x0e, 0x32, 0xc2, 0xf3, 0x0e, 0x02, 0x00, 0xeb, 0x42, 0x02, 0xb2, 0xf9, - 0x0c, 0x21, 0x12, 0x02, 0x02, 0xf3, 0x17, 0x04, 0x49, 0x4e, 0x82, 0xfb, - 0x06, 0x47, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd4, 0x54, 0x62, 0x19, - 0x02, 0xf3, 0x17, 0x05, 0x03, 0xf5, 0x46, 0x52, 0x04, 0x32, 0xc2, 0xf3, - 0x0e, 0x02, 0x00, 0xeb, 0x42, 0x02, 0xb2, 0xf9, 0x0c, 0x21, 0x12, 0x02, - 0x02, 0xf3, 0x17, 0x04, 0x4f, 0xf4, 0x80, 0x06, 0x82, 0xfb, 0x06, 0x47, - 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd4, 0x54, 0x62, 0x19, 0x02, 0xf3, - 0x17, 0x05, 0x03, 0xf5, 0x40, 0x52, 0x1c, 0x32, 0xc2, 0xf3, 0x0e, 0x02, - 0x00, 0xeb, 0x42, 0x02, 0xb2, 0xf9, 0x0c, 0x21, 0x12, 0x02, 0x02, 0xf3, - 0x17, 0x04, 0x4f, 0xf4, 0x80, 0x06, 0x82, 0xfb, 0x06, 0x47, 0x4f, 0xea, - 0x47, 0x27, 0x47, 0xea, 0xd4, 0x54, 0x62, 0x19, 0x02, 0xf3, 0x17, 0x05, - 0x03, 0xf5, 0x33, 0x52, 0x39, 0x32, 0xc2, 0xf3, 0x0e, 0x02, 0x00, 0xeb, - 0x42, 0x02, 0xb2, 0xf9, 0x0c, 0x21, 0x12, 0x02, 0x02, 0xf3, 0x17, 0x04, - 0x27, 0x4e, 0x82, 0xfb, 0x06, 0x47, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, - 0xd4, 0x54, 0x62, 0x19, 0x02, 0xf3, 0x17, 0x05, 0x03, 0xf5, 0x2f, 0x52, - 0x2d, 0x32, 0xc2, 0xf3, 0x0e, 0x02, 0x00, 0xeb, 0x42, 0x02, 0xb2, 0xf9, - 0x0c, 0x21, 0x12, 0x02, 0x02, 0xf3, 0x17, 0x04, 0x4f, 0xf4, 0x80, 0x06, - 0x82, 0xfb, 0x06, 0x47, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd4, 0x54, - 0x62, 0x19, 0x02, 0xf3, 0x17, 0x05, 0x03, 0xf5, 0x25, 0x52, 0x36, 0x32, - 0xc2, 0xf3, 0x0e, 0x02, 0x00, 0xeb, 0x42, 0x02, 0xb2, 0xf9, 0x0c, 0x21, - 0x12, 0x02, 0x02, 0xf3, 0x17, 0x04, 0x4f, 0xf4, 0x80, 0x06, 0x82, 0xfb, - 0x06, 0x47, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd4, 0x54, 0x62, 0x19, - 0x02, 0xf3, 0x17, 0x05, 0x03, 0xf5, 0x1b, 0x54, 0x03, 0x34, 0xc4, 0xf3, - 0x0e, 0x04, 0x00, 0xeb, 0x44, 0x04, 0xb4, 0xf9, 0x0c, 0x41, 0x24, 0x02, - 0x04, 0xf3, 0x17, 0x02, 0x4f, 0xf4, 0x80, 0x06, 0x84, 0xfb, 0x06, 0x27, - 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd2, 0x52, 0x2a, 0x44, 0x02, 0xf3, - 0x17, 0x06, 0x01, 0xe0, 0x00, 0x20, 0x33, 0x00, 0x03, 0xf5, 0x13, 0x54, - 0x0d, 0x34, 0xc4, 0xf3, 0x0e, 0x04, 0x00, 0xeb, 0x44, 0x04, 0xb4, 0xf9, - 0x0c, 0x41, 0x24, 0x02, 0x04, 0xf3, 0x17, 0x02, 0x4f, 0xf4, 0x80, 0x05, - 0x84, 0xfb, 0x05, 0x27, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd2, 0x52, - 0x32, 0x44, 0x02, 0xf3, 0x17, 0x02, 0x03, 0xf5, 0x10, 0x54, 0x17, 0x34, - 0xc4, 0xf3, 0x0e, 0x04, 0x00, 0xeb, 0x44, 0x04, 0xb4, 0xf9, 0x0c, 0x41, - 0x24, 0x02, 0x04, 0xf3, 0x17, 0x06, 0x84, 0xfb, 0x05, 0x67, 0x4f, 0xea, - 0x47, 0x27, 0x47, 0xea, 0xd6, 0x56, 0x32, 0x44, 0x02, 0xf3, 0x17, 0x02, - 0x03, 0xf5, 0x07, 0x54, 0x25, 0x34, 0xc4, 0xf3, 0x0e, 0x04, 0x00, 0xeb, - 0x44, 0x04, 0xb4, 0xf9, 0x0c, 0x41, 0x24, 0x02, 0x04, 0xf3, 0x17, 0x06, - 0x84, 0xfb, 0x05, 0x67, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd6, 0x56, - 0x32, 0x44, 0x02, 0xf3, 0x17, 0x02, 0x03, 0xf5, 0xfa, 0x54, 0x08, 0x34, - 0xc4, 0xf3, 0x0e, 0x04, 0x00, 0xeb, 0x44, 0x04, 0xb4, 0xf9, 0x0c, 0x41, - 0x24, 0x02, 0x04, 0xf3, 0x17, 0x06, 0xe4, 0x4e, 0x84, 0xfb, 0x06, 0x7c, - 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, 0xd7, 0x57, 0x3a, 0x44, 0x02, 0xf3, - 0x17, 0x02, 0x03, 0xf5, 0xeb, 0x54, 0x01, 0x34, 0xc4, 0xf3, 0x0e, 0x04, - 0x00, 0xeb, 0x44, 0x04, 0xb4, 0xf9, 0x0c, 0x41, 0x24, 0x02, 0x04, 0xf3, - 0x17, 0x06, 0x84, 0xfb, 0x05, 0x67, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, - 0xd6, 0x56, 0x32, 0x44, 0x02, 0xf3, 0x17, 0x02, 0x03, 0xf5, 0xdd, 0x54, - 0x03, 0x34, 0xc4, 0xf3, 0x0e, 0x04, 0x00, 0xeb, 0x44, 0x04, 0xb4, 0xf9, - 0x0c, 0x41, 0x24, 0x02, 0x04, 0xf3, 0x17, 0x06, 0x84, 0xfb, 0x05, 0x67, - 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd6, 0x56, 0x32, 0x44, 0x02, 0xf3, - 0x17, 0x02, 0x03, 0xf5, 0xcf, 0x54, 0x07, 0x34, 0xc4, 0xf3, 0x0e, 0x04, - 0x00, 0xeb, 0x44, 0x04, 0xb4, 0xf9, 0x0c, 0x41, 0x24, 0x02, 0x04, 0xf3, - 0x17, 0x06, 0x84, 0xfb, 0x05, 0x67, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, - 0xd6, 0x56, 0x32, 0x44, 0x02, 0xf3, 0x17, 0x02, 0x03, 0xf5, 0xc2, 0x54, - 0x03, 0x34, 0xc4, 0xf3, 0x0e, 0x04, 0x00, 0xeb, 0x44, 0x04, 0xb4, 0xf9, - 0x0c, 0x41, 0x24, 0x02, 0x04, 0xf3, 0x17, 0x06, 0x84, 0xfb, 0x05, 0x67, - 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd6, 0x56, 0x32, 0x44, 0x02, 0xf3, - 0x17, 0x02, 0x03, 0xf5, 0xaa, 0x54, 0x01, 0x34, 0xc4, 0xf3, 0x0e, 0x04, - 0x00, 0xeb, 0x44, 0x04, 0xb4, 0xf9, 0x0c, 0x41, 0x24, 0x02, 0x04, 0xf3, - 0x17, 0x06, 0x84, 0xfb, 0x05, 0x67, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, - 0xd6, 0x56, 0x32, 0x44, 0x02, 0xf3, 0x17, 0x02, 0x03, 0xf5, 0x9d, 0x54, - 0xc4, 0xf3, 0x0e, 0x04, 0x00, 0xeb, 0x44, 0x04, 0xb4, 0xf9, 0x0c, 0x41, - 0x24, 0x02, 0x04, 0xf3, 0x17, 0x06, 0x84, 0xfb, 0x05, 0x67, 0x4f, 0xea, - 0x47, 0x27, 0x47, 0xea, 0xd6, 0x56, 0x32, 0x44, 0x02, 0xf3, 0x17, 0x02, - 0x03, 0xf5, 0x8f, 0x54, 0x19, 0x34, 0xc4, 0xf3, 0x0e, 0x04, 0x00, 0xeb, - 0x44, 0x04, 0xb4, 0xf9, 0x0c, 0x41, 0x24, 0x02, 0x04, 0xf3, 0x17, 0x06, - 0x84, 0xfb, 0x05, 0x67, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd6, 0x56, - 0x32, 0x44, 0x02, 0xf3, 0x17, 0x02, 0x09, 0x02, 0x01, 0xf3, 0x17, 0x04, - 0x95, 0x4e, 0x81, 0xfb, 0x06, 0x47, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, - 0xd4, 0x54, 0x22, 0x44, 0x02, 0xf3, 0x17, 0x02, 0x4f, 0xf4, 0x00, 0x04, - 0xc0, 0xf8, 0x90, 0x20, 0x82, 0xfb, 0x04, 0x71, 0x4f, 0xea, 0x41, 0x21, - 0x41, 0xea, 0xd7, 0x57, 0x07, 0xf3, 0x17, 0x07, 0x03, 0xf5, 0x97, 0x41, - 0x08, 0x31, 0xc1, 0xf3, 0x0e, 0x01, 0x00, 0xeb, 0x41, 0x01, 0xb1, 0xf9, - 0x0c, 0x11, 0x09, 0x02, 0x01, 0xf3, 0x17, 0x0c, 0x81, 0xfb, 0x06, 0xe8, - 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xde, 0x5e, 0x77, 0x44, 0x07, 0xf3, - 0x17, 0x07, 0x03, 0xf5, 0x95, 0x41, 0x1e, 0x31, 0xc1, 0xf3, 0x0e, 0x01, - 0x00, 0xeb, 0x41, 0x01, 0x4f, 0xea, 0x27, 0x2e, 0xa1, 0xf8, 0x0c, 0xe1, - 0x7b, 0x49, 0x87, 0xfb, 0x01, 0xe8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, - 0xde, 0x5e, 0x0e, 0xf3, 0x17, 0x07, 0xbc, 0x44, 0x0c, 0xf3, 0x17, 0x0c, - 0x03, 0xf5, 0x9a, 0x47, 0x47, 0x37, 0xc7, 0xf3, 0x0e, 0x07, 0x00, 0xeb, - 0x47, 0x07, 0xb7, 0xf9, 0x0c, 0x71, 0x3f, 0x02, 0x07, 0xf3, 0x17, 0x0e, - 0x87, 0xfb, 0x06, 0x8a, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, - 0xc4, 0x44, 0x0c, 0xf3, 0x17, 0x0c, 0x03, 0xf5, 0x97, 0x47, 0x09, 0x37, - 0xc7, 0xf3, 0x0e, 0x07, 0x00, 0xeb, 0x47, 0x07, 0x4f, 0xea, 0x2c, 0x28, - 0xa7, 0xf8, 0x0c, 0x81, 0x8c, 0xfb, 0x01, 0x78, 0x4f, 0xea, 0x48, 0x28, - 0x48, 0xea, 0xd7, 0x57, 0x07, 0xf3, 0x17, 0x07, 0xbe, 0x44, 0x0e, 0xf3, - 0x17, 0x0e, 0x03, 0xf5, 0x9e, 0x47, 0x70, 0x37, 0xc7, 0xf3, 0x0e, 0x07, - 0x00, 0xeb, 0x47, 0x07, 0xb7, 0xf9, 0x0c, 0xc1, 0x4f, 0xea, 0x0c, 0x2c, - 0x0c, 0xf3, 0x17, 0x07, 0x8c, 0xfb, 0x06, 0x8a, 0x4f, 0xea, 0x4a, 0x2a, - 0x4a, 0xea, 0xd8, 0x58, 0xc6, 0x44, 0x0e, 0xf3, 0x17, 0x0e, 0x03, 0xf5, - 0x9a, 0x4c, 0x0c, 0xf1, 0x48, 0x0c, 0xcc, 0xf3, 0x0e, 0x0c, 0x00, 0xeb, - 0x4c, 0x0c, 0x4f, 0xea, 0x2e, 0x28, 0xac, 0xf8, 0x0c, 0x81, 0x8e, 0xfb, - 0x01, 0xc8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xdc, 0x5c, 0x0c, 0xf3, - 0x17, 0x0c, 0x67, 0x44, 0x07, 0xf3, 0x17, 0x07, 0x4f, 0xf0, 0x00, 0x0e, - 0x47, 0x66, 0x87, 0xfb, 0x0e, 0xc8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, - 0xdc, 0x5c, 0x0c, 0xf3, 0x17, 0x07, 0x82, 0xfb, 0x04, 0xc8, 0x4f, 0xea, - 0x48, 0x28, 0x48, 0xea, 0xdc, 0x5c, 0x07, 0xeb, 0x0c, 0x02, 0x02, 0xf3, - 0x17, 0x07, 0x03, 0xf5, 0xa0, 0x42, 0x3a, 0x32, 0xc2, 0xf3, 0x0e, 0x02, - 0x00, 0xeb, 0x42, 0x02, 0xb2, 0xf9, 0x0c, 0x21, 0x12, 0x02, 0x02, 0xf3, - 0x17, 0x0c, 0x82, 0xfb, 0x06, 0x8a, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, - 0xd8, 0x58, 0x07, 0xeb, 0x08, 0x02, 0x02, 0xf3, 0x17, 0x07, 0x03, 0xf5, - 0x9e, 0x42, 0x71, 0x32, 0xc2, 0xf3, 0x0e, 0x02, 0x00, 0xeb, 0x42, 0x02, - 0x4f, 0xea, 0x27, 0x28, 0xa2, 0xf8, 0x0c, 0x81, 0x87, 0xfb, 0x01, 0x28, - 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xd2, 0x52, 0x02, 0xf3, 0x17, 0x02, - 0x94, 0x44, 0x0c, 0xf3, 0x17, 0x0c, 0x03, 0xf5, 0xa3, 0x42, 0x40, 0x32, - 0xc2, 0xf3, 0x0e, 0x02, 0x00, 0xeb, 0x42, 0x02, 0xb2, 0xf9, 0x0c, 0x71, - 0x3f, 0x02, 0x07, 0xf3, 0x17, 0x02, 0x87, 0xfb, 0x06, 0x8a, 0x4f, 0xea, - 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, 0xc4, 0x44, 0x0c, 0xf3, 0x17, 0x0c, - 0x03, 0xf5, 0xa0, 0x47, 0x3b, 0x37, 0xc7, 0xf3, 0x0e, 0x07, 0x00, 0xeb, - 0x47, 0x07, 0x4f, 0xea, 0x2c, 0x28, 0xa7, 0xf8, 0x0c, 0x81, 0x8c, 0xfb, - 0x01, 0x78, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xd7, 0x57, 0x07, 0xf3, - 0x17, 0x07, 0x3a, 0x44, 0x02, 0xf3, 0x17, 0x02, 0x03, 0xf5, 0xa8, 0x47, - 0x34, 0x37, 0xc7, 0xf3, 0x0e, 0x07, 0x00, 0xeb, 0x47, 0x07, 0xb7, 0xf9, - 0x0c, 0xc1, 0x4f, 0xea, 0x0c, 0x2c, 0x0c, 0xf3, 0x17, 0x07, 0x8c, 0xfb, - 0x06, 0x8a, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, 0x42, 0x44, - 0x02, 0xf3, 0x17, 0x02, 0x82, 0xfb, 0x01, 0x6c, 0x4f, 0xea, 0x4c, 0x2c, - 0x4c, 0xea, 0xd6, 0x56, 0x03, 0xf5, 0xa3, 0x41, 0x41, 0x31, 0xc1, 0xf3, - 0x0e, 0x01, 0x00, 0xeb, 0x41, 0x01, 0x05, 0xe0, 0x00, 0x20, 0x33, 0x00, - 0x00, 0xc0, 0x4c, 0x00, 0x00, 0x20, 0xb3, 0xff, 0x12, 0x12, 0xa1, 0xf8, - 0x0c, 0x21, 0x06, 0xf3, 0x17, 0x02, 0x3a, 0x44, 0x02, 0xf3, 0x17, 0x02, - 0x82, 0x66, 0x82, 0xfb, 0x0e, 0xc1, 0x4f, 0xea, 0x41, 0x21, 0x41, 0xea, - 0xdc, 0x5c, 0x0c, 0xf3, 0x17, 0x0c, 0x03, 0xf5, 0xce, 0x57, 0x09, 0x37, - 0xc7, 0xf3, 0x0e, 0x07, 0x00, 0xeb, 0x47, 0x07, 0xb7, 0xf9, 0x0c, 0x81, - 0x4f, 0xea, 0x08, 0x28, 0x08, 0xf3, 0x17, 0x02, 0x9d, 0x49, 0x88, 0xfb, - 0x01, 0x26, 0x4f, 0xea, 0x46, 0x26, 0x46, 0xea, 0xd2, 0x52, 0x94, 0x44, - 0x0c, 0xf3, 0x17, 0x0c, 0xd0, 0xf8, 0x94, 0x20, 0xac, 0xeb, 0x02, 0x06, - 0x86, 0xfb, 0x05, 0xab, 0x4f, 0xea, 0x4b, 0x2b, 0x4b, 0xea, 0xda, 0x5a, - 0x52, 0x44, 0x02, 0xf3, 0x17, 0x02, 0x82, 0xfb, 0x01, 0x56, 0x4f, 0xea, - 0x46, 0x26, 0x46, 0xea, 0xd5, 0x55, 0x01, 0x92, 0xac, 0x44, 0x0c, 0xf3, - 0x17, 0x0c, 0x45, 0x6d, 0x8c, 0xfb, 0x05, 0x6a, 0x4f, 0xea, 0x4a, 0x2a, - 0x4a, 0xea, 0xd6, 0x56, 0x06, 0xf3, 0x17, 0x06, 0x08, 0xf3, 0x17, 0x0c, - 0x88, 0xfb, 0x04, 0xca, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xdc, 0x5c, - 0x66, 0x44, 0x06, 0xf3, 0x17, 0x06, 0x4f, 0xea, 0x26, 0x2c, 0xa7, 0xf8, - 0x0c, 0xc1, 0x86, 0xfb, 0x0e, 0xc7, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, - 0xdc, 0x5c, 0x0c, 0xf3, 0x17, 0x0c, 0x03, 0xf5, 0x06, 0x56, 0x19, 0x36, - 0xc6, 0xf3, 0x0e, 0x06, 0x00, 0xeb, 0x46, 0x06, 0xb6, 0xf9, 0x0c, 0x71, - 0x3f, 0x02, 0x07, 0xf3, 0x17, 0x08, 0x87, 0xfb, 0x01, 0x8a, 0x4f, 0xea, - 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, 0xc4, 0x44, 0x0c, 0xf3, 0x17, 0x0c, - 0xd0, 0xf8, 0x98, 0x20, 0xdf, 0xf8, 0xcc, 0xa1, 0xac, 0xeb, 0x02, 0x08, - 0x88, 0xfb, 0x0a, 0xb2, 0x4f, 0xea, 0x42, 0x22, 0x42, 0xea, 0xdb, 0x5b, - 0xd0, 0xf8, 0x98, 0x20, 0x02, 0xeb, 0x0b, 0x08, 0x08, 0xf3, 0x17, 0x08, - 0x88, 0xfb, 0x01, 0xab, 0x4f, 0xea, 0x4b, 0x2b, 0x4b, 0xea, 0xda, 0x5a, - 0xc0, 0xf8, 0x98, 0x80, 0xd4, 0x44, 0x0c, 0xf3, 0x17, 0x08, 0x88, 0xfb, - 0x05, 0xca, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xdc, 0x5c, 0x0c, 0xf3, - 0x17, 0x0c, 0x07, 0xf3, 0x17, 0x08, 0x87, 0xfb, 0x04, 0x8a, 0x4f, 0xea, - 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, 0x0c, 0xeb, 0x08, 0x07, 0x07, 0xf3, - 0x17, 0x07, 0x4f, 0xea, 0x27, 0x2c, 0xa6, 0xf8, 0x0c, 0xc1, 0x87, 0xfb, - 0x0e, 0x6c, 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, 0xd6, 0x56, 0x06, 0xf3, - 0x17, 0x06, 0x03, 0xf5, 0x2d, 0x57, 0x1d, 0x37, 0xc7, 0xf3, 0x0e, 0x07, - 0x00, 0xeb, 0x47, 0x07, 0xb7, 0xf9, 0x0c, 0xc1, 0x4f, 0xea, 0x0c, 0x2c, - 0x0c, 0xf3, 0x17, 0x08, 0x8c, 0xfb, 0x01, 0x8a, 0x4f, 0xea, 0x4a, 0x2a, - 0x4a, 0xea, 0xd8, 0x58, 0x46, 0x44, 0x06, 0xf3, 0x17, 0x06, 0x01, 0x9a, - 0xdf, 0xf8, 0x2c, 0xa1, 0xa6, 0xeb, 0x02, 0x08, 0x88, 0xfb, 0x0a, 0xb2, - 0x4f, 0xea, 0x42, 0x22, 0x42, 0xea, 0xdb, 0x5b, 0x01, 0x9a, 0x5a, 0x44, - 0x02, 0xf3, 0x17, 0x02, 0x82, 0xfb, 0x01, 0x8a, 0x4f, 0xea, 0x4a, 0x2a, - 0x4a, 0xea, 0xd8, 0x58, 0x46, 0x44, 0x06, 0xf3, 0x17, 0x08, 0x88, 0xfb, - 0x05, 0x6a, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd6, 0x56, 0x06, 0xf3, - 0x17, 0x06, 0x0c, 0xf3, 0x17, 0x08, 0x8c, 0xfb, 0x04, 0x8a, 0x4f, 0xea, - 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, 0x46, 0x44, 0x06, 0xf3, 0x17, 0x06, - 0x4f, 0xea, 0x26, 0x2c, 0xa7, 0xf8, 0x0c, 0xc1, 0x86, 0xfb, 0x0e, 0x7c, - 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, 0xd7, 0x57, 0x07, 0xf3, 0x17, 0x07, - 0x03, 0xf5, 0x5c, 0x53, 0x15, 0x33, 0xc3, 0xf3, 0x0e, 0x03, 0x00, 0xeb, - 0x43, 0x03, 0xb3, 0xf9, 0x0c, 0x61, 0x36, 0x02, 0x06, 0xf3, 0x17, 0x0c, - 0x86, 0xfb, 0x01, 0xc8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xdc, 0x5c, - 0x67, 0x44, 0x07, 0xf3, 0x17, 0x07, 0xdf, 0xf8, 0x9c, 0x80, 0xa7, 0xeb, - 0x02, 0x0c, 0x8c, 0xfb, 0x08, 0xab, 0x4f, 0xea, 0x4b, 0x2b, 0x4b, 0xea, - 0xda, 0x5a, 0x52, 0x44, 0x02, 0xf3, 0x17, 0x02, 0x82, 0xfb, 0x01, 0xc8, - 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xdc, 0x5c, 0xc0, 0xf8, 0x94, 0x20, - 0x07, 0xeb, 0x0c, 0x01, 0x01, 0xf3, 0x17, 0x01, 0x81, 0xfb, 0x05, 0x27, - 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xd2, 0x52, 0x02, 0xf3, 0x17, 0x02, - 0x06, 0xf3, 0x17, 0x05, 0x86, 0xfb, 0x04, 0x17, 0x4f, 0xea, 0x47, 0x27, - 0x47, 0xea, 0xd1, 0x51, 0x85, 0x60, 0x0a, 0x44, 0x02, 0xf3, 0x17, 0x02, - 0x14, 0x12, 0x42, 0x60, 0x82, 0xfb, 0x0e, 0x15, 0x4f, 0xea, 0x45, 0x25, - 0x45, 0xea, 0xd1, 0x51, 0xa3, 0xf8, 0x0c, 0x41, 0x01, 0xf3, 0x17, 0x01, - 0x01, 0x60, 0x02, 0xb0, 0xbd, 0xe8, 0xf0, 0x8d, 0xd5, 0xf8, 0x30, 0x21, - 0x04, 0x4f, 0x4f, 0xea, 0xa2, 0x2c, 0xbf, 0x1a, 0x0c, 0xf1, 0x01, 0x06, - 0xff, 0xf7, 0x26, 0xb9, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x3f, 0x00, - 0x00, 0x33, 0x33, 0x00, 0x00, 0x66, 0x26, 0x00, 0x00, 0x99, 0x19, 0x00, - 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, 0x04, 0x00, 0x00, 0x00, - 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, 0x04, 0x00, 0x00, 0x00, - 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, 0x04, 0x00, 0x00, 0x00, - 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, 0x04, 0x00, 0x00, 0x00, - 0x38, 0xb5, 0x08, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x1d, 0x68, 0x55, 0xb1, - 0x06, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x1c, 0x68, 0xe3, 0x88, 0xb4, 0xf9, - 0x04, 0x20, 0x61, 0x88, 0x20, 0x88, 0xa8, 0x47, 0x20, 0x72, 0x38, 0xbd, - 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0xb4, 0x03, 0x4c, - 0x59, 0xf8, 0x04, 0x40, 0xa4, 0x46, 0x5d, 0xf8, 0x04, 0x4b, 0x60, 0x47, - 0x10, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, - 0x14, 0x00, 0x00, 0x00, 0x2d, 0xe9, 0xf0, 0x41, 0x58, 0x4b, 0x59, 0xf8, - 0x03, 0x40, 0x58, 0x4b, 0x00, 0x25, 0xc4, 0xe9, 0x02, 0x55, 0xc4, 0xe9, - 0x04, 0x55, 0xc4, 0xe9, 0x06, 0x55, 0xc4, 0xe9, 0x08, 0x55, 0xc4, 0xe9, - 0x0a, 0x55, 0xc4, 0xe9, 0x0c, 0x55, 0xc4, 0xe9, 0x0e, 0x55, 0xc4, 0xe9, - 0x10, 0x55, 0xc4, 0xe9, 0x12, 0x55, 0xc4, 0xe9, 0x14, 0x55, 0xc4, 0xe9, - 0x16, 0x55, 0xc4, 0xe9, 0x18, 0x55, 0xc4, 0xe9, 0x1a, 0x55, 0xc4, 0xe9, - 0x1c, 0x55, 0xc4, 0xe9, 0x1e, 0x55, 0xc4, 0xe9, 0x20, 0x55, 0xc4, 0xf8, - 0x88, 0x50, 0xc4, 0xf8, 0x08, 0x51, 0x82, 0xb0, 0x59, 0xf8, 0x03, 0x80, - 0x29, 0x46, 0x4f, 0xf4, 0x80, 0x32, 0x04, 0xf5, 0x86, 0x70, 0xc0, 0x47, - 0x04, 0xf5, 0x80, 0x36, 0x3c, 0x4b, 0xc6, 0xf8, 0x14, 0x31, 0xc6, 0xe9, - 0x48, 0x53, 0x01, 0x23, 0x86, 0xf8, 0x48, 0x31, 0x04, 0xf1, 0x10, 0x03, - 0xc6, 0xf8, 0x18, 0x31, 0x04, 0xf1, 0x0c, 0x03, 0xc6, 0xf8, 0x1c, 0x31, - 0x04, 0xf1, 0x18, 0x03, 0xc6, 0xf8, 0x28, 0x31, 0x04, 0xf1, 0x14, 0x03, - 0xc6, 0xf8, 0x2c, 0x31, 0x04, 0xf1, 0x20, 0x03, 0xc6, 0xf8, 0x34, 0x31, - 0x04, 0xf1, 0x1c, 0x03, 0xc6, 0xf8, 0x38, 0x31, 0x04, 0xf1, 0x28, 0x03, - 0xc6, 0xf8, 0x40, 0x31, 0xc6, 0xe9, 0x43, 0x55, 0x04, 0xf1, 0x24, 0x03, - 0xc6, 0xf8, 0x44, 0x31, 0x2b, 0x4b, 0xc6, 0xf8, 0x30, 0x51, 0xc6, 0xf8, - 0x3c, 0x51, 0xc6, 0xf8, 0x50, 0x51, 0x59, 0xf8, 0x03, 0x70, 0x25, 0x60, - 0x65, 0x60, 0x29, 0x46, 0x04, 0xf1, 0x8c, 0x00, 0x7c, 0x22, 0x7c, 0x60, - 0xc0, 0x47, 0x24, 0x4b, 0x9f, 0xed, 0x1f, 0x0a, 0x59, 0xf8, 0x03, 0x20, - 0xc6, 0xf8, 0x4c, 0x21, 0x4f, 0xf0, 0x7c, 0x53, 0xfb, 0x60, 0x3b, 0x61, - 0x7b, 0x61, 0xf7, 0xee, 0x00, 0x0a, 0x1e, 0x4b, 0xc7, 0xed, 0x02, 0x0a, - 0x59, 0xf8, 0x03, 0x00, 0x1c, 0x4b, 0xcd, 0xed, 0x01, 0x0a, 0x8d, 0xed, - 0x00, 0x0a, 0x59, 0xf8, 0x03, 0x40, 0x07, 0xf1, 0x08, 0x01, 0xa0, 0x47, - 0x18, 0x4b, 0xdd, 0xed, 0x01, 0x0a, 0x59, 0xf8, 0x03, 0x00, 0x9d, 0xed, - 0x00, 0x0a, 0x07, 0xf1, 0x0c, 0x01, 0xa0, 0x47, 0x14, 0x4b, 0xdd, 0xed, - 0x01, 0x0a, 0x59, 0xf8, 0x03, 0x00, 0x9d, 0xed, 0x00, 0x0a, 0x07, 0xf1, - 0x10, 0x01, 0xa0, 0x47, 0x10, 0x4b, 0xdd, 0xed, 0x01, 0x0a, 0x59, 0xf8, - 0x03, 0x00, 0x9d, 0xed, 0x00, 0x0a, 0x07, 0xf1, 0x14, 0x01, 0x23, 0x46, - 0x02, 0xb0, 0xbd, 0xe8, 0xf0, 0x41, 0x18, 0x47, 0x01, 0x00, 0x80, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x2d, 0xe9, 0xf0, 0x4d, 0x2d, 0xed, 0x02, 0x8b, - 0x87, 0x4b, 0x88, 0x4a, 0x59, 0xf8, 0x03, 0x80, 0x87, 0x4b, 0x59, 0xf8, - 0x02, 0x00, 0x59, 0xf8, 0x03, 0x10, 0x86, 0x4b, 0x86, 0x4a, 0x59, 0xf8, - 0x03, 0x30, 0xd8, 0xed, 0x03, 0x6a, 0x98, 0xed, 0x04, 0x7a, 0x09, 0x68, - 0xd8, 0xed, 0x05, 0x7a, 0x00, 0x68, 0x59, 0xf8, 0x02, 0x20, 0xd0, 0xf8, - 0x00, 0xa0, 0x1e, 0x68, 0xd1, 0xf8, 0x00, 0xb0, 0xd8, 0xf8, 0x04, 0x70, - 0x15, 0x68, 0x9f, 0xed, 0x76, 0x8a, 0xb0, 0xee, 0x66, 0x6a, 0xf0, 0xee, - 0x47, 0x6a, 0xb0, 0xee, 0x67, 0x7a, 0x8a, 0xb0, 0xbe, 0xee, 0xe4, 0x6a, - 0xfe, 0xee, 0xe4, 0x6a, 0xbe, 0xee, 0xe4, 0x7a, 0xb4, 0x46, 0x59, 0x46, - 0x0a, 0xf1, 0x60, 0x03, 0xcd, 0xe9, 0x06, 0x6a, 0xcd, 0xf8, 0x14, 0xb0, - 0xcd, 0xf8, 0x24, 0x80, 0xd3, 0x46, 0x8d, 0xed, 0x02, 0x6a, 0xcd, 0xed, - 0x03, 0x6a, 0x8d, 0xed, 0x04, 0x7a, 0x07, 0xf5, 0x80, 0x34, 0x08, 0x95, - 0x01, 0x91, 0x2e, 0x46, 0x9a, 0x46, 0xe0, 0x46, 0xfb, 0xec, 0x01, 0x7a, - 0xfe, 0xee, 0xe4, 0x7a, 0x17, 0xee, 0x90, 0x3a, 0x03, 0xf3, 0x17, 0x03, - 0xfb, 0x65, 0x01, 0x9b, 0xf3, 0xec, 0x01, 0x7a, 0xfe, 0xee, 0xe4, 0x7a, - 0x01, 0x93, 0x17, 0xee, 0x90, 0x3a, 0x03, 0xf3, 0x17, 0x03, 0x3b, 0x66, - 0x02, 0x9b, 0x03, 0xf3, 0x17, 0x03, 0xfb, 0x64, 0x03, 0x9b, 0x03, 0xf3, - 0x17, 0x03, 0x3b, 0x65, 0x04, 0x9b, 0x03, 0xf3, 0x17, 0x03, 0x7b, 0x65, - 0x38, 0x46, 0xd4, 0xf8, 0x4c, 0x31, 0x98, 0x47, 0x4f, 0xf0, 0x00, 0x03, - 0x84, 0xf8, 0x48, 0x31, 0xd4, 0xf8, 0x1c, 0x31, 0x19, 0x68, 0xd4, 0xf8, - 0x0c, 0x31, 0x01, 0x3b, 0xc4, 0xf8, 0x0c, 0x31, 0xd4, 0xe9, 0x44, 0x23, - 0x09, 0x12, 0x82, 0xfb, 0x01, 0x0c, 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, - 0xd0, 0x50, 0x03, 0x44, 0x03, 0xf3, 0x17, 0x03, 0x83, 0xfb, 0x01, 0x0c, - 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, 0xd0, 0x50, 0xc4, 0xf8, 0x14, 0x31, - 0x12, 0x1a, 0x02, 0xf3, 0x17, 0x02, 0xd4, 0xf8, 0x2c, 0x31, 0xc4, 0xf8, - 0x10, 0x21, 0x18, 0x68, 0xd4, 0xe9, 0x48, 0x23, 0x00, 0x12, 0x82, 0xfb, - 0x00, 0x1c, 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, 0xd1, 0x51, 0x0b, 0x44, - 0x03, 0xf3, 0x17, 0x03, 0x83, 0xfb, 0x00, 0x1c, 0x4f, 0xea, 0x4c, 0x2c, - 0x4c, 0xea, 0xd1, 0x51, 0xc4, 0xf8, 0x24, 0x31, 0x52, 0x1a, 0x02, 0xf3, - 0x17, 0x02, 0xd4, 0xf8, 0x34, 0x31, 0xc4, 0xf8, 0x20, 0x21, 0x18, 0x68, - 0xd4, 0xf8, 0x40, 0x31, 0x2e, 0x4a, 0x19, 0x68, 0xd4, 0xf8, 0x38, 0x31, - 0xd7, 0xed, 0x19, 0x7a, 0xd4, 0xf8, 0x30, 0x51, 0x40, 0x15, 0x49, 0x15, - 0x42, 0xfa, 0x00, 0xf0, 0x42, 0xfa, 0x01, 0xf1, 0x1a, 0x68, 0xd4, 0xf8, - 0x44, 0x31, 0xb8, 0xee, 0xe7, 0x7a, 0xa5, 0xeb, 0x22, 0x32, 0xd7, 0xed, - 0x1a, 0x7a, 0x1b, 0x68, 0x02, 0x40, 0xc4, 0xf8, 0x30, 0x21, 0xf8, 0xee, - 0xe7, 0x7a, 0xd4, 0xf8, 0x3c, 0x21, 0x27, 0xee, 0x08, 0x7a, 0x67, 0xee, - 0x88, 0x7a, 0xa2, 0xeb, 0x23, 0x33, 0x19, 0x40, 0xd3, 0x45, 0xc4, 0xf8, - 0x3c, 0x11, 0xa6, 0xec, 0x01, 0x7a, 0xe8, 0xec, 0x01, 0x7a, 0x7f, 0xf4, - 0x67, 0xaf, 0xdd, 0xe9, 0x07, 0xa5, 0xdd, 0xe9, 0x05, 0xb6, 0xdd, 0xf8, - 0x24, 0x80, 0xf7, 0xee, 0x00, 0x6a, 0x05, 0xf1, 0x60, 0x03, 0x98, 0xed, - 0x02, 0x7a, 0xfa, 0xec, 0x01, 0x5a, 0x95, 0xed, 0x00, 0x6a, 0x76, 0xee, - 0xc7, 0x7a, 0x67, 0xee, 0xa5, 0x7a, 0xe6, 0xee, 0x07, 0x7a, 0xe5, 0xec, - 0x01, 0x7a, 0x98, 0xed, 0x02, 0x7a, 0xfb, 0xec, 0x01, 0x5a, 0x96, 0xed, - 0x00, 0x6a, 0x76, 0xee, 0xc7, 0x7a, 0xab, 0x42, 0x67, 0xee, 0xa5, 0x7a, - 0xe6, 0xee, 0x07, 0x7a, 0xe6, 0xec, 0x01, 0x7a, 0xe1, 0xd1, 0x0a, 0xb0, - 0xbd, 0xec, 0x02, 0x8b, 0xbd, 0xe8, 0xf0, 0x8d, 0x00, 0x00, 0x00, 0x34, - 0xff, 0xff, 0x3f, 0x00, 0x08, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x70, 0xb5, 0x10, 0x4a, 0x10, 0x4b, 0x59, 0xf8, 0x02, 0x60, 0x59, 0xf8, - 0x03, 0x50, 0x76, 0x1b, 0xb6, 0x10, 0x06, 0xd0, 0x00, 0x24, 0x55, 0xf8, - 0x04, 0x3b, 0x01, 0x34, 0x98, 0x47, 0xa6, 0x42, 0xf9, 0xd1, 0x0a, 0x4a, - 0x0a, 0x4b, 0x59, 0xf8, 0x02, 0x60, 0x59, 0xf8, 0x03, 0x50, 0x76, 0x1b, - 0xb6, 0x10, 0x06, 0xd0, 0x00, 0x24, 0x55, 0xf8, 0x04, 0x3b, 0x01, 0x34, - 0x98, 0x47, 0xa6, 0x42, 0xf9, 0xd1, 0x70, 0xbd, 0x44, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, - 0x2d, 0xe9, 0x00, 0x42, 0x02, 0xb4, 0xdf, 0xf8, 0x10, 0x10, 0xd1, 0xf8, - 0x00, 0x90, 0x02, 0xbc, 0xff, 0xf7, 0xc2, 0xfd, 0xbd, 0xe8, 0x00, 0x82, - 0x00, 0x00, 0x00, 0x20, 0x2d, 0xe9, 0x00, 0x42, 0x02, 0xb4, 0xdf, 0xf8, - 0x10, 0x10, 0xd1, 0xf8, 0x00, 0x90, 0x02, 0xbc, 0xff, 0xf7, 0xda, 0xfd, - 0xbd, 0xe8, 0x00, 0x82, 0x00, 0x00, 0x00, 0x20, 0x2d, 0xe9, 0x00, 0x42, - 0x02, 0xb4, 0xdf, 0xf8, 0x10, 0x10, 0xd1, 0xf8, 0x00, 0x90, 0x02, 0xbc, - 0xff, 0xf7, 0x92, 0xfe, 0xbd, 0xe8, 0x00, 0x82, 0x00, 0x00, 0x00, 0x20, - 0x2d, 0xe9, 0x00, 0x42, 0x02, 0xb4, 0xdf, 0xf8, 0x10, 0x10, 0xd1, 0xf8, - 0x00, 0x90, 0x02, 0xbc, 0xff, 0xf7, 0xa2, 0xff, 0xbd, 0xe8, 0x00, 0x82, - 0x00, 0x00, 0x00, 0x20, 0x44, 0x2f, 0x57, 0x00, 0x50, 0x72, 0x65, 0x44, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x2d, 0x54, 0x69, 0x6d, 0x65, 0x00, 0x00, - 0x44, 0x61, 0x6d, 0x70, 0x00, 0x00, 0x00, 0x00 -}; -unsigned int __FX_Gated_Reverb_bin_len = 5576; diff --git a/app/FX/JU60_chorus.bin b/app/FX/JU60_chorus.bin new file mode 100644 index 0000000000000000000000000000000000000000..9216440e472224082bef603739fd9b225ffa0a08 GIT binary patch literal 8024 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 OES-;^g(613DgG}7z#sAe literal 0 HcmV?d00001 diff --git a/src/fx_juno60_chorus.cxx b/app/FX/JU60_chorus.cpp similarity index 59% rename from src/fx_juno60_chorus.cxx rename to app/FX/JU60_chorus.cpp index e5ac287..13bfe28 100644 --- a/src/fx_juno60_chorus.cxx +++ b/app/FX/JU60_chorus.cpp @@ -29,18 +29,25 @@ // https://github.com/jpcima/rc-effect-playground/issues/2#issuecomment-541340615 // https://github.com/jpcima/string-machine/tree/master/sources/bbd +#include "../squares-and-circles-api.h" +#ifdef ONE_POLE +#undef ONE_POLE +#endif + +#include + +#include "bbd/bbd_line.h" + #include "stmlib/dsp/filter.h" #include "stmlib/dsp/delay_line.h" #include "stmlib/dsp/dsp.h" -#include "bbd/bbd_line.h" -#include "machine.h" - -constexpr int samplerate = machine::SAMPLE_RATE; +#include "bbd/bbd_line.cc" +#include "bbd/bbd_filter.cc" struct Juno60_Chorus { - static constexpr size_t delay_size = (1 + samplerate * 0.0054); // max delay time + static constexpr size_t delay_size = (1 + SAMPLE_RATE * 0.0054); // max delay time stmlib::DelayLine delay_; stmlib::Svf pre_lpf, post_lpf_l, post_lpf_r; @@ -83,10 +90,10 @@ struct Juno60_Chorus void setMode(const Mode &mode) { mode_ = mode; - lmin = mode_.minDelayL * samplerate; - la = (mode_.maxDelayL - mode_.minDelayL) * samplerate; - rmin = mode_.minDelayR * samplerate; - ra = (mode_.maxDelayR - mode_.minDelayR) * samplerate; + lmin = mode_.minDelayL * SAMPLE_RATE; + la = (mode_.maxDelayL - mode_.minDelayL) * SAMPLE_RATE; + rmin = mode_.minDelayR * SAMPLE_RATE; + ra = (mode_.maxDelayR - mode_.minDelayR) * SAMPLE_RATE; } Juno60_Chorus() @@ -95,15 +102,15 @@ struct Juno60_Chorus pre_lpf.Init(); post_lpf_l.Init(); post_lpf_r.Init(); - pre_lpf.set_f_q(7237.f / samplerate, 1.f); - post_lpf_l.set_f_q(10644.f / samplerate, 1.f); - post_lpf_r.set_f_q(10644.f / samplerate, 1.f); + pre_lpf.set_f_q(7237.f / SAMPLE_RATE, 1.f); + post_lpf_l.set_f_q(10644.f / SAMPLE_RATE, 1.f); + post_lpf_r.set_f_q(10644.f / SAMPLE_RATE, 1.f); } void process(float *inOut, float *outR, uint32_t len) { float wet = 1.f - mode_.dry; - float f = mode_.freq / samplerate; + float f = mode_.freq / SAMPLE_RATE; while (len-- > 0) { float lfo_val = lfo_tri(f); @@ -160,17 +167,17 @@ struct Juno60_Chorus_BBD void setMode(const Mode &mode) { mode_ = mode; - minL = BBD_Line::hz_rate_for_delay(mode_.minDelayL, bbd_stages) / machine::SAMPLE_RATE; - maxL = BBD_Line::hz_rate_for_delay(mode_.maxDelayL, bbd_stages) / machine::SAMPLE_RATE; - minR = BBD_Line::hz_rate_for_delay(mode_.minDelayR, bbd_stages) / machine::SAMPLE_RATE; - maxR = BBD_Line::hz_rate_for_delay(mode_.maxDelayR, bbd_stages) / machine::SAMPLE_RATE; + minL = BBD_Line::hz_rate_for_delay(mode_.minDelayL, bbd_stages) / SAMPLE_RATE; + maxL = BBD_Line::hz_rate_for_delay(mode_.maxDelayL, bbd_stages) / SAMPLE_RATE; + minR = BBD_Line::hz_rate_for_delay(mode_.minDelayR, bbd_stages) / SAMPLE_RATE; + maxR = BBD_Line::hz_rate_for_delay(mode_.maxDelayR, bbd_stages) / SAMPLE_RATE; } Juno60_Chorus_BBD() { const unsigned interp_size = 128; - fin = BBD::compute_filter(machine::SAMPLE_RATE, interp_size, bbd_fin_j60); - fout = BBD::compute_filter(machine::SAMPLE_RATE, interp_size, bbd_fout_j60); + fin = BBD::compute_filter(SAMPLE_RATE, interp_size, bbd_fin_j60); + fout = BBD::compute_filter(SAMPLE_RATE, interp_size, bbd_fout_j60); _delayL.setup(bbd_stages, fin, fout); _delayR.setup(bbd_stages, fin, fout); @@ -178,12 +185,12 @@ struct Juno60_Chorus_BBD _delayR.clear(); } - float dry[machine::FRAME_BUFFER_SIZE]; + float dry[FRAME_BUFFER_SIZE]; float phase_ = 0; void lfo_tri(float phase_inc_, float *out) { - for (size_t i = 0; i < machine::FRAME_BUFFER_SIZE; i++) + for (size_t i = 0; i < FRAME_BUFFER_SIZE; i++) { float t = -1.0f + (2.0f * phase_); *out++ = fabsf(t); @@ -194,18 +201,18 @@ struct Juno60_Chorus_BBD } } - float clockL[machine::FRAME_BUFFER_SIZE]; - float clockR[machine::FRAME_BUFFER_SIZE]; + float clockL[FRAME_BUFFER_SIZE]; + float clockR[FRAME_BUFFER_SIZE]; void process(float *inOut, float *outR, uint32_t len) { float wet = 1.f - mode_.dry; - float f = mode_.freq / samplerate; + float f = mode_.freq / SAMPLE_RATE; memcpy(dry, inOut, len * sizeof(float)); lfo_tri(f, clockL); - for (size_t i = 0; i < machine::FRAME_BUFFER_SIZE; i++) + for (size_t i = 0; i < FRAME_BUFFER_SIZE; i++) { dry[i] = stmlib::SoftLimit(dry[i]); @@ -214,10 +221,10 @@ struct Juno60_Chorus_BBD clockR[i] = minR + (mode_.stereo ? (1.f - lfo) : lfo) * (maxR - minR); } - _delayL.process(machine::FRAME_BUFFER_SIZE, dry, inOut, clockL); - _delayR.process(machine::FRAME_BUFFER_SIZE, dry, outR, clockR); + _delayL.process(FRAME_BUFFER_SIZE, dry, inOut, clockL); + _delayR.process(FRAME_BUFFER_SIZE, dry, outR, clockR); - for (size_t i = 0; i < machine::FRAME_BUFFER_SIZE; i++) + for (size_t i = 0; i < FRAME_BUFFER_SIZE; i++) { inOut[i] = inOut[i] * wet + dry[i] * mode_.dry; outR[i] = outR[i] * wet + dry[i] * mode_.dry; @@ -225,115 +232,95 @@ struct Juno60_Chorus_BBD } }; -using namespace machine; - -template -struct Juno60Chorus : public Engine -{ - T _chorus; - - float bufferL[FRAME_BUFFER_SIZE]; - float bufferR[FRAME_BUFFER_SIZE]; +static Juno60_Chorus_BBD _chorus = {}; - uint8_t mode = 1.f; - float raw = 1.f; +static int32_t mode = 1; +static const char *modes[] = { + "Off", "Mode I", "Mode II", "Mode I+II"}; +static float raw = 1.f; - Juno60Chorus() : Engine(AUDIO_PROCESSOR) - { - param[0].init("Amount", &raw, raw); - param[1].init("Mode", &mode, 1, 0, 3); - param[1].print_value = [&](char *name) - { - switch (mode) - { - case 0: - sprintf(name, ">Off"); - break; - case 1: - sprintf(name, ">Mode I"); - break; - case 2: - sprintf(name, ">Mode II"); - break; - case 3: - sprintf(name, ">Mode I+II"); - break; - } - }; - } +void engine::setup() +{ + engine::addParam("Amount", &raw); + engine::addParam(">Modes", &mode, 0, 3, modes); +} - void process(const ControlFrame &frame, OutputFrame &of) override - { - memset(bufferL, 0, sizeof(bufferL)); - memset(bufferR, 0, sizeof(bufferL)); - machine::get_audio(AUX_L, bufferL, raw); - machine::get_audio(AUX_R, bufferR, raw); +void set(float *target, const float *src, float amp) +{ + for (size_t i = 0; i < FRAME_BUFFER_SIZE; i++) + target[i] = src[i] * amp; +} - _chorus.setMode(_chorus.modes_[mode]); - _chorus.process(bufferL, bufferR, machine::FRAME_BUFFER_SIZE); +void mix(float *target, const float *src, float amp) +{ + for (size_t i = 0; i < FRAME_BUFFER_SIZE; i++) + target[i] += src[i] * amp; +} - machine::get_audio(AUX_L, bufferL, 1.f - raw); - machine::get_audio(AUX_R, bufferR, 1.f - raw); +void engine::process() +{ + auto inputL = engine::inputBuffer<0>(); + auto inputR = engine::inputBuffer<1>(); + auto outputL = engine::outputBuffer<0>(); + auto outputR = engine::outputBuffer<1>(); - of.out = bufferL; - of.aux = bufferR; - } -}; + set(outputL, inputL, raw); + set(outputR, inputR, raw); -#include "plaits/dsp/oscillator/oscillator.h" + _chorus.setMode(_chorus.modes_[mode]); + _chorus.process(outputL, outputR, FRAME_BUFFER_SIZE); -template -struct Juno60Chorus_TEST : public Engine -{ - plaits::Oscillator _osc; - stmlib::DCBlocker _dc_blockerL; - stmlib::DCBlocker _dc_blockerR; - T _chorus; + mix(outputL, inputL, 1.f - raw); + mix(outputR, inputR, 1.f - raw); +} - float bufferL[FRAME_BUFFER_SIZE]; - float bufferR[FRAME_BUFFER_SIZE]; +// #include "plaits/dsp/oscillator/oscillator.h" - uint8_t mode = 1; - float raw = 1.f; +// template +// struct Juno60Chorus_TEST : public Engine +// { +// plaits::Oscillator _osc; +// stmlib::DCBlocker _dc_blockerL; +// stmlib::DCBlocker _dc_blockerR; +// T _chorus; - Juno60Chorus_TEST() : Engine() - { - _dc_blockerL.Init(0.999f); - _dc_blockerR.Init(0.999f); - _osc.Init(); - _chorus.setMode(_chorus.modes_[mode]); - } +// float bufferL[FRAME_BUFFER_SIZE]; +// float bufferR[FRAME_BUFFER_SIZE]; - void process(const ControlFrame &frame, OutputFrame &of) override - { - memset(bufferL, 0, sizeof(bufferL)); - memset(bufferR, 0, sizeof(bufferL)); - machine::get_audio(AUX_L, bufferL, raw); - machine::get_audio(AUX_R, bufferR, raw); +// uint8_t mode = 1; +// float raw = 1.f; - _osc.Render(111.11f / machine::SAMPLE_RATE, 0.5f, bufferL, machine::FRAME_BUFFER_SIZE); +// Juno60Chorus_TEST() : Engine() +// { +// _dc_blockerL.Init(0.999f); +// _dc_blockerR.Init(0.999f); +// _osc.Init(); +// _chorus.setMode(_chorus.modes_[mode]); +// } - for (size_t i = 0; i < machine::FRAME_BUFFER_SIZE; i++) - { - bufferL[i] *= 0.5f; - } +// void process(const ControlFrame &frame, OutputFrame &of) override +// { +// memset(bufferL, 0, sizeof(bufferL)); +// memset(bufferR, 0, sizeof(bufferL)); +// get_audio(AUX_L, bufferL, raw); +// get_audio(AUX_R, bufferR, raw); - _chorus.process(bufferL, bufferR, machine::FRAME_BUFFER_SIZE); +// _osc.Render(111.11f / SAMPLE_RATE, 0.5f, bufferL, FRAME_BUFFER_SIZE); - _dc_blockerL.Process(bufferL, machine::FRAME_BUFFER_SIZE); - _dc_blockerR.Process(bufferR, machine::FRAME_BUFFER_SIZE); +// for (size_t i = 0; i < FRAME_BUFFER_SIZE; i++) +// { +// bufferL[i] *= 0.5f; +// } - machine::get_audio(AUX_L, bufferL, 1.f - raw); - machine::get_audio(AUX_R, bufferR, 1.f - raw); +// _chorus.process(bufferL, bufferR, FRAME_BUFFER_SIZE); - of.out = bufferL; - of.aux = bufferR; - } -}; +// _dc_blockerL.Process(bufferL, FRAME_BUFFER_SIZE); +// _dc_blockerR.Process(bufferR, FRAME_BUFFER_SIZE); -void init_juno60_chorus() -{ - machine::add>(FX, "JU60_chorus"); -} +// get_audio(AUX_L, bufferL, 1.f - raw); +// get_audio(AUX_R, bufferR, 1.f - raw); -MACHINE_INIT(init_juno60_chorus); \ No newline at end of file +// of.out = bufferL; +// of.aux = bufferR; +// } +// }; \ No newline at end of file diff --git a/app/FX/Rev-Dattorro.bin b/app/FX/Rev-Dattorro.bin new file mode 100644 index 0000000000000000000000000000000000000000..f8d93599747c84167534552868141377273b869e GIT binary patch literal 4076 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 literal 0 HcmV?d00001 diff --git a/app/FX/Rev-Dattorro.bin.h b/app/FX/Rev-Dattorro.bin.h deleted file mode 100644 index 5528ef1..0000000 --- a/app/FX/Rev-Dattorro.bin.h +++ /dev/null @@ -1,332 +0,0 @@ -const uint8_t __FX_Rev_Dattorro_bin[] FLASHMEM __attribute__((aligned(32))) = { - 0x55, 0x44, 0x4c, 0x4d, 0x19, 0x00, 0x19, 0x00, 0x04, 0x02, 0x00, 0x00, - 0x58, 0x0c, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x48, 0xf7, 0x01, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0xf4, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x50, - 0x3d, 0x0c, 0x00, 0x00, 0x11, 0x01, 0x00, 0x50, 0xe9, 0x0b, 0x00, 0x00, - 0x24, 0x01, 0x00, 0x50, 0x21, 0x0c, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x50, - 0x05, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x32, 0x01, 0x00, 0x10, 0x30, 0x00, 0x00, 0x00, - 0x46, 0x01, 0x00, 0x10, 0x30, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x10, - 0x30, 0x00, 0x00, 0x00, 0x6d, 0x01, 0x00, 0x10, 0x30, 0x00, 0x00, 0x00, - 0x80, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x87, 0x01, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x97, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x01, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0xb6, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x01, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0xc4, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0xd5, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x01, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x46, 0x58, 0x2f, 0x52, 0x65, 0x76, 0x2d, 0x44, 0x61, 0x74, 0x74, 0x6f, - 0x72, 0x72, 0x6f, 0x00, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, - 0x72, 0x72, 0x61, 0x79, 0x00, 0x5f, 0x5f, 0x75, 0x69, 0x5f, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00, - 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x00, 0x73, 0x65, 0x74, 0x75, - 0x70, 0x00, 0x5f, 0x5f, 0x70, 0x72, 0x65, 0x69, 0x6e, 0x69, 0x74, 0x5f, - 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x5f, 0x5f, - 0x70, 0x72, 0x65, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, - 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x5f, 0x5f, 0x69, 0x6e, - 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, - 0x00, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, - 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x6d, 0x61, 0x6c, 0x6c, - 0x6f, 0x63, 0x00, 0x66, 0x72, 0x65, 0x65, 0x00, 0x5f, 0x5f, 0x75, 0x69, - 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x00, 0x61, 0x64, 0x64, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x5f, 0x69, 0x33, 0x32, 0x00, 0x61, 0x64, 0x64, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x66, 0x33, 0x32, 0x00, 0x70, 0x6f, 0x77, - 0x66, 0x00, 0x63, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x00, 0x6d, 0x65, 0x6d, - 0x73, 0x65, 0x74, 0x00, 0x5f, 0x5f, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5f, - 0x69, 0x6e, 0x5f, 0x6c, 0x5f, 0x66, 0x70, 0x70, 0x00, 0x5f, 0x5f, 0x61, - 0x75, 0x64, 0x69, 0x6f, 0x5f, 0x69, 0x6e, 0x5f, 0x72, 0x5f, 0x66, 0x70, - 0x70, 0x00, 0x5f, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6c, - 0x5f, 0x66, 0x70, 0x00, 0x5f, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x5f, 0x72, 0x5f, 0x66, 0x70, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, - 0x03, 0x30, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, - 0x03, 0x30, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, - 0x03, 0x30, 0x18, 0x47, 0x04, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, - 0x03, 0x30, 0x18, 0x47, 0x04, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, - 0x03, 0x30, 0x18, 0x47, 0x04, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, - 0x03, 0x30, 0x18, 0x47, 0x04, 0x00, 0x00, 0x00, 0x38, 0xb5, 0x08, 0x4b, - 0x59, 0xf8, 0x03, 0x30, 0x1d, 0x68, 0x55, 0xb1, 0x06, 0x4b, 0x59, 0xf8, - 0x03, 0x30, 0x1c, 0x68, 0xe3, 0x88, 0xb4, 0xf9, 0x04, 0x20, 0x61, 0x88, - 0x20, 0x88, 0xa8, 0x47, 0x20, 0x72, 0x38, 0xbd, 0x08, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x10, 0xb4, 0x03, 0x4c, 0x59, 0xf8, 0x04, 0x40, - 0xa4, 0x46, 0x5d, 0xf8, 0x04, 0x4b, 0x60, 0x47, 0x10, 0x00, 0x00, 0x00, - 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, 0x14, 0x00, 0x00, 0x00, - 0x08, 0xb5, 0xdf, 0xed, 0x09, 0x7a, 0xdf, 0xed, 0x09, 0x0a, 0x0a, 0x4b, - 0x30, 0xee, 0x67, 0x0a, 0x59, 0xf8, 0x03, 0x30, 0x60, 0xee, 0x20, 0x0a, - 0xb0, 0xee, 0x00, 0x0a, 0x98, 0x47, 0xdf, 0xed, 0x04, 0x7a, 0x20, 0xee, - 0x27, 0x0a, 0x08, 0xbd, 0x00, 0x00, 0x8a, 0x42, 0xab, 0xaa, 0xaa, 0x3d, - 0x00, 0x00, 0xdc, 0x43, 0x18, 0x00, 0x00, 0x00, 0x03, 0x4b, 0x02, 0x49, - 0x59, 0xf8, 0x03, 0x30, 0x01, 0x20, 0x18, 0x47, 0x44, 0xf7, 0x01, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, - 0x04, 0x00, 0x00, 0x00, 0x70, 0x47, 0x00, 0xbf, 0x00, 0x68, 0x70, 0x47, - 0x02, 0x20, 0x70, 0x47, 0x02, 0x20, 0x70, 0x47, 0x70, 0x47, 0x00, 0xbf, - 0x4f, 0xf0, 0x7c, 0x53, 0x00, 0xf5, 0x80, 0x52, 0x83, 0x60, 0xc0, 0xf8, - 0xa8, 0x30, 0x00, 0xf5, 0xfb, 0x31, 0x02, 0xf2, 0xd4, 0x6c, 0x00, 0xf5, - 0xb7, 0x50, 0x02, 0xf2, 0xec, 0x62, 0xcc, 0xf8, 0x00, 0x30, 0x03, 0x60, - 0x13, 0x60, 0xc1, 0xf8, 0x38, 0x31, 0x70, 0x47, 0x2d, 0xe9, 0xf0, 0x45, - 0x6d, 0x4b, 0x00, 0x25, 0x00, 0x26, 0x04, 0x46, 0x05, 0x61, 0x45, 0x61, - 0x86, 0x61, 0x83, 0xb0, 0x59, 0xf8, 0x03, 0x70, 0x31, 0x46, 0x80, 0x22, - 0x1c, 0x30, 0xb8, 0x47, 0xc4, 0xf8, 0x9c, 0x50, 0xc4, 0xf8, 0xa0, 0x50, - 0xc4, 0xf8, 0xa4, 0x50, 0xc4, 0xf8, 0xac, 0x50, 0xc4, 0xf8, 0xb0, 0x50, - 0x31, 0x46, 0x4f, 0xf4, 0x80, 0x62, 0x04, 0xf1, 0xb4, 0x00, 0xb8, 0x47, - 0x04, 0xf2, 0xb4, 0x43, 0x31, 0x46, 0x1d, 0x60, 0x04, 0xf5, 0x97, 0x63, - 0x4f, 0xf4, 0x00, 0x72, 0x1d, 0x60, 0x04, 0xf2, 0xbc, 0x40, 0xb8, 0x47, - 0x04, 0xf2, 0xbc, 0x63, 0x4f, 0xf4, 0x00, 0x62, 0x1d, 0x60, 0x04, 0xf5, - 0xd8, 0x63, 0x31, 0x46, 0x1d, 0x60, 0x04, 0xf2, 0xc4, 0x60, 0x01, 0x92, - 0xb8, 0x47, 0x04, 0xf6, 0xc4, 0x63, 0x01, 0x9a, 0x1d, 0x60, 0x04, 0xf6, - 0xc8, 0x63, 0x31, 0x46, 0x1d, 0x60, 0x04, 0xf6, 0xcc, 0x60, 0xb8, 0x47, - 0x04, 0xf5, 0x80, 0x53, 0x03, 0xf2, 0xcc, 0x62, 0x4f, 0xf4, 0x80, 0x5a, - 0x15, 0x60, 0x03, 0xf5, 0xda, 0x62, 0x04, 0xf5, 0xb7, 0x50, 0x15, 0x60, - 0x03, 0xf5, 0xdb, 0x62, 0x31, 0x46, 0x15, 0x60, 0x03, 0xf2, 0xdc, 0x62, - 0x18, 0x30, 0x15, 0x60, 0x03, 0xf2, 0xe4, 0x62, 0x4f, 0xf4, 0x00, 0x48, - 0x15, 0x60, 0x03, 0xf5, 0xdd, 0x62, 0x15, 0x60, 0x03, 0xf5, 0xde, 0x62, - 0x03, 0xf2, 0xf4, 0x63, 0x15, 0x60, 0x1d, 0x60, 0x52, 0x46, 0xb8, 0x47, - 0x04, 0xf5, 0x00, 0x53, 0x03, 0xf5, 0xdf, 0x62, 0x03, 0xf2, 0xfc, 0x63, - 0x15, 0x60, 0x31, 0x46, 0x1d, 0x60, 0x42, 0x46, 0x04, 0xf5, 0x1c, 0x50, - 0xb8, 0x47, 0x04, 0xf5, 0x27, 0x43, 0x18, 0x46, 0x4f, 0xf4, 0x80, 0x42, - 0x1d, 0x60, 0x5d, 0x60, 0x31, 0x46, 0x08, 0x30, 0x01, 0x92, 0xb8, 0x47, - 0x04, 0xf5, 0x60, 0x43, 0x03, 0xf5, 0xe1, 0x61, 0x03, 0xf2, 0x0c, 0x73, - 0x04, 0xf5, 0x67, 0x40, 0x0d, 0x60, 0x01, 0x9a, 0x1d, 0x60, 0x31, 0x46, - 0x10, 0x30, 0xb8, 0x47, 0x04, 0xf5, 0x90, 0x33, 0x03, 0xf5, 0xe2, 0x61, - 0x03, 0xf2, 0x14, 0x73, 0x04, 0xf5, 0x93, 0x30, 0x0d, 0x60, 0x52, 0x46, - 0x1d, 0x60, 0x31, 0x46, 0x00, 0xf5, 0x8c, 0x70, 0xb8, 0x47, 0x04, 0xf5, - 0x98, 0x33, 0x03, 0xf5, 0xe3, 0x61, 0x03, 0xf2, 0x1c, 0x73, 0x04, 0xf5, - 0x9b, 0x30, 0x0d, 0x60, 0x42, 0x46, 0x1d, 0x60, 0x31, 0x46, 0x00, 0xf5, - 0x90, 0x70, 0xb8, 0x47, 0x04, 0xf5, 0xd8, 0x33, 0x03, 0xf5, 0xe4, 0x62, - 0x03, 0xf2, 0x24, 0x73, 0x04, 0xf5, 0xdb, 0x30, 0x15, 0x60, 0x31, 0x46, - 0x1d, 0x60, 0x4f, 0xf4, 0x00, 0x52, 0x00, 0xf5, 0x94, 0x70, 0x01, 0x92, - 0xb8, 0x47, 0x04, 0xf5, 0xe8, 0x33, 0x03, 0xf5, 0xe5, 0x60, 0x03, 0xf2, - 0x2c, 0x73, 0x05, 0x60, 0x04, 0xf5, 0xeb, 0x30, 0x01, 0x9a, 0x1d, 0x60, - 0x31, 0x46, 0x00, 0xf5, 0x98, 0x70, 0xb8, 0x47, 0x04, 0xf5, 0xf8, 0x34, - 0x04, 0xf5, 0xe6, 0x61, 0x04, 0xf2, 0x34, 0x72, 0x04, 0xf2, 0x3c, 0x73, - 0x04, 0xf5, 0xe8, 0x64, 0x0d, 0x60, 0x15, 0x60, 0x1d, 0x60, 0x25, 0x60, - 0x03, 0xb0, 0xbd, 0xe8, 0xf0, 0x85, 0x00, 0xbf, 0x20, 0x00, 0x00, 0x00, - 0xdf, 0xed, 0x0b, 0x6a, 0x9f, 0xed, 0x0b, 0x6a, 0x01, 0x60, 0x07, 0xee, - 0x90, 0x1a, 0xb7, 0xee, 0x00, 0x7a, 0xf8, 0xee, 0xe7, 0x7a, 0xc7, 0xfe, - 0x87, 0x7a, 0xc7, 0xfe, 0xe6, 0x7a, 0xc6, 0xee, 0x27, 0x6a, 0x37, 0xee, - 0x66, 0x7a, 0xc0, 0xed, 0x01, 0x6a, 0x80, 0xed, 0x03, 0x7a, 0x70, 0x47, - 0x00, 0x80, 0x3b, 0x48, 0x66, 0x66, 0x30, 0x42, 0xdf, 0xed, 0x16, 0x6a, - 0x9f, 0xed, 0x16, 0x6a, 0x01, 0x60, 0x07, 0xee, 0x90, 0x1a, 0xb7, 0xee, - 0x00, 0x7a, 0xf8, 0xee, 0xe7, 0x7a, 0xc7, 0xfe, 0x87, 0x7a, 0xc7, 0xfe, - 0xe6, 0x7a, 0xc6, 0xee, 0x27, 0x6a, 0x00, 0xf5, 0x80, 0x5c, 0x0c, 0xf2, - 0xd4, 0x61, 0x4f, 0xf0, 0x7c, 0x52, 0x82, 0x60, 0xc0, 0xf8, 0xa8, 0x20, - 0x0c, 0xf2, 0xec, 0x6c, 0x00, 0xf5, 0xfb, 0x33, 0x37, 0xee, 0x66, 0x7a, - 0xc0, 0xed, 0x01, 0x6a, 0x80, 0xed, 0x03, 0x7a, 0x0a, 0x60, 0x00, 0xf5, - 0xb7, 0x51, 0x0a, 0x60, 0xcc, 0xf8, 0x00, 0x20, 0xc3, 0xf8, 0x38, 0x21, - 0xff, 0xf7, 0xd6, 0xbe, 0x00, 0x80, 0x3b, 0x48, 0x66, 0x66, 0x30, 0x42, - 0xdf, 0xed, 0x16, 0x6a, 0x9f, 0xed, 0x16, 0x6a, 0x01, 0x60, 0x07, 0xee, - 0x90, 0x1a, 0xb7, 0xee, 0x00, 0x7a, 0xf8, 0xee, 0xe7, 0x7a, 0xc7, 0xfe, - 0x87, 0x7a, 0xc7, 0xfe, 0xe6, 0x7a, 0xc6, 0xee, 0x27, 0x6a, 0x00, 0xf5, - 0x80, 0x5c, 0x0c, 0xf2, 0xd4, 0x61, 0x4f, 0xf0, 0x7c, 0x52, 0x82, 0x60, - 0xc0, 0xf8, 0xa8, 0x20, 0x0c, 0xf2, 0xec, 0x6c, 0x00, 0xf5, 0xfb, 0x33, - 0x37, 0xee, 0x66, 0x7a, 0xc0, 0xed, 0x01, 0x6a, 0x80, 0xed, 0x03, 0x7a, - 0x0a, 0x60, 0x00, 0xf5, 0xb7, 0x51, 0x0a, 0x60, 0xcc, 0xf8, 0x00, 0x20, - 0xc3, 0xf8, 0x38, 0x21, 0xff, 0xf7, 0xa4, 0xbe, 0x00, 0x80, 0x3b, 0x48, - 0x66, 0x66, 0x30, 0x42, 0xf0, 0xb5, 0x00, 0xf5, 0xfb, 0x33, 0x4f, 0xf0, - 0x7c, 0x56, 0x30, 0x4a, 0x9f, 0xed, 0x2c, 0x0a, 0xc3, 0xf8, 0x38, 0x61, - 0x83, 0xb0, 0x03, 0xf5, 0x9c, 0x71, 0x2d, 0x4b, 0x04, 0x46, 0x59, 0xf8, - 0x02, 0x00, 0x8d, 0xed, 0x00, 0x0a, 0x59, 0xf8, 0x03, 0x50, 0x04, 0xf5, - 0x80, 0x57, 0xf7, 0xee, 0x00, 0x0a, 0xa8, 0x47, 0x07, 0xf2, 0xd4, 0x62, - 0x26, 0x4b, 0x16, 0x60, 0x04, 0xf5, 0xb6, 0x51, 0x59, 0xf8, 0x03, 0x00, - 0x9d, 0xed, 0x00, 0x0a, 0xf7, 0xee, 0x00, 0x0a, 0x14, 0x31, 0xa8, 0x47, - 0x04, 0xf5, 0xb7, 0x51, 0x20, 0x4b, 0x0e, 0x60, 0x59, 0xf8, 0x03, 0x00, - 0x9d, 0xed, 0x00, 0x0a, 0xf7, 0xee, 0x00, 0x0a, 0xa8, 0x47, 0x21, 0x46, - 0x1c, 0x4b, 0x41, 0xf8, 0x08, 0x6f, 0x9d, 0xed, 0x00, 0x0a, 0x59, 0xf8, - 0x03, 0x00, 0xf7, 0xee, 0x00, 0x0a, 0xa8, 0x47, 0x07, 0xf2, 0xec, 0x67, - 0xdf, 0xed, 0x10, 0x0a, 0x16, 0x4b, 0xcd, 0xed, 0x01, 0x0a, 0x9f, 0xed, - 0x0f, 0x0a, 0x3e, 0x60, 0x04, 0xf5, 0xb7, 0x51, 0x59, 0xf8, 0x03, 0x00, - 0x8d, 0xed, 0x00, 0x0a, 0x0c, 0x31, 0xa8, 0x47, 0x21, 0x46, 0x10, 0x4b, - 0x41, 0xf8, 0xa8, 0x6f, 0xdd, 0xed, 0x01, 0x0a, 0x59, 0xf8, 0x03, 0x00, - 0x9d, 0xed, 0x00, 0x0a, 0x2b, 0x46, 0x03, 0xb0, 0xbd, 0xe8, 0xf0, 0x40, - 0x18, 0x47, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x70, 0x7d, 0x3f, - 0x0a, 0xd7, 0x23, 0x3c, 0x24, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x2d, 0xe9, 0xf0, 0x4d, - 0x00, 0xf5, 0x80, 0x5c, 0x2d, 0xed, 0x10, 0x8b, 0xd2, 0xe9, 0x00, 0x54, - 0xd0, 0xed, 0x01, 0xda, 0xd0, 0xed, 0x02, 0x7a, 0x90, 0xed, 0x2a, 0xea, - 0x0c, 0xf2, 0xd4, 0x62, 0xd2, 0xed, 0x00, 0xea, 0x00, 0xf5, 0xb7, 0x52, - 0x6d, 0xee, 0xa7, 0x7a, 0x92, 0xed, 0x00, 0xfa, 0x00, 0xf5, 0xf8, 0x3e, - 0x0c, 0xf2, 0xec, 0x62, 0xd2, 0xed, 0x00, 0xfa, 0x98, 0xb0, 0x0e, 0xf5, - 0xe7, 0x62, 0xcd, 0xed, 0x11, 0x7a, 0xd2, 0xed, 0x00, 0x7a, 0x00, 0x29, - 0x2d, 0xee, 0x8e, 0xea, 0x6d, 0xee, 0xae, 0xea, 0x2d, 0xee, 0x8f, 0xfa, - 0x6d, 0xee, 0xaf, 0xfa, 0xd3, 0xe9, 0x00, 0x23, 0x6d, 0xee, 0xa7, 0xda, - 0x40, 0xf3, 0x7b, 0x82, 0xcd, 0xe9, 0x00, 0x32, 0x83, 0x69, 0xd0, 0xed, - 0x05, 0x7a, 0xd0, 0xed, 0x29, 0xba, 0xd0, 0xed, 0x2c, 0x6a, 0xca, 0x18, - 0x10, 0x92, 0x00, 0xf5, 0x97, 0x62, 0xd2, 0xed, 0x00, 0x8a, 0x14, 0x92, - 0x00, 0xf5, 0xd8, 0x62, 0xd2, 0xed, 0x00, 0x5a, 0x16, 0x92, 0x00, 0xf6, - 0xc8, 0x62, 0x92, 0xed, 0x00, 0x7a, 0x15, 0x92, 0x0c, 0xf5, 0xda, 0x62, - 0x92, 0xed, 0x00, 0x6a, 0x0c, 0xf2, 0xdc, 0x62, 0x92, 0xed, 0x00, 0x0a, - 0x0c, 0xf5, 0xdd, 0x62, 0xcd, 0xe9, 0x02, 0x45, 0x92, 0xed, 0x00, 0x9a, - 0x00, 0xf5, 0x00, 0x54, 0x0c, 0xf2, 0xf4, 0x62, 0x92, 0xed, 0x00, 0x5a, - 0x17, 0x94, 0x04, 0xf2, 0xfc, 0x62, 0xd2, 0xed, 0x00, 0x1a, 0x00, 0xf5, - 0x20, 0x46, 0x0e, 0xf2, 0x34, 0x72, 0x00, 0xf5, 0x60, 0x45, 0x92, 0xed, - 0x00, 0x2a, 0x12, 0x95, 0x06, 0xf2, 0x04, 0x72, 0xd2, 0xed, 0x00, 0xaa, - 0x13, 0x96, 0x05, 0xf2, 0x0c, 0x72, 0x00, 0xf5, 0x98, 0x3b, 0xd2, 0xed, - 0x00, 0x2a, 0x00, 0xf5, 0x90, 0x3a, 0x0b, 0xf2, 0x1c, 0x72, 0x92, 0xed, - 0x00, 0x3a, 0x00, 0xf5, 0xd8, 0x38, 0x0a, 0xf2, 0x14, 0x72, 0xd2, 0xed, - 0x00, 0x3a, 0x00, 0xf5, 0xe8, 0x37, 0x08, 0xf2, 0x24, 0x72, 0x92, 0xed, - 0x00, 0xaa, 0x0e, 0x97, 0x07, 0xf2, 0x2c, 0x72, 0x92, 0xed, 0x00, 0x4a, - 0x0e, 0xf5, 0xe8, 0x62, 0xd2, 0xed, 0x00, 0x9a, 0x00, 0xf2, 0xb4, 0x42, - 0x0a, 0x92, 0x00, 0xf2, 0xbc, 0x62, 0x0d, 0x92, 0x00, 0xf6, 0xc4, 0x62, - 0x0b, 0x92, 0x00, 0xf5, 0x27, 0x42, 0x0c, 0x92, 0x0c, 0xf2, 0xcc, 0x62, - 0x04, 0x92, 0x0c, 0xf5, 0xdb, 0x62, 0x05, 0x92, 0x0c, 0xf2, 0xe4, 0x62, - 0x06, 0x92, 0x0c, 0xf5, 0xde, 0x62, 0x07, 0x92, 0x04, 0xf5, 0xdf, 0x62, - 0x08, 0x92, 0x05, 0xf5, 0xe1, 0x62, 0xb7, 0xee, 0x00, 0xba, 0x09, 0x92, - 0xf0, 0xee, 0x40, 0x4a, 0x90, 0xed, 0x03, 0x1a, 0x9d, 0xed, 0x11, 0x0a, - 0x03, 0x9a, 0x0a, 0x99, 0x0d, 0x9d, 0x0b, 0x9e, 0x04, 0x9f, 0xa1, 0xee, - 0x27, 0x0a, 0xf0, 0xee, 0x4e, 0x7a, 0x80, 0xed, 0x04, 0x0a, 0xe1, 0xee, - 0x26, 0x7a, 0xf0, 0xee, 0x6f, 0x6a, 0xe1, 0xee, 0x05, 0x6a, 0xb2, 0xec, - 0x01, 0x5a, 0x03, 0x92, 0x02, 0x9a, 0xf2, 0xec, 0x01, 0xca, 0x35, 0xee, - 0x2c, 0xda, 0x02, 0x92, 0x03, 0xf0, 0x1f, 0x02, 0x00, 0xeb, 0x82, 0x02, - 0x82, 0xed, 0x07, 0xda, 0xa3, 0xf1, 0x18, 0x02, 0xf0, 0xee, 0x6e, 0x0a, - 0xb0, 0xee, 0x4f, 0x8a, 0x02, 0xf0, 0x1f, 0x02, 0xe1, 0xee, 0x24, 0x0a, - 0x00, 0xeb, 0x82, 0x02, 0xa1, 0xee, 0x09, 0x8a, 0xf6, 0xee, 0x00, 0x4a, - 0xb0, 0xee, 0x6d, 0x9a, 0xa1, 0xee, 0x29, 0x9a, 0x60, 0xee, 0x24, 0x4a, - 0xd2, 0xed, 0x07, 0x9a, 0xc0, 0xed, 0x2b, 0x7a, 0x3b, 0xee, 0x40, 0x0a, - 0x64, 0xee, 0xa9, 0x4a, 0xda, 0xb2, 0xe0, 0xee, 0x2b, 0x4a, 0x00, 0xeb, - 0x82, 0x02, 0xb0, 0xee, 0x68, 0xca, 0xf0, 0xee, 0x64, 0xba, 0xe7, 0xee, - 0xe8, 0xba, 0xc0, 0xed, 0x27, 0x4a, 0xa7, 0xee, 0xe5, 0xca, 0xc2, 0xed, - 0x2d, 0xba, 0xa3, 0xf1, 0x8e, 0x02, 0xd2, 0xb2, 0x00, 0xeb, 0x82, 0x02, - 0xa7, 0xee, 0xab, 0xca, 0xd2, 0xf8, 0xb4, 0x20, 0x0a, 0x60, 0x03, 0xf0, - 0x7f, 0x02, 0x02, 0xf5, 0x97, 0x72, 0x00, 0xeb, 0x82, 0x02, 0x82, 0xed, - 0x01, 0xca, 0xa3, 0xf1, 0x6b, 0x02, 0xe7, 0xee, 0xc7, 0x5a, 0x02, 0xf0, - 0x7f, 0x02, 0x02, 0xf5, 0x97, 0x72, 0x00, 0xeb, 0x82, 0x02, 0xe7, 0xee, - 0x8c, 0x5a, 0x52, 0x68, 0x2a, 0x60, 0xa7, 0xee, 0xc6, 0x7a, 0x6f, 0xf4, - 0xbd, 0x72, 0x9a, 0x18, 0xc3, 0xf3, 0x08, 0x01, 0xc2, 0xf3, 0x08, 0x02, - 0xa7, 0xee, 0xa5, 0x7a, 0x00, 0xeb, 0x81, 0x01, 0x02, 0xf5, 0xd8, 0x72, - 0x01, 0xf2, 0xc4, 0x64, 0x00, 0xeb, 0x82, 0x02, 0xc4, 0xed, 0x00, 0x5a, - 0x52, 0x68, 0x32, 0x60, 0x01, 0xf6, 0xcc, 0x61, 0x81, 0xed, 0x00, 0x7a, - 0x6f, 0xf4, 0x8a, 0x71, 0x5a, 0x18, 0xc2, 0xf3, 0x08, 0x02, 0x02, 0xf2, - 0xb2, 0x32, 0x00, 0xeb, 0x82, 0x02, 0x06, 0x99, 0x52, 0x68, 0x3a, 0x60, - 0x05, 0x9a, 0xc2, 0xed, 0x00, 0x0a, 0x81, 0xed, 0x00, 0x8a, 0x07, 0x9d, - 0x08, 0x9e, 0xc5, 0xed, 0x00, 0x6a, 0xa6, 0xee, 0xa1, 0x2a, 0xa3, 0xf5, - 0x63, 0x72, 0xc3, 0xf3, 0x09, 0x05, 0xc2, 0xf3, 0x09, 0x02, 0x00, 0xeb, - 0x85, 0x05, 0x02, 0xf2, 0xbe, 0x52, 0x05, 0xf5, 0xb7, 0x51, 0x00, 0xeb, - 0x82, 0x02, 0x81, 0xed, 0x06, 0x2a, 0x12, 0x68, 0x32, 0x60, 0xe6, 0xee, - 0xc2, 0x1a, 0xa3, 0xf5, 0x83, 0x52, 0xc3, 0xf3, 0x0c, 0x04, 0x19, 0x3a, - 0x00, 0xeb, 0x84, 0x04, 0xc2, 0xf3, 0x0c, 0x02, 0x04, 0xf5, 0x1c, 0x51, - 0x02, 0xf5, 0x1c, 0x62, 0xc1, 0xed, 0x00, 0x1a, 0x00, 0xeb, 0x82, 0x02, - 0xd2, 0xed, 0x00, 0x5a, 0x0c, 0x9a, 0x3b, 0xee, 0x48, 0x0a, 0x62, 0xee, - 0xe6, 0x9a, 0x60, 0xee, 0x25, 0x5a, 0xc3, 0xf3, 0x0b, 0x01, 0xe8, 0xee, - 0x2a, 0x5a, 0x00, 0xeb, 0x81, 0x01, 0x01, 0xf5, 0x27, 0x46, 0x01, 0xf5, - 0x67, 0x41, 0xe0, 0xee, 0xa5, 0x9a, 0x05, 0xf5, 0x93, 0x35, 0x04, 0xf5, - 0x9b, 0x34, 0xc2, 0xed, 0x00, 0x5a, 0xa3, 0xf5, 0x26, 0x62, 0xc2, 0xf3, - 0x0b, 0x02, 0x00, 0xeb, 0x82, 0x02, 0xc6, 0xed, 0x02, 0x9a, 0xe6, 0xee, - 0xa9, 0x2a, 0x02, 0xf5, 0x27, 0x46, 0x02, 0xf5, 0x67, 0x42, 0xb7, 0x68, - 0x09, 0x9e, 0x37, 0x60, 0xc1, 0xed, 0x04, 0x2a, 0xd2, 0xed, 0x04, 0x2a, - 0xf0, 0xee, 0x46, 0x5a, 0xe0, 0xee, 0xa2, 0x5a, 0xa3, 0xf5, 0x28, 0x71, - 0xc1, 0xf3, 0x09, 0x01, 0xe6, 0xee, 0x83, 0x3a, 0xa3, 0xf5, 0x8b, 0x52, - 0x01, 0xf5, 0x93, 0x41, 0xe7, 0xee, 0x87, 0x5a, 0x46, 0x31, 0x05, 0x3a, - 0xa6, 0xee, 0xe3, 0x3a, 0x0a, 0xf5, 0xe2, 0x67, 0x00, 0xeb, 0x81, 0x01, - 0x3b, 0xee, 0x49, 0x1a, 0xc2, 0xf3, 0x0c, 0x02, 0xc7, 0xed, 0x00, 0x5a, - 0x0b, 0xf5, 0xe3, 0x66, 0xc5, 0xed, 0x46, 0x3a, 0x02, 0xf5, 0x9b, 0x42, - 0x09, 0x68, 0x31, 0x60, 0x25, 0xee, 0x01, 0x5a, 0x48, 0x32, 0x84, 0xed, - 0x48, 0x3a, 0x00, 0xeb, 0x82, 0x02, 0xa5, 0xee, 0x89, 0x5a, 0xc3, 0xf3, - 0x0a, 0x01, 0x00, 0xeb, 0x81, 0x01, 0xd2, 0xed, 0x00, 0x5a, 0x60, 0xee, - 0x25, 0x5a, 0x64, 0xee, 0x66, 0x4a, 0xe8, 0xee, 0x0a, 0x5a, 0xa3, 0xf5, - 0xe1, 0x62, 0xc2, 0xf3, 0x0a, 0x02, 0x01, 0xf5, 0xdb, 0x34, 0xe0, 0xee, - 0xa5, 0x4a, 0x08, 0xf5, 0xe4, 0x65, 0x00, 0xeb, 0x82, 0x02, 0xc5, 0xed, - 0x00, 0x5a, 0xa6, 0xee, 0xa4, 0x4a, 0x01, 0xf5, 0xeb, 0x31, 0x01, 0x33, - 0xc4, 0xed, 0x4a, 0x4a, 0x02, 0xf5, 0xdb, 0x34, 0xd4, 0xed, 0x4a, 0x6a, - 0x0e, 0x9c, 0x04, 0xf5, 0xe5, 0x64, 0xc4, 0xed, 0x00, 0x6a, 0x02, 0xf5, - 0xeb, 0x32, 0x81, 0xed, 0x4c, 0x4a, 0xd2, 0xed, 0x4c, 0x6a, 0x0f, 0x94, - 0xa0, 0xee, 0xa6, 0x6a, 0x0e, 0xf5, 0xe6, 0x61, 0x0e, 0xf2, 0x3c, 0x72, - 0xa7, 0xee, 0x87, 0x6a, 0x81, 0xed, 0x00, 0x6a, 0x82, 0xed, 0x00, 0x9a, - 0x01, 0x9c, 0xa4, 0xec, 0x01, 0x5a, 0x91, 0xed, 0x00, 0x7a, 0xd2, 0xed, - 0x00, 0x7a, 0x01, 0x94, 0x67, 0xee, 0x87, 0x7a, 0x00, 0x9c, 0xec, 0xee, - 0x81, 0x7a, 0xe4, 0xec, 0x01, 0x7a, 0x00, 0x94, 0x0a, 0x9c, 0xd0, 0xed, - 0x28, 0xba, 0xd4, 0xed, 0x00, 0x8a, 0x0d, 0x9c, 0x90, 0xed, 0x27, 0x6a, - 0xd4, 0xed, 0x00, 0x5a, 0x0b, 0x9c, 0xd0, 0xed, 0x04, 0x7a, 0x94, 0xed, - 0x00, 0x7a, 0xd0, 0xed, 0x2b, 0x6a, 0x14, 0x9c, 0x80, 0xed, 0x28, 0x6a, - 0xc0, 0xed, 0x05, 0x7a, 0xc0, 0xed, 0x29, 0xba, 0xc0, 0xed, 0x2c, 0x6a, - 0xc4, 0xed, 0x00, 0x8a, 0x16, 0x9c, 0xd7, 0xed, 0x00, 0x3a, 0xc4, 0xed, - 0x00, 0x5a, 0x15, 0x9c, 0x96, 0xed, 0x00, 0x3a, 0x84, 0xed, 0x00, 0x7a, - 0x0f, 0x9c, 0x95, 0xed, 0x00, 0xaa, 0x94, 0xed, 0x00, 0x4a, 0xd2, 0xed, - 0x00, 0x9a, 0x05, 0x9a, 0x08, 0x9e, 0x04, 0x9f, 0xd2, 0xed, 0x00, 0x4a, - 0x0c, 0x9a, 0x91, 0xed, 0x00, 0x2a, 0xd6, 0xed, 0x00, 0x1a, 0x97, 0xed, - 0x00, 0x6a, 0x06, 0x99, 0x07, 0x9d, 0x09, 0x9e, 0xd2, 0xed, 0x00, 0xaa, - 0x91, 0xed, 0x00, 0x9a, 0x95, 0xed, 0x00, 0x5a, 0xd6, 0xed, 0x00, 0x2a, - 0x0e, 0x9c, 0x0c, 0xf5, 0xda, 0x62, 0x82, 0xed, 0x00, 0x6a, 0x0c, 0xf2, - 0xdc, 0x62, 0xc2, 0xed, 0x00, 0x4a, 0x0c, 0xf5, 0xdd, 0x62, 0x82, 0xed, - 0x00, 0x9a, 0x0c, 0xf2, 0xf4, 0x62, 0x82, 0xed, 0x00, 0x5a, 0x17, 0x9a, - 0x02, 0xf2, 0xfc, 0x62, 0xc2, 0xed, 0x00, 0x1a, 0x13, 0x9a, 0x02, 0xf2, - 0x04, 0x72, 0xc2, 0xed, 0x00, 0xaa, 0x12, 0x9a, 0x02, 0xf2, 0x0c, 0x72, - 0xc2, 0xed, 0x00, 0x2a, 0x0a, 0xf2, 0x14, 0x72, 0xc2, 0xed, 0x00, 0x3a, - 0x0b, 0xf2, 0x1c, 0x72, 0x82, 0xed, 0x00, 0x3a, 0x08, 0xf2, 0x24, 0x72, - 0x82, 0xed, 0x00, 0xaa, 0x04, 0xf2, 0x2c, 0x72, 0x82, 0xed, 0x00, 0x4a, - 0x0e, 0xf2, 0x34, 0x72, 0x82, 0xed, 0x00, 0x2a, 0x0e, 0xf5, 0xe8, 0x62, - 0xc2, 0xed, 0x00, 0x9a, 0x10, 0x9a, 0x9a, 0x42, 0x7f, 0xf4, 0x0a, 0xae, - 0x82, 0x61, 0x18, 0xb0, 0xbd, 0xec, 0x10, 0x8b, 0xbd, 0xe8, 0xf0, 0x8d, - 0x06, 0x49, 0x07, 0x4a, 0x59, 0xf8, 0x01, 0x00, 0x9f, 0xed, 0x03, 0x0a, - 0x59, 0xf8, 0x02, 0x20, 0xf7, 0xee, 0x00, 0x0a, 0x19, 0x46, 0x10, 0x47, - 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x70, 0x47, 0x00, 0xbf, 0x10, 0x46, 0x19, 0x46, 0x4b, 0xb1, 0x9f, 0xed, - 0x05, 0x0a, 0x05, 0x4a, 0x83, 0xed, 0x00, 0x0a, 0x59, 0xf8, 0x02, 0x20, - 0xf7, 0xee, 0x00, 0x0a, 0x10, 0x47, 0x70, 0x47, 0x00, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x82, 0xb0, 0x01, 0x93, 0x73, 0xb1, 0x19, 0x46, - 0x07, 0x4b, 0x81, 0xed, 0x00, 0x0a, 0xf0, 0xee, 0x60, 0x7a, 0x59, 0xf8, - 0x03, 0x30, 0xf0, 0xee, 0x41, 0x0a, 0x10, 0x46, 0xb0, 0xee, 0x67, 0x0a, - 0x02, 0xb0, 0x18, 0x47, 0x02, 0xb0, 0x70, 0x47, 0x14, 0x00, 0x00, 0x00, - 0xf0, 0xee, 0x60, 0x7a, 0x10, 0x46, 0xf0, 0xee, 0x41, 0x0a, 0x19, 0x46, - 0x3b, 0xb1, 0x04, 0x4a, 0x83, 0xed, 0x00, 0x0a, 0x59, 0xf8, 0x02, 0x20, - 0xb0, 0xee, 0x67, 0x0a, 0x10, 0x47, 0x70, 0x47, 0x14, 0x00, 0x00, 0x00, - 0x10, 0xb5, 0x16, 0x4b, 0x14, 0x49, 0x59, 0xf8, 0x03, 0x40, 0xdf, 0xf8, - 0x54, 0xc0, 0x61, 0x60, 0x04, 0xf5, 0x80, 0x52, 0x4b, 0xf6, 0x80, 0x30, - 0x20, 0x60, 0x02, 0xf2, 0xd4, 0x60, 0x02, 0xf2, 0xec, 0x62, 0x4f, 0xf0, - 0x7c, 0x53, 0x13, 0x60, 0x04, 0xf5, 0xfb, 0x31, 0x04, 0xf5, 0xb7, 0x52, - 0x82, 0xb0, 0x03, 0x60, 0x20, 0x46, 0xc1, 0xf8, 0x38, 0x31, 0xc4, 0xf8, - 0x0c, 0xc0, 0xa3, 0x60, 0xc4, 0xf8, 0xa8, 0x30, 0x13, 0x60, 0xff, 0xf7, - 0x05, 0xfb, 0x01, 0xa9, 0x20, 0x46, 0xff, 0xf7, 0x61, 0xfc, 0x02, 0xb0, - 0x10, 0xbd, 0x00, 0xbf, 0x44, 0xd8, 0x70, 0x3a, 0x40, 0x00, 0x00, 0x00, - 0xca, 0xc3, 0x7f, 0x3f, 0x10, 0xb5, 0x10, 0x4a, 0x10, 0x4b, 0x59, 0xf8, - 0x02, 0x20, 0x10, 0x48, 0x11, 0x68, 0x10, 0x4a, 0x09, 0x68, 0x84, 0xb0, - 0x00, 0x91, 0x59, 0xf8, 0x03, 0x30, 0x0e, 0x49, 0x1c, 0x68, 0x24, 0x68, - 0x01, 0x94, 0x59, 0xf8, 0x00, 0x00, 0x00, 0x68, 0x02, 0x90, 0x59, 0xf8, - 0x02, 0x00, 0x00, 0x68, 0x03, 0x90, 0x59, 0xf8, 0x01, 0x00, 0x02, 0xab, - 0x6a, 0x46, 0x18, 0x21, 0xff, 0xf7, 0xac, 0xfc, 0x04, 0xb0, 0x10, 0xbd, - 0x44, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0xb5, 0x10, 0x4a, - 0x10, 0x4b, 0x59, 0xf8, 0x02, 0x60, 0x59, 0xf8, 0x03, 0x50, 0x76, 0x1b, - 0xb6, 0x10, 0x06, 0xd0, 0x00, 0x24, 0x55, 0xf8, 0x04, 0x3b, 0x01, 0x34, - 0x98, 0x47, 0xa6, 0x42, 0xf9, 0xd1, 0x0a, 0x4a, 0x0a, 0x4b, 0x59, 0xf8, - 0x02, 0x60, 0x59, 0xf8, 0x03, 0x50, 0x76, 0x1b, 0xb6, 0x10, 0x06, 0xd0, - 0x00, 0x24, 0x55, 0xf8, 0x04, 0x3b, 0x01, 0x34, 0x98, 0x47, 0xa6, 0x42, - 0xf9, 0xd1, 0x70, 0xbd, 0x54, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x2d, 0xe9, 0x00, 0x42, - 0x02, 0xb4, 0xdf, 0xf8, 0x10, 0x10, 0xd1, 0xf8, 0x00, 0x90, 0x02, 0xbc, - 0xff, 0xf7, 0x26, 0xfa, 0xbd, 0xe8, 0x00, 0x82, 0x00, 0x00, 0x00, 0x20, - 0x2d, 0xe9, 0x00, 0x42, 0x02, 0xb4, 0xdf, 0xf8, 0x10, 0x10, 0xd1, 0xf8, - 0x00, 0x90, 0x02, 0xbc, 0xff, 0xf7, 0x60, 0xff, 0xbd, 0xe8, 0x00, 0x82, - 0x00, 0x00, 0x00, 0x20, 0x2d, 0xe9, 0x00, 0x42, 0x02, 0xb4, 0xdf, 0xf8, - 0x10, 0x10, 0xd1, 0xf8, 0x00, 0x90, 0x02, 0xbc, 0xff, 0xf7, 0x84, 0xff, - 0xbd, 0xe8, 0x00, 0x82, 0x00, 0x00, 0x00, 0x20, 0x2d, 0xe9, 0x00, 0x42, - 0x02, 0xb4, 0xdf, 0xf8, 0x10, 0x10, 0xd1, 0xf8, 0x00, 0x90, 0x02, 0xbc, - 0xff, 0xf7, 0xa2, 0xff, 0xbd, 0xe8, 0x00, 0x82, 0x00, 0x00, 0x00, 0x20, - 0x44, 0x2f, 0x57, 0x00, 0x44, 0x65, 0x63, 0x61, 0x79, 0x00, 0x00, 0x00, - 0x44, 0x61, 0x6d, 0x70, 0x00, 0x00, 0x00, 0x00, 0x42, 0x57, 0x00, 0x00, - 0x44, 0x44, 0x69, 0x66, 0x66, 0x00, 0x00, 0x00, 0x49, 0x44, 0x69, 0x66, - 0x66, 0x00, 0x00, 0x00, 0x54, 0x52, 0x49, 0x47, 0x00, 0x00, 0x00, 0x00 -}; -unsigned int __FX_Rev_Dattorro_bin_len = 3948; diff --git a/app/FX/Reverb-HP-LP.bin b/app/FX/Reverb-HP-LP.bin new file mode 100644 index 0000000000000000000000000000000000000000..89904d8b1462c2bfee8aafd8b492e5710f690174 GIT binary patch literal 5272 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 B5dZ)H literal 0 HcmV?d00001 diff --git a/app/FX/Reverb-HP-LP.bin.h b/app/FX/Reverb-HP-LP.bin.h deleted file mode 100644 index 6aeee5c..0000000 --- a/app/FX/Reverb-HP-LP.bin.h +++ /dev/null @@ -1,432 +0,0 @@ -const uint8_t __FX_Reverb_HP_LP_bin[] FLASHMEM __attribute__((aligned(32))) = { - 0x55, 0x44, 0x4c, 0x4d, 0x16, 0x00, 0x16, 0x00, 0xe4, 0x01, 0x00, 0x00, - 0x54, 0x11, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x01, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, - 0xdc, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x50, - 0x39, 0x11, 0x00, 0x00, 0xf9, 0x00, 0x00, 0x50, 0xe5, 0x10, 0x00, 0x00, - 0x0c, 0x01, 0x00, 0x50, 0x1d, 0x11, 0x00, 0x00, 0x14, 0x01, 0x00, 0x50, - 0x01, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x1a, 0x01, 0x00, 0x10, 0x14, 0x00, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x10, - 0x14, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x10, 0x14, 0x00, 0x00, 0x00, - 0x55, 0x01, 0x00, 0x10, 0x14, 0x00, 0x00, 0x00, 0x68, 0x01, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x6e, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x75, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x01, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x85, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x92, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x01, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0xa6, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0xd6, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x46, 0x58, 0x2f, 0x52, 0x65, 0x76, 0x65, 0x72, 0x62, 0x2d, 0x48, 0x50, - 0x2d, 0x4c, 0x50, 0x00, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, - 0x72, 0x72, 0x61, 0x79, 0x00, 0x5f, 0x5f, 0x75, 0x69, 0x5f, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00, - 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x00, 0x73, 0x65, 0x74, 0x75, - 0x70, 0x00, 0x5f, 0x5f, 0x70, 0x72, 0x65, 0x69, 0x6e, 0x69, 0x74, 0x5f, - 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x5f, 0x5f, - 0x70, 0x72, 0x65, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, - 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x5f, 0x5f, 0x69, 0x6e, - 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, - 0x00, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, - 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x65, 0x78, 0x70, 0x32, - 0x66, 0x00, 0x6d, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x00, 0x66, 0x72, 0x65, - 0x65, 0x00, 0x5f, 0x5f, 0x75, 0x69, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x00, 0x61, 0x64, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x69, 0x33, - 0x32, 0x00, 0x61, 0x64, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x66, - 0x33, 0x32, 0x00, 0x6d, 0x65, 0x6d, 0x73, 0x65, 0x74, 0x00, 0x5f, 0x5f, - 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5f, 0x69, 0x6e, 0x5f, 0x6c, 0x5f, 0x66, - 0x70, 0x70, 0x00, 0x5f, 0x5f, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5f, 0x69, - 0x6e, 0x5f, 0x72, 0x5f, 0x66, 0x70, 0x70, 0x00, 0x5f, 0x5f, 0x6f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x5f, 0x72, 0x5f, 0x66, 0x70, 0x00, 0x5f, 0x5f, - 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6c, 0x5f, 0x66, 0x70, 0x00, - 0x2d, 0xe9, 0xf0, 0x4d, 0x02, 0x68, 0xc7, 0x6c, 0xcf, 0x4d, 0x87, 0xfb, - 0x05, 0x31, 0x4f, 0xea, 0x41, 0x21, 0x41, 0xea, 0xd3, 0x53, 0x88, 0xb0, - 0x04, 0x46, 0x02, 0x97, 0x13, 0x44, 0x03, 0xf3, 0x17, 0x03, 0x00, 0x20, - 0xc4, 0xf8, 0x94, 0x30, 0x83, 0xfb, 0x00, 0x12, 0x4f, 0xea, 0x42, 0x22, - 0x42, 0xea, 0xd1, 0x51, 0x01, 0xf3, 0x17, 0x01, 0xc4, 0x4b, 0x87, 0xfb, - 0x03, 0x26, 0x4f, 0xea, 0x46, 0x26, 0x46, 0xea, 0xd2, 0x52, 0x11, 0x44, - 0x01, 0xf3, 0x17, 0x01, 0x4f, 0xf4, 0x00, 0x03, 0x81, 0xfb, 0x03, 0x26, - 0x4f, 0xea, 0x46, 0x26, 0x46, 0xea, 0xd2, 0x52, 0x02, 0xf5, 0xff, 0x02, - 0x02, 0xf5, 0xbe, 0x42, 0x02, 0xf3, 0x17, 0x02, 0x82, 0xfb, 0x05, 0x81, - 0x4f, 0xea, 0x41, 0x21, 0x41, 0xea, 0xd8, 0x58, 0x08, 0xf3, 0x17, 0x08, - 0xc4, 0xf8, 0x90, 0x80, 0x88, 0xfb, 0x00, 0x52, 0x4f, 0xea, 0x42, 0x22, - 0x42, 0xea, 0xd5, 0x55, 0x05, 0xf3, 0x17, 0x05, 0x87, 0xfb, 0x03, 0x21, - 0x4f, 0xea, 0x41, 0x21, 0x41, 0xea, 0xd2, 0x52, 0x15, 0x44, 0x05, 0xf3, - 0x17, 0x05, 0xc4, 0xf8, 0x8c, 0x50, 0x85, 0xfb, 0x03, 0x12, 0x4f, 0xea, - 0x42, 0x22, 0x42, 0xea, 0xd1, 0x51, 0x01, 0xf3, 0x17, 0x01, 0x81, 0xfb, - 0x03, 0x26, 0x4f, 0xea, 0x46, 0x26, 0x46, 0xea, 0xd2, 0x52, 0xa2, 0xf5, - 0x80, 0x03, 0x03, 0xf3, 0x17, 0x03, 0x83, 0x42, 0x13, 0xdc, 0x83, 0xfb, - 0x00, 0x52, 0x4f, 0xea, 0x42, 0x22, 0x42, 0xea, 0xd5, 0x55, 0x05, 0xf5, - 0x80, 0x05, 0x05, 0xf3, 0x17, 0x05, 0xc4, 0xf8, 0x8c, 0x50, 0x85, 0xfb, - 0x00, 0x32, 0x4f, 0xea, 0x42, 0x22, 0x42, 0xea, 0xd3, 0x53, 0x03, 0xf3, - 0x17, 0x03, 0x00, 0x23, 0x03, 0xf3, 0x17, 0x03, 0x4f, 0xf4, 0x00, 0x02, - 0xd4, 0xf8, 0x50, 0xa0, 0x8a, 0xfb, 0x02, 0x10, 0x4f, 0xea, 0x40, 0x20, - 0x40, 0xea, 0xd1, 0x51, 0x0b, 0x44, 0x03, 0xf3, 0x17, 0x03, 0x4f, 0xf4, - 0x80, 0x01, 0x83, 0xfb, 0x01, 0x20, 0x4f, 0xea, 0x40, 0x20, 0x40, 0xea, - 0xd2, 0x52, 0xa2, 0xf5, 0x80, 0x03, 0x03, 0xf3, 0x17, 0x03, 0x00, 0x2b, - 0xc0, 0xf2, 0x5d, 0x85, 0x87, 0x4b, 0x4f, 0xf4, 0x00, 0x02, 0x83, 0xfb, - 0x02, 0x10, 0x4f, 0xea, 0x40, 0x20, 0x40, 0xea, 0xd1, 0x51, 0x01, 0xf3, - 0x17, 0x03, 0x00, 0x21, 0x05, 0x93, 0xc4, 0xf8, 0xb8, 0x30, 0x1e, 0x46, - 0x86, 0xfb, 0x01, 0x30, 0x4f, 0xea, 0x40, 0x20, 0x40, 0xea, 0xd3, 0x53, - 0x03, 0xf3, 0x17, 0x03, 0x66, 0x6d, 0x86, 0xfb, 0x02, 0x10, 0x4f, 0xea, - 0x40, 0x20, 0x40, 0xea, 0xd1, 0x51, 0x0b, 0x44, 0x03, 0xf3, 0x17, 0x03, - 0x4f, 0xf4, 0x80, 0x01, 0x83, 0xfb, 0x01, 0x20, 0x4f, 0xea, 0x40, 0x20, - 0x40, 0xea, 0xd2, 0x52, 0xa2, 0xf5, 0x80, 0x03, 0x03, 0xf3, 0x17, 0x03, - 0x00, 0x2b, 0xc0, 0xf2, 0x3c, 0x85, 0x6f, 0x4a, 0x4f, 0xf4, 0x00, 0x03, - 0x82, 0xfb, 0x03, 0x10, 0x4f, 0xea, 0x40, 0x20, 0x40, 0xea, 0xd1, 0x51, - 0x01, 0xf3, 0x17, 0x01, 0x00, 0x22, 0xc4, 0xf8, 0xbc, 0x10, 0x01, 0x91, - 0x0f, 0x46, 0x87, 0xfb, 0x02, 0x01, 0x4f, 0xea, 0x41, 0x21, 0x41, 0xea, - 0xd0, 0x50, 0x00, 0xf3, 0x17, 0x00, 0x62, 0x49, 0x8a, 0xfb, 0x01, 0xce, - 0x4f, 0xea, 0x4e, 0x2e, 0x4e, 0xea, 0xdc, 0x5c, 0x84, 0x44, 0x0c, 0xf3, - 0x17, 0x0c, 0x8c, 0xfb, 0x03, 0x0e, 0x4f, 0xea, 0x4e, 0x2e, 0x4e, 0xea, - 0xd0, 0x50, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf5, 0xbe, 0x40, 0x00, 0xf3, - 0x17, 0x00, 0x80, 0xfb, 0x03, 0xec, 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, - 0xde, 0x5e, 0x0e, 0xf3, 0x17, 0x0e, 0x8e, 0xfb, 0x00, 0xca, 0x4f, 0xea, - 0x4a, 0x2a, 0x4a, 0xea, 0xdc, 0x5c, 0x0c, 0xf3, 0x17, 0x0c, 0x8c, 0xfb, - 0x00, 0xea, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xde, 0x5e, 0x0e, 0xf3, - 0x17, 0x00, 0xc4, 0xf8, 0xd4, 0x00, 0x06, 0x90, 0x07, 0x46, 0x87, 0xfb, - 0x02, 0x0c, 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, 0xd0, 0x50, 0x00, 0xf3, - 0x17, 0x00, 0x86, 0xfb, 0x03, 0xce, 0x4f, 0xea, 0x4e, 0x2e, 0x4e, 0xea, - 0xdc, 0x5c, 0x60, 0x44, 0x00, 0xf3, 0x17, 0x00, 0x80, 0xfb, 0x06, 0xce, - 0x4f, 0xea, 0x4e, 0x2e, 0x4e, 0xea, 0xdc, 0x5c, 0x0c, 0xf3, 0x17, 0x0c, - 0x8c, 0xfb, 0x06, 0x0e, 0x4f, 0xea, 0x4e, 0x2e, 0x4e, 0xea, 0xd0, 0x50, - 0x00, 0xf3, 0x17, 0x00, 0x80, 0xfb, 0x06, 0xce, 0x4f, 0xea, 0x4e, 0x2e, - 0x4e, 0xea, 0xdc, 0x5c, 0x0c, 0xf3, 0x17, 0x06, 0xc4, 0xf8, 0xd8, 0x60, - 0x07, 0x96, 0x37, 0x46, 0x87, 0xfb, 0x02, 0x06, 0x4f, 0xea, 0x46, 0x26, - 0x46, 0xea, 0xd0, 0x50, 0x00, 0xf3, 0x17, 0x00, 0xe7, 0x6d, 0x04, 0x97, - 0x4f, 0xf4, 0x00, 0x16, 0x87, 0xfb, 0x06, 0xce, 0x4f, 0xea, 0x4e, 0x2e, - 0x4e, 0xea, 0xdc, 0x5c, 0x60, 0x44, 0x00, 0xf3, 0x17, 0x00, 0x27, 0x6e, - 0x03, 0x97, 0x87, 0xfb, 0x06, 0xce, 0x4f, 0xea, 0x4e, 0x2e, 0x4e, 0xea, - 0xdc, 0x5c, 0x60, 0x44, 0x00, 0xf3, 0x17, 0x00, 0x80, 0xfb, 0x08, 0xc6, - 0x4f, 0xea, 0x46, 0x26, 0x46, 0xea, 0xdc, 0x5c, 0x0c, 0xf3, 0x17, 0x0c, - 0x04, 0xf5, 0x80, 0x30, 0xd0, 0xf8, 0x0c, 0x01, 0x00, 0xf1, 0xca, 0x06, - 0xc6, 0xf3, 0x0e, 0x06, 0x04, 0xeb, 0x46, 0x06, 0xb6, 0xf9, 0x0c, 0xe1, - 0x4f, 0xea, 0x0e, 0x2e, 0x0e, 0xf3, 0x17, 0x06, 0xdf, 0xf8, 0x64, 0xb0, - 0x8e, 0xfb, 0x0b, 0x8a, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, - 0xc4, 0x44, 0x0c, 0xf3, 0x17, 0x0c, 0xc0, 0xf3, 0x0e, 0x0e, 0x04, 0xeb, - 0x4e, 0x0e, 0x4f, 0xea, 0x2c, 0x28, 0x10, 0x4f, 0xae, 0xf8, 0x0c, 0x81, - 0x8c, 0xfb, 0x07, 0xe8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xde, 0x5e, - 0x0e, 0xf3, 0x17, 0x0e, 0x76, 0x44, 0x06, 0xf3, 0x17, 0x06, 0x00, 0xf5, - 0x3a, 0x7c, 0xcc, 0xf3, 0x0e, 0x0c, 0x04, 0xeb, 0x4c, 0x0c, 0xbc, 0xf9, - 0x0c, 0xe1, 0x4f, 0xea, 0x0e, 0x2e, 0x0e, 0xf3, 0x17, 0x0c, 0x09, 0xe0, - 0x00, 0xdf, 0xff, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x7f, 0x00, - 0x00, 0x20, 0xb3, 0xff, 0x00, 0xc0, 0x4c, 0x00, 0x8e, 0xfb, 0x0b, 0x8a, - 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, 0x46, 0x44, 0x06, 0xf3, - 0x17, 0x06, 0x00, 0xf1, 0xcb, 0x0e, 0xce, 0xf3, 0x0e, 0x0e, 0x04, 0xeb, - 0x4e, 0x0e, 0x4f, 0xea, 0x26, 0x28, 0xae, 0xf8, 0x0c, 0x81, 0x86, 0xfb, - 0x07, 0xe8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xde, 0x5e, 0x0e, 0xf3, - 0x17, 0x0e, 0xf4, 0x44, 0x0c, 0xf3, 0x17, 0x0c, 0x00, 0xf2, 0x6e, 0x76, - 0xc6, 0xf3, 0x0e, 0x06, 0x04, 0xeb, 0x46, 0x06, 0xb6, 0xf9, 0x0c, 0xe1, - 0x4f, 0xea, 0x0e, 0x2e, 0x0e, 0xf3, 0x17, 0x06, 0x8e, 0xfb, 0x0b, 0x8a, - 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, 0xc4, 0x44, 0x0c, 0xf3, - 0x17, 0x0c, 0x00, 0xf2, 0xe9, 0x2e, 0xce, 0xf3, 0x0e, 0x0e, 0x04, 0xeb, - 0x4e, 0x0e, 0x4f, 0xea, 0x2c, 0x28, 0xae, 0xf8, 0x0c, 0x81, 0x8c, 0xfb, - 0x07, 0xe8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xde, 0x5e, 0x0e, 0xf3, - 0x17, 0x0e, 0x76, 0x44, 0x06, 0xf3, 0x17, 0x06, 0x00, 0xf6, 0xde, 0x6c, - 0xcc, 0xf3, 0x0e, 0x0c, 0x04, 0xeb, 0x4c, 0x0c, 0xbc, 0xf9, 0x0c, 0xc1, - 0x4f, 0xea, 0x0c, 0x2c, 0x0c, 0xf3, 0x17, 0x0e, 0x8c, 0xfb, 0x0b, 0x8a, - 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, 0x46, 0x44, 0x06, 0xf3, - 0x17, 0x06, 0x00, 0xf2, 0x6f, 0x7c, 0xcc, 0xf3, 0x0e, 0x0c, 0x04, 0xeb, - 0x4c, 0x0c, 0x4f, 0xea, 0x26, 0x28, 0xac, 0xf8, 0x0c, 0x81, 0x86, 0xfb, - 0x07, 0xc8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xdc, 0x5c, 0x0c, 0xf3, - 0x17, 0x0c, 0xf4, 0x44, 0x0c, 0xf3, 0x17, 0x0a, 0xc4, 0xf8, 0xc0, 0xa0, - 0x8a, 0xfb, 0x02, 0x6c, 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, 0xd6, 0x56, - 0x06, 0xf3, 0x17, 0x06, 0x00, 0xf5, 0xd1, 0x4c, 0x0c, 0xf1, 0x4f, 0x0c, - 0xcc, 0xf3, 0x0e, 0x0c, 0x04, 0xeb, 0x4c, 0x0c, 0xbc, 0xf9, 0x0c, 0xc1, - 0x4f, 0xea, 0x0c, 0x2c, 0x0c, 0xf3, 0x17, 0x0e, 0x8c, 0xfb, 0x03, 0xe8, - 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xde, 0x5e, 0xb6, 0x44, 0x0e, 0xf3, - 0x17, 0x0e, 0x8e, 0xfb, 0x05, 0x6c, 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, - 0xd6, 0x56, 0x06, 0xf3, 0x17, 0x06, 0x8a, 0xfb, 0x03, 0xce, 0x4f, 0xea, - 0x4e, 0x2e, 0x4e, 0xea, 0xdc, 0x5c, 0x66, 0x44, 0x06, 0xf3, 0x17, 0x06, - 0x00, 0xf5, 0xbb, 0x5c, 0x0c, 0xf1, 0x1b, 0x0c, 0xcc, 0xf3, 0x0e, 0x0c, - 0x04, 0xeb, 0x4c, 0x0c, 0xbc, 0xf9, 0x0c, 0xe1, 0x4f, 0xea, 0x0e, 0x2e, - 0x0e, 0xf3, 0x17, 0x02, 0x8e, 0xfb, 0x0b, 0x8c, 0x4f, 0xea, 0x4c, 0x2c, - 0x4c, 0xea, 0xd8, 0x58, 0xb0, 0x44, 0x08, 0xf3, 0x17, 0x08, 0x00, 0xf6, - 0xdf, 0x66, 0xc6, 0xf3, 0x0e, 0x06, 0x04, 0xeb, 0x46, 0x06, 0x4f, 0xea, - 0x28, 0x2e, 0xa6, 0xf8, 0x0c, 0xe1, 0x88, 0xfb, 0x07, 0x6e, 0x4f, 0xea, - 0x4e, 0x2e, 0x4e, 0xea, 0xd6, 0x56, 0x06, 0xf3, 0x17, 0x06, 0x16, 0x44, - 0x06, 0xf3, 0x17, 0x06, 0x00, 0xf5, 0x11, 0x5c, 0x0c, 0xf1, 0x21, 0x0c, - 0xcc, 0xf3, 0x0e, 0x0c, 0x04, 0xeb, 0x4c, 0x0c, 0xbc, 0xf9, 0x0c, 0xe1, - 0x4f, 0xea, 0x0e, 0x2e, 0x0e, 0xf3, 0x17, 0x02, 0x8e, 0xfb, 0x0b, 0x8c, - 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, 0xd8, 0x58, 0x46, 0x44, 0x06, 0xf3, - 0x17, 0x06, 0x00, 0xf5, 0xbb, 0x5e, 0x0e, 0xf1, 0x1c, 0x0e, 0xce, 0xf3, - 0x0e, 0x0e, 0x04, 0xeb, 0x4e, 0x0e, 0x4f, 0xea, 0x26, 0x28, 0xae, 0xf8, - 0x0c, 0x81, 0x86, 0xfb, 0x07, 0xe8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, - 0xde, 0x5e, 0x0e, 0xf3, 0x17, 0x0e, 0x96, 0x44, 0x0e, 0xf3, 0x17, 0x0e, - 0x00, 0xf5, 0x11, 0x5c, 0x0c, 0xf1, 0x22, 0x0c, 0xcc, 0xf3, 0x0e, 0x0c, - 0x04, 0xeb, 0x4c, 0x0c, 0x4f, 0xea, 0x2e, 0x26, 0xac, 0xf8, 0x0c, 0x61, - 0x00, 0x22, 0x8e, 0xfb, 0x02, 0x68, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, - 0xd6, 0x56, 0x06, 0xf3, 0x17, 0x02, 0x00, 0xf5, 0x57, 0x5e, 0x0e, 0xf1, - 0x0a, 0x0e, 0xce, 0xf3, 0x0e, 0x0e, 0x04, 0xeb, 0x4e, 0x0e, 0xbe, 0xf9, - 0x0c, 0xe1, 0x4f, 0xea, 0x0e, 0x2e, 0x0e, 0xf3, 0x17, 0x08, 0x8e, 0xfb, - 0x03, 0x86, 0x4f, 0xea, 0x46, 0x26, 0x46, 0xea, 0xd8, 0x58, 0x90, 0x44, - 0x08, 0xf3, 0x17, 0x08, 0x88, 0xfb, 0x05, 0x6e, 0x4f, 0xea, 0x4e, 0x2e, - 0x4e, 0xea, 0xd6, 0x56, 0x06, 0xf3, 0x17, 0x06, 0x8a, 0xfb, 0x03, 0x5e, - 0x4f, 0xea, 0x4e, 0x2e, 0x4e, 0xea, 0xd5, 0x55, 0x2e, 0x44, 0x06, 0xf3, - 0x17, 0x06, 0x00, 0xf5, 0x87, 0x45, 0x17, 0x35, 0xc5, 0xf3, 0x0e, 0x05, - 0x04, 0xeb, 0x45, 0x05, 0xb5, 0xf9, 0x0c, 0xe1, 0x4f, 0xea, 0x0e, 0x2e, - 0x0e, 0xf3, 0x17, 0x05, 0x8e, 0xfb, 0x0b, 0x8a, 0x4f, 0xea, 0x4a, 0x2a, - 0x4a, 0xea, 0xd8, 0x58, 0x46, 0x44, 0x06, 0xf3, 0x17, 0x06, 0x00, 0xf5, - 0x57, 0x5e, 0x0e, 0xf1, 0x0b, 0x0e, 0xce, 0xf3, 0x0e, 0x0e, 0x04, 0xeb, - 0x4e, 0x0e, 0x4f, 0xea, 0x26, 0x28, 0xae, 0xf8, 0x0c, 0x81, 0x86, 0xfb, - 0x07, 0xe8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xde, 0x5e, 0x0e, 0xf3, - 0x17, 0x0e, 0x75, 0x44, 0x05, 0xf3, 0x17, 0x05, 0x00, 0xf5, 0xa0, 0x46, - 0x19, 0x36, 0xc6, 0xf3, 0x0e, 0x06, 0x04, 0xeb, 0x46, 0x06, 0xb6, 0xf9, - 0x0c, 0xe1, 0x4f, 0xea, 0x0e, 0x2e, 0x0e, 0xf3, 0x17, 0x06, 0x8e, 0xfb, - 0x0b, 0x8a, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, 0x45, 0x44, - 0x05, 0xf3, 0x17, 0x05, 0x85, 0xfb, 0x07, 0xae, 0x4f, 0xea, 0x4e, 0x2e, - 0x4e, 0xea, 0xda, 0x5a, 0x00, 0xf5, 0x87, 0x4e, 0x0e, 0xf1, 0x18, 0x0e, - 0xce, 0xf3, 0x0e, 0x0e, 0x04, 0xeb, 0x4e, 0x0e, 0x2d, 0x12, 0xae, 0xf8, - 0x0c, 0x51, 0x0a, 0xf3, 0x17, 0x0a, 0x56, 0x44, 0x06, 0xf3, 0x17, 0x06, - 0x00, 0xf5, 0xa0, 0x40, 0x1a, 0x30, 0xc0, 0xf3, 0x0e, 0x00, 0x04, 0xeb, - 0x40, 0x00, 0x46, 0xf3, 0x0f, 0x2a, 0xa0, 0xf8, 0x0c, 0xa1, 0x00, 0x22, - 0x86, 0xfb, 0x02, 0x0e, 0x4f, 0xea, 0x4e, 0x2e, 0x4e, 0xea, 0xd0, 0x50, - 0x00, 0xf3, 0x17, 0x00, 0x04, 0x9f, 0x87, 0xfb, 0x01, 0x6e, 0x4f, 0xea, - 0x4e, 0x2e, 0x4e, 0xea, 0xd6, 0x56, 0x30, 0x44, 0x00, 0xf3, 0x17, 0x00, - 0xbc, 0xf9, 0x0c, 0x61, 0x36, 0x02, 0x06, 0xf3, 0x17, 0x0c, 0x4f, 0xf4, - 0x40, 0x0c, 0x86, 0xfb, 0x0c, 0xe8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, - 0xde, 0x5e, 0x70, 0x44, 0x00, 0xf3, 0x17, 0x00, 0x02, 0x9a, 0x80, 0xfb, - 0x02, 0x6e, 0x4f, 0xea, 0x4e, 0x2e, 0x4e, 0xea, 0xd6, 0x56, 0x06, 0xf3, - 0x17, 0x06, 0x87, 0xfb, 0x03, 0x0e, 0x4f, 0xea, 0x4e, 0x2e, 0x4e, 0xea, - 0xd0, 0x50, 0x06, 0x44, 0x06, 0xf3, 0x17, 0x06, 0x00, 0x25, 0xc4, 0xf8, - 0xc4, 0x60, 0x02, 0x96, 0x86, 0xfb, 0x05, 0x0e, 0x4f, 0xea, 0x4e, 0x2e, - 0x4e, 0xea, 0xd0, 0x50, 0x00, 0xf3, 0x17, 0x00, 0x03, 0x9e, 0x86, 0xfb, - 0x01, 0xe8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xde, 0x5e, 0x70, 0x44, - 0x00, 0xf3, 0x17, 0x00, 0x4f, 0xea, 0x0a, 0x25, 0x05, 0xf3, 0x17, 0x08, - 0x85, 0xfb, 0x0c, 0xea, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xde, 0x5e, - 0xc4, 0xf8, 0x08, 0x80, 0x70, 0x44, 0x00, 0xf3, 0x17, 0x00, 0x80, 0xfb, - 0x02, 0x5c, 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, 0xd5, 0x55, 0x05, 0xf3, - 0x17, 0x05, 0x86, 0xfb, 0x03, 0x07, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, - 0xd0, 0x50, 0x05, 0x44, 0x05, 0xf3, 0x17, 0x05, 0x00, 0x22, 0xc4, 0xf8, - 0xc8, 0x50, 0x85, 0xfb, 0x02, 0x07, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, - 0xd0, 0x50, 0x00, 0xf3, 0x17, 0x00, 0xd4, 0xf8, 0x98, 0xe0, 0x8e, 0xfb, - 0x03, 0x7c, 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, 0xd7, 0x57, 0x38, 0x44, - 0x00, 0xf3, 0x17, 0x00, 0x05, 0x9e, 0x80, 0xfb, 0x06, 0x7c, 0x4f, 0xea, - 0x4c, 0x2c, 0x4c, 0xea, 0xd7, 0x57, 0x07, 0xf3, 0x17, 0x07, 0xd4, 0xf8, - 0x9c, 0x00, 0x80, 0xfb, 0x03, 0xc8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, - 0xdc, 0x5c, 0x67, 0x44, 0x07, 0xf3, 0x17, 0x07, 0xc4, 0xf8, 0x9c, 0x70, - 0x87, 0xfb, 0x01, 0xc0, 0x4f, 0xea, 0x40, 0x20, 0x40, 0xea, 0xdc, 0x5c, - 0x0c, 0xf3, 0x17, 0x0c, 0xa2, 0xf5, 0xcc, 0x12, 0xa2, 0xf5, 0xd0, 0x52, - 0x8e, 0xfb, 0x02, 0x08, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xd0, 0x50, - 0x84, 0x44, 0x0c, 0xf3, 0x17, 0x0c, 0x02, 0x9f, 0x87, 0xfb, 0x03, 0x08, - 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xd0, 0x50, 0x84, 0x44, 0x0c, 0xf3, - 0x17, 0x0c, 0x8c, 0xfb, 0x03, 0x80, 0x4f, 0xea, 0x40, 0x20, 0x40, 0xea, - 0xd8, 0x58, 0x08, 0xf3, 0x17, 0x08, 0x88, 0xfb, 0x06, 0x0a, 0x4f, 0xea, - 0x4a, 0x2a, 0x4a, 0xea, 0xd0, 0x50, 0x00, 0xf3, 0x17, 0x00, 0x8e, 0xfb, - 0x03, 0x8a, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, 0x40, 0x44, - 0x00, 0xf3, 0x17, 0x00, 0x00, 0x27, 0xc4, 0xf8, 0x98, 0x00, 0x80, 0xfb, - 0x07, 0xe8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xde, 0x5e, 0x0e, 0xf3, - 0x17, 0x00, 0xd4, 0xf8, 0xa8, 0x80, 0x88, 0xfb, 0x03, 0xea, 0x4f, 0xea, - 0x4a, 0x2a, 0x4a, 0xea, 0xde, 0x5e, 0x70, 0x44, 0x00, 0xf3, 0x17, 0x00, - 0x37, 0x46, 0x80, 0xfb, 0x06, 0xea, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, - 0xde, 0x5e, 0x0e, 0xf3, 0x17, 0x0e, 0xd4, 0xf8, 0xac, 0x60, 0x86, 0xfb, - 0x03, 0xa0, 0x4f, 0xea, 0x40, 0x20, 0x40, 0xea, 0xda, 0x5a, 0xd6, 0x44, - 0x0e, 0xf3, 0x17, 0x0e, 0xc4, 0xf8, 0xac, 0xe0, 0x8e, 0xfb, 0x01, 0x0a, - 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd0, 0x50, 0x00, 0xf3, 0x17, 0x00, - 0x88, 0xfb, 0x02, 0xea, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xde, 0x5e, - 0x70, 0x44, 0x00, 0xf3, 0x17, 0x00, 0x85, 0xfb, 0x03, 0xea, 0x4f, 0xea, - 0x4a, 0x2a, 0x4a, 0xea, 0xde, 0x5e, 0x70, 0x44, 0x00, 0xf3, 0x17, 0x00, - 0x80, 0xfb, 0x03, 0xae, 0x4f, 0xea, 0x4e, 0x2e, 0x4e, 0xea, 0xda, 0x5a, - 0x0a, 0xf3, 0x17, 0x0a, 0x8a, 0xfb, 0x07, 0xeb, 0x4f, 0xea, 0x4b, 0x2b, - 0x4b, 0xea, 0xde, 0x5e, 0x0e, 0xf3, 0x17, 0x0e, 0x88, 0xfb, 0x03, 0xab, - 0x4f, 0xea, 0x4b, 0x2b, 0x4b, 0xea, 0xda, 0x5a, 0xd6, 0x44, 0x0e, 0xf3, - 0x17, 0x0a, 0x00, 0x26, 0xc4, 0xf8, 0xa8, 0xa0, 0x8a, 0xfb, 0x06, 0xe8, - 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xde, 0x5e, 0x0e, 0xf3, 0x17, 0x0e, - 0x8c, 0xfb, 0x01, 0x8a, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, - 0xc6, 0x44, 0x0e, 0xf3, 0x17, 0x0e, 0x02, 0x9e, 0x86, 0xfb, 0x03, 0x8a, - 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, 0xf0, 0x44, 0x08, 0xf3, - 0x17, 0x08, 0x06, 0x9f, 0x88, 0xfb, 0x07, 0xe6, 0x4f, 0xea, 0x46, 0x26, - 0x46, 0xea, 0xde, 0x5e, 0x0e, 0xf3, 0x17, 0x0e, 0x8c, 0xfb, 0x03, 0x68, - 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xd6, 0x56, 0xb6, 0x44, 0x0e, 0xf3, - 0x17, 0x0e, 0x4f, 0xf0, 0x00, 0x08, 0xc4, 0xf8, 0xcc, 0xe0, 0x8e, 0xfb, - 0x08, 0x6c, 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, 0xd6, 0x56, 0x06, 0xf3, - 0x17, 0x06, 0x80, 0xfb, 0x01, 0xc8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, - 0xdc, 0x5c, 0x66, 0x44, 0x06, 0xf3, 0x17, 0x06, 0x85, 0xfb, 0x03, 0xc8, - 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xdc, 0x5c, 0x66, 0x44, 0x06, 0xf3, - 0x17, 0x06, 0x86, 0xfb, 0x07, 0x5c, 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, - 0xd5, 0x55, 0x05, 0xf3, 0x17, 0x05, 0x80, 0xfb, 0x03, 0x6c, 0x4f, 0xea, - 0x4c, 0x2c, 0x4c, 0xea, 0xd6, 0x56, 0x35, 0x44, 0x05, 0xf3, 0x17, 0x05, - 0x00, 0x27, 0xc4, 0xf8, 0xd0, 0x50, 0x85, 0xfb, 0x07, 0x06, 0x4f, 0xea, - 0x46, 0x26, 0x46, 0xea, 0xd0, 0x50, 0x00, 0xf3, 0x17, 0x00, 0xd4, 0xf8, - 0xa0, 0x60, 0x86, 0xfb, 0x03, 0xc8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, - 0xdc, 0x5c, 0x60, 0x44, 0x00, 0xf3, 0x17, 0x00, 0x01, 0x9f, 0x80, 0xfb, - 0x07, 0xc8, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xdc, 0x5c, 0x0c, 0xf3, - 0x17, 0x0c, 0xd4, 0xf8, 0xa4, 0x00, 0x80, 0xfb, 0x03, 0x8a, 0x4f, 0xea, - 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, 0xc4, 0x44, 0x0c, 0xf3, 0x17, 0x0c, - 0xc4, 0xf8, 0xa4, 0xc0, 0x8c, 0xfb, 0x01, 0x08, 0x4f, 0xea, 0x48, 0x28, - 0x48, 0xea, 0xd0, 0x50, 0x00, 0xf3, 0x17, 0x00, 0x86, 0xfb, 0x02, 0x8a, - 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, 0x40, 0x44, 0x00, 0xf3, - 0x17, 0x00, 0x8e, 0xfb, 0x03, 0x8a, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, - 0xd8, 0x58, 0x40, 0x44, 0x00, 0xf3, 0x17, 0x00, 0x80, 0xfb, 0x07, 0x8a, - 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, 0x08, 0xf3, 0x17, 0x00, - 0x86, 0xfb, 0x03, 0x8a, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd8, 0x58, - 0x40, 0x44, 0x00, 0xf3, 0x17, 0x00, 0x00, 0x22, 0xc4, 0xf8, 0xa0, 0x00, - 0x80, 0xfb, 0x02, 0x68, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xd6, 0x56, - 0x06, 0xf3, 0x17, 0x06, 0xd4, 0xf8, 0xb0, 0x80, 0x88, 0xfb, 0x03, 0x0a, - 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd0, 0x50, 0x06, 0x44, 0x06, 0xf3, - 0x17, 0x06, 0x86, 0xfb, 0x07, 0x0a, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, - 0xd0, 0x50, 0x00, 0xf3, 0x17, 0x00, 0xd4, 0xf8, 0xb4, 0x60, 0x86, 0xfb, - 0x03, 0xab, 0x4f, 0xea, 0x4b, 0x2b, 0x4b, 0xea, 0xda, 0x5a, 0x50, 0x44, - 0x00, 0xf3, 0x17, 0x00, 0x02, 0x46, 0xc4, 0xf8, 0xb4, 0x00, 0x80, 0xfb, - 0x01, 0x6a, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd6, 0x56, 0x06, 0xf3, - 0x17, 0x06, 0x58, 0x4f, 0x88, 0xfb, 0x07, 0xab, 0x4f, 0xea, 0x4b, 0x2b, - 0x4b, 0xea, 0xda, 0x5a, 0x56, 0x44, 0x06, 0xf3, 0x17, 0x06, 0x85, 0xfb, - 0x03, 0xa7, 0x4f, 0xea, 0x47, 0x27, 0x47, 0xea, 0xda, 0x5a, 0x56, 0x44, - 0x06, 0xf3, 0x17, 0x06, 0x01, 0x98, 0x86, 0xfb, 0x00, 0x7a, 0x4f, 0xea, - 0x4a, 0x2a, 0x4a, 0xea, 0xd7, 0x57, 0x07, 0xf3, 0x17, 0x07, 0x88, 0xfb, - 0x03, 0x6a, 0x4f, 0xea, 0x4a, 0x2a, 0x4a, 0xea, 0xd6, 0x56, 0x37, 0x44, - 0x07, 0xf3, 0x17, 0x07, 0x00, 0x20, 0xc4, 0xf8, 0xb0, 0x70, 0x87, 0xfb, - 0x00, 0x68, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xd6, 0x56, 0x06, 0xf3, - 0x17, 0x06, 0x8c, 0xfb, 0x01, 0x78, 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, - 0xd7, 0x57, 0x3e, 0x44, 0x06, 0xf3, 0x17, 0x06, 0x8e, 0xfb, 0x03, 0x78, - 0x4f, 0xea, 0x48, 0x28, 0x48, 0xea, 0xd7, 0x57, 0x3e, 0x44, 0x06, 0xf3, - 0x17, 0x06, 0x07, 0x98, 0x86, 0xfb, 0x00, 0x7e, 0x4f, 0xea, 0x4e, 0x2e, - 0x4e, 0xea, 0xd7, 0x57, 0x07, 0xf3, 0x17, 0x07, 0x8c, 0xfb, 0x03, 0x6e, - 0x4f, 0xea, 0x4e, 0x2e, 0x4e, 0xea, 0xd6, 0x56, 0x37, 0x44, 0x07, 0xf3, - 0x17, 0x07, 0x4f, 0xf0, 0x00, 0x0e, 0x67, 0x66, 0x87, 0xfb, 0x0e, 0x6c, - 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, 0xd6, 0x56, 0x06, 0xf3, 0x17, 0x06, - 0x82, 0xfb, 0x01, 0x7c, 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, 0xd7, 0x57, - 0xf1, 0x19, 0x01, 0xf3, 0x17, 0x01, 0x85, 0xfb, 0x03, 0x67, 0x4f, 0xea, - 0x47, 0x27, 0x47, 0xea, 0xd6, 0x56, 0x31, 0x44, 0x01, 0xf3, 0x17, 0x01, - 0x81, 0xfb, 0x00, 0x56, 0x4f, 0xea, 0x46, 0x26, 0x46, 0xea, 0xd5, 0x55, - 0x05, 0xf3, 0x17, 0x01, 0x82, 0xfb, 0x03, 0x56, 0x4f, 0xea, 0x46, 0x26, - 0x46, 0xea, 0xd5, 0x55, 0x4b, 0x19, 0x03, 0xf3, 0x17, 0x03, 0x63, 0x60, - 0xa3, 0x66, 0x83, 0xfb, 0x0e, 0x10, 0x4f, 0xea, 0x40, 0x20, 0x40, 0xea, - 0xd1, 0x51, 0x01, 0xf3, 0x17, 0x01, 0x21, 0x60, 0x08, 0xb0, 0xbd, 0xe8, - 0xf0, 0x8d, 0x00, 0xee, 0x10, 0x3a, 0x10, 0x4b, 0xba, 0xee, 0xe6, 0x0a, - 0x59, 0xf8, 0x03, 0x30, 0x98, 0x47, 0xbe, 0xee, 0xe4, 0x0a, 0x10, 0xee, - 0x10, 0x3a, 0x03, 0xf3, 0x17, 0x03, 0xff, 0xf7, 0x94, 0xba, 0x00, 0xee, - 0x10, 0x3a, 0x08, 0x4b, 0xba, 0xee, 0xe6, 0x0a, 0x59, 0xf8, 0x03, 0x30, - 0x98, 0x47, 0xbe, 0xee, 0xe4, 0x0a, 0x10, 0xee, 0x10, 0x3a, 0x03, 0xf3, - 0x17, 0x02, 0xff, 0xf7, 0xb5, 0xba, 0x00, 0xbf, 0x00, 0x66, 0xe6, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, - 0x04, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, - 0x04, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, - 0x08, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, - 0x08, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, - 0x08, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, - 0x08, 0x00, 0x00, 0x00, 0x38, 0xb5, 0x08, 0x4b, 0x59, 0xf8, 0x03, 0x30, - 0x1d, 0x68, 0x55, 0xb1, 0x06, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x1c, 0x68, - 0xe3, 0x88, 0xb4, 0xf9, 0x04, 0x20, 0x61, 0x88, 0x20, 0x88, 0xa8, 0x47, - 0x20, 0x72, 0x38, 0xbd, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x10, 0xb4, 0x03, 0x4c, 0x59, 0xf8, 0x04, 0x40, 0xa4, 0x46, 0x5d, 0xf8, - 0x04, 0x4b, 0x60, 0x47, 0x14, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, - 0x03, 0x30, 0x18, 0x47, 0x18, 0x00, 0x00, 0x00, 0x2d, 0xe9, 0xf0, 0x41, - 0x58, 0x4b, 0x59, 0xf8, 0x03, 0x40, 0x58, 0x4b, 0x00, 0x25, 0xc4, 0xe9, - 0x02, 0x55, 0xc4, 0xe9, 0x04, 0x55, 0xc4, 0xe9, 0x06, 0x55, 0xc4, 0xe9, - 0x08, 0x55, 0xc4, 0xe9, 0x0a, 0x55, 0xc4, 0xe9, 0x0c, 0x55, 0xc4, 0xe9, - 0x0e, 0x55, 0xc4, 0xe9, 0x10, 0x55, 0xc4, 0xe9, 0x12, 0x55, 0xc4, 0xe9, - 0x14, 0x55, 0xc4, 0xe9, 0x16, 0x55, 0xc4, 0xe9, 0x18, 0x55, 0xc4, 0xe9, - 0x1a, 0x55, 0xc4, 0xe9, 0x1c, 0x55, 0xc4, 0xe9, 0x1e, 0x55, 0xc4, 0xe9, - 0x20, 0x55, 0xc4, 0xf8, 0x88, 0x50, 0xc4, 0xf8, 0x08, 0x51, 0x82, 0xb0, - 0x59, 0xf8, 0x03, 0x80, 0x29, 0x46, 0x4f, 0xf4, 0x80, 0x32, 0x04, 0xf5, - 0x86, 0x70, 0xc0, 0x47, 0x04, 0xf5, 0x80, 0x36, 0x3c, 0x4b, 0xc6, 0xf8, - 0x14, 0x31, 0xc6, 0xe9, 0x48, 0x53, 0x01, 0x23, 0x86, 0xf8, 0x48, 0x31, - 0x04, 0xf1, 0x10, 0x03, 0xc6, 0xf8, 0x18, 0x31, 0x04, 0xf1, 0x0c, 0x03, - 0xc6, 0xf8, 0x1c, 0x31, 0x04, 0xf1, 0x18, 0x03, 0xc6, 0xf8, 0x28, 0x31, - 0x04, 0xf1, 0x14, 0x03, 0xc6, 0xf8, 0x2c, 0x31, 0x04, 0xf1, 0x20, 0x03, - 0xc6, 0xf8, 0x34, 0x31, 0x04, 0xf1, 0x1c, 0x03, 0xc6, 0xf8, 0x38, 0x31, - 0x04, 0xf1, 0x28, 0x03, 0xc6, 0xf8, 0x40, 0x31, 0xc6, 0xe9, 0x43, 0x55, - 0x04, 0xf1, 0x24, 0x03, 0xc6, 0xf8, 0x44, 0x31, 0x2b, 0x4b, 0xc6, 0xf8, - 0x30, 0x51, 0xc6, 0xf8, 0x3c, 0x51, 0xc6, 0xf8, 0x50, 0x51, 0x59, 0xf8, - 0x03, 0x70, 0x25, 0x60, 0x65, 0x60, 0x29, 0x46, 0x04, 0xf1, 0x8c, 0x00, - 0x7c, 0x22, 0x7c, 0x60, 0xc0, 0x47, 0x24, 0x4b, 0x9f, 0xed, 0x1f, 0x0a, - 0x59, 0xf8, 0x03, 0x20, 0xc6, 0xf8, 0x4c, 0x21, 0x4f, 0xf0, 0x7c, 0x53, - 0xfb, 0x60, 0x3b, 0x61, 0x7b, 0x61, 0xf7, 0xee, 0x00, 0x0a, 0x1e, 0x4b, - 0xc7, 0xed, 0x02, 0x0a, 0x59, 0xf8, 0x03, 0x00, 0x1c, 0x4b, 0xcd, 0xed, - 0x01, 0x0a, 0x8d, 0xed, 0x00, 0x0a, 0x59, 0xf8, 0x03, 0x40, 0x07, 0xf1, - 0x08, 0x01, 0xa0, 0x47, 0x18, 0x4b, 0xdd, 0xed, 0x01, 0x0a, 0x59, 0xf8, - 0x03, 0x00, 0x9d, 0xed, 0x00, 0x0a, 0x07, 0xf1, 0x0c, 0x01, 0xa0, 0x47, - 0x14, 0x4b, 0xdd, 0xed, 0x01, 0x0a, 0x59, 0xf8, 0x03, 0x00, 0x9d, 0xed, - 0x00, 0x0a, 0x07, 0xf1, 0x10, 0x01, 0xa0, 0x47, 0x10, 0x4b, 0xdd, 0xed, - 0x01, 0x0a, 0x59, 0xf8, 0x03, 0x00, 0x9d, 0xed, 0x00, 0x0a, 0x07, 0xf1, - 0x14, 0x01, 0x23, 0x46, 0x02, 0xb0, 0xbd, 0xe8, 0xf0, 0x41, 0x18, 0x47, - 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x2d, 0xe9, 0xf0, 0x4d, - 0x2d, 0xed, 0x02, 0x8b, 0x87, 0x4b, 0x88, 0x4a, 0x59, 0xf8, 0x03, 0x80, - 0x87, 0x4b, 0x59, 0xf8, 0x02, 0x00, 0x59, 0xf8, 0x03, 0x10, 0x86, 0x4b, - 0x86, 0x4a, 0x59, 0xf8, 0x03, 0x30, 0xd8, 0xed, 0x03, 0x6a, 0x98, 0xed, - 0x04, 0x7a, 0x09, 0x68, 0xd8, 0xed, 0x05, 0x7a, 0x00, 0x68, 0x59, 0xf8, - 0x02, 0x20, 0xd0, 0xf8, 0x00, 0xa0, 0x1e, 0x68, 0xd1, 0xf8, 0x00, 0xb0, - 0xd8, 0xf8, 0x04, 0x70, 0x15, 0x68, 0x9f, 0xed, 0x76, 0x8a, 0xb0, 0xee, - 0x66, 0x6a, 0xf0, 0xee, 0x47, 0x6a, 0xb0, 0xee, 0x67, 0x7a, 0x8a, 0xb0, - 0xbe, 0xee, 0xe4, 0x6a, 0xfe, 0xee, 0xe4, 0x6a, 0xbe, 0xee, 0xe4, 0x7a, - 0xb4, 0x46, 0x59, 0x46, 0x0a, 0xf1, 0x60, 0x03, 0xcd, 0xe9, 0x06, 0x6a, - 0xcd, 0xf8, 0x14, 0xb0, 0xcd, 0xf8, 0x24, 0x80, 0xd3, 0x46, 0x8d, 0xed, - 0x02, 0x6a, 0xcd, 0xed, 0x03, 0x6a, 0x8d, 0xed, 0x04, 0x7a, 0x07, 0xf5, - 0x80, 0x34, 0x08, 0x95, 0x01, 0x91, 0x2e, 0x46, 0x9a, 0x46, 0xe0, 0x46, - 0xfb, 0xec, 0x01, 0x7a, 0xfe, 0xee, 0xe4, 0x7a, 0x17, 0xee, 0x90, 0x3a, - 0x03, 0xf3, 0x17, 0x03, 0xfb, 0x65, 0x01, 0x9b, 0xf3, 0xec, 0x01, 0x7a, - 0xfe, 0xee, 0xe4, 0x7a, 0x01, 0x93, 0x17, 0xee, 0x90, 0x3a, 0x03, 0xf3, - 0x17, 0x03, 0x3b, 0x66, 0x02, 0x9b, 0x03, 0xf3, 0x17, 0x03, 0xfb, 0x64, - 0x03, 0x9b, 0x03, 0xf3, 0x17, 0x03, 0x3b, 0x65, 0x04, 0x9b, 0x03, 0xf3, - 0x17, 0x03, 0x7b, 0x65, 0x38, 0x46, 0xd4, 0xf8, 0x4c, 0x31, 0x98, 0x47, - 0x4f, 0xf0, 0x00, 0x03, 0x84, 0xf8, 0x48, 0x31, 0xd4, 0xf8, 0x1c, 0x31, - 0x19, 0x68, 0xd4, 0xf8, 0x0c, 0x31, 0x01, 0x3b, 0xc4, 0xf8, 0x0c, 0x31, - 0xd4, 0xe9, 0x44, 0x23, 0x09, 0x12, 0x82, 0xfb, 0x01, 0x0c, 0x4f, 0xea, - 0x4c, 0x2c, 0x4c, 0xea, 0xd0, 0x50, 0x03, 0x44, 0x03, 0xf3, 0x17, 0x03, - 0x83, 0xfb, 0x01, 0x0c, 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, 0xd0, 0x50, - 0xc4, 0xf8, 0x14, 0x31, 0x12, 0x1a, 0x02, 0xf3, 0x17, 0x02, 0xd4, 0xf8, - 0x2c, 0x31, 0xc4, 0xf8, 0x10, 0x21, 0x18, 0x68, 0xd4, 0xe9, 0x48, 0x23, - 0x00, 0x12, 0x82, 0xfb, 0x00, 0x1c, 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, - 0xd1, 0x51, 0x0b, 0x44, 0x03, 0xf3, 0x17, 0x03, 0x83, 0xfb, 0x00, 0x1c, - 0x4f, 0xea, 0x4c, 0x2c, 0x4c, 0xea, 0xd1, 0x51, 0xc4, 0xf8, 0x24, 0x31, - 0x52, 0x1a, 0x02, 0xf3, 0x17, 0x02, 0xd4, 0xf8, 0x34, 0x31, 0xc4, 0xf8, - 0x20, 0x21, 0x18, 0x68, 0xd4, 0xf8, 0x40, 0x31, 0x2e, 0x4a, 0x19, 0x68, - 0xd4, 0xf8, 0x38, 0x31, 0xd7, 0xed, 0x19, 0x7a, 0xd4, 0xf8, 0x30, 0x51, - 0x40, 0x15, 0x49, 0x15, 0x42, 0xfa, 0x00, 0xf0, 0x42, 0xfa, 0x01, 0xf1, - 0x1a, 0x68, 0xd4, 0xf8, 0x44, 0x31, 0xb8, 0xee, 0xe7, 0x7a, 0xa5, 0xeb, - 0x22, 0x32, 0xd7, 0xed, 0x1a, 0x7a, 0x1b, 0x68, 0x02, 0x40, 0xc4, 0xf8, - 0x30, 0x21, 0xf8, 0xee, 0xe7, 0x7a, 0xd4, 0xf8, 0x3c, 0x21, 0x27, 0xee, - 0x08, 0x7a, 0x67, 0xee, 0x88, 0x7a, 0xa2, 0xeb, 0x23, 0x33, 0x19, 0x40, - 0xd3, 0x45, 0xc4, 0xf8, 0x3c, 0x11, 0xa6, 0xec, 0x01, 0x7a, 0xe8, 0xec, - 0x01, 0x7a, 0x7f, 0xf4, 0x67, 0xaf, 0xdd, 0xe9, 0x07, 0xa5, 0xdd, 0xe9, - 0x05, 0xb6, 0xdd, 0xf8, 0x24, 0x80, 0xf7, 0xee, 0x00, 0x6a, 0x05, 0xf1, - 0x60, 0x03, 0x98, 0xed, 0x02, 0x7a, 0xfa, 0xec, 0x01, 0x5a, 0x95, 0xed, - 0x00, 0x6a, 0x76, 0xee, 0xc7, 0x7a, 0x67, 0xee, 0xa5, 0x7a, 0xe6, 0xee, - 0x07, 0x7a, 0xe5, 0xec, 0x01, 0x7a, 0x98, 0xed, 0x02, 0x7a, 0xfb, 0xec, - 0x01, 0x5a, 0x96, 0xed, 0x00, 0x6a, 0x76, 0xee, 0xc7, 0x7a, 0xab, 0x42, - 0x67, 0xee, 0xa5, 0x7a, 0xe6, 0xee, 0x07, 0x7a, 0xe6, 0xec, 0x01, 0x7a, - 0xe1, 0xd1, 0x0a, 0xb0, 0xbd, 0xec, 0x02, 0x8b, 0xbd, 0xe8, 0xf0, 0x8d, - 0x00, 0x00, 0x00, 0x34, 0xff, 0xff, 0x3f, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x70, 0xb5, 0x10, 0x4a, 0x10, 0x4b, 0x59, 0xf8, - 0x02, 0x60, 0x59, 0xf8, 0x03, 0x50, 0x76, 0x1b, 0xb6, 0x10, 0x06, 0xd0, - 0x00, 0x24, 0x55, 0xf8, 0x04, 0x3b, 0x01, 0x34, 0x98, 0x47, 0xa6, 0x42, - 0xf9, 0xd1, 0x0a, 0x4a, 0x0a, 0x4b, 0x59, 0xf8, 0x02, 0x60, 0x59, 0xf8, - 0x03, 0x50, 0x76, 0x1b, 0xb6, 0x10, 0x06, 0xd0, 0x00, 0x24, 0x55, 0xf8, - 0x04, 0x3b, 0x01, 0x34, 0x98, 0x47, 0xa6, 0x42, 0xf9, 0xd1, 0x70, 0xbd, - 0x48, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x2d, 0xe9, 0x00, 0x42, 0x02, 0xb4, 0xdf, 0xf8, - 0x10, 0x10, 0xd1, 0xf8, 0x00, 0x90, 0x02, 0xbc, 0xff, 0xf7, 0xc2, 0xfd, - 0xbd, 0xe8, 0x00, 0x82, 0x00, 0x00, 0x00, 0x20, 0x2d, 0xe9, 0x00, 0x42, - 0x02, 0xb4, 0xdf, 0xf8, 0x10, 0x10, 0xd1, 0xf8, 0x00, 0x90, 0x02, 0xbc, - 0xff, 0xf7, 0xda, 0xfd, 0xbd, 0xe8, 0x00, 0x82, 0x00, 0x00, 0x00, 0x20, - 0x2d, 0xe9, 0x00, 0x42, 0x02, 0xb4, 0xdf, 0xf8, 0x10, 0x10, 0xd1, 0xf8, - 0x00, 0x90, 0x02, 0xbc, 0xff, 0xf7, 0x92, 0xfe, 0xbd, 0xe8, 0x00, 0x82, - 0x00, 0x00, 0x00, 0x20, 0x2d, 0xe9, 0x00, 0x42, 0x02, 0xb4, 0xdf, 0xf8, - 0x10, 0x10, 0xd1, 0xf8, 0x00, 0x90, 0x02, 0xbc, 0xff, 0xf7, 0xa2, 0xff, - 0xbd, 0xe8, 0x00, 0x82, 0x00, 0x00, 0x00, 0x20, 0x44, 0x2f, 0x57, 0x00, - 0x52, 0x65, 0x76, 0x65, 0x72, 0x62, 0x00, 0x00, 0x48, 0x50, 0x00, 0x00, - 0x4c, 0x50, 0x00, 0x00 -}; -unsigned int __FX_Reverb_HP_LP_bin_len = 5140; diff --git a/app/FX/Reverb.bin b/app/FX/Reverb.bin new file mode 100644 index 0000000000000000000000000000000000000000..a5f078797503d797c5af9acf461eb7c0caff5ba2 GIT binary patch literal 2768 zcmaJ@eN0=|6+h3<2IqmpBPkS2Xbnk7lPoG9MPu0-BMaMLh)SBFEuJQ0upRp;5YK$1 zeVR79&^4mUggUAaw;9pOSKX>|yQJ%?vSd=XOj#>6leKJrOi7k5fhzCHK%JOv89V3s z@zGVylYai)d(OG%o^$Sb_qna1Wq%8&M$OiZt0JIDM;1seDC{nQj*@zGjG|th+ zx!Tx-Oyf-m8gE8yL_CDZLlhuH1U>l(4nej&f^78&vNa&cmi8`0(4G$?$X5}9d=(?e zml;96N)THRp8`}O0Rw3L4F>*iWIwXVL2DE8R^&6tyOEzmrib#a;y`>xovr<>#7Z&I zL;mU6hNwe(wN4s$XxyXmPdTuV?MaPa()f(VF^zw%@kNa=QO^jvE#dsKke`L zM>@dc33Z2hJ>E#f`z%hnLcWj(HQl|Qptsw1#2-On-~Wrkk)xgdo*wA&_x6RMqc0Fp z?ZOfNnlq2T+lOnvDC_CC{j|Qh-AVnlvM=?NcXQ#zCrj!cksg*ognolYm&iMMBj(ZG*v(D1yGZ_i&EX_!YS0#pd zBbSjCtjcI^n9t?5I{5g^Y-N3s^Y-$xb!K^aAHs^`eKj>TRsahk^X}4nV?oe+^B971 zr+0^5)F%*o=92sOD8?6^O^vQb%$W;gw16>+`k>uq4BDv<;#Gx{QDzxaYTSJAs-kmW zQ>vt~3}j=lBKYSt3=GDn*z*$i^J2#Yo0RLCVR%g0?Y^q;(luq5Tg|)qX6Iq{yc}Q? z(uYc}Jg96$Hc5kuDC-=5aAeK5=h_`Lj)Q6a8#ctN_5=89N2IPKl#RQtDQ0;@$&=vB z$LZYb#`$(GF{i6eDB|7`CD%2gn1&KcKJq4vPZY)!(Tr@?4VSYiVV*hM?=sl?4%6>? z)A2LM^&4+F%dF$!8LZi__C-$@TYvDRVEy=`kDkob5b6NJHh@3cp#CMhdhcMpzJ;hq zG$5$Y5{e-@qHMsZ^sy1e7)>Zy7=wUW>7%FFbnFzXh#q77(6j6~W@(5GDjTAMicyX; zn>@+R%KW@fxV&f*;>;Vn&n`u$*>kbqFPaSeLiX-rHf%0#Xxwt2U5=&MoOE%~1jkrF zs$LS|RRyA>3cUXw`%M1bqKVtfoU!Vqd@-Ae!UkOT9=jytn&=L;1NR8S>+H5n>;JT9 z%J~M%dB1|aASW3Nz0RiO-?CZxVJ4cn#XPP&Z5GkLNIqyizpyz!#HOOOM+Mu7z9KNq za#UYQ=9K=+W~D+l91|Avgz|L3S&AV`U3*L77Yt0h!T`6he8wUSkm`7$Sx8a_Z(&{dHatVIl? zh?$wVE~9)=P-}5H#;1nepRpa7kzVZ;KJ~9Q%B--Ks(BdwP!41fXH7BcI;zjwiI#}e zNo%KDuzI?2W|#R?$$`^sKo-?l#+eYMjE=DiiK2duO}c5nqFU;xB(qC&Dzq=13ZJSy zAXdG3hl{S93ijmc$xv=9J+azPsgkxi?1@ck>~tal^h5EJG|8Hxe__*fzS20`xh{tS z5xY#wK@_KHNBgEv4n5+!z^8tEFvnr7`CC@0!}|Hx-%2QYDWMpL`tgl>h8-Vjy7gN7 z-{*82;T10WA>IyycssP$;7ux>Qb4|YhjR}rAoXK*hcOz=O1^%FlS#LLx?gCzQQL}^ zq4vfVeSGGQ@x__hwQ~ izyN+v>gk(;7_c@x{vFW%2tk9lOa1OUy`gT@!~XzU2loH~ literal 0 HcmV?d00001 diff --git a/app/FX/Reverb.cpp b/app/FX/Reverb.cpp new file mode 100644 index 0000000..f8181ef --- /dev/null +++ b/app/FX/Reverb.cpp @@ -0,0 +1,75 @@ +// 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 "stmlib/stmlib.h" +#include "stmlib/dsp/filter.h" +#include "clouds/dsp/fx/reverb.h" + +float raw = 1.f; +float reverb_amount = 0.75f; +float feedback = 0.5f; +float gain = 1.f; + +uint16_t buffer[16384] = {}; +clouds::Reverb fx_; + +void engine::setup() +{ + fx_.Init(buffer); + + engine::addParam("D/W", &raw); + engine::addParam("Reverb", &reverb_amount); + engine::addParam("Damp", &feedback); + engine::addParam("Gain", &gain); +} + +void engine::process() +{ + auto inputL = engine::inputBuffer<0>(); + auto inputR = engine::inputBuffer<1>(); + auto outputL = engine::outputBuffer<0>(); + auto outputR = engine::outputBuffer<1>(); + + fx_.set_amount(reverb_amount * 0.54f); + fx_.set_diffusion(0.7f); + fx_.set_time(0.35f + 0.63f * reverb_amount); + fx_.set_input_gain(gain * 0.1f); // 0.1f); + fx_.set_lp(0.6f + 0.37f * feedback); + + for (int i = 0; i < FRAME_BUFFER_SIZE; i++) + { + outputL[i] = inputL[i]; + outputR[i] = inputR[i]; + } + + fx_.Process(outputL, outputR, FRAME_BUFFER_SIZE); + + for (int i = 0; i < FRAME_BUFFER_SIZE; ++i) + { + outputL[i] = raw * outputL[i] + (1 - raw) * inputL[i]; + outputR[i] = raw * outputR[i] + (1 - raw) * inputR[i]; + } +} diff --git a/app/FX/ReverbSC.bin b/app/FX/ReverbSC.bin new file mode 100644 index 0000000000000000000000000000000000000000..f37fdcfd1a309fc4a2e3de3bb997ff2dc178984e GIT binary patch literal 3224 zcmaJ@3s6+o89sOKWm#9$RY4GOW{uzjK|p+Eg}9ORuIxf27RR`q4lL~Aa;vgkK>bFdG(=*|3<*hQ*8pSj;$p`I-$dU-1C* zH3wk65`ekDZ9>vPh)PHS2g3-C6ub*Z@t|*krh*QFt^oa*1;EG7!9I3>_9e0d;(Kj^ zJpOwiygCB9h9d^1zcEbRVY(|!4|2rF)a%2vF-+US^xZK1LzsRTrhg67Pr`H{OoL%M z9;V_eX`9@;+`f_@<&dJH@}1>XMNXg3xd)pa<*xD~$aYp0d7L|4+uc4etG~8y5@S0G-|_M$Q`JLF@AFU+W@uJTq_ zh2#*2cTC7~UsHZXA#$s-LLy7f_wx7rnK}0-ZPNUQzr$rV|9+0Jq4&f+|FU%Ze&<$| zPv7`8m%xv5)2}KTM;|>Uy-$g}i`Gf?ibhuHuza3=BtM`-(r(atg_rx3NQv==sVLv0 zeR7Z*{;mJKUg1KTyJ_8Hu6pw$+U6*=^eZ#v2FM!}BDE^h9Y(rPA4%(zjWklvBB=1* zLH*JPh`fSclJ0|Eq6-|SXd9wLAo?((3bNNqdI|Ao;EJn3^VwZFJG(=imDTe9TeDJs z#Q&l7>TX@g(_GKyE^TO);Q8vnxo-ud^MLWdX{*tp?yw|FMVfinFpah4|sO=uwyIHPjd)U=9M&SetbbES0{K^vpH^kR+^_7H z00-7KP*bX+J>077I|Cd#Pq#?{Y6E|-JVYaHHR2SpliK8Vx=?;KcX2Uf;4hH()GZ>#Sbt(jJ<@cLRsI8>`>K_d_K1#0{^RfF;6+`Y0x`2}S9hQdoFC66kd)gZe?fQqQcA=?E-D-F^_$Md35#ROR{0* zqUEqh-496?MTcIvBzMq*GP|>&M9Sl1>mL@Xi78x5p(;cPissO-$cti=^(JEB)mYY1 z$;q-VZ6Y)ECjDrQzWFL=)O7aT)*kM;6?l_8z3%PJld_!!$Fk48)t+t4_)E4h@KQD= z^NT1K(xR)$zWwsg*AjDr*#74avX|zsgzQOA7_m{ir-+jzvejmqNIkR?^L!)C$S zeCL>-Td7-00&V^h&!XkC0$gOy!{_8^OrJt^Q3CRr#U>9wx{v=5Qw_WE4!j z3)Y1rx{R)%zvx8oynr{4ADvg}6fs-k@ut!kC5|%sjx-*cXr~;V=pVc}`k`Gq-D?@q zWew6=dBWEM%6f&pluj-~KS8b-pL>*smzH`Kn z^QG`Xe-5`sGg`xA!a1%foTEX}=&zwd3)Q$RH|>xoTLx*QY*7=k*u5H|H9$Fe0QK2P z-I#sts6DGZ2>;vYYoJ=$0zHzp_wKf{k1|$CJ4`HNYsa>o%@D6E5vYG&&#fFEi+rG4 zy7zAJ*?uKO*0z*F&xPzFTc*es&IoE#ds>wRh#R3#vR_0cEW|6ZxmkyH&CQBgsT$6aqXulo#{pE~+R)N$Nm>S#^Wqu2PyclMC+ z&_N!EULNLy<5^!06QkP0W;px&8NWS~{6c2tdoSFa_OUq;9B+4$EeW$#W47P-FB5_Z z+J6@B@5DKc@%9tWBr!u2f;v*_93LxtFv}KeU#}X|zH-Lf<87@<4CVw+W;1KUn+nHv zX1u??%^G8Wdty&A#0k!Hd%vO&=`+buv>C%kf!s&1WuQ!qXtu~xJ0}>LPV1oM-BSRBmB%JaeQpf!_O5W{T;bI0vgdQ zwD8Ap3%u8mEUa2clVl;Y9W(#rZBA}Re|!cl)-OlaZ9~6eI%2xl$wQD{xvIsi(M-&m z-YlHm3|N2-0J|5vr?=Z+Gq5Zcv%Bn?^S(iQg(PlPg*DvrCTsh;Z?EcY`X7{gd-C9? z04M}r0a8cEIt_mR42G*Jsn`5zd~Cyidv1~a5E-A975spVKKy<=)A;wxjy#s3?$*xk za%We}s4CcgX&mPh-qPd`H}Lx;JD$c;%ar{@Z$M$i5-YwU+sF9n1{bf06i- dnOK~nC2b24-ELQjv-GFP0m<`&M*J~ literal 0 HcmV?d00001 diff --git a/app/FX/ReverbSC.cpp b/app/FX/ReverbSC.cpp new file mode 100644 index 0000000..55485c3 --- /dev/null +++ b/app/FX/ReverbSC.cpp @@ -0,0 +1,67 @@ +// Copyright (C)2022 - 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" + +extern "C" +{ +#include "soundpipe/revsc.c" +} + +static sp_data sp_data_ = {}; +static sp_revsc sp_revsc_ = {}; +static uint8_t mem[107440]; // sp_revsc_.aux.size + +static float raw = 1.f; + +void engine::setup() +{ + sp_data_.sr = SAMPLE_RATE; + sp_data_.aux.ptr = &mem[0]; + sp_data_.aux.size = sizeof(mem); + sp_revsc_init(&sp_data_, &sp_revsc_); + + sp_revsc_.feedback = 0.97f; + sp_revsc_.lpfreq = 10000; + + engine::addParam("D/W", &raw); + engine::addParam("Feedback", &sp_revsc_.feedback); + engine::addParam("LpFreq", &sp_revsc_.lpfreq, 0, (SAMPLE_RATE / 2)); +} + +void engine::process() +{ + auto inputL = engine::inputBuffer<0>(); + auto inputR = engine::inputBuffer<1>(); + auto outputL = engine::outputBuffer<0>(); + auto outputR = engine::outputBuffer<1>(); + + for (int i = 0; i < FRAME_BUFFER_SIZE; ++i) + { + sp_revsc_compute(&sp_data_, &sp_revsc_, &inputL[i], &inputR[i], &outputL[i], &outputR[i]); + outputL[i] = raw * outputL[i] + (1 - raw) * inputL[i]; + outputR[i] = raw * outputR[i] + (1 - raw) * inputR[i]; + } +} \ No newline at end of file diff --git a/app/GND/FFT.bin b/app/GND/FFT.bin new file mode 100644 index 0000000000000000000000000000000000000000..7583f9d0f8d1280692bd10ad516f01ed412aba13 GIT binary patch literal 12688 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 literal 0 HcmV?d00001 diff --git a/app/GND/FFT.cpp b/app/GND/FFT.cpp new file mode 100644 index 0000000..f813765 --- /dev/null +++ b/app/GND/FFT.cpp @@ -0,0 +1,191 @@ +// Copyright (C)2024 - 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 "../lib/stmlib/utils/ring_buffer.h" + +extern "C" +{ +#include "../lib/fft/fft4g.h" +#include "../lib/fft/fft4g.c" +} + +#include +#include + +static float apmlitude = 1.f; +static int32_t band = 0; +static const char *sbands[3] = {" 16", " 32", " 64"}; + +struct Complex +{ + float re; + float im; +}; + +const size_t N = 1024; +stmlib::RingBuffer spectrum; +float w[N * 2]; +constexpr int sq_n = 32; // sqrt(N); +int ip[4 + sq_n]; // new int[(int)ceil(4.0 + sqrt((real_t)N))]; +float magnitudes[N / 2] = {}; +float window[N]; +int count = 0; + +void engine::setup() +{ + apmlitude = 1.f; + engine::addParam("_Scale", &apmlitude, 0.f, 2.f); + engine::addParam("_Bands", &band, 0, 2, sbands); + engine::setMode(ENGINE_MODE_COMPACT); + ip[0] = 0; // indicate that re-initialization is necesarry + spectrum.Init(); + + for (int n = 0; n < N; n++) + window[n] = 0.5f * (1.f - cosf((2.f * M_PI * n) / N)); +} + +void set(float *target, const float *src, float amp, float offset) +{ + for (size_t i = 0; i < FRAME_BUFFER_SIZE; i++) + target[i] = src[i] * amp + offset; +} + +void engine::process() +{ + const float m_offset = log10f(N); + + auto inputL = engine::inputBuffer<0>(); + auto outputL = engine::outputBuffer<0>(); + set(outputL, inputL, apmlitude, 0); + + for (size_t i = 0; i < FRAME_BUFFER_SIZE; i += 2) + { + if (spectrum.readable() == (N / 2)) + { + float *buff = const_cast(&spectrum.ImmediateReadPtr(0)->re); + rdft(N, 1, buff, ip, w); + + // for some reason, this routine returns the second half of the spectrum (the complex conjugate + // values of the desired first half), so we need to take the complex conjugates: + for (int n = 3; n < N; n += 2) // start at n=3 (imaginary part of the first bin after DC) + buff[n] = -buff[n]; + + magnitudes[0] = buff[0]; + + for (int k = 1; k < N / 2; k++) + { + float re = buff[2 * k]; + float im = buff[2 * k + 1]; + magnitudes[k] += sqrtf(re * re + im * im); + // auto db = sqrtf(re * re + im * im); + // auto db = 20 * log10f(db); + // auto db = logf(re * re + im * im); + // magnitudes[k] = db; + } + count++; + spectrum.Flush(); + } + else + { + float h = (float)window[spectrum.readable() * 2]; + float h2 = (float)window[spectrum.readable() * 2 + 1]; + Complex v = { + outputL[i] * h / sq_n, + outputL[i + 1] * h2 / sq_n, + }; + spectrum.Overwrite(v); + } + } +} + +float fft_read(int s, int e) +{ + float sum = 0; + while (s <= e) + sum += magnitudes[s++]; + + return (sum / count); +} + +float level2[64]; +float level[64]; + +void draw_spectrum(int yy, int hh) +{ + float logN2 = logf(N / 2); + + int bands = 16; + if (band == 1) + bands = 32; + else if (band == 2) + bands = 64; + + int to = int(expf(logN2 * 0 / bands)); + for (int b = 0; b < bands; b++) + { + int fr = to; + to = int(expf(logN2 * (b + 1) / bands)); + + if (level2[b] > 0) + level2[b] -= 0.1f; + else + level2[b] = 0; + + level[b] = 10.f / hh + log10f(fft_read(fr, to)); + level2[b] = std::max(level[b], level2[b]); + } + + int w = (128 / bands); + for (size_t i = 0; i < bands; i++) + { + auto y = level[i] * hh; + gfx::fillRect(i * w, yy - y, w - 1, y); + + y = level2[i] * hh; + gfx::fillRect(i * w, yy - 1 - y, w - 1, 1); + } + + // uint32_t ylim = 58; + // for (uint32_t i = 0; i < 128; i++) + // { + // auto y = 40 + -(magnitudes[i] / 2); + // gfx::drawLine(i, 58, i, y); + // }; + + for (uint32_t i = 0; i < (N / 2); i++) + magnitudes[i] = 0; + count = 0; +} + +void engine::draw() +{ + draw_spectrum(60, 32); +} +void engine::screensaver() +{ + gfx::clearRect(0, 0, 128, 64); + draw_spectrum(64, 48); +} \ No newline at end of file diff --git a/app/GND/Scope.bin b/app/GND/Scope.bin new file mode 100644 index 0000000000000000000000000000000000000000..3d0863725e30c27d9102209186edb037ebc663e0 GIT binary patch literal 1808 zcmaKsZ%i9?7{{OM9Sniln`O|g%-jHpj-iE-g-qiRn>%Q6s{$s(nf5|ku1jezZNco` zz>I$yFp)T4;H%BJ7=mv=!0}=Y8%ul*VG@lmHZ>Vrq?gt?Em?Fv&+XWVD8J;B@9+83 z=Xrj2ziYRvJO++)HG@{>gTAm=-gWu%|(m)(xUUw5|Eb};3@wNQx#LsnEDZ8 zq`^5;$4&jh)G1TbrhaSccc$Jl^>x zOWWdjnA0yuBC%cw#e+2AW`B?a0k0gF`+eafjgO5G8Z=QyI7->UXdiBHoS2$GQyvI} zW7yIc@r6{HGd7S^2a<+~RuU3wJRD7ij1rwm-1p%f^Yr9dr(L3F^x10W*_RVue zMx_Hv_jIALt5kkT&2DgloDxzKk`QlB(|194gf-%CDeSaeQYBa*KR?TM^yImgi{jgP z&f}Npu5R|F`^3-Q$d_H|$(OcR#EW8ynFR}U-}$-vjAeAM=X}OijHlsko=ZB6oXx-p zTCm5H)q(si7bL6OioGp7`LlXk@d8GQ8ZJmB#zg6L%jkZ^ro5UJSeu_uV`<}i5m0Fc znzIIZ7U5@&^9n1_F3yq zwC*j_x%t^zcP-5$&^$J!rrn|R=->PJO)i`ux)c^v%-z^d~|88BIw2o$M?0q@C^tnp(wv z{u}wr!(&rWQ-1R|MG(tey~fkvvP0YvSCi}9hTZw;hMm8bt7Q*~S97(@yfjq5d+D%P zbf3FBlj}at<(Pt>zOSvW68DLMI4}LUwwmEIhsV)|)$u)nI<0dfeR@iZh?j7FLF` 128) + i = 0; +} + +void set(float *target, const float *src, float amp, float offset) +{ + for (size_t i = 0; i < FRAME_BUFFER_SIZE; i++) + target[i] = src[i] * amp + offset; +} + +void engine::process() +{ + auto inputL = engine::inputBuffer<0>(); + auto outputL = engine::outputBuffer<0>(); + + input = inputL[0]; + set(outputL, inputL, apmlitude, offset); + output = outputL[0]; + + if ((engine::t() % 50) == 0) + push_scope(scope, outputL[0] * 20); +} + +void engine::draw() +{ + int y = 38; + for (int x = 0; x < 127; x++) + { + if (x % 3 == 0) + gfx::setPixel(x, y); + gfx::drawLine(x, y - scope[(i + x) % 128], x + 1, y - scope[(1 + i + x) % 128]); + } + + char tmp[64]; + sprintf(tmp, "IN:%+1.2fV", input * 5); + gfx::drawString(0, 54, tmp, 0); + sprintf(tmp, "OUT:%+1.2fV", output * 5); + gfx::drawString(64, 54, tmp, 0); +} \ No newline at end of file diff --git a/app/MIDI/Clock.bin b/app/MIDI/Clock.bin new file mode 100644 index 0000000000000000000000000000000000000000..f44b1fede7716b6dd30200565be3aaa852913431 GIT binary patch literal 2020 zcmaKsZ%i9y9LImxJ1T!VIALQQf3}0xIACN9$wC}4XTduuAS@Y)WJ}u87OxqUTU$0v zmWVhFiN4V33ug9)NQ^OV={9Qif~LOEcV?F8o5d_@OoY)lWtg={;`#fv4~#(MlFxnb z_wRXr&vW0&5x~C{cN-a9PxxA=-rdH!?Bg) z555%$`f<>4Jq%->QEV1QLVo{_cEIEF4R}JHF<0QF)@Q~D8q{Df)?+qJ=w(YCpNQxa z5!a|IaOyO*%eRH1ijjK9Zku(6j;7lGg-vg;+jy_ zzj{I76=97NDjxQyp>%k?th9gioMm|Z*c*`g$kLe=Qr_1#m+Wbdzv+NfCln=l#g;WS z-Eas=zV?R0F=b6mPl<7w=t8> znpv1t>lJIAk?|O`X1-<19y0i7I&QW_H`kx=o8`bA|0!A0b6d;L5Ow^#bW!V18?9fv z&%=Xd-nNS053RKWkr7&J7xFsNi_qHinCKL778C9Jz~$<1MROADgIVDW*EXwu>DX8* zb{6j&*W&{?);Z)&k?Ad~8}YGK>GlS6~`L(%#tj`^3`w#7-OkKj!s) zVjpbBOu5~y)~uSYy0N)!ds0_@+crfZq3yCqw{5J)KZ1@nksOm_ds2>v#=OlV_y?Mz#l<3COwA5#DT literal 0 HcmV?d00001 diff --git a/app/MIDI/Clock.cpp b/app/MIDI/Clock.cpp new file mode 100644 index 0000000..4810f10 --- /dev/null +++ b/app/MIDI/Clock.cpp @@ -0,0 +1,92 @@ +// 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. +// + +// build_flags: -fno-inline -mfloat-abi=soft -mfpu=fpv5-d16 + +#include "../squares-and-circles-api.h" +#include + +static int32_t bpm = 120; +static int32_t ppqn = 0; +static const char *ppqn_names[]{ + "4ppqn", "8ppqn", "24ppqn"}; +static int32_t offset = 0; +static int32_t impulse = 1; +static int count_down = 0; +static uint32_t next = UINT32_MAX; +static uint32_t last_t = 0; + +void engine::setup() +{ + // 24, 8 or 4 ppqn + bpm = 120; // machine::midi_bpm() / 100; + engine::addParam("@BPM\n%d", &bpm, 60, 250); + engine::addParam("@ppqn", &ppqn, 0, 2, ppqn_names); + engine::addParam("@Impulse\n%dms", &impulse, 1, 5); + engine::addParam("@Offset\n%dms", &offset, 0, 127); + engine::setMode(ENGINE_MODE_CV_OUT); +} + +uint8_t last_clk = 0; +uint8_t clk_change(uint8_t clk) +{ + if (last_clk != clk) + { + last_clk = clk; + return last_clk; + } + else + return 0; +} + +void engine::process() +{ + machine::clk_bpm(bpm * 100); + uint8_t clk = clk_change(engine::clock()); + + if (clk) + last_t = engine::t(); + + uint32_t div = ppqn == 0 ? 6 : (ppqn == 1 ? 3 : 1); + + if ((clk % div) == 1 || (ppqn > 1 && clk)) + { + next = engine::t() + (offset * 2); + } + + if (engine::t() == next) + { + next = UINT32_MAX; + count_down = (impulse * 2); + } + + int16_t a = count_down-- > 0 ? (5 * PITCH_PER_OCTAVE) : 0; + std::fill_n(engine::outputBuffer_i16<0>(), FRAME_BUFFER_SIZE, a); + std::fill_n(engine::outputBuffer_i16<1>(), FRAME_BUFFER_SIZE, a); +} + +void engine::draw() +{ +} diff --git a/app/MIDI/Monitor.bin b/app/MIDI/Monitor.bin new file mode 100644 index 0000000000000000000000000000000000000000..fa9aa52767408db7bd5d68804525ec34450aa134 GIT binary patch literal 2392 zcmaKte@s(X6vyv-ui&FC@I=r8b-orzr2ZJ0xDa(2Jm{;muvVvwWK$?@v5oxb+Txfj zf$3a2gNqB!U?$1ph;fD`=wNe+q--<${YUE`3*aBJm{_%0@|w8#h%xM(_5o&QH2J*m zIrp4<&$;jBzV5GUXw(xusiFy)%OGSoA>;x8E?EVz3L4NXKntjWYyihN0LNAXIF<+G z0Be9;ARoY-0swQ?0+^!%FsBf}oFV{oiUG{Q-#UN-FqZ)^R|Q}$w3^Dz1l0rB>v{lt zd;!27HvrfR4`43_0M|4EC4inH6(FRXB90DN@MX}aP{0QI7w93-JuvP9-41#Lv=9r! z58o5~sy|Zvw3~hxXycyn$EThoT?p)5z}pnzaQ;a}KT~v6Q3zFc<3@3PMLml?9882t zFZ+|CzbpEuqIVUQ6rER;rPK3r6)jTKsOUyT8|&-pUu^8^^o6zaJ~yp zhtKV6_8j$ehMK+3PItQpGrIpf3he4Uu>={yVuwA1Ae zk`7M?^p^_19t!w650juDB-93pt^N*pF7Fr*gt9fsOoh(!e>NV|V$Mo-)dZVbX}x#< z)y$No_udVU&#QQ6m=9mJ@PVpHynA@Jm{j~tFLPCA@moj)$GLH)p-EO%kBA3lm952s zcWkk4>duYdk@KgTWNkGqj))p1i$w4)apSqR?0VP-$+3~rsRwk8%1DR6=QXx`uff}I zTwQBu0iR=SHK-L>W5JLQ`(|h=^-aJ##{;DR_O#`J)M&RktdI>eX#Ug~DbX5ee$3Kf zB_%kbH3;C<<6a!3G_S-c@?xRLR9?2czxi>jF11H8$Ry8d1hjd z(E?Eri)CtOIn2CnVUrZQMc3;uuwBx!)y7(}M&v{`$*`9px-0je z*j8H^_E%B5yVzUoJ^qBrn_2gLqBYN5mhmKS+s69-Cye9vx*rptGfgtZVGUe8Kh-xG zHrOWShj^I36e)s8MlxSLX4xeEmZa2cwlm2=ja}kdbs~cK8WgVpbH_yKbpT zb&GF-O=hwO&54+LZ1TQzdc(=Yp2KZzZ5!cTZU*q9gy)3kTnSVG_}!=m>VVyVf1*3} z#){q}<>n|cwM7e$QBofj7Krp~KV>S2HZA$T^wXy7==ml8=YGbN5uI7`f9TiuUKFg; zc4}H8njiBN8)hr6+xJ3D#S5T{>tr{-c!O*q+HCH85Ixd z&dsweWb5|Z1EP8E*406oozhBu+7@$blrrTlbi$WM;0dpAoyaM*9 zcnY2aqEnphz0k`fsGL@_Ho_QbV~f<6F=GB$W*u~NSV!&H9K`+JGpnK(!23Yf&h5Q6 z2+v1medLzzI9MlS?bLVi0g*{)X)Z9^I|Q}UYlQ_mHH!}(=nV^uV(-1C0}p3&!NTCV zxLu;OPVr8h7zV^|!K1;Oj#J=`fyaOsi__qJ8E4>mDUN4Or%v_@c?fP6`sw>mq&}jn zqq@^$c<1~RoRx!I8tT8T3VY+XKAeGdk*x#JE<75u#;KVWqXzN>v@_iMpV{^@wZ@8Er1*F0`0&X_WD{g zZ! + +static uint8_t voice[4] = {}; +static stmlib::VoiceAllocator allocator = {}; +static int16_t pitch = 0; +static uint8_t cc[128] = {}; + +void engine::setup() +{ + allocator.Init(); + allocator.set_size(LEN_OF(voice)); + engine::setMode(ENGINE_MODE_MIDI_IN); + for (auto &c : cc) + c = 0xFF; +} + +void engine::process() +{ +} + +void engine::draw() +{ + gfx::drawString(2, 12, "VOICE KEY", 0); + gfx::drawString(66, 12, "CONTROL", 0); + + for (int x = 0; x < 128; x += 3) + gfx::setPixel(x, 18); + + char tmp[30]; + for (size_t i = 0; i < LEN_OF(voice); i++) + { + sprintf(tmp, "#%d %4d", i, voice[i]); + gfx::drawString(2, 20 + i * 6, tmp, 0); + } + + for (int y = 12; y < 60; y += 3) + gfx::setPixel(64, y); + + int bpm = machine::clk_bpm(); + int bpm2 = ((bpm % 100) / 10); + sprintf(tmp, "clock: %3d.%d", bpm / 100, bpm2); + gfx::drawString(66, 20, tmp, 0); + + sprintf(tmp, "pitch: %4d", pitch); + gfx::drawString(66, 26, tmp, 0); + + int y = 32; + for (int i = 0; i < 128; i++) + { + if (cc[i] < 0xFF) + { + sprintf(tmp, "cc-%d: %4d", i, cc[i]); + gfx::drawString(66, y, tmp, 0); + y += 6; + } + } +} + +void engine::onMidiNote(uint8_t key, uint8_t velocity) // NoteOff: velocity == 0 +{ + if (velocity > 0) + { + auto ni = allocator.NoteOn(key); + voice[ni] = key; + } + else + { + auto ni = allocator.NoteOff(key); + voice[ni] = 0; + } +} + +void engine::onMidiPitchbend(int16_t value) +{ + pitch = value; +} + +void engine::onMidiCC(uint8_t ccc, uint8_t value) +{ + cc[ccc % 128] = value; +} + +void engine::onMidiSysex(uint8_t byte) +{ +} diff --git a/app/MIDI/VAx6.bin b/app/MIDI/VAx6.bin new file mode 100644 index 0000000000000000000000000000000000000000..54ffdd6125e4383f8fb82998d771c85f0837f702 GIT binary patch literal 17492 zcmch934D~r`Tx5|4nly4C>T*f2nj4_

1GEIBq14iBK!tu~uGtbhoC;H$#kixC71 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Ð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 a7Cf|SCD|D%x!L&d9t2@gVeYD20Q^4#_j#`X literal 0 HcmV?d00001 diff --git a/app/MIDI/VAx6.cpp b/app/MIDI/VAx6.cpp new file mode 100644 index 0000000..55e298b --- /dev/null +++ b/app/MIDI/VAx6.cpp @@ -0,0 +1,202 @@ +// 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" +#define FLASHMEM __attribute__((section(".text"))) + +// #include "../lib/plaits/dsp/engine/virtual_analog_engine.h" +// no virtual functions hack + +#define PLAITS_DSP_ENGINE_VIRTUAL_ANALOG_ENGINE_H_ + +#include "plaits/dsp/engine/engine.h" +#include "plaits/dsp/oscillator/variable_saw_oscillator.h" +#include "plaits/dsp/oscillator/variable_shape_oscillator.h" + +#define VA_VARIANT 2 + +namespace plaits +{ + class VirtualAnalogEngine + { + public: + VirtualAnalogEngine() {} + ~VirtualAnalogEngine() {} + + void Init(stmlib::BufferAllocator *allocator); + void Reset(); + void LoadUserData(const uint8_t *user_data) {} + void Render(const EngineParameters ¶meters, + float *out, + float *aux, + size_t size, + bool *already_enveloped); + + private: + float ComputeDetuning(float detune) const; + + VariableShapeOscillator primary_; + VariableShapeOscillator auxiliary_; + + VariableShapeOscillator sync_; + VariableSawOscillator variable_saw_; + + float auxiliary_amount_; + float xmod_amount_; + float *temp_buffer_; + + DISALLOW_COPY_AND_ASSIGN(VirtualAnalogEngine); + }; + +} // namespace plaits + +#include "../lib/plaits/dsp/envelope.h" +#include "../lib/stmlib/algorithms/voice_allocator.h" +#include "../lib/stmlib/utils/random.h" + +#include "stmlib/dsp/units.cc" +#include "stmlib/utils/random.cc" +#include "../lib/plaits/dsp/engine/virtual_analog_engine.cc" + +plaits::VirtualAnalogEngine voice[6] = {}; + +uint8_t buffer[LEN_OF(voice) * plaits::kMaxBlockSize * sizeof(float)] = {}; +plaits::EngineParameters parameters[LEN_OF(voice)] = {}; +plaits::LPGEnvelope lpg[LEN_OF(voice)] = {}; +bool enveloped[LEN_OF(voice)] = {}; + +stmlib::VoiceAllocator allocator; + +float timbre = 0.5f; +float morph = 0.5f; +float harmonics = 0.5f; +float pitch = 0; +float pitch_bend = 0; + +float decay = 0.5f; +float hf = 1.f; +float pan[LEN_OF(voice)] = {}; +float stereo = 0.5f; + +float voiceBuff[FRAME_BUFFER_SIZE] = {}; +float dummy[FRAME_BUFFER_SIZE] = {}; + +void engine::setup() +{ + allocator.Init(); + allocator.set_size(LEN_OF(voice)); + engine::addParam(V_OCT, &pitch); + engine::addParam("Harmo", &harmonics); + engine::addParam("Timbre", &timbre); + engine::addParam("Morph", &morph); + engine::addParam("Decay", &decay); + engine::addParam("Stereo", &stereo); + engine::setMode(ENGINE_MODE_MIDI_IN); + stmlib::BufferAllocator buffAllocator; + buffAllocator.Init(buffer, sizeof(buffer)); + + for (size_t i = 0; i < LEN_OF(voice); i++) + { + lpg[i].Init(); + voice[i].Init(&buffAllocator); + } +} + +void engine::process() +{ + auto polyBuffL = engine::outputBuffer<0>(); + auto polyBuffR = engine::outputBuffer<1>(); + + std::fill_n(polyBuffL, FRAME_BUFFER_SIZE, 0); + std::fill_n(polyBuffR, FRAME_BUFFER_SIZE, 0); + + const float short_decay = (200.0f * FRAME_BUFFER_SIZE) / SAMPLE_RATE * + stmlib::SemitonesToRatio(-96.0f * decay); + + const float decay_tail = (20.0f * FRAME_BUFFER_SIZE) / SAMPLE_RATE * + stmlib::SemitonesToRatio(-72.0f * decay + 12.0f * hf) - + short_decay; + + for (size_t i = 0; i < LEN_OF(voice); i++) + { + auto p = parameters[i]; + p.note += (pitch * 12.f) + pitch_bend; + p.timbre = timbre; + p.morph = morph; + p.harmonics = harmonics; + + voice[i].Render(p, voiceBuff, dummy, FRAME_BUFFER_SIZE, &enveloped[i]); + + lpg[i].ProcessPing(0.5f, short_decay, decay_tail, hf); + + float l = cosf(pan[i] * M_PI / 2); + float r = sinf(pan[i] * M_PI / 2); + + for (int s = 0; s < FRAME_BUFFER_SIZE; s++) + { + polyBuffL[s] += (voiceBuff[s] * lpg[i].gain()) * l; + polyBuffR[s] += (voiceBuff[s] * lpg[i].gain()) * r; + } + + parameters[i].trigger = plaits::TriggerState::TRIGGER_LOW; + } +} + +void engine::draw() +{ +} + +void engine::onMidiNote(uint8_t key, uint8_t velocity) // NoteOff: velocity == 0 +{ + if (velocity > 0) + { + auto ni = allocator.NoteOn(key); + parameters[ni].trigger = plaits::TriggerState::TRIGGER_RISING_EDGE; + parameters[ni].note = key; + parameters[ni].accent = velocity > 100; + + pan[ni] = 0.5f + stereo * (stmlib::Random::GetFloat() - 0.5f); + + lpg[ni].Trigger(); + } + else + { + allocator.NoteOff(key); + } +} + +void engine::onMidiPitchbend(int16_t pitch) +{ + pitch_bend = ((float)pitch / 8192) * 12; +} + +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/NOISE/808_squares.bin b/app/NOISE/808_squares.bin new file mode 100644 index 0000000000000000000000000000000000000000..104858e58972c21688db3286a4f5320d61091e42 GIT binary patch literal 2268 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 RipVdj&knNs@&M3#^bb+hs$~EG literal 0 HcmV?d00001 diff --git a/app/NOISE/WhitePink.bin.h b/app/NOISE/WhitePink.bin.h deleted file mode 100644 index 45a349f..0000000 --- a/app/NOISE/WhitePink.bin.h +++ /dev/null @@ -1,164 +0,0 @@ -const uint8_t __NOISE_WhitePink_bin[] FLASHMEM __attribute__((aligned(32))) = { - 0x55, 0x44, 0x4c, 0x4d, 0x10, 0x00, 0x13, 0x00, 0x88, 0x01, 0x00, 0x00, - 0x24, 0x05, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x24, 0x05, 0x00, 0x80, 0x12, 0x00, 0x00, 0x00, 0x24, 0x05, 0x00, 0x80, - 0x1b, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0xb4, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x50, - 0xe1, 0x04, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x50, 0x8d, 0x04, 0x00, 0x00, - 0xe4, 0x00, 0x00, 0x50, 0xc5, 0x04, 0x00, 0x00, 0xec, 0x00, 0x00, 0x50, - 0xa9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x10, - 0x2c, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x10, 0x2c, 0x00, 0x00, 0x00, - 0x1c, 0x01, 0x00, 0x10, 0x30, 0x00, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x10, - 0x2c, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x57, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x64, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x71, 0x01, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x7f, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x40, 0xfd, 0x04, 0x00, 0x00, 0x4e, 0x4f, 0x49, 0x53, - 0x45, 0x2f, 0x57, 0x68, 0x69, 0x74, 0x65, 0x50, 0x69, 0x6e, 0x6b, 0x00, - 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, - 0x00, 0x5f, 0x5f, 0x75, 0x69, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, - 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00, 0x70, 0x72, 0x6f, 0x63, - 0x65, 0x73, 0x73, 0x00, 0x73, 0x65, 0x74, 0x75, 0x70, 0x00, 0x5f, 0x5f, - 0x70, 0x72, 0x65, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, - 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x5f, 0x5f, 0x70, 0x72, 0x65, 0x69, - 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x00, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, - 0x72, 0x72, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x5f, 0x5f, 0x69, - 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x00, 0x6d, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x00, 0x66, - 0x72, 0x65, 0x65, 0x00, 0x5f, 0x5f, 0x75, 0x69, 0x5f, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x00, 0x61, 0x64, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x5f, - 0x69, 0x33, 0x32, 0x00, 0x61, 0x64, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, - 0x5f, 0x66, 0x33, 0x32, 0x00, 0x5f, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x5f, 0x6c, 0x5f, 0x66, 0x70, 0x00, 0x6d, 0x65, 0x6d, 0x73, 0x65, - 0x74, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, - 0x04, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, - 0x04, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, - 0x04, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x18, 0x47, - 0x04, 0x00, 0x00, 0x00, 0x38, 0xb5, 0x08, 0x4b, 0x59, 0xf8, 0x03, 0x30, - 0x1d, 0x68, 0x55, 0xb1, 0x06, 0x4b, 0x59, 0xf8, 0x03, 0x30, 0x1c, 0x68, - 0xe3, 0x88, 0xb4, 0xf9, 0x04, 0x20, 0x61, 0x88, 0x20, 0x88, 0xa8, 0x47, - 0x20, 0x72, 0x38, 0xbd, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x10, 0xb4, 0x03, 0x4c, 0x59, 0xf8, 0x04, 0x40, 0xa4, 0x46, 0x5d, 0xf8, - 0x04, 0x4b, 0x60, 0x47, 0x10, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x59, 0xf8, - 0x03, 0x30, 0x18, 0x47, 0x14, 0x00, 0x00, 0x00, 0x10, 0xb5, 0x12, 0x4b, - 0x12, 0x4a, 0x59, 0xf8, 0x03, 0x00, 0x12, 0x4b, 0x59, 0xf8, 0x02, 0x10, - 0x9f, 0xed, 0x0d, 0x0a, 0x59, 0xf8, 0x03, 0x30, 0x82, 0xb0, 0xf7, 0xee, - 0x00, 0x0a, 0x98, 0x47, 0x0d, 0x4a, 0x0e, 0x4b, 0x0e, 0x49, 0x59, 0xf8, - 0x02, 0x00, 0x59, 0xf8, 0x01, 0x10, 0x59, 0xf8, 0x03, 0x20, 0x0c, 0x4b, - 0x00, 0x92, 0x59, 0xf8, 0x03, 0x40, 0x00, 0x22, 0x01, 0x23, 0x04, 0x31, - 0xa0, 0x47, 0x02, 0xb0, 0x10, 0xbd, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x2d, 0xe9, 0xf0, 0x4d, 0xca, 0x4a, 0xcb, 0x4b, - 0x59, 0xf8, 0x02, 0x20, 0x59, 0xf8, 0x03, 0x50, 0x11, 0x68, 0xc9, 0x4a, - 0xd5, 0xf8, 0x04, 0x80, 0xdf, 0xed, 0xc3, 0x6a, 0x59, 0xf8, 0x02, 0xe0, - 0xc2, 0x4f, 0xd5, 0xe9, 0x02, 0x34, 0x4f, 0xf0, 0x00, 0x0a, 0xbf, 0xee, - 0x00, 0x7a, 0xb4, 0xee, 0x00, 0x5a, 0x01, 0xf1, 0x60, 0x0c, 0x56, 0x46, - 0x44, 0xf2, 0xa7, 0x10, 0xb8, 0xf1, 0x00, 0x0f, 0x28, 0xd1, 0x1a, 0x0c, - 0x00, 0xfb, 0x02, 0xf2, 0x9b, 0xb2, 0x4f, 0xea, 0xd2, 0x3b, 0x00, 0xfb, - 0x03, 0xbb, 0x07, 0xea, 0x02, 0x43, 0x5b, 0x44, 0x23, 0xf0, 0x00, 0x42, - 0x02, 0xeb, 0xd3, 0x73, 0x06, 0xee, 0x10, 0x3a, 0xf8, 0xee, 0xc6, 0x5a, - 0xb0, 0xee, 0x47, 0x6a, 0xa5, 0xee, 0xa6, 0x6a, 0x01, 0x26, 0xde, 0xed, - 0x00, 0x7a, 0x67, 0xee, 0x86, 0x7a, 0xc1, 0xed, 0x00, 0x7a, 0x04, 0x31, - 0x8c, 0x45, 0xdb, 0xd1, 0x06, 0xb1, 0xab, 0x60, 0xba, 0xf1, 0x00, 0x0f, - 0x00, 0xd0, 0xec, 0x60, 0xbd, 0xe8, 0xf0, 0x8d, 0x04, 0xf1, 0x01, 0x0a, - 0xba, 0xf5, 0x80, 0x7f, 0x40, 0xf3, 0x0f, 0x81, 0xe2, 0x07, 0x4f, 0xf0, - 0x00, 0x0a, 0x40, 0xf1, 0x0f, 0x81, 0x1a, 0x0c, 0x00, 0xfb, 0x02, 0xf2, - 0x9e, 0xb2, 0xd3, 0x0b, 0x00, 0xfb, 0x06, 0x36, 0x07, 0xea, 0x02, 0x43, - 0x33, 0x44, 0x23, 0xf0, 0x00, 0x42, 0x02, 0xeb, 0xd3, 0x73, 0x07, 0xee, - 0x90, 0x3a, 0xb8, 0xee, 0xe7, 0x6a, 0xf0, 0xee, 0x47, 0x7a, 0xe6, 0xee, - 0x26, 0x7a, 0xa2, 0x07, 0x4f, 0xf0, 0x01, 0x06, 0x27, 0xee, 0x85, 0x6a, - 0x85, 0xed, 0x04, 0x6a, 0x40, 0xf1, 0xf5, 0x80, 0x1a, 0x0c, 0x00, 0xfb, - 0x02, 0xf2, 0x9e, 0xb2, 0xd3, 0x0b, 0x00, 0xfb, 0x06, 0x36, 0x07, 0xea, - 0x02, 0x43, 0x33, 0x44, 0x23, 0xf0, 0x00, 0x42, 0x02, 0xeb, 0xd3, 0x73, - 0x07, 0xee, 0x90, 0x3a, 0xf8, 0xee, 0xe7, 0x5a, 0xf0, 0xee, 0x47, 0x7a, - 0xe5, 0xee, 0xa6, 0x7a, 0x62, 0x07, 0x4f, 0xf0, 0x01, 0x06, 0x67, 0xee, - 0x85, 0x7a, 0xc5, 0xed, 0x05, 0x7a, 0x77, 0xee, 0x86, 0x7a, 0x40, 0xf1, - 0xdb, 0x80, 0x1a, 0x0c, 0x00, 0xfb, 0x02, 0xf2, 0x9e, 0xb2, 0xd3, 0x0b, - 0x00, 0xfb, 0x06, 0x36, 0x07, 0xea, 0x02, 0x43, 0x33, 0x44, 0x23, 0xf0, - 0x00, 0x42, 0x02, 0xeb, 0xd3, 0x73, 0x06, 0xee, 0x10, 0x3a, 0xf8, 0xee, - 0xc6, 0x5a, 0xb0, 0xee, 0x47, 0x6a, 0xa5, 0xee, 0xa6, 0x6a, 0x22, 0x07, - 0x4f, 0xf0, 0x01, 0x06, 0x26, 0xee, 0x05, 0x6a, 0x76, 0xee, 0x27, 0x7a, - 0x85, 0xed, 0x06, 0x6a, 0x40, 0xf1, 0xc1, 0x80, 0x1a, 0x0c, 0x00, 0xfb, - 0x02, 0xf2, 0x9e, 0xb2, 0xd3, 0x0b, 0x00, 0xfb, 0x06, 0x36, 0x07, 0xea, - 0x02, 0x43, 0x33, 0x44, 0x23, 0xf0, 0x00, 0x42, 0x02, 0xeb, 0xd3, 0x73, - 0x06, 0xee, 0x10, 0x3a, 0xf8, 0xee, 0xc6, 0x5a, 0xb0, 0xee, 0x47, 0x6a, - 0xa5, 0xee, 0xa6, 0x6a, 0xe2, 0x06, 0x4f, 0xf0, 0x01, 0x06, 0x26, 0xee, - 0x05, 0x6a, 0x76, 0xee, 0x27, 0x7a, 0x85, 0xed, 0x07, 0x6a, 0x40, 0xf1, - 0xa7, 0x80, 0x1a, 0x0c, 0x00, 0xfb, 0x02, 0xf2, 0x9e, 0xb2, 0xd3, 0x0b, - 0x00, 0xfb, 0x06, 0x36, 0x07, 0xea, 0x02, 0x43, 0x33, 0x44, 0x23, 0xf0, - 0x00, 0x42, 0x02, 0xeb, 0xd3, 0x73, 0x06, 0xee, 0x10, 0x3a, 0xf8, 0xee, - 0xc6, 0x5a, 0xb0, 0xee, 0x47, 0x6a, 0xa5, 0xee, 0xa6, 0x6a, 0xa2, 0x06, - 0x4f, 0xf0, 0x01, 0x06, 0x26, 0xee, 0x05, 0x6a, 0x85, 0xed, 0x08, 0x6a, - 0x36, 0xee, 0x27, 0x6a, 0x40, 0xf1, 0x8d, 0x80, 0x1a, 0x0c, 0x00, 0xfb, - 0x02, 0xf2, 0x9e, 0xb2, 0xd3, 0x0b, 0x00, 0xfb, 0x06, 0x36, 0x07, 0xea, - 0x02, 0x43, 0x33, 0x44, 0x23, 0xf0, 0x00, 0x42, 0x02, 0xeb, 0xd3, 0x73, - 0x07, 0xee, 0x90, 0x3a, 0xf8, 0xee, 0xe7, 0x5a, 0xf0, 0xee, 0x47, 0x7a, - 0xe5, 0xee, 0xa6, 0x7a, 0x62, 0x06, 0x4f, 0xf0, 0x01, 0x06, 0x67, 0xee, - 0x85, 0x7a, 0x37, 0xee, 0x86, 0x6a, 0xc5, 0xed, 0x09, 0x7a, 0x72, 0xd5, - 0x1a, 0x0c, 0x00, 0xfb, 0x02, 0xf2, 0x9e, 0xb2, 0xd3, 0x0b, 0x00, 0xfb, - 0x06, 0x36, 0x07, 0xea, 0x02, 0x43, 0x33, 0x44, 0x23, 0xf0, 0x00, 0x42, - 0x02, 0xeb, 0xd3, 0x73, 0x07, 0xee, 0x90, 0x3a, 0xf8, 0xee, 0xe7, 0x5a, - 0xf0, 0xee, 0x47, 0x7a, 0xe5, 0xee, 0xa6, 0x7a, 0x22, 0x06, 0x4f, 0xf0, - 0x01, 0x06, 0x67, 0xee, 0x85, 0x7a, 0x37, 0xee, 0x86, 0x6a, 0xc5, 0xed, - 0x0a, 0x7a, 0x58, 0xd5, 0x1a, 0x0c, 0x00, 0xfb, 0x02, 0xf2, 0x9c, 0xb2, - 0xd3, 0x0b, 0x00, 0xfb, 0x04, 0x34, 0x07, 0xea, 0x02, 0x43, 0x23, 0x44, - 0x23, 0xf0, 0x00, 0x42, 0x02, 0xeb, 0xd3, 0x73, 0x07, 0xee, 0x90, 0x3a, - 0xf8, 0xee, 0xe7, 0x5a, 0xf0, 0xee, 0x47, 0x7a, 0xe5, 0xee, 0xa6, 0x7a, - 0x01, 0x26, 0x67, 0xee, 0x85, 0x7a, 0xc5, 0xed, 0x0b, 0x7a, 0xde, 0xed, - 0x00, 0x5a, 0x77, 0xee, 0x86, 0x7a, 0x54, 0x46, 0x65, 0xee, 0xa7, 0x7a, - 0x4f, 0xf0, 0x01, 0x0a, 0xc1, 0xed, 0x00, 0x7a, 0xdf, 0xe6, 0x84, 0xea, - 0x0a, 0x04, 0xe2, 0x07, 0x3f, 0xf5, 0xf1, 0xae, 0xa2, 0x07, 0x95, 0xed, - 0x04, 0x6a, 0x3f, 0xf5, 0x0b, 0xaf, 0xd5, 0xed, 0x05, 0x7a, 0x62, 0x07, - 0x77, 0xee, 0x86, 0x7a, 0x3f, 0xf5, 0x25, 0xaf, 0x95, 0xed, 0x06, 0x6a, - 0x22, 0x07, 0x76, 0xee, 0x27, 0x7a, 0x3f, 0xf5, 0x3f, 0xaf, 0x95, 0xed, - 0x07, 0x6a, 0xe2, 0x06, 0x76, 0xee, 0x27, 0x7a, 0x3f, 0xf5, 0x59, 0xaf, - 0x95, 0xed, 0x08, 0x6a, 0xa2, 0x06, 0x36, 0xee, 0x27, 0x6a, 0x3f, 0xf5, - 0x73, 0xaf, 0xd5, 0xed, 0x09, 0x7a, 0x62, 0x06, 0x37, 0xee, 0x86, 0x6a, - 0x8c, 0xd4, 0xd5, 0xed, 0x0a, 0x7a, 0x22, 0x06, 0x37, 0xee, 0x86, 0x6a, - 0xa6, 0xd4, 0xd5, 0xed, 0x0b, 0x7a, 0xbe, 0xe7, 0x00, 0x00, 0x80, 0x30, - 0x00, 0x00, 0xff, 0x7f, 0x28, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x70, 0xb5, 0x10, 0x4a, 0x10, 0x4b, 0x59, 0xf8, - 0x02, 0x60, 0x59, 0xf8, 0x03, 0x50, 0x76, 0x1b, 0xb6, 0x10, 0x06, 0xd0, - 0x00, 0x24, 0x55, 0xf8, 0x04, 0x3b, 0x01, 0x34, 0x98, 0x47, 0xa6, 0x42, - 0xf9, 0xd1, 0x0a, 0x4a, 0x0a, 0x4b, 0x59, 0xf8, 0x02, 0x60, 0x59, 0xf8, - 0x03, 0x50, 0x76, 0x1b, 0xb6, 0x10, 0x06, 0xd0, 0x00, 0x24, 0x55, 0xf8, - 0x04, 0x3b, 0x01, 0x34, 0x98, 0x47, 0xa6, 0x42, 0xf9, 0xd1, 0x70, 0xbd, - 0x2c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x2d, 0xe9, 0x00, 0x42, 0x02, 0xb4, 0xdf, 0xf8, - 0x10, 0x10, 0xd1, 0xf8, 0x00, 0x90, 0x02, 0xbc, 0xff, 0xf7, 0xd4, 0xfd, - 0xbd, 0xe8, 0x00, 0x82, 0x00, 0x00, 0x00, 0x20, 0x2d, 0xe9, 0x00, 0x42, - 0x02, 0xb4, 0xdf, 0xf8, 0x10, 0x10, 0xd1, 0xf8, 0x00, 0x90, 0x02, 0xbc, - 0xff, 0xf7, 0xec, 0xfd, 0xbd, 0xe8, 0x00, 0x82, 0x00, 0x00, 0x00, 0x20, - 0x2d, 0xe9, 0x00, 0x42, 0x02, 0xb4, 0xdf, 0xf8, 0x10, 0x10, 0xd1, 0xf8, - 0x00, 0x90, 0x02, 0xbc, 0xff, 0xf7, 0x12, 0xfe, 0xbd, 0xe8, 0x00, 0x82, - 0x00, 0x00, 0x00, 0x20, 0x2d, 0xe9, 0x00, 0x42, 0x02, 0xb4, 0xdf, 0xf8, - 0x10, 0x10, 0xd1, 0xf8, 0x00, 0x90, 0x02, 0xbc, 0xff, 0xf7, 0xa2, 0xff, - 0xbd, 0xe8, 0x00, 0x82, 0x00, 0x00, 0x00, 0x20, 0x08, 0xb5, 0x07, 0x4b, - 0x59, 0xf8, 0x03, 0x00, 0x00, 0x21, 0x00, 0xf1, 0x08, 0x03, 0xc0, 0xe9, - 0x02, 0x31, 0x04, 0x4b, 0x20, 0x22, 0x59, 0xf8, 0x03, 0x30, 0x10, 0x30, - 0x98, 0x47, 0x08, 0xbd, 0x08, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x3f, 0x40, 0x05, 0x00, 0x00, 0x48, 0x05, 0x00, 0x00, - 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x00, 0x00, 0x00, 0x40, 0x4d, 0x6f, 0x64, - 0x65, 0x00, 0x00, 0x00, 0x3e, 0x57, 0x68, 0x69, 0x74, 0x65, 0x00, 0x00, - 0x3e, 0x50, 0x69, 0x6e, 0x6b, 0x00, 0x00, 0x00, 0xfd, 0x04, 0x00, 0x00 -}; -unsigned int __NOISE_WhitePink_bin_len = 1932; diff --git a/app/SPEECH/LPC.bin b/app/SPEECH/LPC.bin new file mode 100644 index 0000000000000000000000000000000000000000..34f519dd32e3ee8fab18fdc43142d23349bd9d57 GIT binary patch literal 21444 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 literal 0 HcmV?d00001 diff --git a/app/SPEECH/LPC.cpp b/app/SPEECH/LPC.cpp new file mode 100644 index 0000000..97ee2f9 --- /dev/null +++ b/app/SPEECH/LPC.cpp @@ -0,0 +1,268 @@ + +#include "../squares-and-circles-api.h" +#include "stmlib/stmlib.h" +#include "stmlib/dsp/units.h" +#include + +#define private public +#include "plaits/dsp/speech/lpc_speech_synth_controller.h" +#include "plaits/dsp/speech/lpc_speech_synth_words.h" + +#define FLASHMEM __attribute__((section(".text"))) + +#include "plaits/dsp/speech/lpc_speech_synth_controller.cc" +#include "plaits/dsp/speech/lpc_speech_synth_words.cc" +#include "plaits/dsp/speech/lpc_speech_synth_phonemes.cc" +#include "plaits/dsp/speech/lpc_speech_synth.cc" + +#include "stmlib/dsp/units.cc" +#include "stmlib/utils/random.cc" + +// from #include "plaits/resources.cc" +namespace plaits +{ +const int8_t lut_lpc_excitation_pulse[] FLASHMEM = { + 0, 0, 0, 0, + 1, 1, 1, 2, + 3, 3, 4, 5, + 6, 7, 8, 9, + 10, 12, 13, 15, + 17, 19, 21, 23, + 25, 28, 30, 33, + 36, 38, 41, 44, + 48, 51, 54, 57, + 61, 64, 68, 71, + 75, 78, 82, 85, + 89, 92, 95, 99, + 102, 105, 108, 110, + 113, 115, 118, 120, + 121, 123, 124, 125, + 126, 127, 127, 127, + 127, 126, 125, 124, + 122, 121, 118, 116, + 113, 110, 107, 104, + 100, 96, 92, 87, + 83, 78, 73, 68, + 63, 58, 53, 47, + 42, 37, 31, 26, + 21, 16, 11, 6, + 1, -3, -8, -12, + -16, -20, -23, -26, + -29, -32, -35, -37, + -39, -40, -42, -43, + -43, -44, -44, -44, + -44, -44, -43, -42, + -41, -40, -39, -38, + -36, -35, -33, -32, + -30, -29, -27, -26, + -24, -23, -22, -20, + -19, -18, -18, -17, + -16, -16, -16, -16, + -16, -16, -17, -17, + -18, -19, -20, -21, + -23, -24, -26, -27, + -29, -30, -32, -34, + -35, -37, -39, -40, + -42, -43, -44, -46, + -47, -48, -48, -49, + -49, -50, -50, -50, + -49, -49, -48, -47, + -46, -45, -44, -42, + -41, -39, -37, -35, + -33, -31, -29, -27, + -25, -23, -20, -18, + -16, -14, -13, -11, + -9, -8, -7, -6, + -5, -4, -3, -3, + -3, -3, -3, -4, + -5, -6, -7, -9, + -10, -12, -14, -16, + -18, -21, -23, -26, + -29, -32, -34, -37, + -40, -43, -46, -49, + -51, -54, -56, -59, + -61, -63, -65, -67, + -68, -70, -71, -72, + -72, -73, -73, -73, + -73, -72, -72, -71, + -70, -69, -67, -66, + -64, -63, -61, -59, + -57, -54, -52, -50, + -48, -45, -43, -41, + -39, -37, -35, -33, + -31, -29, -27, -26, + -25, -23, -22, -21, + -20, -20, -19, -19, + -19, -18, -18, -18, + -19, -19, -19, -20, + -20, -21, -21, -22, + -22, -23, -23, -24, + -24, -25, -25, -25, + -26, -26, -26, -25, + -25, -25, -24, -24, + -23, -22, -21, -20, + -19, -18, -16, -15, + -13, -12, -10, -8, + -6, -4, -3, -1, + 1, 3, 5, 7, + 8, 10, 12, 13, + 15, 16, 17, 18, + 19, 20, 21, 21, + 22, 22, 22, 22, + 22, 22, 22, 22, + 21, 21, 20, 19, + 19, 18, 17, 16, + 15, 14, 14, 13, + 12, 11, 10, 10, + 9, 9, 8, 8, + 8, 8, 8, 8, + 8, 8, 8, 9, + 9, 10, 11, 12, + 13, 14, 15, 16, + 17, 18, 19, 21, + 22, 23, 24, 26, + 27, 28, 29, 30, + 31, 32, 33, 33, + 34, 35, 35, 35, + 36, 36, 36, 36, + 35, 35, 35, 34, + 34, 33, 33, 32, + 31, 30, 30, 29, + 28, 27, 26, 25, + 25, 24, 23, 22, + 22, 21, 20, 20, + 19, 19, 19, 19, + 19, 19, 19, 19, + 19, 19, 20, 20, + 21, 21, 22, 22, + 23, 23, 24, 25, + 25, 26, 27, 27, + 28, 29, 29, 29, + 30, 30, 30, 31, + 31, 31, 31, 30, + 30, 30, 29, 29, + 28, 28, 27, 26, + 26, 25, 24, 23, + 22, 21, 20, 19, + 18, 17, 16, 15, + 15, 14, 13, 12, + 12, 11, 10, 10, + 10, 9, 9, 9, + 9, 9, 9, 9, + 9, 10, 10, 10, + 11, 11, 12, 12, + 12, 13, 13, 14, + 14, 14, 15, 15, + 15, 15, 15, 15, + 15, 15, 15, 15, + 14, 14, 14, 13, + 12, 12, 11, 10, + 9, 8, 8, 7, + 6, 5, 4, 3, + 2, 1, 0, -1, + -2, -3, -4, -4, + -5, -6, -6, -7, + -7, -8, -8, -8, + -9, -9, -9, -9, + -9, -9, -9, -9, + -8, -8, -8, -7, + -7, -7, -6, -6, + -5, -5, -5, -4, + -4, -4, -3, -3, + -3, -2, -2, -2, + -2, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -2, -2, + -2, -2, -2, -2, + -2, -2, -2, -2, + -2, -2, -2, -2, + -2, -2, -2, -2, + -2, -2, -2, -2, + -2, -1, -1, -1, + -1, -1, -1, 0, + 0, 0, 0, 0, +}; +} + +const float a0 = (440.0f / 8.0f) / 48000.0f; + +inline float NoteToFrequency(float midi_note) +{ + midi_note -= 9.0f; + CONSTRAIN(midi_note, -128.0f, 127.0f); + return a0 * 0.25f * stmlib::SemitonesToRatio(midi_note); +} + +static float _pitch = 0.f; +static int32_t _word = 0; +static float _speed = 0.3f; +static float _formant_shift = 0.5f; +static float _prosody = 0.5f; +static float _out_aux_mix = 0.0f; + +struct +{ + uint8_t bank; + float addr; +} _words[92]; + +static plaits::LPCSpeechSynthController lpc_speech_synth_controller_; +static plaits::LPCSpeechSynthWordBank lpc_speech_synth_word_bank_; + +static uint8_t buffer[16384] = {}; +static stmlib::BufferAllocator allocator; + +void engine::setup() +{ + allocator.Init(buffer, 16384); + + lpc_speech_synth_word_bank_.Init(plaits::word_banks_, + LPC_SPEECH_SYNTH_NUM_WORD_BANKS, + &allocator); + int j = 0; + for (uint8_t i = 0; i < LPC_SPEECH_SYNTH_NUM_WORD_BANKS; i++) + { + lpc_speech_synth_word_bank_.Load(i); + + for (int l = 0; l < lpc_speech_synth_word_bank_.num_words_; l++) + _words[j++] = {i, 1.f / lpc_speech_synth_word_bank_.num_words_ * l}; + } + + lpc_speech_synth_controller_.Init(&lpc_speech_synth_word_bank_); + + engine::addParam(V_OCT, &_pitch); + engine::addParam("Word", &_word, 0, LEN_OF(_words) - 1); + engine::addParam("Speed", &_speed); + engine::addParam("Form.Shift", &_formant_shift); + engine::addParam("Prosody", &_prosody); + engine::addParam("AuxMix", &_out_aux_mix); +} + +void engine::process() +{ + auto note = (float)DEFAULT_NOTE; + + note += engine::cv() * 12; + + const float f0 = NoteToFrequency(note); + + auto _out = engine::outputBuffer<0>(); + auto _aux = engine::outputBuffer<1>(); + + lpc_speech_synth_controller_.Render(false, + engine::trig(), + _words[_word].bank, // Bank + f0, + _prosody, + _speed, // Speed + _words[_word].addr, // Word + _formant_shift, + 1.0f, + _aux, + _out, + FRAME_BUFFER_SIZE); + + for (int i = 0; i < FRAME_BUFFER_SIZE; i++) + _out[i] = stmlib::Crossfade(_out[i], _aux[i], _out_aux_mix); +} \ No newline at end of file diff --git a/app/SPEECH/SAM.bin b/app/SPEECH/SAM.bin new file mode 100644 index 0000000000000000000000000000000000000000..3e24549859a5ff17728d9e8f44b5c31f2d12fd51 GIT binary patch literal 27792 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 0) + open303.setAccentDecay(rosic::linToExp(_dec, 0.0, 1.0, 200.0, 2000.0)); + + _note = (float)DEFAULT_NOTE + 24 + engine::cv() * 12; + CONSTRAIN(_note, 0, 128); + + _gate |= engine::gate(); + + if (engine::trig() > 0) + open303.triggerNote(_note, _acc > 0); + else if (!engine::gate()) + { + open303.releaseNote(_note); + _gate = false; + } + else + open303.oscFreq = rosic::pitchToFreq(_note, open303.tuning); + + auto buffer = engine::outputBuffer<0>(); + for (int i = 0; i < FRAME_BUFFER_SIZE; i++) + buffer[i] = open303.getSample(); +} + +void engine::screensaver() +{ + static uint32_t _r = 0; + static const uint8_t _screenSaver[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, //> + 0x00, 0x80, 0x0f, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x00, + 0x80, 0x01, 0x06, 0xc0, 0x00, 0x01, 0xc0, 0x00, 0x0f, 0xe0, 0x01, 0x03, + 0x60, 0x00, 0x0f, 0xe0, 0x01, 0x06, 0x30, 0x80, 0x1f, 0xf0, 0x03, 0x0c, + 0x10, 0x80, 0x1f, 0xf0, 0x03, 0x08, 0x18, 0x80, 0x1f, 0xf0, 0x03, 0x18, + 0x08, 0x80, 0x1f, 0xf0, 0x03, 0x10, 0x08, 0x80, 0x1f, 0xf0, 0x03, 0x30, + 0x04, 0x80, 0x1f, 0xf0, 0x03, 0x20, 0x04, 0x80, 0x1f, 0xf0, 0x03, 0x20, + 0x04, 0x80, 0x1f, 0xf0, 0x03, 0x60, 0x06, 0x00, 0x0f, 0xe0, 0x01, 0x40, + 0x02, 0x00, 0x0f, 0xe0, 0x01, 0x40, 0x02, 0x00, 0x06, 0xc0, 0x00, 0x40, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, + 0xe2, 0x07, 0x00, 0x00, 0xe0, 0x47, 0xc2, 0x03, 0x00, 0x00, 0xc0, 0x43, + 0x82, 0x01, 0x00, 0x00, 0x80, 0x41, 0x82, 0x01, 0x00, 0x00, 0x80, 0x41, + 0x86, 0x01, 0x00, 0x00, 0xc0, 0x60, 0x04, 0x03, 0x00, 0x00, 0xc0, 0x60, + 0x04, 0x07, 0x00, 0x00, 0xc0, 0x20, 0x0c, 0x06, 0x00, 0x00, 0x60, 0x20, + 0x08, 0x0e, 0x00, 0x00, 0x70, 0x30, 0x08, 0x1c, 0x00, 0x00, 0x30, 0x10, + 0x18, 0x38, 0x00, 0x00, 0x1c, 0x18, 0x10, 0x70, 0x00, 0x00, 0x0e, 0x08, + 0x20, 0xe0, 0x00, 0x00, 0x0f, 0x0c, 0x60, 0xc0, 0x03, 0xc0, 0x03, 0x06, + 0xc0, 0x00, 0x0f, 0xf0, 0x00, 0x02, 0x80, 0x01, 0xfc, 0x3f, 0x00, 0x01, + 0x00, 0x03, 0xe0, 0x07, 0xc0, 0x00, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00, 0x1c, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x0f, 0xf0, 0x01, 0x00, + 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, //> + 0x00, 0xe0, 0xff, 0xff, 0x07, 0x00, 0x00, 0xf0, 0x0f, 0xe0, 0x1f, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x7c, 0x00, + 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x80, 0x07, 0x06, 0xc0, 0xe0, 0x01, + 0xc0, 0x03, 0x0f, 0xe0, 0x81, 0x03, 0xe0, 0x81, 0x1f, 0xf0, 0x83, 0x07, + 0xf0, 0x80, 0x1f, 0xf0, 0x03, 0x0f, 0x78, 0xc0, 0x3f, 0xf8, 0x07, 0x1e, + 0x38, 0xc0, 0x3f, 0xf8, 0x07, 0x1c, 0x3c, 0xc0, 0x3f, 0xf8, 0x07, 0x3c, + 0x1c, 0xc0, 0x3f, 0xf8, 0x07, 0x38, 0x1c, 0xc0, 0x3f, 0xf8, 0x07, 0x78, + 0x0e, 0xc0, 0x3f, 0xf8, 0x07, 0x70, 0x0e, 0xc0, 0x3f, 0xf8, 0x07, 0x70, + 0x0e, 0xc0, 0x1f, 0xf0, 0x07, 0xf0, 0x0f, 0x80, 0x1f, 0xf0, 0x03, 0xe0, + 0x07, 0x80, 0x0f, 0xe0, 0x03, 0xe0, 0x07, 0x00, 0x0f, 0xe0, 0x01, 0xe0, + 0x07, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xe7, 0x07, 0x00, 0x00, 0xe0, 0xe7, + 0xf7, 0x07, 0x00, 0x00, 0xe0, 0xef, 0xe7, 0x07, 0x00, 0x00, 0xe0, 0xe7, + 0xc7, 0x03, 0x00, 0x00, 0xc0, 0xe3, 0xc7, 0x03, 0x00, 0x00, 0xc0, 0xe3, + 0xcf, 0x03, 0x00, 0x00, 0xe0, 0xf1, 0x8e, 0x07, 0x00, 0x00, 0xe0, 0xf1, + 0x8e, 0x0f, 0x00, 0x00, 0xe0, 0x71, 0x1e, 0x0f, 0x00, 0x00, 0xf0, 0x70, + 0x1c, 0x1f, 0x00, 0x00, 0xf8, 0x78, 0x1c, 0x3e, 0x00, 0x00, 0x7c, 0x38, + 0x3c, 0x7c, 0x00, 0x00, 0x3e, 0x3c, 0x38, 0xf8, 0x00, 0x00, 0x1f, 0x1c, + 0x70, 0xf0, 0x03, 0xc0, 0x1f, 0x1e, 0xf0, 0xe0, 0x0f, 0xf0, 0x0f, 0x0f, + 0xe0, 0xc1, 0xff, 0xff, 0x03, 0x07, 0xc0, 0x03, 0xff, 0xff, 0xc0, 0x03, + 0x80, 0x07, 0xfc, 0x3f, 0xe0, 0x01, 0x00, 0x0f, 0xe0, 0x07, 0xf0, 0x00, + 0x00, 0x3e, 0x00, 0x00, 0x7c, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x3f, 0x00, + 0x00, 0xf0, 0x0f, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x07, 0x00, + 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00}; + + gfx::clearRect(0, 0, 128, 64); + + for (int i = 23; i > 0; i--) + { + if ((_r & (1 << i))) + gfx::drawCircle(64, 32, 26 + powf(i, 1.3f)); + } + + if (_gate) + { + _r |= 1; + gfx::drawXbm(40, 8, 48, 48, &_screenSaver[sizeof(_screenSaver) / 2]); + } + else + gfx::drawXbm(40, 8, 48, 48, &_screenSaver[0]); + + _r <<= 1; +} \ No newline at end of file diff --git a/app/SYNTH/Resonator.bin b/app/SYNTH/Resonator.bin new file mode 100644 index 0000000000000000000000000000000000000000..569891828fea0c91c79f9b54b5204833d1e4ad71 GIT binary patch literal 57872 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 + +static int32_t _model = rings::ResonatorModel::RESONATOR_MODEL_MODAL; +const char *_models[] = {"Modal", "Sympath.", "String", "FM", "StrQuant."}; +static rings::Strummer strummer = {}; + +static rings::Part part; +static rings::Patch patch = {}; +static rings::PerformanceState performance_state = {}; + +static float _pitch = 0; + +void engine::setup() +{ + patch.structure = 0.5f; + patch.brightness = 0.5f; + patch.damping = 0.5f; + patch.position = 0.5f; + strummer.Init(0.01f, SAMPLE_RATE / FRAME_BUFFER_SIZE); + + part.Init(); + part.set_model(rings::ResonatorModel::RESONATOR_MODEL_MODAL); + part.set_polyphony(rings::kMaxPolyphony); + + engine::addParam(V_OCT, &_pitch); // pitch is summed with CV and quantized + engine::addParam("@Model", &_model, rings::ResonatorModel::RESONATOR_MODEL_MODAL, + rings::ResonatorModel::RESONATOR_MODEL_SYMPATHETIC_STRING_QUANTIZED, _models); + + engine::addParam("Struc.", &patch.structure); + engine::addParam("Brighn.", &patch.brightness); + engine::addParam("Damping", &patch.damping); + engine::addParam("Pos", &patch.position); +} + +void engine::process() +{ + auto inputL = engine::inputBuffer<0>(); + auto bufferOut = engine::outputBuffer<0>(); + auto bufferAux = engine::outputBuffer<1>(); + + part.set_model((rings::ResonatorModel)_model); + + performance_state.strum = engine::trig() > 0; + performance_state.internal_strum = false; + performance_state.internal_note = true; + performance_state.internal_exciter = true; + performance_state.tonic = 0.2f; + performance_state.chord = 0; + performance_state.note = DEFAULT_NOTE; + + performance_state.note += engine::cv() * 12; + + strummer.Process(inputL, FRAME_BUFFER_SIZE, &performance_state); + part.Process(performance_state, patch, inputL, bufferOut, bufferAux, FRAME_BUFFER_SIZE); +} \ No newline at end of file diff --git a/app/build.sh b/app/build.sh index 7a3cb30..e86bc9f 100644 --- a/app/build.sh +++ b/app/build.sh @@ -1,3 +1,4 @@ +#!/usr/bin/bash set -e #-eo pipefail cd $(dirname $0) @@ -35,7 +36,7 @@ echo "BUILD_FLAGS:$BUILD_FLAGS" $mkmodule $X.cpp \ --no-opt \ --build_flags="-fsingle-precision-constant -DNDEBUG -O3 $BUILD_FLAGS -I. -I../lib/ " \ - --public-symbols="setup,process,draw,screensaver,__ui_event_handler" \ + --public-symbols="setup,process,draw,screensaver,__ui_event_handler,__midi_event_handler" \ --name="$NAME" > $X.log touch -d "$(date -R -r $X.cpp)" $X.bin diff --git a/app/index.json b/app/index.json new file mode 100644 index 0000000..c4174ce --- /dev/null +++ b/app/index.json @@ -0,0 +1,38 @@ +{ + "apps": [ + "NOISE/WhitePink.bin", + "NOISE/NES.bin", + "NOISE/808_squares.bin", + "MIDI/Monitor.bin", + "MIDI/Clock.bin", + + "DRUMS/TR909-HiHat.bin", + "DRUMS/TR909-Ride.bin", + "DRUMS/TR707.bin", + "DRUMS/TR707-HiHat.bin", + + "DRUMS/Vint.Samples.bin", + + "FX/Reverb.bin", + "FX/ReverbSC.bin", + "FX/Rev-Dattorro.bin", + + "DRUMS/Djembe.bin", + "SYNTH/Resonator.bin", + + "SPEECH/LPC.bin", + "SPEECH/SAM.bin", + + "FX/Delay.bin", + "FX/Gated-Reverb.bin", + "FX/Reverb-HP-LP.bin", + + "MIDI/VAx6.bin", + + "SYNTH/Open303.bin", + "FX/JU60_chorus.bin", + + "GND/Scope.bin", + "GND/FFT.bin" + ] +} \ No newline at end of file diff --git a/app/squares-and-circles-api.h b/app/squares-and-circles-api.h index e25ac26..1738389 100644 --- a/app/squares-and-circles-api.h +++ b/app/squares-and-circles-api.h @@ -1,7 +1,7 @@ -// Copyright (C)2023 - Eduard Heidt +// Copyright (C)2023 - E.Heidt // -// Author: Eduard Heidt (eh2k@gmx.de) +// 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 @@ -69,7 +69,7 @@ #endif -#define V_OCT "_V_OCT" +#define V_OCT "V_OCT" #define IO_STEREOLIZE ".IO_STEREO" #ifdef __cplusplus @@ -78,6 +78,7 @@ // # pragma GCC poison _ZSt17__throw_bad_allocv // # pragma GCC poison new delete // # pragma GCC poison malloc new +// # pragma GCC poison virtual #endif #ifndef EMSCRIPTEN @@ -132,6 +133,9 @@ extern "C" uint32_t millis(); #ifndef FRAME_BUFFER_SIZE #define FRAME_BUFFER_SIZE 24 #endif +#ifndef PITCH_PER_OCTAVE +#define PITCH_PER_OCTAVE (12 << 7) +#endif #ifndef engine @@ -156,7 +160,9 @@ extern "C" extern uint32_t *__engine_props; extern float *__adc_voltage_f_p; - extern float **__dac_voltage_fp_p; + extern uint32_t __adc_count; + extern float *__dac_voltage_fp_p; + extern uint32_t __dac_count; extern uint32_t *__digital_inputs_u32_p; extern uint32_t *__bpm; @@ -175,11 +181,25 @@ extern "C" if (__ui_event_handler_ptr) __ui_event->handled = __ui_event_handler_ptr(__ui_event->type, __ui_event->control, __ui_event->value, __ui_event->mask); } + + extern struct + { + uint8_t type; + uint8_t key; + int16_t value; + } *__midi_event; + + void (*__midi_event_handler_ptr)() = nullptr; + void __midi_event_handler() + { + if (__midi_event_handler_ptr) + __midi_event_handler_ptr(); + } } namespace engine { - inline uint32_t t() { return *__accent; } + inline uint32_t t() { return *__t; } inline uint8_t clock() { return *__clock; } inline uint8_t trig() { return *__trig; } inline uint8_t gate() { return *__gate; } @@ -227,6 +247,12 @@ namespace engine __ui_event_handler(); __ui_event_handler_ptr = handler; } + + void __attribute__((weak)) onMidiNote(uint8_t key, uint8_t velocity); // NoteOff: velocity == 0 + void __attribute__((weak)) onMidiPitchbend(int16_t pitch); + 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 @@ -240,10 +266,35 @@ namespace engine addParam_f32(name, value, min, max); } - inline void setUIMode(uint32_t mode) // 1: compact_mode, 2: sample_view + constexpr uint32_t ENGINE_MODE_COMPACT = 1 << 5; + constexpr uint32_t ENGINE_MODE_CV_OUT = 1 << 6; + constexpr uint32_t ENGINE_MODE_MIDI_IN = 1 << 7; + + inline void + setMode(uint32_t mode) // 1: compact_mode, 2: sample_view { - if (mode == 1) - *__engine_props |= 32; + *__engine_props |= mode; + if (mode & ENGINE_MODE_MIDI_IN) + { + __midi_event_handler_ptr = []() + { + switch (__midi_event->type) + { + case 0: + onMidiNote(__midi_event->key, __midi_event->value); + return; + case 1: + onMidiPitchbend(__midi_event->value); + return; + case 2: + onMidiCC(__midi_event->key, __midi_event->value); + return; + case 3: + onMidiSysex(__midi_event->key); + return; + } + }; + } } constexpr uint32_t PARAM_SELECTED = 0x1; @@ -281,23 +332,33 @@ namespace machine { extern "C" const uint8_t *fs_read(const char *blobName); - inline uint32_t midi_bpm() + inline uint32_t clk_bpm() { return *__bpm; } + inline void clk_bpm(uint32_t bpm) + { + *__bpm = bpm; + } inline uint32_t raw_digital_inputs() { return *__digital_inputs_u32_p; } - inline float raw_adc_voltage(uint32_t index) + inline float *raw_adc_voltage(uint32_t index) { - return __adc_voltage_f_p[index]; + if (index < __adc_count) + return &__adc_voltage_f_p[index]; + else + return nullptr; } inline float *raw_dac_buffer(uint32_t index) { - return __dac_voltage_fp_p[index]; + if (index < __dac_count) + return &__dac_voltage_fp_p[index]; + else + return nullptr; } }; #else @@ -317,6 +378,10 @@ namespace gfx 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); diff --git a/boards/dsm0.json b/boards/dsm0.json deleted file mode 100644 index f11c690..0000000 --- a/boards/dsm0.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "build": { - "core": "stm32", - "cpu": "cortex-m7", - "extra_flags": "-mfpu=fpv5-d16 -mthumb -mfloat-abi=hard -DSTM32H7xx -DSTM32H750xx", - "f_cpu": "400000000L", - "mcu": "stm32h750ibk6", - "product_line": "STM32H750xx", - "variant": "STM32H7xx/H742I(G-I)(K-T)_H743I(G-I)(K-T)_H750IB(K-T)_H753II(K-T)" - }, - "debug": { - "jlink_device": "STM32H750IB", - "openocd_target": "stm32h7x", - "svd_path": "STM32H750x.svd" - }, - "frameworks": [], - "name": "squares-and-circles", - "upload": { - "maximum_ram_size": 131072, - "maximum_size": 524288, - "protocol": "custom", - "protocols": [] - }, - "url": "https://github.com/eh2k/squares-and-circles", - "vendor": "eh2k" -} diff --git a/boards/imxrt1062.ld b/boards/imxrt1062.ld deleted file mode 100644 index 96b412d..0000000 --- a/boards/imxrt1062.ld +++ /dev/null @@ -1,114 +0,0 @@ -MEMORY -{ - ITCM (rwx): ORIGIN = 0x00000000, LENGTH = 512K - DTCM (rwx): ORIGIN = 0x20000000, LENGTH = 512K - RAM (rwx): ORIGIN = 0x20200000, LENGTH = 512K - FLASH (rwx): ORIGIN = 0x60000000, LENGTH = 1984K -} - -ENTRY(ImageVectorTable) - -SECTIONS -{ - .text.headers : { - KEEP(*(.flashconfig)) - FILL(0xFF) - . = ORIGIN(FLASH) + 0x1000; - KEEP(*(.ivt)) - KEEP(*(.bootdata)) - . = ALIGN(1024); - } > FLASH - - .text.code : { - KEEP(*(.startup)) - *(.flashmem*) - . = ALIGN(4); - KEEP(*(.init)) - __preinit_array_start = .; - KEEP (*(.preinit_array)) - __preinit_array_end = .; - __init_array_start = .; - KEEP (*(.init_array)) - __init_array_end = .; - . = ALIGN(4); - } > FLASH - - .text.progmem : { - *(.progmem*) - . = ALIGN(4); - } > FLASH - - .text.itcm : { - . = . + 32; /* MPU to trap NULL pointer deref */ - *(.fastrun) - *(.text*) - . = ALIGN(16); - } > ITCM AT> FLASH - - .ARM.exidx : { - __exidx_start = .; - *(.ARM.exidx* .ARM.extab.text* .gnu.linkonce.armexidx.*) - __exidx_end = .; - } > ITCM AT> FLASH - - /* .mySegment 0x20000000 : { - KEEP(*(..udynlink_ram_base)) - } > DTCM */ - - .data : { - KEEP(*(.udynlink_ram_base)) - *(.endpoint_queue) - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.data*))) - KEEP(*(.vectorsram)) - } > DTCM AT> FLASH - - .bss ALIGN(4) : { - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(COMMON))) - . = ALIGN(32); - . = . + 32; /* MPU to trap stack overflow */ - } > DTCM - - .bss.dma (NOLOAD) : { - *(.hab_log) - *(.dmabuffers) - . = ALIGN(32); - } > RAM - - .text.csf : { - FILL(0xFF) - . = ALIGN(1024); - KEEP(*(.csf)) - __text_csf_end = .; - } > FLASH - - _stext = ADDR(.text.itcm); - _etext = ADDR(.text.itcm) + SIZEOF(.text.itcm) + SIZEOF(.ARM.exidx); - _stextload = LOADADDR(.text.itcm); - - _sdata = ADDR(.data); - _edata = ADDR(.data) + SIZEOF(.data); - _sdataload = LOADADDR(.data); - - _sbss = ADDR(.bss); - _ebss = ADDR(.bss) + SIZEOF(.bss); - - _heap_start = ADDR(.bss.dma) + SIZEOF(.bss.dma); - _heap_end = ORIGIN(RAM) + LENGTH(RAM); - - _itcm_block_count = (SIZEOF(.text.itcm) + SIZEOF(.ARM.exidx) + 0x7FFF) >> 15; - _flexram_bank_config = 0xAAAAAAAA | ((1 << (_itcm_block_count * 2)) - 1); - _estack = ORIGIN(DTCM) + ((16 - _itcm_block_count) << 15); - - _flashimagelen = __text_csf_end - ORIGIN(FLASH); - _teensy_model_identifier = 0x24; - - .debug_info 0 : { *(.debug_info) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - -} diff --git a/doc/.conv.sh b/doc/.conv.sh new file mode 100644 index 0000000..c06a7bb --- /dev/null +++ b/doc/.conv.sh @@ -0,0 +1,6 @@ + +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 + +for f in $1; do + convert $f -sample 256x128 ${f%.*}.png +done diff --git a/doc/adc_calib.bmp b/doc/adc_calib.bmp deleted file mode 100644 index eb962c5448aa2e00306f7088c1d21a58a56d6dc4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1056 zcmbW0PfG$p6u?KQLlKo-x|l5<`U(+QW)ajO=-9Di$2!zPq9X~V5N05Bi9SM?4$(;2 z$-Y5RvS@4su{0IZA6lH(n{m|=By>f`-@JJ{zj<$WdO_2Oy5!J<-zb?PF8lz1n*aMl zaavxaPYr^qp*jD}CZxLFNvq|z&CDML5MyR?0^se+OIiLLz_>MZoVFRKTUPOv8U;h& zME>TKSF6eds4D$=d26E{$Lb@RRvt=I)TJ zpTPQ^D!+{~2%ZsGKWG0<5W>c|Rri}z?D*eMala$$C(loRLNV5I zzx7}B%VK{+ET2(+*k3Q!FI@K%y~q(}+4cVBco^BKUqr@3*ZC9WhyC@I7}vQ!r2MeI zSsR}p=RtIamVN)rZ+ssb*}YnP3LU2Rb8}JR%6T;Ryt^+raF9wY5#k&1X~VOwuAt{3 xl~_U6e2Z?$1L;%(*MBP}k28nnL~c&SFdh=f>}mT*350*#44a|FFaiwLn02poqn+Eu>p?*>n^E3+D$RM|4N(JH~#5T3~vk% zn$+iQyw)nZZNnN*j?VZj@5*VKU&MLqm?ON7Z*MTJm?#MFSY3N|PlE@)`KuE28gJKucXU33Ln}%gl z!3#xFC#^|*rh9ejV)h+Pfvoe){_y`%3J{3a*>cy+a+8g=0>6gXHwKX`g{)ihP7^kV zur67Bu|-bdMC%jrYD96FOizf@QLmH{YRn&tc&d!W)!*4NJtc`<*m-MbC^22ARv#A%VQd6 zO#^51kIZYh$XPvC7IS`mWX+D!TXj2nKBMDNezxu-pRyq`zxGaW;N_vHNvX{Y z*MABw>$ddTQe@WRaG!Mv)$R12av)bRbhA$@3aq#4j?!CoJG#9^j^j~&w(isMnWyYC zi`jom-|B~aQ60iTpH5j^%?-o+36>j{?_83rPmAq&PsREYQDzeGB@#dY0$T~3PA4yk XpFzh25P$##AOHafKmY;|SS9ccVyuJc diff --git a/doc/blank.png b/doc/blank.png new file mode 100644 index 0000000000000000000000000000000000000000..1c7462f1addda3926a6a884689fd2b89aa48ffd5 GIT binary patch literal 500 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58aP1Y!Fw;R0V$SrM_)$E)e-c@Ne1&9> zAYTTCDm9?G76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&_}|`tWgMbm%k zH*Vd0Y`>lz=zKI#5K#a1$c*>#IhETDt2+%X&P#OqDMWo9QZ- z1Fv2EQj69*kaj_tev2`&946BFOd8fwIUn0!OZH=*GL@4r<*kp&w|T$yc~;{*_2;^4 z0{r?NIEtOmbKWC|gA3>5&Knf-aXu;gv5)hmy!A2n)8_rw$K0=kqfwvH`4m2GK1ng3 zW$TlS_#77Vv3Z>oKF*ie`YiGO_OM_0*m}sjeBBH1*1U8+@f5?yhs5-}Ky?-K+w&H& z%HYal`u&uDZkc>zhU#fP@O|I#8%_1(1IlAFpRFG?>er~?f9LZ#UVy9$y#D~tUW!(} zJ<}V{gn<44zwL=QmCar^7mq;qvAHMYp={!X-WMNq4>wkKB@(Ort1$V_uF3x@_IEzT z>F4*@kkv0(Rd}{a{i%N2JDZm``q5wN+6We2T~2M(%Tc~*>Vjx491H8gY$bFY8J>51 rD~g_+zN-gMU)y@(utN1~fhjMIAI}+{y=R&GPd4+@C_S(jZutBIZ{hZV diff --git a/doc/config_midi0.png b/doc/config_midi0.png new file mode 100644 index 0000000000000000000000000000000000000000..b8ebd379e7d8ed3ef26b028f31bd6d54ed1bead8 GIT binary patch literal 557 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 literal 0 HcmV?d00001 diff --git a/doc/cv_lfo.png b/doc/cv_lfo.png new file mode 100644 index 0000000000000000000000000000000000000000..b2f155727e3b19144e511c3ae55f053dc3ff96d9 GIT binary patch literal 609 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58o=b4b6v}U9F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMHK4i{28LfC^)DD0N(~qoUL`OvSj}Ky5HFasE6@fg!Ib3f?!v%$w@Y{lkjGx) z>Fdh=f?1Z+Lg9l!Vj|GCOivfbkch)?ub=H|G2mf%;IOW7k5|Har+C{3r3vv%4X!r@ zuib6+Z>jy^cSj#|`0UTTv@wj;orT5u{X-R>1^i9y87aT-7rl38Q*g3kYkn_b%;1$H zbE_djlSiOguRW8Iol8dK{P|YaTge88*yK6*)*e{Ajgdv5U?1a!9h@c&H?B1&9RIb3 zt>eM3xP2D23nlJUG0k#F?$x?zlP;joq{U*y*cjQv%{85IE`zpO!;4NiSB2VTm#6*v z9g!T)b?1B0zEqYFhLkta*IYN2KW(V=EHsc`=QyiK>#KtA@2dvgj=#75Z2bDL&w5+q z$9JMp3~lr8>RIqFVP*fy@I&W7akus91g8J<3gVksZRRxjva2_2SABadfpP!aBF>Xc z`FHm{cR0)BKdJ8Kp;r-Yh55`DFTPe>s7&~~;^Ausd6`hA7OxM{QQ^GLWL8{dI8@rk zV_U}Fdh=f>}mT*350*#44a|r#)R9Ln02po$lRr*nr1@^%hr+sN;6V_}B-z3&IUkqEC4A zT~=GVw*Ig|x0ce8Z{9hs^2r}u7IaIQn*j;9XnpYS~5=vL7Vjpg51Hu7Fby!StBmd}h^3`q;_UNmbu zaD&Yt`@U$PXnGIVN6Vs946+POyanc~*j=Wpus6K5lDft1v!pVB^G2zGF{9q3#dEqu z8+d*InaSq48n@l9NBs~LLjPhGa#6Uj8Gy}Y5PZTSox zMvi_7W%0Maudpq-Vy$-W^qoH(J=fa{D>u(KWAMLuk1^uTZi(NFXKt3gpYcN~k#+l# z3v4?kh)Y{EtU6X_s=(tnL!X@?MD-d|26xK0(@$A4>UABY56oyh`C2JlWsh&E!>_Ax zd4A9M_x<4LIexgpr|zk?`^G~rAMefVuXH}soa%6U&Lh3MZvroImu+s)W9)uxP+YJ} z`iS;gM{R+lYj^&TSiuuFxUO_QmvAU zQh^kMk%5u1uAz~xkzt6Tft7)&m8pTY0gz#kyYw@8UaDRU P)WG2B>gTe~DWM4fJ5&tx literal 2647 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 diff --git a/doc/dac_calib.bmp b/doc/dac_calib.bmp deleted file mode 100644 index 2ada3fea58be8dde354721d06acf8229e114867f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1056 zcmb`GKTE?v6u>W&NJX2>K|%(>#ZRDU)j}7+QOMHKwNr->lQCJE2nCmZhAu*bF-51W zeuaP{NU9(r6vdn`*LyJuNU`|x=kAwx@9xJP**{Vg!Xj%{;IYUa5#XYfvhU@WNvX92 zDITdghs)K3!1!Wh^~Lx*_a?^O_FH!E(pQ?AqhySnz5oZc7#Emv@{By)%JRuOGRyng zRf*luKxXsjz&i7Ndy@|OaK9lk_e*g~?)Qbv{XUVo-?+qX*hXH^uZ=$3&qwBd<@JN4 z>R0ynwITYjdN=GKFXGoN?B5NXuRcny(Qh5j*9dCpm#zYz1qm{p!uc9M%<{UgU7}A` z-*rPBIh)@^n6>}T)&HT&@?rd>5Bld(%OXM~D^gQjYe*NKb3%x^p(>&wEH~r_&p8EF q)MK#;EcHDH#(yv-j|YSMov6j~wzOH#mw@rMT#s`WZe=@%Upn7YW%e!r diff --git a/doc/dac_calib.png b/doc/dac_calib.png new file mode 100644 index 0000000000000000000000000000000000000000..cb4c5fe3339b0c04e67b278f117d4e4e96c62cbd GIT binary patch literal 621 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58o=b4b6v}U9F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMHK4i{28LfC^)DD0N(~qoUL`OvSj}Ky5HFasE6@fg!Ib3f?!v%$w@Y{lkjGx) z>Fdh=f>}mT*350*#44a|rJgR1ArXh)UO$+1L_we-F>zhfdZP)eAFSq%W8UX=;Pru! z%Xuf&9-YbalJau?wyADSxShCa&BCg2G&p_FlpuR8hsw0JDdO)F zBG-6Z?qTexRnxMo=Cf;8J9Fj087YCc;sqO;w#;;5^_tgtV@>c8wrA`fyqXQCB_(QH z-oJ7V`aSz$@k(J!-W|??7kTu5u!}cI@a*dNJ@FT-CS%eZ!RfXN3;|5t!V7Nt2U>?Q zzhFvsy4YmJ>V4jTt%FnG;>^@)`?bvsNel%Oza{JzXWF4KL;JuinNl`S?x-SRnfgB) zuW(&xvgCimSfjq2@lJP{bt_9$QK9@9?FFjSe=wL;D>i<%y~DWWiBLIE%eCYWJMNzM z?Q{GuP%Szqzi7^0mLTiiR<-s8^*pnltF=F<;V)-+ZJ1%*yo5EosBTN7QpUkE>5Lw} zO;=Pt6mW5FNxtCqe96>VTY@HkJ8%B;_k-p40$z0o%h(-0d+=rH4~Eb>hQ2OC7#SFu=o%R78d-!Gnp+uJTA3JX8yHv_7#P*?>_E|wo1c=I XR*74Kv*H#Opaup{S3j3^P6lWe?`j}_6PW+7NoxK7KZ)-;tXIht z0_ETR`?>!7-*xYP@1FJhJ(v&DzYe4y%zp?rKk>Nqf?YfYKzUFoApl|i1CajT503pQ zJPy?Mul_yAeZSwo`}b})jIWQv2f6P@{yVvkFnOT+fa>2N)PwcEf%8HB*FPrr5n?{V zZ6Fpw_f@}ZlBh@M`B(jR|NG6z{MV@bio|vq6!q)&{r-%s9*tj-*vw;(B#)#QBudbI zv{sLn9Wb~umQUne9OP=8CqSfx1VjW}92gy30w8=rAioBM|9pbW0=^2DIHFdh=f>}mT*350*#44a|A)YRdArXh)Uia=gY{0`1(725;*7d>KgW={W(jP*3?s1tE z8ShB7>z&IpS0ssR<81a{5wRjA$p^U`0{8^>c6H2s#FBZ?G2o4F)Rv0C+ZkTnJWP>} zf9uQxwx|RbWzC+jPxU6VN~fDw)@&&!cE?CZuicEP{hkY$9J#0bRj4?4Ag77LUp(#s zQ?tSup-n;e_-`mG8$79JF+HjA#e1i1!^E5O=I}SXG&m5T<9~zq!OJS?hHn9B8RWj$vQc%1Q6?UOX^fEz1oHL}eQTzhqL?d3ynvTnB@uqrZV_;#Fdh=f?1Y}!8*TZl|In6Q=Tr4ArXh~UO$+1*no#2pm813|1O2_=K9zNs}=Vr-MBiz zGjDTRuKDf4o5!xmIsNXCIo&0!q369wVZ++W?n>bu-D({!o2nQuHMkTo96TCx%i+Af zCg%pGEAJmZiT=iCePC6y4`WNry3AvaLT8x*-8E;m9d}eQn;`N*_Qvytj9h^Vw+^Ir z8Ok5rDyC~7AFX`r0qet4Iwv%W9k|aGJBVAIWn?=j-mu{HRX*J#Pn#+kI%;P;WHt!0 z`R1>Gg7H+)^O)!xzY+v)CUFqnO5Pu@VoK!;!k%ENbyJ9xozjMNo2dVgLDAvMDZPO z-ZV8Y@GBKquNjaRth=$K`R7-I{c8W+IU4?#9@ya1yh8O7pB?9f$&A$%(=`*UA7=_& zoEP+CmvMiyZpQuRQ)_(cYJd6MX4>$A*CA`aocR;y5=L41x}A>ZjhDmQEd%21N~S#) z*|2qzU-Mu6c?|deT;;5@eRhAdlzz;Q$q&AS?qR;PH&Z;}^0mXjh*m9ejVMV;EJ?LW zE=mPb3`Pbs-|S)o PYGCkm^>bP0l+XkKHzOCs literal 0 HcmV?d00001 diff --git a/doc/drums_909.png b/doc/drums_909.png new file mode 100644 index 0000000000000000000000000000000000000000..7b7664bf7d60d82b3618a9c2dbc9fba23efb2faa GIT binary patch literal 657 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58o=b4b6v}U9F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMHK4i{28LfC^)DD0N(~qoUL`OvSj}Ky5HFasE6@fg!Ib3f?!v%$w@Y{lkjGx) z>Fdh=f>}mLm9N@W+YM;jOivfbkch)?r=QI_Y{1jNx{K?J7E?TPU1{U`wtZa-!<*I9 zHMd?Dy`9T1?V{_usIK!LD`S78OcB$yGg=J{Gi>jqa(FltivK=rAh?2o<>KEsK23jy zW#xViWeSBiv=l@&GLz>pp7Bh7_wj0s=)niUaV$sV_@0IR73KSpki^pRO3or!IbxBF z-IGLy3YY3N;Rz?ceQo=@<|xAt?jSZJHou=U3f`^XxQ2;y>+X9BYZ*Nh<~lWAV^|c| zc;7mOQQ(c}mgq>fnpcc|+b?rEoNX{`ycVn&#rVp-AbIb$hGS1O&obMw6xJ~8<51r_ z!N`~Cs%Q6?Q@xxQJiM|S9A2xiFh7z}*t&;p!z0_PEYT|d+y~Z%*6DudP>}fggu_AN z>`{)2dNcbC@_s+3?1|@oX?^CFt9YZ;|Fc4y*+gb9Vok`8dXu-|sm^PMvZ|KV61j(~ zeU5+dV>rri_>QPUf!4p5aw| z;B!&(Ear263r=bBfBI*AuJDXM&x8F;apw<<-?<{GI=?sY2{7JNOI#yLQW8s2t&)pU zffR$0fsu)>fw8WUMTnt=m9d$Xv4ysQft7*5t}B9|w1m)*o1c=IR*74~>CTngfEpM) MUHx3vIVCg!0PH~WvH$=8 literal 0 HcmV?d00001 diff --git a/doc/drums_claps.png b/doc/drums_claps.png new file mode 100644 index 0000000000000000000000000000000000000000..408742205c36a72c3a3165665727d0bc0827c680 GIT binary patch literal 654 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58o=b4b6v}U9F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMHK4i{28LfC^)DD0N(~qoUL`OvSj}Ky5HFasE6@fg!Ib3f?!v%$w@Y{lkjGx) z>Fdh=f?1Z+L~2&&_xnKGrg^$JhD02GJN;nS5e1$$=ACRcQxC*&@B78Sm+P~ZUBd%6 z>$_#?Wr5cdZ#viS@p-=ZqC|bLm!47wdnH@#a%RIu%dPR?TfR@cH1B(SIZ zAIp;+7Vj9|nVo!alBt2`AFDt@V8&9RL)WbN)+}P>5MvhW^E3QrW744V$aT}-Cohe$n$zb2+yIN5w;hqljfwv5& zjJnk|w^?N{MP(gRym`U)>OCg|IddQR4_b4!?Pl~iEjydxx`y$AKR0Wd?PGq~SKZS& zx46MBbnl$%9=!!yGM-;^>t1Zzmna^vp4oP{aVPqfGK6^ABI)RE4(*cKlB^p*FR!r^mP#Sixhhaj5O5}*NBpo#FA92*k(KQ%Y8Ja;fTsnE| Q15g8lr>mdKI;Vst00XA^#{d8T literal 0 HcmV?d00001 diff --git a/doc/drums_djembe.png b/doc/drums_djembe.png new file mode 100644 index 0000000000000000000000000000000000000000..32ca50dd4870da9497dd776c79b11141968269c8 GIT binary patch literal 650 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58o=b4b6v}U9F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMHK4i{28LfC^)DD0N(~qoUL`OvSj}Ky5HFasE6@fg!Ib3f?!v%$w@Y{lkjGx) z>Fdh=f?1Y}kxlRa^?IOflRRAxZbos=)=|r zLE9~tmv?X7Ev~1Nx8U}{HJP&&Q>Lp-50FpH986(iT@r&1N-LE9Sd#V3g* zOnf5CKSRu5>Ai=H1~2-1x`Za2hHnrFRWU}S>@5|Fhi^HwEuLDo~a4NzPCD;@O8-9 z*)mVpYEXNylkuMMwB{933GY*4nD^&AVs?2x2Ko06_gRE4B|3y3 zFtB4>xHv&?E0cPK_SQO=TTGV|H~4(#`m;wauJP_9=4{`*gJvviY7-m3?Y((V{$F~I z+G`dMja-Jry+6-0FeNw6Xjto7#j|50;}k8#=(T3wk~)Nc1SI3l4z`@-zs4Ke?&XdR5n`nzh0Ly2OwCG)h);hTT*ZCQWvTkXYt z=Jprl_kHZ`cl%vD?c;&gdQQLoM@&pBII2CF`BwuYOtr){q9i4;B-JXpC>2OC7#SFu z=o%R78d-)I8dw<^SQ(pZ14#n|9d6S|6b-rgDVb@NSTq@Y!@|*ww literal 0 HcmV?d00001 diff --git a/doc/encoder_setup.bmp b/doc/encoder_setup.bmp deleted file mode 100644 index 72466039c0d798d22cbb95587230b8b7d275d691..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1056 zcmd6mF-yZx5XV#Oq+&Bj(WUKYaBve+jbp(Iu7VUt5pk*L%M;WsgCC$$#1GI(MImHs z#_pX`oFtg%P?{mUd%nC&X-N?$(F?hMe(&BTcb8YEWK^(3tQZn4i-dj8qC#@$1usAZ zXD)FC7yN@QJSn~+BH-MRfFMaHs!wBOY6+f`8qBm%Fi`OSf{S{WSH*9UEljJ26Fk# diff --git a/doc/encoder_setup.png b/doc/encoder_setup.png new file mode 100644 index 0000000000000000000000000000000000000000..81400d5bb21cb6798817e94224f32a455df169a7 GIT binary patch literal 616 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58o=b4b6v}U9F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMHK4i{28LfC^)DD0N(~qoUL`OvSj}Ky5HFasE6@fg!Ib3f?!v%$w@Y{lkjGx) z>Fdh=f>}mT*350*#44a|1)eUBArXh)UO(7%SV4g8LE}!YeWx7OHLbUM5c(msC64{g zj4iikw64n4+&w|&(w}dO7a#NBT3UQSyurb1#@y8ASvMTIEI7ToCOuN^6xpli`B;ae z&~!a>k9NZHTIX*s!_{{$P}w}yW9f;gMLx~94fNMH&0l#fQR()SyDC2pHN9kNTh2c3 z0n6qCw-xRgd96@qmumLcNtFnQY4Fr%W-MUX{9@|73W*HP+Aj>BQ<k&{goDpP=XzL11+E)LFa*AqX7`L2ac7Px=9ZZb9H-j|RKi9EA3k z-3&zbAQfS`iPUJjJFmC%G;%w5@zN|ie}41c`_G#lb|)T<2ITN$8Q(%+I}pSN0Ob0g zDTtBj5Ez}uGX~Sb|DsNWIu$FVwngf4R1pKt#Xye$*tV1D7EQ2h(bq7gQ2$IE5}!0B^F$t5$?Rz! z7it^voX6Q0gYsLur5GGTmVBXZ0`7ey=zE!vixJE4&;A`>e{a72{pWKcR6o6cqQ%WK zKL^4*=kja1=nR^nvdRrZ;T#yun)rVMq*HSs diff --git a/doc/engines.png b/doc/engines.png new file mode 100644 index 0000000000000000000000000000000000000000..5f2c27bc3ab0bfcb2319d66ddea6fd45d8486e1b GIT binary patch literal 13442 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 literal 2984 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 TbA7-3^afsT-g|3YNa_Cp=e2ci diff --git a/doc/gnd_fft.png b/doc/gnd_fft.png new file mode 100644 index 0000000000000000000000000000000000000000..4c3e62518d43327bb8f32fa5477ccd45c6722d30 GIT binary patch literal 515 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58o=b4b6v}U9F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMHK4i{28LfC^)DD0N(~qoUL`OvSj}Ky5HFasE6@fg!Ib3f?!v%$w@Y{lkjGx) z>Fdh=f>}mT*350*#44a|+@3CuArXh)UO$_4*no#2!Eqha{;q@J&T+91Rx7MeIuW|y z=IgLICLytR)=Ksk1@DWnw_|m4VZ7iuCBfLop@(yVz=vK{L$O!%Pb+EMBdhm#k z%d1a$4lfWmNQ5}U@#m`=x&@mvR1j|44G-r+Szph!Z}wZ}*URNaikgJyJYdmh`FrvIeAilt?~|G^-*F7tXBug@o7NU4^% zMwFx^mZVxG7o`Fz1|tI_6I}yiT_e*FBO@yVLn~8bZ36=<0|T#b2CGptt<8 literal 0 HcmV?d00001 diff --git a/doc/gnd_scope.png b/doc/gnd_scope.png new file mode 100644 index 0000000000000000000000000000000000000000..8659d6830e2538c894c52f8ef437d3421bc51581 GIT binary patch literal 722 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58o=b4b6v}U9F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMHK4i{28LfC^)DD0N(~qoUL`OvSj}Ky5HFasE6@fg!Ib3f?!v%$w@Y{lkjGx) z>Fdh=f>}mT*350*#44a|w>(`OLn02py?(aquz~=?1IG2tpS75Ga_#%o5U#jh>50}3 zspLs%<<@!3-u!c$Bz{ZQe`e=1WVC3!@5Cx}f%)H${mSx}85Bek4KD_kOrPxT9m!tI zq4a3OHq}pD6B3Rxw{U&xX0R1&FgkuZp}(?%D`rLT+|vevdWY}KVC!>enC=kf#Qt7* zU5Wd?sq?IUvP=>EI6;z=FQMj?iN2>qFQ1oDqtDk5Grp`8Yd)iwB71}Dl1PSS^Nfxq z4A~_KGp23r{JF7nS8w`kF?WNSzSzU0JwYen33G$? zf5W~e&s%HV{T7%h+HeHDO)-0V_WHKOUAH{LcL?w_{x1A)?LEc#Kl={bF8zI?Gwf|< ze4h%8c-0cuh?11Vl2ohYqEsNoU}RuqqHAERYh)T?WMpMvXk}`qZD3$!U?6c$o(Dxk cZhlH;S|x4`nUj}q0BT_HboFyt=akR{0Bd9z9smFU literal 0 HcmV?d00001 diff --git a/doc/inputs.png b/doc/inputs.png index 59e1dfc57669c3bbdebca40f8e46a37659fb73d8..bc696c56eefe351142c7b6a1edadbbf8bf1a3904 100644 GIT binary patch delta 829 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 Sl=Ji7*Bmc*s++)-ar!^tCN^dO diff --git a/doc/inputs2.png b/doc/inputs2.png index b95684798bb9fc25faa3428ed19c1f673c46cb7b..0d81dced336563dfd550c0c5ad49e96a24819153 100644 GIT binary patch delta 724 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 diff --git a/doc/io_test.png b/doc/io_test.png new file mode 100644 index 0000000000000000000000000000000000000000..78766a956906dfc8d811ce64e6f9bc6e450f6ef8 GIT binary patch literal 625 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58o=b4b6v}U9F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMHK4i{28LfC^)DD0N(~qoUL`OvSj}Ky5HFasE6@fg!Ib3f?!v%$w@Y{lkjGx) z>Fdh=f>}mT*350*#44a|m7Xq+ArXh)UO#y1kO9wuj}Ge^_j(;zeIZ=GLiC#!>-xsJ z+*f8-E}Y^0>oP}b2w1ORq<*2; zF5%}o_6pVu(=r(5F&Hs-@yuASFfW{WALC^qj@OKu7EXI_vjs6OdH$N=RnE#DDaVp4 zD|@V#Y)$x;c=Po^*8g{w*rj>ia4=tEfH4>?V8efy-tdWkqs3?y}vytsZ~r z$sAi(li6PwUanq#a_jHfj7!Y>Yd_7B(YdWK)AyU>-1n32T=YA~Eb{!xIiUFh^Cny0 z^sQ<*z1qAn$LuBJr8l?DJb>a35tEcRpS1hYr)JNv=bb#)wC;`N{PL`2=O6N?eqCbT zd$vdw7%!?Nt`Q|Ei6yC4$wjF^iowXh$VAt`Sl7rR#L(Qz$kNKhP}{)3%D}*=hGz$g dhTQy=%(P0}8k`lkumCkMc)I$ztaD0e0s!Iq>IeV; literal 0 HcmV?d00001 diff --git a/doc/menu.bmp b/doc/menu.bmp deleted file mode 100644 index af3365ef62038aca2afae95dd41f425648a580c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1056 zcmaKrF=!J}7{~9T!yzgamlg|+hgfi^;$ntKPjiYLEM{;JjIO%G7>pN4%sZMuB}yR> zoh5_T<mV@Jh8{tUcT+Tf_ z=sew5!D&yIxc>tEv*a%Rzx#&!@6bQG-#q%|aNmVaTzJ_BYv-ZUeHLDKni=l5pwoRm zVgkMN9n>eiB*Z-U?O6Z9PBM9@97FvL{iSBG9r{B}D|L^U{CPP4hBO@dgZ|*UFdh=f>}nykoDM>NKK$^!JaOTArXh)PCegsSV7=e>rS?3p=^7&KEHBW#~QEtAhcj^ zR@S!LVYy=4Hq^DxFtj)7n_oX=77$b^bwsY)GG}(cp|$cmrpO27iO-JyHJ#yBFoVm{ z+nNoEvsgATt2fk0u$1^IGH^5)-cn@P7PHKeBV#>7khs8qoPu;jo}=?4L4 zlb#pPRBrHG{Wt9zV@LCWxsgUM92d+eWztAXjEOaP&#*gEVsG~|$C#{h;pkUyqCYBAZz{_=8OtV}oPPPGYX)xN)|ss$omx zHNzV$c2C#*OMdWocKNICEDTx#td|7MUncNpWZz)ik;>|I>12%Ij0XZ`j8XSGecpLa z*Id(S)Xb2-q;yw6=&i;*S$o@S88%E8d6L@VUBz(kkY7W|O7Ev96Ith>?MniG`J^ tnYMv}m4Sh+$c8W!4Y~O#nQ4`n8jMUK8p>0o^MD!{JYD@<);T3K0RS~=+1vmC literal 0 HcmV?d00001 diff --git a/doc/menu_engines.png b/doc/menu_engines.png new file mode 100644 index 0000000000000000000000000000000000000000..f284832c14746ba3fdbbc89964dd2b2d88a6bf4a GIT binary patch literal 852 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58o=b4b6v}U9F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMHK4i{28LfC^)DD0N(~qoUL`OvSj}Ky5HFasE6@fg!Ib3f?!v%$w@Y{lkjGx) z>Fdh=f>}mT*350*#44bCjHioZNW|f*(=K*BRp4oBy(3m5dhoVWob83^gW-aEL^oZ$ z6}MU_1?iK8L2VcU~wS|8b7 zc%O?=eb=}+MPJoDG>K)wtA@=_bgswrH0&-7uf6$0BnjgCc*J{&k*7AFcQ! zL`3zDr%b=`d&9DO?Tj1T>X|-qabG){$Z(*}{Knjr3GFP|#fD7(N?m;!n$0XOXFk2{ z>Jh=<`{}Oa)N206CIX%lgO{?unO}cz>hik3!VR|@H#f5ET`Or2n#A+NCHe;AUUS16 z220LI$S^&Udm9^5lJhTfZ>s+Ji#D87lC>&T8#l2ohVx)0A31E6 z|K5H_eW&CaiQtu1p^N5zW)*g@j#%iEax?#3l(2)bm_LISgRn#KUU7w|tGaViOx!ih zj~QO@o|0Ah=^@vL1J4*s^FQov&_Di=|CGv&^c7KGR{)cqYKdz^NlIc#s#S7PDv)9@ zGB7gHH89pSvIsFWw=%M{GBMOPFt9Q(Fsk9%fubQdKP5A*61N6t#VssA4Gf;HelF{r G5}E*NW=cc= literal 0 HcmV?d00001 diff --git a/doc/midi_clock.png b/doc/midi_clock.png new file mode 100644 index 0000000000000000000000000000000000000000..4c86ca1a6db879d24d201ab07fb2bf732c9da963 GIT binary patch literal 2956 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 literal 2482 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 BP^16= literal 3498 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 Qzecf>&hAci4na5m2mNx4vj6}9 diff --git a/doc/mod_ef.png b/doc/mod_ef.png new file mode 100644 index 0000000000000000000000000000000000000000..3d12e31d8ca87b024dfee99bf57dc85dfd80fb05 GIT binary patch literal 3433 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 diff --git a/doc/mod_env.png b/doc/mod_env.png new file mode 100644 index 0000000000000000000000000000000000000000..b99c0fb14b7bb6b56be0897efc67052f4a0d86a8 GIT binary patch literal 3518 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 literal 0 HcmV?d00001 diff --git a/doc/mod_lfo.png b/doc/mod_lfo.png new file mode 100644 index 0000000000000000000000000000000000000000..6515987f309f14fbd226c80c336884a70b3b9ada GIT binary patch literal 3582 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 My85}Sb4q9e02As#U;qFB literal 0 HcmV?d00001 diff --git a/doc/mosc_waveforms.png b/doc/mosc_waveforms.png new file mode 100644 index 0000000000000000000000000000000000000000..c42968d92bfdf0fe50e32fe732525d3c610fa3ac GIT binary patch literal 3023 zcmY+Gc|6ox8^F)}nh_>4mPr^UQz?;KStk23W^!|7jWHUkE1C$ECBzV+3@Y8*B}?d< zOpIO0GH=-;G(y>ziOOWn9(sR$-oM`S$N8MkS)TKp=X{?f!PbT%A+8_}0FbacL9zz` z0S^IFR0QrnRaE_2KwPz_n1iAYrLO>>6Rb#Pjv@5v4B-{Rp&c=TmB=rTesAnhJ})>W zaZcpnunA2rCZ+m`NK@6o3fw-xZ93@3+U&&0jpzDXL0#KTCZq~!-`zXH8g?&noBjys zZORoYc{-1m|2{|=yIK)=8O!WUy$`xpeNdi=hpf9-1#2=)ihMF|566~m)*4W%HKrP- zpcbi})ztZ9Wn`*?=$sIVRiX*vGi{SA%YbZRL3H`=+o-^mrsp-xXKlu(_1<^^u_a9B zY;P_WQML}&NwfRQP)oZ3;*_u}q}yce>6pxtyMSwG*DGFX7$Duz*BO$t#Ai6aE}7Iy zi~K7CHQGTEN?Ltqdsy*8H);Qq90W=Ial&c2H-Ej`ltgIHml1F8jA$|y@{`;K{>e2r z+xm)pGH$gdUGJ4l`LVC{WMxJ;6uLyyS$6%3tQ?eu zV}&m1+6~pZr5IAgB^E!;uM)^a6l9ZQj0x zkJq$q<|)BVUnDbbj6Yr#i%jDtt@O)`MKB{ex2jaQXgw03M4U5r<*QO%P@T3qA zPfC91=oYQPj~-&)c_r#5k3jQc-vm#QO|c-9I*B+~o8n9KgE}#mcX(7>~+BT?E0V~M~(T* z`ek54)dNASI#N`+eh08w`stff4NpUgGPweiUGNPrR_mW#Mm$VRX@3o~*!xP+DA`zL zc)g^*pCik6);cizWp(8B!ykUfx@s2sPExb#^nHd)-h8Ek8D@b=0-2?Ns{(tS%ZIE) zT>w@FNMjQ=nI+Y9p@C&tUDOGd9{5l1ek?%qnjvS!R;c(d`lxfXojxNfb<4Xh3t>ng zhhW?b1%<*c!$7wRXJMgSmeXe{2!}*_4(rg{#o8U3ox;#OuTV{ZWu|~st})5ox8<@+ zkNY&z%Dw(@RB3SuiU;8zXz65E3+|aPJY16}->*v((F!zJALbRc!(G;cdIM|D^ zbm}`fnWL6Oe{?$C58?6+DOD@uwM$ip;cJwp7di;dy^yXR5g&B*CWTM$k;aXMLm@wN z({rygEanmZHHNj5yhnc7<{zR9E=@Lfgo^(jAy7mzsczUh?IPI7FYvCFH+9FBbQ=SO)KJeEBVRIoNSS<7P z9+grL7tmdmR@52gu93j- zLU?Of2lOvPQnhV8-xw&`Rz|Pgbeo9Ab)zX81>cW8FHa+~ud639=%4B7)^?HIE#)@T>J}3HVJOv~SZ4aNZxuDxG}f80e_b)g)2x8>e!Vbu_prG7 zt(XBe=M}YvLzFSD4Sd(8(mt|EuIN;9jP%$PQ7%N*y{7|8DYKIv8G=mF ze`2`mWsDJZz!zcZ+9&K9<0!|z$+|tj-*OE|T*#X|HE(<7>8j@dtW~_UowiM^MXY`L zsTdkCCXk-17}*FhBYgra^EO!2EmxN>r|Zt!MfRZvgvpbf=bSCa%CtaHqaxr-F=BYBc4dSaK;93P3!Hg=yWPbM_JCVp6gJYOv+#p&Z>bg`h zc>6k*a0H4Yz|m9bik3HW(u@cFwsTifgQ!vx>?-~(wb_`5+u;yu=th(#_!D8QU+-Co z{(pfj&}bD?xr3jIu9o~a&r-4#!dpy=nZOqn1piv5+`R3&8M%qvI2z%%}t|xQB52u2QLuEhs z=T5s&vtf7*PQCTA-J2DocIR?~)cLg$TD{Fzs{2+itR31+aaYiavYYnwxG6(!K8p~Q z4sa^_2EASILbN<>nLsgTe5T57+ATY-YG+zh&FnKMg8#LC{|?VdYW;TGUiW4Fig2;G z1MlJQI*8^S!&76)<~U84+s%-a<-&){G=#Ti>NCF*+znEX_vNbnNzp2DNR)u z+|Z`?a9t_t@Zld?tLz4;cj^IsLWgkvyti9l5dYR~;ZkhwRz}d3P<^F+ z_r`NFqQy7Z0j(B8cT17@R+$XYy%EX{N;O%_Ut^rnh(y_nl>_g6_hPkl&S|SNfX*;I zOed2bmZs8(;Q|T6{jug z`1FJh$JVRy{L*s`u>F`ff++8=wStK%2B~U@R}W@RYmW%75=@;{s`cA5h5~cSfLolf z+gcMm_0OEN#xmclF1;f2MDt*tPsDXgvUvJ1guP>}cNL9_G@{&Z| z=wRcYSX^8GaSRlh)m5`D$Ae6tjL+lXvxC$M@XckoBLQ|U7r-VP)*XR;hV>?pLB`+a lO{hTRsL~9~M@-aDz^&e2`h9QYBe+5bR+cuTB6E-E{{l0NiM{{; literal 0 HcmV?d00001 diff --git a/doc/noise_808squares.png b/doc/noise_808squares.png new file mode 100644 index 0000000000000000000000000000000000000000..36e8fea8bf8de00151596a3ecfc46d0c62d31285 GIT binary patch literal 2406 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 IG4#iO0i#x6G5`Po literal 0 HcmV?d00001 diff --git a/doc/noise_nes.png b/doc/noise_nes.png index 8ddb9eaab7a7b44061a5f0451cb2137e0c758d6e..ab3c092bd6de6b2294b69715fbacb83857f67e7b 100644 GIT binary patch literal 921 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58aP1Y!Fw;R0V$SrM_)$E)e-c@Ne1&9> zAYTTCDm9?G76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&_}|`tWjWyyf_mhaV$3qJY`~)kzc&gZy&2j!t-72yY3zA+imM_>lS`Iotd>`%e`8k*RopK z{|!F<+^NgLRgtsJ)FA1}|NEByDjEmgeYv)e=iRf{^XymuPH&$h#=v^u?Zy1fx8}1+ z1APJn+f{Bl^@>;9_20JVRSR;MXtt`x_j%s>29qg9+H;S;75z~BM`V72jOCraXnA&4 zmvV;`F-yC6W{n3MHQPV!TKDN@_2ZsYsjWG;0}dn?=d6=G%{Alyvu)|WH~Gf>RMSY% ztdLqE$y^s!$dh}1mFy<5%(?F`d>3cE^2mcZPAns&Y{mNHzcxoLF>Aj2Y*$EtgYLPU z1OI+KesONwrK|a?H+~NXnXvihuLntQT>b=IO0O!YX8p6jCv~e-xb)sT1@`rSO26IP zJ-w0lg6H1v<^I!dYb&sB-nxJDb=E)!zCDF@^|2DHDTyZ6j$-#)no&=t?$OWvWPItI7Q2YSs*uHu`sYt|b8NpE z^>Zx)*9`OO%CKzzz~guKS!(?Mv6#W1@!yH9+YZY8=Y4#)nd#o&2mdafTgxM2kiYHy z^z8c*xy4&--mjm2wBkNH>zB}5IeW{!UT-MdH+|x5?FMcEVA|Nha8b6S4a}Tmm8Iki z_6dkkKlop=>z#v1`+dz>C6SfttgHo$i>w8B;}mu=U;M-TJ8pC31l~u$9KfJj;u=ws zl30>zm0Xkxq!^40jEr>+jdYC+Lktb93@xn;O|%URtPBi}2_0L6q9HdwB{QuOw}$Qh Rb#frbc)I$ztaD0e0sx6ohD-ne literal 1149 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58aUX1@zJ96I)nM+$m1m)#-R+<>!)#40r8-U|MQq z-uBx?=l@Ty-}CS1=dDrJ{dxQEt=|^=*1~k@`S_~Z*S|CW?lHJDfAf8Yf_c;L$yQY# z@qaD1sr>(}K-(wR9py4KGjF^3w*!(Y3>;y5_!6e6 z7~FbM`ET{#x)Vx_4jbNSGrIR)`hG9@!tJ`u{fo~nb-#Q1!JYZGAX~QSbWe`pPz9N}dc&G?O4Y5eg;~e-_uji@cYWK}>T6bNSFFpf{N8&fJI4#?inG@ld;FN9 ztG`6vdLHAhdi>h_?R~Oe_szeTavS8=vz!lJ7&fG5&aXc=%QoZcZ(EJ6_TEV{rqQ4P z$zr4$K866DHvpku7Qht(Htx6Z5A6JlVQ z%#e|kdmwufI84-{*Z)a@h!To}S>bF=a$zY}?(g@C1C0r0u(R<&b+aCUaNkTpZK{bo|2H??y}pr?@df*h`yd^ z|LVuu-_v{IR-UN+bmo921Byo7^A6{s!TpZ5+ z?&`0)Yqur26WDa4)j?*3O@c-%gMFA7cGIf3E9=&&I;Q5PLg~q3_khZGDDY zw(ZVyKYwet?F_ir)F@0IUS0R}I&lxZV2C)VclW`*^~PB}Oj15E~nJ(jeK zRWnM8e{*#6ZH4I|%h&S#S+nMn_oDMp^x?MZ)bSk9;W!D5%x~hegLpctE*;MYl`fvH KelF{r5}E)3pZUcA diff --git a/doc/noise_whitepink.png b/doc/noise_whitepink.png new file mode 100644 index 0000000000000000000000000000000000000000..021f0696c0ef5c1b1752f3823b1ab1c087d1f110 GIT binary patch literal 543 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58o=b4b6v}U9F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMHK4i{28LfC^)DD0N(~qoUL`OvSj}Ky5HFasE6@fg!Ib3f?!v%$w@Y{lkjGx) z>Fdh=f?1Z+jBU@plR`k-)ID7sLn02py?(H(*+78pLF3MU6T&4wM4ed8U%~rB>oY^+ zn~W{owlhjDztgmL4cRxz=Zc?dtZtE>*DMYn5gr$>{h7@y2hJa0wEWP_ePlya9@C*R974v+T@R~yfNm=dxl;=nz|C`PRtJ+RsHciRySi(2&dm#G( zz7w}UhCX8y`pTp@KgMLeA-nCqgO7OaZBD;oDEXhhfb-byRRGl zn|HP1;iLa7_3Iw7E8RM|rDfw8WUWr%^L xm8p@HiKVuIft7)QKR76o$hLRY#C2lx~cO1*i}*LK#UXq%e?rU_eX=DXt}=#B80aYz!kI5SK_Q-2Fq==BgVujaZ6&}R&RD!EEljHFekh+>5@}GTri?~XM%n9oS)3+ zKUtqsPmjKSuN=+%%z4nx`}K0;*yod&ApZf(w7)V%iJhVBNIXzR^~X61Ob6kT#0l~1 z@i)g2_ecC_2Zcx*b?#T0+4C1qnD6Z^QNPL{rxN1*OQafTKW{KgL5mYF@(W5%wy5ue z#l--rn|j^%H`_m?<4{H4f3A2}rSO4L|Ekq$q42se%=ZJozmA(iDLo8h-hznqrho%I zaNOc}gpBkC=}Bv{KG_H$omcA%Zu0vd?p^k}Wyv*&?oWEYN#{qGcw>=Yc5Ju757#dm_7=8hT z8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzbiZkO;9AdkJo)7O>#1+$ExteM-q ziB&*(aZeY=kch)qr=MN*MS-V{`6kyruLE!E9rE@*2>TG$lE-YhaqdiG`&{Ma_jzg- zmTa+mEG@iM?26%s#$(sLO;3N-T;DqLHHU)M)>W~qrbq8z6Ryz5Sj;ZMT^zhZb-Q=Y z-c`YCk{#BvuJX_ebjjM8k*fWqs{9h`4)2J|pZ1957HVGE-NIhNyEc{a%*lkSr@3NO zZ61hanba@XxJ7T`^i_-&Og7S0pAWMBGg!>Ptg52qqQFzIedU3awag4>49gYLo=Vm; z^2s&`KDh9~#2{&f&CLF?=@ze(z4shD$b2A*TlK}msQ^)HG0riZc*8dB z=9GfQ7BAlFeV4bja0mE*=VM52;5FcE{JB#&i~Yxj+H}AAd%w7xgtweAWq-?DGxY}R zjc?KqEfxy+YCaJNdSN(iD`U-r@Ft}c=A?H^b>+(%cDuaDd@mHXsrCQ6!*U-i&M^7% z3MAd=JFNJ@@b{@24zV+mm36f_rxT|ZG^X;`-?h?V-oa2i`7^_b*$vM`4=^e)`nP_L zZn>0X!0=^X*W<&A7wX$Ht4|cl@HHl^Z+83hN2%gmD|5{qw`VF`O7H$vb8HapzFoV1 zrv!t>)8d8zFX;nTiERwg79Rr+v1>e3Z)gvwKCrQtb3?%Dxq3U^TE1kwalXs!Qu$Vc zxvcBlrx+fXW5apj+M}1u_Ut=^wojhnV!f$p4g=p??F05dvi8-#u@L%S!}{U5#UBQ* z{KKalQ)fB>la6YMYeY#(Vo9o1a#1RfVlXl=GS)S)&^0m+F*2|+G_W!<)iyA&GBEh) ub8st)hTQy=%(P0l21DZz12Zc_3o9cth=vXJ$y0zD7(8A5T-G@yGywpu%{3nY literal 2928 zcmXArdpwlc8^F)|dWS(VL#khyjIdV;E_rXK;&x8Cl(g_g{a33?MptQUC)EU1f* zvMi6VJnLVukPWY625tg#TkoT{B(sVI%`#Jy0iSA=>;+bBoIn=yn~_*3nZx0niR<*) z&sIuOq%D=ntK@VEgBSdB*Ggu*SU4P~dfIZKva2NnaE<;-U2P7kOBn3^JUd!Qme6MH zBYlh*IEi`7a@^@v6rrMgU-zVK)|{lhV8G>&h_gZ`1oWLOZqlNFmYc5dlv@BYG~7m# zMb#Ul11G92J>!+*0`Kd6)Knq#IF8;AWzEN{c5yq~v*nLQy4%y=X3LAi+h`t=;Va>G zoi4vWEw28`DS%5)oPnv}?xiCeGkp_~p>)({TL$=RxbVb~0xmS_w`KF!DLtP0yfu0l zPNW^XF-2F?I1i}b2CE*o=g*X+cG6Vh5!O8$jxQ)mu1%_y+ljRT4epHKDHE}I?y0nI z7N9w+^#G3YU2yQn+N8c>YP>3X>tp}M*uLWV-8NNkKeY(wGuwrp7e`!O83zM&QE_3} zG)*N)(m9VS9xF>Usp(}%*;d|B0rFzYi#9Hjy?)M&5odTxfXNWdFP0vW6N1D1rdX!f?a>uo~<}b!XC0Kc) zbg&c&QjtM*$E&lwqci1_3PNK_j=*Kf&E;0dDL)PnT|-NT>W3vED{nurF#b~UlboXq=dtNv{4MnaMZXkY7L$uP$a zO3*4=5FxkWq{`gSX(o^|1{0dz7~BlwDP|2Nb)F#q`xpP{@|Ph5@B)SnEvG(cU;pF` zNvTBHs~^gFHCg#op>6ChF)P9^9+Z_`O&BigdDK!ozbh?pL4dyf`2KK`DKqPS?jRo1 zVL3gUz<#gKl?}?+Nky`_h-q#GsI&Pp%@eI=77S);PxhQM>XJwJ0eN!S;p(qGZq_3@ zBhAJMt?oTPA38Z-F+I8&CWFC@wXQRzd~dMino~Owb!vg^HP}N)I~!ymi z%Ug|h5MF0$d@c%8;BJf`5LCE3r*}3Obf-x~D$181(om9cFyx>6nM%w3_2IM*lhUB$b$gmwru1)P zDXu-uX0wW~?&xz;Wn8thV`fsf?hVU3Mh2SNM7exvMOQsnzKJA@SPSeL#a$g$zp#!A zPwd{?Rc|pt)=P~^dIrgjg`oxh&M$?K+uOas?xm(kebYr=r?w&>2Zs-;& zK!%*!!tSMmCCmlpQ6zE^wSp2E12^e4$*10ILRbg^UE#6ED{=>H3e}r#xOxg(uHk5T zW+)$fg}A`6?pzl`{tCVseEyh$ppxBKvPz#MPgOr_jaE8U)G>0 z5XyxjE)KRHWZO(GMTHZfPe7f_T*G-J_T2S0J%A!xWOzNy=qWLSmDTgb+{5rDZLa&~M|X9G{6pEEVtJQ;eA8}C zaIb?Xt5af8;-@cqs4pUSp6F5Z5!V)Ra+tHdzq2lfcV)$@rVPj{PrF^~pTkp<)|P!B zw7qXQFdNVxmK5%BTmCW^4NLD#|2JdE5x4>SHJdcqb6aD1{kpL&Lq3{6>Wg;J#ld#` z+n{uZ`>&iTJHPS~JHnXP&`#L8nW;Pu9$Wr)3_tHVv;jV^Iy)KpTzf!SJ}m_gCpgA= zf{2h_vwBTmpKvGUujrQ=*R_X#$X?t!Q5gkJcU60o_ zJMo29(I!*y&dR_MdSqP&){M~Z%7Owj*Lk6aR9dz`A z%>n-hd^Q^}UACJMP|Q>VwP{u8No=Vma<->*t;{u=4p8*qW4At%+!odIP`as^%HsK( z^W8|?QQgyk8}M%Y%7qSpUeO=}(7@R6nGLvo9I2vKY4N~(>MZJJe<*0Z8Puoy?p3va zf;6q(qgLBM%rT~bv_ z@Kw5-7$7;bnP+6o4?rz2s~-?7VAY;+jWG&PbnIU}YKa0e=zr*SU!_Y1cx)kTC(^GO zKafJVl;}nejVra|8W^9gyJ^8O@(;2$xyF&Nh8m)(o2=Gm8)!youzjn)ca>-4@&5yM CC}AQ1 diff --git a/doc/outputs2.png b/doc/outputs2.png index 91483df54ab302135c85e0542a07fcd6d6a79cb8..725f5105d165e111a61b78b156800161e48f3118 100644 GIT binary patch delta 781 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 diff --git a/doc/splash.bmp b/doc/splash.bmp deleted file mode 100644 index 1b85b96b7e1fa93d01bbedd58549951f201a3977..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1056 zcmZ|O&uZH+7y$53I9Qj_Zjgfl#_FLD;X`3=7(EnrSYDvZQ3Bc9;z#+NbzmVyH~){Pan&B7NWZ^VJm`n|-{)kAx5iUdEVX|C={noP~%n z5`dfhg$bAfP-FC|KWh39fDuVb6=Qq}a5yo+U*i%+rE*yuDR6Ky-F3$Awr^DCnr~wU zmw@fHvu`cXshZ_w0XNn+orSfJ@6Yl?`3$FGyKGIgHI>|`C@;5Dva@ztJC*UywJUf* zC5FMys%;6N-G!nrOCxE|7nSD_&(d_WkbNJQkAHwgNnYle^s4be-ymiZ7}ZU@aZru- zc#>zy)}Ov*dRRyisW#p>Ne?{TXGJr=?@{4GR3=5>JcZv@;I$r1!u1$Do|(f^QyC1t zgzJYhi%%2qh>Crp81pcGeGftBNjSVi}rakBB>z`HUW`B4=lGG@6;jA8i{(^by z!8pAB0Q1p)FI}<`bnp-k3Fyuf@izgD88@X0PkMcSJM``ORd#;d-45S7J8m*;rXb%} zkNe;D{A=S#n;(oMNmj~}{HZN$+{b*|Oj(qxF8^w``KjXBGsfHet=;B#dcYJt$^Y7Q oeK6cGlHmK>`e|I%7dKn6d^QEHwXVO$Rejo3)~#2+P51fpKNhkr3jhEB diff --git a/doc/splash.png b/doc/splash.png new file mode 100644 index 0000000000000000000000000000000000000000..bcdb8685374b8d9fd982f2761e6dc2141b60915e GIT binary patch literal 14914 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 literal 0 HcmV?d00001 diff --git a/doc/synth_dxfm.png b/doc/synth_dxfm.png new file mode 100644 index 0000000000000000000000000000000000000000..bfdaffc86cd7c707b4305ef19c0f3bf5632a6057 GIT binary patch literal 2793 zcmd6p`BT&97RKN2*FXbYG(Zt827+9qfGpLiP!qb z3j&r+ks63eXf+ZNmROXJRJUS6vHA zwc>k4HhcXEDY+#o$^CJPO|7E9apKP>1=Be;;xXl}q6!9315&D7PNM6TW5HrOeM?due9qV7w?VOL75Z}eo2 z=3IN7v3yi1wDy*Ta6jVn@b2Ue>cHpKOo`6J(TY+uoQfG`#gA$SnCe6C0`C*X@p%IR z{>B)u*<99o8I+br(ak*a5vm1hbXi=Ecfh*J72>NhwGI>q+G8ngCZ0SHsAMLboll-5H`LFPoaX4Rm-x`3i#_d|%fofca$PLA}OfJtdVQ*tu*rLLpH1mazj_74_+ zva2CJBM!F8vTX`fO}{DHV!1AXiU66InPUm+dk?Jnf`d`ZZ_IfX7!aXYM}dat4d~&d zS1&g1u5c5oms%sW8xlNcDnq$4rd|HRyYr`~llm6=yxJ%Dt0q@-2GP)z@9#gG57t#X z?0>2czs*grJPgRDDJyLQ{i%43xx+`83+=zWzRBSR%fuuSPli*^a4@%JT=p++3?q?=jXGXD)B>95@;`)G)2ab2?ng_I+%PlO z5vRu~eK~sLrBkG7or+1xy%s8P4xt=&<_@S%FCTd?T(zx@jNdz7)leOybNR8~M3`I6 z!7ZU_QjXt*`V$$0+k4uPNo%A@a(P=M4y6O$ejwKKOlaOfq&U2@v}AlHr~Z54>Ng_% zTgh4?`VB&4kChxEKWI?2&z02<8x`4MrgiGF6h%cRcUS@>?ZuwWAc=Qi4|T}SQ#16* z!(fjQ?HkMTg|d1=O#IwJHu)2Ro^$&fVwz1XPsxlbkA?AJP31TgK-4wemUy3G@OgUu zs#@JsN$w-MSc3XvO1R^A14C(6emyDL7|7B0?>qFIO|CB4HX<=OIaclGXvTW) z1ze!ExkLnsXSG?i4R&e-rNc{e)CBd|7%z(YzPc6-(?G_&Hzi(}6?498XdC>DiwLZ| zZ)QU&&<=fFo&NQ#l)TveW|-IA^|4dq#=c;H1c5Eq^hwz{;RA^+b>7{X!x|c#jB;Cy zc`uBc%6WKZ_3mX#+E*W3k)k1Em*~zc3t2yvxP}x7{S#!ZA4ASJUi6I+EFZhOr60$t zwDbiIksgTgn}rd3_u7D-+);F;cI+LTe?kC^6kR=OWrNJt*zv9WxE6$biUm-`jUx|{ zbT3UWUZgZV`c5PU?8pDG!@}tjfSr(glP#RKKnT(WTLVjkwgDDs(;wL*PGM-^X{gol z??o656w}Nv6#YvB*xBTB8MVU)KsylITTm5r4d77OB?I_8@*ynR)OTST{@mKIZI9hC zi)aL?*tNq$4>3O9dolX?cG^lAu5ta!THZUnZsGM9yK?FKZ8eV>pHXJh=URq0W{er86!Jx|>rzZRDUnVc zYDrJ5)+A)p-*;>OS#e?J{E@___hk7a*%Jn}oi(DGd@&R9jHs|#JX*kBewmGA@H?US~v?WX*}+Us$jaoIl$#+1^( zm1@5~`OD%aXZWpe2hS_~FBjJMbSBj~mF4-RIn-QeeLLFQI+do{6*y)oM6H)H{d ztpTBeWwwr&*9W_jA29inTm;r2*R1v^z@PuM`05&NX&6fulz+%tqd>!tWtNE&U<0w_fk`;4Gm%#y%2A#&s}rl2sj1%%Z9W3`X;cqLw^A zyx1IdQ%B^DOE(ST$lS@+vy9&lfvsXta_*+?C6LWNJ6Mc~dEVGQW6l_Jv9kf>i}r<5 z*0>_P=Zrr69;Y$y>!7EN)-)iwJCc4%P>1_qf1{@2o;_%&PqSGaT%d>Cd12+qu3<;7 zPf-Jy)`&t-1@a05cLO`TGV4bzQt`b$7)HJOHw`@h1ocW2V9jaD05psQ9)Mn~g8`-{ zwGvI5J>T;GA<8}FaoMkS7&aav5j37^DzkD#?m*l(0r_3erwoIxS-xGbXAA#?G2n^n zfX+^h+Z_EhH`l&muOEQ0;M!@j;gV*mgLZo@n)lM@&0&YA2*dL4xVlnl2&+}| PcLf2y!9E;s(z*WthJ_)| literal 0 HcmV?d00001 diff --git a/doc/synth_open303.png b/doc/synth_open303.png index bdcaa72ff84e3fb5195ea727219ab90e759cf5e3..a409cf64ba3df316a3a6146574b11c1a8e270db8 100644 GIT binary patch literal 741 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 - +<../lib/> - -<../lib/udynlink/tests/> -lib_deps = - https://ehx.spdns.org/squares-and-circles/lib/machine_DSM0_${env.lib_machine}.zip -board_build.ldscript = - $PROJECT_DIR/.pio/libdeps/$PIOENV/libsquares-and-circles-machine/STM32H750IB_sram.lds -extra_scripts = - pre:.pre_build.py - $PROJECT_DIR/.pio/libdeps/$PIOENV/libsquares-and-circles-machine/pio_linker_flags.py -upload_command = - $PROJECT_DIR/.pio/libdeps/$PIOENV/libsquares-and-circles-machine/pio_upload.sh $PROJECT_DIR/.pio/build/$PIOENV/firmware.elf +[env:squares-and-circles] +platform = teensy@5.0.0 ; https://github.com/platformio/platform-teensy/releases +board = teensy41 ; fake setting - the engines are compatibe with all targets -[env:OC_T40] -platform = teensy@4.18.0 ; https://github.com/platformio/platform-teensy/releases -framework = arduino -board = teensy40 -build_flags = - -DUSB_MIDI_SERIAL - -DMACHINE_OC_REV2E - -std=c++17 - -I./lib/ - -ffast-math - ;-Wdouble-promotion - ;-D TEENSY_OPT_FASTEST_CODE -build_unflags = - -fpermissive -board_build.f_cpu = 600000000L -lib_deps = - https://ehx.spdns.org/squares-and-circles/lib/machine_T4X_${env.lib_machine}.zip -board_build.ldscript = - $PROJECT_DIR/.pio/libdeps/$PIOENV/libsquares-and-circles-machine/imxrt1062.ld -lib_ldf_mode = off -build_src_filter = - +<*> - +<../lib/> - -<../lib/udynlink/tests/> - -<../lib/machine> diff --git a/src/SAM.cxx b/src/SAM.cxx deleted file mode 100644 index e6b0d1b..0000000 --- a/src/SAM.cxx +++ /dev/null @@ -1,115 +0,0 @@ -// 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 "machine.h" -#include "stmlib/dsp/dsp.h" -#include "base/SampleEngine.hxx" -#include -#include - -extern "C" -{ -#include "SAM/sam.h" -#include "SAM/reciter.h" -} - -using namespace machine; - -struct SAM : public SampleEngine -{ - uint8_t _buffer[48000]; - tsample_spec _sounds[7] = { - {"electro", _buffer, 0, 22050, 0}, - {"techno", _buffer, 0, 22050, 0}, - {"modular", _buffer, 0, 22050, 0}, - {"synthesizer", _buffer, 0, 22050, 0}, - {"oscillator", _buffer, 0, 22050, 0}, - {"eurorack", _buffer, 0, 22050, 0}, - {"RND_1-9", _buffer, 0, 22050, 0}, - }; - - uint8_t _ti = 0; - - void say(const char *text) - { - static tsample_spec *_sample = nullptr; - _sample = &_sounds[selection]; - - SAM_write_buffer = [](int pos, char value) - { - if (pos < (int)LEN_OF(_buffer)) - { - _sample->len = pos + 1; - ((uint8_t *)_sample->data)[pos] = value; - } - }; - - SetSpeed(64); - SetMouth(128); - SetPitch(64 * 2); - SetThroat(128); - - char input[256] = {}; - sprintf(input, "%s ", text); - for (int i = 0; input[i] != 0; i++) - input[i] = toupper((int)input[i]); - - strncat(input, "[", 255); - TextToPhonemes((unsigned char *)input); - SetInput(input); - SAMMain(); - } - - int _lastSelection = 0; - -public: - SAM() : SampleEngine() - { - setup(&_sounds[0], 0, LEN_OF(_sounds)); - say(_sounds[0].name); - } - - void process(const ControlFrame &frame, OutputFrame &of) override - { - if (selection == LEN_OF(_sounds) - 1 && frame.trigger) - { - char tmp[20]; - sprintf(tmp, "%d", rand() % 10); - say(tmp); - } - else if (_lastSelection != selection) - { - say(_sounds[selection].name); - _lastSelection = selection; - } - - SampleEngine::process(frame, of); - } -}; - -void init_sam() -{ - machine::add("SPEECH", "SAM"); -} \ No newline at end of file diff --git a/src/base/FaustEngine.hxx b/src/base/FaustEngine.hxx deleted file mode 100644 index 4f019bf..0000000 --- a/src/base/FaustEngine.hxx +++ /dev/null @@ -1,156 +0,0 @@ -#include "machine.h" -#include "stmlib/dsp/dsp.h" -#include "stmlib/dsp/units.h" - -struct dsp -{ -}; - -struct Meta -{ - void declare(const char *key, const char *value) - { - } -}; - -struct Soundfile -{ -}; - -struct UI -{ - virtual void openTabBox(const char *label){}; - virtual void openVerticalBox(const char *title) = 0; - virtual void openHorizontalBox(const char *title) = 0; - virtual void closeBox() = 0; - - virtual void declare(float *zone, const char *key, const char *val) = 0; - virtual void addNumEntry(const char *label, float *zone, float init, float min, float max, float step) = 0; - virtual void addHorizontalSlider(const char *label, float *zone, float init, float min, float max, float step) = 0; - virtual void addVerticalSlider(const char *label, float *zone, float init, float min, float max, float step) = 0; - virtual void addButton(const char *label, float *zone) = 0; - virtual void addCheckButton(const char *label, float *zone) = 0; - - // -- passive widgets - - virtual void addHorizontalBargraph(const char *label, float *zone, float min, float max){}; - virtual void addVerticalBargraph(const char *label, float *zone, float min, float max){}; - - // -- soundfiles - - virtual void addSoundfile(const char *label, const char *filename, Soundfile **sf_zone){}; -}; - -using namespace machine; - -template -class FaustEngine : public machine::Engine, UI -{ - static_assert(std::is_base_of::value, "T must derive from dsp"); - - float bufferL[FRAME_BUFFER_SIZE]; - float bufferR[FRAME_BUFFER_SIZE]; - - float _pitch = 0.5f; - - T *_faust = nullptr; - - float *_trigger = nullptr; - - void openVerticalBox(const char *title) override - { - } - void openHorizontalBox(const char *title) override - { - } - void closeBox() override - { - } - void declare(float *zone, const char *key, const char *val) override - { - } - - void addButton(const char *label, float *zone) override - { - if (_trigger == nullptr) - _trigger = zone; - } - - void addNumEntry(const char *label, float *zone, float init, float min, float max, float step) override - { - } - - void addCheckButton(const char *label, float *zone) override - { - addHorizontalSlider(label, zone, 0, 0, 1, 1); - } - - void addVerticalSlider(const char *label, float *zone, float init, float min, float max, float step) override - { - addHorizontalSlider(label, zone, init, min, max, step); - } - - void addHorizontalSlider(const char *label, float *zone, float init, float min, float max, float step) override - { - for (size_t i = 0; i < LEN_OF(param); i++) - { - if (param[i].name == nullptr) - { - param[i].init(label, zone, init, min, max); - return; - } - } - } - -public: - FaustEngine() : machine::Engine(engine_props) - { - // static_assert(sizeof(T) < 150000, ""); - if (void *mem = machine::malloc(sizeof(T))) - { - _faust = new (mem) T(); - _faust->init(48000); - _faust->buildUserInterface(this); - } - } - - ~FaustEngine() override - { - machine::mfree(_faust); - } - - float base_frequency = 440.f; - float base_pitch = 69.f; - - float note_to_frequency(float note) - { - return base_frequency * powf(2.f, (note - base_pitch) / 12.f); - } - - void process(const machine::ControlFrame &frame, OutputFrame &of) override - { - if(_faust == nullptr) - return; - - if (_trigger != nullptr) - *_trigger = frame.trigger ? 1.f : 0.f; - - // auto note = (float)frame.midi.key + _pitch * 12.f + (frame.midi.pitch / 128) + frame.cv_voltage * 12; - // auto f = note_to_frequency(note + 12); - - float *outputs[] = {bufferL, bufferR}; - float *ins[] = {machine::get_aux(AUX_L), machine::get_aux(AUX_R)}; - - _faust->compute(FRAME_BUFFER_SIZE, &ins[0], &outputs[0]); - - of.out = bufferL; - - if (_faust->getNumOutputs() > 1) - of.aux = bufferR; - } - - void display() override - { - gfx::drawEngine(this, _faust ? nullptr : machine::OUT_OF_MEMORY); - } -}; \ No newline at end of file diff --git a/src/base/HiHatsEngine.hxx b/src/base/HiHatsEngine.hxx deleted file mode 100644 index 973d7e6..0000000 --- a/src/base/HiHatsEngine.hxx +++ /dev/null @@ -1,105 +0,0 @@ -// 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. -// - -#pragma once - -#include "machine.h" -#include "braids/envelope.h" - -using namespace machine; - -struct HiHatsEngine : public Engine -{ - Engine *_oh = nullptr; - Engine *_ch = nullptr; - - float _pitch = 0; - float _ch_vol = 0.75f; - - braids::Envelope _ch_env; - braids::Envelope _oh_env; - uint8_t _ch_end; - uint8_t _oh_end; - bool _oh_mute = false; - float bufferOut[machine::FRAME_BUFFER_SIZE]; - -public: - HiHatsEngine() : Engine(TRIGGER_INPUT | ACCENT_INPUT | VOCT_INPUT) - { - _ch_env.Init(); - _oh_env.Init(); - - param[0].init("", &_pitch); - param[1].init("CH-Lev", &_ch_vol); - param[2].init("CH-Dec", &_ch_end, 32, 32, 127); - param[2].step.i = 8; - param[3].init("OH-Dec", &_oh_end, 80, 32, 127); - param[3].step.i = 8; - } - - bool init() override - { - _ch->io = this->io; - _oh->io = this->io; - - return _ch->init() && _oh->init(); - } - - void process(const ControlFrame &frame_, OutputFrame &of) override - { - ControlFrame frame; - memcpy(&frame, &frame_, sizeof(ControlFrame)); - - frame.trigger = frame.trigger && !frame.accent; - - if (frame.trigger) - _ch_env.Trigger(braids::ENV_SEGMENT_ATTACK); - - _ch_env.Update(0, _ch_end); - - OutputFrame ch_of; - _ch->process(frame, ch_of); - - _oh_mute = frame.trigger; - - frame.trigger = frame.accent; - - if (frame.trigger) - _oh_env.Trigger(braids::ENV_SEGMENT_ATTACK); - - _oh_env.Update(0, _oh_mute ? 0 : _oh_end); - - OutputFrame oh_of; - _oh->process(frame, oh_of); - - auto ch_ad = (float)_ch_env.Render() / UINT16_MAX; - auto oh_ad = (float)_oh_env.Render() / UINT16_MAX; - - for (int i = 0; i < FRAME_BUFFER_SIZE; i++) - bufferOut[i] = (float)((ch_of.out[i] * _ch_vol * ch_ad) + (oh_of.out[i] * oh_ad)); - - of.push(bufferOut, LEN_OF(bufferOut)); - } -}; \ No newline at end of file diff --git a/src/base/SampleEngine.hxx b/src/base/SampleEngine.hxx deleted file mode 100644 index ad794d5..0000000 --- a/src/base/SampleEngine.hxx +++ /dev/null @@ -1,224 +0,0 @@ -// 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. -// - -#pragma once -#include "machine.h" -#include "stmlib/dsp/dsp.h" -#include "stmlib/dsp/units.h" - -struct SampleEngine : public machine::Engine -{ - float i = 1; // 0=plays the sample on init, 1=plays the sample next trig - float start = 1; - float end = 1; - - uint8_t selection = 0; - float pitch_coarse = 0; - - struct sample_spec - { - const char *name; - int len; - int sample_rate; - const void *data; - int addr_shift; - virtual float get_float(int index) const = 0; - }; - - const sample_spec *ptr = nullptr; - float default_inc; - float inc; - - float buffer[machine::FRAME_BUFFER_SIZE]; - - inline float Interpolate(const sample_spec &table, float index) - { - index *= table.len; - MAKE_INTEGRAL_FRACTIONAL(index) - float a = table.get_float(index_integral); - float b = table.get_float(index_integral + 1); - return a + (b - a) * index_fractional; - } - - inline float InterpolateHermite(const sample_spec &table, float index) - { - index *= table.len; - MAKE_INTEGRAL_FRACTIONAL(index) - const float xm1 = table.get_float(index_integral - 1); - const float x0 = table.get_float(index_integral + 0); - const float x1 = table.get_float(index_integral + 1); - const float x2 = table.get_float(index_integral + 2); - const float c = (x1 - xm1) * 0.5f; - const float v = x0 - x1; - const float w = c + v; - const float a = w + v + (x2 - x0) * 0.5f; - const float b_neg = w + a; - const float f = index_fractional; - return (((a * f) - b_neg) * f + c) * f + x0; - } - -public: - int loop = 0; // 1 = knight rider, 2 infinite - - uint8_t rtrg = 0; - uint8_t rtim = 0; - uint8_t rtrg2 = 0; - uint32_t trg_next = 0; - - SampleEngine() : machine::Engine() - {} - - void setup(const sample_spec *samples, int select, int count) - { - ptr = samples; - param[0].init("Pitch", &pitch_coarse, pitch_coarse, -.5f, .5f); - param[1].init_presets(ptr[select].name, &selection, select, 0, count - 1); - param[1].value_changed = [&](){ - param[1].name = ptr[selection].name; - }; - param[2].init("Start", &start, 0); - param[3].init("End", &end, 1); - // param[4].init("RTRG", &rtrg, 0, 0, 16); - // param[5].init("RTIM", &rtim, 2, 1, 64); - // param[5].print_value = [&](char *tmp) - // { - // sprintf(tmp, "%c%d/32", param[5].flags & machine::Parameter::IS_SELECTED ? '>' : ' ', rtim); - // }; - } - - void process(const machine::ControlFrame &frame, machine::OutputFrame &of) override - { - auto &smpl = ptr[selection]; - - this->default_inc = 1.0f / smpl.len * (smpl.sample_rate / (float)machine::SAMPLE_RATE); - - this->default_inc *= stmlib::SemitonesToRatio(frame.qz_voltage(this->io, 0.f) * 12); - - float pitch_fine = 0; - this->inc = (this->inc < 0 ? -1.f : 1.f) * - (default_inc + (default_inc * pitch_fine * 0.5f) + (default_inc * pitch_coarse * 2.f)); - - auto p = buffer; - auto size = machine::FRAME_BUFFER_SIZE; - - if (frame.trigger) - { - i = start; - } - - // if (frame.trigger || (rtrg2 > 0 && trg_next == frame.t)) - // { - // if (frame.trigger) - // rtrg2 = rtrg + 1; - - // auto bpm = machine::get_bpm() / (25.f / 24); - // auto t_per_beat = 60.f / bpm; - // auto t_32 = t_per_beat / 32.f; - // --rtrg2; - // static constexpr float t_per_frame = 1.f / (machine::SAMPLE_RATE / machine::FRAME_BUFFER_SIZE); - // trg_next = frame.t + (t_32 / t_per_frame * rtim); - // i = start; - // } - - float s = std::min(start, end); - float e = std::max(start, end); - - while (size--) - { - *p++ = s <= i && i < e ? InterpolateHermite(smpl, i) : 0; - i += this->start < this->end ? inc : -inc; - } - - if (loop == 0) - { - - } - else if (loop == 1) - { - if (i < s || i > e) - inc = -inc; - } - else if (loop == 2) - { - if (i < s) - i += (e-s); - else if (i > e) - i -= (e-s); - } - - of.out = buffer; - } -}; - -template -struct tsample_spec : SampleEngine::sample_spec -{ - virtual float get_float(int index) const; - - tsample_spec(const char *name, const T *data, size_t len, uint16_t sample_rate, int custom) - { - this->data = data; - this->addr_shift = custom; - this->name = name; - this->len = len; - this->sample_rate = sample_rate; - } -}; - -struct Am6070sample : tsample_spec -{ - // https://electricdruid.net/experiments-with-variable-rate-drum-sample-playback/ - // https://electricdruid.net/wp-content/uploads/2018/06/AM6070-uLaw-DAC.pdf - - // 12-bit antilog as per Am6070 datasheet - // for (int i = 0; i < 128; i++) - // antilog[i] = (int16_t)((2 * powf(2.0, i >> 4) * ((i & 15) + 16.5) - 16.5)); - - float get_float(int index) const override - { - static const int16_t antilog[128] = { - 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, - 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 86, 89, 93, - 99, 107, 115, 123, 131, 139, 147, 155, 163, 171, 179, 187, 195, 203, 211, 219, - 231, 247, 263, 279, 295, 311, 327, 343, 359, 375, 391, 407, 423, 439, 455, 471, - 495, 527, 559, 591, 623, 655, 687, 719, 751, 783, 815, 847, 879, 911, 943, 975, - 1023, 1087, 1151, 1215, 1279, 1343, 1407, 1471, 1535, 1599, 1663, 1727, 1791, 1855, 1919, 1983, - 2079, 2207, 2335, 2463, 2591, 2719, 2847, 2975, 3103, 3231, 3359, 3487, 3615, 3743, 3871, 3999, - 4191, 4447, 4703, 4959, 5215, 5471, 5727, 5903, 6239, 6495, 6751, 7007, 7263, 7519, 7775, 8031}; - - if (index < this->len) - { - auto ix = reinterpret_cast(this->data)[index]; - return (float)((ix & 0x80) ? -antilog[ix & 0x7F] : antilog[ix]) / INT16_MAX * this->addr_shift; - } - else - return 0; - } - - Am6070sample(const char *name, const uint8_t *data, size_t len, uint16_t sample_rate, int custom) - : tsample_spec(name, data, len, sample_rate, custom) - { - } -}; \ No newline at end of file diff --git a/src/braids.cxx b/src/braids.cxx deleted file mode 100644 index 33be7f8..0000000 --- a/src/braids.cxx +++ /dev/null @@ -1,165 +0,0 @@ -#include "stmlib/stmlib.h" -#include "stmlib/dsp/dsp.h" -#include "machine.h" - -#define private public -#include "braids/macro_oscillator.h" -#include "braids/envelope.h" -#include "braids/settings.h" -#include "braids/vco_jitter_source.h" - -using namespace braids; -using namespace machine; - -struct BraidsEngine : public Engine -{ - MacroOscillator osc1; - MacroOscillator osc2; - Envelope envelope; - VcoJitterSource jitter_source; - - int16_t audio_samples[FRAME_BUFFER_SIZE]; - uint8_t sync_samples[FRAME_BUFFER_SIZE]; - - float _pitch; - uint8_t _shape; - uint16_t _timbre; - uint16_t _color; - uint16_t _attack; - uint16_t _decay; - - float buffer[FRAME_BUFFER_SIZE]; - float bufferR[FRAME_BUFFER_SIZE]; - - BraidsEngine() : Engine(TRIGGER_INPUT | VOCT_INPUT | STEREOLIZED) - { - settings.Init(); - osc1.Init(); - osc2.Init(); - jitter_source.Init(); - envelope.Init(); - - memset(audio_samples, 0, sizeof(audio_samples)); - memset(sync_samples, 0, sizeof(sync_samples)); - - // 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); - - param[0].init_v_oct("Freq", &_pitch); - param[1].init_presets("Shape", &_shape, braids::MACRO_OSC_SHAPE_CSAW, braids::MACRO_OSC_SHAPE_CSAW, braids::MACRO_OSC_SHAPE_LAST - 1); - param[1].value_changed = [&]() { - param[1].name = braids::settings.metadata(braids::Setting::SETTING_OSCILLATOR_SHAPE).strings[_shape]; - }; - param[2].init("Timbre", &_timbre, INT16_MAX); - param[3].init("Color", &_color, INT16_MAX); - param[4].init("Decay", &_decay, INT16_MAX); - param[5].init("Attack", &_attack, 0); - } - - void process(const ControlFrame &frame, OutputFrame &of) override - { - envelope.Update(_attack / 512, _decay / 512); - - if (frame.trigger) - { - osc1.Strike(); - osc2.Strike(); - envelope.Trigger(braids::ENV_SEGMENT_ATTACK); - } - - if (frame.gate) - { - // Not working witch Attack > 0 - // envelope.Trigger(braids::ENV_SEGMENT_DECAY); - } - - uint32_t ad_value = envelope.Render(); - - float pitchV = frame.qz_voltage(this->io, (_pitch - 1)); - int32_t pitch = (pitchV * 12.f + machine::DEFAULT_NOTE + 24) * 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 (!this->io->tr) - gain = _decay; // No Trigger patched - use Decay as VCA... - - if ((frame.t % 12) != 0) - osc1.set_shape((braids::MacroOscillatorShape)_shape); - else if ((frame.t % 12) != 6) - osc2.set_shape((braids::MacroOscillatorShape)_shape); - - osc1.set_parameters(_timbre >> 1, _color >> 1); - osc1.set_pitch(pitch + settings.pitch_transposition()); - 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; - - of.push(audio_samples, LEN_OF(audio_samples)); - - const float f = (float)this->io->stereo / 255.f; - uint8_t stereo = f * f * f * 255; - if (io->is_stereo() && stereo > 0) // Stereo - { - 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); - 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; - - of.push(audio_samples, LEN_OF(audio_samples)); - } - } - - void display() override - { - if (!this->io->tr) - { - param[4].name = "Level"; - param[5].name = nullptr; - } - else if (_decay < UINT16_MAX) - { - param[4].name = "Decay"; - param[5].name = "Attack"; - } - else - { - param[4].name = "VCA-off"; - param[5].name = nullptr; - } - - gfx::drawEngine(this); - } -}; - -void init_braids() -{ - machine::add(M_OSC, "Waveforms"); -} - -MACHINE_INIT(init_braids); \ No newline at end of file diff --git a/src/build.py b/src/build.py new file mode 100644 index 0000000..a32d2e4 --- /dev/null +++ b/src/build.py @@ -0,0 +1,150 @@ +from SCons.Script import DefaultEnvironment +import subprocess +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 +import os, json, io + +def udynlink_size(file): + with open(file, "rb") as f: + f.read(4) + l = int.from_bytes(f.read(2), byteorder='little')#num_lot + r = int.from_bytes(f.read(2), byteorder='little'); #num_rels + a = int.from_bytes(f.read(4), byteorder='little'); #symt_size + b = int.from_bytes(f.read(4), byteorder='little'); #code_size + c = int.from_bytes(f.read(4), byteorder='little'); #data_size + d = int.from_bytes(f.read(4), byteorder='little'); #bss_size + h = 24 + (r * 8) + a + return(h + b + c) + +def make_engines_hex(apps_json, ih = intelhex.IntelHex(), offset= 0): + + print(apps_json) + if not os.path.exists(apps_json): + print(apps_json, "not found!") + else: + with open(apps_json) as f: + apps = json.load(f) + 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) + print("0x%x" % offset, bin_file, bin_size, udynlink_size(bin_file) % 4) + ih.loadbin(bin_file,offset=offset) + offset += bin_size + offset += 4 - (offset % 4) + 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.Append( + LINKFLAGS=[ + "-specs=nano.specs", + "-specs=nosys.specs", + ] +) + +midi_out = None +midi_in = None + +try: + for mo in mido.get_output_names(): + if "S&C" in mo: + midi_out = mido.open_output(mo) + break + + for mi in mido.get_input_names(): + if "S&C" 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(1/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") + ahx = make_engines_hex(apps_json) + program_path = env.GetBuildPath("$PROJECT_DIR/.pio/build/$PIOENV/engines.hex") + ahx.tofile(program_path, format='hex') + loader_sha = env.GetBuildPath("$PROJECT_DIR/.pio/build/$PIOENV/loader.sha") + with open(loader_sha, "w") as f: + f.write(env.GetProjectOption("squares_and_circles_loader")) + print(program_path, len(ahx)) + +def upload_hex(source, target, env): + if midi_out == None: + exit(-1) + + print(midi_in) + print(midi_out) + + 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)) + + exit(0) + +env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex", post_program_action) +env.AddPreAction("upload", upload_hex) \ No newline at end of file diff --git a/src/claps.cxx b/src/claps.cxx deleted file mode 100644 index 95a882e..0000000 --- a/src/claps.cxx +++ /dev/null @@ -1,279 +0,0 @@ -// 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 "machine.h" -#include "drumsynth/drumsynth.h" -#include "drumsynth/drumsynth_claps.h" -#include "misc/noise.hxx" - -using namespace machine; - -class ClapsEngine : public Engine -{ -private: - float tmp[FRAME_BUFFER_SIZE]; - float tmp2[FRAME_BUFFER_SIZE]; - float buffer[FRAME_BUFFER_SIZE]; - float bufferAux[FRAME_BUFFER_SIZE]; - static constexpr size_t n = 8; - - DrumSynth _instA = nullptr; - DrumSynth _instB = nullptr; - - float pitch = 1.f; - float stereo = 0.5f; - float stretch = 1.f; - - DrumModel inst[32] = {}; - const size_t inst_count; - uint8_t inst_selection = 0; - - DrumModel _cur_inst = {}; - bool _reload_inst = true; - WhiteNoise r; - uint32_t seed = 0; - std::pair seeds[7] = { - {0x6d17ceb4, 1.f}, - {0x73623629, 1.f}, - {0x23cb4e73, 0.5f}, - {0x73C23C29, 0.5f}, - {0x42D1EC10, 1.3f}, - {0x5EFF9F17, 1.3f}, - {0x082087A1, 1.3f}, - }; - -public: - ClapsEngine(const uint8_t *packed_drumKit) : Engine(TRIGGER_INPUT), - inst_count(packed_drumKit[0]) - { - // unpack - const uint8_t *p = packed_drumKit; - p+=4; - for (size_t i = 0; i < inst_count; i++) - { - inst[i].name = reinterpret_cast(p); - p += 12; - inst[i].n = p[0]; - p+=4; - inst[i].part = reinterpret_cast(p); - p += inst[i].n * sizeof(PartArgs); - } - - param[0].init("Color", &pitch, pitch, 0.5f, 1.5f); - param[1].init_presets("Clap", &inst_selection, 0, 0, inst_count + LEN_OF(seeds) - 1); - param[1].value_changed = [&]() - { - _reload_inst = true; - - int n = inst_selection - inst_count; - if (n >= 0 && n < (int)LEN_OF(seeds)) - r.seed = seed = seeds[n].first; - else - seed = r.seed; - }; - param[1].print_value = [&](char *tmp) - { - if (inst_selection < 2) - sprintf(tmp, ">%s", inst[inst_selection].name); - else if (inst_selection < inst_count) - sprintf(tmp, ">Clap%03X", inst_selection); - else - sprintf(tmp, ">%X", (unsigned int)seed); - }; - param[2].init("Decay", &stretch, stretch, 0.1f, 2.0f); - param[3].init("Stereo", &stereo, stereo); - // param[0].init("Crispy", &crispy, crispy, -1.1f, 1.1f); - // param[1].init("Decay", &decay, decay, 0, 2.f); - // TODO: BitCrusher + Filter + Distortion - - load_instrument(inst_selection); - } - - ~ClapsEngine() override - { - free_instrument(); - machine::mfree(_instA); - machine::mfree(_instB); - } - - void free_instrument() - { - for (size_t i = 0; i < inst_count; i++) - if (_cur_inst.part == inst[i].part) - _cur_inst.part = nullptr; - - if (_cur_inst.part != nullptr) - machine::mfree((void *)_cur_inst.part); - } - - void load_instrument(uint8_t num) - { - _reload_inst = false; - - free_instrument(); - - if (inst_selection < inst_count) - _cur_inst = inst[num]; - else - { - seed = r.seed; - - float a = 1.f; - for (auto &it : seeds) - if (it.first == seed) - a = it.second; - - auto partArgs = (PartArgs *)machine::malloc(_cur_inst.n * sizeof(PartArgs)); - for (size_t i = 0; i < _cur_inst.n; i++) - { - size_t n = inst_count; - DrumModel in = inst[r.next() % n]; - partArgs[i] = in.part[r.next() % in.n]; - - in = inst[r.next() % n]; - auto & = in.part[r.next() % in.n].osc_amp; - if (amp.n > 0) - partArgs[i].osc_amp = amp; - - in = inst[r.next() % n]; - partArgs[i].osc_pitch = in.part[r.next() % in.n].osc_pitch; - - in = inst[r.next() % n]; - auto &vca = in.part[r.next() % in.n].vca; - if (vca.n > 0) - partArgs[i].vca = vca; - - in = inst[r.next() % n]; - partArgs[i].bq1 = in.part[r.next() % in.n].bq1; - - in = inst[r.next() % n]; - partArgs[i].bq2 = in.part[r.next() % in.n].bq2; - partArgs[i].level *= a; - } - - _cur_inst.part = partArgs; - } - - machine::mfree(_instA); - machine::mfree(_instB); - _instA = drum_synth_init(&_cur_inst, machine::malloc); - _instB = drum_synth_init(&_cur_inst, machine::malloc); - } - - uint32_t t = UINT32_MAX; - - void process(const ControlFrame &frame, OutputFrame &of) override - { - memset(buffer, 0, sizeof(buffer)); - memset(bufferAux, 0, sizeof(bufferAux)); - - if (frame.trigger) - { - if (_reload_inst) - load_instrument(inst_selection); - - t = 0; - - drum_synth_reset(_instA); - drum_synth_reset(_instB); - } - - if (t < UINT32_MAX) - { - DrumParams params = { - t : t, - attack : 0, - decay : stretch - }; - - float f = pitch; // powf(2.f, (frame.qz_voltage(this->io, 0))); - float a = stereo; - float b = 1.f - a; - - for (size_t k = 0; k < _cur_inst.n; k++) - { - if (stereo > 0.01f && _cur_inst.part[k].osc.type >= OSC_METALLIC) - { - drum_synth_process_frame(_instA, k, (f - (f * 0.01f * stereo)), ¶ms, tmp, machine::FRAME_BUFFER_SIZE); - drum_synth_process_frame(_instB, k, (f + (f * 0.01f * stereo)), ¶ms, tmp2, machine::FRAME_BUFFER_SIZE); - if (_cur_inst.part[k].osc.type == OSC_METALLIC) - { - for (int i = 0; i < machine::FRAME_BUFFER_SIZE; i++) - { - buffer[i] += tmp[i]; - bufferAux[i] += tmp2[i]; - } - } - else - for (int i = 0; i < machine::FRAME_BUFFER_SIZE; i++) - { - buffer[i] += tmp[i]; - bufferAux[i] += tmp[i] * b + tmp2[i] * a; - } - } - else - { - drum_synth_process_frame(_instA, k, f, ¶ms, tmp, machine::FRAME_BUFFER_SIZE); - for (int i = 0; i < machine::FRAME_BUFFER_SIZE; i++) - { - buffer[i] += tmp[i]; - bufferAux[i] += tmp[i]; - } - } - // bufferAux[i] += p._vca.value() * p._amp.value() * 0.99f; - } - - t += machine::FRAME_BUFFER_SIZE; - } - - of.out = buffer; - of.aux = bufferAux; - } -}; - -// #include "base/SampleEngine.hxx" -// #include "claps/cp909.h" -// #include "claps/cp808.h" - -// struct TR909_CP : public SampleEngine -// { -// const tsample_spec _sound = {"", (const int16_t *)cp909_raw, cp909_raw_len / 2, 44100, 0}; - -// TR909_CP() : SampleEngine(&_sound, 0, 1) {} -// }; - -// struct TR808_CP : public SampleEngine -// { -// const tsample_spec _sound = {"", (const int16_t *)cp808_raw, cp808_raw_len / 2, 44100, 0}; - -// TR808_CP() : SampleEngine(&_sound, 0, 1) {} -// }; - -void init_claps() -{ - machine::add(machine::DRUM, "Claps", drum_synth_claps); -} - -MACHINE_INIT(init_claps); \ No newline at end of file diff --git a/src/cv_peaks.cxx b/src/cv_peaks.cxx deleted file mode 100644 index 6c10365..0000000 --- a/src/cv_peaks.cxx +++ /dev/null @@ -1,100 +0,0 @@ -#include "stmlib/stmlib.h" -#include "machine.h" -#include "peaks/gate_processor.h" -#include "peaks/modulations/bouncing_ball.h" -#include "peaks/modulations/mini_sequencer.h" -#include "peaks/modulations/multistage_envelope.h" -#include "peaks/number_station/number_station.h" -#include "peaks/pulse_processor/pulse_shaper.h" -#include "peaks/pulse_processor/pulse_randomizer.h" -#include "peaks/gate_processor.h" - -namespace gfx -{ - void drawEngineWithScope(machine::Engine *engine, int8_t scope[128], int i, int y); - void push_scope(int8_t scope[128], uint8_t &i, int8_t x); -} - -using namespace machine; - -template -struct PeaksCVEngine : public Engine -{ - int8_t scope[128] = {}; - float y = 0; - uint8_t i = 0; - - T _processor; - - uint16_t params_[4]; - - peaks::GateFlags flags[FRAME_BUFFER_SIZE]; - int16_t buffer[FRAME_BUFFER_SIZE]; - - PeaksCVEngine(uint16_t p1 = UINT16_MAX / 2, - uint16_t p2 = UINT16_MAX / 2, - uint16_t p3 = UINT16_MAX / 2, - uint16_t p4 = UINT16_MAX / 2, - const char *param1 = nullptr, - const char *param2 = nullptr, - const char *param3 = nullptr, - const char *param4 = nullptr) : Engine(engine_props) - { - memset(&_processor, 0, sizeof(T)); - _processor.Init(); - std::fill(&flags[0], &flags[FRAME_BUFFER_SIZE], peaks::GATE_FLAG_LOW); - - int P1 = 0; - int P2 = 1; - int P3 = 2; - int P4 = 3; - - param[0].init(param1, ¶ms_[P1], p1); - param[1].init(param2, ¶ms_[P2], p2); - - param[2].init(param3, ¶ms_[P3], p3); - param[3].init(param4, ¶ms_[P4], p4); - } - - void process(const ControlFrame &frame, OutputFrame &of) override - { - _processor.Configure(params_, peaks::CONTROL_MODE_FULL); - - if (frame.trigger) - { - flags[0] = peaks::GATE_FLAG_RISING; - std::fill(&flags[1], &flags[FRAME_BUFFER_SIZE], peaks::GATE_FLAG_HIGH); - } - else if (frame.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); - - of.push(buffer, LEN_OF(buffer)); - - if ((frame.t % 50) == 0) - { - gfx::push_scope(scope, i, y); - y = 0; - } - else - y = std::max(y, (float)buffer[0] / INT16_MAX * 16); - } - - void display() override - { - gfx::drawEngineWithScope(this, scope, i, 56); - } -}; - -void init_cv_peaks() -{ - add>(CV, "EnvGen_ADSR", 0, INT16_MAX, INT16_MAX, INT16_MAX, "Attack", "Decay", "Sustain", "Release"); -} \ No newline at end of file diff --git a/src/dxfm.cxx b/src/dxfm.cxx deleted file mode 100644 index 580b18d..0000000 --- a/src/dxfm.cxx +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (C)2023 - E.Heidt - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "machine.h" -#include "stmlib/utils/ring_buffer.h" -#include "misc/dspinst.h" - -#include "msfa/controllers.h" -#include "msfa/dx7note.h" -#include "msfa/lfo.h" -#include "msfa/synth.h" -#include "msfa/fm_core.h" - -#include "msfa/synth.h" -#include "msfa/exp2.h" -#include "msfa/sin.h" -#include "msfa/freqlut.h" -#include "msfa/porta.h" -#include "msfa/patch.h" - -#include -#include - -#include "plaits/resources.h" - -using namespace machine; - -struct DxFMEngine : public MidiEngine -{ - struct dxfm - { - int note = 0; - int key_down = 0; - Lfo lfo; - FmCore fm_core; - Dx7Note dx7_note; - stmlib::RingBuffer buffer; - } voices[2]; - Controllers controllers; - - float _pitch; - uint8_t _prog; - float _hold; - float _rate; - - char patch[128] = {// MARIMBA - 0x00, 0x3f, 0x37, 0x00, 0x4e, 0x4e, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x38, 0x08, 0x63, 0x08, 0x0d, 0x63, 0x4b, 0x00, 0x08, 0x52, 0x30, 0x00, - 0x00, 0x36, 0x00, 0x2e, 0x00, 0x38, 0x08, 0x5d, 0x00, 0x32, 0x63, 0x4b, - 0x00, 0x52, 0x52, 0x30, 0x00, 0x00, 0x36, 0x00, 0x2e, 0x00, 0x38, 0x08, - 0x55, 0x0a, 0x00, 0x5f, 0x21, 0x31, 0x29, 0x63, 0x5c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3b, 0x04, 0x63, 0x00, 0x00, 0x63, 0x48, 0x00, 0x00, - 0x52, 0x30, 0x00, 0x00, 0x36, 0x00, 0x2e, 0x00, 0x38, 0x08, 0x60, 0x06, - 0x00, 0x5f, 0x28, 0x31, 0x37, 0x63, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3b, 0x00, 0x5f, 0x00, 0x00, 0x5e, 0x43, 0x5f, 0x3c, 0x32, 0x32, - 0x32, 0x32, 0x06, 0x08, 0x23, 0x00, 0x00, 0x00, 0x31, 0x18, 0x4d, 0x41, - 0x52, 0x49, 0x4d, 0x42, 0x41, 0x20, 0x20, 0x20}; - - uint8_t data[156]; - char patch_name[12]; - -#define OP_ENV_RATE(op, i) data[op * 21 + i] -#define OP_ENV_LEVEL(op, i) data[op * 21 + 4 + i] -#define OP_kbd_lev_scl_brk_pt(op) data[op * 21 + 8] -#define OP_kbd_lev_scl_lft_depth(op) data[op * 21 + 9] -#define OP_kbd_lev_scl_rht_depth(op) data[op * 21 + 10] -#define OP_kbd_lev_scl_lft_curve(op) data[op * 21 + 11] -#define OP_kbd_lev_scl_rht_curve(op) data[op * 21 + 12] -#define OP_kbd_rate_scaling(op) data[op * 21 + 13] -#define OP_amp_mod_sensitivity(op) data[op * 21 + 14] -#define OP_key_vel_sensitivity(op) data[op * 21 + 15] -#define OP_output_level(op) data[op * 21 + 16] -#define OP_osc_mode(op) data[op * 21 + 17] -#define OP_osc_freq_coarse(op) data[op * 21 + 18] -#define OP_osc_freq_fine(op) data[op * 21 + 19] -#define OP_osc_detune(op) data[op * 21 + 20] -#define PE_rate(i) data[6 * 21 + i] -#define PE_level(i) data[6 * 21 + 4 + i] -#define ALGORITHM() data[6 * 21 + 8] -#define FEEDBACK() data[6 * 21 + 9] -#define OSC_SYNC() data[6 * 21 + 10] -#define LFO_RATE() data[(6 * 21 + 11)] -#define LFO_DELAY() data[6 * 21 + 12] -#define LFO_PITCH_MOD_DEPTH() data[6 * 21 + 13] -#define LFO_AMP_MOD_DEPTH() data[6 * 21 + 14] -#define LFO_SYNC() data[6 * 21 + 15] -#define LFO_WAVEFORM() data[6 * 21 + 16] -#define PITCH_MOD_SENSITIVITY() data[6 * 21 + 17] -#define TRANSPOSE() data[6 * 21 + 18] -#define NAME() (const char *)&data[6 * 21 + 19] - - void initControllers() - { - controllers.values_[kControllerPitch] = 0x2000; - controllers.values_[kControllerPitchRange] = 0; - controllers.values_[kControllerPitchStep] = 0; - - controllers.modwheel_cc = 0; - controllers.foot_cc = 0; - controllers.breath_cc = 0; - controllers.aftertouch_cc = 0; - controllers.refresh(); - } - - dxfm *active_voice = nullptr; - dxfm *other_voice = nullptr; - - void applyRate(float rate) - { - for (int op = 0; op < 6; op++) - { - auto opData = &patch[op * 17]; - for (int j = 1; j < 4; j++) - { - auto v = min(opData[j] & 0x7f, 99); - OP_ENV_RATE(op, j) = min((int)(v * -rate), 99); - } - - // for (int j = 1; j < 4; j++) - // { - // auto v = min(opData[j + 4] & 0x7f, 99); - // if (_rate < 0) - // OP_ENV_LEVEL(op, j) = v - (99 - v) * -_rate; - // else - // OP_ENV_LEVEL(op, j) = v - v * -_rate; - // } - } - } - DxFMEngine(int bnkNum) : MidiEngine(MIDI_ENGINE | TRIGGER_INPUT | VOCT_INPUT | STEREOLIZED), _bnkNum(bnkNum) - { - Exp2::init(); - Tanh::init(); - Sin::init(); - - Freqlut::init(machine::SAMPLE_RATE); - Lfo::init(machine::SAMPLE_RATE); - PitchEnv::init(machine::SAMPLE_RATE); - Env::init_sr(machine::SAMPLE_RATE); - Porta::init_sr(machine::SAMPLE_RATE); - - initControllers(); - controllers.masterTune = 0; - controllers.opSwitch = 0x3f; // all operators - active_voice = &voices[0]; - other_voice = &voices[1]; - - param[0].init_v_oct("Freq", &_pitch); - - sprintf(patch_name, ">%.10s", NAME()); - param[1].init_presets(patch_name, &_prog, 0, 0, (_bnkNum < 0) ? 31 : 95); - param[1].value_changed = [&]() - { - loadPatch = true; - }; - param[2].init("Rate", &_rate, -1.0f, -1.5f, -0.5f); - param[2].value_changed = [&]() - { - applyRate(_rate); // * ((float)rand() / INT32_MAX * 0.1f)); - }; - param[3].init("Hold", &_hold, 0, 0, SAMPLE_RATE / FRAME_BUFFER_SIZE); - - UnpackPatch(patch, (char *)data); - loadDXPatch(0); - } - - const int _bnkNum = -1; - const char DXFM_PATCH[8] = {'D', 'X', 'F', 'M', 'S', 'Y', 'X', '0'}; - const uint8_t *sysexData = nullptr; - - void loadDXPatch(uint8_t prog) - { - if (_bnkNum < 0) - { - sysexData = machine::flash_read(DXFM_PATCH); - } - else - { - sysexData = plaits::fm_patches_table[0]; - } - - if (sysexData) - { - bool valid = false; - for (int i = 0; i < 128; i++) - valid |= sysexData[i] != 0 && sysexData[i] != 0xFF; - - if (valid) - { - memcpy(patch, (const char *)sysexData + (prog * 128), sizeof(patch)); - UnpackPatch(patch, (char *)data); - sprintf(patch_name, "%.10s", NAME()); - loadPatch = false; - _prog = prog; - return; - } - } - - _prog = 0; - return; - } - - void onMidiNote(uint8_t key, uint8_t velocity) override - { - // Not yet implemented... - } - void onMidiPitchbend(int16_t pitch) override - { - // Not yet implemented... - } - void onMidiCC(uint8_t ccc, uint8_t value) override - { - // Not yet implemented... - } - - char name[16]; - - void display() override - { - if (_bnkNum < 0 && sysexData == nullptr) - { - auto bak = param[0].name; - param[0].name = nullptr; - gfx::drawEngine(this); - param[0].name = bak; - - gfx::drawRect(4, 16, 120, 38); - gfx::drawRect(5, 17, 118, 36); - gfx::drawStringCenter(64, 26, "NO DXFM.SYX FOUND!", 1); - gfx::drawString(10, 38, "Please load a syx file", 0); - gfx::drawString(10, 38 + 7, " with the Webflasher! ", 0); - return; - } - - gfx::drawEngine(this); - } - - float bufferL[machine::FRAME_BUFFER_SIZE]; - float bufferR[machine::FRAME_BUFFER_SIZE]; - - uint8_t trig = 0; - bool loadPatch = true; - - void process(const ControlFrame &frame, OutputFrame &of) override - { - if (_bnkNum < 0 && _prog == 0) - { - return; - } - int velo = 127; - - if (frame.trigger) - { - trig |= 1; - } - else if (frame.gate) - { - // keep key down - } - else - { - for (auto &voice : voices) - if (voice.key_down > 1) - --voice.key_down; - } - - if (voices[0].buffer.readable() < N) - { - // see midinote_to_logfreq - float note = frame.qz_voltage(this->io, 2.f + _pitch) * 12.f + machine::DEFAULT_NOTE; - - if (loadPatch) - { - loadDXPatch(_prog); - loadPatch = false; - - for (auto &voice : voices) - { - voice.dx7_note.keyup(); - voice.lfo.reset(&LFO_RATE()); - voice.dx7_note.update(data, voice.note, velo); - } - } - - for (auto &voice : voices) - { - if ((trig & 1) && &voice == other_voice) - { - voice.key_down = 2 + _hold; - voice.note = note; - voice.lfo.keydown(); - voice.dx7_note.keyup(); - - float r = param[2].to_float(); - if (r < 0.5f) - velo = 64 + 64 * (r * 2); - - voice.dx7_note.init(data, voice.note, velo); - - if (OSC_SYNC()) - voice.dx7_note.oscSync(); - - trig = 0; - - // if (other_voice && active_voice->key_down) - // { - // voice.dx7_note.transferSignal(active_voice->dx7_note); - // voice.dx7_note.transferState(active_voice->dx7_note); - // } - - std::swap(active_voice, other_voice); - } - else if (voice.key_down == 1) - { - voice.key_down = 0; - voice.dx7_note.keyup(); - } - - int32_t lfovalue = voice.lfo.getsample(); - int32_t lfodelay = voice.lfo.getdelay(); - - auto p = voice.buffer.OverwritePtr(N); - memset(p, 0, sizeof(int32_t) * N); - - float diff_note = (note - voice.note) / 12.f; - controllers.masterTune = diff_note * (1 << 24); - voice.dx7_note.compute(p, &voice.fm_core, lfovalue, lfodelay, &controllers); - } - - trig = 0; - } - - memset(bufferL, 0, sizeof(bufferL)); - memset(bufferR, 0, sizeof(bufferL)); - - int v = 0; - float stereo = (1.f - 1.f / 256.f * this->io->stereo); - for (auto &voice : voices) - { - auto p = voice.buffer.ImmediateReadPtr(machine::FRAME_BUFFER_SIZE); - - if (v++ % 2 == 0) - { - for (int i = 0; i < machine::FRAME_BUFFER_SIZE; i++) - { - float s = (float)*p++ / INT32_MAX * 8; - bufferL[i] += s * stereo; - bufferR[i] += s; - } - } - else - { - for (int i = 0; i < machine::FRAME_BUFFER_SIZE; i++) - { - float s = (float)*p++ / INT32_MAX * 8; - bufferL[i] += s; - bufferR[i] += s * stereo; - } - } - } - - of.out = bufferL; - of.aux = bufferR; - } -}; - -void init_dxfm() -{ - machine::add(SYNTH, "DxFM", -1); - machine::add(SYNTH, "DxFM_BNK1-3", 0); -} - -MACHINE_INIT(init_dxfm); \ No newline at end of file diff --git a/src/fx_reverb.cxx b/src/fx_reverb.cxx deleted file mode 100644 index 6407daf..0000000 --- a/src/fx_reverb.cxx +++ /dev/null @@ -1,132 +0,0 @@ -// 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 "stmlib/stmlib.h" -#include "stmlib/dsp/filter.h" -#include "machine.h" -#include - -#include "clouds/dsp/fx/reverb.h" - -using namespace machine; - -struct CloudsReverb : public Engine -{ - float raw = 0; - float reverb_amount; - float feedback; - float gain; - - uint16_t buffer[16384]; - clouds::Reverb fx_; - - float bufferL[FRAME_BUFFER_SIZE]; - float bufferR[FRAME_BUFFER_SIZE]; - - CloudsReverb() : Engine(AUDIO_PROCESSOR) - { - raw = 1.f; - memset(buffer, 0, sizeof(buffer)); - fx_.Init(buffer); - - param[0].init("D/W", &raw, raw); - param[1].init("Reverb", &reverb_amount, 0.75f); - param[2].init("Damp", &feedback, 0.5f); - param[3].init("Gain", &gain, 1.f); - } - - void process(const ControlFrame &frame, OutputFrame &of) override - { - fx_.set_amount(reverb_amount * 0.54f); - fx_.set_diffusion(0.7f); - fx_.set_time(0.35f + 0.63f * reverb_amount); - fx_.set_input_gain(gain * 0.1f); // 0.1f); - fx_.set_lp(0.6f + 0.37f * feedback); - - float *ins[] = {machine::get_aux(AUX_L), machine::get_aux(AUX_R)}; - - for (int i = 0; i < FRAME_BUFFER_SIZE; i++) - { - bufferL[i] = ins[0][i]; - bufferR[i] = ins[1][i]; - } - - fx_.Process(bufferL, bufferR, FRAME_BUFFER_SIZE); - - for (int i = 0; i < FRAME_BUFFER_SIZE; ++i) - { - bufferL[i] = raw * bufferL[i] + (1 - raw) * ins[0][i]; - bufferR[i] = raw * bufferR[i] + (1 - raw) * ins[1][i]; - } - - of.out = bufferL; - of.aux = bufferR; - } -}; - -#include "clouds/dsp/fx/diffuser.h" - -struct CloudsDiffuser : public Engine -{ - float raw = 0; - clouds::Diffuser fx_; - uint16_t buffer[2048 + 1024]; - - float bufferL[FRAME_BUFFER_SIZE]; - float bufferR[FRAME_BUFFER_SIZE]; - - CloudsDiffuser() : Engine(AUDIO_PROCESSOR) - { - raw = 1.f; - fx_.Init(&buffer[0]); - param[0].init("Amount", &raw, raw); - } - - void process(const ControlFrame &frame, OutputFrame &of) override - { - fx_.set_amount(raw); - - float *ins[] = {machine::get_aux(AUX_L), machine::get_aux(AUX_R)}; - - for (int i = 0; i < FRAME_BUFFER_SIZE; i++) - { - bufferL[i] = ins[0][i]; - bufferR[i] = ins[1][i]; - } - - fx_.Process(bufferL, bufferR, FRAME_BUFFER_SIZE); - - of.out = bufferL; - of.aux = bufferR; - } -}; - -void init_reverb() -{ - machine::add(FX, "Reverb"); - //machine::add(FX, "Diffusor"); -} - -MACHINE_INIT(init_reverb); \ No newline at end of file diff --git a/src/fx_reverbSC.cxx b/src/fx_reverbSC.cxx deleted file mode 100644 index 9a70d5f..0000000 --- a/src/fx_reverbSC.cxx +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (C)2022 - 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 "stmlib/stmlib.h" -#include "stmlib/dsp/filter.h" -#include "machine.h" -#include - -extern "C" -{ -#include "soundpipe/revsc.h" -} - -using namespace machine; - -struct ReverbSC : public Engine -{ - sp_data sp_data_; - sp_revsc sp_revsc_; - static constexpr uint32_t AUX_SIZE = 107440; // sp_revsc_.aux.size - uint8_t *mem; - - float raw = 1.f; - float reverb_amount; - float feedback; - float gain; - - float bufferL[FRAME_BUFFER_SIZE]; - float bufferR[FRAME_BUFFER_SIZE]; - - ReverbSC() : Engine(AUDIO_PROCESSOR) - { - mem = (uint8_t *)machine::malloc(AUX_SIZE); - if (mem) - { - sp_data_.sr = machine::SAMPLE_RATE; - sp_data_.aux.ptr = &mem[0]; - sp_data_.aux.size = AUX_SIZE; - sp_revsc_init(&sp_data_, &sp_revsc_); - param[0].init("D/W", &raw, raw); - param[1].init("Feedback", &sp_revsc_.feedback, 0.97f, 0, 1); - param[2].init("LpFreq", &sp_revsc_.lpfreq, 10000, 0, machine::SAMPLE_RATE / 2); - } - } - - ~ReverbSC() override - { - machine::mfree(mem); - } - - void process(const ControlFrame &frame, OutputFrame &of) override - { - if (mem == nullptr) - return; - - float *ins[] = {machine::get_aux(AUX_L), machine::get_aux(AUX_R)}; - - for (int i = 0; i < FRAME_BUFFER_SIZE; ++i) - { - sp_revsc_compute(&sp_data_, &sp_revsc_, &ins[0][i], &ins[1][i], &bufferL[i], &bufferR[i]); - bufferL[i] = raw * bufferL[i] + (1 - raw) * ins[0][i]; - bufferR[i] = raw * bufferR[i] + (1 - raw) * ins[1][i]; - } - - of.out = bufferL; - of.aux = bufferR; - } - - void display() override - { - gfx::drawEngine(this, mem ? nullptr : machine::OUT_OF_MEMORY); - } -}; - -void init_reverbSC() -{ - machine::add(FX, "ReverbSC"); -} - -MACHINE_INIT(init_reverbSC); \ No newline at end of file diff --git a/src/main.cxx b/src/main.cxx index 9156bac..7d5f90d 100644 --- a/src/main.cxx +++ b/src/main.cxx @@ -1,99 +1,5 @@ -// 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 "machine.h" -#include "plaits/resources.h" - -#ifndef FLASHMEM -#include "pgmspace.h" -#endif - -#include "../app/DRUMS/Djembe.bin.h" -#include "../app/NOISE/NES.bin.h" -#include "../app/NOISE/808_squares.bin.h" -#include "../app/NOISE/WhitePink.bin.h" -#include "../app/FX/Rev-Dattorro.bin.h" -#include "../app/FX/Gated-Reverb.bin.h" -#include "../app/FX/Reverb-HP-LP.bin.h" -#include "../app//FX/Delay.bin.h" -#include "../app/SPEECH/SAM.bin.h" - -void init_engines(); - -void init_engines2() -{ -#undef MACHINE_INIT -#define MACHINE_INIT(init_fun) \ - void init_fun() __attribute__((weak)); \ - init_fun(); - - // machine::register_flash_blob("DXFMSYXA", plaits::fm_patches_table[0]); - // machine::register_flash_blob("DXFMSYXB", plaits::fm_patches_table[1]); - // machine::register_flash_blob("DXFMSYXC", plaits::fm_patches_table[2]); - - MACHINE_INIT(init_modulations); - MACHINE_INIT(init_quantizer); - - MACHINE_INIT(init_voltage); - machine::add(__NOISE_WhitePink_bin, __NOISE_WhitePink_bin_len); - machine::add(__NOISE_NES_bin, __NOISE_NES_bin_len); - machine::add(__NOISE_808_squares_bin, __NOISE_808_squares_bin_len); - MACHINE_INIT(init_midi_monitor); - MACHINE_INIT(init_midi_clock); - MACHINE_INIT(init_drums_peaks); - MACHINE_INIT(init_braids); - MACHINE_INIT(init_plaits); - MACHINE_INIT(init_tr909); - MACHINE_INIT(init_tr707); - - MACHINE_INIT(init_claps); - MACHINE_INIT(init_reverb); - MACHINE_INIT(init_reverbSC); - machine::add(__FX_Rev_Dattorro_bin, __FX_Rev_Dattorro_bin_len); - machine::add(__DRUMS_Djembe_bin, __DRUMS_Djembe_bin_len); - MACHINE_INIT(init_rings); - MACHINE_INIT(init_speech); - machine::add(__SPEECH_SAM_bin, __SPEECH_SAM_bin_len); - machine::add(__FX_Delay_bin, __FX_Delay_bin_len); - machine::add(__FX_Gated_Reverb_bin, __FX_Gated_Reverb_bin_len); - machine::add(__FX_Reverb_HP_LP_bin, __FX_Reverb_HP_LP_bin_len); - MACHINE_INIT(init_midi_polyVA) - MACHINE_INIT(init_dxfm); - MACHINE_INIT(init_open303); - MACHINE_INIT(init_aux); - MACHINE_INIT(init_juno60_chorus); - MACHINE_INIT(init_plaits2); - init_engines(); -} int main() { - machine::setup(GIT_COMMIT_SHA, init_engines2); - - while (true) - machine::loop(); - return 0; } \ No newline at end of file diff --git a/src/midiClock.cxx b/src/midiClock.cxx deleted file mode 100644 index 64033c0..0000000 --- a/src/midiClock.cxx +++ /dev/null @@ -1,123 +0,0 @@ - -// 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 "machine.h" - -using namespace machine; - -class MidiClock : public Engine -{ - uint8_t ppqn = 0; - uint8_t offset = 0; - uint8_t impulse = 100; - int count_down = 0; - - int16_t buffer[FRAME_BUFFER_SIZE] = {}; - -public: - MidiClock() : Engine(SEQUENCER_ENGINE | OUT_EQ_VOLT) - { - // 24, 8 or 4 ppqn - param[0].init("ppqn", &ppqn, 0, 0, 2); - param[0].print_value = [&](char *tmp) - { - if (ppqn == 0) - sprintf(tmp, "4ppqn"); - else if (ppqn == 1) - sprintf(tmp, "8ppqn"); - else - sprintf(tmp, "24ppqn"); - }; - - param[1].init("Impulse", &impulse, 10, 1, 100); - param[1].step.i = 1; - param[1].print_value = [&](char *tmp) - { - sprintf(tmp, "Impulse\n%dms", impulse); - }; - - param[2].init("Offset", &offset, 0); - param[2].print_value = [&](char *tmp) - { - sprintf(tmp, "Delay\n%dms", offset); - }; - } - - uint32_t sixteens = 0; - uint32_t next = -1; - uint32_t last_t = 0; - - void process(const ControlFrame &frame, OutputFrame &of) override - { - if (frame.clock) - last_t = frame.t; - - uint32_t div = ppqn == 0 ? 6 : (ppqn == 1 ? 3 : 1); - - if ((frame.clock % div) == 1 || (ppqn > 1 && frame.clock)) - { - next = frame.t + (offset * 2); - } - - if (frame.t == next) - { - if (frame.t - last_t > 1000) - { - // No external clock - so diy and sync with trigger - auto one_div_bpm = 100 * machine::get_bpm() / (25 / 24); - auto t_per_beat = 60 * one_div_bpm; - auto t_24 = t_per_beat / 24 * div; - auto samples_per_frame = machine::SAMPLE_RATE / machine::FRAME_BUFFER_SIZE; - next = frame.t + (t_24 * samples_per_frame); - } - else - next = -1; - - count_down = (impulse * 2); - } - - int16_t a = count_down-- > 0 ? INT16_MAX : 0; - of.push(&a, 1); - } - - void display() override - { - gfx::drawEngine(this); - - char tmp[20]; - int bpm = machine::get_bpm(); - int bpm2 = ((bpm % 100) / 10); - sprintf(tmp, " %d.%dbpm", bpm / 100, bpm2); - gfx::drawString(58, 1, tmp, 0); - } -}; - -void init_midi_clock() -{ - machine::add("MIDI", "Clock"); -} - -MACHINE_INIT(init_midi_clock); \ No newline at end of file diff --git a/src/midiMonitor.cxx b/src/midiMonitor.cxx deleted file mode 100644 index 2a3a854..0000000 --- a/src/midiMonitor.cxx +++ /dev/null @@ -1,89 +0,0 @@ -#include "machine.h" -#include "stmlib/algorithms/voice_allocator.h" -#include - -using namespace machine; - -struct MidiMonitor : public machine::MidiEngine -{ - uint8_t voice[4]; - stmlib::VoiceAllocator allocator; - int16_t pitch = 0; - std::map cc; - - MidiMonitor() - { - allocator.Init(); - allocator.set_size(LEN_OF(voice)); - } - - void process(const machine::ControlFrame &frame, OutputFrame &of) override - { - } - - void display() override - { - gfx::drawEngine(this); - - gfx::drawString(2, 12, "VOICE KEY", 0); - gfx::drawString(66, 12, "CONTROL", 0); - - for (int x = 0; x < 128; x += 3) - gfx::setPixel(x, 18); - - char tmp[30]; - for (size_t i = 0; i < LEN_OF(voice); i++) - { - sprintf(tmp, "#%d %4d", i, voice[i]); - gfx::drawString(2, 20 + i * 6, tmp, 0); - } - - for (int y = 12; y < 60; y += 3) - gfx::setPixel(64, y); - - int bpm = machine::get_bpm(); - int bpm2 = ((bpm % 100) / 10); - sprintf(tmp, "clock: %3d.%d", bpm / 100, bpm2); - gfx::drawString(66, 20, tmp, 0); - - sprintf(tmp, "pitch: %4d", pitch); - gfx::drawString(66, 26, tmp, 0); - - int i = 32; - for(auto c : cc) - { - sprintf(tmp, "cc-%d: %4d", c.first, c.second); - gfx::drawString(66, i, tmp, 0); - i += 6; - } - } - - void onMidiNote(uint8_t key, uint8_t velocity) override // NoteOff: velocity == 0 - { - if (velocity > 0) - { - auto ni = allocator.NoteOn(key); - voice[ni] = key; - } - else - { - auto ni = allocator.NoteOff(key); - voice[ni] = 0; - } - } - - void onMidiPitchbend(int16_t pitch) override - { - this->pitch = pitch; - } - - void onMidiCC(uint8_t ccc, uint8_t value) override - { - cc[ccc] = value; - } -}; - -void init_midi_monitor() -{ - machine::add("MIDI", "Monitor"); -} \ No newline at end of file diff --git a/src/modulations.cxx b/src/modulations.cxx deleted file mode 100644 index 1a7b488..0000000 --- a/src/modulations.cxx +++ /dev/null @@ -1,320 +0,0 @@ -// 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 "machine.h" -#include -#include "stmlib/utils/random.h" - -namespace gfx -{ - void modulation_source_display(const machine::ModulationSource *mod, int x, int y); -} - -struct ModulationBase : machine::ModulationSource -{ - float value; - float attenuverter = 0; - - void display(int x, int y) override - { - gfx::modulation_source_display(this, x, y); - - y += 6; - - if (src > 0) - { - gfx::drawLine(x + 1, y + 32, x + 64, y + 32); - - if (value >= 0) - { - auto m = (value) * 3.1; - for (int yy = 34; yy < 38; yy++) - gfx::drawLine(x + 32, y + yy, x + 32 + m, y + yy); - } - else - { - auto m = (value) * 3.0; - for (int yy = 34; yy < 38; yy++) - gfx::drawLine(x + 33 + m, y + yy, x + 31, y + yy); - } - } - } -}; - -#include "peaks/modulations/lfo.h" -#include "peaks/modulations/multistage_envelope.h" -#include "braids/envelope.h" - -struct Envelope : ModulationBase -{ - uint8_t attack = 0; - uint8_t decay = 0; - uint8_t tr_channel = 0; - - braids::Envelope _processor; - - void eeprom(std::function read_write) override - { - read_write(&tr_channel, sizeof(tr_channel)); - read_write(&attack, sizeof(attack)); - read_write(&decay, sizeof(decay)); - read_write(&attenuverter, sizeof(attenuverter)); - } - - Envelope() - { - _processor.Init(); - param[0].init("TRIG", &tr_channel, tr_channel, 0, machine::get_io_info(0)); - param[0].print_value = [&](char *tmp) - { - if (tr_channel == 0) - sprintf(tmp, "!"); - else - machine::get_io_info(0, tr_channel - 1, tmp); - }; - param[1].init("Att.", &attack, 0); - param[2].init("Dec.", &decay); - param[3].init("%", &attenuverter, attenuverter, -1, +1); - param[3].flags |= machine::Parameter::IS_HIRES; - } - - void process(machine::Parameter &target, machine::ControlFrame &frame) override - { - _processor.Update(attack >> 1, decay >> 1); - - bool trigger = false; - if (tr_channel == 0) - { - trigger = frame.trigger; - } - else - { - trigger = machine::get_trigger(tr_channel - 1); - } - - if (trigger) - _processor.Trigger(braids::ENV_SEGMENT_ATTACK); - - value = ((float)_processor.Render() / UINT16_MAX) * 10.f; - - target.modulate(value * this->attenuverter); - } -}; - -struct LFO : ModulationBase -{ - uint8_t tr_channel = 0; - uint8_t shape = peaks::LFO_SHAPE_SINE; - - uint16_t rate; - peaks::Lfo _processor; - - void eeprom(std::function read_write) override - { - read_write(&rate, sizeof(rate)); - read_write(&attenuverter, sizeof(attenuverter)); - } - - LFO() - { - _processor.Init(); - _processor.set_level(UINT16_MAX); - _processor.set_rate(rate); - _processor.set_parameter(INT16_MAX - 32768); - _processor.set_reset_phase(INT16_MAX - 32768); - - param[0].init_presets("TRIG", &tr_channel, tr_channel, 0, 1 + machine::get_io_info(0)); - param[0].print_value = [&](char *tmp) - { - if (tr_channel == 0) - sprintf(tmp, "-"); - else if (tr_channel - 1 == 0) - sprintf(tmp, "!"); - else - machine::get_io_info(0, tr_channel - 2, tmp); - }; - - _processor.set_shape(peaks::LFO_SHAPE_SINE); - param[1].init_presets("Shape", &shape, shape, 0, peaks::LFO_SHAPE_LAST - 1); - param[1].print_value = [&](char *tmp) - { - switch (shape) - { - case peaks::LFO_SHAPE_SINE: - sprintf(tmp, "SIN"); - break; - case peaks::LFO_SHAPE_TRIANGLE: - sprintf(tmp, "TRI"); - break; - case peaks::LFO_SHAPE_SQUARE: - sprintf(tmp, "SQR"); - break; - case peaks::LFO_SHAPE_STEPS: - sprintf(tmp, "STEPS"); - break; - case peaks::LFO_SHAPE_NOISE: - sprintf(tmp, "NOISE"); - break; - default: - sprintf(tmp, ">?????"); - break; - } - }; - param[2].init("Freq.", &rate, INT16_MAX); - param[3].init("%", &attenuverter, attenuverter, -1, +1); - param[3].flags |= machine::Parameter::IS_HIRES; - } - - uint32_t last_trig = 0; - void process(machine::Parameter &target, machine::ControlFrame &frame) override - { - _processor.set_shape((peaks::LfoShape)shape); - _processor.set_rate(rate); - - peaks::GateFlags flags[] = {peaks::GATE_FLAG_LOW, peaks::GATE_FLAG_LOW}; - - if (tr_channel == 0) - { - // Free LFO - } - else if (tr_channel == 1) - { - if (frame.trigger) - { - flags[0] = peaks::GATE_FLAG_RISING; - flags[1] = peaks::GATE_FLAG_FALLING; - } - } - else - { - if (machine::get_trigger(tr_channel - 2)) - { - flags[0] = peaks::GATE_FLAG_RISING; - flags[1] = peaks::GATE_FLAG_FALLING; - } - } - - int16_t ivalue = 0; - _processor.Process(flags, &ivalue, 1); - value = (float)ivalue / INT16_MAX * 10.f; - target.modulate(value * this->attenuverter); - } -}; - -// https://www.musicdsp.org/en/latest/Filters/265-output-limiter-using-envelope-follower-in-c.html -class EnvelopeFollower -{ -public: - EnvelopeFollower() : envelope(0) - { - } - - void init(float attackMs, float releaseMs, int sampleRate) - { - a = powf(0.01f, 1.0f / (attackMs * sampleRate * 0.001f)); - r = powf(0.01f, 1.0f / (releaseMs * sampleRate * 0.001f)); - } - - float process(float sample) - { - float v = ::fabsf(sample); - if (v > envelope) - envelope = a * (envelope - v) + v; - else - envelope = r * (envelope - v) + v; - - return envelope; - } - -protected: - float envelope; - float a; - float r; -}; - -struct EF : ModulationBase -{ - uint8_t cv_channel = 0; - uint8_t attack = 0; - uint8_t release = 0; - - // DC Block.. - float output_ = 0.0f; - float input_ = 0.0f; - - EnvelopeFollower follower_; - - void eeprom(std::function read_write) override - { - read_write(&cv_channel, sizeof(cv_channel)); - read_write(&attack, sizeof(attack)); - read_write(&release, sizeof(release)); - read_write(&attenuverter, sizeof(attenuverter)); - } - - EF() - { - param[0].init("SRC", &cv_channel, cv_channel, 0, machine::get_io_info(1) - 1); - param[0].print_value = [&](char *tmp) - { - machine::get_io_info(1, cv_channel, tmp); - }; - - param[1].init("ATT", &attack, 0); - param[2].init("REL", &release); - param[1].value_changed = param[2].value_changed = [&]() - { - follower_.init(0.1f + (5.f / UINT8_MAX) * attack, 0.1f + (20.f / UINT8_MAX) * release, machine::SAMPLE_RATE); - }; - param[2].value_changed(); - - param[3].init("%", &attenuverter, attenuverter, -1, +1); - param[3].flags |= machine::Parameter::IS_HIRES; - } - - void process(machine::Parameter &target, machine::ControlFrame &frame) override - { - float in = machine::get_cv(cv_channel); - - // https://ccrma.stanford.edu/~jos/fp/DC_Blocker_Software_Implementations.html - float out = in - input_ + (0.995f * output_); - output_ = out; - input_ = in; - - value = follower_.process(out) * 10.f; - CONSTRAIN(value, 0, 10.f); - - target.modulate(value * attenuverter); - } -}; - -void init_modulations() -{ - machine::add_modulation_source("ENV"); - machine::add_modulation_source("LFO"); -#ifndef MACHINE_TU_REV12 - machine::add_modulation_source("EF"); -#endif -} \ No newline at end of file diff --git a/src/open303.cxx b/src/open303.cxx deleted file mode 100644 index fe806bf..0000000 --- a/src/open303.cxx +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (C)2022 - 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 "stmlib/stmlib.h" -#include "machine.h" -#include "open303/src/rosic_Open303.h" -#include -#define protected public -#include "open303/src/wavetable_gen/rosic_MipMappedWaveTable.h" - -#ifndef FLASHMEM -#include "pgmspace.h" -#endif - -using namespace machine; -using namespace rosic; - -struct Open303Engine : public Engine, rosic::Open303 -{ - Open303Engine() : Engine(TRIGGER_INPUT | VOCT_INPUT), rosic::Open303(nullptr, nullptr) - { - Open303::setSampleRate(machine::SAMPLE_RATE, 1); - Open303::setWaveform(_waveform); - Open303::setTuning(Open303::tuning); - Open303::setAmpSustain(0); - Open303::setAccentAttack(Open303::accentAttack); - Open303::setPitchBend(0); - Open303::setSlideTime(Open303::slideTime); - Open303::setVolume(-12); - Open303::filter.setMode(TeeBeeFilter::TB_303); - - param[0].init_v_oct("Freq", &_pitch); - param[1].init("Acc", &_acc, 100, 1.f, 100.f); - param[2].init("Cutoff", &_cutoff, 0.25f); - param[3].init("Reso", &_res, 33.f, 1.f, 100.f); - param[4].init("EnvMod", &_env, 25.f, 1.f, 100.f); - param[5].init("Dec", &_dec, 0.5f); - // param[6].init("WAVEFORM", &_waveform, _waveform, 0, 1); - // param[6].print_value = [&](char *val) - // { - // sprintf(val, _waveform ? "SQR" : "SAW"); - // }; - _square = (WaveTable *)machine::malloc(sizeof(WaveTable)); - if (_square) - { - MipMappedWaveTable tmp; - tmp.fillWithSquare303(); - tmp.generateMipMap(*_square); - oscillator.setWaveTables(_square, _square); - } - } - - WaveTable *_square = nullptr; - - ~Open303Engine() override - { - machine::mfree(_square); - } - float buffer[FRAME_BUFFER_SIZE]; - - float _pitch = -1; - float _acc = 0; - float _cutoff = 0; - float _res = 0; - float _env = 0; - float _dec = 0; - float _note; - uint8_t _waveform = 1; - bool _gate; - - void process(const ControlFrame &frame, OutputFrame &of) override - { - if (_square == nullptr) - return; - - Open303::setWaveform(_waveform); - Open303::setAccent(_acc); - Open303::setCutoff(linToExp(_cutoff, 0.0, 1.0, 314.0, 2394.0)); - Open303::setResonance(_res); - Open303::setEnvMod(_env); - Open303::setDecay(linToExp(_dec, 0.0, 1.0, 200.0, 2000.0)); - if (_acc > 0) - Open303::setAccentDecay(linToExp(_dec, 0.0, 1.0, 200.0, 2000.0)); - - _note = (float)machine::DEFAULT_NOTE + 24 + frame.qz_voltage(this->io, _pitch) * 12; - CONSTRAIN(_note, 0, 128); - - _gate |= frame.gate; - - if (frame.trigger) - Open303::triggerNote(_note, _acc > 0); - else if (!frame.gate) - { - Open303::releaseNote(_note); - _gate = false; - } - else - Open303::oscFreq = pitchToFreq(_note, tuning); - - for (int i = 0; i < FRAME_BUFFER_SIZE; i++) - buffer[i] = Open303::getSample(); - - of.push(buffer, machine::FRAME_BUFFER_SIZE); - } - - void display() override - { - gfx::drawEngine(this, _square ? nullptr : machine::OUT_OF_MEMORY); - } - - uint32_t _r = 0; - void display_screensaver() override - { - static const uint8_t _screenSaver[] FLASHMEM = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, //> - 0x00, 0x80, 0x0f, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x07, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x30, 0x00, - 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x00, - 0x80, 0x01, 0x06, 0xc0, 0x00, 0x01, 0xc0, 0x00, 0x0f, 0xe0, 0x01, 0x03, - 0x60, 0x00, 0x0f, 0xe0, 0x01, 0x06, 0x30, 0x80, 0x1f, 0xf0, 0x03, 0x0c, - 0x10, 0x80, 0x1f, 0xf0, 0x03, 0x08, 0x18, 0x80, 0x1f, 0xf0, 0x03, 0x18, - 0x08, 0x80, 0x1f, 0xf0, 0x03, 0x10, 0x08, 0x80, 0x1f, 0xf0, 0x03, 0x30, - 0x04, 0x80, 0x1f, 0xf0, 0x03, 0x20, 0x04, 0x80, 0x1f, 0xf0, 0x03, 0x20, - 0x04, 0x80, 0x1f, 0xf0, 0x03, 0x60, 0x06, 0x00, 0x0f, 0xe0, 0x01, 0x40, - 0x02, 0x00, 0x0f, 0xe0, 0x01, 0x40, 0x02, 0x00, 0x06, 0xc0, 0x00, 0x40, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, - 0xe2, 0x07, 0x00, 0x00, 0xe0, 0x47, 0xc2, 0x03, 0x00, 0x00, 0xc0, 0x43, - 0x82, 0x01, 0x00, 0x00, 0x80, 0x41, 0x82, 0x01, 0x00, 0x00, 0x80, 0x41, - 0x86, 0x01, 0x00, 0x00, 0xc0, 0x60, 0x04, 0x03, 0x00, 0x00, 0xc0, 0x60, - 0x04, 0x07, 0x00, 0x00, 0xc0, 0x20, 0x0c, 0x06, 0x00, 0x00, 0x60, 0x20, - 0x08, 0x0e, 0x00, 0x00, 0x70, 0x30, 0x08, 0x1c, 0x00, 0x00, 0x30, 0x10, - 0x18, 0x38, 0x00, 0x00, 0x1c, 0x18, 0x10, 0x70, 0x00, 0x00, 0x0e, 0x08, - 0x20, 0xe0, 0x00, 0x00, 0x0f, 0x0c, 0x60, 0xc0, 0x03, 0xc0, 0x03, 0x06, - 0xc0, 0x00, 0x0f, 0xf0, 0x00, 0x02, 0x80, 0x01, 0xfc, 0x3f, 0x00, 0x01, - 0x00, 0x03, 0xe0, 0x07, 0xc0, 0x00, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, - 0x00, 0x0c, 0x00, 0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00, 0x1c, 0x00, - 0x00, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x0f, 0xf0, 0x01, 0x00, - 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, //> - 0x00, 0xe0, 0xff, 0xff, 0x07, 0x00, 0x00, 0xf0, 0x0f, 0xe0, 0x1f, 0x00, - 0x00, 0xfc, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x7c, 0x00, - 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x80, 0x07, 0x06, 0xc0, 0xe0, 0x01, - 0xc0, 0x03, 0x0f, 0xe0, 0x81, 0x03, 0xe0, 0x81, 0x1f, 0xf0, 0x83, 0x07, - 0xf0, 0x80, 0x1f, 0xf0, 0x03, 0x0f, 0x78, 0xc0, 0x3f, 0xf8, 0x07, 0x1e, - 0x38, 0xc0, 0x3f, 0xf8, 0x07, 0x1c, 0x3c, 0xc0, 0x3f, 0xf8, 0x07, 0x3c, - 0x1c, 0xc0, 0x3f, 0xf8, 0x07, 0x38, 0x1c, 0xc0, 0x3f, 0xf8, 0x07, 0x78, - 0x0e, 0xc0, 0x3f, 0xf8, 0x07, 0x70, 0x0e, 0xc0, 0x3f, 0xf8, 0x07, 0x70, - 0x0e, 0xc0, 0x1f, 0xf0, 0x07, 0xf0, 0x0f, 0x80, 0x1f, 0xf0, 0x03, 0xe0, - 0x07, 0x80, 0x0f, 0xe0, 0x03, 0xe0, 0x07, 0x00, 0x0f, 0xe0, 0x01, 0xe0, - 0x07, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xe7, 0x07, 0x00, 0x00, 0xe0, 0xe7, - 0xf7, 0x07, 0x00, 0x00, 0xe0, 0xef, 0xe7, 0x07, 0x00, 0x00, 0xe0, 0xe7, - 0xc7, 0x03, 0x00, 0x00, 0xc0, 0xe3, 0xc7, 0x03, 0x00, 0x00, 0xc0, 0xe3, - 0xcf, 0x03, 0x00, 0x00, 0xe0, 0xf1, 0x8e, 0x07, 0x00, 0x00, 0xe0, 0xf1, - 0x8e, 0x0f, 0x00, 0x00, 0xe0, 0x71, 0x1e, 0x0f, 0x00, 0x00, 0xf0, 0x70, - 0x1c, 0x1f, 0x00, 0x00, 0xf8, 0x78, 0x1c, 0x3e, 0x00, 0x00, 0x7c, 0x38, - 0x3c, 0x7c, 0x00, 0x00, 0x3e, 0x3c, 0x38, 0xf8, 0x00, 0x00, 0x1f, 0x1c, - 0x70, 0xf0, 0x03, 0xc0, 0x1f, 0x1e, 0xf0, 0xe0, 0x0f, 0xf0, 0x0f, 0x0f, - 0xe0, 0xc1, 0xff, 0xff, 0x03, 0x07, 0xc0, 0x03, 0xff, 0xff, 0xc0, 0x03, - 0x80, 0x07, 0xfc, 0x3f, 0xe0, 0x01, 0x00, 0x0f, 0xe0, 0x07, 0xf0, 0x00, - 0x00, 0x3e, 0x00, 0x00, 0x7c, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x3f, 0x00, - 0x00, 0xf0, 0x0f, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x07, 0x00, - 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00}; - - memset(gfx::display_buffer, 0, 1024); - - for (int i = 23; i > 0; i--) - { - if ((_r & (1 << i))) - gfx::drawCircle(64, 32, 26 + powf(i, 1.3f)); - } - - if (_gate) - { - _r |= 1; - gfx::drawXbm(40, 8, 48, 48, &_screenSaver[sizeof(_screenSaver) / 2]); - } - else - gfx::drawXbm(40, 8, 48, 48, &_screenSaver[0]); - - _r <<= 1; - } -}; - -void init_open303() -{ - machine::add(machine::SYNTH, "Open303"); -} - -MACHINE_INIT(init_open303); diff --git a/src/peaks.cxx b/src/peaks.cxx deleted file mode 100644 index 3208a37..0000000 --- a/src/peaks.cxx +++ /dev/null @@ -1,138 +0,0 @@ -#include "stmlib/stmlib.h" -#include "machine.h" -#include "peaks/drums/bass_drum.h" -#include "peaks/drums/fm_drum.h" -#include "peaks/drums/snare_drum.h" -#include "peaks/drums/high_hat.h" -#include "base/HiHatsEngine.hxx" - -using namespace machine; - -template -struct PeaksEngine : public Engine -{ - T _processor; - - uint16_t params_[4]; - - peaks::GateFlags flags[FRAME_BUFFER_SIZE]; - int16_t buffer[FRAME_BUFFER_SIZE]; - - PeaksEngine(uint16_t p1 = UINT16_MAX / 2, - uint16_t p2 = UINT16_MAX / 2, - uint16_t p3 = UINT16_MAX / 2, - uint16_t p4 = UINT16_MAX / 2, - const char *param1 = nullptr, - const char *param2 = nullptr, - const char *param3 = nullptr, - const char *param4 = nullptr) : Engine(engine_props) - { - memset(&_processor, 0, sizeof(T)); - _processor.Init(); - std::fill(&flags[0], &flags[FRAME_BUFFER_SIZE], peaks::GATE_FLAG_LOW); - - int P1 = 0; - int P2 = 1; - int P3 = 2; - int P4 = 3; - - if (std::is_same::value) - { - P2 = 3; - P3 = 1; - P4 = 2; - } - else if (std::is_same::value) - { - P2 = 2; - P3 = 1; - P4 = 3; - } - - param[0].init(param1, ¶ms_[P1], p1); - param[1].init(param2, ¶ms_[P2], p2); - - - param[2].init(param3, ¶ms_[P3], p3); - param[3].init(param4, ¶ms_[P4], p4); - } - - void process(const ControlFrame &frame, OutputFrame &of) override - { - _processor.Configure(params_, peaks::CONTROL_MODE_FULL); - - if (frame.trigger) - { - flags[0] = peaks::GATE_FLAG_RISING; - std::fill(&flags[1], &flags[FRAME_BUFFER_SIZE], peaks::GATE_FLAG_HIGH); - } - else if (frame.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); - - of.push(buffer, LEN_OF(buffer)); - } -}; - -template <> -void PeaksEngine::process(const ControlFrame &frame, OutputFrame &of) -{ - auto bak = params_[0]; - int val = params_[0]; - val += (frame.qz_voltage(this->io, 0.f) * INT16_MAX / 3); // CV or Midi Pitch ?! - val += (-2 * INT16_MAX / 3); - CONSTRAIN(val, 0, UINT16_MAX); - params_[0] = val; - _processor.Configure(params_, peaks::CONTROL_MODE_FULL); - params_[0] = bak; - - if (frame.trigger) - { - flags[0] = peaks::GATE_FLAG_RISING; - std::fill(&flags[1], &flags[FRAME_BUFFER_SIZE], peaks::GATE_FLAG_HIGH); - } - else if (frame.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); - - of.push(buffer, LEN_OF(buffer)); -} - - -class Hihat808 : public HiHatsEngine -{ - PeaksEngine oh; - PeaksEngine ch; - -public: - Hihat808() : oh(UINT16_MAX), ch(UINT16_MAX) - { - _ch = &ch; - _oh = &oh; - } -}; - -void init_drums_peaks() -{ - add>(DRUM, "FM-Drum", INT16_MAX, INT16_MAX, INT16_MAX, INT16_MAX, "Freq.", "Noise", "FM", "Decay"); - add>(DRUM, "808ish-BD", INT16_MAX, INT16_MAX, INT16_MAX, INT16_MAX, "Pitch", "Punch", "Tone", "Decay"); - add>(DRUM, "808ish-SD", INT16_MAX, INT16_MAX, INT16_MAX, INT16_MAX, "Pitch", "Snappy", "Tone", "Decay"); - // add>(DRUM, "808ish-HiHat", INT16_MAX, INT16_MAX, INT16_MAX, INT16_MAX, "Decay"); - add(DRUM, "808ish-HiHat"); -} \ No newline at end of file diff --git a/src/plaits.cxx b/src/plaits.cxx deleted file mode 100644 index d739fbc..0000000 --- a/src/plaits.cxx +++ /dev/null @@ -1,373 +0,0 @@ -#include "stmlib/stmlib.h" -#include "machine.h" -#define private public // ;-) -#include "plaits/dsp/voice.h" -#include "stmlib/dsp/dsp.h" - -using namespace machine; - -struct InitArgs -{ - int engine; - int output; // output=0 -> out, output=1 -> aux, output=3 -> stereo -}; - -struct PlaitsEngine : public Engine -{ - plaits::Modulations modulations; - plaits::Voice voice; - plaits::Patch patch; - - float bufferOut[machine::FRAME_BUFFER_SIZE]; - float bufferAux[machine::FRAME_BUFFER_SIZE]; - float out_aux_mix = 0.5f; - float _pitch = 0; - float _base_pitch = machine::DEFAULT_NOTE; - - const uint8_t engine = 0; - const uint8_t output = 0; - - uint8_t *_buffer = nullptr; - plaits::Engine *_plaitsEngine = nullptr; - - ~PlaitsEngine() override - { - machine::mfree(_plaitsEngine); - machine::mfree(_buffer); - } - - template - void alloc_engine(size_t mem = 48) - { - _plaitsEngine = new (machine::malloc(sizeof(T))) T(); - _buffer = (uint8_t *)machine::malloc(mem * sizeof(float)); - - stmlib::BufferAllocator allocator; - allocator.Init(_buffer, mem * sizeof(float)); - _plaitsEngine->Init(&allocator); - } - - float harmonics, timbre, morph; - - void init_params(const char *h, float hh, const char *t, float tt, const char *m, float mm, const plaits::PostProcessingSettings &settings) - { - param[1].init(h, &harmonics, hh); - param[2].init(t, &timbre, tt); - param[3].init(m, &morph, mm); - patch.harmonics = harmonics; - patch.timbre = timbre; - patch.morph = morph; - if (_plaitsEngine) - _plaitsEngine->post_processing_settings = settings; - } - - PlaitsEngine(const InitArgs &args) : Engine(TRIGGER_INPUT | VOCT_INPUT), engine(args.engine), output(args.output) - { - voice.Init(); - patch.engine = 0; - memset(&patch, 0, sizeof(patch)); - patch.note = machine::DEFAULT_NOTE + _pitch * 12.f; - - modulations.timbre_patched = true; - patch.timbre_modulation_amount = 0; - - modulations.frequency_patched = true; - patch.frequency_modulation_amount = 0; - - modulations.morph_patched = true; - patch.morph_modulation_amount = 0; - - memset(&modulations, 0, sizeof(modulations)); - - patch.lpg_colour = 0.5; - patch.decay = 0.5; - modulations.trigger_patched = true; // trigger; - // modulations.level_patched = true; //trigger; - // modulations.level = 1; - - param[0].init_v_oct("Pitch", &_pitch); - - switch (engine) - { - case 0: - alloc_engine(); - init_params("Detune", 0.5f, "Square", 0.5f, "CSAW", 0.5f, {0.8f, 0.8f, false}); - break; - case 1: - alloc_engine(); - init_params("Waveform", 0.8f, "Fold", 0.8f, "Asym.", 0.75f, {0.7f, 0.6f, false}); - break; - case 2: - alloc_engine(); - init_params("Ratio", 0.8f, "Mod", 0.8f, "Feedb.", 0.75f, {0.6f, 0.6f, false}); - break; - case 3: - alloc_engine(); - init_params("Ratio", 0.8f, "Frm/Fq.", 0.8f, "Width", 0.75f, {0.7f, 0.6f, false}); - param[5].init("PD-Mix", &out_aux_mix, out_aux_mix); - break; - case 4: - alloc_engine(); - init_params("Bump", 0.8f, "Peak", 0.8f, "Shape", 0.75f, {0.8f, 0.8f, false}); - break; - case 5: - alloc_engine(64 * sizeof(const int16_t *)); - init_params("Bank", 0.f, "Row", 0.8f, "Column", 0.75f, {0.6f, 0.6f, false}); - param[1].init(param[1].name, param[1].value.fp, 0.0f, 0, 0.5f); - _plaitsEngine->LoadUserData(nullptr); - break; - case 6: - { - alloc_engine(plaits::kChordNumChords * plaits::kChordNumNotes + plaits::kChordNumChords + plaits::kChordNumNotes); - init_params("Chord", 0.5f, "Inv.", 0.5f, "Shape", 0.5f, {0.8f, 0.8f, false}); - - auto &chord = static_cast(_plaitsEngine)->chords_.chord_index_quantizer_.quantized_value_; - param[1].init_presets("Chord", (uint8_t *)&chord, 8, 0, - static_cast(_plaitsEngine)->chords_.chord_index_quantizer_.num_steps() - 1); - param[1].print_value = [&](char *tmp) - { - const int chord_index = static_cast(_plaitsEngine)->chords_.chord_index(); - sprintf(tmp, "%s", plaits::chord_names[chord_index]); - }; - } - break; - // case 15: // speech_engine_ - // alloc_engine(false, 0.8f, 0.8f); - // break; - // case 8: // swarm_engine_ - // alloc_engine(false, -3.0f, 1.0f); - // break; - // case 9: // noise_engine_ - // alloc_engine(false, -1.0f, -1.0f); - // break; - // case 10: // particle_engine_ - // alloc_engine(false, -2.0f, 1.0f); - // break; - // case 11: // string_engine_ - // alloc_engine(true, -1.0f, 0.8f); - // break; - // case 12: // modal_engine_ - // alloc_engine(true, -0.5f, 0.8f); - // break; - case 13: - _base_pitch += -24.f; - alloc_engine(); - init_params(output == 0 ? "Drive" : "Punch", 0.8f, "Tone", 0.5f, "Decay", 0.5f, {0.8f, 0.8f, true}); - break; - case 14: - alloc_engine(); - init_params("Snappy", 0.5f, "Tone", 0.5f, "Decay", 0.5f, {0.8f, 0.8f, true}); - break; - case 15: - alloc_engine(); - init_params("Noise", 0.5f, "Tone", 0.9f, "Decay", 0.6f, {0.8f, 0.8f, true}); - break; - // engines 2 - case 16: - alloc_engine(); - init_params("Harsh", 0.5f, "Cutoff", 0.5f, "Morph", 0.5f, {1.f, 1.f, false}); - out_aux_mix = 0; - modulations.timbre_patched = false; - std::swap(param[1], param[3]); - param[4].init("EnvMod", &patch.timbre_modulation_amount, 0, -1.f, 1.f); - param[5].init("Decay", &patch.decay, 0.5f, 0, 0.99f); - break; -#if 0 - case 17: - alloc_engine(plaits::kMaxBlockSize * 4); - _plaitsEngine->post_processing_settings = {0.7f, 0.7f, false}; - break; - case 18: - case 19: - case 20: - alloc_engine( - plaits::kMaxBlockSize * 4 + plaits::kMaxBlockSize * plaits::kNumSixOpVoices + sizeof(plaits::fm::Patch) * 96 / sizeof(float)); - init_params("", 0.0f, "Mod", 0.5f, "Env", 0.5f, {1.f, 1.f, false}); - param[1].init_presets("Preset", &static_cast(_plaitsEngine)->patch_index, 0, 0, 95); - param[1].print_value = [&](char *name) - { - auto i = static_cast(_plaitsEngine)->patch_index; - sprintf(name, ">%.10s", static_cast(_plaitsEngine)->patches_[i].name); - }; - _plaitsEngine->LoadUserData(plaits::fm_patches_table[0]); - modulations.morph_patched = false; - param[5].init("EnvMod", &patch.morph_modulation_amount, 0.0f, -1.f, 1.f); - - modulations.timbre_patched = false; - param[4].init("ModMod", &patch.timbre_modulation_amount, 0.0f, -1.f, 1.f); - break; - case 21: - alloc_engine(plaits::kMaxBlockSize * 4); - _plaitsEngine->post_processing_settings = {0.7f, 0.7f, false}; - patch.engine = (engine - 16); - break; - case 22: - alloc_engine(16 + 3 * (1024 + 265)); - _plaitsEngine->post_processing_settings = {0.8f, 0.8f, false}; - patch.engine = (engine - 16); - break; - case 23: - alloc_engine(plaits::kChordNumChords * plaits::kChordNumNotes + plaits::kChordNumChords + plaits::kChordNumNotes); - _plaitsEngine->post_processing_settings = {0.5f, 0.5f, false}; - patch.engine = (engine - 16); - break; -#endif - } - - if (engine >= 16) - patch.engine = (engine - 16); - - _plaitsEngine->Reset(); - - if (is_drum()) - { - param[0].init("Pitch", &_pitch, 0, -1.f, 1.f); - // modulations.frequency_patched = false; - // param[4].init("Bend", &patch.frequency_modulation_amount, 0.0f, -1.f, 1.f); - } - else - { - if (param[4].name == nullptr) - param[4].init("Decay", &patch.decay); - - if (param[5].name == nullptr) - { - if (output == 2) - param[5].init("AuxMix", &out_aux_mix, out_aux_mix); - else - param[5].init("Color", &patch.lpg_colour); - } - } - } - - bool is_drum() - { - return engine == 13 || engine == 14 || engine == 15; - } - - void process(const machine::ControlFrame &frame, OutputFrame &of) override - { - float a = bufferOut[0] / 256.f; - ONE_POLE(patch.harmonics, harmonics + a, 0.1f); - ONE_POLE(patch.timbre, timbre + a, 0.1f); - ONE_POLE(patch.morph, morph + a, 0.1f); - - modulations.level_patched = false; - modulations.level = 1.f; - - patch.note = _base_pitch + frame.qz_voltage(this->io, _pitch) * 12; - - float last_decay = patch.decay; - float last_morph = patch.morph; - // if (!frame.trigger && frame.gate) - // { - // if (is_drum()) - // patch.morph = 1; - // else - // patch.decay = 1; - - // modulations.level = 1.f; - // // modulations.level_patched = true; - // } - modulations.engine = patch.engine; - modulations.trigger = frame.trigger ? 1 : 0; - - if (!is_drum()) - modulations.trigger_patched = patch.decay < 1.f; - - if (!this->io->tr) - { - modulations.trigger_patched = false; - modulations.level_patched = true; - modulations.level = patch.decay; - patch.decay = 0.001f; - } - else - { - modulations.trigger_patched = true; - } - - modulations.note = 0; - voice.Render(_plaitsEngine, patch, modulations, bufferOut, bufferAux, machine::FRAME_BUFFER_SIZE); - - patch.decay = last_decay; - patch.morph = last_morph; - - switch (output) - { - case 0: - of.out = bufferOut; - break; - case 1: - of.out = bufferAux; - break; - case 2: - for (int i = 0; i < machine::FRAME_BUFFER_SIZE; i++) - bufferOut[i] = stmlib::Crossfade(bufferOut[i], bufferAux[i], out_aux_mix); - of.out = bufferOut; - break; - case 3: - of.out = bufferOut; - of.aux = bufferAux; - break; - } - } - - void display() override - { - for (auto &p : param) - { - if (p.name == nullptr) - break; - - if (p.value.fp == &patch.decay) - { - if (!this->io->tr) - p.name = "Level"; - else - p.name = "Decay"; - } - } - - gfx::drawEngine(this); - } -}; - -void init_plaits() -{ - - // engine1 - machine::add(machine::M_OSC, "Virt.Analog", {0, 0}); - machine::add(machine::M_OSC, "Waveshaping", {1, 0}); - machine::add(machine::M_OSC, "2-OP-FM", {2, 0}); - machine::add(machine::M_OSC, "Formant/PD", {3, 2}); - machine::add(machine::M_OSC, "Harmonic", {4, 2}); - machine::add(machine::M_OSC, "Wavetable", {5, 2}); - machine::add(machine::M_OSC, "Chord", {6, 0}); - // machine::add>(machine::M_OSC, "VowelAndSpeech", 0.f, 0.95f, 0.5f, 0.25f, "Freq", "Harm", "Timbre", "Morph"); - - // machine::add>(machine::M_OSC, "Swarm", 0.f, 0.5f, 0.5f, 0.5f, "Freq", "Harm", "Timbre", "Morph"); - // machine::add>(machine::M_OSC, "Noise", 4.f, 0.0f, 1.0f, 1.0f, "Cutoff", "LP/HP", "Clock", "Q"); - // machine::add>(machine::M_OSC, "Particle", 4.f, 0.8f, 0.9f, 1.0f, "Freq", "Harm", "Timbre", "Morph"); - // machine::add>(machine::M_OSC, "String", 0.f, 0.5f, 0.5f, 0.5f, "Freq", "Harm", "Timbre", "Decay"); - // machine::add>(machine::M_OSC, "Modal", 0.f, 0.5f, 0.5f, 0.5f, "Freq", "Harm", "Timbre", "Decay"); - - machine::add(machine::DRUM, "Analog BD", {13, 0}); - machine::add(machine::DRUM, "Analog SD", {14, 0}); - - machine::add(machine::DRUM, "Analog HH2", {15, 1}); - machine::add(machine::DRUM, "Analog HH", {15, 0}); - machine::add(machine::DRUM, "909ish-BD", {13, 1}); - machine::add(machine::DRUM, "909ish-SD", {14, 1}); -} - -void init_plaits2() -{ - // engine2 https://pichenettes.github.io/mutable-instruments-documentation/modules/plaits/firmware/ - machine::add(machine::SYNTH, "ClassicVAVCF", {16, 2}); - // machine::add(machine::SYNTH, "SixOpFM", {18, 0}); - // machine::add(machine::M_OSC, "PhaseDistort", {17, 0, 0.f, 0.8f, 0.8f, 0.75f, "Freq", "Harm", "Timbre", "Morph"}); - // machine::add(machine::M_OSC, "WaveTerrain", {21, 0, 0.f, 0.5f, 0.5f, 0.5f, "Freq", "Harm", "Timbre", "Morph"}); - // machine::add(machine::M_OSC, "StringEngine", {22, 0, 0.f, 0.5f, 0.5f, 0.5f, "Freq", "Harm", "Timbre", "Morph"}); - // machine::add(machine::M_OSC, "ChipTune", {23, 1, 0.f, 0.5f, 0.5f, 0.5f, "Freq", "Harm", "Timbre", "Morph"}); -} \ No newline at end of file diff --git a/src/polyVA.cxx b/src/polyVA.cxx deleted file mode 100644 index 0d4dda1..0000000 --- a/src/polyVA.cxx +++ /dev/null @@ -1,132 +0,0 @@ -#include "machine.h" -#include "plaits/dsp/engine/virtual_analog_engine.h" -#include "plaits/dsp/envelope.h" -#include "stmlib/algorithms/voice_allocator.h" -#include "stmlib/utils/random.h" - -using namespace machine; - -struct PolyVAEngine : public machine::MidiEngine -{ - plaits::VirtualAnalogEngine voice[6]; - - uint8_t buffer[LEN_OF(voice) * 48 * sizeof(float)]; - stmlib::BufferAllocator buffAllocator; - - plaits::EngineParameters parameters[LEN_OF(voice)]; - plaits::LPGEnvelope lpg[LEN_OF(voice)]; - bool enveloped[LEN_OF(voice)] = {}; - - stmlib::VoiceAllocator allocator; - - float timbre; - float morph; - float harmonics; - float pitch = 0; - float pitch_bend = 0; - - float decay = 0.5f; - float hf = 1.f; - float pan[LEN_OF(voice)]; - float stereo; - - float polyBuffL[machine::FRAME_BUFFER_SIZE]; - float polyBuffR[machine::FRAME_BUFFER_SIZE]; - float voiceBuff[machine::FRAME_BUFFER_SIZE]; - float dummy[machine::FRAME_BUFFER_SIZE]; - - PolyVAEngine() - { - allocator.Init(); - allocator.set_size(LEN_OF(voice)); - param[0].init_v_oct("Pitch", &pitch); - param[1].init("Harmo", &harmonics); - param[2].init("Timbre", &timbre); - param[3].init("Morph", &morph); - param[4].init("Decay", &decay, decay); - param[5].init("Stereo", &stereo, 0.5f); - - memset(buffer, 0, sizeof(buffer)); - buffAllocator.Init(buffer, sizeof(buffer)); - - for (size_t i = 0; i < LEN_OF(voice); i++) - { - lpg[i].Init(); - voice[i].Init(&buffAllocator); - } - } - - void process(const machine::ControlFrame &frame, OutputFrame &of) override - { - std::fill_n(polyBuffL, FRAME_BUFFER_SIZE, 0); - std::fill_n(polyBuffR, FRAME_BUFFER_SIZE, 0); - - const float short_decay = (200.0f * FRAME_BUFFER_SIZE) / SAMPLE_RATE * - stmlib::SemitonesToRatio(-96.0f * decay); - - const float decay_tail = (20.0f * FRAME_BUFFER_SIZE) / SAMPLE_RATE * - stmlib::SemitonesToRatio(-72.0f * decay + 12.0f * hf) - - short_decay; - - for (size_t i = 0; i < LEN_OF(voice); i++) - { - auto p = parameters[i]; - p.note += (pitch * 12.f) + pitch_bend; - p.timbre = timbre; - p.morph = morph; - p.harmonics = harmonics; - - voice[i].Render(p, voiceBuff, dummy, FRAME_BUFFER_SIZE, &enveloped[i]); - - lpg[i].ProcessPing(0.5f, short_decay, decay_tail, hf); - - float l = cosf(pan[i] * M_PI / 2); - float r = sinf(pan[i] * M_PI / 2); - - for (int s = 0; s < FRAME_BUFFER_SIZE; s++) - { - polyBuffL[s] += (voiceBuff[s] * lpg[i].gain()) * l; - polyBuffR[s] += (voiceBuff[s] * lpg[i].gain()) * r; - } - - parameters[i].trigger = plaits::TriggerState::TRIGGER_LOW; - } - - of.push(polyBuffL, FRAME_BUFFER_SIZE); - of.push(polyBuffR, FRAME_BUFFER_SIZE); - } - - void onMidiNote(uint8_t key, uint8_t velocity) override // NoteOff: velocity == 0 - { - if (velocity > 0) - { - auto ni = allocator.NoteOn(key); - parameters[ni].trigger = plaits::TriggerState::TRIGGER_RISING_EDGE; - parameters[ni].note = key; - parameters[ni].accent = velocity > 100; - - pan[ni] = 0.5f + stereo * (stmlib::Random::GetFloat() - 0.5f); - - lpg[ni].Trigger(); - } - else - { - allocator.NoteOff(key); - } - } - - void onMidiPitchbend(int16_t pitch) override - { - pitch_bend = ((float)pitch / 8192) * 12; - } - - void onMidiCC(uint8_t ccc, uint8_t value) override - { - // nothing implemented.. - } -}; - -void init_midi_polyVA() -{ - machine::add("MIDI", "VAx6"); -} \ No newline at end of file diff --git a/src/quantizer.cxx b/src/quantizer.cxx deleted file mode 100644 index a35d8c8..0000000 --- a/src/quantizer.cxx +++ /dev/null @@ -1,16 +0,0 @@ - -#include "machine.h" -#include "braids/quantizer.h" -#include "braids/quantizer_scales.h" -#include "braids/settings.h" - -using namespace braids; -using namespace machine; - -void init_quantizer() -{ - for(size_t i = 0; i < LEN_OF(braids::scales); i++) - machine::add_quantizer_scale(braids::settings.metadata(braids::Setting::SETTING_QUANTIZER_SCALE).strings[i], (const machine::QuantizerScale&)braids::scales[i]); -} - -MACHINE_INIT(init_quantizer); \ No newline at end of file diff --git a/src/rings.cxx b/src/rings.cxx deleted file mode 100644 index d4bd4f6..0000000 --- a/src/rings.cxx +++ /dev/null @@ -1,103 +0,0 @@ -#include "stmlib/stmlib.h" -#include "machine.h" -#include "rings/dsp/strummer.h" - -using namespace machine; - -struct ResonatorEngine : public Engine -{ - uint8_t _model; - rings::Strummer strummer; - rings::Part *part; - rings::Patch patch; - rings::PerformanceState performance_state; - float bufferOut[FRAME_BUFFER_SIZE]; - float bufferAux[FRAME_BUFFER_SIZE]; - - float in[FRAME_BUFFER_SIZE]; - - float _pitch; - - ResonatorEngine() : Engine(TRIGGER_INPUT | VOCT_INPUT | AUDIO_PROCESSOR) - { - memset(&strummer, 0, sizeof(rings::Strummer)); - memset(&patch, 0, sizeof(rings::Patch)); - patch.structure = 0.5f; - patch.brightness = 0.5f; - patch.damping = 0.5f; - patch.position = 0.5f; - memset(&performance_state, 0, sizeof(rings::PerformanceState)); - strummer.Init(0.01f, SAMPLE_RATE / FRAME_BUFFER_SIZE); - if (void *mem = machine::malloc(sizeof(rings::Part))) - { - part = new (mem) rings::Part(); - part->Init(); - part->set_model(rings::ResonatorModel::RESONATOR_MODEL_MODAL); - part->set_polyphony(rings::kMaxPolyphony); - } - memset(in, 0, sizeof(in)); - - param[0].init_v_oct("Freq", &_pitch); - param[1].init_presets("Model", &_model, rings::ResonatorModel::RESONATOR_MODEL_MODAL, - rings::ResonatorModel::RESONATOR_MODEL_MODAL, - rings::ResonatorModel::RESONATOR_MODEL_SYMPATHETIC_STRING_QUANTIZED); - param[2].init("Struc.", &patch.structure); - param[3].init("Brighn.", &patch.brightness); - param[4].init("Damping", &patch.damping); - param[5].init("Pos", &patch.position); - } - - ~ResonatorEngine() override - { - machine::mfree(part); - } - - void process(const ControlFrame &frame, OutputFrame &of) override - { - if (part == nullptr) - return; - - part->set_model((rings::ResonatorModel)_model); - - performance_state.strum = frame.trigger; - performance_state.internal_strum = false; - performance_state.internal_note = true; - performance_state.internal_exciter = true; - performance_state.tonic = 0.2f; - performance_state.chord = 0; - performance_state.note = machine::DEFAULT_NOTE; - - float *input = machine::get_aux(AUX_L); - - performance_state.note += frame.qz_voltage(this->io, _pitch) * 12; - - strummer.Process(input, FRAME_BUFFER_SIZE, &performance_state); - part->Process(performance_state, patch, input, bufferOut, bufferAux, FRAME_BUFFER_SIZE); - - of.out = bufferOut; - of.aux = bufferAux; - } - - void display() override - { - if (_model == rings::ResonatorModel::RESONATOR_MODEL_MODAL) - param[1].name = "@Modal"; - else if (_model == rings::ResonatorModel::RESONATOR_MODEL_SYMPATHETIC_STRING) - param[1].name = "@Sympath."; - else if (_model == rings::ResonatorModel::RESONATOR_MODEL_STRING) - param[1].name = "@String"; - else if (_model == rings::ResonatorModel::RESONATOR_MODEL_FM_VOICE) - param[1].name = "@FM"; - else - param[1].name = "@StrQuant."; - - gfx::drawEngine(this, part ? nullptr : machine::OUT_OF_MEMORY); - } -}; - -void init_rings() -{ - machine::add(M_OSC, "Resonator"); -} - -MACHINE_INIT(init_rings); \ No newline at end of file diff --git a/src/speech.cxx b/src/speech.cxx deleted file mode 100644 index d48005b..0000000 --- a/src/speech.cxx +++ /dev/null @@ -1,111 +0,0 @@ -#include "stmlib/stmlib.h" -#include "stmlib/dsp/units.h" -#include "machine.h" - -#define private public -#include "plaits/dsp/speech/lpc_speech_synth_controller.h" -#include "plaits/dsp/speech/lpc_speech_synth_words.h" - -using namespace machine; - -const float a0 = (440.0f / 8.0f) / 48000.0f; - -inline float NoteToFrequency(float midi_note) -{ - midi_note -= 9.0f; - CONSTRAIN(midi_note, -128.0f, 127.0f); - return a0 * 0.25f * stmlib::SemitonesToRatio(midi_note); -} - -struct SpeechEngine : public Engine -{ - float _pitch = 0.f; - uint8_t _word = 0; - float _speed = 0.3f; - float _formant_shift = 0.5f; - float _prosody = 0.5f; - float _out_aux_mix = 0.0f; - - struct - { - uint8_t bank; - float addr; - } _words[92]; - - plaits::LPCSpeechSynthController lpc_speech_synth_controller_; - plaits::LPCSpeechSynthWordBank lpc_speech_synth_word_bank_; - - float _out[machine::FRAME_BUFFER_SIZE]; - float _aux[machine::FRAME_BUFFER_SIZE]; - - uint8_t buffer[16384]; - stmlib::BufferAllocator allocator; - - SpeechEngine() : Engine(TRIGGER_INPUT | VOCT_INPUT) - { - - memset(buffer, 0, sizeof(buffer)); - allocator.Init(buffer, 16384); - lpc_speech_synth_word_bank_.Init(plaits::word_banks_, - LPC_SPEECH_SYNTH_NUM_WORD_BANKS, - &allocator); - int j = 0; - for (uint8_t i = 0; i < LPC_SPEECH_SYNTH_NUM_WORD_BANKS; i++) - { - lpc_speech_synth_word_bank_.Load(i); - - for (int l = 0; l < lpc_speech_synth_word_bank_.num_words_; l++) - _words[j++] = {i, 1.f / lpc_speech_synth_word_bank_.num_words_ * l}; - } - - lpc_speech_synth_controller_.Init(&lpc_speech_synth_word_bank_); - - param[0].init_v_oct("Pitch", &_pitch); - param[1].init_presets("WORD", &_word, 0, 0, LEN_OF(_words) - 1); - param[2].init("Speed", &_speed, _speed); - param[3].init("Form.Shift", &_formant_shift, _formant_shift); - param[4].init("Prosody", &_prosody, _prosody); - param[5].init("AuxMix", &_out_aux_mix, _out_aux_mix); - } - - void process(const ControlFrame &frame, OutputFrame &of) override - { - auto note = (float)machine::DEFAULT_NOTE; - - note += frame.qz_voltage(this->io, _pitch) * 12; - - const float f0 = NoteToFrequency(note); - - lpc_speech_synth_controller_.Render(false, - frame.trigger, - _words[_word].bank, // Bank - f0, - _prosody, - _speed, // Speed - _words[_word].addr, // Word - _formant_shift, - 1.0f, - _aux, - _out, - machine::FRAME_BUFFER_SIZE); - - for (int i = 0; i < machine::FRAME_BUFFER_SIZE; i++) - _out[i] = stmlib::Crossfade(_out[i], _aux[i], _out_aux_mix); - - of.out = _out; - } - - char tmp[10]; - void display() override - { - sprintf(tmp, "WORD%0d", _word); - param[1].name = tmp; - - gfx::drawEngine(this); - } -}; - -void init_speech() -{ - machine::add("SPEECH", "LPC"); -} \ No newline at end of file diff --git a/src/tr707.cxx b/src/tr707.cxx deleted file mode 100644 index 7336b75..0000000 --- a/src/tr707.cxx +++ /dev/null @@ -1,74 +0,0 @@ - -#include "machine.h" -#include "base/SampleEngine.hxx" -#include "base/HiHatsEngine.hxx" -#include - -// #include "eproms/tr707/IC34_TR707_SNDROM.h" -// #include "eproms/tr707/IC35_TR707_SNDROM.h" - -struct TR707 : public SampleEngine -{ - const uint8_t *IC34_TR707_SNDROM_bin = machine::flash_read("707_IC34"); - const uint8_t *IC35_TR707_SNDROM_bin = machine::flash_read("707_IC35"); - - const uint8_t *BD0 = &IC34_TR707_SNDROM_bin[0x0000]; - const uint8_t *BD1 = &IC34_TR707_SNDROM_bin[0x0001]; - const uint8_t *SD0 = &IC34_TR707_SNDROM_bin[0x2000]; - const uint8_t *SD1 = &IC34_TR707_SNDROM_bin[0x2001]; - const uint8_t *RM = &IC35_TR707_SNDROM_bin[0x4000]; - const uint8_t *CB = &IC35_TR707_SNDROM_bin[0x4001]; - const uint8_t *CP = &IC35_TR707_SNDROM_bin[0x6000]; - const uint8_t *TMB = &IC35_TR707_SNDROM_bin[0x6001]; - - const uint8_t *LT = &IC34_TR707_SNDROM_bin[0x4000]; - const uint8_t *MT = &IC34_TR707_SNDROM_bin[0x6000]; - const uint8_t *HT = &IC35_TR707_SNDROM_bin[0x0000]; - - const uint8_t *HH = &IC35_TR707_SNDROM_bin[0x2000]; - - const tsample_spec _sounds[12] = { - //{"> BD", BD0, 0x2000, 50000, 0}, - {"BD0", BD0, 0x1000, 25000, 1}, - {"BD1", BD1, 0x1000, 25000, 1}, - //{"> SD", SD0, 0x2000, 50000, 0}, - {"SD0", SD0, 0x1000, 25000, 1}, - {"SD1", SD1, 0x1000, 25000, 1}, - {"CP", CP, 0x1000, 25000, 1}, - {"TMB", TMB, 0x1000, 25000, 1}, - {"RM", RM, 0x1000, 25000, 1}, - {"CB", CB, 0x1000, 25000, 1}, - {"LT", LT, 0x2000, 12500, 0}, - {"MT", MT, 0x2000, 12500, 0}, - {"HT", HT, 0x2000, 12500, 0}, - {"HH", HH, 0x2000, 25000, 0}, - }; - - TR707(int sample_num = 0) : SampleEngine() - { - setup(_sounds, sample_num, LEN_OF(_sounds)); - } - - bool init() override - { - return IC34_TR707_SNDROM_bin && IC35_TR707_SNDROM_bin; - } -}; - -struct TR707_CH_OH : public HiHatsEngine -{ - TR707 oh; - TR707 ch; - - TR707_CH_OH() : oh(11), ch(11) - { - _oh = &oh; - _ch = &ch; - } -}; - -void init_tr707() -{ - machine::add(machine::DRUM, "TR707"); - machine::add(machine::DRUM, "TR707-HiHat"); -} \ No newline at end of file diff --git a/src/tr909.cxx b/src/tr909.cxx deleted file mode 100644 index b6ffa56..0000000 --- a/src/tr909.cxx +++ /dev/null @@ -1,87 +0,0 @@ -#include "machine.h" -#include "base/SampleEngine.hxx" -#include "base/HiHatsEngine.hxx" - -// #include "eproms/tr909/hihats.h" -// #include "eproms/tr909/ride.h" - -// TODO: Filter LP-HP - -struct TR909_OH : public SampleEngine -{ - const uint8_t *HiHats_bin = machine::flash_read("909_HIGH"); - const tsample_spec _sound = {"", HiHats_bin, 24576, 32000, 0}; - - TR909_OH() : SampleEngine() - { - setup(&_sound, 0, 1); - } - - bool init() override - { - return HiHats_bin; - } -}; - -constexpr static int ch_start = 24576; -struct TR909_CH : public SampleEngine -{ - const uint8_t *HiHats_bin = machine::flash_read("909_HIGH"); - const tsample_spec _sound = {"", HiHats_bin + ch_start, 32768 - ch_start, 32000, 0}; - - TR909_CH() : SampleEngine() - { - setup(&_sound, 0, 1); - } - - bool init() override - { - return HiHats_bin; - } -}; - -struct TR909_Ride : public SampleEngine -{ - const uint8_t *Ride_bin = machine::flash_read("909_RIDE"); - const tsample_spec _sound = {"", Ride_bin, 32768, 32000, 0}; - - TR909_Ride() : SampleEngine() - { - setup(&_sound, 0, 1); - } - - bool init() override - { - return Ride_bin; - } -}; - -struct TR909_CH_OH : public HiHatsEngine -{ - TR909_OH oh; - TR909_CH ch; - - TR909_CH_OH() - { - _oh = &oh; - _ch = &ch; - } -}; - -struct TR909_CR_OR : public HiHatsEngine -{ - TR909_Ride oh; - TR909_Ride ch; - - TR909_CR_OR() - { - _oh = &oh; - _ch = &ch; - } -}; - -void init_tr909() -{ - machine::add(machine::DRUM, "TR909-HiHat"); - machine::add(machine::DRUM, "TR909-Ride"); -} \ No newline at end of file diff --git a/src/voltage.cxx b/src/voltage.cxx deleted file mode 100644 index ec92b90..0000000 --- a/src/voltage.cxx +++ /dev/null @@ -1,253 +0,0 @@ - -// 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 "machine.h" -#include "stmlib/dsp/dsp.h" - -namespace gfx -{ - void drawEngineWithScope(machine::Engine *engine, int8_t scope[128], int i, int y) - { - for (int x = 0; x < 127; x++) - { - if (x % 3 == 0) - gfx::setPixel(x, y); - gfx::drawLine(x, y - scope[(i + x) % 128], x + 1, y - scope[(1 + i + x) % 128]); - } - - gfx::drawEngineCompact(engine); - } - - void push_scope(int8_t scope[128], uint8_t &i, int8_t y) - { - scope[i++ % 128] = y; - if (i > 128) - i = 0; - } -} - -using namespace machine; - -class VoltsPerOctave : public Engine -{ - char tmp[64]; - uint16_t note = DEFAULT_NOTE * machine::PITCH_PER_OCTAVE / 12; - uint8_t tune = 128; - int32_t cv0 = 0; - int32_t cv = 0; - float glide = 0; - -public: - VoltsPerOctave() : Engine(OUT_EQ_VOLT | VOCT_INPUT) - { - param[0].init_v_oct("Tone", ¬e); - param[1].init("Fine", &tune, tune, 0, 254); - param[2].init("Slew", &glide, 0, 0, 0.5f); - } - - void process(const ControlFrame &frame, OutputFrame &of) override - { - cv0 = frame.qz_voltage(this->io, (machine::PITCH_PER_OCTAVE * 2) + ((int)note - (DEFAULT_NOTE * machine::PITCH_PER_OCTAVE / 12))) + - (((int)tune - 128) << 2); - - ONE_POLE(cv, cv0, powf(1 - glide, 10)); - - of.push_voltage(&cv, 1); - - if ((frame.t % 50) == 0) - gfx::push_scope(scope, i, (float)cv / machine::PITCH_PER_OCTAVE * 4); - } - - int8_t scope[128] = {}; - uint8_t i = 0; - void display() override - { - sprintf(tmp, "OUT:%.2fV", ((float)cv / machine::PITCH_PER_OCTAVE)); - gfx::drawString(4 + 64, 32, tmp, 0); - gfx::drawEngineWithScope(this, scope, i, 50); - } -}; - -class LFOEngine : public Engine -{ - Parameter output; - ModulationSource *_mod = nullptr; - float cv = 0; - -public: - LFOEngine() : Engine(OUT_EQ_VOLT | TRIGGER_INPUT) - { - _mod = machine::create_modulation("LFO"); - if (_mod) - { - *_mod->param[0].value.u8p = 1; // set trigger source - param[0] = _mod->param[2]; // Freq - param[1] = _mod->param[1]; // Shape - // param[2] = _mod->param[3]; // Attenuverter - *_mod->param[3].value.fp = 0.5f; // param[2].name = "+-"; - - output.init(".", &cv, 0, -1.f, 1.f); - } - } - - ~LFOEngine() override - { - machine::mfree(_mod); - } - - int8_t scope[128] = {}; - uint8_t i = 0; - void process(const ControlFrame &frame, OutputFrame &of) override - { - cv = 0.f; - _mod->process(output, (ControlFrame &)frame); - - int32_t v = 5.f * cv * machine::PITCH_PER_OCTAVE; - of.push_voltage(&v, 1); - - if ((frame.t % 50) == 0) - gfx::push_scope(scope, i, cv * 10); - } - - void display() override - { - gfx::drawEngineWithScope(this, scope, i, 44); - } -}; - -class ADEnvelope : public Engine -{ - Parameter output; - ModulationSource *_mod = nullptr; - float cv = 0; - -public: - ADEnvelope() : Engine(OUT_EQ_VOLT | TRIGGER_INPUT) - { - _mod = machine::create_modulation("ENV"); - if (_mod) - { - *_mod->param[0].value.u8p = 0; // set trigger source - param[0] = _mod->param[1]; // Attack - param[0].name = "Attack"; - param[1] = _mod->param[2]; // Decay - param[1].name = "Decay"; - *_mod->param[3].value.fp = 0.5f; // Attenuverter param[2].name = "+-"; - output.init(".", &cv, 0, -1.f, 1.f); - } - } - - ~ADEnvelope() override - { - machine::mfree(_mod); - } - - int8_t scope[128] = {}; - float y = 0; - uint8_t i = 0; - void process(const ControlFrame &frame, OutputFrame &of) override - { - cv = 0.f; - _mod->process(output, (ControlFrame &)frame); - - int32_t v = 5.f * cv * machine::PITCH_PER_OCTAVE; - of.push_voltage(&v, 1); - - if ((frame.t % 50) == 0) - { - gfx::push_scope(scope, i, y * 20); - y = 0; - } - else - y = std::max(y, cv); - } - - void display() override - { - gfx::drawEngineWithScope(this, scope, i, 54); - } -}; - -class EFEngine : public Engine -{ - Parameter output; - ModulationSource *_mod = nullptr; - float cv = 0; - -public: - EFEngine() : Engine(OUT_EQ_VOLT | AUDIO_PROCESSOR_MONO) - { - _mod = machine::create_modulation("EF"); - if (_mod) - { - *_mod->param[0].value.u8p = 0; // set trigger source - param[0] = _mod->param[1]; // Attack - param[1] = _mod->param[2]; // Decay - *_mod->param[3].value.fp = 0.5f; // Attenuverter param[2].name = "+-"; - - output.init(".", &cv, 0, -1.f, 1.f); - } - } - - ~EFEngine() override - { - machine::mfree(_mod); - } - - int8_t scope[128] = {}; - uint8_t i = 0; - void process(const ControlFrame &frame, OutputFrame &of) override - { - cv = 0.f; - if (this->io->aux > 0) - { - *_mod->param[0].value.u8p = this->io->aux - 1; - _mod->process(output, (ControlFrame &)frame); - } - - int32_t v = 5.f * cv * machine::PITCH_PER_OCTAVE; - of.push_voltage(&v, 1); - - if ((frame.t % 50) == 0) - gfx::push_scope(scope, i, cv * 20); - } - - void display() override - { - gfx::drawEngineWithScope(this, scope, i, 54); - } -}; - -void init_cv_peaks(); - -void init_voltage() -{ - machine::add(CV, "V/OCT"); - machine::add(CV, "EnvGen_AD"); - init_cv_peaks(); - machine::add(CV, "LFO"); - machine::add(CV, "EnvFollower"); -} \ No newline at end of file