From 0cff3b0281873a97831dd51a03ad5cd92ce83c0e Mon Sep 17 00:00:00 2001 From: Ewan <915048+hemmer@users.noreply.github.com> Date: Tue, 8 Mar 2022 18:29:13 +0000 Subject: [PATCH] Noise Plethora (v2.1.0) (#31) * Noise Plethora * Initial release * Chopping Kinky * Upgraded to use improved DC blocker * Spring Reverb * Added bypass * Kickall * Allow trigger input and button to work independently * EvenVCO * Fix to remove pop when number of polyphony engines changes (Fixes #33 ) * Muxlicer * Chaining using reset now works correctly (Fixes #32 ) --- CHANGELOG.md | 19 +- LICENSE-dist.md | 35 + Makefile | 1 + plugin.json | 471 +-- res/components/Davies1900hLargeLightGrey.svg | 95 + .../Davies1900hLargeLightGrey_bg.svg | 98 + res/components/SwitchNarrowHoriz_0.svg | 154 + res/components/SwitchNarrowHoriz_1.svg | 149 + res/components/SwitchNarrow_1.svg | 193 +- res/components/SwitchNarrow_2.svg | 42 + res/fonts/OFL.txt | 94 + res/fonts/Segment7Standard.otf | Bin 0 -> 10464 bytes res/panels/NoisePlethora.svg | 2564 +++++++++++++++++ src/ABC.cpp | 17 + src/ChoppingKinky.cpp | 6 +- src/EvenVCO.cpp | 22 +- src/HexmixVCA.cpp | 12 +- src/Kickall.cpp | 10 +- src/Muxlicer.cpp | 86 +- src/NoisePlethora.cpp | 905 ++++++ src/PulseGenerator_4.hpp | 28 - src/Rampage.cpp | 1 - src/SpringReverb.cpp | 14 +- src/noise-plethora/LICENSE.md | 3 + src/noise-plethora/README.md | 17 + src/noise-plethora/plugins/Banks.cpp | 112 + src/noise-plethora/plugins/Banks.hpp | 44 + src/noise-plethora/plugins/Banks_Def.hpp | 53 + .../plugins/NoisePlethoraPlugin.hpp | 90 + src/noise-plethora/plugins/P_Atari.hpp | 70 + src/noise-plethora/plugins/P_BasuraTotal.hpp | 92 + src/noise-plethora/plugins/P_CrossModRing.hpp | 119 + .../plugins/P_FibonacciCluster.hpp | 265 ++ src/noise-plethora/plugins/P_PrimeCluster.hpp | 245 ++ src/noise-plethora/plugins/P_PrimeCnoise.hpp | 248 ++ .../plugins/P_Rwalk_BitCrushPW.hpp | 258 ++ src/noise-plethora/plugins/P_Rwalk_LFree.hpp | 156 + .../plugins/P_Rwalk_SineFMFlange.hpp | 199 ++ src/noise-plethora/plugins/P_S_H.hpp | 65 + src/noise-plethora/plugins/P_TeensyAlt.hpp | 64 + src/noise-plethora/plugins/P_TestPlugin.hpp | 85 + src/noise-plethora/plugins/P_TriFMcluster.hpp | 168 ++ .../plugins/P_WalkingFilomena.hpp | 305 ++ src/noise-plethora/plugins/P_WhiteNoise.hpp | 49 + src/noise-plethora/plugins/P_XModRingSine.hpp | 80 + .../plugins/P_arrayOnTheRocks.hpp | 137 + src/noise-plethora/plugins/P_basurilla.hpp | 108 + src/noise-plethora/plugins/P_clusterSaw.hpp | 206 ++ src/noise-plethora/plugins/P_crCluster2.hpp | 135 + .../plugins/P_existencelsPain.hpp | 146 + src/noise-plethora/plugins/P_grainGlitch.hpp | 91 + .../plugins/P_grainGlitchII.hpp | 78 + .../plugins/P_grainGlitchIII.hpp | 74 + .../plugins/P_partialCluster.hpp | 249 ++ .../plugins/P_phasingCluster.hpp | 294 ++ src/noise-plethora/plugins/P_pwCluster.hpp | 139 + src/noise-plethora/plugins/P_radioOhNo.hpp | 99 + src/noise-plethora/plugins/P_resonoise.hpp | 95 + src/noise-plethora/plugins/P_satanWorkout.hpp | 74 + .../plugins/P_sineFMcluster.hpp | 168 ++ src/noise-plethora/plugins/P_whoKnows.hpp | 148 + src/noise-plethora/plugins/P_xModRingSqr.hpp | 71 + .../plugins/ProgramSelector.hpp | 123 + src/noise-plethora/teensy-audio-device.png | Bin 0 -> 235313 bytes src/noise-plethora/teensy-gui.png | Bin 0 -> 179074 bytes .../teensy/TeensyAudioReplacements.hpp | 21 + src/noise-plethora/teensy/audio_core.hpp | 180 ++ src/noise-plethora/teensy/dspinst.h | 356 +++ .../teensy/effect_bitcrusher.cpp | 90 + src/noise-plethora/teensy/effect_bitcrusher.h | 58 + src/noise-plethora/teensy/effect_combine.cpp | 72 + src/noise-plethora/teensy/effect_combine.hpp | 53 + src/noise-plethora/teensy/effect_flange.cpp | 228 ++ src/noise-plethora/teensy/effect_flange.h | 53 + src/noise-plethora/teensy/effect_freeverb.cpp | 193 ++ src/noise-plethora/teensy/effect_freeverb.hpp | 90 + src/noise-plethora/teensy/effect_granular.cpp | 222 ++ src/noise-plethora/teensy/effect_granular.hpp | 77 + src/noise-plethora/teensy/effect_multiply.cpp | 48 + src/noise-plethora/teensy/effect_multiply.h | 35 + .../teensy/effect_wavefolder.cpp | 49 + .../teensy/effect_wavefolder.hpp | 32 + src/noise-plethora/teensy/filter_variable.cpp | 163 ++ src/noise-plethora/teensy/filter_variable.hpp | 108 + src/noise-plethora/teensy/mixer.hpp | 140 + src/noise-plethora/teensy/synth_dc.hpp | 201 ++ src/noise-plethora/teensy/synth_pinknoise.cpp | 147 + src/noise-plethora/teensy/synth_pinknoise.hpp | 59 + src/noise-plethora/teensy/synth_pwm.cpp | 89 + src/noise-plethora/teensy/synth_pwm.hpp | 61 + src/noise-plethora/teensy/synth_sine.hpp | 188 ++ src/noise-plethora/teensy/synth_waveform.hpp | 553 ++++ .../teensy/synth_whitenoise.cpp | 71 + .../teensy/synth_whitenoise.hpp | 51 + src/plugin.cpp | 1 + src/plugin.hpp | 96 +- 96 files changed, 13672 insertions(+), 351 deletions(-) create mode 100644 LICENSE-dist.md create mode 100644 res/components/Davies1900hLargeLightGrey.svg create mode 100644 res/components/Davies1900hLargeLightGrey_bg.svg create mode 100644 res/components/SwitchNarrowHoriz_0.svg create mode 100644 res/components/SwitchNarrowHoriz_1.svg create mode 100644 res/components/SwitchNarrow_2.svg create mode 100644 res/fonts/OFL.txt create mode 100644 res/fonts/Segment7Standard.otf create mode 100644 res/panels/NoisePlethora.svg create mode 100644 src/NoisePlethora.cpp delete mode 100644 src/PulseGenerator_4.hpp create mode 100644 src/noise-plethora/LICENSE.md create mode 100644 src/noise-plethora/README.md create mode 100644 src/noise-plethora/plugins/Banks.cpp create mode 100644 src/noise-plethora/plugins/Banks.hpp create mode 100644 src/noise-plethora/plugins/Banks_Def.hpp create mode 100644 src/noise-plethora/plugins/NoisePlethoraPlugin.hpp create mode 100644 src/noise-plethora/plugins/P_Atari.hpp create mode 100644 src/noise-plethora/plugins/P_BasuraTotal.hpp create mode 100644 src/noise-plethora/plugins/P_CrossModRing.hpp create mode 100644 src/noise-plethora/plugins/P_FibonacciCluster.hpp create mode 100644 src/noise-plethora/plugins/P_PrimeCluster.hpp create mode 100644 src/noise-plethora/plugins/P_PrimeCnoise.hpp create mode 100644 src/noise-plethora/plugins/P_Rwalk_BitCrushPW.hpp create mode 100644 src/noise-plethora/plugins/P_Rwalk_LFree.hpp create mode 100644 src/noise-plethora/plugins/P_Rwalk_SineFMFlange.hpp create mode 100644 src/noise-plethora/plugins/P_S_H.hpp create mode 100644 src/noise-plethora/plugins/P_TeensyAlt.hpp create mode 100644 src/noise-plethora/plugins/P_TestPlugin.hpp create mode 100644 src/noise-plethora/plugins/P_TriFMcluster.hpp create mode 100644 src/noise-plethora/plugins/P_WalkingFilomena.hpp create mode 100644 src/noise-plethora/plugins/P_WhiteNoise.hpp create mode 100644 src/noise-plethora/plugins/P_XModRingSine.hpp create mode 100644 src/noise-plethora/plugins/P_arrayOnTheRocks.hpp create mode 100644 src/noise-plethora/plugins/P_basurilla.hpp create mode 100644 src/noise-plethora/plugins/P_clusterSaw.hpp create mode 100644 src/noise-plethora/plugins/P_crCluster2.hpp create mode 100644 src/noise-plethora/plugins/P_existencelsPain.hpp create mode 100644 src/noise-plethora/plugins/P_grainGlitch.hpp create mode 100644 src/noise-plethora/plugins/P_grainGlitchII.hpp create mode 100644 src/noise-plethora/plugins/P_grainGlitchIII.hpp create mode 100644 src/noise-plethora/plugins/P_partialCluster.hpp create mode 100644 src/noise-plethora/plugins/P_phasingCluster.hpp create mode 100644 src/noise-plethora/plugins/P_pwCluster.hpp create mode 100644 src/noise-plethora/plugins/P_radioOhNo.hpp create mode 100644 src/noise-plethora/plugins/P_resonoise.hpp create mode 100644 src/noise-plethora/plugins/P_satanWorkout.hpp create mode 100644 src/noise-plethora/plugins/P_sineFMcluster.hpp create mode 100644 src/noise-plethora/plugins/P_whoKnows.hpp create mode 100644 src/noise-plethora/plugins/P_xModRingSqr.hpp create mode 100644 src/noise-plethora/plugins/ProgramSelector.hpp create mode 100644 src/noise-plethora/teensy-audio-device.png create mode 100644 src/noise-plethora/teensy-gui.png create mode 100644 src/noise-plethora/teensy/TeensyAudioReplacements.hpp create mode 100644 src/noise-plethora/teensy/audio_core.hpp create mode 100644 src/noise-plethora/teensy/dspinst.h create mode 100644 src/noise-plethora/teensy/effect_bitcrusher.cpp create mode 100644 src/noise-plethora/teensy/effect_bitcrusher.h create mode 100644 src/noise-plethora/teensy/effect_combine.cpp create mode 100644 src/noise-plethora/teensy/effect_combine.hpp create mode 100644 src/noise-plethora/teensy/effect_flange.cpp create mode 100644 src/noise-plethora/teensy/effect_flange.h create mode 100644 src/noise-plethora/teensy/effect_freeverb.cpp create mode 100644 src/noise-plethora/teensy/effect_freeverb.hpp create mode 100644 src/noise-plethora/teensy/effect_granular.cpp create mode 100644 src/noise-plethora/teensy/effect_granular.hpp create mode 100644 src/noise-plethora/teensy/effect_multiply.cpp create mode 100644 src/noise-plethora/teensy/effect_multiply.h create mode 100644 src/noise-plethora/teensy/effect_wavefolder.cpp create mode 100644 src/noise-plethora/teensy/effect_wavefolder.hpp create mode 100644 src/noise-plethora/teensy/filter_variable.cpp create mode 100644 src/noise-plethora/teensy/filter_variable.hpp create mode 100644 src/noise-plethora/teensy/mixer.hpp create mode 100644 src/noise-plethora/teensy/synth_dc.hpp create mode 100644 src/noise-plethora/teensy/synth_pinknoise.cpp create mode 100644 src/noise-plethora/teensy/synth_pinknoise.hpp create mode 100644 src/noise-plethora/teensy/synth_pwm.cpp create mode 100644 src/noise-plethora/teensy/synth_pwm.hpp create mode 100644 src/noise-plethora/teensy/synth_sine.hpp create mode 100644 src/noise-plethora/teensy/synth_waveform.hpp create mode 100644 src/noise-plethora/teensy/synth_whitenoise.cpp create mode 100644 src/noise-plethora/teensy/synth_whitenoise.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index daa1853..9575353 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,24 @@ # Change Log -## v2.0.0 (unreleased) +## v2.1.0 + * Noise Plethora + * Initial release + * Chopping Kinky + * Upgraded to use improved DC blocker + * Spring Reverb + * Added bypass + * Kickall + * Allow trigger input and button to work independently + * EvenVCO + * Fix to remove pop when number of polyphony engines changes + * Muxlicer + * Chaining using reset now works correctly + +## v2.0.0 * update to Rack 2 API (added tooltips, bypass, removed boilerplate etc) + * UI overhaul -## v1.2.0 (unreleased) +## v1.2.0 * Released new modules: Muxlicer, Mex, Morphader, VC ADSR, Sampling Modulator, ST Mix * Removed DC offset from EvenVCO pulse output diff --git a/LICENSE-dist.md b/LICENSE-dist.md new file mode 100644 index 0000000..9e70f02 --- /dev/null +++ b/LICENSE-dist.md @@ -0,0 +1,35 @@ +# Licenses of libraries used in Befaco for VCV Rack + +## Teensy + +``` + Audio Library for Teensy 3.X + Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com + + Development of this audio library was funded by PJRC.COM, LLC by sales of + Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + open source software by purchasing Teensy or other PJRC products. + + 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, development funding 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. + + ``` + +## Befaco + +Original Noise Plethora plugins were licensed under GPL v3 or later, see LICENSE-GPLv3.txt. diff --git a/Makefile b/Makefile index 38d52b6..5ee49dc 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ RACK_DIR ?= ../.. SOURCES += $(wildcard src/*.cpp) +SOURCES += $(wildcard src/noise-plethora/*/*.cpp) DISTRIBUTABLES += $(wildcard LICENSE*) res diff --git a/plugin.json b/plugin.json index 5abef87..c34486f 100644 --- a/plugin.json +++ b/plugin.json @@ -1,231 +1,242 @@ -{ - "slug": "Befaco", - "version": "2.0.0", - "license": "GPL-3.0-or-later", - "name": "Befaco", - "brand": "Befaco", - "author": "VCV, Ewan Hemingway", - "authorEmail": "support@vcvrack.com", - "pluginUrl": "https://vcvrack.com/Befaco", - "authorUrl": "https://vcvrack.com/", - "sourceUrl": "https://github.com/VCVRack/Befaco", - "changelogUrl": "https://github.com/VCVRack/Befaco/blob/v1/CHANGELOG.md", - "modules": [ - { - "slug": "EvenVCO", - "name": "Even VCO", - "description": "Oscillator including even-harmonic waveform", - "manualUrl": "https://www.befaco.org/even-vco/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-even-vco-", - "tags": [ - "VCO", - "Hardware clone", - "Polyphonic" - ] - }, - { - "slug": "Rampage", - "name": "Rampage", - "description": "Dual ramp generator", - "manualUrl": "https://www.befaco.org/rampage-2/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-rampage", - "tags": [ - "Function Generator", - "Logic", - "Slew Limiter", - "Envelope Follower", - "Dual", - "Hardware clone", - "Polyphonic" - ] - }, - { - "slug": "ABC", - "name": "A*B+C", - "description": "Dual four-quadrant multiplier with VC offset", - "manualUrl": "https://www.befaco.org/abc/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-a-b-c", - "tags": [ - "Ring Modulator", - "Attenuator", - "Dual", - "Hardware clone", - "Polyphonic" - ] - }, - { - "slug": "SpringReverb", - "name": "Spring Reverb", - "description": "Spring reverb tank driver", - "manualUrl": "https://www.befaco.org/spring-reverb/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-spring-reverb-", - "tags": [ - "Reverb", - "Hardware clone" - ] - }, - { - "slug": "Mixer", - "name": "Mixer", - "description": "Four-channel mixer for audio or CV", - "manualUrl": "https://www.befaco.org/mixer-2/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-mixer-", - "tags": [ - "Mixer", - "Hardware clone", - "Polyphonic" - ] - }, - { - "slug": "SlewLimiter", - "name": "Slew Limiter", - "description": "Voltage controlled slew limiter, AKA lag processor", - "manualUrl": "https://www.befaco.org/slew-limiter/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-vc-slew-limiter-", - "tags": [ - "Slew Limiter", - "Envelope Follower", - "Hardware clone", - "Polyphonic" - ] - }, - { - "slug": "DualAtenuverter", - "name": "Dual Atenuverter", - "description": "Attenuates, inverts, and applies offset to a signal", - "manualUrl": "https://www.befaco.org/dual-atenuverter/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-dual-atenuverter-", - "tags": [ - "Attenuator", - "Dual", - "Hardware clone", - "Polyphonic" - ] - }, - { - "slug": "Percall", - "name": "Percall", - "description": "Percussive Envelope Generator", - "manualUrl": "http://www.befaco.org/percall/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-percall", - "tags": [ - "Envelope generator", - "Mixer", - "Polyphonic", - "Hardware clone", - "Quad" - ] - }, - { - "slug": "HexmixVCA", - "name": "Hex Mix VCA", - "description": "Six channel VCA with response curve range from logarithmic to linear and to exponential", - "manualUrl": "https://www.befaco.org/hexmix-vca/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-hexmix-vca", - "tags": [ - "Mixer", - "Hardware clone", - "Polyphonic", - "VCA" - ] - }, - { - "slug": "ChoppingKinky", - "name": "Chopping Kinky", - "description": "Voltage controllable, dual channel wavefolder", - "manualUrl": "https://www.befaco.org/chopping-kinky/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-chopping-kinky", - "tags": [ - "Dual", - "Hardware clone", - "Voltage-controlled amplifier", - "Waveshaper" - ] - }, - { - "slug": "Kickall", - "name": "Kickall", - "description": "Bassdrum module, with pitch and volume envelopes", - "manualUrl": "https://www.befaco.org/kickall-2/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-kickall", - "tags": [ - "Drum", - "Hardware clone", - "Synth voice" - ] - }, - { - "slug": "SamplingModulator", - "name": "Sampling Modulator", - "description": "Multi-function module that lies somewhere between a VCO, a Sample & Hold, and an 8 step trigger sequencer", - "manualUrl": "https://www.befaco.org/sampling-modulator/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-sampling-modulator-", - "tags": [ - "Clock generator", - "Hardware clone", - "Oscillator", - "Sample and hold" - ] - }, - { - "slug": "Morphader", - "name": "Morphader", - "description": "Multichannel CV/Audio crossfader", - "manualUrl": "https://www.befaco.org/morphader-2/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-morphader", - "tags": [ - "Controller", - "Hardware clone", - "Mixer", - "Polyphonic", - "Quad" - ] - }, - { - "slug": "ADSR", - "name": "ADSR", - "description": "ADSR envelope generator with gate output on each stage, plus variable shape", - "manualUrl": "https://www.befaco.org/vc-adsr/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-vc-adsr", - "tags": [ - "Envelope generator", - "Hardware clone" - ] - }, - { - "slug": "STMix", - "name": "STMix", - "description": "A compact 4 channel stereo mixer with an auxiliary input", - "manualUrl": "https://www.befaco.org/stmix/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-stmix-", - "tags": [ - "Hardware clone", - "Mixer", - "Polyphonic" - ] - }, - { - "slug": "Muxlicer", - "name": "Muxlicer", - "description": "VC adressable sequential switch and sequencer", - "manualUrl": "https://www.befaco.org/muxlicer-2/", - "modularGridUrl": "https://www.modulargrid.net/e/befaco-muxlicer", - "tags": [ - "Clock generator", - "Hardware clone", - "Polyphonic", - "Sequencer", - "Switch" - ] - }, - { - "slug": "Mex", - "name": "Mex", - "description": "Gate Expander for Befaco Muxlicer", - "tags": [ - "Expander", - "Hardware clone" - ] - } - ] +{ + "slug": "Befaco", + "version": "2.1.0", + "license": "GPL-3.0-or-later", + "name": "Befaco", + "brand": "Befaco", + "author": "VCV, Ewan Hemingway", + "authorEmail": "support@vcvrack.com", + "pluginUrl": "https://vcvrack.com/Befaco", + "authorUrl": "https://vcvrack.com/", + "sourceUrl": "https://github.com/VCVRack/Befaco", + "changelogUrl": "https://github.com/VCVRack/Befaco/blob/v2/CHANGELOG.md", + "modules": [ + { + "slug": "EvenVCO", + "name": "Even VCO", + "description": "Oscillator including even-harmonic waveform", + "manualUrl": "https://www.befaco.org/even-vco/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-even-vco-", + "tags": [ + "VCO", + "Hardware clone", + "Polyphonic" + ] + }, + { + "slug": "Rampage", + "name": "Rampage", + "description": "Dual ramp generator", + "manualUrl": "https://www.befaco.org/rampage-2/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-rampage", + "tags": [ + "Function Generator", + "Logic", + "Slew Limiter", + "Envelope Follower", + "Dual", + "Hardware clone", + "Polyphonic" + ] + }, + { + "slug": "ABC", + "name": "A*B+C", + "description": "Dual four-quadrant multiplier with VC offset", + "manualUrl": "https://www.befaco.org/abc/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-a-b-c", + "tags": [ + "Ring Modulator", + "Attenuator", + "Dual", + "Hardware clone", + "Polyphonic" + ] + }, + { + "slug": "SpringReverb", + "name": "Spring Reverb", + "description": "Spring reverb tank driver", + "manualUrl": "https://www.befaco.org/spring-reverb/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-spring-reverb-", + "tags": [ + "Reverb", + "Hardware clone" + ] + }, + { + "slug": "Mixer", + "name": "Mixer", + "description": "Four-channel mixer for audio or CV", + "manualUrl": "https://www.befaco.org/mixer-2/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-mixer-", + "tags": [ + "Mixer", + "Hardware clone", + "Polyphonic" + ] + }, + { + "slug": "SlewLimiter", + "name": "Slew Limiter", + "description": "Voltage controlled slew limiter, AKA lag processor", + "manualUrl": "https://www.befaco.org/slew-limiter/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-vc-slew-limiter-", + "tags": [ + "Slew Limiter", + "Envelope Follower", + "Hardware clone", + "Polyphonic" + ] + }, + { + "slug": "DualAtenuverter", + "name": "Dual Atenuverter", + "description": "Attenuates, inverts, and applies offset to a signal", + "manualUrl": "https://www.befaco.org/dual-atenuverter/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-dual-atenuverter-", + "tags": [ + "Attenuator", + "Dual", + "Hardware clone", + "Polyphonic" + ] + }, + { + "slug": "Percall", + "name": "Percall", + "description": "Percussive Envelope Generator", + "manualUrl": "http://www.befaco.org/percall/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-percall", + "tags": [ + "Envelope generator", + "Mixer", + "Polyphonic", + "Hardware clone", + "Quad" + ] + }, + { + "slug": "HexmixVCA", + "name": "Hex Mix VCA", + "description": "Six channel VCA with response curve range from logarithmic to linear and to exponential", + "manualUrl": "https://www.befaco.org/hexmix-vca/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-hexmix-vca", + "tags": [ + "Mixer", + "Hardware clone", + "Polyphonic", + "VCA" + ] + }, + { + "slug": "ChoppingKinky", + "name": "Chopping Kinky", + "description": "Voltage controllable, dual channel wavefolder", + "manualUrl": "https://www.befaco.org/chopping-kinky/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-chopping-kinky", + "tags": [ + "Dual", + "Hardware clone", + "Voltage-controlled amplifier", + "Waveshaper" + ] + }, + { + "slug": "Kickall", + "name": "Kickall", + "description": "Bassdrum module, with pitch and volume envelopes", + "manualUrl": "https://www.befaco.org/kickall-2/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-kickall", + "tags": [ + "Drum", + "Hardware clone", + "Synth voice" + ] + }, + { + "slug": "SamplingModulator", + "name": "Sampling Modulator", + "description": "Multi-function module that lies somewhere between a VCO, a Sample & Hold, and an 8 step trigger sequencer", + "manualUrl": "https://www.befaco.org/sampling-modulator/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-sampling-modulator-", + "tags": [ + "Clock generator", + "Hardware clone", + "Oscillator", + "Sample and hold" + ] + }, + { + "slug": "Morphader", + "name": "Morphader", + "description": "Multichannel CV/Audio crossfader", + "manualUrl": "https://www.befaco.org/morphader-2/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-morphader", + "tags": [ + "Controller", + "Hardware clone", + "Mixer", + "Polyphonic", + "Quad" + ] + }, + { + "slug": "ADSR", + "name": "ADSR", + "description": "ADSR envelope generator with gate output on each stage, plus variable shape", + "manualUrl": "https://www.befaco.org/vc-adsr/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-vc-adsr", + "tags": [ + "Envelope generator", + "Hardware clone" + ] + }, + { + "slug": "STMix", + "name": "STMix", + "description": "A compact 4 channel stereo mixer with an auxiliary input", + "manualUrl": "https://www.befaco.org/stmix/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-stmix-", + "tags": [ + "Hardware clone", + "Mixer", + "Polyphonic" + ] + }, + { + "slug": "Muxlicer", + "name": "Muxlicer", + "description": "VC adressable sequential switch and sequencer", + "manualUrl": "https://www.befaco.org/muxlicer-2/", + "modularGridUrl": "https://www.modulargrid.net/e/befaco-muxlicer", + "tags": [ + "Clock generator", + "Hardware clone", + "Polyphonic", + "Sequencer", + "Switch" + ] + }, + { + "slug": "Mex", + "name": "Mex", + "description": "Gate Expander for Befaco Muxlicer", + "tags": [ + "Expander", + "Hardware clone" + ] + }, + { + "slug": "NoisePlethora", + "name": "Noise Plethora", + "description": "Multitimbral noise monster", + "tags": [ + "Dual", + "Filter", + "Hardware clone", + "Noise" + ] + } + ] } \ No newline at end of file diff --git a/res/components/Davies1900hLargeLightGrey.svg b/res/components/Davies1900hLargeLightGrey.svg new file mode 100644 index 0000000..4964f7d --- /dev/null +++ b/res/components/Davies1900hLargeLightGrey.svg @@ -0,0 +1,95 @@ + +image/svg+xml + + + + + + + + + + + + + + + diff --git a/res/components/Davies1900hLargeLightGrey_bg.svg b/res/components/Davies1900hLargeLightGrey_bg.svg new file mode 100644 index 0000000..0ea8575 --- /dev/null +++ b/res/components/Davies1900hLargeLightGrey_bg.svg @@ -0,0 +1,98 @@ + +image/svg+xml + + + + + + + + + + + + + diff --git a/res/components/SwitchNarrowHoriz_0.svg b/res/components/SwitchNarrowHoriz_0.svg new file mode 100644 index 0000000..01add0b --- /dev/null +++ b/res/components/SwitchNarrowHoriz_0.svg @@ -0,0 +1,154 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/components/SwitchNarrowHoriz_1.svg b/res/components/SwitchNarrowHoriz_1.svg new file mode 100644 index 0000000..35ba7d4 --- /dev/null +++ b/res/components/SwitchNarrowHoriz_1.svg @@ -0,0 +1,149 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/components/SwitchNarrow_1.svg b/res/components/SwitchNarrow_1.svg index 3326265..695c0ae 100644 --- a/res/components/SwitchNarrow_1.svg +++ b/res/components/SwitchNarrow_1.svg @@ -1,42 +1,151 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/components/SwitchNarrow_2.svg b/res/components/SwitchNarrow_2.svg new file mode 100644 index 0000000..3326265 --- /dev/null +++ b/res/components/SwitchNarrow_2.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/fonts/OFL.txt b/res/fonts/OFL.txt new file mode 100644 index 0000000..8e46b9b --- /dev/null +++ b/res/fonts/OFL.txt @@ -0,0 +1,94 @@ +Copyright (c) 2014, Cedric Knight , +with Reserved Font Name "Segment7". + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/res/fonts/Segment7Standard.otf b/res/fonts/Segment7Standard.otf new file mode 100644 index 0000000000000000000000000000000000000000..7429b0d7e62c0e7f33b0b8893bb343d4af50c8c2 GIT binary patch literal 10464 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 literal 0 HcmV?d00001 diff --git a/res/panels/NoisePlethora.svg b/res/panels/NoisePlethora.svg new file mode 100644 index 0000000..a0e2728 --- /dev/null +++ b/res/panels/NoisePlethora.svg @@ -0,0 +1,2564 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +   +   + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +   + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ABC.cpp b/src/ABC.cpp index ec9aa17..56ce2f7 100644 --- a/src/ABC.cpp +++ b/src/ABC.cpp @@ -45,6 +45,23 @@ struct ABC : Module { configParam(C1_LEVEL_PARAM, -1.0, 1.0, 0.0, "C1 Level"); configParam(B2_LEVEL_PARAM, -1.0, 1.0, 0.0, "B2 Level"); configParam(C2_LEVEL_PARAM, -1.0, 1.0, 0.0, "C2 Level"); + + configInput(A1_INPUT, "A1"); + configInput(B1_INPUT, "B1"); + configInput(C1_INPUT, "C1"); + configInput(A2_INPUT, "A2"); + configInput(B2_INPUT, "B2"); + configInput(C2_INPUT, "C2"); + + getInputInfo(B1_INPUT)->description = "Normalled to 5V"; + getInputInfo(C1_INPUT)->description = "Normalled to 10V"; + getInputInfo(B2_INPUT)->description = "Normalled to 5V"; + getInputInfo(C2_INPUT)->description = "Normalled to 10V"; + + configOutput(OUT1_OUTPUT, "Out 1"); + configOutput(OUT2_OUTPUT, "Out 2"); + + getOutputInfo(OUT1_OUTPUT)->description = "Normalled to Out 2"; } void processSection(const ProcessArgs& args, int& lastChannels, float_4* lastOut, ParamIds levelB, ParamIds levelC, InputIds inputA, InputIds inputB, InputIds inputC, OutputIds output, LightIds outLight) { diff --git a/src/ChoppingKinky.cpp b/src/ChoppingKinky.cpp index b66481f..67b1e5d 100644 --- a/src/ChoppingKinky.cpp +++ b/src/ChoppingKinky.cpp @@ -50,7 +50,7 @@ struct ChoppingKinky : Module { chowdsp::VariableOversampling<> oversampler[NUM_CHANNELS]; int oversamplingIndex = 2; // default is 2^oversamplingIndex == x4 oversampling - dsp::BiquadFilter blockDCFilter; + DCBlocker blockDCFilter; bool blockDC = false; ChoppingKinky() { @@ -68,6 +68,8 @@ struct ChoppingKinky : Module { configInput(CV_B_INPUT, "CV B (with attenuator)"); configInput(VCA_CV_B_INPUT, "CV B"); + getInputInfo(CV_B_INPUT)->description = "Normalled to CV A (with attenuator) Input"; + configOutput(OUT_CHOPP_OUTPUT, "Chopp"); configOutput(OUT_A_OUTPUT, "A"); configOutput(OUT_B_OUTPUT, "B"); @@ -81,7 +83,7 @@ struct ChoppingKinky : Module { void onSampleRateChange() override { float sampleRate = APP->engine->getSampleRate(); - blockDCFilter.setParameters(dsp::BiquadFilter::HIGHPASS, 10.3f / sampleRate, M_SQRT1_2, 1.0f); + blockDCFilter.setFrequency(22.05 / sampleRate); for (int channel_idx = 0; channel_idx < NUM_CHANNELS; channel_idx++) { oversampler[channel_idx].setOversamplingIndex(oversamplingIndex); diff --git a/src/EvenVCO.cpp b/src/EvenVCO.cpp index 4a05058..afff33a 100644 --- a/src/EvenVCO.cpp +++ b/src/EvenVCO.cpp @@ -120,8 +120,10 @@ struct EvenVCO : Module { phase[c / 4] += deltaPhase[c / 4]; } - // the next block can't be done with SIMD instructions: - for (int c = 0; c < channels; c++) { + // the next block can't be done with SIMD instructions, but should at least be completed with + // blocks of 4 (otherwise popping artfifacts are generated from invalid phase/oldPhase/deltaPhase) + const int channelsRoundedUpNearestFour = (1 + (channels - 1) / 4) * 4; + for (int c = 0; c < channelsRoundedUpNearestFour; c++) { if (oldPhase[c / 4].s[c % 4] < 0.5 && phase[c / 4].s[c % 4] >= 0.5) { float crossing = -(phase[c / 4].s[c % 4] - 0.5) / deltaPhase[c / 4].s[c % 4]; @@ -161,20 +163,13 @@ struct EvenVCO : Module { float_4 square[4] = {}; float_4 triOut[4] = {}; - for (int c = 0; c < channels; c++) { + for (int c = 0; c < channelsRoundedUpNearestFour; c++) { triSquareMinBlepOut[c / 4].s[c % 4] = triSquareMinBlep[c].process(); doubleSawMinBlepOut[c / 4].s[c % 4] = doubleSawMinBlep[c].process(); sawMinBlepOut[c / 4].s[c % 4] = sawMinBlep[c].process(); squareMinBlepOut[c / 4].s[c % 4] = squareMinBlep[c].process(); } - // Outputs - outputs[TRI_OUTPUT].setChannels(channels); - outputs[SINE_OUTPUT].setChannels(channels); - outputs[EVEN_OUTPUT].setChannels(channels); - outputs[SAW_OUTPUT].setChannels(channels); - outputs[SQUARE_OUTPUT].setChannels(channels); - for (int c = 0; c < channels; c += 4) { triSquare[c / 4] = simd::ifelse((phase[c / 4] < 0.5f), -1.f, +1.f); @@ -208,6 +203,13 @@ struct EvenVCO : Module { outputs[SAW_OUTPUT].setVoltageSimd(saw[c / 4], c); outputs[SQUARE_OUTPUT].setVoltageSimd(square[c / 4], c); } + + // Outputs + outputs[TRI_OUTPUT].setChannels(channels); + outputs[SINE_OUTPUT].setChannels(channels); + outputs[EVEN_OUTPUT].setChannels(channels); + outputs[SAW_OUTPUT].setChannels(channels); + outputs[SQUARE_OUTPUT].setChannels(channels); } }; diff --git a/src/HexmixVCA.cpp b/src/HexmixVCA.cpp index eeb2c1d..e35de99 100644 --- a/src/HexmixVCA.cpp +++ b/src/HexmixVCA.cpp @@ -42,8 +42,16 @@ struct HexmixVCA : Module { HexmixVCA() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); for (int i = 0; i < numRows; ++i) { - configParam(SHAPE_PARAM + i, -1.f, 1.f, 0.f, string::f("Channel %d VCA response", i)); - configParam(VOL_PARAM + i, 0.f, 1.f, 1.f, string::f("Channel %d output level", i)); + configParam(SHAPE_PARAM + i, -1.f, 1.f, 0.f, string::f("Channel %d VCA response", i + 1)); + configParam(VOL_PARAM + i, 0.f, 1.f, 1.f, string::f("Channel %d output level", i + 1)); + + configInput(IN_INPUT + i, string::f("Channel %d", i + 1)); + configInput(CV_INPUT + i, string::f("Gain %d", i + 1)); + configOutput(OUT_OUTPUT + i, string::f("Channel %d", i + 1)); + + getInputInfo(CV_INPUT + i)->description = "Normalled to 10V"; + + configBypass(IN_INPUT + i, OUT_OUTPUT + i); } cvDivider.setDivision(16); diff --git a/src/Kickall.cpp b/src/Kickall.cpp index ba4067c..fc48fea 100644 --- a/src/Kickall.cpp +++ b/src/Kickall.cpp @@ -40,7 +40,8 @@ struct Kickall : Module { ADEnvelope volume; ADEnvelope pitch; - dsp::SchmittTrigger trigger; + dsp::SchmittTrigger gateTrigger; + dsp::BooleanTrigger buttonTrigger; static const int UPSAMPLE = 8; chowdsp::Oversampling oversampler; @@ -69,7 +70,7 @@ struct Kickall : Module { configOutput(OUT_OUTPUT, "Kick"); configLight(ENV_LIGHT, "Volume envelope"); - + // calculate up/downsampling rates onSampleRateChange(); } @@ -80,7 +81,10 @@ struct Kickall : Module { void process(const ProcessArgs& args) override { // TODO: check values - if (trigger.process(inputs[TRIGG_INPUT].getVoltage() / 2.0f + params[TRIGG_BUTTON_PARAM].getValue() * 10.0)) { + const bool risingEdgeGate = gateTrigger.process(inputs[TRIGG_INPUT].getVoltage() / 2.0f); + const bool buttonTriggered = buttonTrigger.process(params[TRIGG_BUTTON_PARAM].getValue()); + // can be triggered by either rising edge on trigger in, or a button press + if (risingEdgeGate || buttonTriggered) { volume.trigger(); pitch.trigger(); } diff --git a/src/Muxlicer.cpp b/src/Muxlicer.cpp index 8f24a0e..1cc2172 100644 --- a/src/Muxlicer.cpp +++ b/src/Muxlicer.cpp @@ -254,9 +254,21 @@ struct Muxlicer : Module { uint32_t runIndex; // which step are we on (0 to 7) uint32_t addressIndex = 0; - bool playHeadHasReset = false; bool tapped = false; + enum ResetStatus { + RESET_NOT_REQUESTED, + RESET_AND_PLAY_ONCE, + RESET_AND_PLAY + }; + // Used to track if a reset has been triggered. Can be from the CV input, or the momentary switch. Note + // that behaviour depends on if the Muxlicer is clocked or not. If clocked, the playhead resets but waits + // for the next clock tick to start. If not clocked, then the sequence will start immediately (i.e. the + // internal clock will be synced at the point where `resetIsRequested` is first true. + ResetStatus resetRequested = RESET_NOT_REQUESTED; + // used to detect when `resetRequested` first becomes active + dsp::BooleanTrigger detectResetTrigger; + // used to track the clock (e.g. if external clock is not connected). NOTE: this clock // is defined _prior_ to any clock division/multiplication logic float internalClockProgress = 0.f; @@ -266,7 +278,6 @@ struct Muxlicer : Module { dsp::SchmittTrigger inputClockTrigger; // to detect incoming clock pulses dsp::BooleanTrigger mainClockTrigger; // to detect when divided/multiplied version of the clock signal has rising edge dsp::SchmittTrigger resetTrigger; // to detect the reset signal - dsp::PulseGenerator resetTimer; // leave a grace period before advancing the step dsp::PulseGenerator endOfCyclePulse; // fire a signal at the end of cycle dsp::BooleanTrigger tapTempoTrigger; // to only trigger tap tempo when push is first detected MultDivClock mainClockMultDiv; // to produce a divided/multiplied version of the (internal or external) clock signal @@ -430,7 +441,21 @@ struct Muxlicer : Module { internalClockLength = tapTime; } tapTime = 0; - internalClockProgress = 0; + internalClockProgress = 0.f; + } + + // If we get a reset signal (which can come from CV or various modes of the switch), and the clock has only + // just started to tick (internalClockProgress < 1ms), we assume that the reset signal is slightly delayed + // due to the 1 sample delay that Rack introduces. If this is the case, the internal clock trigger detector, + // `detectResetTrigger`, which advances the sequence, will not be "primed" to detect a rising edge for another + // whole clock tick, meaning the first step is repeated. See: https://github.com/VCVRack/Befaco/issues/32 + // Also see https://vcvrack.com/manual/VoltageStandards#Timing for 0.001 seconds justification. + if (detectResetTrigger.process(resetRequested != RESET_NOT_REQUESTED) && internalClockProgress < 1e-3) { + // NOTE: the sequence must also be stopped for this to come into effect. In hardware, if the Nth step Gate Out + // is patched back into the reset, that step should complete before the sequence restarts. + if (playState == STATE_STOPPED) { + mainClockTrigger.state = false; + } } tapTime += args.sampleTime; internalClockProgress += args.sampleTime; @@ -451,20 +476,33 @@ struct Muxlicer : Module { // so we must use a BooleanTrigger on the divided/mult'd signal in order to detect rising edge / when to advance the sequence const bool dividedMultipliedClockPulseReceived = mainClockTrigger.process(mainClockMultDiv.process(args.sampleTime, clockPulseReceived)); - // see https://vcvrack.com/manual/VoltageStandards#Timing - const bool resetGracePeriodActive = resetTimer.process(args.sampleTime); - if (dividedMultipliedClockPulseReceived) { - if (isAddressInRunMode && !resetGracePeriodActive && playState != STATE_STOPPED) { + + if (resetRequested != RESET_NOT_REQUESTED) { + runIndex = 7; + + if (resetRequested == RESET_AND_PLAY) { + playState = STATE_PLAY; + } + else if (resetRequested == RESET_AND_PLAY_ONCE) { + playState = STATE_PLAY_ONCE; + + } + } + + if (isAddressInRunMode && playState != STATE_STOPPED) { + runIndex++; + if (runIndex >= SEQUENCE_LENGTH) { + runIndex = 0; + // the sequence resets by placing the play head at the final step (so that the next clock pulse // ticks over onto the first step) - so if we are on the final step _because_ we've reset, - // then don't fire EOC - if (playHeadHasReset) { - playHeadHasReset = false; - runIndex = 0; + // then don't fire EOC, just clear the reset status + if (resetRequested != RESET_NOT_REQUESTED) { + resetRequested = RESET_NOT_REQUESTED; } // otherwise we've naturally arrived at the last step so do fire EOC etc else { @@ -474,12 +512,10 @@ struct Muxlicer : Module { if (playState == STATE_PLAY_ONCE) { playState = STATE_STOPPED; } - else { - runIndex = 0; - } } } } + multiClock.reset(mainClockMultDiv.getEffectiveClockLength()); if (isAddressInRunMode) { @@ -569,13 +605,12 @@ struct Muxlicer : Module { const bool resetPulseInReceived = resetTrigger.process(rescale(inputs[RESET_INPUT].getVoltage(), 0.1f, 2.f, 0.f, 1.f)); if (resetPulseInReceived) { - playHeadHasReset = true; - runIndex = 8; - if (playState == STATE_STOPPED) { - playState = STATE_PLAY_ONCE; + switch (playState) { + case STATE_STOPPED: resetRequested = RESET_AND_PLAY_ONCE; break; + case STATE_PLAY_ONCE: resetRequested = RESET_AND_PLAY_ONCE; break; + case STATE_PLAY: resetRequested = RESET_AND_PLAY; break; } - resetTimer.trigger(); } // if the play switch has effectively been activated for the first time, @@ -583,19 +618,17 @@ struct Muxlicer : Module { const bool switchIsActive = params[PLAY_PARAM].getValue() != STATE_STOPPED; if (playStateTrigger.process(switchIsActive) && switchIsActive) { - // if we were stopped, check for activation (normal or one-shot) + // if we were stopped, check for activation (normal, up or one-shot, down) if (playState == STATE_STOPPED) { if (params[PLAY_PARAM].getValue() == STATE_PLAY) { - playState = STATE_PLAY; + resetRequested = RESET_AND_PLAY; } else if (params[PLAY_PARAM].getValue() == STATE_PLAY_ONCE) { - playState = STATE_PLAY_ONCE; - runIndex = 8; - playHeadHasReset = true; + resetRequested = RESET_AND_PLAY_ONCE; } } // otherwise we are in play mode (and we've not just held onto the play switch), - // so check for stop or reset + // so check for stop (switch up) or reset (switch down) else { // top switch will stop @@ -604,8 +637,7 @@ struct Muxlicer : Module { } // bottom will reset else if (params[PLAY_PARAM].getValue() == STATE_PLAY_ONCE) { - playHeadHasReset = true; - runIndex = 8; + resetRequested = RESET_AND_PLAY_ONCE; } } } diff --git a/src/NoisePlethora.cpp b/src/NoisePlethora.cpp new file mode 100644 index 0000000..e42e460 --- /dev/null +++ b/src/NoisePlethora.cpp @@ -0,0 +1,905 @@ +#include "plugin.hpp" +#include "noise-plethora/plugins/NoisePlethoraPlugin.hpp" +#include "noise-plethora/plugins/ProgramSelector.hpp" + +enum FilterMode { + LOWPASS, + HIGHPASS, + BANDPASS, + NUM_TYPES +}; + + +// Zavalishin 2018, "The Art of VA Filter Design", http://www.native-instruments.com/fileadmin/ni_media/downloads/pdf/VAFilterDesign_2.0.0a.pdf +// Section 6.7, adopted from BogAudio Saturator https://github.com/bogaudio/BogaudioModules/blob/master/src/dsp/signal.cpp +struct Saturator { + + // saturate input at around ~[-1, +1] with soft clipping + static float process(float sample) { + + if (sample < 0.0f) { + return -saturation(-sample); + } + return saturation(sample); + } +private: + + static float saturation(float sample) { + + const float limit = 1.05f; + const float y1 = 0.98765f; // (2*x - 1)/x**2 where x is 0.9. + // correction so that saturation(0) = 0 + const float offset = 0.0062522; // -0.5f + sqrtf(0.5f * 0.5f) / y1; + + float x = sample / limit; + float x1 = (x + 1.0f) * 0.5f; + + return limit * (offset + x1 - std::sqrt(x1 * x1 - y1 * x) * (1.0f / y1)); + } +}; + +// based on Chapter 4 of THE ART OF VA FILTER DESIGN and +// Chap 12.4 of "Designing Audio Effect Plugins in C++" Will Pirkle +class StateVariableFilter2ndOrder { +public: + + StateVariableFilter2ndOrder() { + setParameters(0.f, M_SQRT1_2); + } + + void setParameters(float fc, float q) { + // avoid repeated evaluations of tanh if not needed + if (fc != fcCached || q != qCached) { + + fcCached = fc; + qCached = q; + + const double g = std::tan(M_PI * fc); + const double R = 1.0f / (2 * q); + + alpha0 = 1.0 / (1.0 + 2.0 * R * g + g * g); + alpha = g; + rho = 2.0 * R + g; + } + } + + void process(float input) { + hp = (input - rho * mem1 - mem2) * alpha0; + bp = alpha * hp + mem1; + lp = alpha * bp + mem2; + mem1 = alpha * hp + bp; + mem2 = alpha * bp + lp; + } + + float output(FilterMode mode) { + switch (mode) { + case LOWPASS: return lp; + case HIGHPASS: return hp; + case BANDPASS: return bp; + default: return 0.0; + } + } + +private: + float alpha, alpha0, rho; + + float fcCached = -1.f, qCached = -1.f; + + float hp = 0.0f, bp = 0.0f, lp = 0.0f, mem1 = 0.0f, mem2 = 0.0f; +}; + +class StateVariableFilter4thOrder { + +public: + StateVariableFilter4thOrder() { + + } + + void setParameters(float fc, float q) { + float rootQ = std::sqrt(q); + stage1.setParameters(fc, rootQ); + stage2.setParameters(fc, rootQ); + } + + float process(float input, FilterMode mode) { + stage1.process(input); + float s1 = stage1.output(mode); + + stage2.process(s1); + float s2 = stage2.output(mode); + + return s2; + } + +private: + StateVariableFilter2ndOrder stage1, stage2; +}; + + +struct NoisePlethora : Module { + enum ParamIds { + // A params + X_A_PARAM, + Y_A_PARAM, + CUTOFF_A_PARAM, + RES_A_PARAM, + CUTOFF_CV_A_PARAM, + FILTER_TYPE_A_PARAM, + // misc + PROGRAM_PARAM, + // B params + X_B_PARAM, + Y_B_PARAM, + CUTOFF_B_PARAM, + RES_B_PARAM, + CUTOFF_CV_B_PARAM, + FILTER_TYPE_B_PARAM, + // C params + GRIT_PARAM, + RES_C_PARAM, + CUTOFF_C_PARAM, + CUTOFF_CV_C_PARAM, + FILTER_TYPE_C_PARAM, + SOURCE_C_PARAM, + NUM_PARAMS + }; + enum InputIds { + X_A_INPUT, + Y_A_INPUT, + CUTOFF_A_INPUT, + PROG_A_INPUT, + PROG_B_INPUT, + CUTOFF_B_INPUT, + X_B_INPUT, + Y_B_INPUT, + GRIT_INPUT, + CUTOFF_C_INPUT, + NUM_INPUTS + }; + enum OutputIds { + A_OUTPUT, + B_OUTPUT, + GRITTY_OUTPUT, + FILTERED_OUTPUT, + WHITE_OUTPUT, + NUM_OUTPUTS + }; + enum LightIds { + BANK_LIGHT, + NUM_LIGHTS + }; + + enum Section { + SECTION_A, + SECTION_B, + SECTION_C, + NUM_SECTIONS + }; + + enum ProgramKnobMode { + PROGRAM_MODE, + BANK_MODE + }; + ProgramKnobMode programKnobMode = PROGRAM_MODE; + // one full turn of the program knob corresponds to an increment of dialResolution to the bank/program + static constexpr int dialResolution = 8; + // variable to store what the program knob was prior to the start of dragging (used to calculate deltas) + float programKnobReferenceState = 0.f; + + // section A/B + bool bypassFilters = false; + std::shared_ptr algorithm[2]; // pointer to actual algorithm + std::string algorithmName[2]; // variable to cache which algorithm is active (after program CV applied) + + // filters for A/B + StateVariableFilter2ndOrder svfFilter[2]; + bool blockDC = true; + DCBlocker blockDCFilter[3]; + + ProgramSelector programSelector; // tracks banks and programs for both sections A/B, including which is the "active" section + ProgramSelector programSelectorWithCV; // as above, but also with CV for program applied as an offset - works like Plaits Model CV input + // UI / UX for A/B + std::string textDisplayA = " ", textDisplayB = " "; + bool isDisplayActiveA = false, isDisplayActiveB = false; + bool programButtonHeld = false; + bool programButtonDragged = false; + dsp::BooleanTrigger programHoldTrigger; + dsp::Timer programHoldTimer; + + dsp::PulseGenerator updateParamsTimer; + const float updateTimeSecs = 0.0029f; + + // section C + AudioSynthNoiseWhiteFloat whiteNoiseSource; + AudioSynthNoiseGritFloat gritNoiseSource; + StateVariableFilter4thOrder svfFilterC; + FilterMode typeMappingSVF[3] = {LOWPASS, BANDPASS, HIGHPASS}; + + NoisePlethora() { + config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configParam(X_A_PARAM, 0.f, 1.f, 0.5f, "XA"); + configParam(RES_A_PARAM, 0.f, 1.f, 0.f, "Resonance A"); + configParam(CUTOFF_A_PARAM, 0.f, 1.f, 1.f, "Cutoff A"); + configParam(Y_A_PARAM, 0.f, 1.f, 0.5f, "YA"); + configParam(CUTOFF_CV_A_PARAM, 0.f, 1.f, 0.f, "Cutoff CV A"); + configSwitch(FILTER_TYPE_A_PARAM, 0.f, 2.f, 0.f, "Filter type", {"Lowpass", "Bandpass", "Highpass"}); + configParam(PROGRAM_PARAM, -INFINITY, +INFINITY, 0.f, "Program/Bank selection"); + configSwitch(FILTER_TYPE_B_PARAM, 0.f, 2.f, 0.f, "Filter type", {"Lowpass", "Bandpass", "Highpass"}); + configParam(CUTOFF_CV_B_PARAM, 0.f, 1.f, 0.f, "Cutoff B"); + configParam(X_B_PARAM, 0.f, 1.f, 0.5f, "XB"); + configParam(CUTOFF_B_PARAM, 0.f, 1.f, 1.f, "Cutoff CV B"); + configParam(RES_B_PARAM, 0.f, 1.f, 0.f, "Resonance B"); + configParam(Y_B_PARAM, 0.f, 1.f, 0.5f, "YB"); + configSwitch(FILTER_TYPE_C_PARAM, 0.f, 2.f, 0.f, "Filter type", {"Lowpass", "Bandpass", "Highpass"}); + configParam(CUTOFF_C_PARAM, 0.f, 1.f, 1.f, "Cutoff C"); + configParam(GRIT_PARAM, 0.f, 1.f, 0.f, "Grit Quantity"); + configParam(RES_C_PARAM, 0.f, 1.f, 0.f, "Resonance C"); + configParam(CUTOFF_CV_C_PARAM, 0.f, 1.f, 0.f, "Cutoff CV C"); + configSwitch(SOURCE_C_PARAM, 0.f, 1.f, 0.f, "Filter source", {"Gritty", "White"}); + + configInput(X_A_INPUT, "XA CV"); + configInput(Y_A_INPUT, "YA CV"); + configInput(CUTOFF_A_INPUT, "Cutoff CV A"); + configInput(PROG_A_INPUT, "Program select A"); + configInput(PROG_B_INPUT, "Program select B"); + configInput(CUTOFF_B_INPUT, "Cutoff CV B"); + configInput(X_B_INPUT, "XB CV"); + configInput(Y_B_INPUT, "YB CV"); + configInput(GRIT_INPUT, "Grit Quantity CV"); + configInput(CUTOFF_C_INPUT, "Cutoff CV C"); + + configOutput(A_OUTPUT, "Algorithm A"); + configOutput(B_OUTPUT, "Algorithm B"); + configOutput(GRITTY_OUTPUT, "Gritty noise"); + configOutput(FILTERED_OUTPUT, "Filtered noise"); + configOutput(WHITE_OUTPUT, "White noise"); + + configLight(BANK_LIGHT, "Bank mode"); + + getInputInfo(PROG_A_INPUT)->description = "CV sums with active program (0.5V increments)"; + getInputInfo(PROG_B_INPUT)->description = "CV sums with active program (0.5V increments)"; + + setAlgorithm(SECTION_B, "radioOhNo"); + setAlgorithm(SECTION_A, "radioOhNo"); + onSampleRateChange(); + } + + void onReset(const ResetEvent& e) override { + setAlgorithm(SECTION_B, "radioOhNo"); + setAlgorithm(SECTION_A, "radioOhNo"); + Module::onReset(e); + } + + void onSampleRateChange() override { + // set ~20Hz DC blocker + const float fc = 22.05f / APP->engine->getSampleRate(); + + blockDCFilter[SECTION_A].setFrequency(fc); + blockDCFilter[SECTION_B].setFrequency(fc); + blockDCFilter[SECTION_C].setFrequency(fc); + + if (algorithm[SECTION_A]) { + algorithm[SECTION_A]->init(); + } + if (algorithm[SECTION_B]) { + algorithm[SECTION_B]->init(); + } + } + + void process(const ProcessArgs& args) override { + + // we only periodically update parameters of each algorithm (once per block, ~2.9ms at 44100Hz) + bool updateParams = false; + if (!updateParamsTimer.process(args.sampleTime)) { + updateParams = true; + updateParamsTimer.trigger(updateTimeSecs); + } + + // process A, B and C + processTopSection(SECTION_A, X_A_PARAM, Y_A_PARAM, + FILTER_TYPE_A_PARAM, CUTOFF_A_PARAM, CUTOFF_CV_A_PARAM, RES_A_PARAM, + PROG_A_INPUT, X_A_INPUT, Y_A_INPUT, CUTOFF_A_INPUT, A_OUTPUT, args, updateParams); + processTopSection(SECTION_B, X_B_PARAM, Y_B_PARAM, + FILTER_TYPE_B_PARAM, CUTOFF_B_PARAM, CUTOFF_CV_B_PARAM, RES_B_PARAM, + PROG_B_INPUT, X_B_INPUT, Y_B_INPUT, CUTOFF_B_INPUT, B_OUTPUT, args, updateParams); + processBottomSection(args); + + // UI + updateDataForLEDDisplay(); + processProgramBankKnobLogic(args); + } + + // process CV for section, specifically: work out the offset relative to the current + // program and see if this is a new algorithm + void processCVOffsets(Section SECTION, InputIds PROG_INPUT) { + + const int offset = 2 * inputs[PROG_INPUT].getVoltage(); + + const int bank = programSelector.getSection(SECTION).getBank(); + const int numProgramsForBank = getBankForIndex(bank).getSize(); + + const int programWithoutCV = programSelector.getSection(SECTION).getProgram(); + const int programWithCV = unsigned_modulo(programWithoutCV + offset, numProgramsForBank); + + // duplicate key settings to programSelectorWithCV (expect modified program) + programSelectorWithCV.setMode(programSelector.getMode()); + programSelectorWithCV.getSection(SECTION).setBank(bank); + programSelectorWithCV.getSection(SECTION).setProgram(programWithCV); + + const std::string newAlgorithmName = programSelectorWithCV.getSection(SECTION).getCurrentProgramName(); + + // this is just a caching check to avoid constantly re-initialisating the algorithms + if (newAlgorithmName != algorithmName[SECTION]) { + + algorithm[SECTION] = MyFactory::Instance()->Create(newAlgorithmName); + algorithmName[SECTION] = newAlgorithmName; + + if (algorithm[SECTION]) { + algorithm[SECTION]->init(); + } + else { + DEBUG("WARNING: Failed to initialise %s in programSelector", newAlgorithmName.c_str()); + } + } + } + + // exactly the same for A and B + void processTopSection(Section SECTION, ParamIds X_PARAM, ParamIds Y_PARAM, ParamIds FILTER_TYPE_PARAM, + ParamIds CUTOFF_PARAM, ParamIds CUTOFF_CV_PARAM, ParamIds RES_PARAM, + InputIds PROG_INPUT, InputIds X_INPUT, InputIds Y_INPUT, InputIds CUTOFF_INPUT, OutputIds OUTPUT, + const ProcessArgs& args, bool updateParams) { + + // periodically work out how CV should modify the current sections algorithm + if (updateParams) { + processCVOffsets(SECTION, PROG_INPUT); + } + + float out = 0.f; + if (algorithm[SECTION] && outputs[OUTPUT].isConnected()) { + float cvX = params[X_PARAM].getValue() + rescale(inputs[X_INPUT].getVoltage(), -10.f, +10.f, -1.f, 1.f); + float cvY = params[Y_PARAM].getValue() + rescale(inputs[Y_INPUT].getVoltage(), -10.f, +10.f, -1.f, 1.f); + + // update parameters of the algorithm + if (updateParams) { + algorithm[SECTION]->process(clamp(cvX, 0.f, 1.f), clamp(cvY, 0.f, 1.f)); + } + // process the audio graph + out = algorithm[SECTION]->processGraph(); + // each algorithm has a specific gain factor + out = out * programSelectorWithCV.getSection(SECTION).getCurrentProgramGain(); + + // if filters are active + if (!bypassFilters) { + + // set parameters + const float freqCV = std::pow(params[CUTOFF_CV_PARAM].getValue(), 2) * inputs[CUTOFF_INPUT].getVoltage(); + const float pitch = rescale(params[CUTOFF_PARAM].getValue(), 0, 1, -5.5, +5.5) + freqCV; + const float cutoff = clamp(dsp::FREQ_C4 * std::pow(2.f, pitch), 1.f, 20000.); + const float cutoffNormalised = clamp(cutoff / args.sampleRate, 0.f, 0.49f); + const float q = M_SQRT1_2 + std::pow(params[RES_PARAM].getValue(), 2) * 10.f; + const FilterMode mode = typeMappingSVF[(int) params[FILTER_TYPE_PARAM].getValue()]; + svfFilter[SECTION].setParameters(cutoffNormalised, q); + + // apply filter + svfFilter[SECTION].process(out); + // and retrieve relevant output + out = svfFilter[SECTION].output(mode); + } + + if (blockDC) { + // cascaded Biquad (4th order highpass at ~20Hz) + out = blockDCFilter[SECTION].process(out); + } + } + + outputs[OUTPUT].setVoltage(Saturator::process(out) * 5.f); + } + + // process section C + void processBottomSection(const ProcessArgs& args) { + + float gritCv = rescale(clamp(inputs[GRIT_INPUT].getVoltage(), -10.f, 10.f), -10.f, 10.f, -1.f, 1.f); + float gritAmount = clamp(1.f - params[GRIT_PARAM].getValue() - gritCv, 0.f, 1.f); + float gritFrequency = 0.1 + std::pow(gritAmount, 2) * 20000; + gritNoiseSource.setDensity(gritFrequency); + float gritNoise = gritNoiseSource.process(args.sampleTime); + outputs[GRITTY_OUTPUT].setVoltage(gritNoise * 5.f); + + float whiteNoise = whiteNoiseSource.process(); + outputs[WHITE_OUTPUT].setVoltage(whiteNoise * 5.f); + + float out = 0.f; + if (outputs[FILTERED_OUTPUT].isConnected() && !bypassFilters) { + + const float freqCV = std::pow(params[CUTOFF_CV_C_PARAM].getValue(), 2) * inputs[CUTOFF_C_INPUT].getVoltage(); + const float pitch = rescale(params[CUTOFF_C_PARAM].getValue(), 0, 1, -5.f, +6.4f) + freqCV; + const float cutoff = clamp(dsp::FREQ_C4 * std::pow(2.f, pitch), 1.f, 44100. / 2.f); + const float cutoffNormalised = clamp(cutoff / args.sampleRate, 0.f, 0.49f); + const float Q = 0.5 + std::pow(params[RES_C_PARAM].getValue(), 2) * 20.f; + const FilterMode mode = typeMappingSVF[(int) params[FILTER_TYPE_C_PARAM].getValue()]; + svfFilterC.setParameters(cutoffNormalised, Q); + + float toFilter = params[SOURCE_C_PARAM].getValue() ? whiteNoise : gritNoise; + out = svfFilterC.process(toFilter, mode); + + // assymetric saturator, to get those lovely even harmonics + out = Saturator::process(out + 0.33); + + if (blockDC) { + // cascaded Biquad (4th order highpass at ~20Hz) + out = blockDCFilter[SECTION_C].process(out); + } + } + else if (bypassFilters) { + out = params[SOURCE_C_PARAM].getValue() ? whiteNoise : gritNoise; + } + + outputs[FILTERED_OUTPUT].setVoltage(out * 5.f); + } + + // set which text NoisePlethoraWidget should display on the 7 segment display + void updateDataForLEDDisplay() { + + if (programKnobMode == PROGRAM_MODE) { + textDisplayA = std::to_string(programSelectorWithCV.getA().getProgram()); + } + else if (programKnobMode == BANK_MODE) { + textDisplayA = 'A' + programSelectorWithCV.getA().getBank(); + } + isDisplayActiveA = programSelectorWithCV.getMode() == SECTION_A; + + if (programKnobMode == PROGRAM_MODE) { + textDisplayB = std::to_string(programSelectorWithCV.getB().getProgram()); + } + else if (programKnobMode == BANK_MODE) { + textDisplayB = 'A' + programSelectorWithCV.getB().getBank(); + } + isDisplayActiveB = programSelectorWithCV.getMode() == SECTION_B; + } + + // handle convoluted logic for the multifunction Program knob + void processProgramBankKnobLogic(const ProcessArgs& args) { + + // program knob will either change program for current bank... + if (programButtonDragged) { + // work out the change (in discrete increments) since the program/bank knob started being dragged + const int delta = (int)(dialResolution * (params[PROGRAM_PARAM].getValue() - programKnobReferenceState)); + + if (programKnobMode == PROGRAM_MODE) { + const int numProgramsForCurrentBank = getBankForIndex(programSelector.getCurrent().getBank()).getSize(); + + if (delta != 0) { + const int newProgramFromKnob = unsigned_modulo(programSelector.getCurrent().getProgram() + delta, numProgramsForCurrentBank); + programKnobReferenceState = params[PROGRAM_PARAM].getValue(); + setAlgorithmViaProgram(newProgramFromKnob); + } + } + // ...or change bank, (trying to) keep program the same + else { + + if (delta != 0) { + const int newBankFromKnob = unsigned_modulo(programSelector.getCurrent().getBank() + delta, numBanks); + programKnobReferenceState = params[PROGRAM_PARAM].getValue(); + setAlgorithmViaBank(newBankFromKnob); + } + } + } + + // if we have a new "press" on the knob, time it + if (programHoldTrigger.process(programButtonHeld)) { + programHoldTimer.reset(); + } + + // but cancel if it's actually a knob drag + if (programButtonDragged) { + programHoldTimer.reset(); + programButtonHeld = false; + } + else { + if (programButtonHeld) { + programHoldTimer.process(args.sampleTime); + + // if we've held for at least 0.5 seconds, switch into "bank mode" + if (programHoldTimer.time > 0.5f) { + programButtonHeld = false; + programHoldTimer.reset(); + + if (programKnobMode == PROGRAM_MODE) { + programKnobMode = BANK_MODE; + } + else { + programKnobMode = PROGRAM_MODE; + } + + lights[BANK_LIGHT].setBrightness(programKnobMode == BANK_MODE); + } + } + // no longer held, but has been held for non-zero time (without being dragged), toggle "active" section (A or B), + // this is effectively just a "click" + else if (programHoldTimer.time > 0.f) { + programSelector.setMode(!programSelector.getMode()); + programHoldTimer.reset(); + } + } + + if (!programButtonDragged) { + programKnobReferenceState = params[PROGRAM_PARAM].getValue(); + } + } + + void setAlgorithmViaProgram(int newProgram) { + + const int currentBank = programSelector.getCurrent().getBank(); + const std::string algorithmName = getBankForIndex(currentBank).getProgramName(newProgram); + const int section = programSelector.getMode(); + + setAlgorithm(section, algorithmName); + } + + void setAlgorithmViaBank(int newBank) { + newBank = clamp(newBank, 0, numBanks - 1); + const int currentProgram = programSelector.getCurrent().getProgram(); + // the new bank may not have as many algorithms + const int currentProgramInNewBank = clamp(currentProgram, 0, getBankForIndex(newBank).getSize() - 1); + const std::string algorithmName = getBankForIndex(newBank).getProgramName(currentProgramInNewBank); + const int section = programSelector.getMode(); + + setAlgorithm(section, algorithmName); + } + + void setAlgorithm(int section, std::string algorithmName) { + + if (section > 1) { + return; + } + + for (int bank = 0; bank < numBanks; ++bank) { + for (int program = 0; program < getBankForIndex(bank).getSize(); ++program) { + if (getBankForIndex(bank).getProgramName(program) == algorithmName) { + programSelector.setMode(section); + programSelector.getCurrent().setBank(bank); + programSelector.getCurrent().setProgram(program); + + return; + } + } + } + + DEBUG("WARNING: Didn't find %s in programSelector", algorithmName.c_str()); + } + + void dataFromJson(json_t* rootJ) override { + json_t* bankAJ = json_object_get(rootJ, "algorithmA"); + if (bankAJ) { + setAlgorithm(SECTION_A, json_string_value(bankAJ)); + } + + json_t* bankBJ = json_object_get(rootJ, "algorithmB"); + if (bankBJ) { + setAlgorithm(SECTION_B, json_string_value(bankBJ)); + } + + json_t* bypassFiltersJ = json_object_get(rootJ, "bypassFilters"); + if (bypassFiltersJ) { + bypassFilters = json_boolean_value(bypassFiltersJ); + } + + json_t* blockDCJ = json_object_get(rootJ, "blockDC"); + if (blockDCJ) { + blockDC = json_boolean_value(blockDCJ); + } + } + + json_t* dataToJson() override { + json_t* rootJ = json_object(); + + json_object_set_new(rootJ, "algorithmA", json_string(programSelector.getA().getCurrentProgramName().c_str())); + json_object_set_new(rootJ, "algorithmB", json_string(programSelector.getB().getCurrentProgramName().c_str())); + + json_object_set_new(rootJ, "bypassFilters", json_boolean(bypassFilters)); + json_object_set_new(rootJ, "blockDC", json_boolean(blockDC)); + + return rootJ; + } +}; + + +struct BefacoTinyKnobSnapPress : BefacoTinyKnobBlack { + BefacoTinyKnobSnapPress() { } + + // this seems convoluted but I can't see how to achieve the following (say) with onAction: + // a) need to support standard knob dragging behaviour + // b) need to support click detection (not drag) + // c) need to distinguish short click from long click + // + // To achieve this we have 2 state variables, held and dragged. The Module thread will + // time how long programButtonHeld is "true" and switch between bank and program mode if + // longer than X secs. A drag, as measured here as a displacement greater than Y, will cancel + // this timer and we're back to normal param mode. See processProgramBankKnobLogic(...) for details + void onDragStart(const DragStartEvent& e) override { + NoisePlethora* noisePlethoraModule = static_cast(module); + if (noisePlethoraModule) { + noisePlethoraModule->programButtonHeld = true; + noisePlethoraModule->programButtonDragged = false; + } + + pos = Vec(0, 0); + Knob::onDragStart(e); + } + + void onDragMove(const DragMoveEvent& e) override { + pos += e.mouseDelta; + NoisePlethora* noisePlethoraModule = static_cast(module); + + // cancel if we're doing a drag + if (noisePlethoraModule && std::sqrt(pos.square()) > 5) { + noisePlethoraModule->programButtonHeld = false; + noisePlethoraModule->programButtonDragged = true; + } + + Knob::onDragMove(e); + } + + void onDragEnd(const DragEndEvent& e) override { + + NoisePlethora* noisePlethoraModule = static_cast(module); + if (noisePlethoraModule) { + noisePlethoraModule->programButtonHeld = false; + } + + Knob::onDragEnd(e); + } + + // suppress double click + void onDoubleClick(const DoubleClickEvent& e) override {} + + Vec pos; +}; + +// dervied from https://github.com/countmodula/VCVRackPlugins/blob/v2.0.0/src/components/CountModulaLEDDisplay.hpp +struct NoisePlethoraLEDDisplay : LightWidget { + float fontSize = 28; + Vec textPos = Vec(2, 25); + int numChars = 1; + bool activeDisplay = true; + NoisePlethora* module; + NoisePlethora::Section section = NoisePlethora::SECTION_A; + ui::Tooltip* tooltip; + + NoisePlethoraLEDDisplay() { + box.size = mm2px(Vec(7.236, 10)); + } + + void onEnter(const EnterEvent& e) override { + LightWidget::onEnter(e); + setTooltip(); + } + + void setTooltip() { + std::string activeName = module->programSelector.getSection(section).getCurrentProgramName(); + tooltip = new ui::Tooltip; + tooltip->text = activeName; + APP->scene->addChild(tooltip); + } + + void onHover(const event::Hover& e) override { + LightWidget::onHover(e); + e.consume(this); + } + + void onLeave(const event::Leave& e) override { + LightWidget::onLeave(e); + + APP->scene->removeChild(tooltip); + this->tooltip->requestDelete(); + this->tooltip = NULL; + } + + void setCentredPos(Vec pos) { + box.pos.x = pos.x - box.size.x / 2; + box.pos.y = pos.y - box.size.y / 2; + } + + void drawBackground(const DrawArgs& args) override { + // Background + NVGcolor backgroundColor = nvgRGB(0x24, 0x14, 0x14); + NVGcolor borderColor = nvgRGB(0x10, 0x10, 0x10); + nvgBeginPath(args.vg); + nvgRoundedRect(args.vg, 0.0, 0.0, box.size.x, box.size.y, 2.0); + nvgFillColor(args.vg, backgroundColor); + nvgFill(args.vg); + nvgStrokeWidth(args.vg, 1.0); + nvgStrokeColor(args.vg, borderColor); + nvgStroke(args.vg); + } + + void drawLight(const DrawArgs& args) override { + // Background + NVGcolor backgroundColor = nvgRGB(0x24, 0x14, 0x14); + NVGcolor borderColor = nvgRGB(0x10, 0x10, 0x10); + NVGcolor textColor = nvgRGB(0xaa, 0x20, 0x20); + + // use slightly different LED colour if CV is connected as visual cue + if (module) { + NoisePlethora::InputIds inputId = (section == NoisePlethora::SECTION_A) ? NoisePlethora::PROG_A_INPUT : NoisePlethora::PROG_B_INPUT; + if (module->inputs[inputId].isConnected()) { + textColor = nvgRGB(0xff, 0x40, 0x40); + } + } + + nvgBeginPath(args.vg); + nvgRoundedRect(args.vg, 0.0, 0.0, box.size.x, box.size.y, 2.0); + nvgFillColor(args.vg, backgroundColor); + nvgFill(args.vg); + nvgStrokeWidth(args.vg, 1.0); + nvgStrokeColor(args.vg, borderColor); + nvgStroke(args.vg); + + std::shared_ptr font = APP->window->loadFont(asset::plugin(pluginInstance, "res/fonts/Segment7Standard.otf")); + + if (font && font->handle >= 0) { + + std::string text = "A"; // fallback if module not yet defined + if (module) { + text = (section == NoisePlethora::SECTION_A) ? module->textDisplayA : module->textDisplayB; + } + char buffer[numChars + 1]; + int l = text.size(); + if (l > numChars) + l = numChars; + + nvgGlobalTint(args.vg, color::WHITE); + + text.copy(buffer, l); + buffer[numChars] = '\0'; + + nvgFontSize(args.vg, fontSize); + nvgFontFaceId(args.vg, font->handle); + nvgTextLetterSpacing(args.vg, 1); + + // render the "off" segments + nvgFillColor(args.vg, nvgTransRGBA(textColor, 18)); + nvgText(args.vg, textPos.x, textPos.y, "8", NULL); + + // render the "on segments" + nvgFillColor(args.vg, textColor); + + nvgText(args.vg, textPos.x, textPos.y, buffer, NULL); + } + + if (module) { + const bool isSectionDisplayActive = (section == NoisePlethora::SECTION_A) ? module->isDisplayActiveA : module->isDisplayActiveB; + + // active bank dot + nvgBeginPath(args.vg); + nvgCircle(args.vg, 18, 26, 1.5); + nvgFillColor(args.vg, isSectionDisplayActive ? textColor : nvgTransRGBA(textColor, 18)); + nvgFill(args.vg); + } + } +}; + +struct NoisePlethoraWidget : ModuleWidget { + NoisePlethoraWidget(NoisePlethora* module) { + setModule(module); + setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/panels/NoisePlethora.svg"))); + + addChild(createWidget(Vec(RACK_GRID_WIDTH, 0))); + addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); + addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + + // A params + addParam(createParamCentered(mm2px(Vec(22.325, 16.09)), module, NoisePlethora::X_A_PARAM)); + addParam(createParamCentered(mm2px(Vec(22.325, 30.595)), module, NoisePlethora::Y_A_PARAM)); + addParam(createParamCentered(mm2px(Vec(43.248, 23.058)), module, NoisePlethora::CUTOFF_A_PARAM)); + addParam(createParamCentered(mm2px(Vec(63.374, 16.09)), module, NoisePlethora::RES_A_PARAM)); + addParam(createParamCentered(mm2px(Vec(63.374, 30.595)), module, NoisePlethora::CUTOFF_CV_A_PARAM)); + addParam(createParam(mm2px(Vec(41.494, 38.579)), module, NoisePlethora::FILTER_TYPE_A_PARAM)); + + // (bank) + addParam(createParamCentered(mm2px(Vec(30.866, 49.503)), module, NoisePlethora::PROGRAM_PARAM)); + + // B params + addParam(createParamCentered(mm2px(Vec(22.345, 68.408)), module, NoisePlethora::X_B_PARAM)); + addParam(createParamCentered(mm2px(Vec(22.345, 82.695)), module, NoisePlethora::Y_B_PARAM)); + addParam(createParamCentered(mm2px(Vec(43.248, 75.551)), module, NoisePlethora::CUTOFF_B_PARAM)); + addParam(createParamCentered(mm2px(Vec(63.383, 82.686)), module, NoisePlethora::RES_B_PARAM)); + addParam(createParamCentered(mm2px(Vec(63.36, 68.388)), module, NoisePlethora::CUTOFF_CV_B_PARAM)); + addParam(createParam(mm2px(Vec(41.494, 53.213)), module, NoisePlethora::FILTER_TYPE_B_PARAM)); + + // C params + addParam(createParamCentered(mm2px(Vec(7.6, 99.584)), module, NoisePlethora::GRIT_PARAM)); + addParam(createParamCentered(mm2px(Vec(22.366, 99.584)), module, NoisePlethora::RES_C_PARAM)); + addParam(createParamCentered(mm2px(Vec(47.536, 98.015)), module, NoisePlethora::CUTOFF_C_PARAM)); + addParam(createParamCentered(mm2px(Vec(63.36, 99.584)), module, NoisePlethora::CUTOFF_CV_C_PARAM)); + addParam(createParam(mm2px(Vec(33.19, 92.506)), module, NoisePlethora::FILTER_TYPE_C_PARAM)); + addParam(createParam(mm2px(Vec(31.707, 104.225)), module, NoisePlethora::SOURCE_C_PARAM)); + + addInput(createInputCentered(mm2px(Vec(6.431, 16.102)), module, NoisePlethora::X_A_INPUT)); + addInput(createInputCentered(mm2px(Vec(6.431, 29.959)), module, NoisePlethora::Y_A_INPUT)); + addInput(createInputCentered(mm2px(Vec(52.845, 42.224)), module, NoisePlethora::CUTOFF_A_INPUT)); + addInput(createInputCentered(mm2px(Vec(6.431, 43.212)), module, NoisePlethora::PROG_A_INPUT)); + addInput(createInputCentered(mm2px(Vec(6.431, 55.801)), module, NoisePlethora::PROG_B_INPUT)); + addInput(createInputCentered(mm2px(Vec(52.845, 56.816)), module, NoisePlethora::CUTOFF_B_INPUT)); + addInput(createInputCentered(mm2px(Vec(6.431, 68.398)), module, NoisePlethora::X_B_INPUT)); + addInput(createInputCentered(mm2px(Vec(6.431, 82.729)), module, NoisePlethora::Y_B_INPUT)); + addInput(createInputCentered(mm2px(Vec(7.555, 114.8)), module, NoisePlethora::GRIT_INPUT)); + addInput(createInputCentered(mm2px(Vec(63.36, 114.8)), module, NoisePlethora::CUTOFF_C_INPUT)); + + addOutput(createOutputCentered(mm2px(Vec(64.909, 44.397)), module, NoisePlethora::A_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(64.915, 54.608)), module, NoisePlethora::B_OUTPUT)); + + addOutput(createOutputCentered(mm2px(Vec(22.345, 114.852)), module, NoisePlethora::GRITTY_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(34.981, 114.852)), module, NoisePlethora::FILTERED_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(47.536, 114.852)), module, NoisePlethora::WHITE_OUTPUT)); + + addChild(createLightCentered>(mm2px(Vec(30.866, 37.422)), module, NoisePlethora::BANK_LIGHT)); + + + NoisePlethoraLEDDisplay* displayA = createWidget(mm2px(Vec(13.106, 38.172))); + displayA->module = module; + displayA->section = NoisePlethora::SECTION_A; + addChild(displayA); + + NoisePlethoraLEDDisplay* displayB = createWidget(mm2px(Vec(13.106, 50.712))); + displayB->module = module; + displayB->section = NoisePlethora::SECTION_B; + addChild(displayB); + } + + void appendContextMenu(Menu* menu) override { + NoisePlethora* module = dynamic_cast(this->module); + assert(module); + + // build the two algorithm selection menus programmatically + menu->addChild(createMenuLabel("Algorithms")); + std::vector bankAliases = {"Textures", "HH Clusters", "Harsh & Wild", "Test"}; + char programNames[] = "AB"; + for (int sectionId = 0; sectionId < 2; ++sectionId) { + + menu->addChild(createSubmenuItem(string::f("Program %c", programNames[sectionId]), "", + [ = ](Menu * menu) { + for (int i = 0; i < numBanks; i++) { + const int currentBank = module->programSelector.getSection(sectionId).getBank(); + const int currentProgram = module->programSelector.getSection(sectionId).getProgram(); + + menu->addChild(createSubmenuItem(string::f("Bank %d: %s", i + 1, bankAliases[i].c_str()), currentBank == i ? CHECKMARK_STRING : "", [ = ](Menu * menu) { + for (int j = 0; j < getBankForIndex(i).getSize(); ++j) { + const bool currentProgramAndBank = (currentProgram == j) && (currentBank == i); + const std::string algorithmName = getBankForIndex(i).getProgramName(j); + + bool implemented = false; + for (auto item : MyFactory::Instance()->factoryFunctionRegistry) { + if (item.first == algorithmName) { + implemented = true; + break; + } + } + + if (implemented) { + menu->addChild(createMenuItem(algorithmName, currentProgramAndBank ? CHECKMARK_STRING : "", + [ = ]() { + module->setAlgorithm(sectionId, algorithmName); + })); + } + else { + // placeholder text (greyed out) + menu->addChild(createMenuLabel(algorithmName)); + } + } + })); + } + })); + + + } + + menu->addChild(createMenuLabel("Filters")); + menu->addChild(createBoolPtrMenuItem("Remove DC", "", &module->blockDC)); + menu->addChild(createBoolPtrMenuItem("Bypass Filters", "", &module->bypassFilters)); + } +}; + + +Model* modelNoisePlethora = createModel("NoisePlethora"); \ No newline at end of file diff --git a/src/PulseGenerator_4.hpp b/src/PulseGenerator_4.hpp deleted file mode 100644 index f3229ad..0000000 --- a/src/PulseGenerator_4.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include - - -/** When triggered, holds a high value for a specified time before going low again */ -struct PulseGenerator_4 { - simd::float_4 remaining = 0.f; - - /** Immediately disables the pulse */ - void reset() { - remaining = 0.f; - } - - /** Advances the state by `deltaTime`. Returns whether the pulse is in the HIGH state. */ - simd::float_4 process(float deltaTime) { - - simd::float_4 mask = (remaining > 0.f); - - remaining -= ifelse(mask, deltaTime, 0.f); - return ifelse(mask, simd::float_4::mask(), 0.f); - } - - /** Begins a trigger with the given `duration`. */ - void trigger(simd::float_4 mask, float duration = 1e-3f) { - // Keep the previous pulse if the existing pulse will be held longer than the currently requested one. - remaining = ifelse(mask & (duration > remaining), duration, remaining); - } -}; diff --git a/src/Rampage.cpp b/src/Rampage.cpp index 8b2f959..b204b84 100644 --- a/src/Rampage.cpp +++ b/src/Rampage.cpp @@ -1,5 +1,4 @@ #include "plugin.hpp" -#include "PulseGenerator_4.hpp" using simd::float_4; diff --git a/src/SpringReverb.cpp b/src/SpringReverb.cpp index 1194787..59dd5b8 100644 --- a/src/SpringReverb.cpp +++ b/src/SpringReverb.cpp @@ -71,6 +71,16 @@ struct SpringReverb : Module { delete convolver; } + void processBypass(const ProcessArgs& args) override { + float in1 = inputs[IN1_INPUT].getVoltageSum(); + float in2 = inputs[IN2_INPUT].getVoltageSum(); + + float dry = clamp(in1 + in2, -10.0f, 10.0f); + + outputs[WET_OUTPUT].setVoltage(dry); + outputs[MIX_OUTPUT].setVoltage(dry); + } + void process(const ProcessArgs& args) override { float in1 = inputs[IN1_INPUT].getVoltageSum(); float in2 = inputs[IN2_INPUT].getVoltageSum(); @@ -129,9 +139,9 @@ struct SpringReverb : Module { outputs[WET_OUTPUT].setVoltage(clamp(wet, -10.0f, 10.0f)); outputs[MIX_OUTPUT].setVoltage(clamp(mix, -10.0f, 10.0f)); - // process VU lights + // process VU lights vuFilter.process(args.sampleTime, wet); - // process peak light + // process peak light lightFilter.process(args.sampleTime, dry * 50.0); if (lightRefreshClock.process()) { diff --git a/src/noise-plethora/LICENSE.md b/src/noise-plethora/LICENSE.md new file mode 100644 index 0000000..33c208d --- /dev/null +++ b/src/noise-plethora/LICENSE.md @@ -0,0 +1,3 @@ +Plugins in subdirectory `./plugins` have been derived from source files from https://github.com/Befaco/Noise_plethora/ (prefix `P_*.hpp`) licensed under GPL-3.0-or-later (see https://github.com/Befaco/Noise_plethora/blob/master/README.md). + +The audio components in subdirectory `./teensy` include modified versions of the [Teensy Audio library](https://github.com/PaulStoffregen/Audio), licensed under the MIT License. diff --git a/src/noise-plethora/README.md b/src/noise-plethora/README.md new file mode 100644 index 0000000..32f366a --- /dev/null +++ b/src/noise-plethora/README.md @@ -0,0 +1,17 @@ +Technical Notes +=============== + +The Noise Plethora module consists of a number of plugins designed to run on the Teensy microcontroller, and specifically using the powerful [Teensy audio library](https://www.pjrc.com/teensy/td_libs_Audio.html). This consists of a number of oscillators, filters, noise sources, effects etc. Unfortunately these are designed to run directly on the Teensy, and target ARM processors. A small subset of the library that is required for NoisePlethora has been ported (see `./teensy`), with minor adaptions: + +* any parts that only have ARM instructions have been reimplemented (generally with slower versions) +* Teensy fixes the sample rate at 44100Hz, so parts have been updated to allow arbitrary sample rates +* Teensy uses a simple graph based processing approach, where blocks are processed in the order in which they are _declared_ in the C/C++ code. The code to produce and process this graph is too complex to port, so I've instead modify each Teensy unit's `process()` call to take audio blocks as input/output where appropriate, and manually constructed the computation graph by inspection. (In both the original library and the port, every element in the graph is processed once per loop, and some results stored for the next computation where needed). + +The VCV plugin will generate 1 block's worth of audio (~2.9ms at 44100Hz), store this in a buffer, and play back sample by sample until the buffer empties and the process is repeated. + +An example Teensy plugin is shown below: +![Example plugin](./teensy-gui.png) + +I used my own Teensy to debug and try out things quickly in VCV. Teensy provides a usb audio device which Rack trivially recognises (this is useful to allow rapid dev + it decouples Teensy logic from Noise Plethora's filters): +![Example plugin](./teensy-audio-device.png) + diff --git a/src/noise-plethora/plugins/Banks.cpp b/src/noise-plethora/plugins/Banks.cpp new file mode 100644 index 0000000..30f1a17 --- /dev/null +++ b/src/noise-plethora/plugins/Banks.cpp @@ -0,0 +1,112 @@ +#include "Banks.hpp" +#include "Banks_Def.hpp" + +const Bank::BankElem Bank::defaultElem = {"", 1.0}; + +Bank::Bank() { + programs.fill(defaultElem); +} + +Bank::Bank(const BankElem& p1, const BankElem& p2, const BankElem& p3, + const BankElem& p4, const BankElem& p5, const BankElem& p6, + const BankElem& p7, const BankElem& p8, const BankElem& p9, + const BankElem& p10) + : programs{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10} +{ } + +const std::string Bank::getProgramName(int i) { + if (i >= 0 && i < programsPerBank) { + return programs[i].name; + } + return ""; +} + +float Bank::getProgramGain(int i) { + if (i >= 0 && i < programsPerBank) { + return programs[i].gain; + } + return 1.0; +} + +int Bank::getSize() { + int size = 0; + for (auto it = programs.begin(); it != programs.end(); it++) { + if ((*it).name == "") { + break; + } + size++; + } + return size; +} + + + +// Bank A: +#include "P_radioOhNo.hpp" +#include "P_Rwalk_SineFMFlange.hpp" +#include "P_xModRingSqr.hpp" +#include "P_XModRingSine.hpp" +#include "P_CrossModRing.hpp" +#include "P_resonoise.hpp" +#include "P_grainGlitch.hpp" +#include "P_grainGlitchII.hpp" +#include "P_grainGlitchIII.hpp" +#include "P_basurilla.hpp" + +// Bank B: HH clusters +#include "P_clusterSaw.hpp" +#include "P_pwCluster.hpp" +#include "P_crCluster2.hpp" +#include "P_sineFMcluster.hpp" +#include "P_TriFMcluster.hpp" +#include "P_PrimeCluster.hpp" +#include "P_PrimeCnoise.hpp" +#include "P_FibonacciCluster.hpp" +#include "P_partialCluster.hpp" +#include "P_phasingCluster.hpp" + +// Bank C: harsh and wild +#include "P_BasuraTotal.hpp" +#include "P_Atari.hpp" +#include "P_WalkingFilomena.hpp" +#include "P_S_H.hpp" +#include "P_arrayOnTheRocks.hpp" +#include "P_existencelsPain.hpp" +#include "P_whoKnows.hpp" +#include "P_satanWorkout.hpp" +#include "P_Rwalk_BitCrushPW.hpp" +#include "P_Rwalk_LFree.hpp" + +// Bank D: Test / other +//#include "P_TestPlugin.hpp" +//#include "P_TeensyAlt.hpp" +//#include "P_WhiteNoise.hpp" +//#include "P_Rwalk_LBit.hpp" +//#include "P_Rwalk_SineFM.hpp" +//#include "P_VarWave.hpp" +//#include "P_RwalkVarWave.hpp" +//#include "P_Rwalk_ModWave.hpp" +//#include "P_Rwalk_WaveTwist.hpp" + + +static const Bank bank1 BANKS_DEF_1; // Banks_Def.hpp +static const Bank bank2 BANKS_DEF_2; +static const Bank bank3 BANKS_DEF_3; +//static const Bank bank4 BANKS_DEF_4; +//static const Bank bank5 BANKS_DEF_5; +static std::array banks { bank1, bank2, bank3 }; //, bank5 }; + +// static const Bank bank6 BANKS_DEF_6; +// static const Bank bank7 BANKS_DEF_7; +// static const Bank bank8 BANKS_DEF_8; +// static const Bank bank9 BANKS_DEF_9; +// static const Bank bank10 BANKS_DEF_10; +// static std::array banks { bank1, bank2, bank3, bank4, bank5, bank6, bank7, bank8, bank9, bank10 }; + +Bank& getBankForIndex(int i) { + if (i < 0) + i = 0; + if (i >= programsPerBank) + i = (programsPerBank - 1); + return banks[i]; +} diff --git a/src/noise-plethora/plugins/Banks.hpp b/src/noise-plethora/plugins/Banks.hpp new file mode 100644 index 0000000..4896a0c --- /dev/null +++ b/src/noise-plethora/plugins/Banks.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include + +static const int programsPerBank = 10; +static const int numBanks = 3; + +struct Bank { + + struct BankElem { + BankElem() {}; + + BankElem(std::string n, float g = 1.0) + : name{n} + , gain{g} + {} + + std::string name = ""; + float gain = 1.0; + }; + + static const BankElem defaultElem; + + Bank(); + Bank(const BankElem& p1, const BankElem& p2 = defaultElem, + const BankElem& p3 = defaultElem, const BankElem& p4 = defaultElem, + const BankElem& p5 = defaultElem, const BankElem& p6 = defaultElem, + const BankElem& p7 = defaultElem, const BankElem& p8 = defaultElem, + const BankElem& p9 = defaultElem, const BankElem& p10 = defaultElem); + + const std::string getProgramName(int i); + float getProgramGain(int i); + + int getSize(); + +private: + + std::array programs; + +}; + +Bank& getBankForIndex(int i); diff --git a/src/noise-plethora/plugins/Banks_Def.hpp b/src/noise-plethora/plugins/Banks_Def.hpp new file mode 100644 index 0000000..41c1f63 --- /dev/null +++ b/src/noise-plethora/plugins/Banks_Def.hpp @@ -0,0 +1,53 @@ +#pragma once + +#define BANKS_DEF_1 { \ + { "radioOhNo", 1.0 }, \ + { "Rwalk_SineFMFlange", 1.0 }, \ + { "xModRingSqr", 1.0 }, \ + { "XModRingSine", 1.0 }, \ + { "CrossModRing", 1.0 }, \ + { "resonoise", 1.0 }, \ + { "grainGlitch", 1.0 }, \ + { "grainGlitchII", 1.0 }, \ + { "grainGlitchIII", 1.0 }, \ + { "basurilla", 1.0 } \ + } + +#define BANKS_DEF_2 { \ + { "clusterSaw", 1.0 }, \ + { "pwCluster", 1.0 }, \ + { "crCluster2", 1.0 }, \ + { "sineFMcluster", 1.0 }, \ + { "TriFMcluster", 1.0 }, \ + { "PrimeCluster", 0.8 }, \ + { "PrimeCnoise", 0.8 }, \ + { "FibonacciCluster", 1.0 }, \ + { "partialCluster", 1.0 }, \ + { "phasingCluster", 1.0 } \ + } + +#define BANKS_DEF_3 { \ + { "BasuraTotal", 1.0 }, \ + { "Atari", 1.0 }, \ + { "WalkingFilomena", 1.0 }, \ + { "S_H", 1.0 }, \ + { "arrayOnTheRocks", 1.0 }, \ + { "existencelsPain", 1.0 }, \ + { "whoKnows", 1.0 }, \ + { "satanWorkout", 1.0 }, \ + { "Rwalk_BitCrushPW", 1.0 }, \ + { "Rwalk_LFree", 1.0 } \ + } + +#define BANKS_DEF_4 { \ + { "TestPlugin", 1.0 }, \ + { "WhiteNoise", 1.0 }, \ + { "TeensyAlt", 1.0 } \ + } +#define BANKS_DEF_5 + +// #define BANKS_DEF_6 +// #define BANKS_DEF_7 +// #define BANKS_DEF_8 +// #define BANKS_DEF_9 +// #define BANKS_DEF_10 diff --git a/src/noise-plethora/plugins/NoisePlethoraPlugin.hpp b/src/noise-plethora/plugins/NoisePlethoraPlugin.hpp new file mode 100644 index 0000000..63e8e3a --- /dev/null +++ b/src/noise-plethora/plugins/NoisePlethoraPlugin.hpp @@ -0,0 +1,90 @@ +#pragma once + +#include +#include +#include // string might not be allowed +#include +#include + +#include "../teensy/TeensyAudioReplacements.hpp" + + +class NoisePlethoraPlugin { + +public: + NoisePlethoraPlugin() { } + virtual ~NoisePlethoraPlugin() {} + + NoisePlethoraPlugin(const NoisePlethoraPlugin&) = delete; + NoisePlethoraPlugin& operator=(const NoisePlethoraPlugin&) = delete; + + virtual void init() {}; + // equivelent to arduino void loop() + virtual void process(float k1, float k2) {}; + + // called once-per sample, will consume a buffer of length AUDIO_BLOCK_SAMPLES (128) + // then request that the buffer be refilled, returns values in range [-1, 1] + float processGraph() { + + if (blockBuffer.empty()) { + processGraphAsBlock(blockBuffer); + } + + return int16_to_float_1v(blockBuffer.shift()); + } + + virtual AudioStream& getStream() = 0; + virtual unsigned char getPort() = 0; + +protected: + + // subclass should process the audio graph and fill the supplied buffer + virtual void processGraphAsBlock(TeensyBuffer& blockBuffer) = 0; + + TeensyBuffer blockBuffer; +}; + + +class MyFactory { +public: + static MyFactory* Instance() { + static MyFactory factory; + return &factory; + } + + std::shared_ptr Create(std::string name) { + NoisePlethoraPlugin* instance = nullptr; + + // find name in the registry and call factory method. + auto it = factoryFunctionRegistry.find(name); + if (it != factoryFunctionRegistry.end()) { + instance = it->second(); + } + + // wrap instance in a shared ptr and return + if (instance != nullptr) { + return std::shared_ptr(instance); + } + else { + return nullptr; + } + } + + void RegisterFactoryFunction(std::string name, std::function classFactoryFunction) { + // register the class factory function + factoryFunctionRegistry[name] = classFactoryFunction; + } + + std::map> factoryFunctionRegistry; +}; + +template class Registrar { +public: + Registrar(std::string className) { + // register the class factory function + MyFactory::Instance()->RegisterFactoryFunction(className, + [](void) -> NoisePlethoraPlugin * { return new T();}); + } +}; + +#define REGISTER_PLUGIN(NAME) static Registrar NAME ##_reg(#NAME) \ No newline at end of file diff --git a/src/noise-plethora/plugins/P_Atari.hpp b/src/noise-plethora/plugins/P_Atari.hpp new file mode 100644 index 0000000..ab57b1a --- /dev/null +++ b/src/noise-plethora/plugins/P_Atari.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class Atari : public NoisePlethoraPlugin { + +public: + + Atari() + //:patchCord1(waveformMod1, 0, waveformMod2, 1), + //patchCord3(waveformMod2, 0, waveformMod1, 0) + { } + + ~Atari() override {} + + Atari(const Atari&) = delete; + Atari& operator=(const Atari&) = delete; + + void init() override { + int masterVolume = 1; + waveformMod1.begin(WAVEFORM_SQUARE); + waveformMod2.begin(WAVEFORM_PULSE); + waveformMod1.offset(1); + waveformMod1.amplitude(masterVolume); + waveformMod2.amplitude(masterVolume); + + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + float pitch1 = pow(knob_1, 2); + // float pitch2 = pow(knob_2, 2); + waveformMod1.frequency(10 + (pitch1 * 50)); + waveformMod2.frequency(10 + (knob_2 * 200)); + waveformMod1.frequencyModulation(knob_2 * 8 + 3); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + // waveformMod1 has FM from waveformMod2 + waveformMod1.update(&output2, nullptr, &output1); + + // waveformMod2 has PWM from waveformMod1 + waveformMod2.update(nullptr, &output1, &output2); + + blockBuffer.pushBuffer(output2.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return waveformMod2; + } + unsigned char getPort() override { + return 0; + } + +private: + audio_block_t output1, output2; + + AudioSynthWaveformModulated waveformMod1; + AudioSynthWaveformModulated waveformMod2; + + //AudioSynthWaveformModulated waveformMod1; //xy=334,349 + //AudioSynthWaveformModulated waveformMod2; //xy=616,284 + //AudioConnection patchCord1; + //AudioConnection patchCord3; + +}; + +REGISTER_PLUGIN(Atari); diff --git a/src/noise-plethora/plugins/P_BasuraTotal.hpp b/src/noise-plethora/plugins/P_BasuraTotal.hpp new file mode 100644 index 0000000..8700fa5 --- /dev/null +++ b/src/noise-plethora/plugins/P_BasuraTotal.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class BasuraTotal : public NoisePlethoraPlugin { + +public: + + BasuraTotal() + // : patchCord1(waveformMod1, freeverb1) + {} + + ~BasuraTotal() override {} + + BasuraTotal(const BasuraTotal&) = delete; + BasuraTotal& operator=(const BasuraTotal&) = delete; + + dsp::Timer timer; + + void init() override { + + freeverb1.roomsize(0); + timer.reset(); + waveformMod1.begin(1, 500, WAVEFORM_SINE); + } + + void process(float k1, float k2) override { + + float knob_1 = k1; + float knob_2 = k2; + + float pitch1 = pow(knob_1, 2); + float pitch2 = pow(knob_2, 2); + + float timeMicros = timer.time * 1000000; + if (timeMicros > 100000 * pitch2) { // Changing this value changes the frequency. + timer.reset(); + + waveformMod1.begin(1, 500, WAVEFORM_SQUARE); + waveformMod1.frequency(generateNoise() * (200 + (pitch1 * 5000))) ; + freeverb1.roomsize(1); + } + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + const float blockTime = APP->engine->getSampleTime() * AUDIO_BLOCK_SAMPLES; + timer.process(blockTime); + + waveformMod1.update(nullptr, nullptr, &waveformOut); + freeverb1.update(&waveformOut, &freeverbOut); + + blockBuffer.pushBuffer(freeverbOut.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return freeverb1; + } + unsigned char getPort() override { + return 0; + } + +private: + + static unsigned int generateNoise() { + // See https://en.wikipedia.org/wiki/Linear_feedback_shift_register#Galois_LFSRs + /* initialize with any 32 bit non-zero unsigned long value. */ + static unsigned long int lfsr = 0xfeddfaceUL; /* 32 bit init, nonzero */ + static unsigned long mask = ((unsigned long)(1UL << 31 | 1UL << 15 | 1UL << 2 | 1UL << 1)); + /* If the output bit is 1, apply toggle mask. + * The value has 1 at bits corresponding + * to taps, 0 elsewhere. */ + + if (lfsr & 1) { + lfsr = (lfsr >> 1) ^ mask; + return (1); + } + else { + lfsr >>= 1; + return (0); + } + } + + audio_block_t waveformOut, freeverbOut; + + AudioSynthWaveformModulated waveformMod1; //xy=216.88888549804688,217.9999988898635 + AudioEffectFreeverb freeverb1; //xy=374.8888854980469,153.88888549804688 + // AudioConnection patchCord1; + // unsigned long lastClick; +}; + +REGISTER_PLUGIN(BasuraTotal); \ No newline at end of file diff --git a/src/noise-plethora/plugins/P_CrossModRing.hpp b/src/noise-plethora/plugins/P_CrossModRing.hpp new file mode 100644 index 0000000..0b2f9cd --- /dev/null +++ b/src/noise-plethora/plugins/P_CrossModRing.hpp @@ -0,0 +1,119 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class CrossModRing : public NoisePlethoraPlugin { + +public: + + CrossModRing() + // :patchCord1(waveformMod3, 0, multiply2, 0), + // patchCord2(waveformMod3, 0, waveformMod4, 0), + // patchCord3(waveformMod1, 0, multiply1, 0), + // patchCord4(waveformMod1, 0, waveformMod2, 0), + // patchCord5(waveformMod4, 0, multiply2, 1), + // patchCord6(waveformMod4, 0, waveformMod1, 0), + // patchCord7(waveformMod2, 0, multiply1, 1), + // patchCord8(waveformMod2, 0, waveformMod3, 0), + // patchCord9(multiply2, 0, multiply3, 1), + // patchCord10(multiply1, 0, multiply3, 0) + { } + + ~CrossModRing() override {} + + CrossModRing(const CrossModRing&) = delete; + CrossModRing& operator=(const CrossModRing&) = delete; + + void init() override { + WaveformType masterWaveform = WAVEFORM_SQUARE; + float masterVolume = 0.8; + + waveformMod1.begin(masterWaveform); + waveformMod2.begin(masterWaveform); + waveformMod3.begin(WAVEFORM_SAWTOOTH); + waveformMod3.offset(1); + + waveformMod4.begin(masterWaveform); + + waveformMod1.amplitude(masterVolume); + waveformMod2.amplitude(masterVolume); + waveformMod3.amplitude(masterVolume); + waveformMod4.amplitude(masterVolume); + + + waveformMod1.frequency(1100); + waveformMod2.frequency(1367); + waveformMod3.frequency(345); + waveformMod4.frequency(686); + + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + float pitch1 = pow(knob_1, 2); + + waveformMod1.frequency(20 + (pitch1 * 807)); + waveformMod2.frequency(11 + (knob_1 * 21)); + waveformMod3.frequency(1 + (pitch1 * 29)); + waveformMod4.frequency(1 + (knob_1 * 7) * -1); + + float masterOctaves = 8 * knob_2 + 2; + + waveformMod1.frequencyModulation(masterOctaves); + waveformMod2.frequencyModulation(masterOctaves); + waveformMod3.frequencyModulation(masterOctaves); + waveformMod4.frequencyModulation(masterOctaves); + + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + // NOTE: buffer is zero indexed, waveformMod names are not!! + // NOTE: each waveform is modulated by previous + waveformMod3.update(&waveformModOut[1], nullptr, &waveformModOut[2]); + waveformMod1.update(&waveformModOut[3], nullptr, &waveformModOut[0]); + waveformMod4.update(&waveformModOut[2], nullptr, &waveformModOut[3]); + waveformMod2.update(&waveformModOut[0], nullptr, &waveformModOut[1]); + + // multiply + multiply1.update(&waveformModOut[0], &waveformModOut[1], &multiplyOut[0]); + multiply2.update(&waveformModOut[2], &waveformModOut[3], &multiplyOut[1]); + multiply3.update(&multiplyOut[0], &multiplyOut[1], &multiplyOut[2]); + + blockBuffer.pushBuffer(multiplyOut[2].data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return multiply3; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t waveformModOut[4] = {}, multiplyOut[3] = {}; + + AudioSynthWaveformModulated waveformMod3; //xy=287.99999618530273,420 + AudioSynthWaveformModulated waveformMod1; //xy=288.99999618530273,197 + AudioSynthWaveformModulated waveformMod4; //xy=290.99999618530273,541 + AudioSynthWaveformModulated waveformMod2; //xy=291.99999618530273,318 + AudioEffectMultiply multiply2; //xy=484.99999618530273,474 + AudioEffectMultiply multiply1; //xy=485.99999618530273,251 + AudioEffectMultiply multiply3; //xy=655.9999961853027,356 + + + // AudioConnection patchCord1(waveformMod3, 0, multiply2, 0); + // AudioConnection patchCord2(waveformMod3, 0, waveformMod4, 0); + // AudioConnection patchCord3(waveformMod1, 0, multiply1, 0); + // AudioConnection patchCord4(waveformMod1, 0, waveformMod2, 0); + // AudioConnection patchCord5(waveformMod4, 0, multiply2, 1); + // AudioConnection patchCord6(waveformMod4, 0, waveformMod1, 0); + // AudioConnection patchCord7(waveformMod2, 0, multiply1, 1); + // AudioConnection patchCord8(waveformMod2, 0, waveformMod3, 0); + // AudioConnection patchCord9(multiply2, 0, multiply3, 1); + // AudioConnection patchCord10(multiply1, 0, multiply3, 0); + +}; + +REGISTER_PLUGIN(CrossModRing); diff --git a/src/noise-plethora/plugins/P_FibonacciCluster.hpp b/src/noise-plethora/plugins/P_FibonacciCluster.hpp new file mode 100644 index 0000000..0ade8bf --- /dev/null +++ b/src/noise-plethora/plugins/P_FibonacciCluster.hpp @@ -0,0 +1,265 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class FibonacciCluster : public NoisePlethoraPlugin { + +public: + + FibonacciCluster() + // : patchCord1(noise1, 0, waveform1, 0) + // , patchCord2(noise1, 0, waveform2, 0) + // , patchCord3(noise1, 0, waveform3, 0) + // , patchCord4(noise1, 0, waveform4, 0) + // , patchCord5(noise1, 0, waveform5, 0) + // , patchCord6(noise1, 0, waveform6, 0) + // , patchCord7(noise1, 0, waveform7, 0) + // , patchCord8(noise1, 0, waveform8, 0) + // , patchCord9(noise1, 0, waveform9, 0) + // , patchCord10(noise1, 0, waveform10, 0) + // , patchCord11(noise1, 0, waveform11, 0) + // , patchCord12(noise1, 0, waveform12, 0) + // , patchCord13(noise1, 0, waveform13, 0) + // , patchCord14(noise1, 0, waveform14, 0) + // , patchCord15(noise1, 0, waveform15, 0) + // , patchCord16(noise1, 0, waveform16, 0) + // , patchCord17(waveform16, 0, mixer4, 3) + // , patchCord18(waveform14, 0, mixer4, 1) + // , patchCord19(waveform15, 0, mixer4, 2) + // , patchCord20(waveform13, 0, mixer4, 0) + // , patchCord21(waveform8, 0, mixer2, 3) + // , patchCord22(waveform6, 0, mixer2, 1) + // , patchCord23(waveform7, 0, mixer2, 2) + // , patchCord24(waveform12, 0, mixer3, 3) + // , patchCord25(waveform5, 0, mixer2, 0) + // , patchCord26(waveform10, 0, mixer3, 1) + // , patchCord27(waveform11, 0, mixer3, 2) + // , patchCord28(waveform9, 0, mixer3, 0) + // , patchCord29(waveform4, 0, mixer1, 3) + // , patchCord30(waveform2, 0, mixer1, 1) + // , patchCord31(waveform3, 0, mixer1, 2) + // , patchCord32(waveform1, 0, mixer1, 0) + // , patchCord33(mixer4, 0, mixer5, 3) + // , patchCord34(mixer3, 0, mixer5, 2) + // , patchCord35(mixer2, 0, mixer5, 1) + // , patchCord36(mixer1, 0, mixer5, 0) + {} + + ~FibonacciCluster() override {} + + FibonacciCluster(const FibonacciCluster&) = delete; + FibonacciCluster& operator=(const FibonacciCluster&) = delete; + + void init() override { + mixer1.gain(0, 1); + mixer1.gain(1, 1); + mixer1.gain(2, 1); + mixer1.gain(3, 1); + mixer2.gain(0, 1); + mixer2.gain(1, 1); + mixer2.gain(2, 1); + mixer2.gain(3, 1); + mixer3.gain(0, 1); + mixer3.gain(1, 1); + mixer3.gain(2, 1); + mixer3.gain(3, 1); + mixer4.gain(0, 1); + mixer4.gain(1, 1); + mixer4.gain(2, 1); + mixer4.gain(3, 1); + mixer5.gain(0, 1); + mixer5.gain(1, 1); + mixer5.gain(2, 1); + mixer5.gain(3, 1); + + int masterWaveform = WAVEFORM_SAWTOOTH; + float masterVolume = 0.2; + + waveform1.begin(masterVolume, 794, masterWaveform); + waveform2.begin(masterVolume, 647, masterWaveform); + waveform3.begin(masterVolume, 524, masterWaveform); + waveform4.begin(masterVolume, 444, masterWaveform); + waveform5.begin(masterVolume, 368, masterWaveform); + waveform6.begin(masterVolume, 283, masterWaveform); + waveform7.begin(masterVolume, 283, masterWaveform); + waveform8.begin(masterVolume, 283, masterWaveform); + waveform9.begin(masterVolume, 283, masterWaveform); + waveform10.begin(masterVolume, 283, masterWaveform); + waveform11.begin(masterVolume, 283, masterWaveform); + waveform12.begin(masterVolume, 283, masterWaveform); + waveform13.begin(masterVolume, 283, masterWaveform); + waveform14.begin(masterVolume, 283, masterWaveform); + waveform15.begin(masterVolume, 283, masterWaveform); + waveform16.begin(masterVolume, 283, masterWaveform); + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + + float pitch1 = pow(knob_1, 2); + float pitch2 = pow(knob_2, 2); + float spread = pitch2 / 2 + 0.1; + + float f1 = 40 + pitch1 * 5000; + float f2 = f1 * (2 * spread + 1); + float f3 = f1 + f2 * spread; + float f4 = f2 + f3 * spread; + float f5 = f3 + f4 * spread; + float f6 = f4 + f5 * spread; + float f7 = f5 + f6 * spread; + float f8 = f6 + f7 * spread; + float f9 = f7 + f8 * spread; + float f10 = f8 + f9 * spread; + float f11 = f9 + f10 * spread; + float f12 = f10 + f11 * spread; + float f13 = f11 + f12 * spread; + float f14 = f12 + f13 * spread; + float f15 = f13 + f14 * spread; + float f16 = f14 + f15 * spread; + + waveform1.frequency(f1); + waveform2.frequency(f2); + waveform3.frequency(f3); + waveform4.frequency(f4); + waveform5.frequency(f5); + waveform6.frequency(f6); + waveform7.frequency(f7); + waveform8.frequency(f8); + waveform9.frequency(f9); + waveform10.frequency(f10); + waveform11.frequency(f11); + waveform12.frequency(f12); + waveform13.frequency(f13); + waveform14.frequency(f14); + waveform15.frequency(f15); + waveform16.frequency(f16); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + noise1.update(&noiseOut); + + // FM from single noise source + waveform1.update(&noiseOut, nullptr, &waveformOut[0]); + waveform2.update(&noiseOut, nullptr, &waveformOut[1]); + waveform3.update(&noiseOut, nullptr, &waveformOut[2]); + waveform4.update(&noiseOut, nullptr, &waveformOut[3]); + waveform5.update(&noiseOut, nullptr, &waveformOut[4]); + waveform6.update(&noiseOut, nullptr, &waveformOut[5]); + waveform7.update(&noiseOut, nullptr, &waveformOut[6]); + waveform8.update(&noiseOut, nullptr, &waveformOut[7]); + waveform9.update(&noiseOut, nullptr, &waveformOut[8]); + waveform10.update(&noiseOut, nullptr, &waveformOut[9]); + waveform11.update(&noiseOut, nullptr, &waveformOut[10]); + waveform12.update(&noiseOut, nullptr, &waveformOut[11]); + waveform13.update(&noiseOut, nullptr, &waveformOut[12]); + waveform14.update(&noiseOut, nullptr, &waveformOut[13]); + waveform15.update(&noiseOut, nullptr, &waveformOut[14]); + waveform16.update(&noiseOut, nullptr, &waveformOut[15]); + + mixer1.update(&waveformOut[0], &waveformOut[1], &waveformOut[2], &waveformOut[3], &mixerOut[0]); + mixer2.update(&waveformOut[4], &waveformOut[5], &waveformOut[6], &waveformOut[7], &mixerOut[1]); + mixer3.update(&waveformOut[8], &waveformOut[9], &waveformOut[10], &waveformOut[11], &mixerOut[2]); + mixer4.update(&waveformOut[12], &waveformOut[13], &waveformOut[14], &waveformOut[15], &mixerOut[3]); + + mixer5.update(&mixerOut[0], &mixerOut[1], &mixerOut[2], &mixerOut[3], &mixerOut[4]); + + blockBuffer.pushBuffer(mixerOut[4].data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return mixer5; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t noiseOut, waveformOut[16] = {}, mixerOut[5] = {}; + + AudioSynthNoiseWhite noise1; //xy=306.20001220703125,530 + AudioSynthWaveformModulated waveform16; //xy=591.2000122070312,906 + AudioSynthWaveformModulated waveform14; //xy=593.2000122070312,801 + AudioSynthWaveformModulated waveform15; //xy=593.2000122070312,846 + AudioSynthWaveformModulated waveform13; //xy=594.2000122070312,759 + AudioSynthWaveformModulated waveform8; //xy=601.2000122070312,486 + AudioSynthWaveformModulated waveform6; //xy=603.2000122070312,381 + AudioSynthWaveformModulated waveform7; //xy=603.2000122070312,426 + AudioSynthWaveformModulated waveform12; //xy=602.2000122070312,697 + AudioSynthWaveformModulated waveform5; //xy=604.2000122070312,339 + AudioSynthWaveformModulated waveform10; //xy=604.2000122070312,592 + AudioSynthWaveformModulated waveform11; //xy=604.2000122070312,637 + AudioSynthWaveformModulated waveform9; //xy=605.2000122070312,550 + AudioSynthWaveformModulated waveform4; //xy=609.2000122070312,271 + AudioSynthWaveformModulated waveform2; //xy=611.2000122070312,166 + AudioSynthWaveformModulated waveform3; //xy=611.2000122070312,211 + AudioSynthWaveformModulated waveform1; //xy=612.2000122070312,123 + AudioMixer4 mixer4; //xy=811.2000122070312,850 + AudioMixer4 mixer3; //xy=822.2000122070312,641 + AudioMixer4 mixer2; //xy=828.2000122070312,430 + AudioMixer4 mixer1; //xy=829.2000122070312,215 + AudioMixer4 mixer5; //xy=1076.2000122070312,427 + + // AudioSynthWaveformModulated waveform16; //xy=581.75,1167.5 + // AudioSynthWaveformModulated waveform14; //xy=583.75,1062.5 + // AudioSynthWaveformModulated waveform15; //xy=583.75,1107.5 + // AudioSynthWaveformModulated waveform13; //xy=584.75,1020 + // AudioSynthWaveformModulated waveform8; //xy=591.75,747.5 + // AudioSynthWaveformModulated waveform6; //xy=593.75,642.5 + // AudioSynthWaveformModulated waveform7; //xy=593.75,687.5 + // AudioSynthWaveformModulated waveform12; //xy=592.75,958.5 + // AudioSynthWaveformModulated waveform5; //xy=594.75,600 + // AudioSynthWaveformModulated waveform10; //xy=594.75,853.5 + // AudioSynthWaveformModulated waveform11; //xy=594.75,898.5 + // AudioSynthWaveformModulated waveform9; //xy=595.75,811 + // AudioSynthWaveformModulated waveform4; //xy=599.75,532.25 + // AudioSynthWaveformModulated waveform2; //xy=601.75,427.25 + // AudioSynthWaveformModulated waveform3; //xy=601.75,472.25 + // AudioSynthWaveformModulated waveform1; //xy=602.75,384.75 + // AudioMixer4 mixer4; //xy=801.75,1111.25 + // AudioMixer4 mixer3; //xy=812.75,902.25 + // AudioMixer4 mixer2; //xy=818.75,691.25 + // AudioMixer4 mixer1; //xy=819.75,476 + // AudioMixer4 mixer5; //xy=1066.75,688 + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + // AudioConnection patchCord5; + // AudioConnection patchCord6; + // AudioConnection patchCord7; + // AudioConnection patchCord8; + // AudioConnection patchCord9; + // AudioConnection patchCord10; + // AudioConnection patchCord11; + // AudioConnection patchCord12; + // AudioConnection patchCord13; + // AudioConnection patchCord14; + // AudioConnection patchCord15; + // AudioConnection patchCord16; + // AudioConnection patchCord17; + // AudioConnection patchCord18; + // AudioConnection patchCord19; + // AudioConnection patchCord20; + // AudioConnection patchCord21; + // AudioConnection patchCord22; + // AudioConnection patchCord23; + // AudioConnection patchCord24; + // AudioConnection patchCord25; + // AudioConnection patchCord26; + // AudioConnection patchCord27; + // AudioConnection patchCord28; + // AudioConnection patchCord29; + // AudioConnection patchCord30; + // AudioConnection patchCord31; + // AudioConnection patchCord32; + // AudioConnection patchCord33; + // AudioConnection patchCord34; + // AudioConnection patchCord35; + // AudioConnection patchCord36; + +}; + +REGISTER_PLUGIN(FibonacciCluster); diff --git a/src/noise-plethora/plugins/P_PrimeCluster.hpp b/src/noise-plethora/plugins/P_PrimeCluster.hpp new file mode 100644 index 0000000..704c090 --- /dev/null +++ b/src/noise-plethora/plugins/P_PrimeCluster.hpp @@ -0,0 +1,245 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class PrimeCluster : public NoisePlethoraPlugin { + +public: + + PrimeCluster() + // : patchCord1(noise1, 0, waveform1, 0) + // , patchCord2(noise1, 0, waveform2, 0) + // , patchCord3(noise1, 0, waveform3, 0) + // , patchCord4(noise1, 0, waveform4, 0) + // , patchCord5(noise1, 0, waveform5, 0) + // , patchCord6(noise1, 0, waveform6, 0) + // , patchCord7(noise1, 0, waveform7, 0) + // , patchCord8(noise1, 0, waveform8, 0) + // , patchCord9(noise1, 0, waveform9, 0) + // , patchCord10(noise1, 0, waveform10, 0) + // , patchCord11(noise1, 0, waveform11, 0) + // , patchCord12(noise1, 0, waveform12, 0) + // , patchCord13(noise1, 0, waveform13, 0) + // , patchCord14(noise1, 0, waveform14, 0) + // , patchCord15(noise1, 0, waveform15, 0) + // , patchCord16(noise1, 0, waveform16, 0) + // , patchCord17(waveform16, 0, mixer4, 3) + // , patchCord18(waveform14, 0, mixer4, 1) + // , patchCord19(waveform15, 0, mixer4, 2) + // , patchCord20(waveform13, 0, mixer4, 0) + // , patchCord21(waveform8, 0, mixer2, 3) + // , patchCord22(waveform6, 0, mixer2, 1) + // , patchCord23(waveform7, 0, mixer2, 2) + // , patchCord24(waveform12, 0, mixer3, 3) + // , patchCord25(waveform5, 0, mixer2, 0) + // , patchCord26(waveform10, 0, mixer3, 1) + // , patchCord27(waveform11, 0, mixer3, 2) + // , patchCord28(waveform9, 0, mixer3, 0) + // , patchCord29(waveform4, 0, mixer1, 3) + // , patchCord30(waveform2, 0, mixer1, 1) + // , patchCord31(waveform3, 0, mixer1, 2) + // , patchCord32(waveform1, 0, mixer1, 0) + // , patchCord33(mixer4, 0, mixer5, 3) + // , patchCord34(mixer3, 0, mixer5, 2) + // , patchCord35(mixer2, 0, mixer5, 1) + // , patchCord36(mixer1, 0, mixer5, 0) + {} + + ~PrimeCluster() override {} + + PrimeCluster(const PrimeCluster&) = delete; + PrimeCluster& operator=(const PrimeCluster&) = delete; + + void init() override { + mixer1.gain(0, 1); + mixer1.gain(1, 1); + mixer1.gain(2, 1); + mixer1.gain(3, 1); + mixer2.gain(0, 1); + mixer2.gain(1, 1); + mixer2.gain(2, 1); + mixer2.gain(3, 1); + mixer3.gain(0, 1); + mixer3.gain(1, 1); + mixer3.gain(2, 1); + mixer3.gain(3, 1); + mixer4.gain(0, 1); + mixer4.gain(1, 1); + mixer4.gain(2, 1); + mixer4.gain(3, 1); + mixer5.gain(0, 1); + mixer5.gain(1, 1); + mixer5.gain(2, 1); + mixer5.gain(3, 1); + + int masterWaveform = WAVEFORM_TRIANGLE_VARIABLE; + float masterVolume = 0.3; + + waveform1.begin(masterVolume, 200, masterWaveform); + waveform2.begin(masterVolume, 647, masterWaveform); + waveform3.begin(masterVolume, 524, masterWaveform); + waveform4.begin(masterVolume, 444, masterWaveform); + waveform5.begin(masterVolume, 368, masterWaveform); + waveform6.begin(masterVolume, 283, masterWaveform); + waveform7.begin(masterVolume, 283, masterWaveform); + waveform8.begin(masterVolume, 283, masterWaveform); + waveform9.begin(masterVolume, 283, masterWaveform); + waveform10.begin(masterVolume, 283, masterWaveform); + waveform11.begin(masterVolume, 283, masterWaveform); + waveform12.begin(masterVolume, 283, masterWaveform); + waveform13.begin(masterVolume, 283, masterWaveform); + waveform14.begin(masterVolume, 283, masterWaveform); + waveform15.begin(masterVolume, 283, masterWaveform); + waveform16.begin(masterVolume, 283, masterWaveform); + } + + void process(float k1, float k2) override { + float multfactor = k1 * 10 + 0.5; + + waveform1.frequency(53 * multfactor); + waveform2.frequency(127 * multfactor); + waveform3.frequency(199 * multfactor); + waveform4.frequency(283 * multfactor); + waveform5.frequency(383 * multfactor); + waveform6.frequency(467 * multfactor); + waveform7.frequency(577 * multfactor); + waveform8.frequency(661 * multfactor); + waveform9.frequency(769 * multfactor); + waveform10.frequency(877 * multfactor); + waveform11.frequency(983 * multfactor); + waveform12.frequency(1087 * multfactor); + waveform13.frequency(1193 * multfactor); + waveform14.frequency(1297 * multfactor); + waveform15.frequency(1429 * multfactor); + waveform16.frequency(1523 * multfactor); + + noise1.amplitude(k2 * 0.2); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + noise1.update(&noiseOut); + + // FM from single noise source + waveform1.update(&noiseOut, nullptr, &waveformOut[0]); + waveform2.update(&noiseOut, nullptr, &waveformOut[1]); + waveform3.update(&noiseOut, nullptr, &waveformOut[2]); + waveform4.update(&noiseOut, nullptr, &waveformOut[3]); + waveform5.update(&noiseOut, nullptr, &waveformOut[4]); + waveform6.update(&noiseOut, nullptr, &waveformOut[5]); + waveform7.update(&noiseOut, nullptr, &waveformOut[6]); + waveform8.update(&noiseOut, nullptr, &waveformOut[7]); + waveform9.update(&noiseOut, nullptr, &waveformOut[8]); + waveform10.update(&noiseOut, nullptr, &waveformOut[9]); + waveform11.update(&noiseOut, nullptr, &waveformOut[10]); + waveform12.update(&noiseOut, nullptr, &waveformOut[11]); + waveform13.update(&noiseOut, nullptr, &waveformOut[12]); + waveform14.update(&noiseOut, nullptr, &waveformOut[13]); + waveform15.update(&noiseOut, nullptr, &waveformOut[14]); + waveform16.update(&noiseOut, nullptr, &waveformOut[15]); + + mixer1.update(&waveformOut[0], &waveformOut[1], &waveformOut[2], &waveformOut[3], &mixerOut[0]); + mixer2.update(&waveformOut[4], &waveformOut[5], &waveformOut[6], &waveformOut[7], &mixerOut[1]); + mixer3.update(&waveformOut[8], &waveformOut[9], &waveformOut[10], &waveformOut[11], &mixerOut[2]); + mixer4.update(&waveformOut[12], &waveformOut[13], &waveformOut[14], &waveformOut[15], &mixerOut[3]); + + mixer5.update(&mixerOut[0], &mixerOut[1], &mixerOut[2], &mixerOut[3], &mixerOut[4]); + + blockBuffer.pushBuffer(mixerOut[4].data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return mixer5; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t noiseOut, waveformOut[16] = {}, mixerOut[5] = {}; + + AudioSynthNoiseWhite noise1; //xy=306.20001220703125,530 + AudioSynthWaveformModulated waveform16; //xy=591.2000122070312,906 + AudioSynthWaveformModulated waveform14; //xy=593.2000122070312,801 + AudioSynthWaveformModulated waveform15; //xy=593.2000122070312,846 + AudioSynthWaveformModulated waveform13; //xy=594.2000122070312,759 + AudioSynthWaveformModulated waveform8; //xy=601.2000122070312,486 + AudioSynthWaveformModulated waveform6; //xy=603.2000122070312,381 + AudioSynthWaveformModulated waveform7; //xy=603.2000122070312,426 + AudioSynthWaveformModulated waveform12; //xy=602.2000122070312,697 + AudioSynthWaveformModulated waveform5; //xy=604.2000122070312,339 + AudioSynthWaveformModulated waveform10; //xy=604.2000122070312,592 + AudioSynthWaveformModulated waveform11; //xy=604.2000122070312,637 + AudioSynthWaveformModulated waveform9; //xy=605.2000122070312,550 + AudioSynthWaveformModulated waveform4; //xy=609.2000122070312,271 + AudioSynthWaveformModulated waveform2; //xy=611.2000122070312,166 + AudioSynthWaveformModulated waveform3; //xy=611.2000122070312,211 + AudioSynthWaveformModulated waveform1; //xy=612.2000122070312,123 + AudioMixer4 mixer4; //xy=811.2000122070312,850 + AudioMixer4 mixer3; //xy=822.2000122070312,641 + AudioMixer4 mixer2; //xy=828.2000122070312,430 + AudioMixer4 mixer1; //xy=829.2000122070312,215 + AudioMixer4 mixer5; //xy=1076.2000122070312,427 + + // AudioSynthWaveformModulated waveform16; //xy=581.75,1167.5 + // AudioSynthWaveformModulated waveform14; //xy=583.75,1062.5 + // AudioSynthWaveformModulated waveform15; //xy=583.75,1107.5 + // AudioSynthWaveformModulated waveform13; //xy=584.75,1020 + // AudioSynthWaveformModulated waveform8; //xy=591.75,747.5 + // AudioSynthWaveformModulated waveform6; //xy=593.75,642.5 + // AudioSynthWaveformModulated waveform7; //xy=593.75,687.5 + // AudioSynthWaveformModulated waveform12; //xy=592.75,958.5 + // AudioSynthWaveformModulated waveform5; //xy=594.75,600 + // AudioSynthWaveformModulated waveform10; //xy=594.75,853.5 + // AudioSynthWaveformModulated waveform11; //xy=594.75,898.5 + // AudioSynthWaveformModulated waveform9; //xy=595.75,811 + // AudioSynthWaveformModulated waveform4; //xy=599.75,532.25 + // AudioSynthWaveformModulated waveform2; //xy=601.75,427.25 + // AudioSynthWaveformModulated waveform3; //xy=601.75,472.25 + // AudioSynthWaveformModulated waveform1; //xy=602.75,384.75 + // AudioMixer4 mixer4; //xy=801.75,1111.25 + // AudioMixer4 mixer3; //xy=812.75,902.25 + // AudioMixer4 mixer2; //xy=818.75,691.25 + // AudioMixer4 mixer1; //xy=819.75,476 + // AudioMixer4 mixer5; //xy=1066.75,688 + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + // AudioConnection patchCord5; + // AudioConnection patchCord6; + // AudioConnection patchCord7; + // AudioConnection patchCord8; + // AudioConnection patchCord9; + // AudioConnection patchCord10; + // AudioConnection patchCord11; + // AudioConnection patchCord12; + // AudioConnection patchCord13; + // AudioConnection patchCord14; + // AudioConnection patchCord15; + // AudioConnection patchCord16; + // AudioConnection patchCord17; + // AudioConnection patchCord18; + // AudioConnection patchCord19; + // AudioConnection patchCord20; + // AudioConnection patchCord21; + // AudioConnection patchCord22; + // AudioConnection patchCord23; + // AudioConnection patchCord24; + // AudioConnection patchCord25; + // AudioConnection patchCord26; + // AudioConnection patchCord27; + // AudioConnection patchCord28; + // AudioConnection patchCord29; + // AudioConnection patchCord30; + // AudioConnection patchCord31; + // AudioConnection patchCord32; + // AudioConnection patchCord33; + // AudioConnection patchCord34; + // AudioConnection patchCord35; + // AudioConnection patchCord36; + +}; + +REGISTER_PLUGIN(PrimeCluster); \ No newline at end of file diff --git a/src/noise-plethora/plugins/P_PrimeCnoise.hpp b/src/noise-plethora/plugins/P_PrimeCnoise.hpp new file mode 100644 index 0000000..b83f0cc --- /dev/null +++ b/src/noise-plethora/plugins/P_PrimeCnoise.hpp @@ -0,0 +1,248 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class PrimeCnoise : public NoisePlethoraPlugin { + +public: + + PrimeCnoise() + // : patchCord1(noise1, 0, waveform1, 0) + // , patchCord2(noise1, 0, waveform2, 0) + // , patchCord3(noise1, 0, waveform3, 0) + // , patchCord4(noise1, 0, waveform4, 0) + // , patchCord5(noise1, 0, waveform5, 0) + // , patchCord6(noise1, 0, waveform6, 0) + // , patchCord7(noise1, 0, waveform7, 0) + // , patchCord8(noise1, 0, waveform8, 0) + // , patchCord9(noise1, 0, waveform9, 0) + // , patchCord10(noise1, 0, waveform10, 0) + // , patchCord11(noise1, 0, waveform11, 0) + // , patchCord12(noise1, 0, waveform12, 0) + // , patchCord13(noise1, 0, waveform13, 0) + // , patchCord14(noise1, 0, waveform14, 0) + // , patchCord15(noise1, 0, waveform15, 0) + // , patchCord16(noise1, 0, waveform16, 0) + // , patchCord17(waveform16, 0, mixer4, 3) + // , patchCord18(waveform14, 0, mixer4, 1) + // , patchCord19(waveform15, 0, mixer4, 2) + // , patchCord20(waveform13, 0, mixer4, 0) + // , patchCord21(waveform8, 0, mixer2, 3) + // , patchCord22(waveform6, 0, mixer2, 1) + // , patchCord23(waveform7, 0, mixer2, 2) + // , patchCord24(waveform12, 0, mixer3, 3) + // , patchCord25(waveform5, 0, mixer2, 0) + // , patchCord26(waveform10, 0, mixer3, 1) + // , patchCord27(waveform11, 0, mixer3, 2) + // , patchCord28(waveform9, 0, mixer3, 0) + // , patchCord29(waveform4, 0, mixer1, 3) + // , patchCord30(waveform2, 0, mixer1, 1) + // , patchCord31(waveform3, 0, mixer1, 2) + // , patchCord32(waveform1, 0, mixer1, 0) + // , patchCord33(mixer4, 0, mixer5, 3) + // , patchCord34(mixer3, 0, mixer5, 2) + // , patchCord35(mixer2, 0, mixer5, 1) + // , patchCord36(mixer1, 0, mixer5, 0) + {} + + ~PrimeCnoise() override {} + + PrimeCnoise(const PrimeCnoise&) = delete; + PrimeCnoise& operator=(const PrimeCnoise&) = delete; + + void init() override { + mixer1.gain(0, 1); + mixer1.gain(1, 1); + mixer1.gain(2, 1); + mixer1.gain(3, 1); + mixer2.gain(0, 1); + mixer2.gain(1, 1); + mixer2.gain(2, 1); + mixer2.gain(3, 1); + mixer3.gain(0, 1); + mixer3.gain(1, 1); + mixer3.gain(2, 1); + mixer3.gain(3, 1); + mixer4.gain(0, 1); + mixer4.gain(1, 1); + mixer4.gain(2, 1); + mixer4.gain(3, 1); + mixer5.gain(0, 1); + mixer5.gain(1, 1); + mixer5.gain(2, 1); + mixer5.gain(3, 1); + + int masterWaveform = WAVEFORM_TRIANGLE_VARIABLE; + float masterVolume = 100; + + waveform1.begin(masterVolume, 200, masterWaveform); + waveform2.begin(masterVolume, 647, masterWaveform); + waveform3.begin(masterVolume, 524, masterWaveform); + waveform4.begin(masterVolume, 444, masterWaveform); + waveform5.begin(masterVolume, 368, masterWaveform); + waveform6.begin(masterVolume, 283, masterWaveform); + waveform7.begin(masterVolume, 283, masterWaveform); + waveform8.begin(masterVolume, 283, masterWaveform); + waveform9.begin(masterVolume, 283, masterWaveform); + waveform10.begin(masterVolume, 283, masterWaveform); + waveform11.begin(masterVolume, 283, masterWaveform); + waveform12.begin(masterVolume, 283, masterWaveform); + waveform13.begin(masterVolume, 283, masterWaveform); + waveform14.begin(masterVolume, 283, masterWaveform); + waveform15.begin(masterVolume, 283, masterWaveform); + waveform16.begin(masterVolume, 283, masterWaveform); + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + + float pitch1 = pow(knob_1, 2); + + float multfactor = pitch1 * 12 + 0.5; + + waveform1.frequency(53 * multfactor); + waveform2.frequency(127 * multfactor); + waveform3.frequency(199 * multfactor); + waveform4.frequency(283 * multfactor); + waveform5.frequency(383 * multfactor); + waveform6.frequency(467 * multfactor); + waveform7.frequency(577 * multfactor); + waveform8.frequency(661 * multfactor); + waveform9.frequency(769 * multfactor); + waveform10.frequency(877 * multfactor); + waveform11.frequency(983 * multfactor); + waveform12.frequency(1087 * multfactor); + waveform13.frequency(1193 * multfactor); + waveform14.frequency(1297 * multfactor); + waveform15.frequency(1429 * multfactor); + waveform16.frequency(1523 * multfactor); + + noise1.amplitude(knob_2 * 0.2); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + noise1.update(&noiseOut); + + // FM from single noise source + waveform1.update(&noiseOut, nullptr, &waveformOut[0]); + waveform2.update(&noiseOut, nullptr, &waveformOut[1]); + waveform3.update(&noiseOut, nullptr, &waveformOut[2]); + waveform4.update(&noiseOut, nullptr, &waveformOut[3]); + waveform5.update(&noiseOut, nullptr, &waveformOut[4]); + waveform6.update(&noiseOut, nullptr, &waveformOut[5]); + waveform7.update(&noiseOut, nullptr, &waveformOut[6]); + waveform8.update(&noiseOut, nullptr, &waveformOut[7]); + waveform9.update(&noiseOut, nullptr, &waveformOut[8]); + waveform10.update(&noiseOut, nullptr, &waveformOut[9]); + waveform11.update(&noiseOut, nullptr, &waveformOut[10]); + waveform12.update(&noiseOut, nullptr, &waveformOut[11]); + waveform13.update(&noiseOut, nullptr, &waveformOut[12]); + waveform14.update(&noiseOut, nullptr, &waveformOut[13]); + waveform15.update(&noiseOut, nullptr, &waveformOut[14]); + waveform16.update(&noiseOut, nullptr, &waveformOut[15]); + + mixer1.update(&waveformOut[0], &waveformOut[1], &waveformOut[2], &waveformOut[3], &mixerOut[0]); + mixer2.update(&waveformOut[4], &waveformOut[5], &waveformOut[6], &waveformOut[7], &mixerOut[1]); + mixer3.update(&waveformOut[8], &waveformOut[9], &waveformOut[10], &waveformOut[11], &mixerOut[2]); + mixer4.update(&waveformOut[12], &waveformOut[13], &waveformOut[14], &waveformOut[15], &mixerOut[3]); + + mixer5.update(&mixerOut[0], &mixerOut[1], &mixerOut[2], &mixerOut[3], &mixerOut[4]); + + blockBuffer.pushBuffer(mixerOut[4].data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return mixer5; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t noiseOut, waveformOut[16] = {}, mixerOut[5] = {}; + + AudioSynthNoiseWhite noise1; //xy=306.20001220703125,530 + AudioSynthWaveformModulated waveform16; //xy=591.2000122070312,906 + AudioSynthWaveformModulated waveform14; //xy=593.2000122070312,801 + AudioSynthWaveformModulated waveform15; //xy=593.2000122070312,846 + AudioSynthWaveformModulated waveform13; //xy=594.2000122070312,759 + AudioSynthWaveformModulated waveform8; //xy=601.2000122070312,486 + AudioSynthWaveformModulated waveform6; //xy=603.2000122070312,381 + AudioSynthWaveformModulated waveform7; //xy=603.2000122070312,426 + AudioSynthWaveformModulated waveform12; //xy=602.2000122070312,697 + AudioSynthWaveformModulated waveform5; //xy=604.2000122070312,339 + AudioSynthWaveformModulated waveform10; //xy=604.2000122070312,592 + AudioSynthWaveformModulated waveform11; //xy=604.2000122070312,637 + AudioSynthWaveformModulated waveform9; //xy=605.2000122070312,550 + AudioSynthWaveformModulated waveform4; //xy=609.2000122070312,271 + AudioSynthWaveformModulated waveform2; //xy=611.2000122070312,166 + AudioSynthWaveformModulated waveform3; //xy=611.2000122070312,211 + AudioSynthWaveformModulated waveform1; //xy=612.2000122070312,123 + AudioMixer4 mixer4; //xy=811.2000122070312,850 + AudioMixer4 mixer3; //xy=822.2000122070312,641 + AudioMixer4 mixer2; //xy=828.2000122070312,430 + AudioMixer4 mixer1; //xy=829.2000122070312,215 + AudioMixer4 mixer5; //xy=1076.2000122070312,427 + + // AudioSynthWaveformModulated waveform16; //xy=581.75,1167.5 + // AudioSynthWaveformModulated waveform14; //xy=583.75,1062.5 + // AudioSynthWaveformModulated waveform15; //xy=583.75,1107.5 + // AudioSynthWaveformModulated waveform13; //xy=584.75,1020 + // AudioSynthWaveformModulated waveform8; //xy=591.75,747.5 + // AudioSynthWaveformModulated waveform6; //xy=593.75,642.5 + // AudioSynthWaveformModulated waveform7; //xy=593.75,687.5 + // AudioSynthWaveformModulated waveform12; //xy=592.75,958.5 + // AudioSynthWaveformModulated waveform5; //xy=594.75,600 + // AudioSynthWaveformModulated waveform10; //xy=594.75,853.5 + // AudioSynthWaveformModulated waveform11; //xy=594.75,898.5 + // AudioSynthWaveformModulated waveform9; //xy=595.75,811 + // AudioSynthWaveformModulated waveform4; //xy=599.75,532.25 + // AudioSynthWaveformModulated waveform2; //xy=601.75,427.25 + // AudioSynthWaveformModulated waveform3; //xy=601.75,472.25 + // AudioSynthWaveformModulated waveform1; //xy=602.75,384.75 + // AudioMixer4 mixer4; //xy=801.75,1111.25 + // AudioMixer4 mixer3; //xy=812.75,902.25 + // AudioMixer4 mixer2; //xy=818.75,691.25 + // AudioMixer4 mixer1; //xy=819.75,476 + // AudioMixer4 mixer5; //xy=1066.75,688 + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + // AudioConnection patchCord5; + // AudioConnection patchCord6; + // AudioConnection patchCord7; + // AudioConnection patchCord8; + // AudioConnection patchCord9; + // AudioConnection patchCord10; + // AudioConnection patchCord11; + // AudioConnection patchCord12; + // AudioConnection patchCord13; + // AudioConnection patchCord14; + // AudioConnection patchCord15; + // AudioConnection patchCord16; + // AudioConnection patchCord17; + // AudioConnection patchCord18; + // AudioConnection patchCord19; + // AudioConnection patchCord20; + // AudioConnection patchCord21; + // AudioConnection patchCord22; + // AudioConnection patchCord23; + // AudioConnection patchCord24; + // AudioConnection patchCord25; + // AudioConnection patchCord26; + // AudioConnection patchCord27; + // AudioConnection patchCord28; + // AudioConnection patchCord29; + // AudioConnection patchCord30; + // AudioConnection patchCord31; + // AudioConnection patchCord32; + // AudioConnection patchCord33; + // AudioConnection patchCord34; + // AudioConnection patchCord35; + // AudioConnection patchCord36; +}; + +REGISTER_PLUGIN(PrimeCnoise); diff --git a/src/noise-plethora/plugins/P_Rwalk_BitCrushPW.hpp b/src/noise-plethora/plugins/P_Rwalk_BitCrushPW.hpp new file mode 100644 index 0000000..54ab7ff --- /dev/null +++ b/src/noise-plethora/plugins/P_Rwalk_BitCrushPW.hpp @@ -0,0 +1,258 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class Rwalk_BitCrushPW : public NoisePlethoraPlugin { + +public: + + Rwalk_BitCrushPW() + //: patchCord4(waveform8, 0, mixer2, 3) + //, patchCord6(waveform9, 0, mixer3, 0) + //, patchCord9(waveform7, 0, mixer2, 2) + //, patchCord11(waveform4, 0, mixer1, 3) + //, patchCord12(waveform5, 0, mixer2, 0) + //, patchCord13(waveform6, 0, mixer2, 1) + //, patchCord14(waveform3, 0, mixer1, 2) + //, patchCord15(waveform1, 0, mixer1, 0) + //, patchCord16(waveform2, 0, mixer1, 1) + //, patchCord17(mixer2, 0, mixer5, 2) + //, patchCord18(mixer1, 0, mixer5, 1) + //, patchCord19(mixer3, 0, mixer6, 1) + //, patchCord21(mixer6, freeverb1) + //, patchCord22(mixer5, bitcrusher1) + //, patchCord23(bitcrusher1, 0, mixer7, 1) + //, patchCord24(freeverb1, 0, mixer7, 2) + { } + ~Rwalk_BitCrushPW() override {} + + // delete copy constructors + Rwalk_BitCrushPW(const Rwalk_BitCrushPW&) = delete; + Rwalk_BitCrushPW& operator=(const Rwalk_BitCrushPW&) = delete; + + void init() override { + + L = 600; // Size of box: maximum frequency + v_0 = 30; // speed: size of step in frequency units. + + mixer1.gain(0, 1); + mixer1.gain(1, 1); + mixer1.gain(2, 1); + mixer1.gain(3, 1); + mixer2.gain(0, 1); + mixer2.gain(1, 1); + mixer2.gain(2, 1); + mixer2.gain(3, 1); + // mixer3.gain(0, 1); + // mixer3.gain(1, 1); + // mixer3.gain(2, 1); + // mixer3.gain(3, 1); + + // SINE + int masterWaveform = WaveformType::WAVEFORM_PULSE; + + waveform1.pulseWidth(0.2); + waveform1.begin(1, 794, masterWaveform); + + waveform2.pulseWidth(0.2); + waveform2.begin(1, 647, masterWaveform); + + waveform3.pulseWidth(0.2); + waveform3.begin(1, 524, masterWaveform); + + waveform4.pulseWidth(0.2); + waveform4.begin(1, 444, masterWaveform); + + waveform5.pulseWidth(0.2); + waveform5.begin(1, 368, masterWaveform); + + waveform6.pulseWidth(0.2); + waveform6.begin(1, 283, masterWaveform); + + waveform7.pulseWidth(0.2); + waveform7.begin(1, 283, masterWaveform); + + waveform8.pulseWidth(0.2); + waveform8.begin(1, 283, masterWaveform); + + waveform9.pulseWidth(0.2); + waveform9.begin(1, 283, masterWaveform); + + + // random walk initial conditions + for (int i = 0; i < 9; i++) { + // velocities: initial conditions in -pi : +pi + theta = M_PI * (random::uniform() * 2.0 - 1.0); + vx[i] = std::cos(theta); + vy[i] = std::sin(theta); + // positions: random in [0,L] x [0, L] + x[i] = random::uniform() * L; + y[i] = random::uniform() * L; + + } + } + + void process(float k1, float k2) override { + + float knob_1 = k1; + float knob_2 = k2; + + float dL; + + dL = L + 100; + + v_var = v_0; + + bc_01 = (knob_1 - 0) * (0.75 - 0.2) / (1 - 0) + 0.2; // función para recortar intervalo de 0.1 a 0.9 + + + bitcrusher1.bits(1); + + fv = knob_2; + freeverb1.roomsize(fv); + + // loop to "walk" randomly + for (int i = 0; i < 9; i++) { + theta = M_PI * (random::uniform() * 2.0 - 1.0); + + posx = std::cos(theta); + vx[i] = posx; + + posy = std::sin(theta); + vy[i] = posy; + + // Update new position + xn = x[i] + v_var * vx[i]; + yin = y[i] + v_var * vy[i]; + + // periodic boundary conditions + if (xn < 50) + //xn += dL; + xn += 10; + else if (xn > dL) + //xn -= dL; + xn -= 10; + + if (yin < 0.01) + yin += dL; + else if (yin > dL) + yin -= dL; + x[i] = xn; + y[i] = yin; + + } + + + + waveform1.frequency(x[0]); + waveform2.frequency(x[1]); + waveform3.frequency(x[2]); + waveform4.frequency(x[3]); + waveform5.frequency(x[4]); + waveform6.frequency(x[5]); + waveform7.frequency(x[6]); + waveform8.frequency(x[7]); + waveform9.frequency(x[8]); + + waveform1.pulseWidth(bc_01); + waveform2.pulseWidth(bc_01); + waveform3.pulseWidth(bc_01); + waveform4.pulseWidth(bc_01); + waveform5.pulseWidth(bc_01); + waveform6.pulseWidth(bc_01); + waveform7.pulseWidth(bc_01); + waveform8.pulseWidth(bc_01); + waveform9.pulseWidth(bc_01); + + } + + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + // sum first block of oscillators + waveform1.update(&waveformBlock[0]); + waveform2.update(&waveformBlock[1]); + waveform3.update(&waveformBlock[2]); + waveform4.update(&waveformBlock[3]); + mixer1.update(&waveformBlock[0], &waveformBlock[1], &waveformBlock[2], &waveformBlock[3], &mixerBlock[0]); + + // sum second block of oscillators + waveform5.update(&waveformBlock[4]); + waveform6.update(&waveformBlock[5]); + waveform7.update(&waveformBlock[6]); + waveform8.update(&waveformBlock[7]); + mixer2.update(&waveformBlock[4], &waveformBlock[5], &waveformBlock[6], &waveformBlock[7], &mixerBlock[1]); + + // sum two blocks and feed into bitcrusher + mixer5.update(&mixerBlock[0], &mixerBlock[1], nullptr, nullptr, &mixerBlock[2]); + bitcrusher1.update(&mixerBlock[2], &bitcrushBlock); + + waveform9.update(&waveformBlock[8]); + // mixer3/6 are just one-input + unit gain so just skip to freeverb + freeverb1.update(&waveformBlock[8], &freeverbBlock); + + // finally sum bitcrush and freeverb + mixer7.update(&bitcrushBlock, &freeverbBlock, nullptr, nullptr, &mixerBlock[3]); + + blockBuffer.pushBuffer(mixerBlock[3].data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return mixer7; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t waveformBlock[9], mixerBlock[4], bitcrushBlock, freeverbBlock; + + /* will be filled in */ + // GUItool: begin automatically generated code + AudioSynthWaveform waveform8; //xy=519.75,577.75 + AudioSynthWaveform waveform9; //xy=519.75,614.75 + AudioSynthWaveform waveform7; //xy=520.75,541.75 + AudioSynthWaveform waveform4; //xy=521.75,427.75 + AudioSynthWaveform waveform5; //xy=521.75,466.75 + AudioSynthWaveform waveform6; //xy=521.75,504.75 + AudioSynthWaveform waveform3; //xy=522.75,391.75 + AudioSynthWaveform waveform1; //xy=523.75,316.75 + AudioSynthWaveform waveform2; //xy=523.75,354.75 + AudioMixer4 mixer2; //xy=713.75,528.75 + AudioMixer4 mixer1; //xy=714.75,377.75 + //AudioMixer4 mixer3; //xy=716.75,664.75 + //AudioMixer4 mixer6; //xy=1248,561 + + AudioMixer4 mixer5; //xy=961.75,589.75 + + AudioEffectBitcrusher bitcrusher1; //xy=1439,393 + AudioEffectFreeverb freeverb1; //xy=923.5,281.5 + AudioMixer4 mixer7; //xy=1650,448 + + //AudioOutputI2S i2s1; //xy=1227.75,604.75 + // AudioConnection patchCord4(waveform8, 0, mixer2, 3); + // AudioConnection patchCord6(waveform9, 0, mixer3, 0); + // AudioConnection patchCord9(waveform7, 0, mixer2, 2); + // AudioConnection patchCord11(waveform4, 0, mixer1, 3); + // AudioConnection patchCord12(waveform5, 0, mixer2, 0); + // AudioConnection patchCord13(waveform6, 0, mixer2, 1); + // AudioConnection patchCord14(waveform3, 0, mixer1, 2); + // AudioConnection patchCord15(waveform1, 0, mixer1, 0); + // AudioConnection patchCord16(waveform2, 0, mixer1, 1); + // AudioConnection patchCord17(mixer2, 0, mixer5, 2); + // AudioConnection patchCord18(mixer1, 0, mixer5, 1); + // AudioConnection patchCord19(mixer3, 0, mixer6, 1); + // AudioConnection patchCord21(mixer6, freeverb1); + // AudioConnection patchCord22(mixer5, bitcrusher1); + // AudioConnection patchCord23(bitcrusher1, 0, mixer7, 1); + // AudioConnection patchCord24(freeverb1, 0, mixer7, 2); + + + int L; //, i, t; + float theta, posx, posy, xn, yin; + float v_0, v_var, bc_01, fv;//pw = pulse width + float x[9], y[9], vx[9], vy[9]; // number depends on waveforms declared + +}; + +REGISTER_PLUGIN(Rwalk_BitCrushPW); // this is important, so that we can include the plugin in a bank diff --git a/src/noise-plethora/plugins/P_Rwalk_LFree.hpp b/src/noise-plethora/plugins/P_Rwalk_LFree.hpp new file mode 100644 index 0000000..d4a07e6 --- /dev/null +++ b/src/noise-plethora/plugins/P_Rwalk_LFree.hpp @@ -0,0 +1,156 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class Rwalk_LFree : public NoisePlethoraPlugin { + +public: + + Rwalk_LFree() + // : patchCord1(pwm2, 0, mixer5, 1) + // , patchCord2(pwm1, 0, mixer5, 0) + // , patchCord3(pwm3, 0, mixer5, 2) + // , patchCord4(pwm4, 0, mixer5, 3) + // , patchCord5(mixer5, freeverb1) + { } + + ~Rwalk_LFree() override {} + + // delete copy constructors + Rwalk_LFree(const Rwalk_LFree&) = delete; + Rwalk_LFree& operator=(const Rwalk_LFree&) = delete; + + void init() override { + + L = 500; // Size of box: maximum frequency + v_0 = 5; // speed: size of step in frequency units. + + mixer5.gain(0, 1); + mixer5.gain(1, 1); + mixer5.gain(2, 1); + mixer5.gain(3, 1); + + + pwm1.frequency(794); + pwm1.amplitude(1); + + pwm2.frequency(647); + pwm2.amplitude(1); + + pwm3.frequency(524); + pwm3.amplitude(1); + + pwm4.frequency(444); + pwm4.amplitude(1); + + // random walk initial conditions + for (int i = 0; i < 4; i++) { + // velocities: initial conditions in -pi : +pi + theta = M_PI * (random::uniform() * 2.0 - 1.0); + vx[i] = std::cos(theta); + vy[i] = std::sin(theta); + // positions: random in [0,L] x [0, L] + x[i] = random::uniform() * L; + y[i] = random::uniform() * L; + } + } + + void process(float k1, float k2) override { + + float knob_1 = k1; + float knob_2 = k2; + float dL, fv; + + dL = knob_1 * L + 50; + + v_var = v_0; + + fv = knob_2; + freeverb1.roomsize(fv); + + // loop to "walk" randomly + for (int i = 0; i < 4; i++) { + theta = M_PI * (random::uniform() * 2.0 - 1.0); + + posx = std::cos(theta); + vx[i] = posx; + + posy = std::sin(theta); + vy[i] = posy; + + // Update new position + xn = x[i] + v_var * vx[i]; + yin = y[i] + v_var * vy[i]; + + // periodic boundary conditions + if (xn < 40) + //xn += dL; + xn += 10; + else if (xn > dL) + //xn -= dL; + xn -= 10; + + if (yin < 0.01) + yin += dL; + else if (yin > dL) + yin -= dL; + x[i] = xn; + y[i] = yin; + } + pwm1.frequency(x[0]); + pwm2.frequency(x[1]); + pwm3.frequency(x[2]); + pwm4.frequency(x[3]); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + pwm1.update(nullptr, &pwmBlock[0]); + pwm2.update(nullptr, &pwmBlock[1]); + pwm3.update(nullptr, &pwmBlock[2]); + pwm4.update(nullptr, &pwmBlock[3]); + + mixer5.update(&pwmBlock[0], &pwmBlock[1], &pwmBlock[2], &pwmBlock[3], &mixerBlock); + freeverb1.update(&mixerBlock, &freeverbBlock); + + blockBuffer.pushBuffer(freeverbBlock.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return freeverb1; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t pwmBlock[4], mixerBlock, freeverbBlock; + + /* will be filled in */ + // GUItool: begin automatically generated code + + AudioMixer4 mixer5; //xy=961.75,589.75 + + AudioSynthWaveformPWM pwm2; //xy=588.5,279.5 + AudioSynthWaveformPWM pwm1; //xy=589.5,228.5 + AudioSynthWaveformPWM pwm3; //xy=593.5,331.5 + AudioSynthWaveformPWM pwm4; //xy=596.5,375.5 + + AudioEffectFreeverb freeverb1; + + //AudioOutputI2S i2s1; //xy=1227.75,604.75 + //AudioConnection patchCord1; + //AudioConnection patchCord2; + //AudioConnection patchCord3; + //AudioConnection patchCord4; + //AudioConnection patchCord5; + + int L; //, i, t; + float theta, posx, posy, xn, yin; + float v_0, v_var;//pw = pulse width + float x[4], y[4], vx[4], vy[4]; // number depends on waveforms declared + +}; + +REGISTER_PLUGIN(Rwalk_LFree); // this is important, so that we can include the plugin in a bank diff --git a/src/noise-plethora/plugins/P_Rwalk_SineFMFlange.hpp b/src/noise-plethora/plugins/P_Rwalk_SineFMFlange.hpp new file mode 100644 index 0000000..b4cf41c --- /dev/null +++ b/src/noise-plethora/plugins/P_Rwalk_SineFMFlange.hpp @@ -0,0 +1,199 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +#define FLANGE_DELAY_LENGTH (2*AUDIO_BLOCK_SAMPLES) + +class Rwalk_SineFMFlange : public NoisePlethoraPlugin { + +public: + + Rwalk_SineFMFlange() + // : patchCord1(waveform4, sine_fm3) + // , patchCord2(waveform3, sine_fm4) + // , patchCord3(waveform2, sine_fm2) + // , patchCord4(waveform1, sine_fm1) + // , patchCord5(sine_fm3, 0, mixer1, 3) + // , patchCord6(sine_fm2, 0, mixer1, 1) + // , patchCord7(sine_fm1, 0, mixer1, 0) + // , patchCord8(sine_fm4, 0, mixer1, 2) + // , patchCord9(mixer1, flange1) + { } + + ~Rwalk_SineFMFlange() override {} + + // delete copy constructors + Rwalk_SineFMFlange(const Rwalk_SineFMFlange&) = delete; + Rwalk_SineFMFlange& operator=(const Rwalk_SineFMFlange&) = delete; + + void init() override { + + L = 600; // Size of box: maximum frequency + v_0 = 30; // speed: size of step in frequency units. + + mixer1.gain(0, 1); + mixer1.gain(2, 1); + + sine_fm1.amplitude(1); + sine_fm2.amplitude(1); + sine_fm3.amplitude(1); + sine_fm4.amplitude(1); + + flange1.begin(l_delayline, FLANGE_DELAY_LENGTH, s_idx, s_depth, s_freq); + + int masterWaveform = WAVEFORM_PULSE; + + + waveform1.pulseWidth(0.2); + waveform1.begin(1, 794, masterWaveform); + + waveform2.pulseWidth(0.2); + waveform2.begin(1, 647, masterWaveform); + + waveform3.pulseWidth(0.2); + waveform3.begin(1, 750, masterWaveform); + + waveform4.pulseWidth(0.2); + waveform4.begin(1, 200, masterWaveform); + + + // random walk initial conditions + for (int i = 0; i < 4; i++) { + // velocities: initial conditions in -pi : +pi + theta = M_PI * (random::uniform() * (2.0) - 1.0); + vx[i] = cos(theta); + vy[i] = sin(theta); + // positions: random in [0,L] x [0, L] + x[i] = random::uniform() * (L); + y[i] = random::uniform() * (L); + } + } + + void process(float k1, float k2) override { + + + float knob_1 = k1; + float knob_2 = k2; + float dL; + + dL = L + 100; + + v_var = v_0; + + snfm = knob_1 * 500 + 10; + + mod_freq = knob_2 * 3; + + + // loop to "walk" randomly + for (int i = 0; i < 4; i++) { + theta = M_PI * (random::uniform() * (2.0) - 1.0); + + posx = cos(theta); + vx[i] = posx; + + posy = sin(theta); + vy[i] = posy; + + // Update new position + xn = x[i] + v_var * vx[i]; + yin = y[i] + v_var * vy[i]; + + // periodic boundary conditions + if (xn < 50) + //xn += dL; + xn += 10; + else if (xn > dL) + //xn -= dL; + xn -= 10; + + if (yin < 0.01) + yin += dL; + else if (yin > dL) + yin -= dL; + x[i] = xn; + y[i] = yin; + } + sine_fm1.frequency(snfm); + sine_fm2.frequency(snfm + 55); + sine_fm3.frequency(snfm + 65); + sine_fm4.frequency(snfm + 75); + + flange1.voices(s_idx, s_depth, mod_freq); + + + waveform1.frequency(x[0]); + waveform2.frequency(x[1]); + waveform3.frequency(x[2]); + waveform4.frequency(x[3]); + } + + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + waveform1.update(&waveformBlock[0]); + waveform2.update(&waveformBlock[1]); + waveform3.update(&waveformBlock[2]); + waveform4.update(&waveformBlock[3]); + + sine_fm1.update(&waveformBlock[0], &sineFMBlock[0]); + sine_fm2.update(&waveformBlock[1], &sineFMBlock[1]); + sine_fm3.update(&waveformBlock[2], &sineFMBlock[2]); + sine_fm4.update(&waveformBlock[3], &sineFMBlock[3]); + + mixer1.update(&sineFMBlock[0], &sineFMBlock[1], &sineFMBlock[2], &sineFMBlock[3], &mixerBlock); + flange1.update(&mixerBlock, &flangeBlock); + + blockBuffer.pushBuffer(flangeBlock.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return flange1; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t waveformBlock[4], sineFMBlock[4], flangeBlock, mixerBlock; + + AudioSynthWaveform waveform1; + AudioSynthWaveform waveform2; + AudioSynthWaveform waveform3; + AudioSynthWaveform waveform4; + AudioSynthWaveformSineModulated sine_fm3; + AudioSynthWaveformSineModulated sine_fm2; + AudioSynthWaveformSineModulated sine_fm1; + AudioSynthWaveformSineModulated sine_fm4; + + AudioEffectFlange flange1; + AudioMixer4 mixer1; + + + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + // AudioConnection patchCord5; + // AudioConnection patchCord6; + // AudioConnection patchCord7; + // AudioConnection patchCord8; + // AudioConnection patchCord9; + + + int L; //, i, t; + float theta, posx, posy, xn, yin; + float v_0, v_var, snfm;//pw = pulse width + float x[4], y[4], vx[4], vy[4]; // number depends on waveforms declared + + /*Variables for flange effect*/ + short l_delayline[FLANGE_DELAY_LENGTH]; //left channel + int s_idx = 2 * FLANGE_DELAY_LENGTH / 4; + int s_depth = FLANGE_DELAY_LENGTH / 4; + double s_freq = 3; + double mod_freq; + +}; + +REGISTER_PLUGIN(Rwalk_SineFMFlange); // this is important, so that we can include the plugin in a bank diff --git a/src/noise-plethora/plugins/P_S_H.hpp b/src/noise-plethora/plugins/P_S_H.hpp new file mode 100644 index 0000000..61a64a3 --- /dev/null +++ b/src/noise-plethora/plugins/P_S_H.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class S_H : public NoisePlethoraPlugin { + +public: + + S_H() + //: patchCord1(waveformMod1, 0, mixer1, 0) + //, patchCord2(waveformMod1, freeverb1) + //, patchCord3(freeverb1, 0, mixer1, 1) + { } + + ~S_H() override {} + + S_H(const S_H&) = delete; + S_H& operator=(const S_H&) = delete; + + void init() override { + waveformMod1.begin(1, 200, WAVEFORM_SAMPLE_HOLD); + waveformMod1.frequencyModulation(10); + + freeverb1.damping(1); + freeverb1.roomsize(0.5); + + mixer1.gain(0, 1); + mixer1.gain(1, 0); + } + + void process(float k1, float k2) override { + waveformMod1.frequency(5000 * k1 + 15); + mixer1.gain(0, 1 - k2); + mixer1.gain(1, k2 * 4); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + waveformMod1.update(nullptr, nullptr, &waveformModBlock); + freeverb1.update(&waveformModBlock, &freeverbBlock); + mixer1.update(&waveformModBlock, &freeverbBlock, nullptr, nullptr, &mixerBlock); + + blockBuffer.pushBuffer(mixerBlock.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return mixer1; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t waveformModBlock, mixerBlock, freeverbBlock; + + AudioSynthWaveformModulated waveformMod1; //xy=517.5666656494141,413.99998474121094 + AudioEffectFreeverb freeverb1; //xy=711.5666656494141,465.99998474121094 + AudioMixer4 mixer1; //xy=868.5666656494141,399.99998474121094 + //AudioConnection patchCord1(waveformMod1, 0, mixer1, 0); + //AudioConnection patchCord2(waveformMod1, freeverb1); + //AudioConnection patchCord3(freeverb1, 0, mixer1, 1); + +}; + +REGISTER_PLUGIN(S_H); diff --git a/src/noise-plethora/plugins/P_TeensyAlt.hpp b/src/noise-plethora/plugins/P_TeensyAlt.hpp new file mode 100644 index 0000000..9dfbe03 --- /dev/null +++ b/src/noise-plethora/plugins/P_TeensyAlt.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class TeensyAlt : public NoisePlethoraPlugin { + +public: + + TeensyAlt() + //:patchCord1(waveformMod1, 0, waveformMod2, 1), + //patchCord3(waveformMod2, 0, waveformMod1, 0) + { } + + ~TeensyAlt() override {} + + TeensyAlt(const TeensyAlt&) = delete; + TeensyAlt& operator=(const TeensyAlt&) = delete; + + void init() override { + + waveform1.begin(1, 200, WAVEFORM_SAMPLE_HOLD); + filter1.resonance(5); + + DEBUG("init finished"); + } + + void process(float k1, float k2) override { + + float knob_1 = k1; + float knob_2 = k2; + (void) knob_2; + + float pitch1 = pow(knob_1, 2); + // float pitch2 = pow(knob_2, 2); + + waveform1.frequency(50 + (pitch1 * 5000)); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + waveform1.update(&output1); + filter1.update(&output1, nullptr, &filterOutLP, &filterOutBP, &filterOutHP); + + blockBuffer.pushBuffer(filterOutBP.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return filter1; + } + unsigned char getPort() override { + return 0; + } + +private: + audio_block_t output1 = {}; + audio_block_t filterOutLP, filterOutBP, filterOutHP; + + + AudioSynthWaveform waveform1; //xy=829.0908737182617,499.54540252685547 + AudioFilterStateVariable filter1; //xy=1062.2726001739502,460.8181266784668 + +}; + +REGISTER_PLUGIN(TeensyAlt); diff --git a/src/noise-plethora/plugins/P_TestPlugin.hpp b/src/noise-plethora/plugins/P_TestPlugin.hpp new file mode 100644 index 0000000..a4fff57 --- /dev/null +++ b/src/noise-plethora/plugins/P_TestPlugin.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include + +#include "NoisePlethoraPlugin.hpp" + + +class TestPlugin : public NoisePlethoraPlugin { + +public: + + TestPlugin() + //: patchCord1(waveformMod1, 0, waveformMod2, 1), + //patchCord3(waveformMod2, 0, waveformMod1, 0) + { } + + ~TestPlugin() override {} + + TestPlugin(const TestPlugin&) = delete; + TestPlugin& operator=(const TestPlugin&) = delete; + + void init() override { + //test.begin(WaveformType::WAVEFORM_SQUARE); + //test.offset(1); + + /* + int masterVolume= 1; + waveformMod1.begin(WAVEFORM_SQUARE); + waveformMod2.begin(WAVEFORM_PULSE); + waveformMod1.offset(1); + waveformMod1.amplitude(masterVolume); + waveformMod2.amplitude(masterVolume); + */ + + waveform1.amplitude(1.0); + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + float pitch1 = std::pow(knob_1, 2); + + waveform1.frequency((pitch1 * 10000)); + if (knob_2 > 0.5) { + waveform1.begin((knob_2 > 0.75) ? WAVEFORM_SQUARE : WAVEFORM_SINE); + } + else { + waveform1.begin((knob_2 > 0.25) ? WAVEFORM_TRIANGLE : WAVEFORM_SAWTOOTH); + } + + //waveformMod1.frequency(10+(pitch1*50)); + //waveformMod2.frequency(10+(knob_2*200)); + //waveformMod1.frequencyModulation(knob_2*8+3); + //DEBUG(string::f("%g %d %g %g", waveform1.frequency, waveform1.tone_type, k1, k2).c_str()); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + // waveformMod1 + waveform1.update(nullptr, nullptr, &waveformOut); + blockBuffer.pushBuffer(waveformOut.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return waveform1; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t waveformOut; + + AudioSynthWaveformModulated waveform1; + + //AudioSynthWaveformModulated waveformMod1; //xy=334,349 + //AudioSynthWaveformModulated waveformMod2; //xy=616,284 + //AudioConnection patchCord1; + //AudioConnection patchCord3; + +}; + + +REGISTER_PLUGIN(TestPlugin); \ No newline at end of file diff --git a/src/noise-plethora/plugins/P_TriFMcluster.hpp b/src/noise-plethora/plugins/P_TriFMcluster.hpp new file mode 100644 index 0000000..d8acd3c --- /dev/null +++ b/src/noise-plethora/plugins/P_TriFMcluster.hpp @@ -0,0 +1,168 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class TriFMcluster : public NoisePlethoraPlugin { + +public: + + TriFMcluster() + // : patchCord1(modulator1, 0, waveform1, 0), + // patchCord2(modulator3, 0, waveform3, 0), + // patchCord3(modulator2, 0, waveform2, 0), + // patchCord4(modulator5, 0, waveform5, 0), + // patchCord5(modulator4, 0, waveform4, 0), + // patchCord6(modulator6, 0, waveform6, 0), + // patchCord7(waveform1, 0, mixer1, 0), + // patchCord8(waveform4, 0, mixer1, 3), + // patchCord9(waveform2, 0, mixer1, 1), + // patchCord10(waveform3, 0, mixer1, 2), + // patchCord11(waveform6, 0, mixer2, 1), + // patchCord12(waveform5, 0, mixer2, 0), + // patchCord13(mixer2, 0, mixer5, 1), + // patchCord14(mixer1, 0, mixer5, 0) + { } + + ~TriFMcluster() override {} + + TriFMcluster(const TriFMcluster&) = delete; + TriFMcluster& operator=(const TriFMcluster&) = delete; + + void init() override { + mixer1.gain(0, 1); + mixer1.gain(1, 1); + mixer1.gain(2, 1); + mixer1.gain(3, 1); + mixer2.gain(0, 1); + mixer2.gain(1, 1); + mixer2.gain(2, 1); + mixer2.gain(3, 1); + mixer5.gain(0, 1); + mixer5.gain(1, 1); + mixer5.gain(2, 1); + mixer5.gain(3, 1); + + int masterWaveform = WAVEFORM_TRIANGLE; + float masterVolume = 0.25; + + waveform1.begin(masterVolume, 794, masterWaveform); + waveform2.begin(masterVolume, 647, masterWaveform); + waveform3.begin(masterVolume, 524, masterWaveform); + waveform4.begin(masterVolume, 444, masterWaveform); + waveform5.begin(masterVolume, 368, masterWaveform); + waveform6.begin(masterVolume, 283, masterWaveform); + + modulator1.begin(1, 1000, WAVEFORM_SINE); + modulator2.begin(1, 1000, WAVEFORM_SINE); + modulator3.begin(1, 1000, WAVEFORM_SINE); + modulator4.begin(1, 1000, WAVEFORM_SINE); + modulator5.begin(1, 1000, WAVEFORM_SINE); + modulator6.begin(1, 1000, WAVEFORM_SINE); + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + float pitch1 = pow(knob_1, 2); + + float f1 = 300 + pitch1 * 8000; + float f2 = f1 * 1.227; + float f3 = f2 * 1.24; + float f4 = f3 * 1.17; + float f5 = f4 * 1.2; + float f6 = f5 * 1.3; + + float index = knob_2 * 0.9 + 0.1; + float indexFreq = 0.07; + + modulator1.amplitude(index); + modulator2.amplitude(index); + modulator3.amplitude(index); + modulator4.amplitude(index); + modulator5.amplitude(index); + modulator6.amplitude(index); + + + modulator1.frequency(f1 * indexFreq); + modulator2.frequency(f2 * indexFreq); + modulator3.frequency(f3 * indexFreq); + modulator4.frequency(f4 * indexFreq); + modulator5.frequency(f5 * indexFreq); + modulator6.frequency(f6 * indexFreq); + + + waveform1.frequency(f1); + waveform2.frequency(f2); + waveform3.frequency(f3); + waveform4.frequency(f4); + waveform5.frequency(f5); + waveform6.frequency(f6); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + // modulators for the 6 oscillators + modulator1.update(&waveformOut[0]); + modulator2.update(&waveformOut[1]); + modulator3.update(&waveformOut[2]); + modulator4.update(&waveformOut[3]); + modulator5.update(&waveformOut[4]); + modulator6.update(&waveformOut[5]); + + // FM for the 6 oscillators from modulators + waveform1.update(&waveformOut[0], nullptr, &waveformModOut[0]); + waveform2.update(&waveformOut[1], nullptr, &waveformModOut[1]); + waveform3.update(&waveformOut[2], nullptr, &waveformModOut[2]); + waveform4.update(&waveformOut[3], nullptr, &waveformModOut[3]); + waveform5.update(&waveformOut[4], nullptr, &waveformModOut[4]); + waveform6.update(&waveformOut[5], nullptr, &waveformModOut[5]); + + mixer1.update(&waveformModOut[0], &waveformModOut[1], &waveformModOut[2], &waveformModOut[3], &mixerOut[0]); + mixer2.update(&waveformModOut[4], &waveformModOut[5], nullptr, nullptr, &mixerOut[1]); + mixer5.update(&mixerOut[0], &mixerOut[1], nullptr, nullptr, &mixerOut[2]); + + blockBuffer.pushBuffer(mixerOut[2].data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return mixer5; + } + unsigned char getPort() override { + return 0; + } + +private: + audio_block_t waveformOut[6] = {}, waveformModOut[6] = {}, mixerOut[3] = {}; + + AudioSynthWaveform modulator1; //xy=236.88888549804688,262.55556869506836 + AudioSynthWaveform modulator3; //xy=238.88890075683594,366.555606842041 + AudioSynthWaveform modulator2; //xy=239.88890075683594,313.5556392669678 + AudioSynthWaveform modulator5; //xy=239.88890075683594,485.5555810928345 + AudioSynthWaveform modulator4; //xy=240.88890075683594,428.55560970306396 + AudioSynthWaveform modulator6; //xy=242.8888931274414,541.5555143356323 + AudioSynthWaveformModulated waveform1; //xy=459.88890075683594,268.6667013168335 + AudioSynthWaveformModulated waveform4; //xy=459.8888854980469,433.6666889190674 + AudioSynthWaveformModulated waveform2; //xy=461.88890838623047,322.66671657562256 + AudioSynthWaveformModulated waveform3; //xy=461.8888854980469,373.6666889190674 + AudioSynthWaveformModulated waveform6; //xy=461.88890838623047,546.6666688919067 + AudioSynthWaveformModulated waveform5; //xy=462.88888931274414,492.66670417785645 + AudioMixer4 mixer2; //xy=663.8888053894043,520.6666412353516 + AudioMixer4 mixer1; //xy=667.888916015625,349.6667251586914 + AudioMixer4 mixer5; //xy=853.8889122009277,448.6667900085449 + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + // AudioConnection patchCord5; + // AudioConnection patchCord6; + // AudioConnection patchCord7; + // AudioConnection patchCord8; + // AudioConnection patchCord9; + // AudioConnection patchCord10; + // AudioConnection patchCord11; + // AudioConnection patchCord12; + // AudioConnection patchCord13; + // AudioConnection patchCord14; + +}; + +REGISTER_PLUGIN(TriFMcluster); diff --git a/src/noise-plethora/plugins/P_WalkingFilomena.hpp b/src/noise-plethora/plugins/P_WalkingFilomena.hpp new file mode 100644 index 0000000..879d9d3 --- /dev/null +++ b/src/noise-plethora/plugins/P_WalkingFilomena.hpp @@ -0,0 +1,305 @@ +#pragma once +#include + +#include "NoisePlethoraPlugin.hpp" + +class WalkingFilomena : public NoisePlethoraPlugin { + +public: + + WalkingFilomena() + // : patchCord1(waveform12, 0, mixer3, 3) + // , patchCord2(waveform16, 0, mixer4, 3) + // , patchCord3(waveform11, 0, mixer3, 2) + // , patchCord4(waveform8, 0, mixer2, 3) + // , patchCord5(waveform15, 0, mixer4, 2) + // , patchCord6(waveform9, 0, mixer3, 0) + // , patchCord7(waveform10, 0, mixer3, 1) + // , patchCord8(waveform13, 0, mixer4, 0) + // , patchCord9(waveform7, 0, mixer2, 2) + // , patchCord10(waveform14, 0, mixer4, 1) + // , patchCord11(waveform4, 0, mixer1, 3) + // , patchCord12(waveform5, 0, mixer2, 0) + // , patchCord13(waveform6, 0, mixer2, 1) + // , patchCord14(waveform3, 0, mixer1, 2) + // , patchCord15(waveform1, 0, mixer1, 0) + // , patchCord16(waveform2, 0, mixer1, 1) + // , patchCord17(mixer2, 0, mixer5, 1) + // , patchCord18(mixer1, 0, mixer5, 0) + // , patchCord19(mixer3, 0, mixer5, 2) + // , patchCord20(mixer4, 0, mixer5, 3) + // //patchCord21(mixer5, 0, i2s1, 0); + { } + ~WalkingFilomena() override {} + + // delete copy constructors + WalkingFilomena(const WalkingFilomena&) = delete; + WalkingFilomena& operator=(const WalkingFilomena&) = delete; + + void init() override { + + L = 1800; // Size of box: maximum frequency + v_0 = 10; // speed: size of step in frequency units. + + mixer1.gain(0, 1); + mixer1.gain(1, 1); + mixer1.gain(2, 1); + mixer1.gain(3, 1); + mixer2.gain(0, 1); + mixer2.gain(1, 1); + mixer2.gain(2, 1); + mixer2.gain(3, 1); + mixer3.gain(0, 1); + mixer3.gain(1, 1); + mixer3.gain(2, 1); + mixer3.gain(3, 1); + mixer4.gain(0, 1); + mixer4.gain(1, 1); + mixer4.gain(2, 1); + mixer4.gain(3, 1); + mixer5.gain(0, 1); + mixer5.gain(1, 1); + mixer5.gain(2, 1); + mixer5.gain(3, 1); + + // SINE + WaveformType masterWaveform = WAVEFORM_PULSE; + + waveform1.pulseWidth(0.5); + waveform1.begin(1, 794, masterWaveform); + + waveform2.pulseWidth(0.5); + waveform2.begin(1, 647, masterWaveform); + + waveform3.pulseWidth(0.5); + waveform3.begin(1, 524, masterWaveform); + + waveform4.pulseWidth(0.5); + waveform4.begin(1, 444, masterWaveform); + + waveform5.pulseWidth(0.5); + waveform5.begin(1, 368, masterWaveform); + + waveform6.pulseWidth(0.5); + waveform6.begin(1, 283, masterWaveform); + + waveform7.pulseWidth(0.5); + waveform7.begin(1, 283, masterWaveform); + + waveform8.pulseWidth(0.5); + waveform8.begin(1, 283, masterWaveform); + + waveform9.pulseWidth(0.5); + waveform9.begin(1, 283, masterWaveform); + + waveform10.pulseWidth(0.5); + waveform10.begin(1, 283, masterWaveform); + + waveform11.pulseWidth(0.5); + waveform11.begin(1, 283, masterWaveform); + + waveform12.pulseWidth(0.5); + waveform12.begin(1, 283, masterWaveform); + + waveform13.pulseWidth(0.5); + waveform13.begin(1, 283, masterWaveform); + + waveform14.pulseWidth(0.5); + waveform14.begin(1, 283, masterWaveform); + + waveform15.pulseWidth(0.5); + waveform15.begin(1, 283, masterWaveform); + + waveform16.pulseWidth(0.5); + waveform16.begin(1, 283, masterWaveform); + + // random walk initial conditions + for (int i = 0; i < 16; i++) { + // velocities: initial conditions in -pi : +pi + theta = M_PI * (random::uniform() * 2.0 - 1.0); + vx[i] = std::cos(theta); + vy[i] = std::sin(theta); + // positions: random in [0,L] x [0, L] + x[i] = random::uniform() * L; + y[i] = random::uniform() * L; + + } + } + + void process(float k1, float k2) override { + + + + float knob_1 = k1; + float knob_2 = k2; + float pw; + float dL; + + dL = knob_1 * L + 200; + + v_var = v_0; + + pw = (knob_2 - 0) * (0.9 - 0.1) / (1 - 0) + 0.1; // función para recortar intervalo de 0.1 a 0.9 + + // loop to "walk" randomly + for (int i = 0; i < 16; i++) { + theta = M_PI * (random::uniform() * 2.0 - 1.0); + + posx = std::cos(theta); + vx[i] = posx; + + posy = std::sin(theta); + vy[i] = posy; + + // Update new position + xn = x[i] + v_var * vx[i]; + yin = y[i] + v_var * vy[i]; + + // periodic boundary conditions + if (xn < 100) + //xn += dL; + xn += 10; + else if (xn > dL) + //xn -= dL; + xn -= 10; + + if (yin < 0.01) + yin += dL; + else if (yin > dL) + yin -= dL; + x[i] = xn; + y[i] = yin; + + } + + waveform1.pulseWidth(pw); + waveform2.pulseWidth(pw); + waveform3.pulseWidth(pw); + waveform4.pulseWidth(pw); + waveform5.pulseWidth(pw); + waveform6.pulseWidth(pw); + waveform7.pulseWidth(pw); + waveform8.pulseWidth(pw); + + waveform9.pulseWidth(pw); + waveform10.pulseWidth(pw); + waveform11.pulseWidth(pw); + waveform12.pulseWidth(pw); + waveform13.pulseWidth(pw); + waveform14.pulseWidth(pw); + waveform15.pulseWidth(pw); + waveform16.pulseWidth(pw); + + waveform1.frequency(x[0]); + waveform2.frequency(x[1]); + waveform3.frequency(x[2]); + waveform4.frequency(x[3]); + waveform5.frequency(x[4]); + waveform6.frequency(x[5]); + waveform7.frequency(x[6]); + waveform8.frequency(x[7]); + waveform9.frequency(x[8]); + waveform10.frequency(x[9]); + waveform11.frequency(x[10]); + waveform12.frequency(x[11]); + waveform13.frequency(x[12]); + waveform14.frequency(x[13]); + waveform15.frequency(x[14]); + waveform16.frequency(x[15]); + + + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + waveform1.update(&waveformBlock[0]); + waveform2.update(&waveformBlock[1]); + waveform3.update(&waveformBlock[2]); + waveform4.update(&waveformBlock[3]); + waveform5.update(&waveformBlock[4]); + waveform6.update(&waveformBlock[5]); + waveform7.update(&waveformBlock[6]); + waveform8.update(&waveformBlock[7]); + waveform9.update(&waveformBlock[8]); + waveform10.update(&waveformBlock[9]); + waveform11.update(&waveformBlock[10]); + waveform12.update(&waveformBlock[11]); + waveform13.update(&waveformBlock[12]); + waveform14.update(&waveformBlock[13]); + waveform15.update(&waveformBlock[14]); + waveform16.update(&waveformBlock[15]); + + mixer1.update(&waveformBlock[0], &waveformBlock[1], &waveformBlock[2], &waveformBlock[3], &mixBlock[0]); + mixer2.update(&waveformBlock[4], &waveformBlock[5], &waveformBlock[6], &waveformBlock[7], &mixBlock[1]); + mixer3.update(&waveformBlock[8], &waveformBlock[9], &waveformBlock[10], &waveformBlock[11], &mixBlock[2]); + mixer4.update(&waveformBlock[12], &waveformBlock[13], &waveformBlock[14], &waveformBlock[15], &mixBlock[3]); + + mixer5.update(&mixBlock[0], &mixBlock[1], &mixBlock[2], &mixBlock[3], &mixBlock[4]); + blockBuffer.pushBuffer(mixBlock[4].data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return mixer5; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t waveformBlock[16], mixBlock[5]; + + /* will be filled in */ + // GUItool: begin automatically generated code + AudioSynthWaveform waveform12; //xy=517.75,725.75 + AudioSynthWaveform waveform16; //xy=517.75,874.75 + AudioSynthWaveform waveform11; //xy=518.75,689.75 + AudioSynthWaveform waveform8; //xy=519.75,577.75 + AudioSynthWaveform waveform15; //xy=518.75,838.75 + AudioSynthWaveform waveform9; //xy=519.75,614.75 + AudioSynthWaveform waveform10; //xy=519.75,652.75 + AudioSynthWaveform waveform13; //xy=519.75,763.75 + AudioSynthWaveform waveform7; //xy=520.75,541.75 + AudioSynthWaveform waveform14; //xy=519.75,801.75 + AudioSynthWaveform waveform4; //xy=521.75,427.75 + AudioSynthWaveform waveform5; //xy=521.75,466.75 + AudioSynthWaveform waveform6; //xy=521.75,504.75 + AudioSynthWaveform waveform3; //xy=522.75,391.75 + AudioSynthWaveform waveform1; //xy=523.75,316.75 + AudioSynthWaveform waveform2; //xy=523.75,354.75 + AudioMixer4 mixer2; //xy=713.75,528.75 + AudioMixer4 mixer1; //xy=714.75,377.75 + AudioMixer4 mixer3; //xy=716.75,664.75 + AudioMixer4 mixer4; //xy=717.75,792.75 + AudioMixer4 mixer5; //xy=961.75,589.75 + //AudioOutputI2S i2s1; //xy=1227.75,604.75 + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + // AudioConnection patchCord5; + // AudioConnection patchCord6; + // AudioConnection patchCord7; + // AudioConnection patchCord8; + // AudioConnection patchCord9; + // AudioConnection patchCord10; + // AudioConnection patchCord11; + // AudioConnection patchCord12; + // AudioConnection patchCord13; + // AudioConnection patchCord14; + // AudioConnection patchCord15; + // AudioConnection patchCord16; + // AudioConnection patchCord17; + // AudioConnection patchCord18; + // AudioConnection patchCord19; + // AudioConnection patchCord20; + //AudioConnection patchCord21(mixer5, 0, i2s1, 0); + //AudioControlSGTL5000 audioOut; //xy=1016.75,846.75 + int L; //, i, t; + float theta, posx, posy, xn, yin; + float v_0, v_var;//pw = pulse width + float x[16], y[16], vx[16], vy[16]; // number depends on waveforms declared + +}; + +REGISTER_PLUGIN(WalkingFilomena); // this is important, so that we can include the plugin in a bank diff --git a/src/noise-plethora/plugins/P_WhiteNoise.hpp b/src/noise-plethora/plugins/P_WhiteNoise.hpp new file mode 100644 index 0000000..8923983 --- /dev/null +++ b/src/noise-plethora/plugins/P_WhiteNoise.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" +#include + +class WhiteNoise : public NoisePlethoraPlugin { + +public: + + WhiteNoise() + //: patchCord1(waveformMod1, 0, waveformMod2, 1), + //patchCord3(waveformMod2, 0, waveformMod1, 0) + { } + + ~WhiteNoise() override {} + + WhiteNoise(const WhiteNoise&) = delete; + WhiteNoise& operator=(const WhiteNoise&) = delete; + + void init() override { + noise1.amplitude(1); + } + + void process(float k1, float k2) override { + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + noise1.update(&noiseOut); + blockBuffer.pushBuffer(noiseOut.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return noise1; + } + unsigned char getPort() override { + return 0; + } + + +private: + + TeensyBuffer buffer; + audio_block_t noiseOut; + + AudioSynthNoiseWhite noise1; + +}; + +REGISTER_PLUGIN(WhiteNoise); diff --git a/src/noise-plethora/plugins/P_XModRingSine.hpp b/src/noise-plethora/plugins/P_XModRingSine.hpp new file mode 100644 index 0000000..156d1f5 --- /dev/null +++ b/src/noise-plethora/plugins/P_XModRingSine.hpp @@ -0,0 +1,80 @@ + +#pragma once + +#include "NoisePlethoraPlugin.hpp" + + +class XModRingSine : public NoisePlethoraPlugin { + +public: + XModRingSine() + // : patchCord1(sine_fm1, sine_fm2), + // patchCord2(sine_fm1, 0, multiply1, 0), + // patchCord3(sine_fm2, sine_fm1), + // patchCord4(sine_fm2, 0, multiply1, 1) + // // patchCord5(multiply1, 0, i2s1, 0) + { } + ~XModRingSine() override {} + + // delete copy constructors + XModRingSine(const XModRingSine&) = delete; + XModRingSine& operator=(const XModRingSine&) = delete; + + + void init() override { + sine_fm1.frequency(1100); + sine_fm2.frequency(1367); + + sine_fm1.amplitude(1); + sine_fm2.amplitude(1); + } + void process(float k1, float k2) override { + // Read CV and knobs,sum them and scale to 0-1.0 + float knob_1 = k1; + float knob_2 = k2; + + float pitch1 = pow(knob_1, 2); + float pitch2 = pow(knob_2, 2); + + + sine_fm1.frequency(100 + (pitch1 * 8000)); + sine_fm2.frequency(60 + (pitch2 * 3000)); + + + //Serial.print(knob_2*0.5); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + sine_fm1.update(&sineModOut[1], &sineModOut[0]); + sine_fm2.update(&sineModOut[0], &sineModOut[1]); + + multiply1.update(&sineModOut[0], &sineModOut[1], &multiplyOut); + + blockBuffer.pushBuffer(multiplyOut.data, AUDIO_BLOCK_SAMPLES); + } + + + AudioStream& getStream() override { + return multiply1; + } + + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t sineModOut[2] = {}, multiplyOut; + + AudioSynthWaveformSineModulated sine_fm1; //xy=360,220 + AudioSynthWaveformSineModulated sine_fm2; //xy=363,404 + AudioEffectMultiply multiply1; //xy=569,311 + + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; +}; + +REGISTER_PLUGIN(XModRingSine); // this is important, so that we can include the plugin in a bank diff --git a/src/noise-plethora/plugins/P_arrayOnTheRocks.hpp b/src/noise-plethora/plugins/P_arrayOnTheRocks.hpp new file mode 100644 index 0000000..c302dac --- /dev/null +++ b/src/noise-plethora/plugins/P_arrayOnTheRocks.hpp @@ -0,0 +1,137 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + + + +class arrayOnTheRocks: public NoisePlethoraPlugin { +public: + + arrayOnTheRocks() + // : patchCord1(waveform1, 0, waveformMod1, 0) + {} + ~arrayOnTheRocks() override {} + + // delete copy constructors + arrayOnTheRocks(const arrayOnTheRocks&) = delete; + arrayOnTheRocks& operator=(const arrayOnTheRocks&) = delete; + + + void init() override { + + //noise1.amplitude(1); + + waveformMod1.arbitraryWaveform(myWaveform, 172.0); + + waveformMod1.begin(1, 250, WAVEFORM_ARBITRARY); + waveform1.begin(1, 500, WAVEFORM_SINE); + + /*test=random(-28000, 28000); + + myWaveform = {0, 1895, 3748, 5545, 7278, 8934, 10506, 11984, 13362, 14634, + test, 16840, 17769, 18580, 19274, 19853, 20319, 20678, 20933, 21093, + 21163, 21153, 21072, 20927, 20731, 20492, 20221, test, 19625, 19320, + 19022, 18741, 18486, 18263, 18080, 17942, 17853, 17819, 17841, 17920, + 18058, 18254, 18507, 18813, 19170, 19573, 20017, 20497, 21006, test, + test, test, test, 23753, 24294, 24816, 25314, 25781, 26212, 26604, + 26953, test, test, 27718, 27876, 27986, test, test, test, 27989, + 27899, 27782, 27644, 27490, test, test, test, test, test, 26582, + 26487, 26423, test, test, test, test, test, 26812, 27012, 27248, + 27514, 27808, 28122, test, 28787, test, 29451, 29762, 30045, 30293, + test, 30643, 30727, 30738, 30667, test, 30254, 29897, test, 28858, + 28169, 27363, 26441, 25403, 24251, 22988, 21620, 20150, 18587, 16939, + 15214, 13423, 11577, 9686, 7763, 5820, 3870, 1926, 0, -1895, + -3748, -5545, -7278, -8934,-10506, test,-13362,-14634,-15794,-16840, + -17769,-18580,-19274,-19853,-20319,-20678,-20933,-21093,-21163,-21153, + -21072,-20927,-test,-20492,-20221,-19929,-19625,-19320,-19022,-18741, + -test,-18263,-18080,-17942,-17853,-test,-17841,-17920,-18058,-18254, + -18507,-18813,-19170,-19573,-test,-20497,-21006,-21538,-22085,-22642, + -23200,-23753,-test,-test,-25314,-25781,-26212,-26604,-26953,-27256, + -27511,-27718,-test,-test,-test,-28068,-28047,-test,-27899,-27782, + -27644,-27490,-27326,-test,-26996,-26841,-26701,-26582,-26487,-test, + -26392,-26397,-26441,-26525,-test,-26812,-test,-27248,-27514,-27808, + -28122,-28451,-test,-test,-test,-29762,-test,-test,-test,-test, + -test,-test,-test,-test,-test,-test,-test,test,-28169,-27363, + -test,-test,-test,-test,-test,-test,-test,-test,-test,test, + -test, -test, -test, -test, -test, -test};*/ + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + + float pitch1 = pow(knob_1, 2); + // float pitch2 = pow(knob_2, 2); + + waveformMod1.frequency(10 + (pitch1 * 10000)); + waveform1.frequency(100 + (pitch1 * 500)); + + waveform1.amplitude(knob_2); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + waveform1.update(&waveformBlock); + waveformMod1.update(&waveformBlock, nullptr, &waveformModBlock); + + blockBuffer.pushBuffer(waveformModBlock.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return waveformMod1; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t waveformBlock, waveformModBlock; + + // GUItool: begin automatically generated code + AudioSynthWaveform waveform1; //xy=305.3333282470703,648.3333358764648 + AudioSynthWaveformModulated waveformMod1; //xy=475.88893127441406,517.2221565246582 + // AudioConnection patchCord1; + + const int16_t test = 8622; // (int16_t)random(-28000, 28000); + const int16_t myWaveform[256] = {0, 1895, 3748, 5545, 7278, 8934, 10506, 11984, 13362, 14634, + test, 16840, 17769, 18580, 19274, 19853, 20319, 20678, 20933, 21093, + 21163, 21153, 21072, 20927, 20731, 20492, 20221, test, 19625, 19320, + 19022, 18741, 18486, 18263, 18080, 17942, 17853, 17819, 17841, 17920, + 18058, 18254, 18507, 18813, 19170, 19573, 20017, 20497, 21006, test, + test, test, test, 23753, 24294, 24816, 25314, 25781, 26212, 26604, + 26953, test, test, 27718, 27876, 27986, test, test, test, 27989, + 27899, 27782, 27644, 27490, test, test, test, test, test, 26582, + 26487, 26423, test, test, test, test, test, 26812, 27012, 27248, + 27514, 27808, 28122, test, 28787, test, 29451, 29762, 30045, 30293, + test, 30643, 30727, 30738, 30667, test, 30254, 29897, test, 28858, + 28169, 27363, 26441, 25403, 24251, 22988, 21620, 20150, 18587, 16939, + 15214, 13423, 11577, 9686, 7763, 5820, 3870, 1926, 0, -1895, + -3748, -5545, -7278, -8934, -10506, test, -13362, -14634, -15794, -16840, + -17769, -18580, -19274, -19853, -20319, -20678, -20933, -21093, -21163, -21153, + -21072, -20927, (int16_t) - test, -20492, -20221, -19929, -19625, -19320, -19022, -18741, + (int16_t) - test, -18263, -18080, -17942, -17853, (int16_t) - test, -17841, -17920, -18058, -18254, + -18507, -18813, -19170, -19573, (int16_t) - test, -20497, -21006, -21538, -22085, -22642, + -23200, -23753, (int16_t) - test, (int16_t) - test, -25314, -25781, -26212, -26604, -26953, -27256, + -27511, -27718, (int16_t) - test, (int16_t) - test, (int16_t) - test, -28068, -28047, (int16_t) - test, -27899, -27782, + -27644, -27490, -27326, (int16_t) - test, -26996, -26841, -26701, -26582, -26487, (int16_t) - test, + -26392, -26397, -26441, -26525, (int16_t) - test, -26812, (int16_t) - test, -27248, -27514, -27808, + -28122, -28451, (int16_t) - test, (int16_t) - test, (int16_t) - test, -29762, (int16_t) - test, (int16_t) - test, (int16_t) - test, (int16_t) - test, + (int16_t) - test, (int16_t) - test, (int16_t) - test, (int16_t) - test, (int16_t) - test, (int16_t) - test, (int16_t) - test, test, -28169, -27363, + (int16_t) - test, (int16_t) - test, (int16_t) - test, (int16_t) - test, (int16_t) - test, (int16_t) - test, (int16_t) - test, (int16_t) - test, (int16_t) - test, test, + (int16_t) - test, (int16_t) - test, (int16_t) - test, (int16_t) - test, (int16_t) - test, (int16_t) - test + }; + + // int current_waveform = 0; + + /* PREGUNTA A DIEGO ¿Este sobra? */ + //extern const int16_t myWaveform[256]; // defined in myWaveform.ino + + +}; + + + + + + +REGISTER_PLUGIN(arrayOnTheRocks); // this is important, so that we can include the plugin in a bank diff --git a/src/noise-plethora/plugins/P_basurilla.hpp b/src/noise-plethora/plugins/P_basurilla.hpp new file mode 100644 index 0000000..c313b6a --- /dev/null +++ b/src/noise-plethora/plugins/P_basurilla.hpp @@ -0,0 +1,108 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class basurilla : public NoisePlethoraPlugin { + +public: + + basurilla() + // : patchCord1(noise1, 0, multiply1, 0), + // patchCord2(noise1, 0, multiply2, 0), + // patchCord3(noise1, 0, multiply3, 0), + // patchCord6(waveform3, 0, multiply3, 1), + // patchCord7(waveform2, 0, multiply2, 1), + // patchCord8(waveform1, 0, multiply1, 1), + // patchCord9(multiply2, 0, mixer1, 1), + // patchCord10(multiply1, 0, mixer1, 0), + // patchCord11(multiply3, 0, mixer1, 2) + {} + + + ~basurilla() override {} + + basurilla(const basurilla&) = delete; + basurilla& operator=(const basurilla&) = delete; + + void init() override { + + waveform1.begin(1, 100, WAVEFORM_PULSE); + waveform1.offset(1); + waveform1.pulseWidth(0.5); + waveform2.begin(0, 77, WAVEFORM_PULSE); + waveform2.offset(1); + waveform2.pulseWidth(0.5); + waveform3.begin(0, 77, WAVEFORM_PULSE); + waveform3.offset(1); + waveform3.pulseWidth(0.5); + noise1.amplitude(1); + } + + void process(float k1, float k2) override { + + float knob_1 = k1; + float knob_2 = k2; + float pitch = pow(knob_1, 2); + waveform1.frequency(pitch * 100 + 10); + waveform1.pulseWidth(knob_2 * 0.95); + noise1.amplitude(knob_2 * -1 + 2); + waveform2.frequency(pitch * 0.1); + waveform2.pulseWidth(knob_2 * 0.5 + 0.2); + waveform3.frequency(pitch * 0.7 - 500); + waveform3.pulseWidth(knob_2 * 0.5); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + noise1.update(&noiseOut); + + // NOTE: 2,3 not actually used, as volume is 0 in init()! + // waveform3.update(&waveformOut[2]); + // waveform2.update(&waveformOut[1]); + waveform1.update(&waveformOut[0]); + + multiply1.update(&noiseOut, &waveformOut[0], &multiplyOut[0]); + // NOTE: 2,3 not actually used, as volume is 0 in init()! + // multiply2.update(&noiseOut, &waveformOut[1], &multiplyOut[1]); + // multiply3.update(&noiseOut, &waveformOut[2], &multiplyOut[2]); + + // NOTE: 2,3 not actually used, as volume is 0 in init()! + // mixer1.update(&multiplyOut[0], &multiplyOut[1], &multiplyOut[2], nullptr, &mixerOut); + + blockBuffer.pushBuffer(multiplyOut[0].data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return mixer1; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t noiseOut, waveformOut[3] = {}, multiplyOut[3] = {}; + + AudioSynthNoiseWhite noise1; //xy=240,621 + AudioSynthWaveform waveform3; //xy=507,823 + AudioSynthWaveform waveform2; //xy=522,657 + AudioSynthWaveform waveform1; //xy=545,475 + AudioEffectMultiply multiply2; //xy=615,596 + AudioEffectMultiply multiply1; //xy=634,340 + AudioEffectMultiply multiply3; //xy=635,753 + AudioMixer4 mixer1; //xy=863,612 + + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord6; + // AudioConnection patchCord7; + // AudioConnection patchCord8; + // AudioConnection patchCord9; + // AudioConnection patchCord10; + // AudioConnection patchCord11; + // + +}; + +REGISTER_PLUGIN(basurilla); diff --git a/src/noise-plethora/plugins/P_clusterSaw.hpp b/src/noise-plethora/plugins/P_clusterSaw.hpp new file mode 100644 index 0000000..67e6c75 --- /dev/null +++ b/src/noise-plethora/plugins/P_clusterSaw.hpp @@ -0,0 +1,206 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class clusterSaw : public NoisePlethoraPlugin { + +public: + + clusterSaw() + // : patchCord18(waveform16, 0, mixer4, 3), + // patchCord19(waveform14, 0, mixer4, 1), + // patchCord20(waveform15, 0, mixer4, 2), + // patchCord21(waveform13, 0, mixer4, 0), + // patchCord22(waveform8, 0, mixer2, 3), + // patchCord23(waveform6, 0, mixer2, 1), + // patchCord24(waveform7, 0, mixer2, 2), + // patchCord25(waveform12, 0, mixer3, 3), + // patchCord26(waveform5, 0, mixer2, 0), + // patchCord27(waveform10, 0, mixer3, 1), + // patchCord28(waveform11, 0, mixer3, 2), + // patchCord29(waveform9, 0, mixer3, 0), + // patchCord30(waveform4, 0, mixer1, 3), + // patchCord31(waveform2, 0, mixer1, 1), + // patchCord32(waveform3, 0, mixer1, 2), + // patchCord33(waveform1, 0, mixer1, 0), + // patchCord34(mixer4, 0, mixer5, 3), + // patchCord35(mixer2, 0, mixer5, 1), + // patchCord36(mixer1, 0, mixer5, 0), + // patchCord37(mixer3, 0, mixer5, 2) + { } + + ~clusterSaw() override {} + + clusterSaw(const clusterSaw&) = delete; + clusterSaw& operator=(const clusterSaw&) = delete; + + void init() override { + mixer1.gain(0, 1); + mixer1.gain(1, 1); + mixer1.gain(2, 1); + mixer1.gain(3, 1); + mixer2.gain(0, 1); + mixer2.gain(1, 1); + mixer2.gain(2, 1); + mixer2.gain(3, 1); + mixer3.gain(0, 1); + mixer3.gain(1, 1); + mixer3.gain(2, 1); + mixer3.gain(3, 1); + mixer4.gain(0, 1); + mixer4.gain(1, 1); + mixer4.gain(2, 1); + mixer4.gain(3, 1); + mixer5.gain(0, 1); + mixer5.gain(1, 1); + mixer5.gain(2, 1); + mixer5.gain(3, 1); + + WaveformType masterWaveform = WAVEFORM_SAWTOOTH; + float masterVolume = 0.25; + waveform1.begin(masterVolume, 0, masterWaveform); + waveform2.begin(masterVolume, 0, masterWaveform); + waveform3.begin(masterVolume, 0, masterWaveform); + waveform4.begin(masterVolume, 0, masterWaveform); + waveform5.begin(masterVolume, 0, masterWaveform); + waveform6.begin(masterVolume, 0, masterWaveform); + waveform7.begin(masterVolume, 0, masterWaveform); + waveform8.begin(masterVolume, 0, masterWaveform); + waveform9.begin(masterVolume, 0, masterWaveform); + waveform10.begin(masterVolume, 0, masterWaveform); + waveform11.begin(masterVolume, 0, masterWaveform); + waveform12.begin(masterVolume, 0, masterWaveform); + waveform13.begin(masterVolume, 0, masterWaveform); + waveform14.begin(masterVolume, 0, masterWaveform); + waveform15.begin(masterVolume, 0, masterWaveform); + waveform16.begin(masterVolume, 0, masterWaveform); + + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + float pitch1 = pow(knob_1, 2); + float pitch2 = pow(knob_2, 2); + float multFactor = 1.01 + (pitch2 * 0.9); + float f1 = 20 + pitch1 * 1000; + float f2 = f1 * multFactor; + float f3 = f2 * multFactor; + float f4 = f3 * multFactor; + float f5 = f4 * multFactor; + float f6 = f5 * multFactor; + float f7 = f6 * multFactor; + float f8 = f7 * multFactor; + float f9 = f8 * multFactor; + float f10 = f9 * multFactor; + float f11 = f10 * multFactor; + float f12 = f11 * multFactor; + float f13 = f12 * multFactor; + float f14 = f13 * multFactor; + float f15 = f14 * multFactor; + float f16 = f15 * multFactor; + waveform1.frequency(f1); + waveform2.frequency(f2); + waveform3.frequency(f3); + waveform4.frequency(f4); + waveform5.frequency(f5); + waveform6.frequency(f6); + waveform7.frequency(f7); + waveform8.frequency(f8); + waveform9.frequency(f9); + waveform10.frequency(f10); + waveform11.frequency(f11); + waveform12.frequency(f12); + waveform13.frequency(f13); + waveform14.frequency(f14); + waveform15.frequency(f15); + waveform16.frequency(f16); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + // update waveforms + // FM from single noise source + waveform1.update(nullptr, nullptr, &waveformOut[0]); + waveform2.update(nullptr, nullptr, &waveformOut[1]); + waveform3.update(nullptr, nullptr, &waveformOut[2]); + waveform4.update(nullptr, nullptr, &waveformOut[3]); + waveform5.update(nullptr, nullptr, &waveformOut[4]); + waveform6.update(nullptr, nullptr, &waveformOut[5]); + waveform7.update(nullptr, nullptr, &waveformOut[6]); + waveform8.update(nullptr, nullptr, &waveformOut[7]); + waveform9.update(nullptr, nullptr, &waveformOut[8]); + waveform10.update(nullptr, nullptr, &waveformOut[9]); + waveform11.update(nullptr, nullptr, &waveformOut[10]); + waveform12.update(nullptr, nullptr, &waveformOut[11]); + waveform13.update(nullptr, nullptr, &waveformOut[12]); + waveform14.update(nullptr, nullptr, &waveformOut[13]); + waveform15.update(nullptr, nullptr, &waveformOut[14]); + waveform16.update(nullptr, nullptr, &waveformOut[15]); + + // update mixers + mixer1.update(&waveformOut[0], &waveformOut[1], &waveformOut[2], &waveformOut[3], &mixerOut[0]); + mixer2.update(&waveformOut[4], &waveformOut[5], &waveformOut[6], &waveformOut[7], &mixerOut[1]); + mixer3.update(&waveformOut[8], &waveformOut[9], &waveformOut[10], &waveformOut[11], &mixerOut[2]); + mixer4.update(&waveformOut[12], &waveformOut[13], &waveformOut[14], &waveformOut[15], &mixerOut[3]); + // mixer of mixers + mixer5.update(&mixerOut[0], &mixerOut[1], &mixerOut[2], &mixerOut[3], &mixerOut[4]); + + blockBuffer.pushBuffer(mixerOut[4].data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return mixer5; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t waveformOut[16] = {}, mixerOut[5] = {}; + + AudioSynthWaveformModulated waveform16; //xy=360.00000381469727,1486.0000076293945 + AudioSynthWaveformModulated waveform14; //xy=362.00000381469727,1381.0000076293945 + AudioSynthWaveformModulated waveform15; //xy=362.00000381469727,1426.0000076293945 + AudioSynthWaveformModulated waveform13; //xy=363.00000381469727,1339.0000076293945 + AudioSynthWaveformModulated waveform8; //xy=370.00000381469727,1066.0000076293945 + AudioSynthWaveformModulated waveform6; //xy=372.00000381469727,961.0000076293945 + AudioSynthWaveformModulated waveform7; //xy=372.00000381469727,1006.0000076293945 + AudioSynthWaveformModulated waveform12; //xy=371.00000381469727,1277.0000076293945 + AudioSynthWaveformModulated waveform5; //xy=373.00000381469727,919.0000076293945 + AudioSynthWaveformModulated waveform10; //xy=373.00000381469727,1172.0000076293945 + AudioSynthWaveformModulated waveform11; //xy=373.00000381469727,1217.0000076293945 + AudioSynthWaveformModulated waveform9; //xy=374.00000381469727,1130.0000076293945 + AudioSynthWaveformModulated waveform4; //xy=378.00000381469727,851.0000076293945 + AudioSynthWaveformModulated waveform2; //xy=380.00000381469727,746.0000076293945 + AudioSynthWaveformModulated waveform3; //xy=380.00000381469727,791.0000076293945 + AudioSynthWaveformModulated waveform1; //xy=381.00000381469727,703.0000076293945 + AudioMixer4 mixer4; //xy=546.0000038146973,1408.0000381469727 + AudioMixer4 mixer2; //xy=554.9999923706055,984.0000381469727 + AudioMixer4 mixer1; //xy=556.9999885559082,771.0000076293945 + AudioMixer4 mixer3; //xy=557.0000114440918,1196.0000228881836 + AudioMixer4 mixer5; //xy=755.0000267028809,1082.9999923706055 + // AudioConnection patchCord18; + // AudioConnection patchCord19; + // AudioConnection patchCord20; + // AudioConnection patchCord21; + // AudioConnection patchCord22; + // AudioConnection patchCord23; + // AudioConnection patchCord24; + // AudioConnection patchCord25; + // AudioConnection patchCord26; + // AudioConnection patchCord27; + // AudioConnection patchCord28; + // AudioConnection patchCord29; + // AudioConnection patchCord30; + // AudioConnection patchCord31; + // AudioConnection patchCord32; + // AudioConnection patchCord33; + // AudioConnection patchCord34; + // AudioConnection patchCord35; + // AudioConnection patchCord36; + // AudioConnection patchCord37; +}; + +REGISTER_PLUGIN(clusterSaw); diff --git a/src/noise-plethora/plugins/P_crCluster2.hpp b/src/noise-plethora/plugins/P_crCluster2.hpp new file mode 100644 index 0000000..df05469 --- /dev/null +++ b/src/noise-plethora/plugins/P_crCluster2.hpp @@ -0,0 +1,135 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class crCluster2 : public NoisePlethoraPlugin { + +public: + + crCluster2() // : + // patchCord1(modulator, 0, waveform1, 0), + // patchCord2(modulator, 0, waveform2, 0), + // patchCord3(modulator, 0, waveform3, 0), + // patchCord4(modulator, 0, waveform4, 0), + // patchCord5(modulator, 0, waveform5, 0), + // patchCord6(modulator, 0, waveform6, 0), + // patchCord7(waveform6, 0, mixer2, 1), + // patchCord8(waveform5, 0, mixer2, 0), + // patchCord9(waveform4, 0, mixer1, 3), + // patchCord10(waveform2, 0, mixer1, 1), + // patchCord11(waveform3, 0, mixer1, 2), + // patchCord12(waveform1, 0, mixer1, 0), + // patchCord13(mixer2, 0, mixer5, 1), + // patchCord14(mixer1, 0, mixer5, 0) + { } + + ~crCluster2() override {} + + crCluster2(const crCluster2&) = delete; + crCluster2& operator=(const crCluster2&) = delete; + + void init() override { + mixer1.gain(0, 1); + mixer1.gain(1, 1); + mixer1.gain(2, 1); + mixer1.gain(3, 1); + mixer2.gain(0, 1); + mixer2.gain(1, 1); + mixer2.gain(2, 1); + mixer2.gain(3, 1); + mixer5.gain(0, 1); + mixer5.gain(1, 1); + mixer5.gain(2, 1); + mixer5.gain(3, 1); + + int masterWaveform = WAVEFORM_SINE; + float masterVolume = 0.2; + + waveform1.begin(masterVolume, 794, masterWaveform); + waveform2.begin(masterVolume, 647, masterWaveform); + waveform3.begin(masterVolume, 524, masterWaveform); + waveform4.begin(masterVolume, 444, masterWaveform); + waveform5.begin(masterVolume, 368, masterWaveform); + waveform6.begin(masterVolume, 283, masterWaveform); + + modulator.begin(1, 1000, WAVEFORM_SINE); + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + float pitch1 = pow(knob_1, 2); + + float f1 = 40 + pitch1 * 8000; + float f2 = f1 * 1.227; + float f3 = f2 * 1.24; + float f4 = f3 * 1.17; + float f5 = f4 * 1.2; + float f6 = f5 * 1.3; + + modulator.amplitude(knob_2); + modulator.frequency(f1 * 2.7); + + waveform1.frequency(f1); + waveform2.frequency(f2); + waveform3.frequency(f3); + waveform4.frequency(f4); + waveform5.frequency(f5); + waveform6.frequency(f6); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + modulator.update(&waveformOut); + + // FM from modulator for the 6 oscillators + waveform1.update(&waveformOut, nullptr, &waveformModOut[0]); + waveform2.update(&waveformOut, nullptr, &waveformModOut[1]); + waveform3.update(&waveformOut, nullptr, &waveformModOut[2]); + waveform4.update(&waveformOut, nullptr, &waveformModOut[3]); + waveform5.update(&waveformOut, nullptr, &waveformModOut[4]); + waveform6.update(&waveformOut, nullptr, &waveformModOut[5]); + + mixer1.update(&waveformModOut[0], &waveformModOut[1], &waveformModOut[2], &waveformModOut[3], &mixerOut[0]); + mixer2.update(&waveformModOut[4], &waveformModOut[5], nullptr, nullptr, &mixerOut[1]); + mixer5.update(&mixerOut[0], &mixerOut[1], nullptr, nullptr, &mixerOut[2]); + + blockBuffer.pushBuffer(mixerOut[2].data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return mixer5; + } + unsigned char getPort() override { + return 0; + } + +private: + audio_block_t waveformOut, waveformModOut[6] = {}, mixerOut[3] = {}; + + AudioSynthWaveform modulator; //xy=135.88888549804688,405.55555725097656 + AudioSynthWaveformModulated waveform6; //xy=453.8888854980469,543.6666889190674 + AudioSynthWaveformModulated waveform5; //xy=454.8888854980469,501.6666889190674 + AudioSynthWaveformModulated waveform4; //xy=459.8888854980469,433.6666889190674 + AudioSynthWaveformModulated waveform2; //xy=461.8888854980469,328.6666889190674 + AudioSynthWaveformModulated waveform3; //xy=461.8888854980469,373.6666889190674 + AudioSynthWaveformModulated waveform1; //xy=462.8888854980469,285.6666889190674 + AudioMixer4 mixer2; //xy=678.8888778686523,495.66669845581055 + AudioMixer4 mixer1; //xy=679.8888854980469,377.6666889190674 + AudioMixer4 mixer5; //xy=883.8888854980469,446.66675567626953 + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + // AudioConnection patchCord5; + // AudioConnection patchCord6; + // AudioConnection patchCord7; + // AudioConnection patchCord8; + // AudioConnection patchCord9; + // AudioConnection patchCord10; + // AudioConnection patchCord11; + // AudioConnection patchCord12; + // AudioConnection patchCord13; + // AudioConnection patchCord14; +}; + +REGISTER_PLUGIN(crCluster2); diff --git a/src/noise-plethora/plugins/P_existencelsPain.hpp b/src/noise-plethora/plugins/P_existencelsPain.hpp new file mode 100644 index 0000000..c62e411 --- /dev/null +++ b/src/noise-plethora/plugins/P_existencelsPain.hpp @@ -0,0 +1,146 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class existencelsPain : public NoisePlethoraPlugin { + +public: + + existencelsPain() + // : patchCord1(waveform1, 0, filter1, 0) + // , patchCord2(waveform1, 0, filter2, 0) + // , patchCord3(waveform1, 0, filter3, 0) + // , patchCord4(waveform1, 0, filter4, 0) + // , patchCord5(waveformMod1, 0, filter1, 1) + // , patchCord6(waveformMod2, 0, filter2, 1) + // , patchCord7(waveformMod4, 0, filter4, 1) + // , patchCord8(waveformMod3, 0, filter3, 1) + // , patchCord9(filter1, 1, mixer1, 0) + // , patchCord10(filter2, 1, mixer1, 1) + // , patchCord11(filter3, 1, mixer1, 2) + // , patchCord12(filter4, 1, mixer1, 3) + { } + + ~existencelsPain() override {} + + // delete copy constructors + existencelsPain(const existencelsPain&) = delete; + existencelsPain& operator=(const existencelsPain&) = delete; + + void init() override { + + //noise1.amplitude(1); + + mixer1.gain(0, 0.8); + mixer1.gain(1, 0.8); + mixer1.gain(2, 0.8); + mixer1.gain(3, 0.8); + + + waveformMod1.begin(1, 11, WAVEFORM_TRIANGLE); + waveformMod2.begin(1, 70, WAVEFORM_TRIANGLE); + waveformMod3.begin(1, 23, WAVEFORM_TRIANGLE); + waveformMod4.begin(1, 0.01, WAVEFORM_TRIANGLE); + + waveform1.begin(1, 5, WAVEFORM_SAMPLE_HOLD); + //waveform1.pulseWidth(0.1); + + filter1.resonance(5); + filter1.octaveControl(7); + + filter2.resonance(5); + filter2.octaveControl(7); + + filter3.resonance(5); + filter3.octaveControl(7); + + filter4.resonance(5); + filter4.octaveControl(7); + } + + void process(float k1, float k2) override { + + + float knob_1 = k1; + float knob_2 = k2; + + float pitch1 = pow(knob_1, 2); + // float pitch2 = pow(knob_2, 2); + + + waveform1.frequency(50 + (pitch1 * 5000)); + + float octaves = knob_2 * 3 + 0.3; + + /*filter1.resonance(resonanceLevel); + filter2.resonance(resonanceLevel); + filter3.resonance(resonanceLevel); + filter4.resonance(resonanceLevel);*/ + + filter1.octaveControl(octaves); + filter2.octaveControl(octaves); + filter3.octaveControl(octaves); + filter4.octaveControl(octaves); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + // waveform to filter + waveform1.update(&waveformOut); + + waveformMod1.update(nullptr, nullptr, &waveformModOut[0]); + waveformMod2.update(nullptr, nullptr, &waveformModOut[1]); + waveformMod3.update(nullptr, nullptr, &waveformModOut[2]); + waveformMod4.update(nullptr, nullptr, &waveformModOut[3]); + + // SVF needs LP, BP and HP (even if we only use one) + filter1.update(&waveformOut, &waveformModOut[0], &filterOutLP[0], &filterOutBP[0], &filterOutHP[0]); + filter2.update(&waveformOut, &waveformModOut[1], &filterOutLP[1], &filterOutBP[1], &filterOutHP[1]); + filter3.update(&waveformOut, &waveformModOut[2], &filterOutLP[2], &filterOutBP[2], &filterOutHP[2]); + filter4.update(&waveformOut, &waveformModOut[3], &filterOutLP[3], &filterOutBP[3], &filterOutHP[3]); + + // sum up + mixer1.update(&filterOutBP[0], &filterOutBP[1], &filterOutBP[2], &filterOutBP[3], &mixerOut); + + blockBuffer.pushBuffer(mixerOut.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return mixer1; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t waveformModOut[4]; + audio_block_t filterOutLP[4], filterOutBP[4], filterOutHP[4]; + audio_block_t waveformOut, mixerOut; + + // GUItool: begin automatically generated code + AudioSynthWaveform waveform1; //xy=283,566 + AudioSynthWaveformModulated waveformMod1; //xy=363.888916015625,321.2221794128418 + AudioSynthWaveformModulated waveformMod2; //xy=368,380.3332633972168 + AudioSynthWaveformModulated waveformMod4; //xy=374,689.3332633972168 + AudioSynthWaveformModulated waveformMod3; //xy=378,638.3332633972168 + AudioFilterStateVariable filter1; //xy=578.888916015625,420.8889274597168 + AudioFilterStateVariable filter2; //xy=579,486.0000114440918 + AudioFilterStateVariable filter3; //xy=581,549.0000114440918 + AudioFilterStateVariable filter4; //xy=581,614.0000114440918 + AudioMixer4 mixer1; //xy=752,520.0000114440918 + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + // AudioConnection patchCord5; + // AudioConnection patchCord6; + // AudioConnection patchCord7; + // AudioConnection patchCord8; + // AudioConnection patchCord9; + // AudioConnection patchCord10; + // AudioConnection patchCord11; + // AudioConnection patchCord12; + +}; + +REGISTER_PLUGIN(existencelsPain); // this is important, so that we can include the plugin in a bank diff --git a/src/noise-plethora/plugins/P_grainGlitch.hpp b/src/noise-plethora/plugins/P_grainGlitch.hpp new file mode 100644 index 0000000..985e521 --- /dev/null +++ b/src/noise-plethora/plugins/P_grainGlitch.hpp @@ -0,0 +1,91 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" +#define GRANULAR_MEMORY_SIZE 12800 // enough for 290 ms at 44.1 kHz + +class grainGlitch : public NoisePlethoraPlugin { + +public: + + grainGlitch() + // : patchCord1(granular1, 0, waveformMod1, 0), + // patchCord2(granular1, 0, combine1, 0), + // patchCord3(waveformMod1, granular1), + // patchCord4(waveformMod1, 0, combine1, 1) + { } + + ~grainGlitch() override {} + + grainGlitch(const grainGlitch&) = delete; + grainGlitch& operator=(const grainGlitch&) = delete; + + void init() override { + + // combine1.AudioEffectDigitalCombine::XOR; + + + waveformMod1.begin(1, 1000, WAVEFORM_SQUARE); + + // the Granular effect requires memory to operate + granular1.begin(granularMemory, GRANULAR_MEMORY_SIZE); + + float msec = 150.0; + granular1.beginFreeze(msec); + + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + + float pitch1 = pow(knob_1, 2); + + waveformMod1.frequencyModulation(knob_2 * 2); + + float msec2 = 25.0 + (knob_2 * 75.0); + + granular1.beginPitchShift(msec2); + waveformMod1.frequency(pitch1 * 5000 + 500); + + float ratio; + + ratio = powf(2.0, knob_2 * 6.0 - 3.0); + granular1.setSpeed(ratio); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + granular1.update(&waveformMod1Out, &granularOut); + + waveformMod1.update(&granularOut, nullptr, &waveformMod1Out); + + combine1.update(&granularOut, &waveformMod1Out, &combine1Out); + + blockBuffer.pushBuffer(combine1Out.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return combine1; + } + unsigned char getPort() override { + return 0; + } + +private: + AudioEffectGranular granular1; //xy=885.75,359.9999985694885 + AudioSynthWaveformModulated waveformMod1; //xy=889.75,480.74999871477485 + AudioEffectDigitalCombine combine1; //xy=1111.7500114440918,295.74999809265137 + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + + int16_t granularMemory[GRANULAR_MEMORY_SIZE]; + + + audio_block_t granularOut; + audio_block_t waveformMod1Out; + audio_block_t combine1Out; +}; + +REGISTER_PLUGIN(grainGlitch); diff --git a/src/noise-plethora/plugins/P_grainGlitchII.hpp b/src/noise-plethora/plugins/P_grainGlitchII.hpp new file mode 100644 index 0000000..d575895 --- /dev/null +++ b/src/noise-plethora/plugins/P_grainGlitchII.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" +#define GRANULAR_MEMORY_SIZE 12800 // enough for 290 ms at 44.1 kHz + +class grainGlitchII : public NoisePlethoraPlugin { + +public: + + grainGlitchII() + // : patchCord1(granular1, 0, waveformMod1, 0), + // patchCord2(granular1, amp1), + // patchCord3(waveformMod1, granular1) + { } + + ~grainGlitchII() override {} + + grainGlitchII(const grainGlitchII&) = delete; + grainGlitchII& operator=(const grainGlitchII&) = delete; + + void init() override { + + float msec = 150.0; + waveformMod1.begin(1, 1000, WAVEFORM_SQUARE); + amp1.gain(32000); + // the Granular effect requires memory to operate + granular1.begin(granularMemory, GRANULAR_MEMORY_SIZE); + granular1.beginFreeze(msec); + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + + float pitch1 = pow(knob_1, 2); + float msec2 = 25.0 + (knob_2 * 75.0); + float ratio; + + waveformMod1.frequencyModulation(knob_2 * 2); + granular1.beginPitchShift(msec2); + + waveformMod1.frequency(pitch1 * 5000 + 500); + ratio = powf(2.0, knob_2 * 6.0 - 3.0); // 0.125 to 8.0 -- uncomment for far too much range! + granular1.setSpeed(ratio); + + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + granular1.update(&waveformMod1Out, &granularOut); + + waveformMod1.update(&granularOut, nullptr, &waveformMod1Out); + + amp1.update(&granularOut); + + blockBuffer.pushBuffer(granularOut.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return amp1; + } + unsigned char getPort() override { + return 0; + } + +private: + AudioEffectGranular granular1; //xy=369,297 + AudioSynthWaveformModulated waveformMod1; //xy=376,406 + AudioAmplifier amp1; //xy=602,359 + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + int16_t granularMemory[GRANULAR_MEMORY_SIZE]; + + audio_block_t granularOut, waveformMod1Out; +}; + +REGISTER_PLUGIN(grainGlitchII); diff --git a/src/noise-plethora/plugins/P_grainGlitchIII.hpp b/src/noise-plethora/plugins/P_grainGlitchIII.hpp new file mode 100644 index 0000000..f9c5b67 --- /dev/null +++ b/src/noise-plethora/plugins/P_grainGlitchIII.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" +#define GRANULAR_MEMORY_SIZE 12800 + +class grainGlitchIII : public NoisePlethoraPlugin { + +public: + + grainGlitchIII() + //:patchCord2(granular1, 0, waveformMod1, 0), + // patchCord3(waveformMod1, granular1) + { } + + ~grainGlitchIII() override {} + + grainGlitchIII(const grainGlitchIII&) = delete; + grainGlitchIII& operator=(const grainGlitchIII&) = delete; + + void init() override { + float msec = 150.0; + + waveformMod1.begin(1, 1000, WAVEFORM_SAWTOOTH); + // the Granular effect requires memory to operate + granular1.begin(granularMemory, GRANULAR_MEMORY_SIZE); + granular1.beginFreeze(msec); + + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + + float pitch1 = pow(knob_1, 2); + // float pitch2 = pow(knob_2, 2); + float msec2 = 25.0 + (knob_2 * 55.0); + float ratio; + + + waveformMod1.frequencyModulation(knob_2 * 2); + granular1.beginPitchShift(msec2); + waveformMod1.frequency(pitch1 * 5000 + 400); + ratio = powf(2.0, knob_2 * 6.0 - 3.0); + granular1.setSpeed(ratio); + + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + granular1.update(&waveformMod1Previous, &granularOut); + + waveformMod1.update(&granularOut, nullptr, &waveformMod1Previous); + + blockBuffer.pushBuffer(granularOut.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return granular1; + } + unsigned char getPort() override { + return 0; + } + +private: + AudioEffectGranular granular1; //xy=885.75,359.9999985694885 + AudioSynthWaveformModulated waveformMod1; //xy=889.75,480.74999871477485 + //AudioConnection patchCord2; + //AudioConnection patchCord3; + int16_t granularMemory[GRANULAR_MEMORY_SIZE]; + + audio_block_t granularOut; + audio_block_t waveformMod1Previous; +}; + +REGISTER_PLUGIN(grainGlitchIII); diff --git a/src/noise-plethora/plugins/P_partialCluster.hpp b/src/noise-plethora/plugins/P_partialCluster.hpp new file mode 100644 index 0000000..9bd3d68 --- /dev/null +++ b/src/noise-plethora/plugins/P_partialCluster.hpp @@ -0,0 +1,249 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class partialCluster : public NoisePlethoraPlugin { + +public: + + partialCluster() + // : + // patchCord1(noise1, 0, waveform1, 0), + // patchCord2(noise1, 0, waveform2, 0), + // patchCord3(noise1, 0, waveform3, 0), + // patchCord4(noise1, 0, waveform4, 0), + // patchCord5(noise1, 0, waveform5, 0), + // patchCord6(noise1, 0, waveform6, 0), + // patchCord7(noise1, 0, waveform7, 0), + // patchCord8(noise1, 0, waveform8, 0), + // patchCord9(noise1, 0, waveform9, 0), + // patchCord10(noise1, 0, waveform10, 0), + // patchCord11(noise1, 0, waveform11, 0), + // patchCord12(noise1, 0, waveform12, 0), + // patchCord13(noise1, 0, waveform13, 0), + // patchCord14(noise1, 0, waveform14, 0), + // patchCord15(noise1, 0, waveform15, 0), + // patchCord16(noise1, 0, waveform16, 0), + // patchCord17(waveform16, 0, mixer4, 3), + // patchCord18(waveform14, 0, mixer4, 1), + // patchCord19(waveform15, 0, mixer4, 2), + // patchCord20(waveform13, 0, mixer4, 0), + // patchCord21(waveform8, 0, mixer2, 3), + // patchCord22(waveform6, 0, mixer2, 1), + // patchCord23(waveform7, 0, mixer2, 2), + // patchCord24(waveform12, 0, mixer3, 3), + // patchCord25(waveform5, 0, mixer2, 0), + // patchCord26(waveform10, 0, mixer3, 1), + // patchCord27(waveform11, 0, mixer3, 2), + // patchCord28(waveform9, 0, mixer3, 0), + // patchCord29(waveform4, 0, mixer1, 3), + // patchCord30(waveform2, 0, mixer1, 1), + // patchCord31(waveform3, 0, mixer1, 2), + // patchCord32(waveform1, 0, mixer1, 0), + // patchCord33(mixer4, 0, mixer5, 3), + // patchCord34(mixer3, 0, mixer5, 2), + // patchCord35(mixer2, 0, mixer5, 1), + // patchCord36(mixer1, 0, mixer5, 0) + { } + + ~partialCluster() override {} + + partialCluster(const partialCluster&) = delete; + partialCluster& operator=(const partialCluster&) = delete; + + void init() override { + mixer1.gain(0, 1); + mixer1.gain(1, 1); + mixer1.gain(2, 1); + mixer1.gain(3, 1); + mixer2.gain(0, 1); + mixer2.gain(1, 1); + mixer2.gain(2, 1); + mixer2.gain(3, 1); + mixer3.gain(0, 1); + mixer3.gain(1, 1); + mixer3.gain(2, 1); + mixer3.gain(3, 1); + mixer4.gain(0, 1); + mixer4.gain(1, 1); + mixer4.gain(2, 1); + mixer4.gain(3, 1); + mixer5.gain(0, 1); + mixer5.gain(1, 1); + mixer5.gain(2, 1); + mixer5.gain(3, 1); + + int masterWaveform = WAVEFORM_SAWTOOTH; + float masterVolume = 0.25; + + waveform1.begin(masterVolume, 794, masterWaveform); + waveform2.begin(masterVolume, 647, masterWaveform); + waveform3.begin(masterVolume, 524, masterWaveform); + waveform4.begin(masterVolume, 444, masterWaveform); + waveform5.begin(masterVolume, 368, masterWaveform); + waveform6.begin(masterVolume, 283, masterWaveform); + waveform7.begin(masterVolume, 283, masterWaveform); + waveform8.begin(masterVolume, 283, masterWaveform); + waveform9.begin(masterVolume, 283, masterWaveform); + waveform10.begin(masterVolume, 283, masterWaveform); + waveform11.begin(masterVolume, 283, masterWaveform); + waveform12.begin(masterVolume, 283, masterWaveform); + waveform13.begin(masterVolume, 283, masterWaveform); + waveform14.begin(masterVolume, 283, masterWaveform); + waveform15.begin(masterVolume, 283, masterWaveform); + waveform16.begin(masterVolume, 283, masterWaveform); + + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + float pitch1 = pow(knob_1, 2); + // float pitch2 = pow(knob_2, 2); + + float spread = knob_2 * 1.1 + 1.01; + + float fundamental = 50 + pitch1 * 1000; + + float f1 = 1; + float f2 = f1 * spread; + float f3 = f2 * spread; + float f4 = f3 * spread; + float f5 = f4 * spread; + float f6 = f5 * spread; + float f7 = f6 * spread; + float f8 = f7 * spread; + float f9 = f8 * spread; + float f10 = f9 * spread; + float f11 = f10 * spread; + float f12 = f11 * spread; + float f13 = f12 * spread; + float f14 = f13 * spread; + float f15 = f14 * spread; + float f16 = f15 * spread; + + + waveform1.frequency(fundamental); + waveform2.frequency(f2 * fundamental); + waveform3.frequency(f3 * fundamental); + waveform4.frequency(f4 * fundamental); + waveform5.frequency(f5 * fundamental); + waveform6.frequency(f6 * fundamental); + waveform7.frequency(f7 * fundamental); + waveform8.frequency(f8 * fundamental); + waveform9.frequency(f9 * fundamental); + waveform10.frequency(f10 * fundamental); + waveform11.frequency(f11 * fundamental); + waveform12.frequency(f12 * fundamental); + waveform13.frequency(f13 * fundamental); + waveform14.frequency(f14 * fundamental); + waveform15.frequency(f15 * fundamental); + waveform16.frequency(f16 * fundamental); + + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + noise1.update(&noiseOut); + + // FM from single noise source + waveform1.update(&noiseOut, nullptr, &waveformOut[0]); + waveform2.update(&noiseOut, nullptr, &waveformOut[1]); + waveform3.update(&noiseOut, nullptr, &waveformOut[2]); + waveform4.update(&noiseOut, nullptr, &waveformOut[3]); + waveform5.update(&noiseOut, nullptr, &waveformOut[4]); + waveform6.update(&noiseOut, nullptr, &waveformOut[5]); + waveform7.update(&noiseOut, nullptr, &waveformOut[6]); + waveform8.update(&noiseOut, nullptr, &waveformOut[7]); + waveform9.update(&noiseOut, nullptr, &waveformOut[8]); + waveform10.update(&noiseOut, nullptr, &waveformOut[9]); + waveform11.update(&noiseOut, nullptr, &waveformOut[10]); + waveform12.update(&noiseOut, nullptr, &waveformOut[11]); + waveform13.update(&noiseOut, nullptr, &waveformOut[12]); + waveform14.update(&noiseOut, nullptr, &waveformOut[13]); + waveform15.update(&noiseOut, nullptr, &waveformOut[14]); + waveform16.update(&noiseOut, nullptr, &waveformOut[15]); + + mixer1.update(&waveformOut[0], &waveformOut[1], &waveformOut[2], &waveformOut[3], &mixerOut[0]); + mixer2.update(&waveformOut[4], &waveformOut[5], &waveformOut[6], &waveformOut[7], &mixerOut[1]); + mixer3.update(&waveformOut[8], &waveformOut[9], &waveformOut[10], &waveformOut[11], &mixerOut[2]); + mixer4.update(&waveformOut[12], &waveformOut[13], &waveformOut[14], &waveformOut[15], &mixerOut[3]); + + mixer5.update(&mixerOut[0], &mixerOut[1], &mixerOut[2], &mixerOut[3], &mixerOut[4]); + + blockBuffer.pushBuffer(mixerOut[4].data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return mixer5; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t noiseOut, waveformOut[16] = {}, mixerOut[5] = {}; + + AudioSynthNoiseWhite noise1; //xy=296.75,791.75 + AudioSynthWaveformModulated waveform16; //xy=581.75,1167.5 + AudioSynthWaveformModulated waveform14; //xy=583.75,1062.5 + AudioSynthWaveformModulated waveform15; //xy=583.75,1107.5 + AudioSynthWaveformModulated waveform13; //xy=584.75,1020 + AudioSynthWaveformModulated waveform8; //xy=591.75,747.5 + AudioSynthWaveformModulated waveform6; //xy=593.75,642.5 + AudioSynthWaveformModulated waveform7; //xy=593.75,687.5 + AudioSynthWaveformModulated waveform12; //xy=592.75,958.5 + AudioSynthWaveformModulated waveform5; //xy=594.75,600 + AudioSynthWaveformModulated waveform10; //xy=594.75,853.5 + AudioSynthWaveformModulated waveform11; //xy=594.75,898.5 + AudioSynthWaveformModulated waveform9; //xy=595.75,811 + AudioSynthWaveformModulated waveform4; //xy=599.75,532.25 + AudioSynthWaveformModulated waveform2; //xy=601.75,427.25 + AudioSynthWaveformModulated waveform3; //xy=601.75,472.25 + AudioSynthWaveformModulated waveform1; //xy=602.75,384.75 + AudioMixer4 mixer4; //xy=801.75,1111.25 + AudioMixer4 mixer3; //xy=812.75,902.25 + AudioMixer4 mixer2; //xy=818.75,691.25 + AudioMixer4 mixer1; //xy=819.75,476 + AudioMixer4 mixer5; //xy=1066.75,688 + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + // AudioConnection patchCord5; + // AudioConnection patchCord6; + // AudioConnection patchCord7; + // AudioConnection patchCord8; + // AudioConnection patchCord9; + // AudioConnection patchCord10; + // AudioConnection patchCord11; + // AudioConnection patchCord12; + // AudioConnection patchCord13; + // AudioConnection patchCord14; + // AudioConnection patchCord15; + // AudioConnection patchCord16; + // AudioConnection patchCord17; + // AudioConnection patchCord18; + // AudioConnection patchCord19; + // AudioConnection patchCord20; + // AudioConnection patchCord21; + // AudioConnection patchCord22; + // AudioConnection patchCord23; + // AudioConnection patchCord24; + // AudioConnection patchCord25; + // AudioConnection patchCord26; + // AudioConnection patchCord27; + // AudioConnection patchCord28; + // AudioConnection patchCord29; + // AudioConnection patchCord30; + // AudioConnection patchCord31; + // AudioConnection patchCord32; + // AudioConnection patchCord33; + // AudioConnection patchCord34; + // AudioConnection patchCord35; + // AudioConnection patchCord36; + +}; + +REGISTER_PLUGIN(partialCluster); diff --git a/src/noise-plethora/plugins/P_phasingCluster.hpp b/src/noise-plethora/plugins/P_phasingCluster.hpp new file mode 100644 index 0000000..6e6c295 --- /dev/null +++ b/src/noise-plethora/plugins/P_phasingCluster.hpp @@ -0,0 +1,294 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class phasingCluster : public NoisePlethoraPlugin { + +public: + + phasingCluster() + // : patchCord1(modulator13, 0, waveform13, 0), + // patchCord2(modulator14, 0, waveform14, 0), + // patchCord3(modulator15, 0, waveform15, 0), + // patchCord4(modulator2, 0, waveform2, 0), + // patchCord5(modulator4, 0, waveform4, 0), + // patchCord6(modulator1, 0, waveform1, 0), + // patchCord7(modulator16, 0, waveform16, 0), + // patchCord8(modulator12, 0, waveform12, 0), + // patchCord9(modulator11, 0, waveform11, 0), + // patchCord10(modulator3, 0, waveform3, 0), + // patchCord11(modulator5, 0, waveform5, 0), + // patchCord12(modulator6, 0, waveform6, 0), + // patchCord13(modulator7, 0, waveform7, 0), + // patchCord14(modulator10, 0, waveform10, 0), + // patchCord15(modulator8, 0, waveform8, 0), + // patchCord16(modulator9, 0, waveform9, 0), + // patchCord17(waveform16, 0, mixer4, 3), + // patchCord18(waveform14, 0, mixer4, 1), + // patchCord19(waveform15, 0, mixer4, 2), + // patchCord20(waveform13, 0, mixer4, 0), + // patchCord21(waveform8, 0, mixer2, 3), + // patchCord22(waveform6, 0, mixer2, 1), + // patchCord23(waveform7, 0, mixer2, 2), + // patchCord24(waveform12, 0, mixer3, 3), + // patchCord25(waveform5, 0, mixer2, 0), + // patchCord26(waveform10, 0, mixer3, 1), + // patchCord27(waveform11, 0, mixer3, 2), + // patchCord28(waveform9, 0, mixer3, 0), + // patchCord29(waveform4, 0, mixer1, 3), + // patchCord30(waveform2, 0, mixer1, 1), + // patchCord31(waveform3, 0, mixer1, 2), + // patchCord32(waveform1, 0, mixer1, 0), + // patchCord33(mixer4, 0, mixer5, 3), + // patchCord34(mixer3, 0, mixer5, 2), + // patchCord35(mixer2, 0, mixer5, 1), + // patchCord36(mixer1, 0, mixer5, 0) + { } + + ~phasingCluster() override {} + + phasingCluster(const phasingCluster&) = delete; + phasingCluster& operator=(const phasingCluster&) = delete; + + + void init() override { + mixer1.gain(0, 1); + mixer1.gain(1, 1); + mixer1.gain(2, 1); + mixer1.gain(3, 1); + mixer2.gain(0, 1); + mixer2.gain(1, 1); + mixer2.gain(2, 1); + mixer2.gain(3, 1); + mixer3.gain(0, 1); + mixer3.gain(1, 1); + mixer3.gain(2, 1); + mixer3.gain(3, 1); + mixer4.gain(0, 1); + mixer4.gain(1, 1); + mixer4.gain(2, 1); + mixer4.gain(3, 1); + mixer5.gain(0, 1); + mixer5.gain(1, 1); + mixer5.gain(2, 1); + mixer5.gain(3, 1); + + int masterWaveform = WAVEFORM_SQUARE; + float masterVolume = 0.1; + int indexWaveform = WAVEFORM_TRIANGLE; + float index = 0.005; + + waveform1.begin(masterVolume, 794, masterWaveform); + waveform2.begin(masterVolume, 647, masterWaveform); + waveform3.begin(masterVolume, 524, masterWaveform); + waveform4.begin(masterVolume, 444, masterWaveform); + waveform5.begin(masterVolume, 368, masterWaveform); + waveform6.begin(masterVolume, 283, masterWaveform); + waveform7.begin(masterVolume, 283, masterWaveform); + waveform8.begin(masterVolume, 283, masterWaveform); + waveform9.begin(masterVolume, 283, masterWaveform); + waveform10.begin(masterVolume, 283, masterWaveform); + waveform11.begin(masterVolume, 283, masterWaveform); + waveform12.begin(masterVolume, 283, masterWaveform); + waveform13.begin(masterVolume, 283, masterWaveform); + waveform14.begin(masterVolume, 283, masterWaveform); + waveform15.begin(masterVolume, 283, masterWaveform); + waveform16.begin(masterVolume, 283, masterWaveform); + + modulator1.begin(index, 10, indexWaveform); + modulator2.begin(index, 11, indexWaveform); + modulator3.begin(index, 15, indexWaveform); + modulator4.begin(index, 1, indexWaveform); + modulator5.begin(index, 1, indexWaveform); + modulator6.begin(index, 3, indexWaveform); + modulator7.begin(index, 17, indexWaveform); + modulator8.begin(index, 14, indexWaveform); + modulator9.begin(index, 0.11, indexWaveform); + modulator10.begin(index, 5, indexWaveform); + modulator11.begin(index, 2, indexWaveform); + modulator12.begin(index, 7, indexWaveform); + modulator13.begin(index, 1, indexWaveform); + modulator14.begin(index, 0.1, indexWaveform); + modulator15.begin(index, 0.7, indexWaveform); + modulator16.begin(index, 0.5, indexWaveform); + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + float pitch1 = pow(knob_1, 2); + + + float spread = knob_2 * 0.5 + 1; + + float f1 = 30 + pitch1 * 5000; + float f2 = f1 * spread; + float f3 = f2 * spread; + float f4 = f3 * spread; + float f5 = f4 * spread; + float f6 = f5 * spread; + float f7 = f6 * spread; + float f8 = f7 * spread; + float f9 = f8 * spread; + float f10 = f9 * spread; + float f11 = f10 * spread; + float f12 = f11 * spread; + float f13 = f12 * spread; + float f14 = f13 * spread; + float f15 = f14 * spread; + float f16 = f15 * spread; + + waveform1.frequency(f1); + waveform2.frequency(f2); + waveform3.frequency(f3); + waveform4.frequency(f4); + waveform5.frequency(f5); + waveform6.frequency(f6); + waveform7.frequency(f7); + waveform8.frequency(f8); + waveform9.frequency(f9); + waveform10.frequency(f10); + waveform11.frequency(f11); + waveform12.frequency(f12); + waveform13.frequency(f13); + waveform14.frequency(f14); + waveform15.frequency(f15); + waveform16.frequency(f16); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + // first update modulators + modulator1.update(&waveformOut[0]); + modulator2.update(&waveformOut[1]); + modulator3.update(&waveformOut[2]); + modulator4.update(&waveformOut[3]); + modulator5.update(&waveformOut[4]); + modulator6.update(&waveformOut[5]); + modulator7.update(&waveformOut[6]); + modulator8.update(&waveformOut[7]); + modulator9.update(&waveformOut[8]); + modulator10.update(&waveformOut[9]); + modulator11.update(&waveformOut[10]); + modulator12.update(&waveformOut[11]); + modulator13.update(&waveformOut[12]); + modulator14.update(&waveformOut[13]); + modulator15.update(&waveformOut[14]); + modulator16.update(&waveformOut[15]); + + // FM from each of the modulators + waveform1.update(&waveformOut[0], nullptr, &waveformModOut[0]); + waveform2.update(&waveformOut[1], nullptr, &waveformModOut[1]); + waveform3.update(&waveformOut[2], nullptr, &waveformModOut[2]); + waveform4.update(&waveformOut[3], nullptr, &waveformModOut[3]); + waveform5.update(&waveformOut[4], nullptr, &waveformModOut[4]); + waveform6.update(&waveformOut[5], nullptr, &waveformModOut[5]); + waveform7.update(&waveformOut[6], nullptr, &waveformModOut[6]); + waveform8.update(&waveformOut[7], nullptr, &waveformModOut[7]); + waveform9.update(&waveformOut[8], nullptr, &waveformModOut[8]); + waveform10.update(&waveformOut[9], nullptr, &waveformModOut[9]); + waveform11.update(&waveformOut[10], nullptr, &waveformModOut[10]); + waveform12.update(&waveformOut[11], nullptr, &waveformModOut[11]); + waveform13.update(&waveformOut[12], nullptr, &waveformModOut[12]); + waveform14.update(&waveformOut[13], nullptr, &waveformModOut[13]); + waveform15.update(&waveformOut[14], nullptr, &waveformModOut[14]); + waveform16.update(&waveformOut[15], nullptr, &waveformModOut[15]); + + mixer1.update(&waveformModOut[0], &waveformModOut[1], &waveformModOut[2], &waveformModOut[3], &mixerOut[0]); + mixer2.update(&waveformModOut[4], &waveformModOut[5], &waveformModOut[6], &waveformModOut[7], &mixerOut[1]); + mixer3.update(&waveformModOut[8], &waveformModOut[9], &waveformModOut[10], &waveformModOut[11], &mixerOut[2]); + mixer4.update(&waveformModOut[12], &waveformModOut[13], &waveformModOut[14], &waveformModOut[15], &mixerOut[3]); + + mixer5.update(&mixerOut[0], &mixerOut[1], &mixerOut[2], &mixerOut[3], &mixerOut[4]); + + blockBuffer.pushBuffer(mixerOut[4].data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return mixer5; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t waveformOut[16] = {}, waveformModOut[16] = {}, mixerOut[5] = {}; + + AudioSynthWaveform modulator13; //xy=331.3333435058594,888.6666870117188 + AudioSynthWaveform modulator14; //xy=331.3333435058594,935.6666870117188 + AudioSynthWaveform modulator15; //xy=331.3333435058594,976.6666870117188 + AudioSynthWaveform modulator2; //xy=335.3333435058594,243.6666717529297 + AudioSynthWaveform modulator4; //xy=336.3333435058594,349.6666564941406 + AudioSynthWaveform modulator1; //xy=337.33335876464844,198.6666660308838 + AudioSynthWaveform modulator16; //xy=334.3333435058594,1026.6666259765625 + AudioSynthWaveform modulator12; //xy=335.3333435058594,823.6666870117188 + AudioSynthWaveform modulator11; //xy=337.3333435058594,753.6666870117188 + AudioSynthWaveform modulator3; //xy=339.3333435058594,293.6666564941406 + AudioSynthWaveform modulator5; //xy=339.3333435058594,414.6666564941406 + AudioSynthWaveform modulator6; //xy=341.3333435058594,467.6666564941406 + AudioSynthWaveform modulator7; //xy=344.3333435058594,522.6666870117188 + AudioSynthWaveform modulator10; //xy=344.3333435058594,687.6666870117188 + AudioSynthWaveform modulator8; //xy=346.3333435058594,569.6666870117188 + AudioSynthWaveform modulator9; //xy=350.3333435058594,624.6666870117188 + AudioSynthWaveformModulated waveform16; //xy=532.3333282470703,986.8888931274414 + AudioSynthWaveformModulated waveform14; //xy=534.3333282470703,881.8888931274414 + AudioSynthWaveformModulated waveform15; //xy=534.3333282470703,926.8888931274414 + AudioSynthWaveformModulated waveform13; //xy=535.3333282470703,839.8888931274414 + AudioSynthWaveformModulated waveform8; //xy=542.3333282470703,566.8888931274414 + AudioSynthWaveformModulated waveform6; //xy=544.3333282470703,461.8888931274414 + AudioSynthWaveformModulated waveform7; //xy=544.3333282470703,506.8888931274414 + AudioSynthWaveformModulated waveform12; //xy=543.3333282470703,777.8888931274414 + AudioSynthWaveformModulated waveform5; //xy=545.3333282470703,419.8888931274414 + AudioSynthWaveformModulated waveform10; //xy=545.3333282470703,672.8888931274414 + AudioSynthWaveformModulated waveform11; //xy=545.3333282470703,717.8888931274414 + AudioSynthWaveformModulated waveform9; //xy=546.3333282470703,630.8888931274414 + AudioSynthWaveformModulated waveform4; //xy=550.3333282470703,351.8888931274414 + AudioSynthWaveformModulated waveform2; //xy=552.3333282470703,246.8888931274414 + AudioSynthWaveformModulated waveform3; //xy=552.3333282470703,291.8888931274414 + AudioSynthWaveformModulated waveform1; //xy=553.3333282470703,203.8888931274414 + AudioMixer4 mixer4; //xy=752.3333282470703,930.8888931274414 + AudioMixer4 mixer3; //xy=763.3333282470703,721.8888931274414 + AudioMixer4 mixer2; //xy=769.3333282470703,510.8888931274414 + AudioMixer4 mixer1; //xy=770.3333282470703,295.8888931274414 + AudioMixer4 mixer5; //xy=1017.3333282470703,507.8888931274414 + + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + // AudioConnection patchCord5; + // AudioConnection patchCord6; + // AudioConnection patchCord7; + // AudioConnection patchCord8; + // AudioConnection patchCord9; + // AudioConnection patchCord10; + // AudioConnection patchCord11; + // AudioConnection patchCord12; + // AudioConnection patchCord13; + // AudioConnection patchCord14; + // AudioConnection patchCord15; + // AudioConnection patchCord16; + // AudioConnection patchCord17; + // AudioConnection patchCord18; + // AudioConnection patchCord19; + // AudioConnection patchCord20; + // AudioConnection patchCord21; + // AudioConnection patchCord22; + // AudioConnection patchCord23; + // AudioConnection patchCord24; + // AudioConnection patchCord25; + // AudioConnection patchCord26; + // AudioConnection patchCord27; + // AudioConnection patchCord28; + // AudioConnection patchCord29; + // AudioConnection patchCord30; + // AudioConnection patchCord31; + // AudioConnection patchCord32; + // AudioConnection patchCord33; + // AudioConnection patchCord34; + // AudioConnection patchCord35; + // AudioConnection patchCord36; +}; + +REGISTER_PLUGIN(phasingCluster); diff --git a/src/noise-plethora/plugins/P_pwCluster.hpp b/src/noise-plethora/plugins/P_pwCluster.hpp new file mode 100644 index 0000000..ecb39a1 --- /dev/null +++ b/src/noise-plethora/plugins/P_pwCluster.hpp @@ -0,0 +1,139 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class pwCluster : public NoisePlethoraPlugin { + +public: + + pwCluster() + //: + //patchCord1(dc1, 0, waveform1, 1), + //patchCord2(dc1, 0, waveform2, 1), + //patchCord3(dc1, 0, waveform3, 1), + //patchCord4(dc1, 0, waveform4, 1), + //patchCord5(dc1, 0, waveform5, 1), + //patchCord6(dc1, 0, waveform6, 1), + //patchCord7(waveform6, 0, mixer2, 1), + //patchCord8(waveform5, 0, mixer2, 0), + //patchCord9(waveform4, 0, mixer1, 3), + //patchCord10(waveform2, 0, mixer1, 1), + //patchCord11(waveform3, 0, mixer1, 2), + //patchCord12(waveform1, 0, mixer1, 0), + //patchCord13(mixer1, 0, mixer5, 0), + //patchCord14(mixer2, 0, mixer5, 1) + { + DEBUG("pwCluster initialised"); + } + + ~pwCluster() override { + DEBUG("pwCluster destroyed"); + } + + pwCluster(const pwCluster&) = delete; + pwCluster& operator=(const pwCluster&) = delete; + + void init() override { + + mixer1.gain(0, 1); + mixer1.gain(1, 1); + mixer1.gain(2, 1); + mixer1.gain(3, 1); + mixer2.gain(0, 1); + mixer2.gain(1, 1); + mixer2.gain(2, 1); + mixer2.gain(3, 1); + mixer5.gain(0, 1); + mixer5.gain(1, 1); + mixer5.gain(2, 1); + mixer5.gain(3, 1); + + int masterWaveform = WAVEFORM_PULSE; + float masterVolume = 0.7; + + waveform1.begin(masterVolume, 794, masterWaveform); + waveform2.begin(masterVolume, 647, masterWaveform); + waveform3.begin(masterVolume, 524, masterWaveform); + waveform4.begin(masterVolume, 444, masterWaveform); + waveform5.begin(masterVolume, 368, masterWaveform); + waveform6.begin(masterVolume, 283, masterWaveform); + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + float pitch1 = std::pow(knob_1, 2); + + float f1 = 40 + pitch1 * 8000; + float f2 = f1 * 1.227; + float f3 = f2 * 1.24; + float f4 = f3 * 1.17; + float f5 = f4 * 1.2; + float f6 = f5 * 1.3; + dc1.amplitude(1 - (knob_2 * 0.97)); + + waveform1.frequency(f1); + waveform2.frequency(f2); + waveform3.frequency(f3); + waveform4.frequency(f4); + waveform5.frequency(f5); + waveform6.frequency(f6); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + dc1.update(&dcOut); + + // pulsewidth from dc1 for the 6 oscillators + waveform1.update(nullptr, &dcOut, &waveformOut[0]); + waveform2.update(nullptr, &dcOut, &waveformOut[1]); + waveform3.update(nullptr, &dcOut, &waveformOut[2]); + waveform4.update(nullptr, &dcOut, &waveformOut[3]); + waveform5.update(nullptr, &dcOut, &waveformOut[4]); + waveform6.update(nullptr, &dcOut, &waveformOut[5]); + + mixer1.update(&waveformOut[0], &waveformOut[1], &waveformOut[2], &waveformOut[3], &mixerOut[0]); + mixer2.update(&waveformOut[4], &waveformOut[5], nullptr, nullptr, &mixerOut[1]); + mixer5.update(&mixerOut[0], &mixerOut[1], nullptr, nullptr, &mixerOut[2]); + + blockBuffer.pushBuffer(mixerOut[2].data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return mixer5; + } + unsigned char getPort() override { + return 0; + } + +private: + audio_block_t dcOut, waveformOut[6] = {}, mixerOut[3] = {}; + + AudioSynthWaveformDc dc1; //xy=305.8888854980469,1069.1111450195312 + AudioSynthWaveformModulated waveform6; //xy=482.8888854980469,800.1111450195312 + AudioSynthWaveformModulated waveform5; //xy=483.8888854980469,758.1111450195312 + AudioSynthWaveformModulated waveform4; //xy=488.8888854980469,690.1111450195312 + AudioSynthWaveformModulated waveform2; //xy=490.8888854980469,585.1111450195312 + AudioSynthWaveformModulated waveform3; //xy=490.8888854980469,630.1111450195312 + AudioSynthWaveformModulated waveform1; //xy=491.8888854980469,542.1111450195312 + AudioMixer4 mixer1; //xy=708.8888854980469,634.1111450195312 + AudioMixer4 mixer2; //xy=719.8888854980469,789.1111450195312 + AudioMixer4 mixer5; //xy=955.8888854980469,846.1111450195312 + + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + // AudioConnection patchCord5; + // AudioConnection patchCord6; + // AudioConnection patchCord7; + // AudioConnection patchCord8; + // AudioConnection patchCord9; + // AudioConnection patchCord10; + // AudioConnection patchCord11; + // AudioConnection patchCord12; + // AudioConnection patchCord13; + // AudioConnection patchCord14; + +}; + +REGISTER_PLUGIN(pwCluster); diff --git a/src/noise-plethora/plugins/P_radioOhNo.hpp b/src/noise-plethora/plugins/P_radioOhNo.hpp new file mode 100644 index 0000000..4b2fa90 --- /dev/null +++ b/src/noise-plethora/plugins/P_radioOhNo.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class radioOhNo : public NoisePlethoraPlugin { + +public: + + radioOhNo() + //: patchCord1(dc1, 0, waveformMod1, 1), + // patchCord2(dc1, 0, waveformMod2, 1), + // patchCord3(dc1, 0, waveformMod3, 1), + // patchCord4(dc1, 0, waveformMod4, 1), + // patchCord5(waveformMod2, 0, waveformMod1, 0), + // patchCord6(waveformMod1, 0, waveformMod2, 0), + // patchCord7(waveformMod1, 0, mixer1, 0), + // patchCord8(waveformMod3, 0, waveformMod4, 0), + // patchCord9(waveformMod3, 0, mixer1, 1), + // patchCord10(waveformMod4, 0, waveformMod3, 0) + { } + + ~radioOhNo() override {} + + radioOhNo(const radioOhNo&) = delete; + radioOhNo& operator=(const radioOhNo&) = delete; + + void init() override { + waveformMod1.begin(0.8, 500, WAVEFORM_PULSE); + waveformMod2.begin(0.8, 1500, WAVEFORM_PULSE); + waveformMod3.begin(0.8, 600, WAVEFORM_PULSE); + waveformMod4.begin(0.8, 1600, WAVEFORM_PULSE); + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + float pitch1 = pow(knob_1, 2); + // float pitch2 = pow(knob_2, 2); + + + waveformMod1.frequency(2500 * pitch1 + 20); + waveformMod2.frequency(1120 - (1100 * pitch1)); + waveformMod3.frequency(2900 * pitch1 + 20); + waveformMod4.frequency(8020 - (8000 * pitch1 + 20)); + waveformMod1.frequencyModulation(5); + waveformMod2.frequencyModulation(5); + waveformMod1.frequencyModulation(5); + waveformMod2.frequencyModulation(5); + dc1.amplitude(knob_2); + + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + dc1.update(&dcPrevious); + + waveformMod2.update(&waveformModPrevious[1], &dcPrevious, &waveformModPrevious[2]); + waveformMod1.update(&waveformModPrevious[2], &dcPrevious, &waveformModPrevious[1]); + + waveformMod3.update(&waveformModPrevious[4], &dcPrevious, &waveformModPrevious[3]); + waveformMod4.update(&waveformModPrevious[3], &dcPrevious, &waveformModPrevious[4]); + + mixer1.update(&waveformModPrevious[1], &waveformModPrevious[3], nullptr, nullptr, &mixerOut); + + blockBuffer.pushBuffer(mixerOut.data, AUDIO_BLOCK_SAMPLES); + + } + + AudioStream& getStream() override { + return mixer1; + } + unsigned char getPort() override { + return 0; + } + +private: + + audio_block_t waveformModPrevious[5]; + audio_block_t dcPrevious; + audio_block_t mixerOut; + + AudioSynthWaveformDc dc1; //xy=179.75,710.75 + AudioSynthWaveformModulated waveformMod2; //xy=464.75,614.75 + AudioSynthWaveformModulated waveformMod1; //xy=466.75,490.75 + AudioSynthWaveformModulated waveformMod3; //xy=468.75,729.75 + AudioSynthWaveformModulated waveformMod4; //xy=470.75,848.75 + AudioMixer4 mixer1; //xy=676.750057220459,680.7500286102295 + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + // AudioConnection patchCord5; + // AudioConnection patchCord6; + // AudioConnection patchCord7; + // AudioConnection patchCord8; + // AudioConnection patchCord9; + // AudioConnection patchCord10; +}; + +REGISTER_PLUGIN(radioOhNo); diff --git a/src/noise-plethora/plugins/P_resonoise.hpp b/src/noise-plethora/plugins/P_resonoise.hpp new file mode 100644 index 0000000..0f9f630 --- /dev/null +++ b/src/noise-plethora/plugins/P_resonoise.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class resonoise : public NoisePlethoraPlugin { + +public: + + resonoise() + // : patchCord1(waveformMod1, sine_fm1) + // , patchCord2(noise1, 0, filter1, 0) + // , patchCord3(sine_fm1, 0, wavefolder1, 0) + // , patchCord4(dc1, 0, wavefolder1, 1) + // , patchCord5(wavefolder1, 0, filter1, 1) + { } + + ~resonoise() override {} + + // delete copy constructors + resonoise(const resonoise&) = delete; + resonoise& operator=(const resonoise&) = delete; + + void init() override { + + noise1.amplitude(1); + + sine_fm1.frequency(1100); + + + sine_fm1.amplitude(1); + waveformMod1.begin(1, 500, WAVEFORM_SQUARE); + + filter1.resonance(3); + filter1.octaveControl(5); + } + + void process(float k1, float k2) override { + + + float knob_1 = k1; + float knob_2 = k2; + + float pitch1 = pow(knob_1, 2); + + dc1.amplitude(knob_2 * 0.2 + 0.03, 1); + + sine_fm1.frequency(20 + (pitch1 * 10000)); + waveformMod1.frequency(20 + (pitch1 * 7777)); + + } + + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + waveformMod1.update(nullptr, nullptr, &waveformMod1Block); + sine_fm1.update(&waveformMod1Block, &sineFMBlock); + + dc1.update(&dcBlock); + wavefolder1.update(&sineFMBlock, &dcBlock, &wavefolderBlock); + + noise1.update(&noiseBlock); + filter1.update(&noiseBlock, &wavefolderBlock, &filterOutLP, &filterOutBP, &filterOutHP); + + blockBuffer.pushBuffer(filterOutLP.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return filter1; + } + unsigned char getPort() override { + return 0; + } + +private: + // GUItool: begin automatically generated code + AudioSynthWaveformModulated waveformMod1; //xy=245.88888549804688,699.2222213745117 + AudioSynthNoiseWhite noise1; //xy=271.8888854980469,354.8888854980469 + AudioSynthWaveformSineModulated sine_fm1; //xy=303.88890838623047,455.8889751434326 + AudioSynthWaveformDc dc1; //xy=436.8888854980469,646.1111145019531 + AudioEffectWaveFolder wavefolder1; //xy=469.8888854980469,520.1111145019531 + AudioFilterStateVariable filter1; //xy=559.8888854980469,410.88891983032227 + + audio_block_t noiseBlock, waveformMod1Block, sineFMBlock, wavefolderBlock, dcBlock; + audio_block_t filterOutLP, filterOutBP, filterOutHP; + + + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + // AudioConnection patchCord5; + +}; + +REGISTER_PLUGIN(resonoise); // this is important, so that we can include the plugin in a bank diff --git a/src/noise-plethora/plugins/P_satanWorkout.hpp b/src/noise-plethora/plugins/P_satanWorkout.hpp new file mode 100644 index 0000000..e7c9b81 --- /dev/null +++ b/src/noise-plethora/plugins/P_satanWorkout.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class satanWorkout : public NoisePlethoraPlugin { + +public: + + satanWorkout() + //: patchCord1(pink1, pwm1) + //, patchCord2(pwm1, freeverb1) + { } + + ~satanWorkout() override {} + + // delete copy constructors + satanWorkout(const satanWorkout&) = delete; + satanWorkout& operator=(const satanWorkout&) = delete; + + void init() override { + + pink1.amplitude(1); + pwm1.amplitude(1); + freeverb1.damping(-5); + + } + + void process(float k1, float k2) override { + + + float knob_1 = k1; + float knob_2 = k2; + + float pitch1 = pow(knob_1, 2); + // float pitch2 = pow(knob_2, 2); + + pwm1.frequency(8 + pitch1 * 6000); + + freeverb1.roomsize(0.001 + knob_2 * 4); + + + //Serial.print(pitch1 * 10000 + 20); + //Serial.println(); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + pink1.update(&noiseBlock); + pwm1.update(&noiseBlock, &pwmBlock); + freeverb1.update(&pwmBlock, &freeverbBlock); + + blockBuffer.pushBuffer(freeverbBlock.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return freeverb1; + } + unsigned char getPort() override { + return 0; + } + +private: + audio_block_t noiseBlock, pwmBlock, freeverbBlock; + + // GUItool: begin automatically generated code + AudioSynthNoisePink pink1; //xy=927.6667137145996,1712.0000095367432 + AudioSynthWaveformPWM pwm1; //xy=1065.6666564941406,1795.666675567627 + AudioEffectFreeverb freeverb1; //xy=1152.6666564941406,1739.6666746139526 + //AudioConnection patchCord1; + //AudioConnection patchCord2; + + +}; + +REGISTER_PLUGIN(satanWorkout); // this is important, so that we can include the plugin in a bank diff --git a/src/noise-plethora/plugins/P_sineFMcluster.hpp b/src/noise-plethora/plugins/P_sineFMcluster.hpp new file mode 100644 index 0000000..3b38622 --- /dev/null +++ b/src/noise-plethora/plugins/P_sineFMcluster.hpp @@ -0,0 +1,168 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class sineFMcluster : public NoisePlethoraPlugin { + +public: + + sineFMcluster() + // : patchCord1(modulator1, 0, waveform1, 0), + // patchCord2(modulator3, 0, waveform3, 0), + // patchCord3(modulator2, 0, waveform2, 0), + // patchCord4(modulator5, 0, waveform5, 0), + // patchCord5(modulator4, 0, waveform4, 0), + // patchCord6(modulator6, 0, waveform6, 0), + // patchCord7(waveform1, 0, mixer1, 0), + // patchCord8(waveform4, 0, mixer1, 3), + // patchCord9(waveform2, 0, mixer1, 1), + // patchCord10(waveform3, 0, mixer1, 2), + // patchCord11(waveform6, 0, mixer2, 1), + // patchCord12(waveform5, 0, mixer2, 0), + // patchCord13(mixer2, 0, mixer5, 1), + // patchCord14(mixer1, 0, mixer5, 0) + { } + + ~sineFMcluster() override {} + + sineFMcluster(const sineFMcluster&) = delete; + sineFMcluster& operator=(const sineFMcluster&) = delete; + + void init() override { + mixer1.gain(0, 1); + mixer1.gain(1, 1); + mixer1.gain(2, 1); + mixer1.gain(3, 1); + mixer2.gain(0, 1); + mixer2.gain(1, 1); + mixer2.gain(2, 1); + mixer2.gain(3, 1); + mixer5.gain(0, 1); + mixer5.gain(1, 1); + mixer5.gain(2, 1); + mixer5.gain(3, 1); + + int masterWaveform = WAVEFORM_TRIANGLE; + float masterVolume = 0.25; + + waveform1.begin(masterVolume, 794, masterWaveform); + waveform2.begin(masterVolume, 647, masterWaveform); + waveform3.begin(masterVolume, 524, masterWaveform); + waveform4.begin(masterVolume, 444, masterWaveform); + waveform5.begin(masterVolume, 368, masterWaveform); + waveform6.begin(masterVolume, 283, masterWaveform); + + modulator1.begin(1, 1000, WAVEFORM_SINE); + modulator2.begin(1, 1000, WAVEFORM_SINE); + modulator3.begin(1, 1000, WAVEFORM_SINE); + modulator4.begin(1, 1000, WAVEFORM_SINE); + modulator5.begin(1, 1000, WAVEFORM_SINE); + modulator6.begin(1, 1000, WAVEFORM_SINE); + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + float pitch1 = pow(knob_1, 2); + + float f1 = 300 + pitch1 * 8000; + float f2 = f1 * 1.227; + float f3 = f2 * 1.24; + float f4 = f3 * 1.17; + float f5 = f4 * 1.2; + float f6 = f5 * 1.3; + + float index = knob_2 * 0.9 + 0.1; + float indexFreq = 0.333; + + modulator1.amplitude(index); + modulator2.amplitude(index); + modulator3.amplitude(index); + modulator4.amplitude(index); + modulator5.amplitude(index); + modulator6.amplitude(index); + + + modulator1.frequency(f1 * indexFreq); + modulator2.frequency(f2 * indexFreq); + modulator3.frequency(f3 * indexFreq); + modulator4.frequency(f4 * indexFreq); + modulator5.frequency(f5 * indexFreq); + modulator6.frequency(f6 * indexFreq); + + + waveform1.frequency(f1); + waveform2.frequency(f2); + waveform3.frequency(f3); + waveform4.frequency(f4); + waveform5.frequency(f5); + waveform6.frequency(f6); + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + // modulators for the 6 oscillators + modulator1.update(&waveformOut[0]); + modulator2.update(&waveformOut[1]); + modulator3.update(&waveformOut[2]); + modulator4.update(&waveformOut[3]); + modulator5.update(&waveformOut[4]); + modulator6.update(&waveformOut[5]); + + // FM for the 6 oscillators from modulators + waveform1.update(&waveformOut[0], nullptr, &waveformModOut[0]); + waveform2.update(&waveformOut[1], nullptr, &waveformModOut[1]); + waveform3.update(&waveformOut[2], nullptr, &waveformModOut[2]); + waveform4.update(&waveformOut[3], nullptr, &waveformModOut[3]); + waveform5.update(&waveformOut[4], nullptr, &waveformModOut[4]); + waveform6.update(&waveformOut[5], nullptr, &waveformModOut[5]); + + mixer1.update(&waveformModOut[0], &waveformModOut[1], &waveformModOut[2], &waveformModOut[3], &mixerOut[0]); + mixer2.update(&waveformModOut[4], &waveformModOut[5], nullptr, nullptr, &mixerOut[1]); + mixer5.update(&mixerOut[0], &mixerOut[1], nullptr, nullptr, &mixerOut[2]); + + blockBuffer.pushBuffer(mixerOut[2].data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return mixer5; + } + unsigned char getPort() override { + return 0; + } + +private: + audio_block_t waveformOut[6] = {}, waveformModOut[6] = {}, mixerOut[3] = {}; + + AudioSynthWaveform modulator1; //xy=236.88888549804688,262.55556869506836 + AudioSynthWaveform modulator3; //xy=238.88890075683594,366.555606842041 + AudioSynthWaveform modulator2; //xy=239.88890075683594,313.5556392669678 + AudioSynthWaveform modulator5; //xy=239.88890075683594,485.5555810928345 + AudioSynthWaveform modulator4; //xy=240.88890075683594,428.55560970306396 + AudioSynthWaveform modulator6; //xy=242.8888931274414,541.5555143356323 + AudioSynthWaveformModulated waveform1; //xy=459.88890075683594,268.6667013168335 + AudioSynthWaveformModulated waveform4; //xy=459.8888854980469,433.6666889190674 + AudioSynthWaveformModulated waveform2; //xy=461.88890838623047,322.66671657562256 + AudioSynthWaveformModulated waveform3; //xy=461.8888854980469,373.6666889190674 + AudioSynthWaveformModulated waveform6; //xy=461.88890838623047,546.6666688919067 + AudioSynthWaveformModulated waveform5; //xy=462.88888931274414,492.66670417785645 + AudioMixer4 mixer2; //xy=663.8888053894043,520.6666412353516 + AudioMixer4 mixer1; //xy=667.888916015625,349.6667251586914 + AudioMixer4 mixer5; //xy=853.8889122009277,448.6667900085449 + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + // AudioConnection patchCord5; + // AudioConnection patchCord6; + // AudioConnection patchCord7; + // AudioConnection patchCord8; + // AudioConnection patchCord9; + // AudioConnection patchCord10; + // AudioConnection patchCord11; + // AudioConnection patchCord12; + // AudioConnection patchCord13; + // AudioConnection patchCord14; + +}; + +REGISTER_PLUGIN(sineFMcluster); diff --git a/src/noise-plethora/plugins/P_whoKnows.hpp b/src/noise-plethora/plugins/P_whoKnows.hpp new file mode 100644 index 0000000..bd03b49 --- /dev/null +++ b/src/noise-plethora/plugins/P_whoKnows.hpp @@ -0,0 +1,148 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class whoKnows : public NoisePlethoraPlugin { + +public: + + whoKnows() + // : patchCord1(waveform1, 0, filter1, 0) + // , patchCord2(waveform1, 0, filter2, 0) + // , patchCord3(waveform1, 0, filter3, 0) + // , patchCord4(waveform1, 0, filter4, 0) + // , patchCord5(waveformMod1, 0, filter1, 1) + // , patchCord6(waveformMod2, 0, filter2, 1) + // , patchCord7(waveformMod4, 0, filter4, 1) + // , patchCord8(waveformMod3, 0, filter3, 1) + // , patchCord9(filter1, 1, mixer1, 0) + // , patchCord10(filter2, 1, mixer1, 1) + // , patchCord11(filter3, 1, mixer1, 2) + // , patchCord12(filter4, 1, mixer1, 3) + { } + + ~whoKnows() override {} + + // delete copy constructors + whoKnows(const whoKnows&) = delete; + whoKnows& operator=(const whoKnows&) = delete; + + void init() override { + + //noise1.amplitude(1); + + mixer1.gain(0, 0.8); + mixer1.gain(1, 0.8); + mixer1.gain(2, 0.8); + mixer1.gain(3, 0.8); + + + waveformMod1.begin(1, 21, WAVEFORM_TRIANGLE); + waveformMod2.begin(1, 70, WAVEFORM_TRIANGLE); + waveformMod3.begin(1, 90, WAVEFORM_TRIANGLE); + waveformMod4.begin(1, 77, WAVEFORM_TRIANGLE); + + waveform1.begin(1, 5, WAVEFORM_PULSE); + waveform1.pulseWidth(0.1); + + filter1.resonance(7); + filter1.octaveControl(7); + + filter2.resonance(7); + filter2.octaveControl(7); + + filter3.resonance(7); + filter3.octaveControl(7); + + filter4.resonance(7); + filter4.octaveControl(7); + } + + void process(float k1, float k2) override { + + + float knob_1 = k1; + float knob_2 = k2; + + float pitch1 = pow(knob_1, 2); + // float pitch2 = pow(knob_2, 2); + + + waveform1.frequency(15 + (pitch1 * 500)); + + float octaves = knob_2 * 6 + 0.3; + + /*filter1.resonance(resonanceLevel); + filter2.resonance(resonanceLevel); + filter3.resonance(resonanceLevel); + filter4.resonance(resonanceLevel);*/ + + filter1.octaveControl(octaves); + filter2.octaveControl(octaves); + filter3.octaveControl(octaves); + filter4.octaveControl(octaves); + + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + + // waveform to filter + waveform1.update(&waveformOut); + + waveformMod1.update(nullptr, nullptr, &waveformModOut[0]); + waveformMod2.update(nullptr, nullptr, &waveformModOut[1]); + waveformMod3.update(nullptr, nullptr, &waveformModOut[2]); + waveformMod4.update(nullptr, nullptr, &waveformModOut[3]); + + filter1.update(&waveformOut, &waveformModOut[0], &filterOutLP[0], &filterOutBP[0], &filterOutHP[0]); + filter2.update(&waveformOut, &waveformModOut[1], &filterOutLP[1], &filterOutBP[1], &filterOutHP[1]); + filter3.update(&waveformOut, &waveformModOut[2], &filterOutLP[2], &filterOutBP[2], &filterOutHP[2]); + filter4.update(&waveformOut, &waveformModOut[3], &filterOutLP[3], &filterOutBP[3], &filterOutHP[3]); + + // sum up + mixer1.update(&filterOutBP[0], &filterOutBP[1], &filterOutBP[2], &filterOutBP[3], &mixerOut); + + blockBuffer.pushBuffer(mixerOut.data, AUDIO_BLOCK_SAMPLES); + } + + + AudioStream& getStream() override { + return mixer1; + } + unsigned char getPort() override { + return 0; + } + +private: + + + audio_block_t filterOutLP[4], filterOutBP[4], filterOutHP[4], waveformModOut[4], waveformOut, mixerOut; + + + // GUItool: begin automatically generated code + AudioSynthWaveform waveform1; //xy=283,566 + AudioSynthWaveformModulated waveformMod1; //xy=363.888916015625,321.2221794128418 + AudioSynthWaveformModulated waveformMod2; //xy=368,380.3332633972168 + AudioSynthWaveformModulated waveformMod4; //xy=374,689.3332633972168 + AudioSynthWaveformModulated waveformMod3; //xy=378,638.3332633972168 + AudioFilterStateVariable filter1; //xy=578.888916015625,420.8889274597168 + AudioFilterStateVariable filter2; //xy=579,486.0000114440918 + AudioFilterStateVariable filter3; //xy=581,549.0000114440918 + AudioFilterStateVariable filter4; //xy=581,614.0000114440918 + AudioMixer4 mixer1; //xy=752,520.0000114440918 + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + // AudioConnection patchCord5; + // AudioConnection patchCord6; + // AudioConnection patchCord7; + // AudioConnection patchCord8; + // AudioConnection patchCord9; + // AudioConnection patchCord10; + // AudioConnection patchCord11; + // AudioConnection patchCord12; + +}; + +REGISTER_PLUGIN(whoKnows); // this is important, so that we can include the plugin in a bank diff --git a/src/noise-plethora/plugins/P_xModRingSqr.hpp b/src/noise-plethora/plugins/P_xModRingSqr.hpp new file mode 100644 index 0000000..843d538 --- /dev/null +++ b/src/noise-plethora/plugins/P_xModRingSqr.hpp @@ -0,0 +1,71 @@ +#pragma once + +#include "NoisePlethoraPlugin.hpp" + +class xModRingSqr : public NoisePlethoraPlugin { + +public: + + xModRingSqr() + // : patchCord1(waveformMod2, 0, multiply1, 1), + // patchCord2(waveformMod2, 0, waveformMod1, 0), + // patchCord3(waveformMod1, 0, multiply1, 0), + // patchCord4(waveformMod1, 0, waveformMod2, 0) + { } + + ~xModRingSqr() override {} + + xModRingSqr(const xModRingSqr&) = delete; + xModRingSqr& operator=(const xModRingSqr&) = delete; + + void init() override { + waveformMod1.begin(0.8, 500, WAVEFORM_SQUARE); + waveformMod2.begin(0.8, 500, WAVEFORM_SQUARE); + + waveformMod1.frequencyModulation(1); + waveformMod2.frequencyModulation(1); + + } + + void process(float k1, float k2) override { + float knob_1 = k1; + float knob_2 = k2; + float pitch1 = pow(knob_1, 2); + float pitch2 = pow(knob_2, 2); + + + waveformMod1.frequency(100 + (pitch1 * 5000)); + waveformMod2.frequency(20 + (pitch2 * 1000)); + + } + + void processGraphAsBlock(TeensyBuffer& blockBuffer) override { + waveformMod2.update(&waveformModOut[0], nullptr, &waveformModOut[1]); + waveformMod1.update(&waveformModOut[1], nullptr, &waveformModOut[0]); + + multiply1.update(&waveformModOut[0], &waveformModOut[1], &multiplyOut); + + blockBuffer.pushBuffer(multiplyOut.data, AUDIO_BLOCK_SAMPLES); + } + + AudioStream& getStream() override { + return multiply1; + } + unsigned char getPort() override { + return 0; + } + +private: + audio_block_t waveformModOut[2] = {}, multiplyOut; + + AudioSynthWaveformModulated waveformMod2; //xy=464,422 + AudioSynthWaveformModulated waveformMod1; //xy=472,319 + AudioEffectMultiply multiply1; //xy=682,361 + // AudioConnection patchCord1; + // AudioConnection patchCord2; + // AudioConnection patchCord3; + // AudioConnection patchCord4; + +}; + +REGISTER_PLUGIN(xModRingSqr); diff --git a/src/noise-plethora/plugins/ProgramSelector.hpp b/src/noise-plethora/plugins/ProgramSelector.hpp new file mode 100644 index 0000000..9765a06 --- /dev/null +++ b/src/noise-plethora/plugins/ProgramSelector.hpp @@ -0,0 +1,123 @@ +#pragma once + +#include "Banks.hpp" + +#define CLAMP(x, a, b) (x) < (a) ? (a) : (x) > (b) ? (b) : (x); + +enum { + PROG_A = 0, + PROG_B +}; + +class Selection { + +public: + + Selection(int numPrograms = programsPerBank) + : value(0) + , min(0) + , max(numPrograms - 1) + {} + + int getValue() { + return value; + } + + int setValue(int val, int numValues = -1) { + if (numValues == -1) { + numValues = max + 1; + } + val = CLAMP(val, min, numValues - 1); + value = val; + return value; + } + + void setMin(int v) { + min = v; + } + + void setMax(int v) { + max = v; + } + +private: + + int value; + int min; + int max; + +}; + +class ProgramSelection { + +public: + + int getBank() { + return bank.getValue(); + } + int getProgram() { + return program.getValue(); + } + int setBank(int b) { + if (getBankForIndex(b).getSize()) { // assumed that only top bank can be empty + return bank.setValue(b); + } + return getBank(); + } + int setProgram(int p) { + return program.setValue(p, getBankForIndex(getBank()).getSize()); + } + + const std::string getCurrentProgramName() { + return getBankForIndex(getBank()).getProgramName(getProgram()); + } + + float getCurrentProgramGain() { + return getBankForIndex(getBank()).getProgramGain(getProgram()); + } + +private: + + Selection bank{numBanks}; + Selection program; + +}; + +class ProgramSelector { + +public: + + ProgramSelector() + : currentProgram(PROG_A) + {} + + ~ProgramSelector() {} + + ProgramSelection& getCurrent() { + return currentProgram == PROG_A ? progA : progB; + } + ProgramSelection& getA() { + return progA; + } + ProgramSelection& getB() { + return progB; + } + + ProgramSelection& getSection(unsigned int program) { + return program ? progB : progA; + } + + unsigned int getMode() { + return currentProgram; + } + void setMode(unsigned int current) { + currentProgram = current ? PROG_B : PROG_A; + } + +private: + + ProgramSelection progA; + ProgramSelection progB; + unsigned int currentProgram; + +}; diff --git a/src/noise-plethora/teensy-audio-device.png b/src/noise-plethora/teensy-audio-device.png new file mode 100644 index 0000000000000000000000000000000000000000..1de2e2d1dcf6c020769df7417243766b493210af GIT binary patch literal 235313 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 literal 0 HcmV?d00001 diff --git a/src/noise-plethora/teensy-gui.png b/src/noise-plethora/teensy-gui.png new file mode 100644 index 0000000000000000000000000000000000000000..3be7dafda831de8e197a37f53f20fcc9c16d6c7c GIT binary patch literal 179074 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

r<5Z$X}O z)WyZc(Tt=^MM1Kh5zDrO)bnuqpR!lBFtd5lRzp<#=a9|N`Z5V2BM+MgZ;`?EjV!DN=~mU{t;2;>fIm!j&Q=jpeqwc52H z$nxpJe$;+zE=W@Atg8oziq|N2zrM9A1k(9kn8Eh;iR~8b=l5n!^~5cZ!v={>>U)vz zYSu>rZCtLg9VZ>SZSi1Lx>AUtiyjnYTb{)nvXHR*8FE0=Zi$6Pl7lZkP2ZbHDYnHI z>^?dpc)~bF;m{;w$DUhUa7Uioax5fM_bI&-)J^yl&o(fNu_vs3vHI}c&rem8vuEOD z^f-?{fviDJL_v#BLe;w4LpGYJ0}Q3|=-O66<|2_mLR6<*LC$ z3sZzzX$l1(G#g;J0#rXnf5rI_M7W=p7vv$llgs-1bS``Th|; zgYkib_q+yW`r;VjCsH{?O>keZ;K&W`F7BVsK;Sw^KUt@^fe9B_Qr99Ba=6O}s-PDT zoBJF0I7<*WM+WSU@F4tW_K9uMe=z<3_N5NNl$xrOOxLR^hVX&8z0T|M9TseB2f}MF zof{b_EO6>$CMUDYiR{+76!#aTbsTb1x|27Z#5tsA!elGw=JulPI`{M2$%;g6z#;pu z2|wDBDz!oTj}{=@XmQT`uNKWM!A}DJ3K`0;X%{v6L;!jW3?!XP)KA(uH!)Un1zA;0 zy8?=Yng^nT;`l3X2QTt$yk-Bx2>D39AMYU?1t9+`LMMN8kc6Co$0{kxEBKQqEDptf z{Vi?0yI9@TDKFzbI=k4g$a?!+++b_BL&jLsh(eQmpTgTnnNjNMZB{W{ei@I`ss#0g zj&Hq@a@c#-#%EfMbn1yIcl94oEvLC#$Qu{^DP-AdBFDKp1uRsCgv42&DX6D(VC~wyHA$`k3}eP2(F)vr+!Hms{0$mZBqrNQjd9z~ zf0t^w;@RAtl4qEK!@kPngM%N8pz!`zSV*$*G7|B?7&DE?Y+7OuVzy*LcJ?|r?#mJC z`3-~Sh~yCLO2~p?Oh<_N3wZ1>7Ur*U0@5@&~u#6(g}9qirh_8+~hPHoNBh>Q@ZqI?woZpKt6axT19i;`bHw z81Sd+>w_1!zc0S>BmU|6mCCg85%=ewe*ZF=YD1vTizeMMDNXz0E^CB~MohL#cNS%O zE;P}s6BN2sW_%@mi`QUt0lAtFEdW9i;c^aa?wGUMVq%-FemrcvziyMXj7$%X&+fN< z`Olwk#4Ygarygx0&YpSlQM~8Jz&wriTW+Pd+*NbB zg!3W)8HW$-jIa(PQXz%`}X35!kgUu$=R=i zqblB6R2s5l>%Y>IW4C8cmQKJi>$F&JWMtIrJVzYU$op81#|mlX>8TG2nE!xj(Fp0A z_#p=>IN|%LJG=rTF-esp-&rWh0I#0Lw3Z=c+k3`U$k@HY#nX}ZO4!!A3sc(90@EEh zrl#~SIyqTRaV+JzXisA`xf>N3>x&qt+NCms(-xG&7@N`In@ zz&#>B6WI-yr$;x#43+id$rH=gO@4|9qD@&W#;lmc^mHLRK6QjEp4}PkQMf(Gq@Ok7 zs+g6;uf6ftR`Mq{uDURivCnj|nA4~6OeOJ<>}Tuz1QBXK-;nAxsQxXrEGx0PvAL58 z%Mp+EOV8m)ayAab8qZCc{VQeWHjqcRciLOLy$;7+U-UXXRnzdXvWxi{>-a-f16wU9+8wd>? zTzaE99Tk-+QLWo8F2t3PvP>Ufz4>XeT{0Yn*#o)}tG}ODD{^-c(E1^I^Dd?MtIt=o z6<%f9_AJxf+)S{019#Y@Y?_L)vj6CUTSLL1g? zYj$mRTy*?M_p)vU`7-A*dXZD+B+<)eY8?so&XV+rjVV4c@7n$MCDW4IUhmtcJ7k0Z ze^MfuR-7Sgrx<8B9EBBl4ZHQ^Wizhq5brglA7NLb6)p{9i68e#8XB@eQk8@-Dhe%q zdh^_1;aWiVsAb@U_q(gAr{^B3qd<*PgJ9i-!(1=!a|@e(RVgqZ$)VRc|7`>DTNf{G z;bi>hd$ao~nn^|yQ{q%kG+gjMctGTu_ghJvHiTg5)UW9_G0o)c52aKtQoDBfVaYmn z%6`<~Ux$zzgRix9J6QYxi7kV?RX<%uM6k1He9dUCe3{U|Y)*Gu9o*l?j^94;L&VJO z@+n7G#Q9D2MZTy*)Z8)4d)72fUh^xFW@)fFYu_U26>SHw*0;@t}vRqnU-!OaUMkSFPOopLBy6Y_e6 zPleW3Q?D2VN+aCesZ+K+Lx0#H+t4}@NFs>dn^93wPM%g5R+F;MaF*}4s95aW;cUiY z)W`SuFv|tA#RFeEvmJC=b4+4ta;Cb-o-5a|Mi9 zbiLzWP3a?{CqkK^`~3T6RH7`m&7B3WW=+$RV)VK?L_^9Zk*AB1md0i9EML!d&ti1iAXM+9Leu~0XheF7F3Zmmvw=;H9DVO zn;v|vd<$|!ERJjLxrB^_F9VXl+)9d8@^9s2#O5Oo7EIBo|G^1@>+xgJg3i%L`Bmx| zAVe|S4+<)p`B(K~5A{`idD)JZ60CWo5+Eo<#*#DRIAsfE3>PlPp&Jk+u$&MW$Ips%~z%wrck?9RrG>z9Y0_ z!4F^T1Gqx5eysvgy=Qhpuk+ysR*bA8%C>?s~oL zaeek=m#Z<~}d2ha!Na!>BQbj2vsBTw7%Gh>m9 zL|(s4l4d+rb7x-tBdTW9(^I9FZenlnd=$KCCLV#TC0})Owh*#4lKl7YU~QsirCt}h z#Mx3lHdCVH-s}UyH^Q=V3W9fLeTj1ruI}4^IKXTuv8L?a_kJhK&$n}AQv>A9H$6UB z+%|7*T+v+ZUeNlU=E}s0W5QFoVhLUh`T!KJJ?EdnfP`1!u$dStoxO}dL-|Oz9o(k0B?uq(Y%tH= zh*K&-+cRu7ZkYUQsWjPyXw=ZqJ?DPDWiBweoq0v$*UWt*2iMr5rp0<6Py_RO9PI2` z9F7o0vL1aDc~B@sQ5VHO4g~*%FX<7LBfP56cLgu$yOM;X%kGVAdWAh3+x8b3_|z%0 z^TnL4723G-U7ybecxd3c+Yjb;MR#ty&Lw}_a^m!*MO)b+k@pOCg{N~3B_t%YKCGOl zt!rrLLsR|}4#w6%HFHd37zmcX-j5qVJd%WwGjCjFYKfYSk<^pK_NL*?@wnD7JG0)0 z4atrSQ&aCfeGabSWL$}MLhAM^f81}P;pta{2mmp`f;LMKv(ccbJrfnieh-+8jdvUsY>O7|p)8@v$CReY)Ql_~h@4c+uj;Z+*f$r({ z#bF$g(i%d4B`Qd1G>gm0`PSEKB1qfvkQN~jlJi`cGgu^FLG~`v%5l(sTbRF6bY+?m zbTB|I!kqcow6tV!;4ElxjL z^3fd+OUFeO1`w*R8oWT>gAY$f0b20k83Af@KE1TOuc9r(yoO&~rn4w6M?RE;`H*C% z{v$4%=Pul+Y2Q(+W2JNMaplB2c%!-SY^vp3nOoC*Aie8RM5$wm40B7hb~QDaFk3zK z70Ie}KIYfl^*)+Vk!3TXT2t*FD_giO=bmO*+DRy=*tAf9QA!GOpq%<++~{7;>s*WE6mOcaMq#s<@o3-XgK&^XJdkjBR(~#N*$-eHrp$xSZcnXg9Mt%cc{6st)90-wh9NZpP~vu`A}-F!><4kQ-ZaGUZ*@`*f9z%D4eM?3rDn z_|usw-qf6Vpgx2*@` zk3KH-pp2y{DN!JL5aOx+iu}$T@zRHn}P z=^yMQ+3bIZ1WdJ$()ZP5e^tc7#D-fhbK3n{NK)(6txcmjs?eF)-i&XdYJT-# zB_XvtWsv8kTBHRjb#eSTLb~r+2L?S5TrJQIk1_}zf{JJo>gu0e82EH#dyCB4>cM88J-=^Umg0W!NlBb$@e`{1-r%M9p2if zC7TIRtObjeq;=Fwk?$#=9<7hS)Puqy3TCF2Wv66DRdUuxW)ItkZ<}h`X!)~tA3m#k z>F3+U-f!{S7O zUp9@@)-C!Be(hWzJl9^C{;FPhVn{8ya`;H+dj~16LHuPO3a#Q6vK=hV1f7rWcKKfW zOAXZ}G%7$eX?`-0@}ZUnvWBWIW}l~rx<|bm4LO%T#eMaK+FFU9{fCY_M87Uu^31dc z9nfOsRR$y;TyLzcrx!%(ouDV_sx2|p_w4k{{FVAv(enI!Qm#j8qb0wC#IE7-A`=dT zb2GZRB~6EKJgC&$kHaV@f2tSv5;lzB;9hd&>|=5LFViA<)mLV|*lE8#ZYx<8`Of#= zZge}?61H8+fd#RZdK&4S`Xq80Z(h54hxwBZ>gHb)10d@~h{l_OW4 z&t@fl-#2O3PoM|Q$!Sv}{VZd%`=%GdOIXy-25qOhy=r%Adux(rDh;{vL*7T;*ui_& zB`?b+G4~=qFONMVBjYlfNgzk!^76O5y}haCZe}=mcyM9RL-c|RIKo@tYZFpaS0hLn zgPdNV>;eb1(@hf+il)V4CI$w(pO1t?Ugz}eV137P%+T2DlIT4h?8)D&wBoOcUr$Ud zScD=k)2<8U`F*JvJyYuH$hn!-^WyAX**(8Le~rhZ6ceBg~k_Y?eWirKDMZV|l7Wdm9F4x;#LG-9y?+fj9+tbP}_P^Qi z?%lfwB_+g{`119uBJ_kaGc#{7gAmb})X-ib;gsg5$j2CZ%K5-k@4%8C%`&FqHj3q`s%2&IHZe0W>i!$f2%_60 zF2s0cH|{J3Qwb^^a$AkacZhPEPGg=9s1CyBw1NtFh2UEU<(@N9H=zMyP)Wi;M1(|u zp`$5&eD^N%eD}O^fB!AhZwsAYZ+a#dU)YLE=o4o+M+Ds-N{=!rBLT$p)ze1^f8@~- z=eR+(CNQFB5MY&$O|KUg_pUez&>a{Co|fg*r$`--Q`v2ATUu!H+i#tdD;lg0eZ92Y zlWcK9A3U?+LbIX1!xjgAalaO&)a9RWcg^g)?3YhbFZZS{;WsnYl2z=?Cs9m?|JXGy zPkdcme89Pa&|}YEu?#uYBG=s9nVI>JrFCnsw)vc3OPPhkvy~y%eO9wLMv0f#bB^^3 zv#D`KMFj?Jym_uguwf7#ITh37jJzofQVvXW7_$E=EO?>rz ze}DDs2XN6nL{7dm17vIXg_5=X^XsQE(`7JlfuTWHhw(95rVdKiL%po`9640sBz?>- zB{Tm8T={s?{t0JouB;AOS|e%(@zkiJUzN}VGNF!cI!)dD)#6ytZa*t(zfg_T^ib5a zj<|>9)kc;oqchK4_VtBbip*%h(Wx^^Gm=@1DA>q>_v!+zVB60SsfP5Up~}1?;*8 zxFE#*=PUb)jB9TLD~^(-+-xnzV_AFalu*Oq1RcbaV?#uD4j3!q+$`|dTRI()=Vp6` zHod$bb_IV3!CU+ewf8|wjvh(@8E>|tIqqpUyKT0Y-^A3dV^ukg0@W>qb;|Z;5^%uP zs2!?GNXtxL1p9j6#=t0)0@o=)F6a3*Ooa>Hp7TRBBGMA#?k!8#yy?0_z0cH90EAhl zq|xc=h2*``(UZya65wPco;DDL=iCZ_jtnQapN+}1kl#D(14;|}4~6sS1q z(H$@3dRFXNU+L5MHNOg2QRbk_cbh|wuRot>`^j87HQMnk+veEJXyF*J-*j_R9(3t` ze*wkZG;`(Yv7w&1);+Xj$)(7znJ5l8m06Wk1F$Cs5#cjA5e{vb2{l|TgyRK|#wAFd zf@8%kJO6*fvBEUWX2b>YkzVw^kbI#oWF5j9+iO~H5;c=zKSbzNzQ^>GAE%!@l8~CU z0T1a6X2)Ur4zH?Um)HRUy3W`bj!{N`O}PfR`|ZYxn0nur88fyaqUJ2+-uz-~4j5+U z{UwjmeSOX@JfhZ7VblMCOZM{Bi5-eE5}kp}&EsW@EP-Sol<%o);8I^NP|GiVi$OhN zCdJ%C`MTB4h@I$_<~xIk9Grce$rMFV|~`Ppu9}?^q+ToyxWMNde{d@!{*rNfN(d$#9JB^F3)Uh2*)taq2Ix$bI+2o-dhYM1K(@v`q7Wx$-4c9x zoe9vv+9GW_QWnQrIz@@aUD}h|uf=ryj%eS6@RqX4qJilcYMqOGjCI`g)>F`1{5sN% zR0tA3)YcCO5Kwm4u1E<{8ENUWZ89)OqHOO&oOv|{rGEnxO+@FB$+Sd>%E#OjC2o;k ze%ISnDfjiva}H^ZLpBy_ouZld(4`3b^c^iSuG0PEQ@y*2wE4E_1x8Z9n%aoC)%|m{ zpd(#^E_aQbe@39LdqQ5{V?PHF*arp1HTQ-iaSHLt$t!n8+qGo;dXFyo_L7+vn+S}V zFA1yDnh!kq+PLZ2`8$@s(&)!W z=N{nWzn>Z2RXmvftKyFPnxEo4P?qW6N9i>)F&Y^eX})i6q6WAzy_|jip3H75ECML! zD=)}F zH!{62&myiTn_M0iKi1ivI0IswZGbF$0H4@2*u-1#KlLJ5Y1c}EK(YCIQ8Wx(haE^Q z36K%UXhrbr4^+s;RD_`c=M09Ko;Y!Tp>l`g(9qD^rnA-UtrZaq1qGm^ON*|ZkuK?< zzE$m&t#2M4tXj}jL^K%ygA-lI%n6Cx$paQ;>?Kl zK&I!fXb-5bYP-dyvhF!YW0uqWPCz{MvE?$E)A-X(x98^1G{&(yI8#oUGlhs=dCnEN z^9p-&WyH0hU9o^3bW5aUxNa2xdb|*G1!1utm}ZMG=Czi?;r#KWq#blz@~$`Vp^H?K zupE1dE(vP-@dnR@kpEbQIAf7Rg*byPYk`v0aKJi^X_G2j*1i%TG9wTdP&Rnc+`?i7 z?g48lNlB{YX1|*^X^Y(Di=a`vwSs?{@8e45I|kyj0{f19jgi0ZdW?lzonAdV#FVPZ z#!Iy_mE<+JxZrd|dsPkV%|PW-P1Tk2@}9e&^iQAqUC}lHOHW-%2Hha{k*oK8bTQawg7Xpym4A)BZIPL{Z(3Sf&f5uKX$;*e(i^KN1Ro>_=@CRZj`#8x^ptQ} zs|ToTf(SHmaXu$657VtJ=`{!k0pek3K~#pkzR_OVanejM`(L||?|$|}>!^~=Cgv8H z`89*DOQmz-L}!{%xFli?($kHmSL^TeLPYr?oeQQ__X^k$uva;{II*~W{`gtjaO>IK zfB&c5-MtNE6hRM`|7P{i*+@VrP51} zpxPMgVz&z2_OI85K(xtFb+7%)o(flh_i{5{v7I9JMNF-x7bd;g?GW{oh$P|N0cKlX zc3v(vT#xk3{%-i-k6v5-0L9^|_?By-s|@LXGY4GAdd?36C_|(g0O>+%5&ZB1g?j3U z`>1Hkwrb`%YHHg3+_VsV_sT4bli`1~08CsK#`E`fBeRMi`m+t$LNnlB#xNPDzNQh= zQC1OA32`>((L84yQt?SiNoGM(1kQO&lJ_O_$>?fOVjy7*YZfHI!T38RQK_87DWq~Z zpntA%)OHOi{eJo6=Z)>+d;T=^h`^v{V6db=2*ZS}#|fa9p+W}l8PqYE_a#_Nn9TCO zY@c~**;Q7yj2J$PxnIV`u53U0ubf*LKA}aJXL<&nkMIMEj#Y4fZW$y?e4-W(?LGwW zLmh{*D?Q?1{962?)~RvR@KQb7mjBV+FFT4OVo7r2n-_vMFlWcRj~}1+x4NP2?Mq9p zL6-1H81W7?ouI64-+MET`_i`Q%Y-)l7Ed)Q z=jP`p(d0_U5rwQa^evaVAJ?Lekfz?9srg1?;(i>wB|mUG8#RSF+uC{N>%aX2$~2L!H-Zu6 zQgHJHeUMN(_*$S7_f+K)HT1yRFpK-63)?N_ab&uYs}kz#>vP&&_r~h=X(NM#`LTj5 zJ}taX2qRMR3#yENJ9yHp5Z1wSLY`Q8T7%-y_2Jjy z;Ct*uDE-f(gdM<-cEy$7OM8oEnfjpDj{aw^slvY{`O&GV0`j7rPh?L1?Cc;Xyj95$ z3`&%wUbnrEbZg~Fhm!Pt-J&fc&+r*uvZ-Dg?NBYWBd>LW`W;j0*7wv9tgWwF(AKGr zq)I75D<@nFg#cV+YrRtAdt48g@Oo2eDTbNf8NkmpCdc>ertCC3AzAy5{g^HdULkL= z;L}2d&#%ZWr^!?Vbq*HhT9vu?Ym0+GowK-Sj?exaKlRe=B7P|1njW@eEuStrVP$1? z_i-%cc~26pjkyKj*CR27ym@cd-4%%QLgZF_xlP55_PFWwhohcTX`CqU_`eFC^bn|t zYUvO@5toyEg8&`PJHC`A9)-Ze#0MI18FQEsBx~;ucs(}V_q8p1L!uUDE`1ys9vW)0 zpT^XtZJdnjdxn-CM#urhhwnm3C=vbuO+bgs`^FK@Uqnj=&Hk>{2uMr)Y``{aj}1+n z24bPLP)iWV6GQ@kYq0dBq@-NUhOR8AXlm_9QF>DFB=DK_Eib?9A^IOj!a8=kK*6wH z)c6%gIJC3j&a-I9EQ?0K-1wiHA_x}6q}n?Ld?>hB+I##OT#8NHy&+Bc2g-=x(3_a) zJu})IF7P8j8f#4=tyi;F9)1-<2Ees6XG1p)nc#4m+#+NtU(`64%fw6&ar@u7nBnX) z$nvCl|Jk|FvHwkEV0j9l=*BbBBesT6SlM4eGIC|#IM3XQKOY8J2)+PTKnd*dr=q~B zlOq!l3cctNC$P7ycZst-*+nY+nu86MDgL8A4a9FHCT<(H6QUd+DY_t3mhb1~too|E z>=XbIxyWQ)s*vVEMeKu@1s8vOJr3sfhYZf`p9qR-w(o9lH@Xpbm9j)~Hn23DKz@&_ z1@7Ls$^xi_zi*6KwqJ`CLKF_9ipX)>6QTw$+kFnki!2BbKipR>?!a01?W(~gB6uBYf$CA@&+eEG zhv5=C{I5Znf@h93(P)-CD0Wt^-C^U#$BE@Ohun+VAo&K|b(Gaor(HkdcflC-bT#Qz zg@W760|KI$BhB0h*Pood^|(@8Hp9*}9kG_*xyEDWP`*Ksj(KY}1yll#pPOK)Nt?#) zbLWQ)c5&Nt?rW6i5{OwN2bZ>vo*ra6tl_LmudkS~;H5yog;U-vTSDA!I;-t0{;F&3 zBlWIEMT-1O*JUXAELF3Q)`r-&E$jztK^v$>ADe7g)Y{Iq@}S`g9d12ZvS$P6G!VTI zrrkhAKd959RLU>m!!$1jt|MYRs%na?xwCZ`40$y z%IUsN2%opj%T!6O{A*Xs{R*sGmeXVH6?0SwIB378L0=-8mH=J$+q6nZHOF_EV z875OR#ObX4y?`v&MJPPC+)<)bX}-y5d~?9do=Aq?iZegbBWfhXp-&;CHA@t%_weV- zjhWWYl8;m}Nr=JBAV$UFi&Wz)sDkq@jGyKH5?ATeUdJ%cWF}@(v>)i$x5R}2*t^ki zm0L(=YzVE)$9HWmzW?A$9CJtayFEKc~< zDR<2H!nKa!XD?Bg?_>?tjNR*ZVW7STQ;j#xa9tY1DE0_c+^D(VK)j|+4kh{BMVYI% zlu8nsc5o$bct$0|%Ae<)(<89ZpiaGp_x9?6%Hpvjm-Yz;vROA0KtE)ecUj$8w$&1R zN1jJJQYKr5RlrA{%E(CHoT^Sr3gx_rE-w@*<)mkJWIv zf)EI1kFT6&$=?GGv*h`!-=d1r1xTF0c|!%OUK$GyDG`iO&MfP6p`qDs=gG@WrI}}w z2lcZ{WTqg*83&*n2wfID%<(GZ+

  • zF@Y|9c&<``{LU>j(p5zSeaBg_~lDkQ&ZE; z(lPM1O{2(_l1`5ECU(M^JyO_=B#IO)!vZG-+JazSWJ&zt@btc5Rvxzf8;^Q>Hl3Z& zRh~&bOt-`QvxW`luZH49ZzwByy#=y5jlkZ!raZe?p3_gqm6g%)t!(ePCw}68F z3*z37?XD*u7kd-3;h3Sp(biJsj?-WV?Is9zgd9EH2oWo`$Ew7}h{*}xIKFX1B{Q|T zf@6G6OY*iOr437RVioNhcxqd~HAw8)psb|i8n`Zh7eNL0SLXU>8rdq`vUL@A1uT~4 zDBuW7FWRmc&4IL_WIP;#^T+&apahvF#V-KZylrYCdUrxmp(COC2HEC5d3kw{8g2wb z23vwDOSzUt3q*;*9J&qgF78`ABuHef3-^|GXL@RCAz4IlDH&cj4Pn|!2ED6N)H%3` zaSvznU!|v{5GvHEecTEc6`6Q=ZlcafOh`Cr>O{;GhUUcBRP`Rm1;w+D#hgdzG|dUR z-c$(Ux3q1{S1YG$bCgUVj|x0#1(KhbbI>G{^!TCLUT%RYTb;y+V~)8Wf4ISATiJ4q zCx(clhEU@DEfV#7h${w{_1E2`(z!4Z&UOUZpVh@zrqRt2Z6at3fxe*!ZnrUZ7cGaLYFR zb$lYu;f2o zxBSy!Vm_fED0wje0f2Q+6?P$^+yUi|H?wyzF!9~2$Ame3cF5oWi=W7del#@Mr|C(l z%+?uOc=NuuAC^{Qu!v?L4J*kdHXb|gl?oUa_Htrai#W%d;W2HpZT~NIN+s}2!gnI9 zawpEd>333*EZhFYtm=Jcp?sbJZoiam`a6>zzhnkM{^J5vR^>@+_#rY96Uc)YDOmrY z-^loTLy3FVYBJ({vF*BoUW0{WC5PuUBpqEZ`wQFfbJ%k7mo`MEw)^dZwZT6YthGm2&fCs7Kj^tLa(^%$`?Xp;XGMT zB69yjy=LXZ)ldp{19T|{X_z#?cFF>Fiu%9TBYv8kHd6H}1c{*tw{1F}7`(Q{@n zS)`PavJ}ssI;tl#@|BPIKB^d&cqlOcbui^(VmE-Z2_M-aVq*6o4o+gc2cekB+{uz2 zR9RiMOD+ArDX&88MkB=sEZy6h2ehg0_#W%+OZBqOjez09yi7pZ%y8rp-}r^3*wvv8 zWf!69gwUC|H~{!nz#@TZO-)VOULNbtL)Ra|9)Th+fHF%>QIW4JSyoQ`IM7~J;KZR)srg+quboi^X6|;mk236l_y*Ztw>QhjI_7ErPi-Ya1}A zqu519?s_LGB4S6!^^#@4MVqOb-@Vh#B0}NOSAN<6piGWvLJm=iXq>w$J5+<|*ohkY zPr24Mxn4YGWEZ$Lgd$*I?yk*cw!a0v)`Az!=xDY@+^4f(Bi@CaX*WGn{poqmc|v06 zRykk_JpQt#El}1*A%m24_r5V5c z!$&{*PxVT-0R!&jiY^>*<3#zKHx44ScV_A(gS^V6-S_#{p9YxG)Z0YF@cdp~mgNA* zo9Or*`5{_R1Y###3;vU!K*L;qF=C2SnSFkRd1^J-*>h72r(TSR%>;;OI$FIL@qsIY zFdCSr`gGcZ_Bp<<p7txE>{jV*zdf`ME_^d)$NhJbb^=|FH}3Ijs$w)cCUa07lK|yDSB!_WhzK^_&9@ zuoLD>vcPUek)NT_j(k4^J-MjP_KS_L)*+>l#|fy zAic4AF7PJPwzm7=VRGc*)(WrHt5osyfLlpOM7-E_D(wR?r4NNLJ3S9?lD*G%eIe_p zoBOxinQXvkfZYkr1fIrcdC@xe8ObUSua~dg!K!yyKf`Dx>1Tvf+Pqx@f8H9%jAJyz%8tSx-|!!HtVRT0=cR9i1Jf zBUKSYX>cPyHN#9H9!WouaTa23l4?59tl0jxHqo8$|Cg`n;s5kC>0!YTfa|`PW@0|| z_c*{sV6d&dtfj1IDF~p}Y1+)zfXY{_^t2&77)z?*PcWI8kOE#7s9ckHbc_Gz!<_!% zXc#Oj`}o?cm*yIVCIFR^7oU<}+%`~_lT&c*SEN~e7Dgt!Sv~R8_Nc^~Vm-9q3k$b_T}3&A9)QK;7#vc?V`ZY0cEzjN|6F;bZ;VhNhC zUJ%!HVdhrmC2Uy}MbonLyDkwsHgmrwiC@RiY$GS9@DF0ND7G)dp`mB$sqLSU&f-Jt zAORYRBcwtsgLS@YmftT<6z;{q>H1#CP~FJZ6`lA`e`| zx`t*D#QyzmPC{qmcUQova4&OIr5f1{fKyP}r~7{U$3+iKW$q~}MAhh#l71(ObSfrlA$|iG zxuNG~huN3kS^N>rn;mj8kiNd>`3QNzxSc?mPsU}F2E;mxujKz(?G)3GFNufOZ{!<( z?wm(yiMPpPA!2AJ4&blOdjN?}u9xuBF);86JH4l?gzM#Gb(NFp+Fzg96cfjtJU@KX zrf=%_9#(3$2h{AjAN1_=-lul`o&qh4pygoR9*_)>g2n^C-#;*)Y@~20YR|dFu2XwG zesTf`cT~H$dvu?2b4J+1R&z$5#7_+-R98_EVr6-GdHwTv9>zlGh0%6*ERXN=6fm{= z{~=dn^2=BQUNS?OFl{}2?N!~)La@reSt`Y7mj8*|BIZb>Z&CQAKwXw$hUGf5A`=Hg zW3Y%XFnl+Q5^?LB@`!_|S%ku%zu*z(dzoZRXeoS}2j6gnX;%+kOh{^r%|~Zddsoh) z;e7_|UKG(GPtA6XW@LX5o=nKV*yTy*)GmQ+9>>2I7>k~X(*Nq?+=Y=94{6B5t(og* zpAt8uZ_RD+8Ri+UcvZDOI=cX{27;kyAZls&8U~#3R&1{20r5NflX+-@wpx`GFM}Vf zA<{wYOC0esRO1TU&dCni3V~IX6K+i_~n}5w}%}t4Us?(ADgklvVSkfav z*=#taJv4u>{Wq(m#Xo+TbG?`eX$=W2#os^10-eucC?SQg$F45$BVPgG3Q1fM{uqUQ zHafp+M6xOo*HPCz>z)-9Z4pp;{f!$pss*TnW32>F4!I1a>bHEoMPJbG6>nax`rZ)L zvq1)oLJ@i2>B%h+JhCaHb4b_7I<$6)g<-Z!0&h#MN&?5l`sc-l9iY%>09Gjw;`{}o zbbkl}jk0jQhtb?UYas5o&%v2S=h@QeWjiY%sGw7qSdN(s+ZeaEXSI)9o|zPYGlnqF z%)hN~gGfX2u?gkO{9W>h5G{f)$(&HHATy(KKv%C$K)j`;<)np$#UV#)C=+nIfl$gi z!x_Jy^+H^psPEYy^yDc#?dj}~bgAbzj9-)6^fyQr8p?)&;4gq2gIR~fxW+)D>h`vn zIZfEWpc(L=Ki8duKsKTm6%jpA?3(+5m=A-C{5>vmM9670uch-QY71vTzG4FVaW~?e zK_id3*#JM)v*jJY$gy6R&UZ==*I#phSX9CK+vvz^pgC`RVlecjU`` zLO7(U3Hb`tHp+3E^7uhsUS+J#G}=8qrf_rKdCzXn(%#pJ>o3m~1nDGP$j@EZY9||V zuo;Jp|NNcqdjOeF8y90+>VG8?r%^%M;?`UfR86fK3_&|SE`9~q6I4HHM^RLI7TkL$;$7%r426pvO^)dUUx&-hP8Og&XoR;F+B$uk=}V&t3PtPmm+1|AJ$L(d zn`oFdWw6aZ+q!*v&{Li^;B&(W`*wbQ|M@2kHHcG{dYMEflg)`4zQjE&1DdJx|=YOB-lJ<>9|Lag^b+O_(T2y<~T}XAE$((jXucMjuR@yPr!!Kfg$^Fq0 zZHMakU0+l2`;{1Z%-t!e5U2)DAy7&|c<}CPo7}KBk))825V&WtX$UT#a&!_QX1*z3 zlkS)Ez6kzlMM&6KAey1b6JHC6C$W@2SUZt>uYK9FjT)+o2Xw{mf!0}OX1R;8R5zwY zJ!WpH`?6afMeYH0HWPOF*^PKGEadI;1fh|Mt~5HLbz)fu3rv0@ksZ( zYcW2jf5H|Hdh?SfmxDaYZj1BN8~U2yjsz3{RVC#_YQMQvLewu5-auHsz(`;Q2pm)@ zDR8yI4N05Mu+HAI%XACPyw-|&tv5&57KwTZ%m83|ia`30&l{nC2+3@T$**3A$w_=S zuWqcjUi#){ix0UXC_7x}&gpaK)+TG-ui*%{L>m|DiuMg{QU*7G?(Vq!%cX{f^}m^s!HHa2G88?~iU*#g7|yQz z5bhrs2yl;F`tr9y!z@MPq0rSAhG-dd5>8gVmLggrp$7ifJtEWM5^4QYG)*1JVme>f z+r)HOnd?@e&q5d&8q0rvIvWph;RxRh8$YRg8fLq?R(4|RfO$tAY_^RtG1dZdf-JF6 z;(ebnl7ti+LiClq;71+VP-V9?5MUw{qW^A{j(1^d_9T9!(sYFt(LFUb-kmBLS~A@F z|G!ue8wv{&o5?3GA|{rI*=D%ejAexH?{#58#0j)3N`;!lv6V1V|G;`9dI`DfFvsq1 zmc}flf``_ICeTM>MHF^2LIFf{kS(&tccdcal4RD|?}KKVAd4VS#wm>cV`jW+NsGKA zx@_{K?oF$mzVL5{u^Tk;v)>w?-V{U)w@7M`Aa!$TG7MZmF2ID~7Xl<4C=5d&;S(6? zxCN+R%A;hk-<>eiErAE$VB-hg^>l`-uYzU9^x62NBlqsHeebE8o0E^g0ZM3dEv+`e zEBzOYZdFhVwbBzeucEs88cMRydg63rwmeO#&EakwidTJfnkAn(zxEOW82V5`pfknm zgv>pm+@{&I<6K_%|MWWloMB2~{d1+og7;C$r?1NQJ$Cj~L#TP9+}`Z+M+Oq1wgfgW z7pS}q84U2aMLRtd&^2Zm-|>gAAkqhjV29)*dc&SwU#2g2wFkKdICT#60}BI9LgNx+ z8+8->Ne_lY5F}nJgE}r=nnHHsb@9~P-U`Tt{OZ&6Y&`BmO8<}f95*p^z`$Vr*_{Zs zRQMbBIPMS-{%WaaOK8%0g%T47#GvXv>ShZLf`UNZ72vVi9G{e8KGX_DRwc!qbC*4& zWS15VVikZkF;pd;jf)%D_7yYD2>T%vaEP@1`22u?Ba(Tp9_9_6kio=STp=DD1TFvL z5^N(NTQRvqg?w-&f5JgC$}y#_`vv87)z&NP#TAOiDQ+hsWMC}TJtFd$nvqM$MhyZa zUKxVL0BGsLnc;q59dF7TAVvLZd#cVr+e zyI;SIKfDZ%YE5Dm72yq>k5kYiR+l5_0~o3J?M`m@=y%Z69n9ai#2)C3PSlPV%wFOH zLKs}x8fEK{@oQQV7nD#qe3q1aCdf)QSb;2nw^cl{q zQ$TrD+iUDB-cl1O4RK2phfj&+{bxVIxNH;y2@@ao$^9Slm#|y#$Ai;G$DdKdb<;ei zZVXV+k2$3{!=ThN%Z`EtQidE8G{Q-h6=Xcm3gatl0BXa8%8m7x`1HI=Q^OXIQ6Skv z?H~O@)%>*5u`~&e4|ErkGQ4B}eL-|(4YFy^XTojxFt;~20@~^mrSp}QicP1^AOacP z8j1h52Yvr|zCUs9`F?+mRIL)e*n}N3&X;kqA{2T> zN@XYkHvYE6vBKs@$wUx6>2}?UfafJMQkZ-AB<@5kk&|@+5|c2Kp5$+K_xr$8!tXeB zBE6?f$ng+hP%7`%1sKmu^NHKpCASGy@B4v!$~^$#qVq{EA0 zAJ!Y8E2IP>TrD}l)$otw^h`Q*j~i9Q*OvP*JTm`CLRv_TrsAEp*W!f0mQ4Yhs_BI~ z_)i=bgfY>BJ2i{XDY^)sW4m3kftJ=?=a<^OzO#_#`Y{VQv0OjeyMeUHPdU=O@ies# zIXkR!WL-nV%tq>FB&RfXbkIZ5JUBQ=HTQ#ZbTsOVgVW9lRl|OPSj>~!q*)q-1Z5h? zAF|1x5dYd+Ui$jQQGVI{wAW%eL8j?x_}x{G@#L)+Cg60BeSTRHwObc3X*aHNjjQ+$Wf8bXVqkK<6=ml_qTD zEV_D@|9JS%2<5+uj(#t`(>Oxp`)?;BB6vVH{;LkBa<5O1 z(;ma-!(O%A9PzZ1$040sXGs5QYWFrrwpL_}0i90(Q-sxq5E0Gfb=>Pp^3i!NADH;Q=YXcF-OIznLsd&K7viGV3|gY3iVJDYn{iU-BEhg0uPC)=EVs zKM~UFcwnMuIMQjKTikB4CAaC=LXe@e(wn1(#%mgPDs5iluU&ccA@54VaDV9!1B+Q9 zA8wB{nCK3?$?Chhd5;rkm)PKyMmdGmEzin|rsVh0nAkoVNlK(8n zLRNe3;$JU~8aHT+|0T(JG@kN9xkm#r-$^2m`4qJA6c9u8v>qaMrfPrw$f z^p=DR;mUTB-hIy>U)!=p{AADCh-J&lcxL3Onl-Z%M+VA|Ia)`RvD$Z39;$iCl>5bY zd<%;L-B|a+)HQpP(!}W2u`l-n#%x@Ey?OP4ML8lViEn`-N;B9mz%1uy5ux5vpH$ORSBtsVPWA7iqRSqbfocaFvP>2fTZ!49ouBY zG`dMk+!e8QLVZoRBofCm_0y{_R8ZrCACvR@b~Z`tu0RKB4L+{BK1zo$PHI`emjY^? zQn9xF+p&*>@{6T4%;;ooZ#K}nA~Tk;Q=iV%$V4HLc#OG)M-nxXGKRXmhUxcliE%~t zdJSPpWRvIItS95#8!fLv%hKxq)7G_sGrjk5MRcK5$m@R4NMen$L{29qj9llEX*w>s zw z6{7-gu2BNA(NxXhiE15XqN?_?$qjnM8zY3zVCK09L|Y0BNELE6ZBZm;9lH#c19E8@>DDRDL5p}3{&f2WFjwh@qNm{K3GkiNP%$Wwq(J+SWsp>p2t^{te z@A~TJ2`5_zR}`vma4@5=Pm9nba01k>VbN&Y>Bq|udm~tE>AI3Uq8Mp;$K$!1PLYi! z;#;fe1jg!#jSa;u%|q6&!qtpgnqgOY&mmiYjGP6?1l` z3HeyrpxGocj`lU8bI+crM7|ESqT*OfjWXa!Q$6pT7WOGCZ+Ud#b0&hsZmXP47b8d2 z>$U_tXr-oDYJb7Z;4OmI7nRZ=e`dM9KQoge{sL*sX|NoGG7(CMd;>Pi~_!3XwGj9 z`&eVftY$ZU3bW_GELfFEfy@Qmr7my12sd{ln1I`fE*P}J^+>A4K`)rg5Ot}zFmvvs ziStnn|H90Yt0Sw(bObWb&i8Z6I4Fg{92sHg={c@+c(GcL?p~txy1=(WLI_pc(tgLH zK2H~<6!DIl{Wk>JMGVpi1@^%NjyHFX_WWHw;ytX~OPtEDo)TySW|{x%&e3k;a~r$p zN?@RsGVbd`aGusrroFCVbjKGrJM{kq&7O1NEx1cG<#z)c4XweX!CUhOnd8K_8naUh!#ZS$+Q9xzdA*Mx)4BaP~o?E)X{1tMxfanYPM z2M^78*Rn1}-W!j-MB*7XqaOFf6IPI#nu;Ca3pA4XS@oj@h+tr@%0OlK^)@bV(hb7U z_mLy+jEz~KG`z~9^v+lNg`?`0z4*%Sfnt8)?d+XeQakq#{R*Dz5qfzqM&;gC#%n@b z5pVF_d%fssE6uHpscbQBjw#a;Oru_;^0oj@+Ba{rv9_i=t5Ok+6fc($l)lu%HX6d}f9~NfkL?a=|ajN#q zt+n)$k)8uNrTmi6#b&4KYZcFQPhINkui{K+mQsI}!CZCIoe5!$PICI&Jnd2~yoRfc zfZc9xOWIzQG`&MY@OS9*+9^-;7&P-NcTI(6MzOZzpk|=`{ z1i`1Uvikbcp&=BOlnz5L$L&It4A@4N=JTwh(Ghjg{H(dCOZZ4wB~hmqXPX)nMO?;# zlew#_YY(NI&F1?Ed?xgb5AGm=r;Nz-Q)>u{+uZeClATkT;1|{6l9FlA2PlgI@~qIO z^ZQt%^9{4=^hGHVJV>XUwQhdYA3f06BJ-rkG6F<{**>(yOF?Kf_V_2M8bQTvK zjiN^n;=C~Pf8oMvcustei;>1I%xsEi5@9jN542SNOvA8d<4ePw1!-cFehX1=_+5&C zV4XmGX_acu^A%3^kZor#7CLARe)#YXG?&5;eE49KXJ>mVryq<+^^qY)3{f+poS1ZQ z55iCo7z&^TRxK*qZ=!aD4DUACMLCwIR_ug z@`RmW(A3S>)^L;w{==>I-~1b2O@16$6jQZ&(=8=RVsXXmqnvFFwV`!?`6NVeJP4C& zP(ga#Bw42heXBaqusRb_4!<>}E+VMA-tV%3yg7J%1^;t_QWAIbS=x$Q?u_}l%iA8j0IVQ%lm|u@(o(GRD?oE(q#KAd z8^dgpFM1;^vf~I!6Cp1z5BPw+ zvdZVLc5b!zFV*mmT$s%Z2AvcpZ|i9dW}S@W)BHWgcK9r7=L072emOpAeozD=fFqkU zdcJoi>_j5)ic6Ywf^SCmiY1kEL7Es*M-p$edFAY2n4K7N`bN*xYh;Pc5|0;Vyza|Q z?f&D~Nk7ig>yfEFh*B;+hdIPK{2Q08bY8F%1PN}F9vl_`ZL<+9$zUNE>*2OD20cyF z*A^FLnBHAQUbL=L>;I@sd_NZyTQKtI?`si-K^6aJ4Udco+KR=O)-iaZLd(DI0W6>O z1_X^huVgc;zpDFM_S27{8-@bfoF&f(W52|;9PB8Q(Sm{$Z2iu0_5{;1-{ZT4otIR% zZ*AJB;ukGhCJi+u^2V^B_xM9O^*6MSKApPW=gS@MJsG-3tup|UQ;+x_oNxD?mb?Oo zNtozx;KKF*@11h8>6`afQj>Fck|-@YP~U0t0Lr+~H=jb6cF>f9Y*znGyL2KO!cegf zK^Wt$Ak0c>>Kv97z$9VOT8}!~y+d7Vs!lDcc=Ut*QZMT;uHLi5)nx-&?c)okT-gm6 zC0OO=fCZ6!s6Q-sG0lh$P>7mAI(Q$2>q#K)cxa|tOaXl3XfTv68aL}x-&NbVU61Er zfI?lQJaN!E*a-b!dGxJ-#R9dC$tB>e$WYh{RrxI0MU;#z%CjqYhJX|?tEkyn&&x8= z|3qZw#Yq3Bkq^G-q=18<6#7+UXm=!W*8GlVs;L2q7K|=XIdpxfdD19cOD4YEv#h!@ zV_I`3_n@aP^kpUJh4-TE7XvH;rGO z0<{VSU>abB7FLs*eK9irc)GVD@t5x?UIkh=XRj#*K%19r^PhyKc*_m={2%ApH3Vl} z32o!z1}cv*^rfSW#jO)ZTg$Z5$=Cq=4*2fxCCPhceM{#GTO`i&ZGzy-=4Y) +#include "../../plugin.hpp" + +#include "audio_core.hpp" +#include "effect_bitcrusher.h" +#include "effect_combine.hpp" +#include "effect_freeverb.hpp" +#include "effect_flange.h" +#include "effect_granular.hpp" +#include "effect_multiply.h" +#include "effect_wavefolder.hpp" +#include "filter_variable.hpp" +#include "mixer.hpp" +#include "synth_dc.hpp" +#include "synth_sine.hpp" +#include "synth_waveform.hpp" +#include "synth_whitenoise.hpp" +#include "synth_pinknoise.hpp" +#include "synth_pwm.hpp" \ No newline at end of file diff --git a/src/noise-plethora/teensy/audio_core.hpp b/src/noise-plethora/teensy/audio_core.hpp new file mode 100644 index 0000000..d4089a1 --- /dev/null +++ b/src/noise-plethora/teensy/audio_core.hpp @@ -0,0 +1,180 @@ +#pragma once + +#include +#include "dspinst.h" + +class AudioStream { +public: + AudioStream(int num_inputs_) : num_inputs(num_inputs_) {} + const int num_inputs; +}; + +#define AUDIO_BLOCK_SAMPLES 128 + +// even if rack sample rate is different, we don't want Teensy to behave differently +// w.r.t. aliasing etc - this generally used to put upper bounds on frequencies etc +#define AUDIO_SAMPLE_RATE_EXACT 44100.0f + +typedef rack::dsp::RingBuffer TeensyBuffer; + +typedef struct audio_block_struct { + // uint8_t ref_count; + // uint8_t reserved1; + // uint16_t memory_pool_index; + int16_t data[AUDIO_BLOCK_SAMPLES] = {}; + + // initialises data to zeroes + void zeroAudioBlock() { + memset(data, 0, sizeof(int16_t) * AUDIO_BLOCK_SAMPLES); + } + + static void copyBlock(const audio_block_struct* src, audio_block_struct* dst) { + if (src && dst) { + memcpy(&(dst->data), &(src->data), AUDIO_BLOCK_SAMPLES); + } + } +} audio_block_t; + +enum WaveformType { + WAVEFORM_SINE, + WAVEFORM_SAWTOOTH, + WAVEFORM_SQUARE, + WAVEFORM_TRIANGLE, + WAVEFORM_ARBITRARY, + WAVEFORM_PULSE, + WAVEFORM_SAWTOOTH_REVERSE, + WAVEFORM_SAMPLE_HOLD, + WAVEFORM_TRIANGLE_VARIABLE, + WAVEFORM_BANDLIMIT_SAWTOOTH, + WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE, + WAVEFORM_BANDLIMIT_SQUARE, + WAVEFORM_BANDLIMIT_PULSE, +}; + +const int16_t AudioWaveformSine[257] = { + 0, 804, 1608, 2410, 3212, 4011, 4808, 5602, 6393, 7179, + 7962, 8739, 9512, 10278, 11039, 11793, 12539, 13279, 14010, 14732, + 15446, 16151, 16846, 17530, 18204, 18868, 19519, 20159, 20787, 21403, + 22005, 22594, 23170, 23731, 24279, 24811, 25329, 25832, 26319, 26790, + 27245, 27683, 28105, 28510, 28898, 29268, 29621, 29956, 30273, 30571, + 30852, 31113, 31356, 31580, 31785, 31971, 32137, 32285, 32412, 32521, + 32609, 32678, 32728, 32757, 32767, 32757, 32728, 32678, 32609, 32521, + 32412, 32285, 32137, 31971, 31785, 31580, 31356, 31113, 30852, 30571, + 30273, 29956, 29621, 29268, 28898, 28510, 28105, 27683, 27245, 26790, + 26319, 25832, 25329, 24811, 24279, 23731, 23170, 22594, 22005, 21403, + 20787, 20159, 19519, 18868, 18204, 17530, 16846, 16151, 15446, 14732, + 14010, 13279, 12539, 11793, 11039, 10278, 9512, 8739, 7962, 7179, + 6393, 5602, 4808, 4011, 3212, 2410, 1608, 804, 0, -804, + -1608, -2410, -3212, -4011, -4808, -5602, -6393, -7179, -7962, -8739, + -9512, -10278, -11039, -11793, -12539, -13279, -14010, -14732, -15446, -16151, + -16846, -17530, -18204, -18868, -19519, -20159, -20787, -21403, -22005, -22594, + -23170, -23731, -24279, -24811, -25329, -25832, -26319, -26790, -27245, -27683, + -28105, -28510, -28898, -29268, -29621, -29956, -30273, -30571, -30852, -31113, + -31356, -31580, -31785, -31971, -32137, -32285, -32412, -32521, -32609, -32678, + -32728, -32757, -32767, -32757, -32728, -32678, -32609, -32521, -32412, -32285, + -32137, -31971, -31785, -31580, -31356, -31113, -30852, -30571, -30273, -29956, + -29621, -29268, -28898, -28510, -28105, -27683, -27245, -26790, -26319, -25832, + -25329, -24811, -24279, -23731, -23170, -22594, -22005, -21403, -20787, -20159, + -19519, -18868, -18204, -17530, -16846, -16151, -15446, -14732, -14010, -13279, + -12539, -11793, -11039, -10278, -9512, -8739, -7962, -7179, -6393, -5602, + -4808, -4011, -3212, -2410, -1608, -804, 0 +}; + + +namespace teensy { + +static uint32_t seed; + +inline int32_t random_teensy(void) { + int32_t hi, lo, x; + + // the algorithm used in avr-libc 1.6.4 + x = seed; + if (x == 0) + x = 123459876; + hi = x / 127773; + lo = x % 127773; + x = 16807 * lo - 2836 * hi; + if (x < 0) + x += 0x7FFFFFFF; + seed = x; + return x; +} + +inline uint32_t random_teensy(uint32_t howbig) { + if (howbig == 0) + return 0; + return random_teensy() % howbig; +} + +inline int32_t random_teensy(int32_t howsmall, int32_t howbig) { + if (howsmall >= howbig) + return howsmall; + int32_t diff = howbig - howsmall; + return random_teensy(diff) + howsmall; +} +} + + + + +class AudioSynthNoiseWhiteFloat : public AudioStream { +public: + AudioSynthNoiseWhiteFloat() : AudioStream(0) { } + + void amplitude(float level) { + level_ = level; + } + + // uniform on [-1, 1] + float process() { + return level_ * ((rand31pm_next() / 2147483647.0) * 2.f - 1.f); + } + + // uniform on [0, 1] + float processNonnegative() { + return level_ * (rand31pm_next() / 2147483647.0); + } + + long unsigned int rand31pm_next() { + double const a = 16807; + double const m = 2147483647.0 ; + + return (seed31pm = (long)(fmod((seed31pm * a), m))); + } + +private: + float level_ = 1.0; + long unsigned int seed31pm = 1; +}; + + +class AudioSynthNoiseGritFloat : public AudioStream { +public: + AudioSynthNoiseGritFloat() : AudioStream(0) { } + + void setDensity(float density) { + density_ = density; + } + + float process(float sampleTime) { + + float threshold = density_ * sampleTime; + float scale = threshold > 0.f ? 2.f / threshold : 0.f; + + float z = white.processNonnegative(); + + if (z < threshold) { + return z * scale - 1.0f; + } + else { + return 0.f; + } + } + +private: + + float density_ = 0.f; + + AudioSynthNoiseWhiteFloat white; +}; \ No newline at end of file diff --git a/src/noise-plethora/teensy/dspinst.h b/src/noise-plethora/teensy/dspinst.h new file mode 100644 index 0000000..743705d --- /dev/null +++ b/src/noise-plethora/teensy/dspinst.h @@ -0,0 +1,356 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +#ifndef dspinst_h_ +#define dspinst_h_ + +#include + +#define KINETISL + +static inline float int16_to_float_1v(const int16_t& toConvert) { + return toConvert / 32767.f; +} + +// computes limit((val >> rshift), 2**bits) +static inline int32_t signed_saturate_rshift(int32_t val, int bits, int rshift) __attribute__((always_inline, unused)); +static inline int32_t signed_saturate_rshift(int32_t val, int bits, int rshift) { +#if defined (__ARM_ARCH_7EM__) + int32_t out; + asm volatile("ssat %0, %1, %2, asr %3" : "=r"(out) : "I"(bits), "r"(val), "I"(rshift)); + return out; +#elif defined(KINETISL) + int32_t out, max; + out = val >> rshift; + max = 1 << (bits - 1); + if (out >= 0) { + if (out > max - 1) + out = max - 1; + } + else { + if (out < -max) + out = -max; + } + return out; +#endif +} + +// computes limit(val, 2**bits) +static inline int16_t saturate16(int32_t val) __attribute__((always_inline, unused)); +static inline int16_t saturate16(int32_t val) { +#if defined (__ARM_ARCH_7EM__) + int16_t out; + int32_t tmp; + asm volatile("ssat %0, %1, %2" : "=r"(tmp) : "I"(16), "r"(val)); + out = (int16_t)(tmp); + return out; +#else + if (val > 32767) + val = 32767; + else if (val < -32768) + val = -32768; + return val; +#endif +} + +// computes ((a[31:0] * b[15:0]) >> 16) +static inline int32_t signed_multiply_32x16b(int32_t a, uint32_t b) __attribute__((always_inline, unused)); +static inline int32_t signed_multiply_32x16b(int32_t a, uint32_t b) { +#if defined (__ARM_ARCH_7EM__) + int32_t out; + asm volatile("smulwb %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +#elif defined(KINETISL) + return ((int64_t)a * (int16_t)(b & 0xFFFF)) >> 16; +#endif +} + +// computes ((a[31:0] * b[31:16]) >> 16) +static inline int32_t signed_multiply_32x16t(int32_t a, uint32_t b) __attribute__((always_inline, unused)); +static inline int32_t signed_multiply_32x16t(int32_t a, uint32_t b) { +#if defined (__ARM_ARCH_7EM__) + int32_t out; + asm volatile("smulwt %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +#elif defined(KINETISL) + return ((int64_t)a * (int16_t)(b >> 16)) >> 16; +#endif +} + +// computes (((int64_t)a[31:0] * (int64_t)b[31:0]) >> 32) +static inline int32_t multiply_32x32_rshift32(int32_t a, int32_t b) __attribute__((always_inline, unused)); +static inline int32_t multiply_32x32_rshift32(int32_t a, int32_t b) { +#if defined (__ARM_ARCH_7EM__) + int32_t out; + asm volatile("smmul %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +#elif defined(KINETISL) + return ((int64_t)a * (int64_t)b) >> 32; +#endif +} + +// computes (((int64_t)a[31:0] * (int64_t)b[31:0] + 0x8000000) >> 32) +static inline int32_t multiply_32x32_rshift32_rounded(int32_t a, int32_t b) __attribute__((always_inline, unused)); +static inline int32_t multiply_32x32_rshift32_rounded(int32_t a, int32_t b) { +#if defined (__ARM_ARCH_7EM__) + int32_t out; + asm volatile("smmulr %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +#elif defined(KINETISL) + return (((int64_t)a * (int64_t)b) + 0x8000000) >> 32; +#endif +} + +// computes sum + (((int64_t)a[31:0] * (int64_t)b[31:0] + 0x8000000) >> 32) +static inline int32_t multiply_accumulate_32x32_rshift32_rounded(int32_t sum, int32_t a, int32_t b) __attribute__((always_inline, unused)); +static inline int32_t multiply_accumulate_32x32_rshift32_rounded(int32_t sum, int32_t a, int32_t b) { +#if defined (__ARM_ARCH_7EM__) + int32_t out; + asm volatile("smmlar %0, %2, %3, %1" : "=r"(out) : "r"(sum), "r"(a), "r"(b)); + return out; +#elif defined(KINETISL) + return sum + ((((int64_t)a * (int64_t)b) + 0x8000000) >> 32); +#endif +} + +// computes sum - (((int64_t)a[31:0] * (int64_t)b[31:0] + 0x8000000) >> 32) +static inline int32_t multiply_subtract_32x32_rshift32_rounded(int32_t sum, int32_t a, int32_t b) __attribute__((always_inline, unused)); +static inline int32_t multiply_subtract_32x32_rshift32_rounded(int32_t sum, int32_t a, int32_t b) { +#if defined (__ARM_ARCH_7EM__) + int32_t out; + asm volatile("smmlsr %0, %2, %3, %1" : "=r"(out) : "r"(sum), "r"(a), "r"(b)); + return out; +#elif defined(KINETISL) + return sum - ((((int64_t)a * (int64_t)b) + 0x8000000) >> 32); +#endif +} + + +// computes (a[31:16] | (b[31:16] >> 16)) +static inline uint32_t pack_16t_16t(int32_t a, int32_t b) __attribute__((always_inline, unused)); +static inline uint32_t pack_16t_16t(int32_t a, int32_t b) { +#if defined (__ARM_ARCH_7EM__) + int32_t out; + asm volatile("pkhtb %0, %1, %2, asr #16" : "=r"(out) : "r"(a), "r"(b)); + return out; +#elif defined(KINETISL) + return (a & 0xFFFF0000) | ((uint32_t)b >> 16); +#endif +} + +// computes (a[31:16] | b[15:0]) +static inline uint32_t pack_16t_16b(int32_t a, int32_t b) __attribute__((always_inline, unused)); +static inline uint32_t pack_16t_16b(int32_t a, int32_t b) { +#if defined (__ARM_ARCH_7EM__) + int32_t out; + asm volatile("pkhtb %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +#elif defined(KINETISL) + return (a & 0xFFFF0000) | (b & 0x0000FFFF); +#endif +} + +// computes ((a[15:0] << 16) | b[15:0]) +static inline uint32_t pack_16b_16b(int32_t a, int32_t b) __attribute__((always_inline, unused)); +static inline uint32_t pack_16b_16b(int32_t a, int32_t b) { +#if defined (__ARM_ARCH_7EM__) + int32_t out; + asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(out) : "r"(b), "r"(a)); + return out; +#elif defined(KINETISL) + return (a << 16) | (b & 0x0000FFFF); +#endif +} + +// computes ((a[15:0] << 16) | b[15:0]) +/* +static inline uint32_t pack_16x16(int32_t a, int32_t b) __attribute__((always_inline, unused)); +static inline uint32_t pack_16x16(int32_t a, int32_t b) +{ + int32_t out; + asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r" (out) : "r" (b), "r" (a)); + return out; +} +*/ +#if defined (__ARM_ARCH_7EM__) +// computes (((a[31:16] + b[31:16]) << 16) | (a[15:0 + b[15:0])) (saturates) +static inline uint32_t signed_add_16_and_16(uint32_t a, uint32_t b) __attribute__((always_inline, unused)); +static inline uint32_t signed_add_16_and_16(uint32_t a, uint32_t b) { + int32_t out; + asm volatile("qadd16 %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +} + +// computes (((a[31:16] - b[31:16]) << 16) | (a[15:0 - b[15:0])) (saturates) +static inline int32_t signed_subtract_16_and_16(int32_t a, int32_t b) __attribute__((always_inline, unused)); +static inline int32_t signed_subtract_16_and_16(int32_t a, int32_t b) { + int32_t out; + asm volatile("qsub16 %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +} + +// computes out = (((a[31:16]+b[31:16])/2) <<16) | ((a[15:0]+b[15:0])/2) +static inline int32_t signed_halving_add_16_and_16(int32_t a, int32_t b) __attribute__((always_inline, unused)); +static inline int32_t signed_halving_add_16_and_16(int32_t a, int32_t b) { + int32_t out; + asm volatile("shadd16 %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +} + +// computes out = (((a[31:16]-b[31:16])/2) <<16) | ((a[15:0]-b[15:0])/2) +static inline int32_t signed_halving_subtract_16_and_16(int32_t a, int32_t b) __attribute__((always_inline, unused)); +static inline int32_t signed_halving_subtract_16_and_16(int32_t a, int32_t b) { + int32_t out; + asm volatile("shsub16 %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +} + +// computes (sum + ((a[31:0] * b[15:0]) >> 16)) +static inline int32_t signed_multiply_accumulate_32x16b(int32_t sum, int32_t a, uint32_t b) __attribute__((always_inline, unused)); +static inline int32_t signed_multiply_accumulate_32x16b(int32_t sum, int32_t a, uint32_t b) { + int32_t out; + asm volatile("smlawb %0, %2, %3, %1" : "=r"(out) : "r"(sum), "r"(a), "r"(b)); + return out; +} + +// computes (sum + ((a[31:0] * b[31:16]) >> 16)) +static inline int32_t signed_multiply_accumulate_32x16t(int32_t sum, int32_t a, uint32_t b) __attribute__((always_inline, unused)); +static inline int32_t signed_multiply_accumulate_32x16t(int32_t sum, int32_t a, uint32_t b) { + int32_t out; + asm volatile("smlawt %0, %2, %3, %1" : "=r"(out) : "r"(sum), "r"(a), "r"(b)); + return out; +} + +// computes logical and, forces compiler to allocate register and use single cycle instruction +static inline uint32_t logical_and(uint32_t a, uint32_t b) __attribute__((always_inline, unused)); +static inline uint32_t logical_and(uint32_t a, uint32_t b) { + asm volatile("and %0, %1" : "+r"(a) : "r"(b)); + return a; +} + +// computes ((a[15:0] * b[15:0]) + (a[31:16] * b[31:16])) +static inline int32_t multiply_16tx16t_add_16bx16b(uint32_t a, uint32_t b) __attribute__((always_inline, unused)); +static inline int32_t multiply_16tx16t_add_16bx16b(uint32_t a, uint32_t b) { + int32_t out; + asm volatile("smuad %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +} + +// computes ((a[15:0] * b[31:16]) + (a[31:16] * b[15:0])) +static inline int32_t multiply_16tx16b_add_16bx16t(uint32_t a, uint32_t b) __attribute__((always_inline, unused)); +static inline int32_t multiply_16tx16b_add_16bx16t(uint32_t a, uint32_t b) { + int32_t out; + asm volatile("smuadx %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +} + +// // computes sum += ((a[15:0] * b[15:0]) + (a[31:16] * b[31:16])) +static inline int64_t multiply_accumulate_16tx16t_add_16bx16b(int64_t sum, uint32_t a, uint32_t b) { + asm volatile("smlald %Q0, %R0, %1, %2" : "+r"(sum) : "r"(a), "r"(b)); + return sum; +} + +// // computes sum += ((a[15:0] * b[31:16]) + (a[31:16] * b[15:0])) +static inline int64_t multiply_accumulate_16tx16b_add_16bx16t(int64_t sum, uint32_t a, uint32_t b) { + asm volatile("smlaldx %Q0, %R0, %1, %2" : "+r"(sum) : "r"(a), "r"(b)); + return sum; +} + +// computes ((a[15:0] * b[15:0]) +static inline int32_t multiply_16bx16b(uint32_t a, uint32_t b) __attribute__((always_inline, unused)); +static inline int32_t multiply_16bx16b(uint32_t a, uint32_t b) { + int32_t out; + asm volatile("smulbb %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +} + +// computes ((a[15:0] * b[31:16]) +static inline int32_t multiply_16bx16t(uint32_t a, uint32_t b) __attribute__((always_inline, unused)); +static inline int32_t multiply_16bx16t(uint32_t a, uint32_t b) { + int32_t out; + asm volatile("smulbt %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +} + +// computes ((a[31:16] * b[15:0]) +static inline int32_t multiply_16tx16b(uint32_t a, uint32_t b) __attribute__((always_inline, unused)); +static inline int32_t multiply_16tx16b(uint32_t a, uint32_t b) { + int32_t out; + asm volatile("smultb %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +} + +// computes ((a[31:16] * b[31:16]) +static inline int32_t multiply_16tx16t(uint32_t a, uint32_t b) __attribute__((always_inline, unused)); +static inline int32_t multiply_16tx16t(uint32_t a, uint32_t b) { + int32_t out; + asm volatile("smultt %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +} + +// computes (a - b), result saturated to 32 bit integer range +static inline int32_t substract_32_saturate(uint32_t a, uint32_t b) __attribute__((always_inline, unused)); +static inline int32_t substract_32_saturate(uint32_t a, uint32_t b) { + int32_t out; + asm volatile("qsub %0, %1, %2" : "=r"(out) : "r"(a), "r"(b)); + return out; +} + +// Multiply two S.31 fractional integers, and return the 32 most significant +// bits after a shift left by the constant z. +// This comes from rockbox.org + +static inline int32_t FRACMUL_SHL(int32_t x, int32_t y, int z) { + int32_t t, t2; + asm("smull %[t], %[t2], %[a], %[b]\n\t" + "mov %[t2], %[t2], asl %[c]\n\t" + "orr %[t], %[t2], %[t], lsr %[d]\n\t" + : [t] "=&r"(t), [t2] "=&r"(t2) + : [a] "r"(x), [b] "r"(y), + [c] "Mr"((z) + 1), [d] "Mr"(31 - (z))); + return t; +} + +#endif + +//get Q from PSR +static inline uint32_t get_q_psr(void) __attribute__((always_inline, unused)); +static inline uint32_t get_q_psr(void) { + uint32_t out; + asm("mrs %0, APSR" : "=r"(out)); + return (out & 0x8000000) >> 27; +} + +//clear Q BIT in PSR +static inline void clr_q_psr(void) __attribute__((always_inline, unused)); +static inline void clr_q_psr(void) { + uint32_t t; + asm("mov %[t],#0\n" + "msr APSR_nzcvq,%0\n" : [t] "=&r"(t)::"cc"); +} + + +#endif diff --git a/src/noise-plethora/teensy/effect_bitcrusher.cpp b/src/noise-plethora/teensy/effect_bitcrusher.cpp new file mode 100644 index 0000000..4203cd3 --- /dev/null +++ b/src/noise-plethora/teensy/effect_bitcrusher.cpp @@ -0,0 +1,90 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Jonathan Payne (jon@jonnypayne.com) + * Based on Effect_Fade by Paul Stoffregen + * Also samplerate reduction based on Pete Brown's bitcrusher here: + * http://10rem.net/blog/2013/01/13/a-simple-bitcrusher-and-sample-rate-reducer-in-cplusplus-for-a-windows-store-app + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +#include "effect_bitcrusher.h" + +void AudioEffectBitcrusher::update(const audio_block_t* inputBlock, audio_block_t* outputBlock) { + uint32_t i; + uint32_t sampleSquidge, sampleSqueeze; //squidge is bitdepth, squeeze is for samplerate + + if (!inputBlock || !outputBlock) { + return; + } + + if (crushBits == 16 && sampleStep <= 1) { + // nothing to do. Output is sent through clean, then exit the function + audio_block_t::copyBlock(inputBlock, outputBlock); + } + + if (sampleStep <= 1) { //no sample rate mods, just crush the bitdepth. + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + // shift bits right to cut off fine detail sampleSquidge is a + // uint32 so sign extension will not occur, fills with zeroes. + sampleSquidge = inputBlock->data[i] >> (16 - crushBits); + // shift bits left again to regain the volume level. + // fills with zeroes. + outputBlock->data[i] = sampleSquidge << (16 - crushBits); + } + } + else if (crushBits == 16) { //bitcrusher not being used, samplerate mods only. + i = 0; + while (i < AUDIO_BLOCK_SAMPLES) { + // save the root sample. this will pick up a root + // sample every _sampleStep_ samples. + sampleSqueeze = inputBlock->data[i]; + for (int j = 0; j < sampleStep && i < AUDIO_BLOCK_SAMPLES; j++) { + // for each repeated sample, paste in the current + // root sample, then move onto the next step. + outputBlock->data[i] = sampleSqueeze; + i++; + } + } + } + else { //both being used. crush those bits and mash those samples. + i = 0; + while (i < AUDIO_BLOCK_SAMPLES) { + // save the root sample. this will pick up a root sample + // every _sampleStep_ samples. + sampleSqueeze = inputBlock->data[i]; + for (int j = 0; j < sampleStep && i < AUDIO_BLOCK_SAMPLES; j++) { + // shift bits right to cut off fine detail sampleSquidge + // is a uint32 so sign extension will not occur, fills + // with zeroes. + sampleSquidge = sampleSqueeze >> (16 - crushBits); + // shift bits left again to regain the volume level. + // fills with zeroes. paste into buffer sample + + // sampleStep offset. + outputBlock->data[i] = sampleSquidge << (16 - crushBits); + i++; + } + } + } +} + + diff --git a/src/noise-plethora/teensy/effect_bitcrusher.h b/src/noise-plethora/teensy/effect_bitcrusher.h new file mode 100644 index 0000000..ac438c2 --- /dev/null +++ b/src/noise-plethora/teensy/effect_bitcrusher.h @@ -0,0 +1,58 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Jonathan Payne (jon@jonnypayne.com) + * Based on Effect_Fade by Paul Stoffregen + + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +#pragma once + +#include "audio_core.hpp" + +class AudioEffectBitcrusher : public AudioStream { +public: + AudioEffectBitcrusher(void) + : AudioStream(1) {} + void bits(uint8_t b) { + if (b > 16) + b = 16; + else if (b == 0) + b = 1; + crushBits = b; + } + void sampleRate(float hz) { + // modification to account for Rack sample rate + int n = (APP->engine->getSampleRate() / hz) + 0.5f; + if (n < 1) + n = 1; + else if (n > 64) + n = 64; + sampleStep = n; + } + virtual void update(const audio_block_t* inputBlock, audio_block_t* block); + +private: + uint8_t crushBits; // 16 = off + uint8_t sampleStep; // the number of samples to double up. This simple technique only allows a few stepped positions. +}; + diff --git a/src/noise-plethora/teensy/effect_combine.cpp b/src/noise-plethora/teensy/effect_combine.cpp new file mode 100644 index 0000000..76a00fc --- /dev/null +++ b/src/noise-plethora/teensy/effect_combine.cpp @@ -0,0 +1,72 @@ +/* Copyright (c) 2018 John-Michael Reed + * bleeplabs.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + * + * Combine analog signals with bitwise expressions like XOR. + * Combining two simple oscillators results in interesting new waveforms, + * Combining white noise or dynamic incoming audio results in aggressive digital distortion. + */ + +#include "effect_combine.hpp" + + +void AudioEffectDigitalCombine::update(const audio_block_t* blocka, const audio_block_t* blockb, audio_block_t* output) { + uint32_t* pa, *pb, *end, *pout; + uint32_t a12, a34; //, a56, a78; + uint32_t b12, b34; //, b56, b78; + + if (!blocka || !blockb || !output) { + return; + } + + pa = (uint32_t*)(blocka->data); + pb = (uint32_t*)(blockb->data); + pout = (uint32_t*)(output->data); + end = pa + AUDIO_BLOCK_SAMPLES / 2; + + while (pa < end) { + a12 = *pa++; + a34 = *pa++; + b12 = *pb++; + b34 = *pb++; + if (mode_sel == OR) { + a12 = a12 | b12; + a34 = a34 | b34; + } + if (mode_sel == XOR) { + a12 = a12 ^ b12; + a34 = a34 ^ b34; + } + if (mode_sel == AND) { + a12 = a12 & b12; + a34 = a34 & b34; + } + if (mode_sel == MODULO) { + a12 = a12 % b12; + a34 = a34 % b34; + } + *pout++ = a12; + *pout++ = a34; + } +} diff --git a/src/noise-plethora/teensy/effect_combine.hpp b/src/noise-plethora/teensy/effect_combine.hpp new file mode 100644 index 0000000..8249f5c --- /dev/null +++ b/src/noise-plethora/teensy/effect_combine.hpp @@ -0,0 +1,53 @@ +/* Copyright (c) 2018 John-Michael Reed + * bleeplabs.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + * + * Combine analog signals with bitwise expressions like XOR. + * Combining two simple oscillators results in interesting new waveforms, + * Combining white noise or dynamic incoming audio results in aggressive digital distortion. + */ + +#pragma once + +#include "audio_core.hpp" + +class AudioEffectDigitalCombine : public AudioStream { +public: + enum combineMode { + OR = 0, + XOR = 1, + AND = 2, + MODULO = 3, + }; + AudioEffectDigitalCombine() : AudioStream(2), mode_sel(OR) { } + void setCombineMode(int mode_in) { + if (mode_in > 3) { + mode_in = 3; + } + mode_sel = mode_in; + } + virtual void update(const audio_block_t* blocka, const audio_block_t* blockb, audio_block_t* output); +private: + short mode_sel; +}; diff --git a/src/noise-plethora/teensy/effect_flange.cpp b/src/noise-plethora/teensy/effect_flange.cpp new file mode 100644 index 0000000..b9d582d --- /dev/null +++ b/src/noise-plethora/teensy/effect_flange.cpp @@ -0,0 +1,228 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Pete (El Supremo) + * + * 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. + */ + + +#include "effect_flange.h" + + +int16_t sin16_C(uint16_t theta) { + static const uint16_t base[] = + { 0, 6393, 12539, 18204, 23170, 27245, 30273, 32137 }; + static const uint8_t slope[] = + { 49, 48, 44, 38, 31, 23, 14, 4 }; + + uint16_t offset = (theta & 0x3FFF) >> 3; // 0..2047 + if (theta & 0x4000) + offset = 2047 - offset; + + uint8_t section = offset / 256; // 0..7 + uint16_t b = base[section]; + uint8_t m = slope[section]; + + uint8_t secoffset8 = (uint8_t)(offset) / 2; + + uint16_t mx = m * secoffset8; + int16_t y = mx + b; + + if (theta & 0x8000) + y = -y; + + return y; +} + +/******************************************************************/ +// A u d i o E f f e c t F l a n g e +// Written by Pete (El Supremo) Jan 2014 +// 140529 - change to handle mono stream and change modify() to voices() +// 140207 - fix calculation of delay_rate_incr which is expressed as +// a fraction of 2*PI +// 140207 - cosmetic fix to begin() +// 140219 - correct the calculation of "frac" + +// circular addressing indices for left and right channels +//short AudioEffectFlange::l_circ_idx; +//short AudioEffectFlange::r_circ_idx; + +//short * AudioEffectFlange::l_delayline = NULL; +//short * AudioEffectFlange::r_delayline = NULL; + +// User-supplied offset for the delayed sample +// but start with passthru +//int AudioEffectFlange::delay_offset_idx = FLANGE_DELAY_PASSTHRU; +//int AudioEffectFlange::delay_length; + +//int AudioEffectFlange::delay_depth; +//int AudioEffectFlange::delay_rate_incr; +//unsigned int AudioEffectFlange::l_delay_rate_index; +//unsigned int AudioEffectFlange::r_delay_rate_index; +// fails if the user provides unreasonable values but will +// coerce them and go ahead anyway. e.g. if the delay offset +// is >= CHORUS_DELAY_LENGTH, the code will force it to +// CHORUS_DELAY_LENGTH-1 and return false. +// delay_rate is the rate (in Hz) of the sine wave modulation +// delay_depth is the maximum variation around delay_offset +// i.e. the total offset is delay_offset + delay_depth * sin(delay_rate) +bool AudioEffectFlange::begin(short* delayline, int d_length, int delay_offset, int d_depth, float delay_rate) { + bool all_ok = true; + + delay_length = d_length / 2; + l_delayline = delayline; + + delay_depth = d_depth; + // initial index + l_delay_rate_index = 0; + l_circ_idx = 0; + delay_rate_incr = (delay_rate * 2147483648.0) / APP->engine->getSampleRate(); + + + delay_offset_idx = delay_offset; + // Allow the passthru code to go through + if (delay_offset_idx < -1) { + delay_offset_idx = 0; + all_ok = false; + } + if (delay_offset_idx >= delay_length) { + delay_offset_idx = delay_length - 1; + all_ok = false; + } + return (all_ok); +} + + +bool AudioEffectFlange::voices(int delay_offset, int d_depth, float delay_rate) { + bool all_ok = true; + + delay_depth = d_depth; + + delay_rate_incr = (delay_rate * 2147483648.0) / APP->engine->getSampleRate(); + + delay_offset_idx = delay_offset; + // Allow the passthru code to go through + if (delay_offset_idx < -1) { + delay_offset_idx = 0; + all_ok = false; + } + if (delay_offset_idx >= delay_length) { + delay_offset_idx = delay_length - 1; + all_ok = false; + } + l_delay_rate_index = 0; + l_circ_idx = 0; + return (all_ok); +} + +void AudioEffectFlange::update(const audio_block_t* inputBlock, audio_block_t* outputBlock) { + + int idx; + const short* inbp; + short* outbp; + short frac; + int idx1; + + if (l_delayline == NULL) + return; + + // do passthru + if (delay_offset_idx == FLANGE_DELAY_PASSTHRU) { + // Just passthrough + + if (inputBlock) { + inbp = inputBlock->data; + // fill the delay line + for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + l_circ_idx++; + if (l_circ_idx >= delay_length) { + l_circ_idx = 0; + } + l_delayline[l_circ_idx] = *inbp++; + } + // transmit the unmodified block + audio_block_t::copyBlock(inputBlock, outputBlock); + } + return; + } + + // L E F T C H A N N E L + if (inputBlock && outputBlock) { + inbp = inputBlock->data; + outbp = outputBlock->data; + for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + // increment the index into the circular delay line buffer + l_circ_idx++; + // wrap the index around if necessary + if (l_circ_idx >= delay_length) { + l_circ_idx = 0; + } + // store the current sample in the delay line + l_delayline[l_circ_idx] = *inbp++; + // The argument to the arm_sin_q15 function is NOT in radians. It is + // actually, in effect, the fraction remaining after the division + // of radians/(2*PI) which is then expressed as a positive Q15 + // fraction in the interval [0 , +1) - this is l_delay_rate_index. + // l_delay_rate_index should probably be called l_delay_rate_phase + // (sorry about that!) + // It is a Q31 positive number of which the high order 16 bits are + // used when calculating the sine. idx will have a value in the + // interval [-1 , +1) + frac = sin16_C(((l_delay_rate_index >> 16) & 0x7fff)); + // multiply the sin by the delay depth + idx = (frac * delay_depth) >> 15; + //Serial.println(idx); + // Calculate the offset into the buffer + idx = l_circ_idx - (delay_offset_idx + idx); + // and adjust idx to point into the circular buffer + if (idx < 0) { + idx += delay_length; + } + if (idx >= delay_length) { + idx -= delay_length; + } + + // Here we interpolate between two indices but if the sine was negative + // then we interpolate between idx and idx-1, otherwise the + // interpolation is between idx and idx+1 + if (frac < 0) + idx1 = idx - 1; + else + idx1 = idx + 1; + // adjust idx1 in the circular buffer + if (idx1 < 0) { + idx1 += delay_length; + } + if (idx1 >= delay_length) { + idx1 -= delay_length; + } + // Do the interpolation + frac = (l_delay_rate_index >> 1) & 0x7fff; + frac = (((int)(l_delayline[idx1] - l_delayline[idx]) * frac) >> 15); + *outbp++ = (l_delayline[l_circ_idx] + l_delayline[idx] + frac) / 2; + + l_delay_rate_index += delay_rate_incr; + if (l_delay_rate_index & 0x80000000) { + l_delay_rate_index &= 0x7fffffff; + } + } + } +} + + + diff --git a/src/noise-plethora/teensy/effect_flange.h b/src/noise-plethora/teensy/effect_flange.h new file mode 100644 index 0000000..30d0c6f --- /dev/null +++ b/src/noise-plethora/teensy/effect_flange.h @@ -0,0 +1,53 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Pete (El Supremo) + * + * 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. + */ + +#pragma once +#include "audio_core.hpp" + +/******************************************************************/ +// A u d i o E f f e c t F l a n g e +// Written by Pete (El Supremo) Jan 2014 +// 140529 - change to handle mono stream and change modify() to voices() + +#define FLANGE_DELAY_PASSTHRU 0 + +class AudioEffectFlange : + public AudioStream { +public: + AudioEffectFlange(void): + AudioStream(1) { + } + + bool begin(short* delayline, int d_length, int delay_offset, int d_depth, float delay_rate); + bool voices(int delay_offset, int d_depth, float delay_rate); + virtual void update(const audio_block_t* inputBlock, audio_block_t* outputBlock); + +private: + + short* l_delayline; + int delay_length; + short l_circ_idx; + int delay_depth; + int delay_offset_idx; + int delay_rate_incr; + unsigned int l_delay_rate_index; +}; diff --git a/src/noise-plethora/teensy/effect_freeverb.cpp b/src/noise-plethora/teensy/effect_freeverb.cpp new file mode 100644 index 0000000..91356bf --- /dev/null +++ b/src/noise-plethora/teensy/effect_freeverb.cpp @@ -0,0 +1,193 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2018, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +// A fixed point implementation of Freeverb by Jezar at Dreampoint +// http://blog.bjornroche.com/2012/06/freeverb-original-public-domain-code-by.html +// https://music.columbia.edu/pipermail/music-dsp/2001-October/045433.html + +#include "effect_freeverb.hpp" + + +AudioEffectFreeverb::AudioEffectFreeverb() : AudioStream(1) { + memset(comb1buf, 0, sizeof(comb1buf)); + memset(comb2buf, 0, sizeof(comb2buf)); + memset(comb3buf, 0, sizeof(comb3buf)); + memset(comb4buf, 0, sizeof(comb4buf)); + memset(comb5buf, 0, sizeof(comb5buf)); + memset(comb6buf, 0, sizeof(comb6buf)); + memset(comb7buf, 0, sizeof(comb7buf)); + memset(comb8buf, 0, sizeof(comb8buf)); + comb1index = 0; + comb2index = 0; + comb3index = 0; + comb4index = 0; + comb5index = 0; + comb6index = 0; + comb7index = 0; + comb8index = 0; + comb1filter = 0; + comb2filter = 0; + comb3filter = 0; + comb4filter = 0; + comb5filter = 0; + comb6filter = 0; + comb7filter = 0; + comb8filter = 0; + combdamp1 = 6553; + combdamp2 = 26215; + combfeeback = 27524; + memset(allpass1buf, 0, sizeof(allpass1buf)); + memset(allpass2buf, 0, sizeof(allpass2buf)); + memset(allpass3buf, 0, sizeof(allpass3buf)); + memset(allpass4buf, 0, sizeof(allpass4buf)); + allpass1index = 0; + allpass2index = 0; + allpass3index = 0; + allpass4index = 0; +} + + +// cleaner sat16 by http://www.moseleyinstruments.com/ +__attribute__((unused)) +static int16_t sat16(int32_t n, int rshift) { + // we should always round towards 0 + // to avoid recirculating round-off noise + // + // a 2s complement positive number is always + // rounded down, so we only need to take + // care of negative numbers + if (n < 0) { + n = n + (~(0xFFFFFFFFUL << rshift)); + } + n = n >> rshift; + if (n > 32767) { + return 32767; + } + if (n < -32768) { + return -32768; + } + return n; +} + +void AudioEffectFreeverb::update(const audio_block_t* block, audio_block_t* outblock) { + int i; + int16_t input, bufout, output; + int32_t sum; + + if (!block || !outblock) { + return; + } + + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + // TODO: scale numerical range depending on roomsize & damping + input = sat16(block->data[i] * 8738, 17); // for numerical headroom + sum = 0; + + bufout = comb1buf[comb1index]; + sum += bufout; + comb1filter = sat16(bufout * combdamp2 + comb1filter * combdamp1, 15); + comb1buf[comb1index] = sat16(input + sat16(comb1filter * combfeeback, 15), 0); + if (++comb1index >= sizeof(comb1buf) / sizeof(int16_t)) + comb1index = 0; + + bufout = comb2buf[comb2index]; + sum += bufout; + comb2filter = sat16(bufout * combdamp2 + comb2filter * combdamp1, 15); + comb2buf[comb2index] = sat16(input + sat16(comb2filter * combfeeback, 15), 0); + if (++comb2index >= sizeof(comb2buf) / sizeof(int16_t)) + comb2index = 0; + + bufout = comb3buf[comb3index]; + sum += bufout; + comb3filter = sat16(bufout * combdamp2 + comb3filter * combdamp1, 15); + comb3buf[comb3index] = sat16(input + sat16(comb3filter * combfeeback, 15), 0); + if (++comb3index >= sizeof(comb3buf) / sizeof(int16_t)) + comb3index = 0; + + bufout = comb4buf[comb4index]; + sum += bufout; + comb4filter = sat16(bufout * combdamp2 + comb4filter * combdamp1, 15); + comb4buf[comb4index] = sat16(input + sat16(comb4filter * combfeeback, 15), 0); + if (++comb4index >= sizeof(comb4buf) / sizeof(int16_t)) + comb4index = 0; + + bufout = comb5buf[comb5index]; + sum += bufout; + comb5filter = sat16(bufout * combdamp2 + comb5filter * combdamp1, 15); + comb5buf[comb5index] = sat16(input + sat16(comb5filter * combfeeback, 15), 0); + if (++comb5index >= sizeof(comb5buf) / sizeof(int16_t)) + comb5index = 0; + + bufout = comb6buf[comb6index]; + sum += bufout; + comb6filter = sat16(bufout * combdamp2 + comb6filter * combdamp1, 15); + comb6buf[comb6index] = sat16(input + sat16(comb6filter * combfeeback, 15), 0); + if (++comb6index >= sizeof(comb6buf) / sizeof(int16_t)) + comb6index = 0; + + bufout = comb7buf[comb7index]; + sum += bufout; + comb7filter = sat16(bufout * combdamp2 + comb7filter * combdamp1, 15); + comb7buf[comb7index] = sat16(input + sat16(comb7filter * combfeeback, 15), 0); + if (++comb7index >= sizeof(comb7buf) / sizeof(int16_t)) + comb7index = 0; + + bufout = comb8buf[comb8index]; + sum += bufout; + comb8filter = sat16(bufout * combdamp2 + comb8filter * combdamp1, 15); + comb8buf[comb8index] = sat16(input + sat16(comb8filter * combfeeback, 15), 0); + if (++comb8index >= sizeof(comb8buf) / sizeof(int16_t)) + comb8index = 0; + + output = sat16(sum * 31457, 17); + + bufout = allpass1buf[allpass1index]; + allpass1buf[allpass1index] = output + (bufout >> 1); + output = sat16(bufout - output, 1); + if (++allpass1index >= sizeof(allpass1buf) / sizeof(int16_t)) + allpass1index = 0; + + bufout = allpass2buf[allpass2index]; + allpass2buf[allpass2index] = output + (bufout >> 1); + output = sat16(bufout - output, 1); + if (++allpass2index >= sizeof(allpass2buf) / sizeof(int16_t)) + allpass2index = 0; + + bufout = allpass3buf[allpass3index]; + allpass3buf[allpass3index] = output + (bufout >> 1); + output = sat16(bufout - output, 1); + if (++allpass3index >= sizeof(allpass3buf) / sizeof(int16_t)) + allpass3index = 0; + + bufout = allpass4buf[allpass4index]; + allpass4buf[allpass4index] = output + (bufout >> 1); + output = sat16(bufout - output, 1); + if (++allpass4index >= sizeof(allpass4buf) / sizeof(int16_t)) + allpass4index = 0; + + outblock->data[i] = sat16(output * 30, 0); + } +} \ No newline at end of file diff --git a/src/noise-plethora/teensy/effect_freeverb.hpp b/src/noise-plethora/teensy/effect_freeverb.hpp new file mode 100644 index 0000000..65026d1 --- /dev/null +++ b/src/noise-plethora/teensy/effect_freeverb.hpp @@ -0,0 +1,90 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2018, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +#pragma once + +#include "audio_core.hpp" + +class AudioEffectFreeverb : public AudioStream { +public: + AudioEffectFreeverb(); + virtual void update(const audio_block_t* block, audio_block_t* outblock); + void roomsize(float n) { + if (n > 1.0f) + n = 1.0f; + else if (n < 0.0f) + n = 0.0f; + combfeeback = (int)(n * 9175.04f) + 22937; + } + void damping(float n) { + if (n > 1.0f) + n = 1.0f; + else if (n < 0.0f) + n = 0.0f; + int x1 = (int)(n * 13107.2f); + int x2 = 32768 - x1; + //__disable_irq(); + combdamp1 = x1; + combdamp2 = x2; + //__enable_irq(); + } +private: + int16_t comb1buf[1116]; + int16_t comb2buf[1188]; + int16_t comb3buf[1277]; + int16_t comb4buf[1356]; + int16_t comb5buf[1422]; + int16_t comb6buf[1491]; + int16_t comb7buf[1557]; + int16_t comb8buf[1617]; + uint16_t comb1index; + uint16_t comb2index; + uint16_t comb3index; + uint16_t comb4index; + uint16_t comb5index; + uint16_t comb6index; + uint16_t comb7index; + uint16_t comb8index; + int16_t comb1filter; + int16_t comb2filter; + int16_t comb3filter; + int16_t comb4filter; + int16_t comb5filter; + int16_t comb6filter; + int16_t comb7filter; + int16_t comb8filter; + int16_t combdamp1; + int16_t combdamp2; + int16_t combfeeback; + int16_t allpass1buf[556]; + int16_t allpass2buf[441]; + int16_t allpass3buf[341]; + int16_t allpass4buf[225]; + uint16_t allpass1index; + uint16_t allpass2index; + uint16_t allpass3index; + uint16_t allpass4index; +}; \ No newline at end of file diff --git a/src/noise-plethora/teensy/effect_granular.cpp b/src/noise-plethora/teensy/effect_granular.cpp new file mode 100644 index 0000000..11ed517 --- /dev/null +++ b/src/noise-plethora/teensy/effect_granular.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2018 John-Michael Reed + * bleeplabs.com + * + * 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. + */ + + +#include "effect_granular.hpp" + +void AudioEffectGranular::begin(int16_t* sample_bank_def, int16_t max_len_def) { + max_sample_len = max_len_def; + grain_mode = 0; + read_head = 0; + write_head = 0; + prev_input = 0; + playpack_rate = 65536; + accumulator = 0; + allow_len_change = true; + sample_loaded = false; + sample_bank = sample_bank_def; +} + +void AudioEffectGranular::beginFreeze_int(int grain_samples) { + //__disable_irq(); + grain_mode = 1; + if (grain_samples < max_sample_len) { + freeze_len = grain_samples; + } + else { + freeze_len = grain_samples; + } + sample_loaded = false; + write_en = false; + sample_req = true; + //__enable_irq(); +} + +void AudioEffectGranular::beginPitchShift_int(int grain_samples) { + //__disable_irq(); + grain_mode = 2; + if (allow_len_change) { + if (grain_samples < 100) + grain_samples = 100; + int maximum = (max_sample_len - 1) / 3; + if (grain_samples > maximum) + grain_samples = maximum; + glitch_len = grain_samples; + } + sample_loaded = false; + write_en = false; + sample_req = true; + //__enable_irq(); +} + + +void AudioEffectGranular::stop() { + grain_mode = 0; + allow_len_change = true; +} + +void AudioEffectGranular::update(const audio_block_t* input_block, audio_block_t* output_block) { + + + if (sample_bank == NULL) { + /* block = receiveReadOnly(0); + if (block) + release(block); + */ + return; + } + + // block = receiveWritable(0); + if (!output_block || !input_block) + return; + + if (grain_mode == 0) { + // passthrough, no granular effect + memcpy(output_block->data, input_block->data, AUDIO_BLOCK_SAMPLES); + + // prev_input = block->data[AUDIO_BLOCK_SAMPLES - 1]; + } + else if (grain_mode == 1) { + // Freeze - sample 1 grain, then repeatedly play it back + for (int j = 0; j < AUDIO_BLOCK_SAMPLES; j++) { + if (sample_req) { + // only begin capture on zero cross + int16_t current_input = input_block->data[j]; + if ((current_input < 0 && prev_input >= 0) || + (current_input >= 0 && prev_input < 0)) { + write_en = true; + write_head = 0; + read_head = 0; + sample_req = false; + } + else { + prev_input = current_input; + } + } + if (write_en) { + sample_bank[write_head++] = input_block->data[j]; + if (write_head >= freeze_len) { + sample_loaded = true; + } + if (write_head >= max_sample_len) { + write_en = false; + } + } + if (sample_loaded) { + // was "if (playpack_rate >= 0)", always true for uint + if (true) { + accumulator += playpack_rate; + read_head = accumulator >> 16; + } + if (read_head >= freeze_len) { + accumulator = 0; + read_head = 0; + } + output_block->data[j] = sample_bank[read_head]; + } + } + } + else if (grain_mode == 2) { + //GLITCH SHIFT + //basic granular synth thingy + // the shorter the sample the max_sample_len the more tonal it is. + // Longer it has more definition. It's a bit roboty either way which + // is obv great and good enough for noise music. + + for (int k = 0; k < AUDIO_BLOCK_SAMPLES; k++) { + // only start recording when the audio is crossing zero to minimize pops + if (sample_req) { + int16_t current_input = input_block->data[k]; + if ((current_input < 0 && prev_input >= 0) || + (current_input >= 0 && prev_input < 0)) { + write_en = true; + } + else { + prev_input = current_input; + } + } + + if (write_en) { + sample_req = false; + allow_len_change = true; // Reduces noise by not allowing the + // length to change after the sample has been + // recored. Kind of not too much though + if (write_head >= glitch_len) { + write_head = 0; + sample_loaded = true; + write_en = false; + allow_len_change = false; + } + sample_bank[write_head] = input_block->data[k]; + write_head++; + } + + if (sample_loaded) { + //move it to the middle third of the bank. + //3 "seperate" banks are used + float fade_len = 20.00; + int16_t m2 = fade_len; + + for (int m = 0; m < 2; m++) { + // I'm off by one somewhere? why is there a tick at the + // beginning of this only when it's combined with the + // fade out???? ooor am i osbserving that incorrectly + // either wait it works enough + sample_bank[m + glitch_len] = 0; + } + + for (int m = 2; m < glitch_len - m2; m++) { + sample_bank[m + glitch_len] = sample_bank[m]; + } + + for (int m = glitch_len - m2; m < glitch_len; m++) { + // fade out the end. You can just make fadet=0 + // but it's a little too daleky + float fadet = sample_bank[m] * (m2 / fade_len); + sample_bank[m + glitch_len] = (int16_t)fadet; + m2--; + } + sample_loaded = false; + prev_input = output_block->data[k]; + sample_req = true; + } + + accumulator += playpack_rate; + read_head = (accumulator >> 16); + + if (read_head >= glitch_len) { + read_head -= glitch_len; + accumulator = 0; + + for (int m = 0; m < glitch_len; m++) { + sample_bank[m + (glitch_len * 2)] = sample_bank[m + glitch_len]; + // sample_bank[m + (glitch_len*2)] = (m%20)*1000; + } + } + output_block->data[k] = sample_bank[read_head + (glitch_len * 2)]; + } + } + //transmit(block); + //release(block); +} + diff --git a/src/noise-plethora/teensy/effect_granular.hpp b/src/noise-plethora/teensy/effect_granular.hpp new file mode 100644 index 0000000..8560b14 --- /dev/null +++ b/src/noise-plethora/teensy/effect_granular.hpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018 John-Michael Reed + * bleeplabs.com + * + * 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. + */ +#pragma once + +#include "audio_core.hpp" + +class AudioEffectGranular : public AudioStream { +public: + AudioEffectGranular(void): AudioStream(1) { } + + void begin(int16_t* sample_bank_def, int16_t max_len_def); + + void setSpeed(float ratio) { + if (ratio < 0.125f) + ratio = 0.125f; + else if (ratio > 8.0f) + ratio = 8.0f; + playpack_rate = ratio * 65536.0f + 0.499f; + } + + void beginFreeze(float grain_length) { + if (grain_length <= 0.0f) + return; + beginFreeze_int(grain_length * (APP->engine->getSampleRate() * 0.001f) + 0.5f); + } + + void beginPitchShift(float grain_length) { + if (grain_length <= 0.0f) + return; + beginPitchShift_int(grain_length * (APP->engine->getSampleRate() * 0.001f) + 0.5f); + } + + void stop(); + + void update(const audio_block_t* input_block, audio_block_t* output_block); + +private: + + void beginFreeze_int(int grain_samples); + void beginPitchShift_int(int grain_samples); + + int16_t* sample_bank; + uint32_t playpack_rate; + uint32_t accumulator; + int16_t max_sample_len; + int16_t write_head; + int16_t read_head; + int16_t grain_mode; + int16_t freeze_len; + int16_t prev_input; + int16_t glitch_len; + bool allow_len_change; + bool sample_loaded; + bool write_en; + bool sample_req; +}; + diff --git a/src/noise-plethora/teensy/effect_multiply.cpp b/src/noise-plethora/teensy/effect_multiply.cpp new file mode 100644 index 0000000..30f4d91 --- /dev/null +++ b/src/noise-plethora/teensy/effect_multiply.cpp @@ -0,0 +1,48 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +#include "effect_multiply.h" + + +void AudioEffectMultiply::update(const audio_block_t* blocka, const audio_block_t* blockb, audio_block_t* blockout) { + + const int16_t* pa, *pb, *end; + int16_t* out = blockout->data; + + if (!blocka || ! blockb || !blockout) { + return; + } + + pa = (blocka->data); + pb = (blockb->data); + end = pa + AUDIO_BLOCK_SAMPLES; + + while (pa < end) { + *out++ = (int16_t) signed_saturate_rshift(int32_t (*pa++) * int32_t (*pb++), 16, 15); + } + +} + diff --git a/src/noise-plethora/teensy/effect_multiply.h b/src/noise-plethora/teensy/effect_multiply.h new file mode 100644 index 0000000..c3ccaf7 --- /dev/null +++ b/src/noise-plethora/teensy/effect_multiply.h @@ -0,0 +1,35 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +#pragma once + +#include "audio_core.hpp" + +class AudioEffectMultiply : public AudioStream { +public: + AudioEffectMultiply() : AudioStream(2) { } + virtual void update(const audio_block_t* blocka, const audio_block_t* blockb, audio_block_t* blockout); +}; diff --git a/src/noise-plethora/teensy/effect_wavefolder.cpp b/src/noise-plethora/teensy/effect_wavefolder.cpp new file mode 100644 index 0000000..ba1cac1 --- /dev/null +++ b/src/noise-plethora/teensy/effect_wavefolder.cpp @@ -0,0 +1,49 @@ +/* Wavefolder effect for Teensy Audio library + * + * Copyright (c) 2020, Mark Tillotson + * + * 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, development funding 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. + */ + +#include "effect_wavefolder.hpp" + +void AudioEffectWaveFolder::update(const audio_block_t* blocka, const audio_block_t* blockb, audio_block_t* output) { + + if (!blocka || !blockb || !output) { + return; + } + + const int16_t* pa = blocka->data ; + const int16_t* pb = blockb->data ; + int16_t* po = output->data ; + + for (int i = 0 ; i < AUDIO_BLOCK_SAMPLES ; i++) { + int32_t a12 = pa[i]; + int32_t b12 = pb[i]; + + // scale upto 16 times input, so that can fold upto 16 times in each polarity + int32_t s1 = (a12 * b12 + 0x400) >> 11 ; + // if in a band where the sense needs to be reverse, detect this + bool flip1 = ((s1 + 0x8000) >> 16) & 1 ; + // reverse and truncate to 16 bits + s1 = 0xFFFF & (flip1 ? ~s1 : +s1) ; + + po[i] = s1; + } +} \ No newline at end of file diff --git a/src/noise-plethora/teensy/effect_wavefolder.hpp b/src/noise-plethora/teensy/effect_wavefolder.hpp new file mode 100644 index 0000000..b30c2cc --- /dev/null +++ b/src/noise-plethora/teensy/effect_wavefolder.hpp @@ -0,0 +1,32 @@ +/* Wavefolder effect for Teensy Audio library + * + * Copyright (c) 2020, Mark Tillotson + * + * 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, development funding 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. + */ + +#pragma once + +#include "audio_core.hpp" + +class AudioEffectWaveFolder : public AudioStream { +public: + AudioEffectWaveFolder() : AudioStream(2) {} + virtual void update(const audio_block_t* blocka, const audio_block_t* blockb, audio_block_t* output); +}; \ No newline at end of file diff --git a/src/noise-plethora/teensy/filter_variable.cpp b/src/noise-plethora/teensy/filter_variable.cpp new file mode 100644 index 0000000..3d4a0e7 --- /dev/null +++ b/src/noise-plethora/teensy/filter_variable.cpp @@ -0,0 +1,163 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +#include "filter_variable.hpp" + +// State Variable Filter (Chamberlin) with 2X oversampling +// http://www.musicdsp.org/showArchiveComment.php?ArchiveID=92 + +// The fast 32x32 with rshift32 discards 2 bits, which probably +// never matter. +//#define MULT(a, b) (int32_t)(((int64_t)(a) * (b)) >> 30) +#define MULT(a, b) (multiply_32x32_rshift32_rounded(a, b) << 2) + +// It's very unlikely anyone could hear any difference, but if you +// care deeply about numerical precision in seldom-used cases, +// uncomment this to improve the control signal accuracy +//#define IMPROVE_HIGH_FREQUENCY_ACCURACY + +// This increases the exponential approximation accuracy from +// about 0.341% error to only 0.012% error, which probably makes +// no audible difference. +//#define IMPROVE_EXPONENTIAL_ACCURACY + + +void AudioFilterStateVariable::update_fixed(const int16_t* in, int16_t* lp, int16_t* bp, int16_t* hp) { + const int16_t* end = in + AUDIO_BLOCK_SAMPLES; + int32_t input, inputprev; + int32_t lowpass, bandpass, highpass; + int32_t lowpasstmp, bandpasstmp, highpasstmp; + int32_t fmult, damp; + + fmult = setting_fmult; + damp = setting_damp; + inputprev = state_inputprev; + lowpass = state_lowpass; + bandpass = state_bandpass; + do { + input = (*in++) << 12; + lowpass = lowpass + MULT(fmult, bandpass); + highpass = ((input + inputprev) >> 1) - lowpass - MULT(damp, bandpass); + inputprev = input; + bandpass = bandpass + MULT(fmult, highpass); + lowpasstmp = lowpass; + bandpasstmp = bandpass; + highpasstmp = highpass; + lowpass = lowpass + MULT(fmult, bandpass); + highpass = input - lowpass - MULT(damp, bandpass); + bandpass = bandpass + MULT(fmult, highpass); + lowpasstmp = signed_saturate_rshift(lowpass + lowpasstmp, 16, 13); + bandpasstmp = signed_saturate_rshift(bandpass + bandpasstmp, 16, 13); + highpasstmp = signed_saturate_rshift(highpass + highpasstmp, 16, 13); + *lp++ = lowpasstmp; + *bp++ = bandpasstmp; + *hp++ = highpasstmp; + } while (in < end); + state_inputprev = inputprev; + state_lowpass = lowpass; + state_bandpass = bandpass; +} + + +void AudioFilterStateVariable::update_variable(const int16_t* in, const int16_t* ctl, int16_t* lp, int16_t* bp, int16_t* hp) { + const int16_t* end = in + AUDIO_BLOCK_SAMPLES; + int32_t input, inputprev, control; + int32_t lowpass, bandpass, highpass; + int32_t lowpasstmp, bandpasstmp, highpasstmp; + int32_t fcenter, fmult, damp, octavemult; + int32_t n; + + fcenter = setting_fcenter; + octavemult = setting_octavemult; + damp = setting_damp; + inputprev = state_inputprev; + lowpass = state_lowpass; + bandpass = state_bandpass; + do { + // compute fmult using control input, fcenter and octavemult + control = *ctl++; // signal is always 15 fractional bits + control *= octavemult; // octavemult range: 0 to 28671 (12 frac bits) + n = control & 0x7FFFFFF; // 27 fractional control bits +#ifdef IMPROVE_EXPONENTIAL_ACCURACY + // exp2 polynomial suggested by Stefan Stenzel on "music-dsp" + // mail list, Wed, 3 Sep 2014 10:08:55 +0200 + int32_t x = n << 3; + n = multiply_accumulate_32x32_rshift32_rounded(536870912, x, 1494202713); + int32_t sq = multiply_32x32_rshift32_rounded(x, x); + n = multiply_accumulate_32x32_rshift32_rounded(n, sq, 1934101615); + n = n + (multiply_32x32_rshift32_rounded(sq, + multiply_32x32_rshift32_rounded(x, 1358044250)) << 1); + n = n << 1; +#else + // exp2 algorithm by Laurent de Soras + // https://www.musicdsp.org/en/latest/Other/106-fast-exp2-approximation.html + n = (n + 134217728) << 3; + n = multiply_32x32_rshift32_rounded(n, n); + n = multiply_32x32_rshift32_rounded(n, 715827883) << 3; + n = n + 715827882; +#endif + n = n >> (6 - (control >> 27)); // 4 integer control bits + fmult = multiply_32x32_rshift32_rounded(fcenter, n); + if (fmult > 5378279) + fmult = 5378279; + fmult = fmult << 8; + // fmult is within 0.4% accuracy for all but the top 2 octaves + // of the audio band. This math improves accuracy above 5 kHz. + // Without this, the filter still works fine for processing + // high frequencies, but the filter's corner frequency response + // can end up about 6% higher than requested. +#ifdef IMPROVE_HIGH_FREQUENCY_ACCURACY + // From "Fast Polynomial Approximations to Sine and Cosine" + // Charles K Garrett, http://krisgarrett.net/ + fmult = (multiply_32x32_rshift32_rounded(fmult, 2145892402) + + multiply_32x32_rshift32_rounded( + multiply_32x32_rshift32_rounded(fmult, fmult), + multiply_32x32_rshift32_rounded(fmult, -1383276101))) << 1; +#endif + // now do the state variable filter as normal, using fmult + input = (*in++) << 12; + lowpass = lowpass + MULT(fmult, bandpass); + highpass = ((input + inputprev) >> 1) - lowpass - MULT(damp, bandpass); + inputprev = input; + bandpass = bandpass + MULT(fmult, highpass); + lowpasstmp = lowpass; + bandpasstmp = bandpass; + highpasstmp = highpass; + lowpass = lowpass + MULT(fmult, bandpass); + highpass = input - lowpass - MULT(damp, bandpass); + bandpass = bandpass + MULT(fmult, highpass); + lowpasstmp = signed_saturate_rshift(lowpass + lowpasstmp, 16, 13); + bandpasstmp = signed_saturate_rshift(bandpass + bandpasstmp, 16, 13); + highpasstmp = signed_saturate_rshift(highpass + highpasstmp, 16, 13); + *lp++ = lowpasstmp; + *bp++ = bandpasstmp; + *hp++ = highpasstmp; + } while (in < end); + state_inputprev = inputprev; + state_lowpass = lowpass; + state_bandpass = bandpass; +} + diff --git a/src/noise-plethora/teensy/filter_variable.hpp b/src/noise-plethora/teensy/filter_variable.hpp new file mode 100644 index 0000000..3a2113c --- /dev/null +++ b/src/noise-plethora/teensy/filter_variable.hpp @@ -0,0 +1,108 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +#pragma once + +#include "audio_core.hpp" + +class AudioFilterStateVariable: public AudioStream { +public: + AudioFilterStateVariable() : AudioStream(2) { + frequency(1000); + octaveControl(1.0); // default values + resonance(0.707); + state_inputprev = 0; + state_lowpass = 0; + state_bandpass = 0; + } + void frequency(float freq) { + // for reproducibility, max frequency cuts out at 2/5 Teensy sample rate + // (unless we're running at very low sample rates, in which case make sure we don't allow unstable f_c) + const float minFrequency = 20.f; + const float maxFrequency = std::min(AUDIO_SAMPLE_RATE_EXACT, APP->engine->getSampleRate()) / 2.5f; + + if (freq < minFrequency) { + freq = minFrequency; + } + else if (freq > maxFrequency) { + freq = maxFrequency; + } + setting_fcenter = (freq * (3.141592654f / (APP->engine->getSampleRate() * 2.0f))) + * 2147483647.0f; + // TODO: should we use an approximation when freq is not a const, + // so the sinf() function isn't linked? + setting_fmult = sinf(freq * (3.141592654f / (APP->engine->getSampleRate() * 2.0f))) + * 2147483647.0f; + } + void resonance(float q) { + if (q < 0.7f) + q = 0.7f; + else if (q > 5.0f) + q = 5.0f; + // TODO: allow lower Q when frequency is lower + setting_damp = (1.0f / q) * 1073741824.0f; + } + void octaveControl(float n) { + // filter's corner frequency is Fcenter * 2^(control * N) + // where "control" ranges from -1.0 to +1.0 + // and "N" allows the frequency to change from 0 to 7 octaves + if (n < 0.0f) + n = 0.0f; + else if (n > 6.9999f) + n = 6.9999f; + setting_octavemult = n * 4096.0f; + } + + void update(const audio_block_t* input_block, const audio_block_t* control_block, + audio_block_t* lowpass_block, audio_block_t* bandpass_block, audio_block_t* highpass_block) { + + if (control_block) { + update_variable(input_block->data, + control_block->data, + lowpass_block->data, + bandpass_block->data, + highpass_block->data); + } + else { + update_fixed(input_block->data, + lowpass_block->data, + bandpass_block->data, + highpass_block->data); + } + return; + } + +private: + void update_fixed(const int16_t* in, int16_t* lp, int16_t* bp, int16_t* hp); + void update_variable(const int16_t* in, const int16_t* ctl, int16_t* lp, int16_t* bp, int16_t* hp); + int32_t setting_fcenter; + int32_t setting_fmult; + int32_t setting_octavemult; + int32_t setting_damp; + int32_t state_inputprev; + int32_t state_lowpass; + int32_t state_bandpass; +}; diff --git a/src/noise-plethora/teensy/mixer.hpp b/src/noise-plethora/teensy/mixer.hpp new file mode 100644 index 0000000..0ec19fb --- /dev/null +++ b/src/noise-plethora/teensy/mixer.hpp @@ -0,0 +1,140 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +#pragma once + +#include "audio_core.hpp" + +#define MULTI_UNITYGAIN 256 + +static void applyGain(int16_t* data, int32_t mult) { + const int16_t* end = data + AUDIO_BLOCK_SAMPLES; + + do { + int32_t val = *data * mult; + *data++ = signed_saturate_rshift(val, 16, 0); + } while (data < end); +} + +static void applyGainThenAdd(int16_t* dst, const int16_t* src, int32_t mult) { + const int16_t* end = dst + AUDIO_BLOCK_SAMPLES; + + if (mult == MULTI_UNITYGAIN) { + do { + int32_t val = *dst + *src++; + *dst++ = signed_saturate_rshift(val, 16, 0); + } while (dst < end); + } + else { + do { + int32_t val = *dst + ((*src++ * mult) >> 8); // overflow possible?? + *dst++ = signed_saturate_rshift(val, 16, 0); + } while (dst < end); + } +} + +class AudioMixer4 : public AudioStream { +public: + AudioMixer4(void) : AudioStream(4) { + for (int i = 0; i < 4; i++) + multiplier[i] = 256; + } + + void update(const audio_block_t* in1, const audio_block_t* in2, const audio_block_t* in3, const audio_block_t* in4, audio_block_t* out) { + + if (!out) { + return; + } + else { + // zero buffer before processing + out->zeroAudioBlock(); + } + + if (in1) { + applyGainThenAdd(out->data, in1->data, multiplier[0]); + } + if (in2) { + applyGainThenAdd(out->data, in2->data, multiplier[1]); + } + if (in3) { + applyGainThenAdd(out->data, in3->data, multiplier[2]); + } + if (in4) { + applyGainThenAdd(out->data, in4->data, multiplier[3]); + } + } + + void gain(unsigned int channel, float gain) { + if (channel >= 4) + return; + if (gain > 127.0f) + gain = 127.0f; + else if (gain < -127.0f) + gain = -127.0f; + multiplier[channel] = gain * 256.0f; // TODO: proper roundoff? + } +private: + int16_t multiplier[4]; +}; + + +class AudioAmplifier : public AudioStream { +public: + AudioAmplifier(void) : AudioStream(1), multiplier(65536) { + } + + // acts in place + void update(audio_block_t* block) { + if (!block) { + return; + } + + int32_t mult = multiplier; + + if (mult == 0) { + // zero gain, discard any input and transmit nothing + memset(block->data, 0, sizeof(int16_t) * AUDIO_BLOCK_SAMPLES); + } + else if (mult == MULTI_UNITYGAIN) { + // unity gain, pass input to output without any change + return; + } + else { + // apply gain to signal + applyGain(block->data, mult); + } + } + + void gain(float n) { + if (n > 32767.0f) + n = 32767.0f; + else if (n < -32767.0f) + n = -32767.0f; + multiplier = n * 65536.0f; + } +private: + int32_t multiplier; +}; \ No newline at end of file diff --git a/src/noise-plethora/teensy/synth_dc.hpp b/src/noise-plethora/teensy/synth_dc.hpp new file mode 100644 index 0000000..8d03523 --- /dev/null +++ b/src/noise-plethora/teensy/synth_dc.hpp @@ -0,0 +1,201 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +#pragma once + +#include "audio_core.hpp" + +// compute (a - b) / c ... handling 32 bit interger overflow without slow 64 bit math +static inline int32_t substract_int32_then_divide_int32(int32_t a, int32_t b, int32_t c) __attribute__((always_inline, unused)); +static inline int32_t substract_int32_then_divide_int32(int32_t a, int32_t b, int32_t c) { + uint32_t diff; + uint8_t negative; + + if (a >= 0) { + if (b >= 0) { + return (a - b) / c; // no overflow if both a & b are positive + } + else { + diff = a + (b * -1); // assumes 0x80000000 * -1 == 0x80000000 + negative = 0; + } + } + else { + if (b >= 0) { + diff = (a * -1) + b; // assumes 0x80000000 * -1 == 0x80000000 + negative = 1; + } + else { + return (a - b) / c; // no overflow if both a & b are negative + } + } + if (c >= 0) { + diff = diff / (uint32_t)c; + } + else { + diff = diff / (uint32_t)(c * -1); + negative ^= 1; + } + if (negative) { + if (diff > 0x7FFFFFFF) + return 0x80000000; + return (int32_t)diff * -1; + } + else { + if (diff > 0x7FFFFFFF) + return 0x7FFFFFFF; + return (int32_t)diff; + } +} + + +class AudioSynthWaveformDc : public AudioStream { +public: + AudioSynthWaveformDc() : AudioStream(0), state(0), magnitude(0) {} + // immediately jump to the new DC level + void amplitude(float n) { + if (n > 1.0f) + n = 1.0f; + else if (n < -1.0f) + n = -1.0f; + int32_t m = (int32_t)(n * 2147418112.0f); + magnitude = m; + state = 0; + } + // slowly transition to the new DC level + void amplitude(float n, float milliseconds) { + if (milliseconds <= 0.0f) { + amplitude(n); + return; + } + if (n > 1.0f) + n = 1.0f; + else if (n < -1.0f) + n = -1.0f; + int32_t c = (int32_t)(milliseconds * (AUDIO_SAMPLE_RATE_EXACT / 1000.0f)); + if (c == 0) { + amplitude(n); + return; + } + int32_t t = (int32_t)(n * 2147418112.0f); + target = t; + if (target == magnitude) { + state = 0; + return; + } + increment = substract_int32_then_divide_int32(target, magnitude, c); + if (increment == 0) { + increment = (target > magnitude) ? 1 : -1; + } + state = 1; + } + float read(void) { + int32_t m = magnitude; + return (float)m * (float)(1.0 / 2147418112.0); + } + void update(audio_block_t* block) { + uint32_t* p, *end, val; + int32_t count, t1, t2, t3, t4; + + if (!block) { + return; + } + p = (uint32_t*)(block->data); + end = p + AUDIO_BLOCK_SAMPLES / 2; + + if (state == 0) { + // steady DC output, simply fill the buffer with fixed value + val = pack_16t_16t(magnitude, magnitude); + do { + *p++ = val; + *p++ = val; + *p++ = val; + *p++ = val; + *p++ = val; + *p++ = val; + *p++ = val; + *p++ = val; + } while (p < end); + } + else { + // transitioning to a new DC level + //count = (target - magnitude) / increment; + count = substract_int32_then_divide_int32(target, magnitude, increment); + if (count >= AUDIO_BLOCK_SAMPLES) { + // this update will not reach the target + do { + magnitude += increment; + t1 = magnitude; + magnitude += increment; + t1 = pack_16t_16t(magnitude, t1); + magnitude += increment; + t2 = magnitude; + magnitude += increment; + t2 = pack_16t_16t(magnitude, t2); + magnitude += increment; + t3 = magnitude; + magnitude += increment; + t3 = pack_16t_16t(magnitude, t3); + magnitude += increment; + t4 = magnitude; + magnitude += increment; + t4 = pack_16t_16t(magnitude, t4); + *p++ = t1; + *p++ = t2; + *p++ = t3; + *p++ = t4; + } while (p < end); + } + else { + // this update reaches the target + while (count >= 2) { + count -= 2; + magnitude += increment; + t1 = magnitude; + magnitude += increment; + t1 = pack_16t_16t(magnitude, t1); + *p++ = t1; + } + if (count) { + t1 = pack_16t_16t(target, magnitude + increment); + *p++ = t1; + } + magnitude = target; + state = 0; + val = pack_16t_16t(magnitude, magnitude); + while (p < end) { + *p++ = val; + } + } + } + } + +private: + uint8_t state; // 0=steady output, 1=transitioning + int32_t magnitude; // current output + int32_t target; // designed output (while transitiong) + int32_t increment; // adjustment per sample (while transitiong) +}; diff --git a/src/noise-plethora/teensy/synth_pinknoise.cpp b/src/noise-plethora/teensy/synth_pinknoise.cpp new file mode 100644 index 0000000..2046d62 --- /dev/null +++ b/src/noise-plethora/teensy/synth_pinknoise.cpp @@ -0,0 +1,147 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +// http://stenzel.waldorfmusic.de/post/pink/ +// https://github.com/Stenzel/newshadeofpink +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// New Shade of Pink +// (c) 2014 Stefan Stenzel +// stefan at waldorfmusic.de +// +// Terms of use: +// Use for any purpose. If used in a commercial product, you should give me one. +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +#include "synth_pinknoise.hpp" + +int16_t AudioSynthNoisePink::instance_cnt = 0; + +// Let preprocessor and compiler calculate two lookup tables for 12-tap FIR Filter +// with these coefficients: 1.190566, 0.162580, 0.002208, 0.025475, -0.001522, +// 0.007322, 0.001774, 0.004529, -0.001561, 0.000776, -0.000486, 0.002017 +#define Fn(cf,m,shift) (2048*cf*(2*((m)>>shift&1)-1)) +#define FA(n) (int32_t)(Fn(1.190566,n,0)+Fn(0.162580,n,1)+Fn(0.002208,n,2)+\ + Fn(0.025475,n,3)+Fn(-0.001522,n,4)+Fn(0.007322,n,5)) +#define FB(n) (int32_t)(Fn(0.001774,n,0)+Fn(0.004529,n,1)+Fn(-0.001561,n,2)+\ + Fn(0.000776,n,3)+Fn(-0.000486,n,4)+Fn(0.002017,n,5)) +#define FA8(n) FA(n),FA(n+1),FA(n+2),FA(n+3),FA(n+4),FA(n+5),FA(n+6),FA(n+7) +#define FB8(n) FB(n),FB(n+1),FB(n+2),FB(n+3),FB(n+4),FB(n+5),FB(n+6),FB(n+7) +const int32_t AudioSynthNoisePink::pfira[64] = // 1st FIR lookup table +{FA8(0), FA8(8), FA8(16), FA8(24), FA8(32), FA8(40), FA8(48), FA8(56)}; +const int32_t AudioSynthNoisePink::pfirb[64] = // 2nd FIR lookup table +{FB8(0), FB8(8), FB8(16), FB8(24), FB8(32), FB8(40), FB8(48), FB8(56)}; + +// bitreversed lookup table +#define PM16(n) n,0x80,0x40,0x80,0x20,0x80,0x40,0x80,0x10,0x80,0x40,0x80,0x20,0x80,0x40,0x80 +const uint8_t AudioSynthNoisePink::pnmask[256] = { + PM16(0), PM16(8), PM16(4), PM16(8), PM16(2), PM16(8), PM16(4), PM16(8), + PM16(1), PM16(8), PM16(4), PM16(8), PM16(2), PM16(8), PM16(4), PM16(8) +}; + +#define PINT(bitmask, out) /* macro for processing: */\ + bit = lfsr >> 31; /* spill random to all bits */\ + dec &= ~bitmask; /* blank old decrement bit */\ + lfsr <<= 1; /* shift lfsr */\ + dec |= inc & bitmask; /* copy increment to decrement bit */\ + inc ^= bit & bitmask; /* new random bit */\ + accu += inc - dec; /* integrate */\ + lfsr ^= bit & taps; /* update lfsr */\ + out = accu + /* save output */\ + pfira[lfsr & 0x3F] + /* add 1st half precalculated FIR */\ + pfirb[lfsr >> 6 & 0x3F] /* add 2nd half, also correts bias */ + +void AudioSynthNoisePink::update(audio_block_t* block) { + uint32_t* p, *end; + int32_t n1, n2; + int32_t gain; + int32_t inc, dec, accu, bit, lfsr; + int32_t taps; + + gain = level; + if (gain == 0) + return; + + if (!block) + return; + p = (uint32_t*)(block->data); + end = p + AUDIO_BLOCK_SAMPLES / 2; + taps = 0x46000001; + inc = pinc; + dec = pdec; + accu = paccu; + lfsr = plfsr; + do { + int32_t mask = pnmask[pncnt++]; + PINT(mask, n1); + n1 = signed_multiply_32x16b(gain, n1); + PINT(0x0800, n2); + n2 = signed_multiply_32x16b(gain, n2); + *p++ = pack_16b_16b(n2, n1); + PINT(0x0400, n1); + n1 = signed_multiply_32x16b(gain, n1); + PINT(0x0800, n2); + n2 = signed_multiply_32x16b(gain, n2); + *p++ = pack_16b_16b(n2, n1); + PINT(0x0200, n1); + n1 = signed_multiply_32x16b(gain, n1); + PINT(0x0800, n2); + n2 = signed_multiply_32x16b(gain, n2); + *p++ = pack_16b_16b(n2, n1); + PINT(0x0400, n1); + n1 = signed_multiply_32x16b(gain, n1); + PINT(0x0800, n2); + n2 = signed_multiply_32x16b(gain, n2); + *p++ = pack_16b_16b(n2, n1); + PINT(0x0100, n1); + n1 = signed_multiply_32x16b(gain, n1); + PINT(0x0800, n2); + n2 = signed_multiply_32x16b(gain, n2); + *p++ = pack_16b_16b(n2, n1); + PINT(0x0400, n1); + n1 = signed_multiply_32x16b(gain, n1); + PINT(0x0800, n2); + n2 = signed_multiply_32x16b(gain, n2); + *p++ = pack_16b_16b(n2, n1); + PINT(0x0200, n1); + n1 = signed_multiply_32x16b(gain, n1); + PINT(0x0800, n2); + n2 = signed_multiply_32x16b(gain, n2); + *p++ = pack_16b_16b(n2, n1); + PINT(0x0400, n1); + n1 = signed_multiply_32x16b(gain, n1); + PINT(0x0800, n2); + n2 = signed_multiply_32x16b(gain, n2); + *p++ = pack_16b_16b(n2, n1); + } while (p < end); + pinc = inc; + pdec = dec; + paccu = accu; + plfsr = lfsr; +} + + + diff --git a/src/noise-plethora/teensy/synth_pinknoise.hpp b/src/noise-plethora/teensy/synth_pinknoise.hpp new file mode 100644 index 0000000..f2f42c5 --- /dev/null +++ b/src/noise-plethora/teensy/synth_pinknoise.hpp @@ -0,0 +1,59 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +#pragma once + +#include "audio_core.hpp" + +class AudioSynthNoisePink : public AudioStream { +public: + AudioSynthNoisePink() : AudioStream(0) { + plfsr = 0x5EED41F5 + instance_cnt++; + paccu = 0; + pncnt = 0; + pinc = 0x0CCC; + pdec = 0x0CCC; + } + void amplitude(float n) { + if (n < 0.0f) + n = 0.0; + else if (n > 1.0f) + n = 1.0f; + level = (int32_t)(n * 65536.0f); + } + virtual void update(audio_block_t* block); +private: + static const uint8_t pnmask[256]; + static const int32_t pfira[64]; + static const int32_t pfirb[64]; + static int16_t instance_cnt; + int32_t plfsr; // linear feedback shift register + int32_t pinc; // increment for all noise sources (bits) + int32_t pdec; // decrement for all noise sources + int32_t paccu; // accumulator + uint8_t pncnt; // overflowing counter as index to pnmask[] + int32_t level; // 0=off, 65536=max +}; diff --git a/src/noise-plethora/teensy/synth_pwm.cpp b/src/noise-plethora/teensy/synth_pwm.cpp new file mode 100644 index 0000000..611bb53 --- /dev/null +++ b/src/noise-plethora/teensy/synth_pwm.cpp @@ -0,0 +1,89 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2017, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +#include "synth_pwm.hpp" +#include "dspinst.h" + + +void AudioSynthWaveformPWM::update(const audio_block_t* modinput, audio_block_t* block) { + uint32_t i; + int32_t out; + + if (!block) { + return; + } + else if (magnitude == 0) { + block->zeroAudioBlock(); + } + + if (modinput) { + const uint32_t _duration = duration; + uint32_t _elapsed = elapsed; + int32_t _magnitude = magnitude; + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + _elapsed += 65536; + int32_t in = modinput->data[i]; + if (_magnitude < 0) + in = -in; + uint32_t dur = ((uint64_t)(in + 32768) * _duration) >> 15; + if (_elapsed < dur) { + out = _magnitude; + } + else { + int32_t e = _elapsed - dur; + signed_saturate_rshift(e, 17, 0); + if (e < 0) + e = 0; + _elapsed = e; + // elapsed must be 0 to 65535 + // magnitude must be -32767 to +32767 + out = _magnitude - ((_magnitude * _elapsed) >> 15); + _magnitude = -_magnitude; + } + block->data[i] = out; + } + elapsed = _elapsed; + magnitude = _magnitude; + + } + else { + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + elapsed += 65536; + if (elapsed < duration) { + out = magnitude; + } + else { + elapsed -= duration; + // elapsed must be 0 to 65535 + // magnitude must be -32767 to +32767 + out = magnitude - ((magnitude * elapsed) >> 15); + magnitude = -magnitude; + } + block->data[i] = out; + } + } +} + diff --git a/src/noise-plethora/teensy/synth_pwm.hpp b/src/noise-plethora/teensy/synth_pwm.hpp new file mode 100644 index 0000000..cf79480 --- /dev/null +++ b/src/noise-plethora/teensy/synth_pwm.hpp @@ -0,0 +1,61 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2017, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +#pragma once + +#include "audio_core.hpp" + +class AudioSynthWaveformPWM : public AudioStream { +public: + AudioSynthWaveformPWM() : AudioStream(1), magnitude(0), elapsed(0) {} + void frequency(float freq) { + + // for reproducibility, max frequency cuts out at 1/2 Teensy sample rate + // (unless we're running at very low sample rates, in which case use those to limit range) + const float maxFrequency = std::min(AUDIO_SAMPLE_RATE_EXACT, APP->engine->getSampleRate()) / 4.0f; + + if (freq < 1.0) { + freq = 1.0; + } + else if (freq > maxFrequency) { + freq = maxFrequency; + } + //phase_increment = freq * (4294967296.0f / AUDIO_SAMPLE_RATE_EXACT); + duration = (APP->engine->getSampleRate() * 65536.0f + freq) / (freq * 2.0f); + } + void amplitude(float n) { + if (n < 0.0f) + n = 0; + else if (n > 1.0f) + n = 1.0f; + magnitude = n * 32767.0f; + } + virtual void update(const audio_block_t* modinput, audio_block_t* block); +private: + uint32_t duration; // samples per half cycle (when 50% duty) * 65536 + int32_t magnitude; + uint32_t elapsed; +}; \ No newline at end of file diff --git a/src/noise-plethora/teensy/synth_sine.hpp b/src/noise-plethora/teensy/synth_sine.hpp new file mode 100644 index 0000000..06f6e8b --- /dev/null +++ b/src/noise-plethora/teensy/synth_sine.hpp @@ -0,0 +1,188 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +#pragma once + +#include "audio_core.hpp" + + +// TODO: investigate making a high resolution sine wave +// using Taylor series expansion. +// http://www.musicdsp.org/showone.php?id=13 + +class AudioSynthWaveformSine : public AudioStream { +public: + AudioSynthWaveformSine() : AudioStream(0), magnitude(16384) {} + void frequency(float freq) { + + // for reproducibility, max frequency cuts out at 1/2 Teensy sample rate + // (unless we're running at very low sample rates, in which case use those to limit range) + const float maxFrequency = std::min(AUDIO_SAMPLE_RATE_EXACT, APP->engine->getSampleRate()) / 2.0f; + + if (freq < 0.0f) + freq = 0.0; + else if (freq > maxFrequency) + freq = maxFrequency; + phase_increment = freq * (4294967296.0f / APP->engine->getSampleRate()); + } + void phase(float angle) { + if (angle < 0.0f) + angle = 0.0f; + else if (angle > 360.0f) { + angle = angle - 360.0f; + if (angle >= 360.0f) + return; + } + phase_accumulator = angle * (float)(4294967296.0 / 360.0); + } + void amplitude(float n) { + if (n < 0.0f) + n = 0; + else if (n > 1.0f) + n = 1.0f; + magnitude = n * 65536.0f; + } + void update(audio_block_t* block) { + uint32_t i, ph, inc, index, scale; + int32_t val1, val2; + + if (magnitude) { + if (block) { + ph = phase_accumulator; + inc = phase_increment; + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + index = ph >> 24; + val1 = AudioWaveformSine[index]; + val2 = AudioWaveformSine[index + 1]; + scale = (ph >> 8) & 0xFFFF; + val2 *= scale; + val1 *= 0x10000 - scale; + block->data[i] = (((val1 + val2) >> 16) * magnitude) >> 16; + ph += inc; + } + phase_accumulator = ph; + return; + } + } + phase_accumulator += phase_increment * AUDIO_BLOCK_SAMPLES; + } +private: + uint32_t phase_accumulator; + uint32_t phase_increment; + int32_t magnitude; +}; + + + + +class AudioSynthWaveformSineModulated : public AudioStream { +public: + AudioSynthWaveformSineModulated() : AudioStream(1), magnitude(16384) {} + // maximum unmodulated carrier frequency is 11025 Hz + // input = +1.0 doubles carrier + // input = -1.0 DC output + void frequency(float freq) { + + // for reproducibility, max frequency cuts out at 1/4 Teensy sample rate + // (unless we're running at very low sample rates, in which case use those to limit range) + const float maxFrequency = std::min(AUDIO_SAMPLE_RATE_EXACT, APP->engine->getSampleRate()) / 4.0f; + + if (freq < 0.0f) + freq = 0.0f; + else if (freq > maxFrequency) + freq = maxFrequency; + phase_increment = freq * (4294967296.0f / APP->engine->getSampleRate()); + } + void phase(float angle) { + if (angle < 0.0f) + angle = 0.0; + else if (angle > 360.0f) { + angle = angle - 360.0f; + if (angle >= 360.0f) + return; + } + phase_accumulator = angle * (float)(4294967296.0 / 360.0); + } + + void amplitude(float n) { + if (n < 0.0f) + n = 0; + else if (n > 1.0f) + n = 1.0f; + magnitude = n * 65536.0f; + } + + void update(const audio_block_t* modinput, audio_block_t* block) { + + uint32_t i, ph, inc, index, scale; + int32_t val1, val2; + int16_t mod; + + ph = phase_accumulator; + inc = phase_increment; + if (!block) { + // unable to allocate memory, so we'll send nothing + return; + } + if (modinput) { + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + index = ph >> 24; + val1 = AudioWaveformSine[index]; + val2 = AudioWaveformSine[index + 1]; + scale = (ph >> 8) & 0xFFFF; + val2 *= scale; + val1 *= 0x10000 - scale; + //block->data[i] = (((val1 + val2) >> 16) * magnitude) >> 16; + block->data[i] = multiply_32x32_rshift32(val1 + val2, magnitude); + // -32768 = no phase increment + // 32767 = double phase increment + mod = modinput->data[i]; + ph += inc + (multiply_32x32_rshift32(inc, mod << 16) << 1); + //ph += inc + (((int64_t)inc * (mod << 16)) >> 31); + } + } + else { + ph = phase_accumulator; + inc = phase_increment; + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + index = ph >> 24; + val1 = AudioWaveformSine[index]; + val2 = AudioWaveformSine[index + 1]; + scale = (ph >> 8) & 0xFFFF; + val2 *= scale; + val1 *= 0x10000 - scale; + block->data[i] = multiply_32x32_rshift32(val1 + val2, magnitude); + ph += inc; + } + } + phase_accumulator = ph; + } +private: + uint32_t phase_accumulator; + uint32_t phase_increment; + int32_t magnitude; +}; + diff --git a/src/noise-plethora/teensy/synth_waveform.hpp b/src/noise-plethora/teensy/synth_waveform.hpp new file mode 100644 index 0000000..0b8956c --- /dev/null +++ b/src/noise-plethora/teensy/synth_waveform.hpp @@ -0,0 +1,553 @@ +#pragma once + +#include "audio_core.hpp" + +class AudioSynthWaveform : public AudioStream { +public: + AudioSynthWaveform(void) : AudioStream(0), + phase_accumulator(0), phase_increment(0), phase_offset(0), + magnitude(0), pulse_width(0x40000000), + arbdata(NULL), sample(0), tone_type(WAVEFORM_SINE), + tone_offset(0) { + } + + void frequency(float freq) { + + // for reproducibility, max frequency cuts out at 1/2 Teensy sample rate + // (unless we're running at very low sample rates, in which case use those to limit range) + const float maxFrequency = std::min(AUDIO_SAMPLE_RATE_EXACT, APP->engine->getSampleRate()) / 2.0f; + + if (freq < 0.0f) { + freq = 0.0; + } + else if (freq > maxFrequency) { + freq = maxFrequency; + } + phase_increment = freq * (4294967296.0f / APP->engine->getSampleRate()); + if (phase_increment > 0x7FFE0000u) + phase_increment = 0x7FFE0000; + } + void phase(float angle) { + if (angle < 0.0f) { + angle = 0.0; + } + else if (angle > 360.0f) { + angle = angle - 360.0f; + if (angle >= 360.0f) + return; + } + phase_offset = angle * (float)(4294967296.0 / 360.0); + } + void amplitude(float n) { // 0 to 1.0 + if (n < 0) { + n = 0; + } + else if (n > 1.0f) { + n = 1.0; + } + magnitude = n * 65536.0f; + } + void offset(float n) { + if (n < -1.0f) { + n = -1.0f; + } + else if (n > 1.0f) { + n = 1.0f; + } + tone_offset = n * 32767.0f; + } + void pulseWidth(float n) { // 0.0 to 1.0 + if (n < 0) { + n = 0; + } + else if (n > 1.0f) { + n = 1.0f; + } + pulse_width = n * 4294967296.0f; + } + void begin(short t_type) { + phase_offset = 0; + tone_type = t_type; + } + void begin(float t_amp, float t_freq, short t_type) { + amplitude(t_amp); + frequency(t_freq); + phase_offset = 0; + begin(t_type); + } + + void arbitraryWaveform(const int16_t* data, float maxFreq) { + arbdata = data; + } + + void update(audio_block_t* block) { + + int16_t* bp, *end; + int32_t val1, val2; + int16_t magnitude15; + uint32_t i, ph, index, index2, scale; + const uint32_t inc = phase_increment; + + ph = phase_accumulator + phase_offset; + if (magnitude == 0) { + phase_accumulator += inc * AUDIO_BLOCK_SAMPLES; + return; + } + + if (!block) { + phase_accumulator += inc * AUDIO_BLOCK_SAMPLES; + return; + } + bp = block->data; + + switch (tone_type) { + case WAVEFORM_SINE: + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + index = ph >> 24; + val1 = AudioWaveformSine[index]; + val2 = AudioWaveformSine[index + 1]; + scale = (ph >> 8) & 0xFFFF; + val2 *= scale; + val1 *= 0x10000 - scale; + *bp++ = multiply_32x32_rshift32(val1 + val2, magnitude); + ph += inc; + } + break; + + case WAVEFORM_ARBITRARY: + if (!arbdata) { + phase_accumulator += inc * AUDIO_BLOCK_SAMPLES; + return; + } + // len = 256 + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + index = ph >> 24; + index2 = index + 1; + if (index2 >= 256) + index2 = 0; + val1 = *(arbdata + index); + val2 = *(arbdata + index2); + scale = (ph >> 8) & 0xFFFF; + val2 *= scale; + val1 *= 0x10000 - scale; + *bp++ = multiply_32x32_rshift32(val1 + val2, magnitude); + ph += inc; + } + break; + + case WAVEFORM_SQUARE: + magnitude15 = signed_saturate_rshift(magnitude, 16, 1); + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + if (ph & 0x80000000) { + *bp++ = -magnitude15; + } + else { + *bp++ = magnitude15; + } + ph += inc; + } + break; + + case WAVEFORM_SAWTOOTH: + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + *bp++ = signed_multiply_32x16t(magnitude, ph); + ph += inc; + } + break; + + case WAVEFORM_SAWTOOTH_REVERSE: + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + *bp++ = signed_multiply_32x16t(0xFFFFFFFFu - magnitude, ph); + ph += inc; + } + break; + + case WAVEFORM_TRIANGLE: + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + uint32_t phtop = ph >> 30; + if (phtop == 1 || phtop == 2) { + *bp++ = ((0xFFFF - (ph >> 15)) * magnitude) >> 16; + } + else { + *bp++ = (((int32_t)ph >> 15) * magnitude) >> 16; + } + ph += inc; + } + break; + + case WAVEFORM_TRIANGLE_VARIABLE: + do { + uint32_t rise = 0xFFFFFFFF / (pulse_width >> 16); + uint32_t fall = 0xFFFFFFFF / (0xFFFF - (pulse_width >> 16)); + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + if (ph < pulse_width / 2) { + uint32_t n = (ph >> 16) * rise; + *bp++ = ((n >> 16) * magnitude) >> 16; + } + else if (ph < 0xFFFFFFFF - pulse_width / 2) { + uint32_t n = 0x7FFFFFFF - (((ph - pulse_width / 2) >> 16) * fall); + *bp++ = (((int32_t)n >> 16) * magnitude) >> 16; + } + else { + uint32_t n = ((ph + pulse_width / 2) >> 16) * rise + 0x80000000; + *bp++ = (((int32_t)n >> 16) * magnitude) >> 16; + } + ph += inc; + } + } while (0); + break; + + case WAVEFORM_PULSE: + magnitude15 = signed_saturate_rshift(magnitude, 16, 1); + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + if (ph < pulse_width) { + *bp++ = magnitude15; + } + else { + *bp++ = -magnitude15; + } + ph += inc; + } + break; + + case WAVEFORM_SAMPLE_HOLD: + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + *bp++ = sample; + uint32_t newph = ph + inc; + if (newph < ph) { + sample = teensy::random_teensy(magnitude) - (magnitude >> 1); + } + ph = newph; + } + break; + } + phase_accumulator = ph - phase_offset; + + if (tone_offset) { + bp = block->data; + end = bp + AUDIO_BLOCK_SAMPLES; + do { + val1 = *bp; + *bp++ = signed_saturate_rshift(val1 + tone_offset, 16, 0); + } while (bp < end); + } + } + +private: + uint32_t phase_accumulator; + uint32_t phase_increment; + uint32_t phase_offset; + int32_t magnitude; + uint32_t pulse_width; + const int16_t* arbdata; + int16_t sample; // for WAVEFORM_SAMPLE_HOLD + short tone_type; + int16_t tone_offset; +}; + +class AudioSynthWaveformModulated : public AudioStream { +public: + AudioSynthWaveformModulated(void) : AudioStream(2), + phase_accumulator(0), phase_increment(0), modulation_factor(32768), + magnitude(0), arbdata(NULL), sample(0), tone_offset(0), + tone_type(WAVEFORM_SINE), modulation_type(0) { + } + + void frequency(float freq) { + + // for reproducibility, max frequency cuts out at 1/2 Teensy sample rate + // (unless we're running at very low sample rates, in which case use those to limit range) + const float maxFrequency = std::min(AUDIO_SAMPLE_RATE_EXACT, APP->engine->getSampleRate()) / 2.0f; + + if (freq < 0.0f) { + freq = 0.0; + } + else if (freq > maxFrequency) { + freq = maxFrequency; + } + phase_increment = freq * (4294967296.0f / APP->engine->getSampleRate()); + if (phase_increment > 0x7FFE0000u) + phase_increment = 0x7FFE0000; + } + void amplitude(float n) { // 0 to 1.0 + if (n < 0) { + n = 0; + } + else if (n > 1.0f) { + n = 1.0f; + } + magnitude = n * 65536.0f; + } + void offset(float n) { + if (n < -1.0f) { + n = -1.0f; + } + else if (n > 1.0f) { + n = 1.0f; + } + tone_offset = n * 32767.0f; + } + void begin(short t_type) { + tone_type = t_type; + // band-limited waveforms not used + } + void begin(float t_amp, float t_freq, short t_type) { + amplitude(t_amp); + frequency(t_freq); + begin(t_type) ; + } + void arbitraryWaveform(const int16_t* data, float maxFreq) { + arbdata = data; + } + void frequencyModulation(float octaves) { + if (octaves > 12.0f) { + octaves = 12.0f; + } + else if (octaves < 0.1f) { + octaves = 0.1f; + } + modulation_factor = octaves * 4096.0f; + modulation_type = 0; + } + void phaseModulation(float degrees) { + if (degrees > 9000.0f) { + degrees = 9000.0f; + } + else if (degrees < 30.0f) { + degrees = 30.0f; + } + modulation_factor = degrees * (float)(65536.0 / 180.0); + modulation_type = 1; + } + + void update(audio_block_t* moddata, audio_block_t* shapedata, audio_block_t* block) { + + int16_t* bp, *end; + int32_t val1, val2; + int16_t magnitude15; + uint32_t i, ph, index, index2, scale, priorphase; + const uint32_t inc = phase_increment; + + if (!block) { + return; + } + + // Pre-compute the phase angle for every output sample of this update + ph = phase_accumulator; + priorphase = phasedata[AUDIO_BLOCK_SAMPLES - 1]; + if (moddata && modulation_type == 0) { + // Frequency Modulation + bp = moddata->data; + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + int32_t n = (*bp++) * modulation_factor; // n is # of octaves to mod + int32_t ipart = n >> 27; // 4 integer bits + n &= 0x7FFFFFF; // 27 fractional bits +#ifdef IMPROVE_EXPONENTIAL_ACCURACY + // exp2 polynomial suggested by Stefan Stenzel on "music-dsp" + // mail list, Wed, 3 Sep 2014 10:08:55 +0200 + int32_t x = n << 3; + n = multiply_accumulate_32x32_rshift32_rounded(536870912, x, 1494202713); + int32_t sq = multiply_32x32_rshift32_rounded(x, x); + n = multiply_accumulate_32x32_rshift32_rounded(n, sq, 1934101615); + n = n + (multiply_32x32_rshift32_rounded(sq, + multiply_32x32_rshift32_rounded(x, 1358044250)) << 1); + n = n << 1; +#else + // exp2 algorithm by Laurent de Soras + // https://www.musicdsp.org/en/latest/Other/106-fast-exp2-approximation.html + n = (n + 134217728) << 3; + + n = multiply_32x32_rshift32_rounded(n, n); + n = multiply_32x32_rshift32_rounded(n, 715827883) << 3; + n = n + 715827882; +#endif + uint32_t scale = n >> (14 - ipart); + uint64_t phstep = (uint64_t)inc * scale; + uint32_t phstep_msw = phstep >> 32; + if (phstep_msw < 0x7FFE) { + ph += phstep >> 16; + } + else { + ph += 0x7FFE0000; + } + phasedata[i] = ph; + } + } + else if (moddata) { + // Phase Modulation + bp = moddata->data; + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + // more than +/- 180 deg shift by 32 bit overflow of "n" + uint32_t n = ((uint32_t)(*bp++)) * modulation_factor; + phasedata[i] = ph + n; + ph += inc; + } + } + else { + // No Modulation Input + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + phasedata[i] = ph; + ph += inc; + } + } + phase_accumulator = ph; + + bp = block->data; + + // Now generate the output samples using the pre-computed phase angles + switch (tone_type) { + case WAVEFORM_SINE: + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + ph = phasedata[i]; + index = ph >> 24; + val1 = AudioWaveformSine[index]; + val2 = AudioWaveformSine[index + 1]; + scale = (ph >> 8) & 0xFFFF; + val2 *= scale; + val1 *= 0x10000 - scale; + *bp++ = multiply_32x32_rshift32(val1 + val2, magnitude); + } + break; + + case WAVEFORM_ARBITRARY: + if (!arbdata) { + block->zeroAudioBlock(); + return; + } + // len = 256 + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + ph = phasedata[i]; + index = ph >> 24; + index2 = index + 1; + if (index2 >= 256) + index2 = 0; + val1 = *(arbdata + index); + val2 = *(arbdata + index2); + scale = (ph >> 8) & 0xFFFF; + val2 *= scale; + val1 *= 0x10000 - scale; + *bp++ = multiply_32x32_rshift32(val1 + val2, magnitude); + } + break; + + case WAVEFORM_PULSE: + if (shapedata) { + magnitude15 = signed_saturate_rshift(magnitude, 16, 1); + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + uint32_t width = ((shapedata->data[i] + 0x8000) & 0xFFFF) << 16; + if (phasedata[i] < width) { + *bp++ = magnitude15; + } + else { + *bp++ = -magnitude15; + } + } + break; + } // else fall through to orginary square without shape modulation + // fall through + case WAVEFORM_SQUARE: + magnitude15 = signed_saturate_rshift(magnitude, 16, 1); + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + if (phasedata[i] & 0x80000000) { + *bp++ = -magnitude15; + } + else { + *bp++ = magnitude15; + } + } + break; + + case WAVEFORM_SAWTOOTH: + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + *bp++ = signed_multiply_32x16t(magnitude, phasedata[i]); + } + break; + + case WAVEFORM_SAWTOOTH_REVERSE: + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + *bp++ = signed_multiply_32x16t(0xFFFFFFFFu - magnitude, phasedata[i]); + } + break; + + case WAVEFORM_TRIANGLE_VARIABLE: + if (shapedata) { + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + uint32_t width = (shapedata->data[i] + 0x8000) & 0xFFFF; + uint32_t rise = 0xFFFFFFFF / width; + uint32_t fall = 0xFFFFFFFF / (0xFFFF - width); + uint32_t halfwidth = width << 15; + uint32_t n; + ph = phasedata[i]; + if (ph < halfwidth) { + n = (ph >> 16) * rise; + *bp++ = ((n >> 16) * magnitude) >> 16; + } + else if (ph < 0xFFFFFFFF - halfwidth) { + n = 0x7FFFFFFF - (((ph - halfwidth) >> 16) * fall); + *bp++ = (((int32_t)n >> 16) * magnitude) >> 16; + } + else { + n = ((ph + halfwidth) >> 16) * rise + 0x80000000; + *bp++ = (((int32_t)n >> 16) * magnitude) >> 16; + } + ph += inc; + } + break; + } // else fall through to orginary triangle without shape modulation + // fall through + case WAVEFORM_TRIANGLE: + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + ph = phasedata[i]; + uint32_t phtop = ph >> 30; + if (phtop == 1 || phtop == 2) { + *bp++ = ((0xFFFF - (ph >> 15)) * magnitude) >> 16; + } + else { + *bp++ = (((int32_t)ph >> 15) * magnitude) >> 16; + } + } + break; + case WAVEFORM_SAMPLE_HOLD: + for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { + ph = phasedata[i]; + if (ph < priorphase) { // does not work for phase modulation + sample = teensy::random_teensy(magnitude) - (magnitude >> 1); + } + priorphase = ph; + *bp++ = sample; + } + break; + } + + if (tone_offset) { + bp = block->data; + end = bp + AUDIO_BLOCK_SAMPLES; + do { + val1 = *bp; + *bp++ = signed_saturate_rshift(val1 + tone_offset, 16, 0); + } while (bp < end); + } + /* + if (shapedata) + release(shapedata); + transmit(block, 0); + release(block); + */ + } + +private: + + uint32_t phase_accumulator; + uint32_t phase_increment; + uint32_t modulation_factor; + int32_t magnitude; + const int16_t* arbdata; + uint32_t phasedata[AUDIO_BLOCK_SAMPLES]; + + int16_t sample; // for WAVEFORM_SAMPLE_HOLD + int16_t tone_offset; + uint8_t tone_type; + uint8_t modulation_type; + +}; + diff --git a/src/noise-plethora/teensy/synth_whitenoise.cpp b/src/noise-plethora/teensy/synth_whitenoise.cpp new file mode 100644 index 0000000..bed65ab --- /dev/null +++ b/src/noise-plethora/teensy/synth_whitenoise.cpp @@ -0,0 +1,71 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + + +#include "synth_whitenoise.hpp" + +// Park-Miller-Carta Pseudo-Random Number Generator +// http://www.firstpr.com.au/dsp/rand31/ + +void AudioSynthNoiseWhite::update(audio_block_t* block) { + uint32_t* p, *end; + int32_t n1, n2, gain; + uint32_t lo, hi; + + gain = level; + if (gain == 0) + return; + + if (!block) + return; + p = (uint32_t*)(block->data); + end = p + AUDIO_BLOCK_SAMPLES / 2; + lo = seed; + do { + uint32_t val1; + + hi = 16807 * (lo >> 16); + lo = 16807 * (lo & 0xFFFF); + lo += (hi & 0x7FFF) << 16; + lo += hi >> 15; + lo = (lo & 0x7FFFFFFF) + (lo >> 31); + n1 = signed_multiply_32x16b(gain, lo); + hi = 16807 * (lo >> 16); + lo = 16807 * (lo & 0xFFFF); + lo += (hi & 0x7FFF) << 16; + lo += hi >> 15; + lo = (lo & 0x7FFFFFFF) + (lo >> 31); + n2 = signed_multiply_32x16b(gain, lo); + val1 = pack_16b_16b(n2, n1); + *p++ = val1; + + } while (p < end); + seed = lo; +} + +uint16_t AudioSynthNoiseWhite::instance_count = 0; + + diff --git a/src/noise-plethora/teensy/synth_whitenoise.hpp b/src/noise-plethora/teensy/synth_whitenoise.hpp new file mode 100644 index 0000000..7368058 --- /dev/null +++ b/src/noise-plethora/teensy/synth_whitenoise.hpp @@ -0,0 +1,51 @@ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * 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, development funding 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. + */ + +#ifndef synth_whitenoise_h_ +#define synth_whitenoise_h_ +#include "audio_core.hpp" + +class AudioSynthNoiseWhite : public AudioStream { +public: + AudioSynthNoiseWhite() : AudioStream(0) { + level = 0; + seed = 1 + instance_count++; + } + void amplitude(float n) { + if (n < 0.0f) + n = 0.0; + else if (n > 1.0f) + n = 1.0f; + level = (int32_t)(n * 65536.0f); + } + virtual void update(audio_block_t* block); +private: + int32_t level; // 0=off, 65536=max + uint32_t seed; // must start at 1 + static uint16_t instance_count; +}; + +#endif diff --git a/src/plugin.cpp b/src/plugin.cpp index 1f9f5e8..03f4dba 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -23,4 +23,5 @@ void init(rack::Plugin *p) { p->addModel(modelSTMix); p->addModel(modelMuxlicer); p->addModel(modelMex); + p->addModel(modelNoisePlethora); } diff --git a/src/plugin.hpp b/src/plugin.hpp index fc3d447..50dac69 100644 --- a/src/plugin.hpp +++ b/src/plugin.hpp @@ -24,7 +24,7 @@ extern Model* modelADSR; extern Model* modelSTMix; extern Model* modelMuxlicer; extern Model* modelMex; - +extern Model* modelNoisePlethora; struct Knurlie : SvgScrew { Knurlie() { @@ -106,7 +106,7 @@ using BefacoInputPort = BananutBlack; struct CKSSNarrow : app::SvgSwitch { CKSSNarrow() { addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchNarrow_0.svg"))); - addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchNarrow_1.svg"))); + addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchNarrow_2.svg"))); } }; @@ -131,6 +131,31 @@ struct BefacoSwitchHorizontal : app::SvgSwitch { } }; +struct CKSSHoriz2 : app::SvgSwitch { + CKSSHoriz2() { + addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchNarrowHoriz_0.svg"))); + addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchNarrowHoriz_1.svg"))); + } +}; + +struct CKSSNarrow3 : app::SvgSwitch { + CKSSNarrow3() { + addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchNarrow_0.svg"))); + addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchNarrow_1.svg"))); + addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchNarrow_2.svg"))); + } +}; + +struct Davies1900hLargeLightGreyKnob : Davies1900hKnob { + Davies1900hLargeLightGreyKnob() { + setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/Davies1900hLargeLightGrey.svg"))); + bg->setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/Davies1900hLargeLightGrey_bg.svg"))); + } +}; + +inline int unsigned_modulo(int a, int b) { + return ((a % b) + b) % b; +} template T sin2pi_pade_05_5_4(T x) { @@ -199,4 +224,71 @@ struct ADEnvelope { private: float envLinear = 0.f; +}; + +// Creates a Butterworth 2*Nth order highpass filter for blocking DC +template +struct DCBlockerT { + + DCBlockerT() { + setFrequency(0.1f); + } + + // set frequency (in normalised units, 0 < fc < 1) + void setFrequency(float fc) { + fc_ = fc; + recalculateCoefficients(); + } + + float process(float x) { + + x = blockDCFilter[0].process(x); + return blockDCFilter[1].process(x); + } + +private: + + // https://www.earlevel.com/main/2016/09/29/cascading-filters/ + void recalculateCoefficients() { + + float poleInc = M_PI / order; + float firstAngle = poleInc / 2; + + for (int idx = 0; idx < N; idx++) { + float Q = 1.0f / (2.0f * std::cos(firstAngle + idx * poleInc)); + blockDCFilter[idx].setParameters(dsp::BiquadFilter::HIGHPASS, fc_, Q, 1.0f); + } + } + + float fc_; + static const int order = 2 * N; + + dsp::BiquadFilter blockDCFilter[N]; +}; + +typedef DCBlockerT<2> DCBlocker; + +/** When triggered, holds a high value for a specified time before going low again */ +struct PulseGenerator_4 { + simd::float_4 remaining = 0.f; + + /** Immediately disables the pulse */ + void reset() { + remaining = 0.f; + } + + /** Advances the state by `deltaTime`. Returns whether the pulse is in the HIGH state. */ + simd::float_4 process(float deltaTime) { + + simd::float_4 mask = (remaining > 0.f); + + remaining -= ifelse(mask, deltaTime, 0.f); + return ifelse(mask, simd::float_4::mask(), 0.f); + } + + /** Begins a trigger with the given `duration`. */ + void trigger(simd::float_4 mask, float duration = 1e-3f) { + // Keep the previous pulse if the existing pulse will be held longer than the currently requested one. + remaining = ifelse(mask & (duration > remaining), duration, remaining); + } }; \ No newline at end of file