* 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 )tags/v2.1.0^0
@@ -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 | |||
@@ -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. |
@@ -1,6 +1,7 @@ | |||
RACK_DIR ?= ../.. | |||
SOURCES += $(wildcard src/*.cpp) | |||
SOURCES += $(wildcard src/noise-plethora/*/*.cpp) | |||
DISTRIBUTABLES += $(wildcard LICENSE*) res | |||
@@ -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" | |||
] | |||
} | |||
] | |||
} |
@@ -0,0 +1,95 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<svg | |||
xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
xmlns:cc="http://creativecommons.org/ns#" | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
version="1.0" | |||
id="svg16908" | |||
x="0px" | |||
y="0px" | |||
width="54px" | |||
height="54.0024px" | |||
viewBox="0 0 54 54.0024" | |||
enable-background="new 0 0 54 54.0024" | |||
xml:space="preserve" | |||
sodipodi:docname="Davies1900hLargeLightGrey.svg" | |||
inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)"><metadata | |||
id="metadata20"><rdf:RDF><cc:Work | |||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs | |||
id="defs18" /> | |||
<sodipodi:namedview | |||
bordercolor="#666666" | |||
borderopacity="1.0" | |||
fit-margin-bottom="0" | |||
fit-margin-left="0" | |||
fit-margin-right="0" | |||
fit-margin-top="0" | |||
id="base" | |||
inkscape:current-layer="svg16908" | |||
inkscape:cx="-10.751444" | |||
inkscape:cy="-11.595852" | |||
inkscape:document-rotation="0" | |||
inkscape:document-units="mm" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:window-height="1361" | |||
inkscape:window-maximized="1" | |||
inkscape:window-width="2560" | |||
inkscape:window-x="-9" | |||
inkscape:window-y="-9" | |||
inkscape:zoom="7.919596" | |||
pagecolor="#ffffff" | |||
showgrid="false" | |||
units="px"> | |||
</sodipodi:namedview> | |||
<path | |||
opacity="0.47" | |||
fill="#5C5C5C" | |||
enable-background="new " | |||
d="M27.02268,0.73659v2.03027 c1.27875,0.00146,2.53516,0.104,3.75995,0.29834c0.46338,0.07373,0.85632,0.36035,1.12384,0.74561 c2.21851,3.19629,6.10315,5.08032,9.98499,4.84155c0.52692-0.03223,1.05591,0.10986,1.44531,0.46606 c1.80054,1.64844,3.35272,3.56396,4.5885,5.68701c0.26941,0.46289,0.29169,1.0188,0.13892,1.53223 c-1.12714,3.78711-0.12201,8.07324,2.58411,10.9585c0.32593,0.34741,0.52509,0.802,0.49414,1.27759 c-0.16333,2.51123-0.70642,4.91748-1.57739,7.1604c-0.17554,0.4519-0.55823,0.78076-1.01154,0.95312 c-3.80048,1.44556-6.62811,5.00684-7.17157,9.03711c-0.06476,0.48096-0.29797,0.92871-0.69806,1.20312 c-1.9472,1.33643-4.09882,2.39307-6.3974,3.11743c-0.52441,0.16504-1.08594,0.05493-1.55981-0.22363 c-3.47559-2.04443-7.97785-2.04443-11.45343,0c-0.47388,0.27856-1.0354,0.38867-1.55981,0.22363 c-2.2984-0.72388-4.44958-1.78076-6.39502-3.11694c-0.40002-0.2749-0.63318-0.72266-0.6983-1.20361 c-0.54541-4.03027-3.37311-7.5918-7.17151-9.03711c-0.45312-0.17236-0.83563-0.50098-1.01105-0.95288 c-0.87109-2.24292-1.41443-4.64942-1.57953-7.16065c-0.03131-0.47559,0.16766-0.93018,0.49359-1.27759 c2.7063-2.88525,3.71338-7.17139,2.58453-10.9585c-0.15302-0.51343-0.13086-1.06958,0.13861-1.53223 c1.23566-2.1228,2.78772-4.03857,4.58807-5.68652c0.38959-0.35669,0.91882-0.49878,1.44611-0.46655 c3.88336,0.23877,7.76623-1.64526,9.98456-4.84155c0.26746-0.38525,0.66058-0.67188,1.12396-0.74536 c1.22595-0.19458,2.48102-0.29712,3.75989-0.29858V0.73659C12.48216,0.74879,0.736,12.50416,0.736,27.00001 c0,14.50562,11.75848,26.26636,26.26398,26.26636c14.50562,0,26.2641-11.76074,26.2641-26.26636 C53.26408,12.50441,41.51774,0.74879,27.02268,0.73659z" | |||
id="path3" /> | |||
<g | |||
id="path109720_00000161623284270420770010000002804528334434327450_" | |||
inkscape:connector-curvature="0" | |||
opacity="0.25" | |||
enable-background="new "> | |||
<g | |||
id="g7"> | |||
<path | |||
fill="#1F1F1F" | |||
d="M26.99993,3.51607c1.22003,0,2.45315,0.09756,3.66509,0.28996 c0.31782,0.05046,0.52821,0.29271,0.62533,0.43263c2.21967,3.19763,6.02818,5.18403,9.93928,5.18403 c0.23562,0,0.47189-0.00719,0.70781-0.02171c0.03308-0.00203,0.06617-0.00306,0.0992-0.00306 c0.31888,0,0.60076,0.09727,0.7937,0.27389c1.75971,1.61091,3.2558,3.46506,4.44672,5.51095 c0.20056,0.34455,0.12889,0.73739,0.06831,0.94091c-1.2006,4.03361-0.11887,8.62042,2.75585,11.68545 c0.2017,0.21505,0.30843,0.47598,0.29281,0.71591c-0.15568,2.39318-0.66981,4.72728-1.52811,6.93746 c-0.08791,0.22636-0.29897,0.41728-0.57905,0.52381c-4.06512,1.54603-7.06721,5.32912-7.64818,9.63787 c-0.04012,0.2975-0.17833,0.54719-0.37921,0.68505c-1.9082,1.30967-3.99364,2.32585-6.1984,3.02034 c-0.09016,0.0284-0.18601,0.0428-0.28489,0.0428c-0.21794,0-0.44938-0.06837-0.66929-0.19772 c-1.82046-1.07078-3.9322-1.63676-6.10694-1.63676s-4.28649,0.56598-6.10696,1.63676 c-0.21992,0.12935-0.45137,0.19772-0.6693,0.19772c-0.09888,0-0.19474-0.0144-0.28492-0.04281 c-2.20529-0.69465-4.28985-1.71067-6.19578-3.01983c-0.201-0.13808-0.3394-0.38806-0.3797-0.68586 c-0.58306-4.30856-3.5851-8.09152-7.64805-9.63754c-0.27988-0.1065-0.49079-0.2973-0.57863-0.52349 c-0.85789-2.20901-1.37275-4.5434-1.53028-6.93834c-0.01577-0.23977,0.09076-0.5005,0.29228-0.71534 c2.87636-3.06649,3.95825-7.65344,2.75622-11.6858c-0.06065-0.20347-0.13247-0.59625,0.06806-0.94072 c1.19086-2.04576,2.68682-3.89977,4.44634-5.51054c0.19313-0.1768,0.47526-0.27417,0.79441-0.27417 c0.03302,0,0.06611,0.00103,0.09922,0.00307c0.23627,0.01452,0.47211,0.0217,0.70804,0.0217 c3.91094,0,7.7192-1.98642,9.93865-5.18406c0.09708-0.13986,0.30741-0.38202,0.62539-0.43248 C24.54806,3.61367,25.78114,3.51607,26.99993,3.51607 M26.99993,2.76607c-1.28691,0-2.54927,0.10367-3.78251,0.29935 c-0.46337,0.07352-0.85647,0.36013-1.12399,0.74556c-2.09207,3.01413-5.66515,4.86171-9.32252,4.86171 c-0.2206,0-0.44111-0.0067-0.66202-0.02029c-0.04843-0.00298-0.09689-0.00448-0.14524-0.00448 c-0.47806,0-0.94699,0.14704-1.30084,0.47097c-1.80037,1.64817-3.35239,3.56364-4.58809,5.68643 c-0.26946,0.46289-0.29163,1.01901-0.13862,1.53229c1.12885,3.78689,0.12182,8.07323-2.5845,10.95844 c-0.32595,0.34749-0.52491,0.80227-0.49364,1.27767c0.16517,2.51117,0.70847,4.91771,1.57953,7.16062 c0.1755,0.45189,0.55795,0.78055,1.01104,0.95295c3.79847,1.44538,6.62614,5.00687,7.17154,9.03715 c0.06508,0.48089,0.29829,0.92872,0.69829,1.20348c1.94542,1.33629,4.09663,2.39298,6.39509,3.11698 c0.16765,0.0528,0.33909,0.07746,0.51025,0.07746c0.36421,0,0.72715-0.11164,1.04953-0.30125 c1.73779-1.02215,3.73227-1.53323,5.72673-1.53323s3.98891,0.51107,5.7267,1.53322 c0.32237,0.18962,0.68531,0.30126,1.04953,0.30126c0.17116,0,0.3426-0.02466,0.51024-0.07746 c2.29866-0.72406,4.45023-1.78086,6.39746-3.11731c0.40004-0.27456,0.63323-0.72235,0.69807-1.20319 c0.54342-4.03026,3.37107-7.59172,7.17152-9.03709c0.45332-0.17241,0.83599-0.5012,1.01157-0.95331 c0.87096-2.24279,1.41405-4.64924,1.5774-7.16028c0.03094-0.47545-0.16824-0.93016-0.49419-1.27768 c-2.70606-2.8852-3.71122-7.17153-2.58406-10.95841c0.15279-0.51329,0.13046-1.06934-0.13896-1.53218 c-1.23578-2.12296-2.78795-4.03857-4.58848-5.68684c-0.35365-0.32374-0.82233-0.4707-1.30013-0.4707 c-0.04836,0-0.0968,0.00151-0.14524,0.00449c-0.22057,0.01357-0.44147,0.02029-0.66176,0.02029 c-3.65639,0-7.23074-1.84738-9.32317-4.86171c-0.26755-0.38543-0.66045-0.6721-1.12384-0.74567 C29.55049,2.8697,28.28661,2.76607,26.99993,2.76607L26.99993,2.76607z" | |||
id="path5" /> | |||
</g> | |||
</g> | |||
<g | |||
id="path109720_00000155831737055662349650000008503574696319157933_" | |||
inkscape:connector-curvature="0" | |||
opacity="0.36"> | |||
<path | |||
fill="#808080" | |||
d="M27,6.02426c0.74651,0,1.50209,0.04102,2.24578,0.12207c0.75726,0.08252,1.48725,0.50586,2.05547,1.19214 c2.05435,2.48169,5.19908,3.96314,8.41215,3.96314c0.0855,0,0.17151-0.00098,0.25709-0.00317l0.0519-0.00073 c0.55985,0,1.09537,0.22046,1.50799,0.62061c1.22828,1.19067,2.30643,2.52637,3.20454,3.97021 c0.31184,0.50122,0.40833,1.10767,0.26473,1.66406c-0.87377,3.3855-0.00654,7.13867,2.26324,9.79517 c0.38327,0.44849,0.56183,1.0271,0.50277,1.62891c-0.15583,1.58838-0.49282,3.15357-1.00161,4.65186 c-0.22486,0.66211-0.73924,1.20801-1.4483,1.53687c-3.1218,1.44751-5.46496,4.44238-6.11509,7.81592 c-0.1266,0.65698-0.4899,1.20532-1.02308,1.54346c-1.34915,0.85645-2.79754,1.55688-4.30498,2.08154 c-0.23154,0.08057-0.47222,0.12134-0.71536,0.12134c-0.35114,0-0.69938-0.0874-1.00722-0.25293 c-1.55588-0.83618-3.33667-1.27832-5.14985-1.27832c-1.81336,0-3.59429,0.44214-5.15021,1.27856 c-0.30769,0.16528-0.65592,0.25269-1.00703,0.25269c-0.2432,0-0.48391-0.04077-0.71553-0.12134 c-1.50687-0.52466-2.95429-1.22437-4.30217-2.08032c-0.5335-0.33887-0.8973-0.8877-1.02441-1.54541 c-0.65173-3.37329-2.99482-6.36792-6.11475-7.81519c-0.70874-0.32886-1.22286-0.87451-1.44767-1.53638 c-0.50884-1.4978-0.84639-3.06372-1.00326-4.65381c-0.05846-0.59253,0.1244-1.18579,0.50175-1.6272 c2.27122-2.65747,3.13872-6.41089,2.26394-9.79565c-0.14378-0.55615-0.04739-1.16284,0.2645-1.66406 c0.8978-1.44336,1.97575-2.77905,3.20377-3.96973c0.41301-0.40039,0.94897-0.62085,1.50918-0.62085l0.05194,0.00073 c0.08578,0.0022,0.17141,0.00317,0.25713,0.00317c3.21307,0,6.35757-1.48169,8.41153-3.96314 c0.56791-0.68628,1.29773-1.10938,2.05501-1.19189C25.49921,6.06552,26.25492,6.02426,27,6.02426 M27,5.27426 c-0.78646,0-1.56266,0.04346-2.32729,0.12671c-1.01355,0.11035-1.90151,0.67383-2.55159,1.45923 c-1.90757,2.30469-4.83893,3.69141-7.83377,3.69141c-0.07956,0-0.15904-0.00098-0.23867-0.00293 c-0.02348-0.00049-0.04697-0.00098-0.07039-0.00098c-0.75951,0-1.48426,0.30225-2.03115,0.83228 c-1.26579,1.22729-2.38271,2.60742-3.31866,4.11206c-0.41827,0.67236-0.55193,1.48144-0.35377,2.24805 c0.81537,3.15479,0.00987,6.64258-2.10796,9.12061c-0.51749,0.60547-0.75618,1.39551-0.67799,2.18823 c0.1648,1.67041,0.51766,3.28516,1.0395,4.82129c0.30273,0.89136,0.98827,1.57935,1.8421,1.97559 c2.91277,1.35107,5.08415,4.12012,5.69408,7.2771c0.16186,0.83765,0.63857,1.57886,1.35878,2.03613 c1.38668,0.88062,2.88077,1.60669,4.45763,2.15552c0.31282,0.10889,0.63809,0.16309,0.96207,0.16309 c0.47051,0,0.93836-0.11426,1.36209-0.34204c1.4747-0.79272,3.13502-1.18921,4.79515-1.18921 c1.66013,0,3.32007,0.39624,4.79477,1.18896c0.42374,0.22778,0.89176,0.34229,1.36229,0.34229 c0.32398,0,0.64912-0.0542,0.96195-0.16309c1.57748-0.54907,3.0723-1.27539,4.46034-2.15649 c0.71982-0.45679,1.19625-1.19751,1.35759-2.03491c0.6084-3.15698,2.77983-5.92603,5.69413-7.27734 c0.85425-0.39624,1.54018-1.08447,1.84297-1.97607c0.52152-1.53589,0.87403-3.1499,1.03786-4.81983 c0.07782-0.79321-0.16123-1.5835-0.67899-2.18945c-2.11739-2.47803-2.92142-5.96582-2.10724-9.12036 c0.19786-0.7666,0.06405-1.57568-0.35413-2.2478c-0.93609-1.50488-2.05325-2.88525-3.31932-4.11255 c-0.54657-0.53003-1.27095-0.83203-2.03001-0.83203c-0.02345,0-0.04689,0.00049-0.0704,0.00098 c-0.07942,0.00195-0.15924,0.00293-0.23859,0.00293c-2.99408,0-5.92635-1.38647-7.83442-3.69141 c-0.65026-0.7854-1.5383-1.34912-2.55204-1.45947C28.56251,5.31747,27.78602,5.27426,27,5.27426L27,5.27426z" | |||
id="path10" /> | |||
</g> | |||
<path | |||
id="path109722_00000132790347987467418750000015594545222572185506_" | |||
inkscape:connector-curvature="0" | |||
fill="#E3E3E3" | |||
d=" M27.95065,1.74111c0,0.52557-0.42744,0.94836-0.95066,0.94836s-0.94833-0.42279-0.94833-0.94836 c0-0.52555,0.42511-0.94835,0.94833-0.94835S27.95065,1.21556,27.95065,1.74111" /> | |||
<path | |||
opacity="0.64" | |||
fill="#4A4A4A" | |||
enable-background="new " | |||
d="M27.00003,6.02426c-0.74512,0-1.5008,0.04126-2.24616,0.12231 c-0.75726,0.08252-1.48706,0.50562-2.05499,1.19189c-2.05395,2.48145-5.19842,3.96314-8.4115,3.96314 c-0.08575,0-0.17139-0.00098-0.25714-0.00317l-0.05194-0.00073c-0.56018,0-1.09619,0.22046-1.50916,0.62085 c-1.22802,1.19067-2.30595,2.52637-3.20379,3.96973c-0.31189,0.50122-0.40826,1.10791-0.26447,1.66406 c0.87476,3.38477,0.00727,7.13818-2.26397,9.79565c-0.37733,0.44141-0.5602,1.03467-0.50177,1.6272 c0.15691,1.59009,0.49444,3.15601,1.00329,4.65381c0.22478,0.66187,0.73889,1.20752,1.44763,1.53638 c3.11993,1.44727,5.46307,4.44189,6.11475,7.81519c0.12714,0.65771,0.49091,1.20654,1.02441,1.54541 c1.3479,0.85596,2.79535,1.55566,4.30219,2.08032c0.23163,0.08057,0.47235,0.12134,0.71552,0.12134 c0.35114,0,0.69934-0.0874,1.00702-0.25269c1.55597-0.83643,3.33686-1.27856,5.15027-1.27856 c1.81317,0,3.59393,0.44214,5.14984,1.27832c0.3078,0.16553,0.65607,0.25293,1.0072,0.25293 c0.24317,0,0.48383-0.04077,0.71534-0.12134c1.50744-0.52466,2.95587-1.2251,4.30499-2.08154 c0.5332-0.33813,0.89648-0.88647,1.02307-1.54346c0.65015-3.37354,2.99329-6.36841,6.11511-7.81592 c0.70905-0.32886,1.22345-0.87476,1.44831-1.53687c0.50879-1.49829,0.84576-3.06348,1.00158-4.65186 c0.05909-0.60181-0.1195-1.18042-0.50274-1.62891c-2.26978-2.65649-3.13703-6.40967-2.26325-9.79517 c0.14362-0.5564,0.04712-1.16284-0.26471-1.66406c-0.89813-1.44385-1.97625-2.77954-3.20459-3.97021 c-0.4126-0.40015-0.94812-0.62061-1.50793-0.62061l-0.05194,0.00073c-0.08557,0.0022-0.17157,0.00317-0.25708,0.00317 c-3.21308,0-6.35779-1.48145-8.41217-3.96314c-0.56818-0.68628-1.29816-1.10962-2.05542-1.19214 C28.5021,6.06527,27.74655,6.02426,27.00003,6.02426L27.00003,6.02426z" | |||
id="path14" | |||
style="fill:#878787;fill-opacity:1" /> | |||
<path | |||
id="path109724_00000046337844363982079960000015404365734540027067_" | |||
inkscape:connector-curvature="0" | |||
fill="#E3E3E3" | |||
d=" M27.18946,27.00234h-0.37662c-0.42039,0-0.76119-0.3408-0.76119-0.76119V7.28285c0-0.42039,0.3408-0.76119,0.76119-0.76119h0.37662 c0.42039,0,0.76119,0.3408,0.76119,0.76119v18.9583C27.95065,26.66154,27.60986,27.00234,27.18946,27.00234z" /> | |||
</svg> |
@@ -0,0 +1,98 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<svg | |||
xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
xmlns:cc="http://creativecommons.org/ns#" | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
version="1.0" | |||
id="svg16908" | |||
x="0px" | |||
y="0px" | |||
width="54px" | |||
height="54.0024px" | |||
viewBox="0 0 54 54.0024" | |||
enable-background="new 0 0 54 54.0024" | |||
xml:space="preserve" | |||
sodipodi:docname="Davies1900hLargeLightGrey_bg.svg" | |||
inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)"><metadata | |||
id="metadata19"><rdf:RDF><cc:Work | |||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs | |||
id="defs17" /> | |||
<sodipodi:namedview | |||
bordercolor="#666666" | |||
borderopacity="1.0" | |||
fit-margin-bottom="0" | |||
fit-margin-left="0" | |||
fit-margin-right="0" | |||
fit-margin-top="0" | |||
id="base" | |||
inkscape:current-layer="svg16908" | |||
inkscape:cx="52.324654" | |||
inkscape:cy="47.546467" | |||
inkscape:document-rotation="0" | |||
inkscape:document-units="mm" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:window-height="1361" | |||
inkscape:window-maximized="1" | |||
inkscape:window-width="2560" | |||
inkscape:window-x="-9" | |||
inkscape:window-y="-9" | |||
inkscape:zoom="8" | |||
pagecolor="#ffffff" | |||
showgrid="false" | |||
units="px"> | |||
</sodipodi:namedview> | |||
<linearGradient | |||
id="path109718_1_" | |||
gradientUnits="userSpaceOnUse" | |||
x1="27" | |||
y1="8.8817842e-16" | |||
x2="27" | |||
y2="54.00236"> | |||
<stop | |||
offset="0" | |||
style="stop-color:#c8c6c6;stop-opacity:1" | |||
id="stop3" /> | |||
<stop | |||
offset="1" | |||
style="stop-color:#878787;stop-opacity:1" | |||
id="stop5" /> | |||
</linearGradient> | |||
<path | |||
id="path109718_00000041986084651045777730000015174648132872021642_" | |||
inkscape:connector-curvature="0" | |||
fill="url(#path109718_1_)" | |||
d=" M54,26.99999c0,14.91202-12.08797,27.00237-27.00001,27.00237S0,41.91201,0,26.99999C0,12.09032,12.08796,0,26.99999,0 S54,12.09032,54,26.99999" | |||
style="fill:url(#path109718_1_)" /> | |||
<linearGradient | |||
id="SVGID_1_" | |||
gradientUnits="userSpaceOnUse" | |||
x1="120.93008" | |||
y1="216.11739" | |||
x2="120.93398" | |||
y2="239.55823" | |||
gradientTransform="matrix(-1 0 0 0.50871 147.93398 -99.80668)"> | |||
<stop | |||
offset="0" | |||
style="stop-color:#ffffff;stop-opacity:1" | |||
id="stop9" /> | |||
<stop | |||
offset="1" | |||
style="stop-color:#fcfeff;stop-opacity:0" | |||
id="stop11" /> | |||
</linearGradient> | |||
<ellipse | |||
opacity="0.4" | |||
fill="url(#SVGID_1_)" | |||
cx="27" | |||
cy="16.07793" | |||
rx="12.03752" | |||
ry="5.98187" | |||
id="ellipse14" | |||
style="fill:url(#SVGID_1_)" /> | |||
</svg> |
@@ -0,0 +1,154 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<svg | |||
xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
xmlns:cc="http://creativecommons.org/ns#" | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
version="1.0" | |||
id="svg56722" | |||
inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" | |||
x="0px" | |||
y="0px" | |||
width="20.641029" | |||
height="10" | |||
viewBox="0 0 20.641029 10" | |||
enable-background="new 0 0 10 20.64111" | |||
xml:space="preserve" | |||
sodipodi:docname="SwitchNarrowHoriz_0.svg"><metadata | |||
id="metadata32"><rdf:RDF><cc:Work | |||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs | |||
id="defs30" /> | |||
<sodipodi:namedview | |||
bordercolor="#666666" | |||
borderopacity="1.0" | |||
fit-margin-bottom="0" | |||
fit-margin-left="0" | |||
fit-margin-right="0" | |||
fit-margin-top="0" | |||
id="base" | |||
inkscape:current-layer="svg56722" | |||
inkscape:cx="3.4909301" | |||
inkscape:cy="3.9708842" | |||
inkscape:document-rotation="0" | |||
inkscape:document-units="mm" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:window-height="1292" | |||
inkscape:window-maximized="0" | |||
inkscape:window-width="2559" | |||
inkscape:window-x="0" | |||
inkscape:window-y="101" | |||
inkscape:zoom="31.678384" | |||
pagecolor="#ffffff" | |||
showgrid="false" | |||
units="px"> | |||
</sodipodi:namedview> | |||
<g | |||
id="g1501" | |||
transform="rotate(90,10.353775,10.353775)"><path | |||
id="path5785_1_" | |||
inkscape:connector-curvature="0" | |||
d="M 0,1.5416 C 0,0.73117 0.66471,0.06652 1.47514,0.06652 H 8.52486 C 9.33523,0.06652 10,0.7313 10,1.5416 v 17.69189 c 0,0.81043 -0.66471,1.47406 -1.47514,1.47406 H 1.47514 C 0.66477,20.70754 0,20.04391 0,19.23348 Z" /><g | |||
id="g5795_1_" | |||
opacity="0.54"> | |||
<g | |||
id="g5797_1_"> | |||
<linearGradient | |||
id="path5805_00000026147093842360495760000000346361381535047831_" | |||
gradientUnits="userSpaceOnUse" | |||
x1="4.9991698" | |||
y1="1.39937" | |||
x2="4.9991698" | |||
y2="19.52606"> | |||
<stop | |||
offset="0" | |||
style="stop-color:#3B3B3B" | |||
id="stop4" /> | |||
<stop | |||
offset="1" | |||
style="stop-color:#242424" | |||
id="stop6" /> | |||
</linearGradient> | |||
<path | |||
id="path5805_1_" | |||
inkscape:connector-curvature="0" | |||
fill="url(#path5805_00000026147093842360495760000000346361381535047831_)" | |||
d="m 2.19312,1.39937 c -0.48687,0 -0.88421,0.39734 -0.88421,0.88421 v 0 16.35726 c 0,0.48687 0.3974,0.88522 0.88421,0.88522 v 0 h 5.61312 c 0.48477,0 0.88319,-0.39848 0.88319,-0.88522 v 0 -16.35726 c 0,-0.48687 -0.39842,-0.88421 -0.88319,-0.88421 v 0 z" | |||
style="fill:url(#path5805_00000026147093842360495760000000346361381535047831_)" /> | |||
</g> | |||
</g><rect | |||
x="1.30993" | |||
y="18.65077" | |||
fill="none" | |||
width="0.68290001" | |||
height="0.89523" | |||
id="rect12" /><rect | |||
x="0.99908" | |||
y="0.88112998" | |||
opacity="0.3" | |||
width="8.0001898" | |||
height="1.71664" | |||
id="rect14" /><g | |||
id="g27"> | |||
<linearGradient | |||
id="path5815_00000176018740175221449750000008623012870990731937_" | |||
gradientUnits="userSpaceOnUse" | |||
x1="4.9991698" | |||
y1="10.67955" | |||
x2="4.9991698" | |||
y2="19.52606"> | |||
<stop | |||
offset="0.00559" | |||
style="stop-color:#3D3B3B" | |||
id="stop16" /> | |||
<stop | |||
offset="1" | |||
style="stop-color:#2D2C2C" | |||
id="stop18" /> | |||
</linearGradient> | |||
<path | |||
id="path5815_4_" | |||
inkscape:connector-curvature="0" | |||
fill="url(#path5815_00000176018740175221449750000008623012870990731937_)" | |||
d="m 1.30891,10.67955 h 7.38052 v 8.84651 H 1.30891 Z" | |||
style="fill:url(#path5815_00000176018740175221449750000008623012870990731937_)" /> | |||
<path | |||
id="path5817_4_" | |||
inkscape:connector-curvature="0" | |||
fill="#5e5e5e" | |||
d="m 1.30891,14.22647 h 7.38052 v 0.87738 H 1.30891 Z" /> | |||
<path | |||
id="path5819_4_" | |||
inkscape:connector-curvature="0" | |||
fill="#5e5e5e" | |||
d="m 1.30891,17.77339 h 7.38052 v 0.87738 H 1.30891 Z" /> | |||
<path | |||
id="path5821_4_" | |||
inkscape:connector-curvature="0" | |||
fill="#5e5e5e" | |||
d="m 1.30891,16.00079 h 7.38052 v 0.87738 H 1.30891 Z" /> | |||
<path | |||
id="path5823_4_" | |||
inkscape:connector-curvature="0" | |||
fill="#5e5e5e" | |||
d="m 1.30891,12.45307 h 7.38052 v 0.87738 H 1.30891 Z" /> | |||
<path | |||
id="path5825_4_" | |||
inkscape:connector-curvature="0" | |||
fill="#797979" | |||
d="m 1.30891,10.67955 h 7.38052 v 0.87738 H 1.30891 Z" | |||
style="fill:#5e5e5e;fill-opacity:1" /> | |||
</g></g> | |||
</svg> |
@@ -0,0 +1,149 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<svg | |||
xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
xmlns:cc="http://creativecommons.org/ns#" | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
version="1.0" | |||
id="svg56722" | |||
inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" | |||
x="0px" | |||
y="0px" | |||
width="20.64102" | |||
height="10" | |||
viewBox="0 0 20.64102 10" | |||
enable-background="new 0 0 10 20.64111" | |||
xml:space="preserve" | |||
sodipodi:docname="SwitchNarrowHoriz_1.svg"><metadata | |||
id="metadata919"><rdf:RDF><cc:Work | |||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs | |||
id="defs917" /> | |||
<sodipodi:namedview | |||
bordercolor="#666666" | |||
borderopacity="1.0" | |||
fit-margin-bottom="0" | |||
fit-margin-left="0" | |||
fit-margin-right="0" | |||
fit-margin-top="0" | |||
id="base" | |||
inkscape:current-layer="svg56722" | |||
inkscape:cx="17.685308" | |||
inkscape:cy="15.724034" | |||
inkscape:document-rotation="0" | |||
inkscape:document-units="mm" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:window-height="1393" | |||
inkscape:window-maximized="0" | |||
inkscape:window-width="2560" | |||
inkscape:window-x="0" | |||
inkscape:window-y="0" | |||
inkscape:zoom="15.839192" | |||
pagecolor="#ffffff" | |||
showgrid="false" | |||
units="px"> | |||
</sodipodi:namedview> | |||
<path | |||
id="path5785" | |||
inkscape:connector-curvature="0" | |||
d="m 19.16594,0 c 0.81043,0 1.47508,0.66471 1.47508,1.47514 V 8.52486 C 20.64102,9.33523 19.97624,10 19.16594,10 H 1.47406 C 0.66363,10 0,9.33529 0,8.52486 V 1.47514 C 0,0.66477 0.66363,0 1.47406,0 Z" /><g | |||
id="g5795" | |||
opacity="0.54" | |||
transform="rotate(90,10.32053,10.32053)"> | |||
<g | |||
id="g5797"> | |||
<linearGradient | |||
id="path5805_00000083768858156117840380000007545053210476265646_" | |||
gradientUnits="userSpaceOnUse" | |||
x1="4.9991698" | |||
y1="1.33289" | |||
x2="4.9991698" | |||
y2="19.459579"> | |||
<stop | |||
offset="0" | |||
style="stop-color:#3B3B3B" | |||
id="stop891" /> | |||
<stop | |||
offset="1" | |||
style="stop-color:#242424" | |||
id="stop893" /> | |||
</linearGradient> | |||
<path | |||
id="path5805" | |||
inkscape:connector-curvature="0" | |||
fill="url(#path5805_00000083768858156117840380000007545053210476265646_)" | |||
d="m 2.19312,1.33289 c -0.48687,0 -0.88421,0.39734 -0.88421,0.88421 v 0 16.35726 c 0,0.48687 0.3974,0.88522 0.88421,0.88522 v 0 h 5.61312 c 0.48477,0 0.88319,-0.39848 0.88319,-0.88522 v 0 V 2.2171 c 0,-0.48687 -0.39842,-0.88421 -0.88319,-0.88421 v 0 z" | |||
style="fill:url(#path5805_00000083768858156117840380000007545053210476265646_)" /> | |||
</g> | |||
</g><rect | |||
x="1.30993" | |||
y="-2.0567706" | |||
fill="none" | |||
width="0.68290001" | |||
height="0.89523" | |||
id="rect899" | |||
transform="rotate(90)" /><g | |||
id="g914" | |||
transform="rotate(90,10.32053,10.32053)"> | |||
<linearGradient | |||
id="path5815_00000170964631234716849240000010152055143087385985_" | |||
gradientUnits="userSpaceOnUse" | |||
x1="5.0001898" | |||
y1="1.33289" | |||
x2="5.0001898" | |||
y2="10.17941"> | |||
<stop | |||
offset="0.00559" | |||
style="stop-color:#3D3B3B" | |||
id="stop903" /> | |||
<stop | |||
offset="1" | |||
style="stop-color:#2D2C2C" | |||
id="stop905" /> | |||
</linearGradient> | |||
<path | |||
id="path5815" | |||
inkscape:connector-curvature="0" | |||
fill="url(#path5815_00000170964631234716849240000010152055143087385985_)" | |||
d="M 1.30993,1.33289 H 8.69045 V 10.1794 H 1.30993 Z" | |||
style="fill:url(#path5815_00000170964631234716849240000010152055143087385985_)" /> | |||
<path | |||
id="path5817" | |||
inkscape:connector-curvature="0" | |||
fill="#5e5e5e" | |||
d="M 1.30993,4.87982 H 8.69045 V 5.7572 H 1.30993 Z" /> | |||
<path | |||
id="path5819" | |||
inkscape:connector-curvature="0" | |||
fill="#5e5e5e" | |||
d="M 1.30993,8.42674 H 8.69045 V 9.30412 H 1.30993 Z" /> | |||
<path | |||
id="path5821" | |||
inkscape:connector-curvature="0" | |||
fill="#5e5e5e" | |||
d="M 1.30993,6.65414 H 8.69045 V 7.53152 H 1.30993 Z" /> | |||
<path | |||
id="path5823" | |||
inkscape:connector-curvature="0" | |||
fill="#5e5e5e" | |||
d="M 1.30993,3.10641 H 8.69045 V 3.98379 H 1.30993 Z" /> | |||
<path | |||
id="path5825" | |||
inkscape:connector-curvature="0" | |||
fill="#797979" | |||
d="M 1.30993,1.33289 H 8.69045 V 2.21027 H 1.30993 Z" | |||
style="fill:#5e5e5e;fill-opacity:1" /> | |||
</g> | |||
</svg> |
@@ -1,42 +1,151 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> | |||
<svg version="1.0" | |||
id="svg56722" inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="10px" height="20.64111px" | |||
viewBox="0 0 10 20.64111" enable-background="new 0 0 10 20.64111" xml:space="preserve"> | |||
<sodipodi:namedview bordercolor="#666666" borderopacity="1.0" fit-margin-bottom="0" fit-margin-left="0" fit-margin-right="0" fit-margin-top="0" id="base" inkscape:current-layer="layer1" inkscape:cx="-7.1500998" inkscape:cy="8.220078" inkscape:document-rotation="0" inkscape:document-units="mm" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:window-height="1393" inkscape:window-maximized="0" inkscape:window-width="2560" inkscape:window-x="0" inkscape:window-y="0" inkscape:zoom="31.678384" pagecolor="#ffffff" showgrid="false" units="px"> | |||
</sodipodi:namedview> | |||
<path id="path5785" inkscape:connector-curvature="0" d="M0,1.47512c0-0.81043,0.66471-1.47508,1.47514-1.47508h7.04972 | |||
C9.33523,0.00004,10,0.66482,10,1.47512V19.167c0,0.81043-0.66471,1.47406-1.47514,1.47406H1.47514 | |||
C0.66477,20.64106,0,19.97743,0,19.167V1.47512z"/> | |||
<g id="g5795" opacity="0.54"> | |||
<g id="g5797"> | |||
<linearGradient id="path5805_00000083768858156117840380000007545053210476265646_" gradientUnits="userSpaceOnUse" x1="4.99917" y1="1.33289" x2="4.99917" y2="19.45958"> | |||
<stop offset="0" style="stop-color:#3B3B3B"/> | |||
<stop offset="1" style="stop-color:#242424"/> | |||
</linearGradient> | |||
<path id="path5805" inkscape:connector-curvature="0" fill="url(#path5805_00000083768858156117840380000007545053210476265646_)" d=" | |||
M2.19312,1.33289c-0.48687,0-0.88421,0.39734-0.88421,0.88421l0,0v16.35726c0,0.48687,0.3974,0.88522,0.88421,0.88522l0,0h5.61312 | |||
c0.48477,0,0.88319-0.39848,0.88319-0.88522l0,0V2.2171c0-0.48687-0.39842-0.88421-0.88319-0.88421l0,0H2.19312z"/> | |||
</g> | |||
</g> | |||
<rect x="1.30993" y="18.58429" fill="none" width="0.6829" height="0.89523"/> | |||
<rect x="0.99908" y="9.84516" opacity="0.44" width="8.00019" height="3.54676"/> | |||
<g> | |||
<linearGradient id="path5815_00000170964631234716849240000010152055143087385985_" gradientUnits="userSpaceOnUse" x1="5.00019" y1="1.33289" x2="5.00019" y2="10.17941"> | |||
<stop offset="0.00559" style="stop-color:#3D3B3B"/> | |||
<stop offset="1" style="stop-color:#2D2C2C"/> | |||
</linearGradient> | |||
<path id="path5815" inkscape:connector-curvature="0" fill="url(#path5815_00000170964631234716849240000010152055143087385985_)" d=" | |||
M1.30993,1.33289h7.38052v8.84651H1.30993V1.33289z"/> | |||
<path id="path5817" inkscape:connector-curvature="0" fill="#5E5E5E" d="M1.30993,4.87982h7.38052v0.87738H1.30993V4.87982z"/> | |||
<path id="path5819" inkscape:connector-curvature="0" fill="#5E5E5E" d="M1.30993,8.42674h7.38052v0.87738H1.30993V8.42674z"/> | |||
<path id="path5821" inkscape:connector-curvature="0" fill="#5E5E5E" d="M1.30993,6.65414h7.38052v0.87738H1.30993V6.65414z"/> | |||
<path id="path5823" inkscape:connector-curvature="0" fill="#5E5E5E" d="M1.30993,3.10641h7.38052v0.87738H1.30993V3.10641z"/> | |||
<path id="path5825" inkscape:connector-curvature="0" fill="#797979" d="M1.30993,1.33289h7.38052v0.87738H1.30993V1.33289z"/> | |||
</g> | |||
</svg> | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<svg | |||
xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
xmlns:cc="http://creativecommons.org/ns#" | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
version="1.0" | |||
id="svg56722" | |||
inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" | |||
x="0px" | |||
y="0px" | |||
width="10px" | |||
height="20.64111px" | |||
viewBox="0 0 10 20.64111" | |||
enable-background="new 0 0 10 20.64111" | |||
xml:space="preserve" | |||
sodipodi:docname="SwitchNarrow_1.svg"><metadata | |||
id="metadata32"><rdf:RDF><cc:Work | |||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs | |||
id="defs30" /> | |||
<sodipodi:namedview | |||
bordercolor="#666666" | |||
borderopacity="1.0" | |||
fit-margin-bottom="0" | |||
fit-margin-left="0" | |||
fit-margin-right="0" | |||
fit-margin-top="0" | |||
id="base" | |||
inkscape:current-layer="svg56722" | |||
inkscape:cx="-7.1500998" | |||
inkscape:cy="10.745459" | |||
inkscape:document-rotation="0" | |||
inkscape:document-units="mm" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:window-height="906" | |||
inkscape:window-maximized="0" | |||
inkscape:window-width="1779" | |||
inkscape:window-x="2646" | |||
inkscape:window-y="289" | |||
inkscape:zoom="31.678384" | |||
pagecolor="#ffffff" | |||
showgrid="false" | |||
units="px"> | |||
</sodipodi:namedview> | |||
<path | |||
id="path5785" | |||
inkscape:connector-curvature="0" | |||
d="M0,1.47512c0-0.81043,0.66471-1.47508,1.47514-1.47508h7.04972 C9.33523,0.00004,10,0.66482,10,1.47512V19.167c0,0.81043-0.66471,1.47406-1.47514,1.47406H1.47514 C0.66477,20.64106,0,19.97743,0,19.167V1.47512z" /> | |||
<g | |||
id="g5795" | |||
opacity="0.54"> | |||
<g | |||
id="g5797"> | |||
<linearGradient | |||
id="path5805_00000083768858156117840380000007545053210476265646_" | |||
gradientUnits="userSpaceOnUse" | |||
x1="4.99917" | |||
y1="1.33289" | |||
x2="4.99917" | |||
y2="19.45958"> | |||
<stop | |||
offset="0" | |||
style="stop-color:#3B3B3B" | |||
id="stop4" /> | |||
<stop | |||
offset="1" | |||
style="stop-color:#242424" | |||
id="stop6" /> | |||
</linearGradient> | |||
<path | |||
id="path5805" | |||
inkscape:connector-curvature="0" | |||
fill="url(#path5805_00000083768858156117840380000007545053210476265646_)" | |||
d=" M2.19312,1.33289c-0.48687,0-0.88421,0.39734-0.88421,0.88421l0,0v16.35726c0,0.48687,0.3974,0.88522,0.88421,0.88522l0,0h5.61312 c0.48477,0,0.88319-0.39848,0.88319-0.88522l0,0V2.2171c0-0.48687-0.39842-0.88421-0.88319-0.88421l0,0H2.19312z" /> | |||
</g> | |||
</g> | |||
<rect | |||
x="1.30993" | |||
y="18.58429" | |||
fill="none" | |||
width="0.6829" | |||
height="0.89523" | |||
id="rect12" /> | |||
<rect | |||
x="0.99908" | |||
y="13.750457" | |||
opacity="0.44" | |||
width="8.0001898" | |||
height="3.5467601" | |||
id="rect14" /> | |||
<g | |||
id="g27" | |||
transform="translate(0,4.64009)"> | |||
<linearGradient | |||
id="path5815_00000170964631234716849240000010152055143087385985_" | |||
gradientUnits="userSpaceOnUse" | |||
x1="5.0001898" | |||
y1="1.33289" | |||
x2="5.0001898" | |||
y2="10.17941"> | |||
<stop | |||
offset="0.00559" | |||
style="stop-color:#3D3B3B" | |||
id="stop16" /> | |||
<stop | |||
offset="1" | |||
style="stop-color:#2D2C2C" | |||
id="stop18" /> | |||
</linearGradient> | |||
<path | |||
id="path5815" | |||
inkscape:connector-curvature="0" | |||
fill="url(#path5815_00000170964631234716849240000010152055143087385985_)" | |||
d="M 1.30993,1.33289 H 8.69045 V 10.1794 H 1.30993 Z" | |||
style="fill:url(#path5815_00000170964631234716849240000010152055143087385985_)" /> | |||
<path | |||
id="path5817" | |||
inkscape:connector-curvature="0" | |||
fill="#5e5e5e" | |||
d="M 1.30993,4.87982 H 8.69045 V 5.7572 H 1.30993 Z" /> | |||
<path | |||
id="path5819" | |||
inkscape:connector-curvature="0" | |||
fill="#5e5e5e" | |||
d="M 1.30993,8.42674 H 8.69045 V 9.30412 H 1.30993 Z" /> | |||
<path | |||
id="path5821" | |||
inkscape:connector-curvature="0" | |||
fill="#5e5e5e" | |||
d="M 1.30993,6.65414 H 8.69045 V 7.53152 H 1.30993 Z" /> | |||
<path | |||
id="path5823" | |||
inkscape:connector-curvature="0" | |||
fill="#5e5e5e" | |||
d="M 1.30993,3.10641 H 8.69045 V 3.98379 H 1.30993 Z" /> | |||
<path | |||
id="path5825" | |||
inkscape:connector-curvature="0" | |||
fill="#797979" | |||
d="M 1.30993,1.33289 H 8.69045 V 2.21027 H 1.30993 Z" /> | |||
</g> | |||
</svg> |
@@ -0,0 +1,42 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> | |||
<svg version="1.0" | |||
id="svg56722" inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="10px" height="20.64111px" | |||
viewBox="0 0 10 20.64111" enable-background="new 0 0 10 20.64111" xml:space="preserve"> | |||
<sodipodi:namedview bordercolor="#666666" borderopacity="1.0" fit-margin-bottom="0" fit-margin-left="0" fit-margin-right="0" fit-margin-top="0" id="base" inkscape:current-layer="layer1" inkscape:cx="-7.1500998" inkscape:cy="8.220078" inkscape:document-rotation="0" inkscape:document-units="mm" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:window-height="1393" inkscape:window-maximized="0" inkscape:window-width="2560" inkscape:window-x="0" inkscape:window-y="0" inkscape:zoom="31.678384" pagecolor="#ffffff" showgrid="false" units="px"> | |||
</sodipodi:namedview> | |||
<path id="path5785" inkscape:connector-curvature="0" d="M0,1.47512c0-0.81043,0.66471-1.47508,1.47514-1.47508h7.04972 | |||
C9.33523,0.00004,10,0.66482,10,1.47512V19.167c0,0.81043-0.66471,1.47406-1.47514,1.47406H1.47514 | |||
C0.66477,20.64106,0,19.97743,0,19.167V1.47512z"/> | |||
<g id="g5795" opacity="0.54"> | |||
<g id="g5797"> | |||
<linearGradient id="path5805_00000083768858156117840380000007545053210476265646_" gradientUnits="userSpaceOnUse" x1="4.99917" y1="1.33289" x2="4.99917" y2="19.45958"> | |||
<stop offset="0" style="stop-color:#3B3B3B"/> | |||
<stop offset="1" style="stop-color:#242424"/> | |||
</linearGradient> | |||
<path id="path5805" inkscape:connector-curvature="0" fill="url(#path5805_00000083768858156117840380000007545053210476265646_)" d=" | |||
M2.19312,1.33289c-0.48687,0-0.88421,0.39734-0.88421,0.88421l0,0v16.35726c0,0.48687,0.3974,0.88522,0.88421,0.88522l0,0h5.61312 | |||
c0.48477,0,0.88319-0.39848,0.88319-0.88522l0,0V2.2171c0-0.48687-0.39842-0.88421-0.88319-0.88421l0,0H2.19312z"/> | |||
</g> | |||
</g> | |||
<rect x="1.30993" y="18.58429" fill="none" width="0.6829" height="0.89523"/> | |||
<rect x="0.99908" y="9.84516" opacity="0.44" width="8.00019" height="3.54676"/> | |||
<g> | |||
<linearGradient id="path5815_00000170964631234716849240000010152055143087385985_" gradientUnits="userSpaceOnUse" x1="5.00019" y1="1.33289" x2="5.00019" y2="10.17941"> | |||
<stop offset="0.00559" style="stop-color:#3D3B3B"/> | |||
<stop offset="1" style="stop-color:#2D2C2C"/> | |||
</linearGradient> | |||
<path id="path5815" inkscape:connector-curvature="0" fill="url(#path5815_00000170964631234716849240000010152055143087385985_)" d=" | |||
M1.30993,1.33289h7.38052v8.84651H1.30993V1.33289z"/> | |||
<path id="path5817" inkscape:connector-curvature="0" fill="#5E5E5E" d="M1.30993,4.87982h7.38052v0.87738H1.30993V4.87982z"/> | |||
<path id="path5819" inkscape:connector-curvature="0" fill="#5E5E5E" d="M1.30993,8.42674h7.38052v0.87738H1.30993V8.42674z"/> | |||
<path id="path5821" inkscape:connector-curvature="0" fill="#5E5E5E" d="M1.30993,6.65414h7.38052v0.87738H1.30993V6.65414z"/> | |||
<path id="path5823" inkscape:connector-curvature="0" fill="#5E5E5E" d="M1.30993,3.10641h7.38052v0.87738H1.30993V3.10641z"/> | |||
<path id="path5825" inkscape:connector-curvature="0" fill="#797979" d="M1.30993,1.33289h7.38052v0.87738H1.30993V1.33289z"/> | |||
</g> | |||
</svg> |
@@ -0,0 +1,94 @@ | |||
Copyright (c) 2014, Cedric Knight <fonts@cedders.com>, | |||
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. |
@@ -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) { | |||
@@ -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); | |||
@@ -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); | |||
} | |||
}; | |||
@@ -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); | |||
@@ -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<UPSAMPLE> 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(); | |||
} | |||
@@ -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; | |||
} | |||
} | |||
} | |||
@@ -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<NoisePlethoraPlugin> 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<NoisePlethora*>(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<NoisePlethora*>(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<NoisePlethora*>(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> 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<Knurlie>(Vec(RACK_GRID_WIDTH, 0))); | |||
addChild(createWidget<Knurlie>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | |||
addChild(createWidget<Knurlie>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | |||
addChild(createWidget<Knurlie>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | |||
// A params | |||
addParam(createParamCentered<BefacoTinyKnobDarkGrey>(mm2px(Vec(22.325, 16.09)), module, NoisePlethora::X_A_PARAM)); | |||
addParam(createParamCentered<BefacoTinyKnobDarkGrey>(mm2px(Vec(22.325, 30.595)), module, NoisePlethora::Y_A_PARAM)); | |||
addParam(createParamCentered<Davies1900hLargeGreyKnob>(mm2px(Vec(43.248, 23.058)), module, NoisePlethora::CUTOFF_A_PARAM)); | |||
addParam(createParamCentered<BefacoTinyKnobDarkGrey>(mm2px(Vec(63.374, 16.09)), module, NoisePlethora::RES_A_PARAM)); | |||
addParam(createParamCentered<BefacoTinyKnobDarkGrey>(mm2px(Vec(63.374, 30.595)), module, NoisePlethora::CUTOFF_CV_A_PARAM)); | |||
addParam(createParam<CKSSNarrow3>(mm2px(Vec(41.494, 38.579)), module, NoisePlethora::FILTER_TYPE_A_PARAM)); | |||
// (bank) | |||
addParam(createParamCentered<BefacoTinyKnobSnapPress>(mm2px(Vec(30.866, 49.503)), module, NoisePlethora::PROGRAM_PARAM)); | |||
// B params | |||
addParam(createParamCentered<BefacoTinyKnobLightGrey>(mm2px(Vec(22.345, 68.408)), module, NoisePlethora::X_B_PARAM)); | |||
addParam(createParamCentered<BefacoTinyKnobLightGrey>(mm2px(Vec(22.345, 82.695)), module, NoisePlethora::Y_B_PARAM)); | |||
addParam(createParamCentered<Davies1900hLargeLightGreyKnob>(mm2px(Vec(43.248, 75.551)), module, NoisePlethora::CUTOFF_B_PARAM)); | |||
addParam(createParamCentered<BefacoTinyKnobLightGrey>(mm2px(Vec(63.383, 82.686)), module, NoisePlethora::RES_B_PARAM)); | |||
addParam(createParamCentered<BefacoTinyKnobLightGrey>(mm2px(Vec(63.36, 68.388)), module, NoisePlethora::CUTOFF_CV_B_PARAM)); | |||
addParam(createParam<CKSSNarrow3>(mm2px(Vec(41.494, 53.213)), module, NoisePlethora::FILTER_TYPE_B_PARAM)); | |||
// C params | |||
addParam(createParamCentered<BefacoTinyKnobBlack>(mm2px(Vec(7.6, 99.584)), module, NoisePlethora::GRIT_PARAM)); | |||
addParam(createParamCentered<BefacoTinyKnobDarkGrey>(mm2px(Vec(22.366, 99.584)), module, NoisePlethora::RES_C_PARAM)); | |||
addParam(createParamCentered<Davies1900hDarkGreyKnob>(mm2px(Vec(47.536, 98.015)), module, NoisePlethora::CUTOFF_C_PARAM)); | |||
addParam(createParamCentered<BefacoTinyKnobDarkGrey>(mm2px(Vec(63.36, 99.584)), module, NoisePlethora::CUTOFF_CV_C_PARAM)); | |||
addParam(createParam<CKSSNarrow3>(mm2px(Vec(33.19, 92.506)), module, NoisePlethora::FILTER_TYPE_C_PARAM)); | |||
addParam(createParam<CKSSHoriz2>(mm2px(Vec(31.707, 104.225)), module, NoisePlethora::SOURCE_C_PARAM)); | |||
addInput(createInputCentered<BefacoInputPort>(mm2px(Vec(6.431, 16.102)), module, NoisePlethora::X_A_INPUT)); | |||
addInput(createInputCentered<BefacoInputPort>(mm2px(Vec(6.431, 29.959)), module, NoisePlethora::Y_A_INPUT)); | |||
addInput(createInputCentered<BefacoInputPort>(mm2px(Vec(52.845, 42.224)), module, NoisePlethora::CUTOFF_A_INPUT)); | |||
addInput(createInputCentered<BefacoInputPort>(mm2px(Vec(6.431, 43.212)), module, NoisePlethora::PROG_A_INPUT)); | |||
addInput(createInputCentered<BefacoInputPort>(mm2px(Vec(6.431, 55.801)), module, NoisePlethora::PROG_B_INPUT)); | |||
addInput(createInputCentered<BefacoInputPort>(mm2px(Vec(52.845, 56.816)), module, NoisePlethora::CUTOFF_B_INPUT)); | |||
addInput(createInputCentered<BefacoInputPort>(mm2px(Vec(6.431, 68.398)), module, NoisePlethora::X_B_INPUT)); | |||
addInput(createInputCentered<BefacoInputPort>(mm2px(Vec(6.431, 82.729)), module, NoisePlethora::Y_B_INPUT)); | |||
addInput(createInputCentered<BefacoInputPort>(mm2px(Vec(7.555, 114.8)), module, NoisePlethora::GRIT_INPUT)); | |||
addInput(createInputCentered<BefacoInputPort>(mm2px(Vec(63.36, 114.8)), module, NoisePlethora::CUTOFF_C_INPUT)); | |||
addOutput(createOutputCentered<BefacoOutputPort>(mm2px(Vec(64.909, 44.397)), module, NoisePlethora::A_OUTPUT)); | |||
addOutput(createOutputCentered<BefacoOutputPort>(mm2px(Vec(64.915, 54.608)), module, NoisePlethora::B_OUTPUT)); | |||
addOutput(createOutputCentered<BefacoOutputPort>(mm2px(Vec(22.345, 114.852)), module, NoisePlethora::GRITTY_OUTPUT)); | |||
addOutput(createOutputCentered<BefacoOutputPort>(mm2px(Vec(34.981, 114.852)), module, NoisePlethora::FILTERED_OUTPUT)); | |||
addOutput(createOutputCentered<BefacoOutputPort>(mm2px(Vec(47.536, 114.852)), module, NoisePlethora::WHITE_OUTPUT)); | |||
addChild(createLightCentered<MediumLight<RedLight>>(mm2px(Vec(30.866, 37.422)), module, NoisePlethora::BANK_LIGHT)); | |||
NoisePlethoraLEDDisplay* displayA = createWidget<NoisePlethoraLEDDisplay>(mm2px(Vec(13.106, 38.172))); | |||
displayA->module = module; | |||
displayA->section = NoisePlethora::SECTION_A; | |||
addChild(displayA); | |||
NoisePlethoraLEDDisplay* displayB = createWidget<NoisePlethoraLEDDisplay>(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<NoisePlethora*>(this->module); | |||
assert(module); | |||
// build the two algorithm selection menus programmatically | |||
menu->addChild(createMenuLabel("Algorithms")); | |||
std::vector<std::string> 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, NoisePlethoraWidget>("NoisePlethora"); |
@@ -1,28 +0,0 @@ | |||
#pragma once | |||
#include <rack.hpp> | |||
/** 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); | |||
} | |||
}; |
@@ -1,5 +1,4 @@ | |||
#include "plugin.hpp" | |||
#include "PulseGenerator_4.hpp" | |||
using simd::float_4; | |||
@@ -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()) { | |||
@@ -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. |
@@ -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: | |||
 | |||
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): | |||
 | |||
@@ -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<Bank, numBanks> 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<Bank, programsPerBank> 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]; | |||
} |
@@ -0,0 +1,44 @@ | |||
#pragma once | |||
#include <string> | |||
#include <memory> | |||
#include <array> | |||
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<BankElem, programsPerBank> programs; | |||
}; | |||
Bank& getBankForIndex(int i); |
@@ -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 |
@@ -0,0 +1,90 @@ | |||
#pragma once | |||
#include <rack.hpp> | |||
#include <memory> | |||
#include <string> // string might not be allowed | |||
#include <functional> | |||
#include <map> | |||
#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<NoisePlethoraPlugin> 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<NoisePlethoraPlugin>(instance); | |||
} | |||
else { | |||
return nullptr; | |||
} | |||
} | |||
void RegisterFactoryFunction(std::string name, std::function<NoisePlethoraPlugin*(void)> classFactoryFunction) { | |||
// register the class factory function | |||
factoryFunctionRegistry[name] = classFactoryFunction; | |||
} | |||
std::map<std::string, std::function<NoisePlethoraPlugin*(void)>> factoryFunctionRegistry; | |||
}; | |||
template<class T> 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> NAME ##_reg(#NAME) |
@@ -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); |
@@ -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); |
@@ -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); |
@@ -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); |
@@ -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); |
@@ -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); |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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); |
@@ -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); |
@@ -0,0 +1,85 @@ | |||
#pragma once | |||
#include <rack.hpp> | |||
#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); |
@@ -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); |
@@ -0,0 +1,305 @@ | |||
#pragma once | |||
#include <cmath> | |||
#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 |
@@ -0,0 +1,49 @@ | |||
#pragma once | |||
#include "NoisePlethoraPlugin.hpp" | |||
#include <rack.hpp> | |||
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); |
@@ -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 |
@@ -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 |
@@ -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); |
@@ -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); |
@@ -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); |
@@ -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 |
@@ -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); |
@@ -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); |
@@ -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); |
@@ -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); |
@@ -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); |
@@ -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); |
@@ -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); |
@@ -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 |
@@ -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 |
@@ -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); |
@@ -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 |
@@ -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); |
@@ -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; | |||
}; |
@@ -0,0 +1,21 @@ | |||
#pragma once | |||
#include <rack.hpp> | |||
#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" |
@@ -0,0 +1,180 @@ | |||
#pragma once | |||
#include <rack.hpp> | |||
#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<int16_t, AUDIO_BLOCK_SAMPLES> 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; | |||
}; |
@@ -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 <stdint.h> | |||
#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 |
@@ -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++; | |||
} | |||
} | |||
} | |||
} | |||
@@ -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. | |||
}; | |||
@@ -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; | |||
} | |||
} |
@@ -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; | |||
}; |
@@ -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; | |||
} | |||
} | |||
} | |||
} | |||
@@ -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; | |||
}; |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
}; |
@@ -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); | |||
} | |||
@@ -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; | |||
}; | |||
@@ -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); | |||
} | |||
} | |||
@@ -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); | |||
}; |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
}; |
@@ -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; | |||
} | |||
@@ -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; | |||
}; |
@@ -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; | |||
}; |
@@ -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) | |||
}; |
@@ -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; | |||
} | |||
@@ -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 | |||
}; |
@@ -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; | |||
} | |||
} | |||
} | |||
@@ -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; | |||
}; |
@@ -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; | |||
}; | |||
@@ -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; | |||
}; | |||
@@ -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; | |||
@@ -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 |
@@ -23,4 +23,5 @@ void init(rack::Plugin *p) { | |||
p->addModel(modelSTMix); | |||
p->addModel(modelMuxlicer); | |||
p->addModel(modelMex); | |||
p->addModel(modelNoisePlethora); | |||
} |
@@ -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 <typename T> | |||
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<int N> | |||
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); | |||
} | |||
}; |