@@ -8,6 +8,7 @@ | |||
+ supports up to 8 audio inputs | |||
+ supports VST program chunks (=> patches are saved with the DAW's project file or as .fxp files) | |||
+ supports VST host timing (audioMasterGetTime / kVstTempoValid / kVstTransportPlaying, see Core.MIDI-1 module) | |||
+ supports VST parameters (send / recv) | |||
- does not support plugin DLLs due to VCV Rack's architecture which prevents this when it is run as a plugin itself | |||
- future releases may contain additional (open source) add-ons modules | |||
@@ -22,7 +23,7 @@ Tested in | |||
# Downloads | |||
The current release can be found in the [vst2_bin/](vst2_bin/) folder. | |||
Here's a snapshot of it: [veeseevstrack_0_6_1_win64_bin-09Jul2018.7z](dist/veeseevstrack_0_6_1_win64_bin-09Jul2018.7z) (64bit) | |||
Here's a snapshot of it: [veeseevstrack_0_6_1_win64_bin-10Jul2018.7z](dist/veeseevstrack_0_6_1_win64_bin-10Jul2018.7z) (64bit) | |||
**WARNING: DON'T TRY TO USE THE INSTRUMENT AND EFFECT PLUGINS IN THE SAME PROJECT OR YOUR DAW WILL CRASH.** | |||
@@ -40,7 +41,7 @@ Here's a demo video of it: https://vimeo.com/277703414 | |||
# Add-on modules | |||
The following add-on modules are statically linked with the VST plugin: | |||
The following (441) add-on modules are statically linked with the VST plugin: | |||
- Alikins.IdleSwitch | |||
- Alikins.MomentaryOnButtons | |||
- Alikins.BigMuteButton | |||
@@ -245,6 +246,23 @@ The following add-on modules are statically linked with the VST plugin: | |||
- Fundamentals.VCMixer | |||
- Fundamentals.VCO | |||
- Fundamentals.VCO2 | |||
- Gratrix.VCO_F1 | |||
- Gratrix.VCO_F2 | |||
- Gratrix.VCF_F1 | |||
- Gratrix.VCA_F1 | |||
- Gratrix.ADSR_F1 | |||
- Gratrix.Chord_G1 | |||
- Gratrix.Octave_G1 | |||
- Gratrix.Fade_G1 | |||
- Gratrix.Fade_G2 | |||
- Gratrix.Binary_G1 | |||
- Gratrix.Seq_G1 | |||
- Gratrix.Keys_G1 | |||
- Gratrix.VU_G1 | |||
- Gratrix.Blank_03 | |||
- Gratrix.Blank_06 | |||
- Gratrix.Blank_09 | |||
- Gratrix.Blank_12 | |||
- HetrickCV.TwoToFour | |||
- HetrickCV.AnalogToDigital | |||
- HetrickCV.ASR | |||
@@ -289,6 +307,10 @@ The following add-on modules are statically linked with the VST plugin: | |||
- LOGinstruments.LessMess | |||
- LOGinstruments.Velvet | |||
- LOGinstruments.Crystal | |||
- moDllz.MIDIPoly | |||
- moDllz.TwinGlider | |||
- moDllz.MIDIdualCV | |||
- moDllz.XBender | |||
- modular80.Logistiker | |||
- mscHack.MasterClockx4 | |||
- mscHack.Seq_3x16x16 | |||
@@ -318,8 +340,6 @@ The following add-on modules are statically linked with the VST plugin: | |||
- NauModular.Osc | |||
- ML_modules.Quantizer | |||
- ML_modules.Quantum | |||
- Southpole-parasites.Annuli | |||
- Southpole-parasites.Splash | |||
- ML_modules.TrigBuf | |||
- ML_modules.SeqSwitch | |||
- ML_modules.SeqSwitch2 | |||
@@ -354,6 +374,34 @@ The following add-on modules are statically linked with the VST plugin: | |||
- Qwelk.Scaler | |||
- Qwelk.Wrap | |||
- Qwelk.XFade | |||
- RJModules.Supersaw | |||
- RJModules.TwinLFO | |||
- RJModules.Noise | |||
- RJModules.RangeLFO | |||
- RJModules.BitCrush | |||
- RJModules.Widener | |||
- RJModules.FilterDelay | |||
- RJModules.Sidechain | |||
- RJModules.Stutter | |||
- RJModules.Filter | |||
- RJModules.Filters | |||
- RJModules.Notch | |||
- RJModules.Integers | |||
- RJModules.Floats | |||
- RJModules.Randoms | |||
- RJModules.LRMixer | |||
- RJModules.Mono | |||
- RJModules.Volumes | |||
- RJModules.Panner | |||
- RJModules.Panners | |||
- RJModules.BPM | |||
- RJModules.Button | |||
- RJModules.Buttons | |||
- RJModules.Splitter | |||
- RJModules.Splitters | |||
- RJModules.Displays | |||
- RJModules.Range | |||
- SerialRacker.MidiMultiplexer | |||
- SonusModular.Addiction | |||
- SonusModular.Bitter | |||
- SonusModular.Bymidside | |||
@@ -376,6 +424,8 @@ The following add-on modules are statically linked with the VST plugin: | |||
- SonusModular.Scramblase | |||
- SonusModular.Twoff | |||
- SonusModular.Yabp | |||
- Southpole-parasites.Annuli | |||
- Southpole-parasites.Splash | |||
- squinkylabs-plug1.Booty | |||
- squinkylabs-plug1.Vocal | |||
- squinkylabs-plug1.VocalFilter | |||
@@ -0,0 +1,26 @@ | |||
# Fundamental | |||
Copyright (c) 2016 Andrew Belt | |||
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. | |||
# kissfft | |||
Copyright (c) 2003-2010 Mark Borgerding | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | |||
* Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@@ -0,0 +1,7 @@ | |||
Copyright (c) 2017 Sam Gratrix | |||
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. |
@@ -0,0 +1,11 @@ | |||
SLUG = Gratrix | |||
VERSION = 0.6.0 | |||
FLAGS += -I../../src/core | |||
SOURCES += $(wildcard src/*.cpp) | |||
DISTRIBUTABLES += $(wildcard LICENSE*) res | |||
RACK_DIR ?= ../.. | |||
include $(RACK_DIR)/plugin.mk |
@@ -0,0 +1,5 @@ | |||
# Gratrix Modules for VCV Rack | |||
Please head over to [gratrix.net/vcvrack](http://gratrix.net/vcvrack/) for details. | |||
 |
@@ -0,0 +1,13 @@ | |||
#!/bin/bash | |||
for f in build/res/*.svg | |||
do | |||
b=$(basename "$f") | |||
r=${b%.*} | |||
# "/c/Program Files/Inkscape/Inkscape.exe" $f --export-png=res/${r}.png | |||
"/c/Program Files/Inkscape/Inkscape.exe" $f --export-plain-svg=res/${r}.svg --export-text-to-path | |||
# if [[ "$OSTYPE" == "msys" ]]; then | |||
# unix2dos res/${r}.svg | |||
# fi | |||
done |
@@ -0,0 +1,22 @@ | |||
ALL_OBJ= \ | |||
src/ADSR.o \ | |||
src/Binary-G1.o \ | |||
src/Blank03.o \ | |||
src/Blank06.o \ | |||
src/Blank09.o \ | |||
src/Blank12.o \ | |||
src/Chord-G1.o \ | |||
src/Fade-G1.o \ | |||
src/Fade-G2.o \ | |||
src/Gratrix.o \ | |||
src/Keys-G1.o \ | |||
src/MIDI-C1.o \ | |||
src/MIDI-G1.o \ | |||
src/Octave-G1.o \ | |||
src/Scope-G1.o \ | |||
src/Seq-G1.o \ | |||
src/Seq-G2.o \ | |||
src/VCA.o \ | |||
src/VCF.o \ | |||
src/VCO.o \ | |||
src/VU-G1.o |
@@ -0,0 +1,7 @@ | |||
SLUG=Gratrix | |||
include ../../../../dep/yac/install_msvc.mk | |||
include make.objects | |||
include ../../../build_plugin.mk |
@@ -0,0 +1,45 @@ | |||
<?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" | |||
id="svg8" | |||
version="1.1" | |||
viewBox="0 0 45 380"> | |||
<metadata | |||
id="metadata14"> | |||
<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="defs12" /> | |||
<rect | |||
id="rect2" | |||
style="fill:#CEE1FD;stroke:black;stroke-width:1" | |||
height="390" | |||
width="55" | |||
y="-5" | |||
x="-5" /> | |||
<rect | |||
id="rect4" | |||
style="fill:#BED7FC;stroke:black;stroke-width:1" | |||
height="35" | |||
width="55" | |||
y="-5" | |||
x="-5" /> | |||
<rect | |||
id="rect6" | |||
style="fill:#BED7FC;stroke:black;stroke-width:1" | |||
height="25" | |||
width="55" | |||
y="360" | |||
x="-5" /> | |||
</svg> |
@@ -0,0 +1,45 @@ | |||
<?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" | |||
id="svg8" | |||
version="1.1" | |||
viewBox="0 0 90 380"> | |||
<metadata | |||
id="metadata14"> | |||
<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="defs12" /> | |||
<rect | |||
id="rect2" | |||
style="fill:#CEE1FD;stroke:black;stroke-width:1" | |||
height="390" | |||
width="100" | |||
y="-5" | |||
x="-5" /> | |||
<rect | |||
id="rect4" | |||
style="fill:#BED7FC;stroke:black;stroke-width:1" | |||
height="35" | |||
width="100" | |||
y="-5" | |||
x="-5" /> | |||
<rect | |||
id="rect6" | |||
style="fill:#BED7FC;stroke:black;stroke-width:1" | |||
height="25" | |||
width="100" | |||
y="360" | |||
x="-5" /> | |||
</svg> |
@@ -0,0 +1,45 @@ | |||
<?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" | |||
id="svg8" | |||
version="1.1" | |||
viewBox="0 0 135 380"> | |||
<metadata | |||
id="metadata14"> | |||
<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="defs12" /> | |||
<rect | |||
id="rect2" | |||
style="fill:#CEE1FD;stroke:black;stroke-width:1" | |||
height="390" | |||
width="145" | |||
y="-5" | |||
x="-5" /> | |||
<rect | |||
id="rect4" | |||
style="fill:#BED7FC;stroke:black;stroke-width:1" | |||
height="35" | |||
width="145" | |||
y="-5" | |||
x="-5" /> | |||
<rect | |||
id="rect6" | |||
style="fill:#BED7FC;stroke:black;stroke-width:1" | |||
height="25" | |||
width="145" | |||
y="360" | |||
x="-5" /> | |||
</svg> |
@@ -0,0 +1,45 @@ | |||
<?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" | |||
id="svg8" | |||
version="1.1" | |||
viewBox="0 0 180 380"> | |||
<metadata | |||
id="metadata14"> | |||
<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="defs12" /> | |||
<rect | |||
id="rect2" | |||
style="fill:#CEE1FD;stroke:black;stroke-width:1" | |||
height="390" | |||
width="190" | |||
y="-5" | |||
x="-5" /> | |||
<rect | |||
id="rect4" | |||
style="fill:#BED7FC;stroke:black;stroke-width:1" | |||
height="35" | |||
width="190" | |||
y="-5" | |||
x="-5" /> | |||
<rect | |||
id="rect6" | |||
style="fill:#BED7FC;stroke:black;stroke-width:1" | |||
height="25" | |||
width="190" | |||
y="360" | |||
x="-5" /> | |||
</svg> |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-28 -28 56 56" version="1.1"> | |||
<circle cx="0" cy="0" r="27.25" style="fill:#333333;stroke:#000000;stroke-width:1.0" /> | |||
<path d="M-27.25,0 A1,1 0,0,0 27.25,0" style="fill:#000000;stroke:#000000;stroke-width:1.0" /> | |||
<line x1="0" y1="0" x2="0" y2="-28" style="fill:none; stroke:#eeeeee;stroke-width:1.5" /> | |||
</svg> |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-23 -23 46 46" version="1.1"> | |||
<circle cx="0" cy="0" r="22.3" style="fill:#333333;stroke:#000000;stroke-width:1.0" /> | |||
<path d="M-22.3,0 A1,1 0,0,0 22.3,0" style="fill:#000000;stroke:#000000;stroke-width:1.0" /> | |||
<line x1="0" y1="0" x2="0" y2="-23" style="fill:none; stroke:#eeeeee;stroke-width:1.5" /> | |||
</svg> |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-19 -19 38 38" version="1.1"> | |||
<circle cx="0" cy="0" r="18.35" style="fill:#333333;stroke:#000000;stroke-width:1.0" /> | |||
<path d="M-18.35,0 A1,1 0,0,0 18.35,0" style="fill:#000000;stroke:#000000;stroke-width:1.0" /> | |||
<line x1="0" y1="0" x2="0" y2="-19" style="fill:none; stroke:#eeeeee;stroke-width:1.5" /> | |||
</svg> |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-14 -14 28 28" version="1.1"> | |||
<circle cx="0" cy="0" r="13.4" style="fill:#333333;stroke:#000000;stroke-width:1.0" /> | |||
<path d="M-13.4,0 A1,1 0,0,0 13.4,0" style="fill:#000000;stroke:#000000;stroke-width:1.0" /> | |||
<line x1="0" y1="0" x2="0" y2="-14" style="fill:none; stroke:#eeeeee;stroke-width:1.5" /> | |||
</svg> |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-12.5 -12.5 25 25" version="1.1"> | |||
<circle cx="0" cy="0" r="11.9" style="fill:#777777;stroke:#000000;stroke-width:1.0" /> | |||
<line x1="0" y1="0" x2="0" y2="-11.9" style="fill:none; stroke:blue; stroke-width:2.0" /> | |||
<circle cx="0" cy="0" r="1" style="fill:blue; stroke:blue; stroke-width:1.0" /> | |||
</svg> |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-28 -28 56 56" version="1.1"> | |||
<circle cx="0" cy="0" r="27.25" style="fill:#333333;stroke:#000000;stroke-width:1.0" /> | |||
<path d="M-27.25,0 A1,1 0,0,0 27.25,0" style="fill:#000000;stroke:#000000;stroke-width:1.0" /> | |||
<line x1="0" y1="0" x2="0" y2="-28" style="fill:none; stroke:#eeeeee;stroke-width:1.5" /> | |||
</svg> |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-23 -23 46 46" version="1.1"> | |||
<circle cx="0" cy="0" r="22.3" style="fill:#333333;stroke:#000000;stroke-width:1.0" /> | |||
<path d="M-22.3,0 A1,1 0,0,0 22.3,0" style="fill:#000000;stroke:#000000;stroke-width:1.0" /> | |||
<line x1="0" y1="0" x2="0" y2="-23" style="fill:none; stroke:#eeeeee;stroke-width:1.5" /> | |||
</svg> |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-19 -19 38 38" version="1.1"> | |||
<circle cx="0" cy="0" r="18.35" style="fill:#333333;stroke:#000000;stroke-width:1.0" /> | |||
<path d="M-18.35,0 A1,1 0,0,0 18.35,0" style="fill:#000000;stroke:#000000;stroke-width:1.0" /> | |||
<line x1="0" y1="0" x2="0" y2="-19" style="fill:none; stroke:#eeeeee;stroke-width:1.5" /> | |||
</svg> |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-14 -14 28 28" version="1.1"> | |||
<circle cx="0" cy="0" r="13.4" style="fill:#333333;stroke:#000000;stroke-width:1.0" /> | |||
<path d="M-13.4,0 A1,1 0,0,0 13.4,0" style="fill:#000000;stroke:#000000;stroke-width:1.0" /> | |||
<line x1="0" y1="0" x2="0" y2="-14" style="fill:none; stroke:#eeeeee;stroke-width:1.5" /> | |||
</svg> |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-12.5 -12.5 25 25" version="1.1"> | |||
<circle cx="0" cy="0" r="11.9" style="fill:#777777;stroke:#000000;stroke-width:1.0" /> | |||
<line x1="0" y1="0" x2="0" y2="-11.9" style="fill:none; stroke:red; stroke-width:2.0" /> | |||
<circle cx="0" cy="0" r="1" style="fill:red; stroke:red; stroke-width:1.0" /> | |||
</svg> |
@@ -0,0 +1,11 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-12.5 -12.5 25 25" version="1.1"> | |||
<circle cx="0" cy="0" r="11.75" style="fill:#EEEEEE;stroke:#777777;stroke-width:1.0" /> | |||
<!--<line x1="0" y1="8" x2="0" y2="4.25" style="fill:none; stroke:green; stroke-width:2.0" />--> | |||
<circle cx="0" cy="0" r="8.0" style="fill:none; stroke:#777777;stroke-width:1.0" /> | |||
<circle cx="0" cy="0" r="4.25" style="fill:black; stroke:black; stroke-width:1.0" /> | |||
</svg> | |||
@@ -0,0 +1,11 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-9 -9 18 18" version="1.1"> | |||
<circle cx="0" cy="0" r="8" style="fill:#EEEEEE;stroke:none; stroke-width:1.0" /> | |||
<!--<line x1="0" y1="8" x2="0" y2="4.25" style="fill:none; stroke:green; stroke-width:2.0" />--> | |||
<circle cx="0" cy="0" r="8.0" style="fill:none; stroke:#777777;stroke-width:1.0" /> | |||
<circle cx="0" cy="0" r="4.25" style="fill:black; stroke:black; stroke-width:1.0" /> | |||
</svg> | |||
@@ -0,0 +1,11 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-12.5 -12.5 25 25" version="1.1"> | |||
<circle cx="0" cy="0" r="11.75" style="fill:#EEEEEE;stroke:#777777;stroke-width:1.0" /> | |||
<!--<line x1="0" y1="8" x2="0" y2="4.25" style="fill:none; stroke:red; stroke-width:2.0" />--> | |||
<circle cx="0" cy="0" r="8.0" style="fill:none; stroke:#777777;stroke-width:1.0" /> | |||
<circle cx="0" cy="0" r="4.25" style="fill:black; stroke:black; stroke-width:1.0" /> | |||
</svg> | |||
@@ -0,0 +1,11 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-9 -9 18 18" version="1.1"> | |||
<circle cx="0" cy="0" r="8" style="fill:#EEEEEE;stroke:none; stroke-width:1.0" /> | |||
<!--<line x1="0" y1="8" x2="0" y2="4.25" style="fill:none; stroke:red; stroke-width:2.0" />--> | |||
<circle cx="0" cy="0" r="8.0" style="fill:none; stroke:#777777;stroke-width:1.0" /> | |||
<circle cx="0" cy="0" r="4.25" style="fill:black; stroke:black; stroke-width:1.0" /> | |||
</svg> | |||
@@ -0,0 +1,93 @@ | |||
Sudo is Copyright (c) 2009-2016, Jens Kutilek (http://www.kutilek.de/). | |||
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. |
@@ -0,0 +1 @@ | |||
Font is public domain and was obtained from http://www.fontspace.com/lcd-solid/lcd-solid |
@@ -0,0 +1,201 @@ | |||
#include "Gratrix.hpp" | |||
#include "dsp/digital.hpp" | |||
namespace rack_plugin_Gratrix { | |||
//============================================================================================================ | |||
struct ADSR : MicroModule { | |||
enum ParamIds { | |||
ATTACK_PARAM, | |||
DECAY_PARAM, | |||
SUSTAIN_PARAM, | |||
RELEASE_PARAM, | |||
NUM_PARAMS | |||
}; | |||
enum InputIds { | |||
ATTACK_INPUT, // 1 | |||
DECAY_INPUT, // 1 | |||
SUSTAIN_INPUT, // 1 | |||
RELEASE_INPUT, // 1 | |||
GATE_INPUT, // N+1 | |||
TRIG_INPUT, // N+1 | |||
NUM_INPUTS, | |||
OFF_INPUTS = GATE_INPUT | |||
}; | |||
enum OutputIds { | |||
ENVELOPE_OUTPUT, // N | |||
INVERTED_OUTPUT, // N | |||
NUM_OUTPUTS, | |||
OFF_OUTPUTS = ENVELOPE_OUTPUT | |||
}; | |||
enum LightIds { | |||
NUM_LIGHTS | |||
}; | |||
bool decaying = false; | |||
float env = 0.0f; | |||
SchmittTrigger trigger; | |||
ADSR() : MicroModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} | |||
void step(); | |||
}; | |||
//============================================================================================================ | |||
void ADSR::step() { | |||
float attack = clamp(params[ATTACK_INPUT].value + inputs[ATTACK_INPUT].value / 10.0f, 0.0f, 1.0f); | |||
float decay = clamp(params[DECAY_PARAM].value + inputs[DECAY_INPUT].value / 10.0f, 0.0f, 1.0f); | |||
float sustain = clamp(params[SUSTAIN_PARAM].value + inputs[SUSTAIN_INPUT].value / 10.0f, 0.0f, 1.0f); | |||
float release = clamp(params[RELEASE_PARAM].value + inputs[RELEASE_PARAM].value / 10.0f, 0.0f, 1.0f); | |||
// Gate and trigger | |||
bool gated = inputs[GATE_INPUT].value >= 1.0f; | |||
if (trigger.process(inputs[TRIG_INPUT].value)) | |||
decaying = false; | |||
const float base = 20000.0f; | |||
const float maxTime = 10.0f; | |||
if (gated) { | |||
if (decaying) { | |||
// Decay | |||
if (decay < 1e-4) { | |||
env = sustain; | |||
} | |||
else { | |||
env += powf(base, 1 - decay) / maxTime * (sustain - env) * engineGetSampleTime(); | |||
} | |||
} | |||
else { | |||
// Attack | |||
// Skip ahead if attack is all the way down (infinitely fast) | |||
if (attack < 1e-4) { | |||
env = 1.0f; | |||
} | |||
else { | |||
env += powf(base, 1 - attack) / maxTime * (1.01f - env) * engineGetSampleTime(); | |||
} | |||
if (env >= 1.0f) { | |||
env = 1.0f; | |||
decaying = true; | |||
} | |||
} | |||
} | |||
else { | |||
// Release | |||
if (release < 1e-4) { | |||
env = 0.0f; | |||
} | |||
else { | |||
env += powf(base, 1 - release) / maxTime * (0.0f - env) * engineGetSampleTime(); | |||
} | |||
decaying = false; | |||
} | |||
outputs[ENVELOPE_OUTPUT].value = 10.0 * env; | |||
outputs[INVERTED_OUTPUT].value = 10.0 * (1.0 - env); | |||
} | |||
//============================================================================================================ | |||
struct GtxModule_ADSR : Module | |||
{ | |||
std::array<ADSR, GTX__N> inst; | |||
GtxModule_ADSR() | |||
: | |||
Module(ADSR::NUM_PARAMS, | |||
(GTX__N+1) * (ADSR::NUM_INPUTS - ADSR::OFF_INPUTS ) + ADSR::OFF_INPUTS, | |||
(GTX__N ) * (ADSR::NUM_OUTPUTS - ADSR::OFF_OUTPUTS) + ADSR::OFF_OUTPUTS) | |||
{} | |||
static constexpr std::size_t imap(std::size_t port, std::size_t bank) | |||
{ | |||
return (port < ADSR::OFF_INPUTS) ? port : port + bank * (ADSR::NUM_INPUTS - ADSR::OFF_INPUTS); | |||
} | |||
static constexpr std::size_t omap(std::size_t port, std::size_t bank) | |||
{ | |||
// return (port < ADSR::OFF_OUTPUTS) ? port : port + bank * (ADSR::NUM_OUTPUTS - ADSR::OFF_OUTPUTS); | |||
return port + bank * ADSR::NUM_OUTPUTS; | |||
} | |||
void step() override | |||
{ | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
for (std::size_t p=0; p<ADSR::NUM_PARAMS; ++p) inst[i].params[p] = params[p]; | |||
for (std::size_t p=0; p<ADSR::NUM_INPUTS; ++p) inst[i].inputs[p] = inputs[imap(p, i)].active ? inputs[imap(p, i)] : inputs[imap(p, GTX__N)]; | |||
for (std::size_t p=0; p<ADSR::NUM_OUTPUTS; ++p) inst[i].outputs[p] = outputs[omap(p, i)]; | |||
inst[i].step(); | |||
for (std::size_t p=0; p<ADSR::NUM_OUTPUTS; ++p) outputs[omap(p, i)].value = inst[i].outputs[p].value; | |||
} | |||
} | |||
}; | |||
//============================================================================================================ | |||
struct GtxWidget_ADSR : ModuleWidget | |||
{ | |||
GtxWidget_ADSR(GtxModule_ADSR *module) : ModuleWidget(module) | |||
{ | |||
GTX__WIDGET(); | |||
box.size = Vec(12*15, 380); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/ADSR-F1.svg"), box.size, "ADSR-F1"); | |||
pg.nob_med(0, -0.28, "ATTACK"); pg.nob_med(1, -0.28, "DECAY"); | |||
pg.nob_med(0, +0.28, "SUSTAIN"); pg.nob_med(1, +0.28, "RELEASE"); | |||
pg.bus_in(0, 1, "GATE"); pg.bus_out(1, 1, "OUT"); | |||
pg.bus_in(0, 2, "TRIG"); pg.bus_out(1, 2, "INV OUT"); | |||
} | |||
#endif | |||
setPanel(SVG::load(assetPlugin(plugin, "res/ADSR-F1.svg"))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365))); | |||
addParam(createParamGTX<KnobFreeMed>(Vec(fx(0+0.18), fy(-0.28)), module, ADSR::ATTACK_PARAM, 0.0, 1.0, 0.5)); | |||
addParam(createParamGTX<KnobFreeMed>(Vec(fx(1+0.18), fy(-0.28)), module, ADSR::DECAY_PARAM, 0.0, 1.0, 0.5)); | |||
addParam(createParamGTX<KnobFreeMed>(Vec(fx(0+0.18), fy(+0.28)), module, ADSR::SUSTAIN_PARAM, 0.0, 1.0, 0.5)); | |||
addParam(createParamGTX<KnobFreeMed>(Vec(fx(1+0.18), fy(+0.28)), module, ADSR::RELEASE_PARAM, 0.0, 1.0, 0.5)); | |||
addInput(createInputGTX<PortInMed>(Vec(fx(0-0.28), fy(-0.28)), module, ADSR::ATTACK_INPUT)); | |||
addInput(createInputGTX<PortInMed>(Vec(fx(1-0.28), fy(-0.28)), module, ADSR::DECAY_INPUT)); | |||
addInput(createInputGTX<PortInMed>(Vec(fx(0-0.28), fy(+0.28)), module, ADSR::SUSTAIN_INPUT)); | |||
addInput(createInputGTX<PortInMed>(Vec(fx(1-0.28), fy(+0.28)), module, ADSR::RELEASE_INPUT)); | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(1, i)), module, GtxModule_ADSR::imap(ADSR::GATE_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(2, i)), module, GtxModule_ADSR::imap(ADSR::TRIG_INPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(1, i), py(1, i)), module, GtxModule_ADSR::omap(ADSR::ENVELOPE_OUTPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(1, i), py(2, i)), module, GtxModule_ADSR::omap(ADSR::INVERTED_OUTPUT, i))); | |||
} | |||
addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(1)), module, GtxModule_ADSR::imap(ADSR::GATE_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(2)), module, GtxModule_ADSR::imap(ADSR::TRIG_INPUT, GTX__N))); | |||
} | |||
}; | |||
} // namespace rack_plugin_Gratrix | |||
using namespace rack_plugin_Gratrix; | |||
RACK_PLUGIN_MODEL_INIT(Gratrix, ADSR_F1) { | |||
Model *model = Model::create<GtxModule_ADSR, GtxWidget_ADSR>("Gratrix", "ADSR-F1", "ADSR-F1", ENVELOPE_GENERATOR_TAG); | |||
return model; | |||
} |
@@ -0,0 +1,213 @@ | |||
//============================================================================================================ | |||
//! | |||
//! \file Binary-G1.cpp | |||
//! | |||
//! \brief Binary-G1 provides some simple logic gates. | |||
//! | |||
//============================================================================================================ | |||
#include "Gratrix.hpp" | |||
namespace rack_plugin_Gratrix { | |||
//============================================================================================================ | |||
//! \brief The module. | |||
struct GtxModule_Binary_G1 : Module | |||
{ | |||
enum ParamIds { | |||
INVERT_A_PARAM, | |||
INVERT_B_PARAM, | |||
FUNCTION_AB_1_PARAM, | |||
FUNCTION_AB_2_PARAM, | |||
INVERT_1_PARAM, | |||
INVERT_2_PARAM, | |||
NUM_PARAMS | |||
}; | |||
enum InputIds { | |||
IN_A_INPUT, | |||
IN_B_INPUT, | |||
NUM_INPUTS, | |||
OFF_INPUTS = IN_A_INPUT | |||
}; | |||
enum OutputIds { | |||
OUT_1_OUTPUT, | |||
OUT_2_OUTPUT, | |||
NUM_OUTPUTS, | |||
OFF_OUTPUTS = OUT_1_OUTPUT | |||
}; | |||
enum LightIds { | |||
FUNCTION_0_AB_1_LIGHT, | |||
FUNCTION_1_AB_1_LIGHT, | |||
FUNCTION_2_AB_1_LIGHT, | |||
FUNCTION_3_AB_1_LIGHT, | |||
FUNCTION_4_AB_1_LIGHT, | |||
FUNCTION_0_AB_2_LIGHT, | |||
FUNCTION_1_AB_2_LIGHT, | |||
FUNCTION_2_AB_2_LIGHT, | |||
FUNCTION_3_AB_2_LIGHT, | |||
FUNCTION_4_AB_2_LIGHT, | |||
NUM_LIGHTS | |||
}; | |||
GtxModule_Binary_G1() | |||
: | |||
Module(NUM_PARAMS, | |||
(GTX__N+1) * (NUM_INPUTS - OFF_INPUTS ) + OFF_INPUTS, | |||
(GTX__N ) * (NUM_OUTPUTS - OFF_OUTPUTS) + OFF_OUTPUTS, | |||
NUM_LIGHTS) | |||
{ | |||
} | |||
static constexpr std::size_t imap(std::size_t port, std::size_t bank) | |||
{ | |||
return port + bank * NUM_INPUTS; | |||
} | |||
static constexpr std::size_t omap(std::size_t port, std::size_t bank) | |||
{ | |||
return port + bank * NUM_OUTPUTS; | |||
} | |||
void step() override | |||
{ | |||
float leds[NUM_LIGHTS] = {}; | |||
int fn1 = FUNCTION_0_AB_1_LIGHT + static_cast<int>(params[FUNCTION_AB_1_PARAM].value + 0.5f); | |||
int fn2 = FUNCTION_0_AB_2_LIGHT + static_cast<int>(params[FUNCTION_AB_2_PARAM].value + 0.5f); | |||
if (fn1 >= FUNCTION_0_AB_1_LIGHT && fn1 <= FUNCTION_4_AB_1_LIGHT) leds[fn1] = 1.0; | |||
if (fn2 >= FUNCTION_0_AB_2_LIGHT && fn2 <= FUNCTION_4_AB_2_LIGHT) leds[fn2] = 1.0; | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
bool inA = (inputs[imap(IN_A_INPUT, i)].active ? inputs[imap(IN_A_INPUT, i)].value : inputs[imap(IN_A_INPUT, GTX__N)].value) >= 1.0f; | |||
bool inB = (inputs[imap(IN_B_INPUT, i)].active ? inputs[imap(IN_B_INPUT, i)].value : inputs[imap(IN_B_INPUT, GTX__N)].value) >= 1.0f; | |||
inA ^= (params[INVERT_A_PARAM].value < 0.5f); | |||
inB ^= (params[INVERT_B_PARAM].value < 0.5f); | |||
bool out1, out2; | |||
switch (fn1) | |||
{ | |||
case FUNCTION_0_AB_1_LIGHT : out1 = inA ; break; | |||
case FUNCTION_1_AB_1_LIGHT : out1 = inB; break; | |||
case FUNCTION_2_AB_1_LIGHT : out1 = inA & inB; break; | |||
case FUNCTION_3_AB_1_LIGHT : out1 = inA | inB; break; | |||
case FUNCTION_4_AB_1_LIGHT : out1 = inA ^ inB; break; | |||
default : out1 = false; | |||
} | |||
switch (fn2) | |||
{ | |||
case FUNCTION_0_AB_2_LIGHT : out2 = inA ; break; | |||
case FUNCTION_1_AB_2_LIGHT : out2 = inB; break; | |||
case FUNCTION_2_AB_2_LIGHT : out2 = inA & inB; break; | |||
case FUNCTION_3_AB_2_LIGHT : out2 = inA | inB; break; | |||
case FUNCTION_4_AB_2_LIGHT : out2 = inA ^ inB; break; | |||
default : out2 = false; | |||
} | |||
out1 ^= (params[INVERT_1_PARAM].value < 0.5f); | |||
out2 ^= (params[INVERT_2_PARAM].value < 0.5f); | |||
outputs[omap(OUT_1_OUTPUT, i)].value = out1 ? 10.0f : 0.0f; | |||
outputs[omap(OUT_2_OUTPUT, i)].value = out2 ? 10.0f : 0.0f; | |||
} | |||
for (std::size_t i=0; i<NUM_LIGHTS; ++i) | |||
{ | |||
lights[i].value = leds[i]; | |||
} | |||
} | |||
}; | |||
//============================================================================================================ | |||
//! \brief The widget. | |||
struct GtxWidget_Binary_G1 : ModuleWidget | |||
{ | |||
GtxWidget_Binary_G1(GtxModule_Binary_G1 *module) : ModuleWidget(module) | |||
{ | |||
GTX__WIDGET(); | |||
box.size = Vec(12*15, 380); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/Binary-G1.svg"), box.size, "BINARY-G1"); | |||
pg.nob_sml_raw(fx(1 - 0.75) - 3, fy(-0.28), "OP 1"); | |||
pg.nob_sml_raw(fx(1 - 0.75) - 3, fy(+0.28), "OP 2"); | |||
pg.tog(1 - 1.27, -0.28, "A", "INV A"); pg.tog(1.27, -0.28, "1", "INV 1"); | |||
pg.tog(1 - 1.27, +0.28, "B", "INV B"); pg.tog(1.27, +0.28, "2", "INV 2"); | |||
pg.text(Vec(fx(0.72) - 5, fy(-0.28) - 6 * rad_l_s() + 3), "A", 10, "start"); | |||
pg.text(Vec(fx(0.72) - 5, fy(-0.28) - 3 * rad_l_s() + 3), "B", 10, "start"); | |||
pg.text(Vec(fx(0.72) - 5, fy(-0.28) - 0 * rad_l_s() + 3), "AND", 10, "start"); | |||
pg.text(Vec(fx(0.72) - 5, fy(-0.28) + 3 * rad_l_s() + 3), "OR", 10, "start"); | |||
pg.text(Vec(fx(0.72) - 5, fy(-0.28) + 6 * rad_l_s() + 3), "XOR", 10, "start"); | |||
pg.text(Vec(fx(0.72) - 5, fy(+0.28) - 6 * rad_l_s() + 3), "A", 10, "start"); | |||
pg.text(Vec(fx(0.72) - 5, fy(+0.28) - 3 * rad_l_s() + 3), "B", 10, "start"); | |||
pg.text(Vec(fx(0.72) - 5, fy(+0.28) - 0 * rad_l_s() + 3), "AND", 10, "start"); | |||
pg.text(Vec(fx(0.72) - 5, fy(+0.28) + 3 * rad_l_s() + 3), "OR", 10, "start"); | |||
pg.text(Vec(fx(0.72) - 5, fy(+0.28) + 6 * rad_l_s() + 3), "XOR", 10, "start"); | |||
pg.bus_in(0, 1, "IN A"); pg.bus_out(1, 1, "OUT 1"); | |||
pg.bus_in(0, 2, "IN B"); pg.bus_out(1, 2, "OUT 2"); | |||
} | |||
#endif | |||
setPanel(SVG::load(assetPlugin(plugin, "res/Binary-G1.svg"))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365))); | |||
addParam(ParamWidget::create<CKSS>( tog(fx(1 - 1.27) , fy(-0.28)), module, GtxModule_Binary_G1::INVERT_A_PARAM, 0.0, 1.0, 1.0)); | |||
addParam(ParamWidget::create<CKSS>( tog(fx(1 - 1.27) , fy(+0.28)), module, GtxModule_Binary_G1::INVERT_B_PARAM, 0.0, 1.0, 1.0)); | |||
addParam(createParamGTX<KnobSnapSml>(Vec(fx(1 - 0.75) - 3, fy(-0.28)), module, GtxModule_Binary_G1::FUNCTION_AB_1_PARAM, 0.0, 4.0, 2.0)); | |||
addParam(createParamGTX<KnobSnapSml>(Vec(fx(1 - 0.75) - 3, fy(+0.28)), module, GtxModule_Binary_G1::FUNCTION_AB_2_PARAM, 0.0, 4.0, 2.0)); | |||
addParam(ParamWidget::create<CKSS>( tog(fx( 1.27) , fy(-0.28)), module, GtxModule_Binary_G1::INVERT_1_PARAM, 0.0, 1.0, 1.0)); | |||
addParam(ParamWidget::create<CKSS>( tog(fx( 1.27) , fy(+0.28)), module, GtxModule_Binary_G1::INVERT_2_PARAM, 0.0, 1.0, 1.0)); | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(1, i)), module, GtxModule_Binary_G1::imap(GtxModule_Binary_G1::IN_A_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(2, i)), module, GtxModule_Binary_G1::imap(GtxModule_Binary_G1::IN_B_INPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(1, i), py(1, i)), module, GtxModule_Binary_G1::omap(GtxModule_Binary_G1::OUT_1_OUTPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(1, i), py(2, i)), module, GtxModule_Binary_G1::omap(GtxModule_Binary_G1::OUT_2_OUTPUT, i))); | |||
} | |||
addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(1)), module, GtxModule_Binary_G1::imap(GtxModule_Binary_G1::IN_A_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(2)), module, GtxModule_Binary_G1::imap(GtxModule_Binary_G1::IN_B_INPUT, GTX__N))); | |||
addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(l_s(fx(0.72) - 2.5 * rad_l_s() - 5, fy(-0.28) - 6 * rad_l_s()), module, GtxModule_Binary_G1::FUNCTION_0_AB_1_LIGHT)); | |||
addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(l_s(fx(0.72) - 2.5 * rad_l_s() - 5, fy(-0.28) - 3 * rad_l_s()), module, GtxModule_Binary_G1::FUNCTION_1_AB_1_LIGHT)); | |||
addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(l_s(fx(0.72) - 2.5 * rad_l_s() - 5, fy(-0.28) - 0 * rad_l_s()), module, GtxModule_Binary_G1::FUNCTION_2_AB_1_LIGHT)); | |||
addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(l_s(fx(0.72) - 2.5 * rad_l_s() - 5, fy(-0.28) + 3 * rad_l_s()), module, GtxModule_Binary_G1::FUNCTION_3_AB_1_LIGHT)); | |||
addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(l_s(fx(0.72) - 2.5 * rad_l_s() - 5, fy(-0.28) + 6 * rad_l_s()), module, GtxModule_Binary_G1::FUNCTION_4_AB_1_LIGHT)); | |||
addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(l_s(fx(0.72) - 2.5 * rad_l_s() - 5, fy(+0.28) - 6 * rad_l_s()), module, GtxModule_Binary_G1::FUNCTION_0_AB_2_LIGHT)); | |||
addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(l_s(fx(0.72) - 2.5 * rad_l_s() - 5, fy(+0.28) - 3 * rad_l_s()), module, GtxModule_Binary_G1::FUNCTION_1_AB_2_LIGHT)); | |||
addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(l_s(fx(0.72) - 2.5 * rad_l_s() - 5, fy(+0.28) - 0 * rad_l_s()), module, GtxModule_Binary_G1::FUNCTION_2_AB_2_LIGHT)); | |||
addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(l_s(fx(0.72) - 2.5 * rad_l_s() - 5, fy(+0.28) + 3 * rad_l_s()), module, GtxModule_Binary_G1::FUNCTION_3_AB_2_LIGHT)); | |||
addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(l_s(fx(0.72) - 2.5 * rad_l_s() - 5, fy(+0.28) + 6 * rad_l_s()), module, GtxModule_Binary_G1::FUNCTION_4_AB_2_LIGHT)); | |||
} | |||
}; | |||
} // namespace rack_plugin_Gratrix | |||
using namespace rack_plugin_Gratrix; | |||
RACK_PLUGIN_MODEL_INIT(Gratrix, Binary_G1) { | |||
Model *model = Model::create<GtxModule_Binary_G1, GtxWidget_Binary_G1>("Gratrix", "Binary-G1", "Binary-G1", LOGIC_TAG); | |||
return model; | |||
} |
@@ -0,0 +1,55 @@ | |||
//============================================================================================================ | |||
//! | |||
//! \file Blank03.cpp | |||
//! | |||
//! \brief Blank 3 is a simple do nothing 3-hole high quality blank. | |||
//! | |||
//============================================================================================================ | |||
#include "Gratrix.hpp" | |||
namespace rack_plugin_Gratrix { | |||
//============================================================================================================ | |||
//! \brief The module. | |||
struct GtxModule_Blank_03 : Module | |||
{ | |||
GtxModule_Blank_03() : Module(0, 0, 0) {} | |||
}; | |||
//============================================================================================================ | |||
//! \brief The widget. | |||
struct GtxWidget_Blank_03 : ModuleWidget | |||
{ | |||
GtxWidget_Blank_03(GtxModule_Blank_03 *module) : ModuleWidget(module) | |||
{ | |||
GTX__WIDGET(); | |||
box.size = Vec(3*15, 380); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/Blank03.svg"), box.size); | |||
} | |||
#endif | |||
setPanel(SVG::load(assetPlugin(plugin, "res/Blank03.svg"))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365))); | |||
} | |||
}; | |||
} // namespace rack_plugin_Gratrix | |||
using namespace rack_plugin_Gratrix; | |||
RACK_PLUGIN_MODEL_INIT(Gratrix, Blank_03) { | |||
Model *model = Model::create<GtxModule_Blank_03, GtxWidget_Blank_03>("Gratrix", "Blank3", "Blank 3", BLANK_TAG); | |||
return model; | |||
} |
@@ -0,0 +1,55 @@ | |||
//============================================================================================================ | |||
//! | |||
//! \file Blank06.cpp | |||
//! | |||
//! \brief Blank 6 is a simple do nothing 6-hole high quality blank. | |||
//! | |||
//============================================================================================================ | |||
#include "Gratrix.hpp" | |||
namespace rack_plugin_Gratrix { | |||
//============================================================================================================ | |||
//! \brief The module. | |||
struct GtxModule_Blank_06 : Module | |||
{ | |||
GtxModule_Blank_06() : Module(0, 0, 0) {} | |||
}; | |||
//============================================================================================================ | |||
//! \brief The widget. | |||
struct GtxWidget_Blank_06 : ModuleWidget | |||
{ | |||
GtxWidget_Blank_06(GtxModule_Blank_06 *module) : ModuleWidget(module) | |||
{ | |||
GTX__WIDGET(); | |||
box.size = Vec(6*15, 380); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/Blank06.svg"), box.size); | |||
} | |||
#endif | |||
setPanel(SVG::load(assetPlugin(plugin, "res/Blank06.svg"))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365))); | |||
} | |||
}; | |||
} // namespace rack_plugin_Gratrix | |||
using namespace rack_plugin_Gratrix; | |||
RACK_PLUGIN_MODEL_INIT(Gratrix, Blank_06) { | |||
Model *model = Model::create<GtxModule_Blank_06, GtxWidget_Blank_06>("Gratrix", "Blank6", "Blank 6", BLANK_TAG); | |||
return model; | |||
} |
@@ -0,0 +1,55 @@ | |||
//============================================================================================================ | |||
//! | |||
//! \file Blank09.cpp | |||
//! | |||
//! \brief Blank 9 is a simple do nothing 9-hole high quality blank. | |||
//! | |||
//============================================================================================================ | |||
#include "Gratrix.hpp" | |||
namespace rack_plugin_Gratrix { | |||
//============================================================================================================ | |||
//! \brief The module. | |||
struct GtxModule_Blank_09 : Module | |||
{ | |||
GtxModule_Blank_09() : Module(0, 0, 0) {} | |||
}; | |||
//============================================================================================================ | |||
//! \brief The widget. | |||
struct GtxWidget_Blank_09 : ModuleWidget | |||
{ | |||
GtxWidget_Blank_09(GtxModule_Blank_09 *module) : ModuleWidget(module) | |||
{ | |||
GTX__WIDGET(); | |||
box.size = Vec(9*15, 380); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/Blank09.svg"), box.size); | |||
} | |||
#endif | |||
setPanel(SVG::load(assetPlugin(plugin, "res/Blank09.svg"))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365))); | |||
} | |||
}; | |||
} // namespace rack_plugin_Gratrix | |||
using namespace rack_plugin_Gratrix; | |||
RACK_PLUGIN_MODEL_INIT(Gratrix, Blank_09) { | |||
Model *model = Model::create<GtxModule_Blank_09, GtxWidget_Blank_09>("Gratrix", "Blank9", "Blank 9", BLANK_TAG); | |||
return model; | |||
} |
@@ -0,0 +1,55 @@ | |||
//============================================================================================================ | |||
//! | |||
//! \file Blank12.cpp | |||
//! | |||
//! \brief Blank 12 is a simple do nothing 12-hole high quality blank. | |||
//! | |||
//============================================================================================================ | |||
#include "Gratrix.hpp" | |||
namespace rack_plugin_Gratrix { | |||
//============================================================================================================ | |||
//! \brief The module. | |||
struct GtxModule_Blank_12 : Module | |||
{ | |||
GtxModule_Blank_12() : Module(0, 0, 0) {} | |||
}; | |||
//============================================================================================================ | |||
//! \brief The widget. | |||
struct GtxWidget_Blank_12 : ModuleWidget | |||
{ | |||
GtxWidget_Blank_12(GtxModule_Blank_12 *module) : ModuleWidget(module) | |||
{ | |||
GTX__WIDGET(); | |||
box.size = Vec(12*15, 380); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/Blank12.svg"), box.size); | |||
} | |||
#endif | |||
setPanel(SVG::load(assetPlugin(plugin, "res/Blank12.svg"))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365))); | |||
} | |||
}; | |||
} // namespace rack_plugin_Gratrix | |||
using namespace rack_plugin_Gratrix; | |||
RACK_PLUGIN_MODEL_INIT(Gratrix, Blank_12) { | |||
Model *model = Model::create<GtxModule_Blank_12, GtxWidget_Blank_12>("Gratrix", "Blank12", "Blank 12", BLANK_TAG); | |||
return model; | |||
} |
@@ -0,0 +1,374 @@ | |||
//============================================================================================================ | |||
//! | |||
//! \file Chord-G1.cpp | |||
//! | |||
//! \brief Chord-G1 genearates chords via a CV program selection and a fundamental bass note V/octave input. | |||
//! | |||
//============================================================================================================ | |||
#include "Gratrix.hpp" | |||
#include "dsp/digital.hpp" | |||
namespace rack_plugin_Gratrix { | |||
//============================================================================================================ | |||
//! \brief Some settings. | |||
enum Spec | |||
{ | |||
E = 12, // ET | |||
T = 25, // ET | |||
N = GTX__N | |||
}; | |||
//============================================================================================================ | |||
//! \brief The module. | |||
struct GtxModule_Chord_G1 : Module | |||
{ | |||
enum ParamIds { | |||
PROG_PARAM = 0, | |||
NOTE_PARAM = PROG_PARAM + 1, | |||
NUM_PARAMS = NOTE_PARAM + T | |||
}; | |||
enum InputIds { | |||
PROG_INPUT, // 1 | |||
GATE_INPUT, // 1 | |||
VOCT_INPUT, // 1 | |||
NUM_INPUTS, | |||
OFF_INPUTS = VOCT_INPUT | |||
}; | |||
enum OutputIds { | |||
GATE_OUTPUT, // N | |||
VOCT_OUTPUT, // N | |||
NUM_OUTPUTS, | |||
OFF_OUTPUTS = GATE_OUTPUT | |||
}; | |||
enum LightIds { | |||
PROG_LIGHT = 0, | |||
NOTE_LIGHT = PROG_LIGHT + 2*E, | |||
FUND_LIGHT = NOTE_LIGHT + 2*T, | |||
NUM_LIGHTS = FUND_LIGHT + E | |||
}; | |||
struct Decode | |||
{ | |||
/*static constexpr*/ float e = static_cast<float>(E); // Static constexpr gives | |||
/*static constexpr*/ float s = 1.0f / e; // link error on Mac build. | |||
float in = 0; //!< Raw input. | |||
float out = 0; //!< Input quantized. | |||
int note = 0; //!< Integer note (offset midi note). | |||
int key = 0; //!< C, C#, D, D#, etc. | |||
int oct = 0; //!< Octave (C4 = 0). | |||
void step(float input) | |||
{ | |||
int safe, fnote; | |||
in = input; | |||
fnote = std::floor(in * e + 0.5f); | |||
out = fnote * s; | |||
note = static_cast<int>(fnote); | |||
safe = note + (E * 1000); // push away from negative numbers | |||
key = safe % E; | |||
oct = (safe / E) - 1000; | |||
} | |||
}; | |||
Decode prg_prm; | |||
Decode prg_cv; | |||
Decode input; | |||
SchmittTrigger note_trigger[T]; | |||
bool note_enable[E][T] = {}; | |||
float gen[N] = {0,1,2,3,4,5}; | |||
//-------------------------------------------------------------------------------------------------------- | |||
//! \brief Constructor. | |||
GtxModule_Chord_G1() | |||
: | |||
Module(NUM_PARAMS, NUM_INPUTS, N * NUM_OUTPUTS, NUM_LIGHTS) | |||
{} | |||
//-------------------------------------------------------------------------------------------------------- | |||
//! \brief Save data. | |||
json_t *toJson() override | |||
{ | |||
json_t *rootJ = json_object(); | |||
if (json_t *neJA = json_array()) | |||
{ | |||
for (std::size_t i = 0; i < E; ++i) | |||
{ | |||
for (std::size_t j = 0; j < T; ++j) | |||
{ | |||
if (json_t *neJI = json_integer((int) note_enable[i][j])) | |||
{ | |||
json_array_append_new(neJA, neJI); | |||
} | |||
} | |||
} | |||
json_object_set_new(rootJ, "note_enable", neJA); | |||
} | |||
return rootJ; | |||
} | |||
//-------------------------------------------------------------------------------------------------------- | |||
//! \brief Load data. | |||
void fromJson(json_t *rootJ) override | |||
{ | |||
// Note enable | |||
if (json_t *neJA = json_object_get(rootJ, "note_enable")) | |||
{ | |||
for (std::size_t i = 0; i < E; ++i) | |||
{ | |||
for (std::size_t j = 0; j < T; ++j) | |||
{ | |||
if (json_t *neJI = json_array_get(neJA, i*T+j)) | |||
{ | |||
note_enable[i][j] = !!json_integer_value(neJI); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
//-------------------------------------------------------------------------------------------------------- | |||
//! \brief Output map. | |||
static constexpr std::size_t omap(std::size_t port, std::size_t bank) | |||
{ | |||
return port + bank * NUM_OUTPUTS; | |||
} | |||
//-------------------------------------------------------------------------------------------------------- | |||
//! \brief Step function. | |||
void step() override | |||
{ | |||
// Clear all lights | |||
float leds[NUM_LIGHTS] = {}; | |||
// Decode inputs and params | |||
bool act_prm = false; | |||
if (params[PROG_PARAM].value < 12.0f) | |||
{ | |||
prg_prm.step(params[PROG_PARAM].value / 12.0f); | |||
act_prm = true; | |||
} | |||
prg_cv.step(inputs[PROG_INPUT].value); | |||
input .step(inputs[VOCT_INPUT].value); | |||
float gate = clamp(inputs[GATE_INPUT].normalize(10.0f), 0.0f, 10.0f); | |||
// Input leds | |||
if (act_prm) | |||
{ | |||
leds[PROG_LIGHT + prg_prm.key*2] = 1.0f; // Green | |||
} | |||
else | |||
{ | |||
leds[PROG_LIGHT + prg_cv.key*2+1] = 1.0f; // Red | |||
} | |||
leds[FUND_LIGHT + input.key] = 1.0f; // Red | |||
// Chord bit | |||
if (act_prm) | |||
{ | |||
// Detect buttons and deduce what's enabled | |||
for (std::size_t j = 0; j < T; ++j) | |||
{ | |||
if (note_trigger[j].process(params[j + NOTE_PARAM].value)) | |||
{ | |||
note_enable[prg_prm.key][j] = !note_enable[prg_prm.key][j]; | |||
} | |||
} | |||
for (std::size_t j = 0, b = 0; j < T; ++j) | |||
{ | |||
if (note_enable[prg_prm.key][j]) | |||
{ | |||
if (b++ >= N) | |||
{ | |||
note_enable[prg_prm.key][j] = false; | |||
} | |||
} | |||
} | |||
} | |||
// Based on what's enabled turn on leds | |||
if (act_prm) | |||
{ | |||
for (std::size_t j = 0; j < T; ++j) | |||
{ | |||
if (note_enable[prg_prm.key][j]) | |||
{ | |||
leds[NOTE_LIGHT + j*2] = 1.0f; // Green | |||
} | |||
} | |||
} | |||
else | |||
{ | |||
for (std::size_t j = 0; j < T; ++j) | |||
{ | |||
if (note_enable[prg_cv.key][j]) | |||
{ | |||
leds[NOTE_LIGHT + j*2+1] = 1.0f; // Red | |||
} | |||
} | |||
} | |||
// Based on what's enabled generate output | |||
{ | |||
std::size_t i = 0; | |||
for (std::size_t j = 0; j < T; ++j) | |||
{ | |||
if (note_enable[prg_cv.key][j]) | |||
{ | |||
outputs[omap(GATE_OUTPUT, i)].value = gate; | |||
outputs[omap(VOCT_OUTPUT, i)].value = input.out + static_cast<float>(j) / 12.0f; | |||
++i; | |||
} | |||
} | |||
while (i < N) | |||
{ | |||
outputs[omap(GATE_OUTPUT, i)].value = 0.0f; | |||
outputs[omap(VOCT_OUTPUT, i)].value = 0.0f; // is this a good value? | |||
++i; | |||
} | |||
} | |||
// Write output in one go, seems to prevent flicker | |||
for (std::size_t i=0; i<NUM_LIGHTS; ++i) | |||
{ | |||
lights[i].value = leds[i]; | |||
} | |||
} | |||
}; | |||
//============================================================================================================ | |||
static double x0(double shift = 0) { return 6+6*15 + shift * 66; } | |||
static double xd(double i, double radius = 37.0, double spill = 1.65) { return (x0() + (radius + spill * i) * dx(i, E)); } | |||
static double yd(double i, double radius = 37.0, double spill = 1.65) { return (gy(1.5) + (radius + spill * i) * dy(i, E)); } | |||
//============================================================================================================ | |||
//! \brief The widget. | |||
struct GtxWidget_Chord_G1 : ModuleWidget | |||
{ | |||
GtxWidget_Chord_G1(GtxModule_Chord_G1 *module) : ModuleWidget(module) | |||
{ | |||
GTX__WIDGET(); | |||
box.size = Vec(18*15, 380); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/Chord-G1.svg"), box.size, "CHORD-G1"); | |||
pg.nob_med_raw(x0(), fy(-0.28), "PROGRAM"); | |||
pg.prt_in_raw (x0(-1), fy(-0.28), "CV"); | |||
pg.prt_in_raw (x0(+1), fy(-0.28), "SELECT"); | |||
pg.nob_med_raw(x0(), fy(+0.28), "BASS NOTE"); | |||
pg.prt_in_raw (x0(-1), fy(+0.28), "V/OCT"); | |||
pg.prt_in_raw (x0(+1), fy(+0.28), "GATE"); | |||
pg.bus_inx(0.5, 1, "CHORD NOTES"); | |||
pg.bus_out(2.0, 1, "GATE"); | |||
pg.bus_out(2.0, 2, "V/OCT"); | |||
for (double i=0.0; i<T-1.0; i+=0.1) | |||
{ | |||
pg.line(Vec(xd(i), yd(i)), Vec(xd(i+0.1), yd(i+0.1)), "fill:none;stroke:#7092BE;stroke-width:2"); | |||
} | |||
pg.line(Vec(x0(), gy(1.5)), Vec(xd(24), yd(24)), "fill:none;stroke:#7092BE;stroke-width:4"); | |||
pg.line(Vec(x0(), gy(1.5)), Vec(xd(16), yd(16)), "fill:none;stroke:#7092BE;stroke-width:4"); | |||
pg.line(Vec(x0(), gy(1.5)), Vec(xd(19), yd(19)), "fill:none;stroke:#7092BE;stroke-width:4"); | |||
pg.line(Vec(x0(), gy(1.5)), Vec(xd(22), yd(22)), "fill:none;stroke:#7092BE;stroke-width:4"); | |||
} | |||
#endif | |||
setPanel(SVG::load(assetPlugin(plugin, "res/Chord-G1.svg"))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365))); | |||
addParam(createParamGTX<KnobSnapSml>(Vec(x0(+1), fy(-0.28)), module, GtxModule_Chord_G1::PROG_PARAM, 0.0f, 12.0f, 12.0f)); | |||
addInput(createInputGTX<PortInMed> (Vec(x0(-1), fy(-0.28)), module, GtxModule_Chord_G1::PROG_INPUT)); | |||
addInput(createInputGTX<PortInMed> (Vec(x0(+1), fy(+0.28)), module, GtxModule_Chord_G1::GATE_INPUT)); | |||
addInput(createInputGTX<PortInMed> (Vec(x0(-1), fy(+0.28)), module, GtxModule_Chord_G1::VOCT_INPUT)); | |||
for (std::size_t i=0; i<N; ++i) | |||
{ | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(2, i), py(1, i)), module, GtxModule_Chord_G1::omap(GtxModule_Chord_G1::GATE_OUTPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(2, i), py(2, i)), module, GtxModule_Chord_G1::omap(GtxModule_Chord_G1::VOCT_OUTPUT, i))); | |||
} | |||
for (std::size_t i=0; i<T; ++i) | |||
{ | |||
addParam(ParamWidget::create<LEDButton>(but(xd(i), yd(i)), module, i + GtxModule_Chord_G1::NOTE_PARAM, 0.0f, 1.0f, 0.0f)); | |||
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(l_m(xd(i), yd(i)), module, GtxModule_Chord_G1::NOTE_LIGHT + i*2)); | |||
} | |||
addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(x0() - 30, fy(-0.28) + 5), module, GtxModule_Chord_G1::PROG_LIGHT + 0*2)); // C | |||
addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(x0() - 25, fy(-0.28) - 5), module, GtxModule_Chord_G1::PROG_LIGHT + 1*2)); // C# | |||
addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(x0() - 20, fy(-0.28) + 5), module, GtxModule_Chord_G1::PROG_LIGHT + 2*2)); // D | |||
addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(x0() - 15, fy(-0.28) - 5), module, GtxModule_Chord_G1::PROG_LIGHT + 3*2)); // Eb | |||
addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(x0() - 10, fy(-0.28) + 5), module, GtxModule_Chord_G1::PROG_LIGHT + 4*2)); // E | |||
addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(x0() , fy(-0.28) + 5), module, GtxModule_Chord_G1::PROG_LIGHT + 5*2)); // F | |||
addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(x0() + 5, fy(-0.28) - 5), module, GtxModule_Chord_G1::PROG_LIGHT + 6*2)); // Fs | |||
addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(x0() + 10, fy(-0.28) + 5), module, GtxModule_Chord_G1::PROG_LIGHT + 7*2)); // G | |||
addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(x0() + 15, fy(-0.28) - 5), module, GtxModule_Chord_G1::PROG_LIGHT + 8*2)); // Ab | |||
addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(x0() + 20, fy(-0.28) + 5), module, GtxModule_Chord_G1::PROG_LIGHT + 9*2)); // A | |||
addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(x0() + 25, fy(-0.28) - 5), module, GtxModule_Chord_G1::PROG_LIGHT + 10*2)); // Bb | |||
addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(x0() + 30, fy(-0.28) + 5), module, GtxModule_Chord_G1::PROG_LIGHT + 11*2)); // B | |||
addChild(ModuleLightWidget::create<SmallLight< RedLight>>(l_s(x0() - 30, fy(+0.28) + 5), module, GtxModule_Chord_G1::FUND_LIGHT + 0)); // C | |||
addChild(ModuleLightWidget::create<SmallLight< RedLight>>(l_s(x0() - 25, fy(+0.28) - 5), module, GtxModule_Chord_G1::FUND_LIGHT + 1)); // C# | |||
addChild(ModuleLightWidget::create<SmallLight< RedLight>>(l_s(x0() - 20, fy(+0.28) + 5), module, GtxModule_Chord_G1::FUND_LIGHT + 2)); // D | |||
addChild(ModuleLightWidget::create<SmallLight< RedLight>>(l_s(x0() - 15, fy(+0.28) - 5), module, GtxModule_Chord_G1::FUND_LIGHT + 3)); // Eb | |||
addChild(ModuleLightWidget::create<SmallLight< RedLight>>(l_s(x0() - 10, fy(+0.28) + 5), module, GtxModule_Chord_G1::FUND_LIGHT + 4)); // E | |||
addChild(ModuleLightWidget::create<SmallLight< RedLight>>(l_s(x0() , fy(+0.28) + 5), module, GtxModule_Chord_G1::FUND_LIGHT + 5)); // F | |||
addChild(ModuleLightWidget::create<SmallLight< RedLight>>(l_s(x0() + 5, fy(+0.28) - 5), module, GtxModule_Chord_G1::FUND_LIGHT + 6)); // Fs | |||
addChild(ModuleLightWidget::create<SmallLight< RedLight>>(l_s(x0() + 10, fy(+0.28) + 5), module, GtxModule_Chord_G1::FUND_LIGHT + 7)); // G | |||
addChild(ModuleLightWidget::create<SmallLight< RedLight>>(l_s(x0() + 15, fy(+0.28) - 5), module, GtxModule_Chord_G1::FUND_LIGHT + 8)); // Ab | |||
addChild(ModuleLightWidget::create<SmallLight< RedLight>>(l_s(x0() + 20, fy(+0.28) + 5), module, GtxModule_Chord_G1::FUND_LIGHT + 9)); // A | |||
addChild(ModuleLightWidget::create<SmallLight< RedLight>>(l_s(x0() + 25, fy(+0.28) - 5), module, GtxModule_Chord_G1::FUND_LIGHT + 10)); // Bb | |||
addChild(ModuleLightWidget::create<SmallLight< RedLight>>(l_s(x0() + 30, fy(+0.28) + 5), module, GtxModule_Chord_G1::FUND_LIGHT + 11)); // B | |||
} | |||
}; | |||
} // namespace rack_plugin_Gratrix | |||
using namespace rack_plugin_Gratrix; | |||
RACK_PLUGIN_MODEL_INIT(Gratrix, Chord_G1) { | |||
Model *model = Model::create<GtxModule_Chord_G1, GtxWidget_Chord_G1>("Gratrix", "Chord-G1", "Chord-G1", SYNTH_VOICE_TAG); // right tag? | |||
return model; | |||
} |
@@ -0,0 +1,150 @@ | |||
//============================================================================================================ | |||
//! | |||
//! \file Fade-G1.cpp | |||
//! | |||
//! \brief Fade-G1 is a two input six voice one-dimensional fader. | |||
//! | |||
//============================================================================================================ | |||
#include "Gratrix.hpp" | |||
namespace rack_plugin_Gratrix { | |||
//============================================================================================================ | |||
//! \brief The module. | |||
struct GtxModule_Fade_G1 : Module | |||
{ | |||
enum ParamIds { | |||
BLEND12_PARAM, | |||
NUM_PARAMS | |||
}; | |||
enum InputIds { | |||
BLEND12_INPUT, | |||
IN1_INPUT, | |||
IN2_INPUT, | |||
NUM_INPUTS, | |||
OFF_INPUTS = IN1_INPUT | |||
}; | |||
enum OutputIds { | |||
OUT1_OUTPUT, | |||
OUT2_OUTPUT, | |||
NUM_OUTPUTS, | |||
OFF_OUTPUTS = OUT1_OUTPUT | |||
}; | |||
enum LightIds { | |||
IN_1_GREEN, IN_1_RED, | |||
IN_2_GREEN, IN_2_RED, | |||
OUT_1_GREEN, OUT_1_RED, | |||
OUT_2_GREEN, OUT_2_RED, | |||
NUM_LIGHTS | |||
}; | |||
GtxModule_Fade_G1() | |||
: | |||
Module(NUM_PARAMS, | |||
(GTX__N+1) * (NUM_INPUTS - OFF_INPUTS ) + OFF_INPUTS, | |||
(GTX__N ) * (NUM_OUTPUTS - OFF_OUTPUTS) + OFF_OUTPUTS, | |||
NUM_LIGHTS) | |||
{ | |||
lights[IN_1_GREEN].value = 0.0f; lights[IN_1_RED].value = 1.0f; | |||
lights[IN_2_GREEN].value = 1.0f; lights[IN_2_RED].value = 0.0f; | |||
} | |||
static constexpr std::size_t imap(std::size_t port, std::size_t bank) | |||
{ | |||
return (port < OFF_INPUTS) ? port : port + bank * (NUM_INPUTS - OFF_INPUTS); | |||
} | |||
static constexpr std::size_t omap(std::size_t port, std::size_t bank) | |||
{ | |||
return port + bank * NUM_OUTPUTS; | |||
} | |||
void step() override | |||
{ | |||
float blend12 = params[BLEND12_PARAM].value; | |||
if (inputs[BLEND12_INPUT].active) blend12 *= clamp(inputs[BLEND12_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f); | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
float input1 = inputs[imap(IN1_INPUT, i)].active ? inputs[imap(IN1_INPUT, i)].value : inputs[imap(IN1_INPUT, GTX__N)].value; | |||
float input2 = inputs[imap(IN2_INPUT, i)].active ? inputs[imap(IN2_INPUT, i)].value : inputs[imap(IN2_INPUT, GTX__N)].value; | |||
float delta12 = blend12 * (input2 - input1); | |||
outputs[omap(OUT1_OUTPUT, i)].value = input1 + delta12; | |||
outputs[omap(OUT2_OUTPUT, i)].value = input2 - delta12; | |||
} | |||
lights[OUT_1_GREEN].value = lights[OUT_2_RED].value = blend12; | |||
lights[OUT_2_GREEN].value = lights[OUT_1_RED].value = 1.0f - blend12; | |||
} | |||
}; | |||
//============================================================================================================ | |||
//! \brief The widget. | |||
struct GtxWidget_Fade_G1 : ModuleWidget | |||
{ | |||
GtxWidget_Fade_G1(GtxModule_Fade_G1 *module) : ModuleWidget(module) | |||
{ | |||
GTX__WIDGET(); | |||
box.size = Vec(12*15, 380); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/Fade-G1.svg"), box.size, "FADE-G1"); | |||
// ― is a horizontal bar see https://en.wikipedia.org/wiki/Dash#Horizontal_bar | |||
pg.prt_in2(0, 0, "CV 1―2"); pg.nob_big(1, 0, "1―2"); | |||
pg.bus_in(0, 1, "IN 1"); pg.bus_out(1, 1, "OUT 1"); | |||
pg.bus_in(0, 2, "IN 2"); pg.bus_out(1, 2, "OUT 2"); | |||
} | |||
#endif | |||
setPanel(SVG::load(assetPlugin(plugin, "res/Fade-G1.svg"))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365))); | |||
addParam(createParamGTX<KnobFreeHug>(Vec(fx(1), fy(0)), module, GtxModule_Fade_G1::BLEND12_PARAM, 0.0f, 1.0f, 0.0f)); | |||
addInput(createInputGTX<PortInMed>(Vec(fx(0), fy(0)), module, GtxModule_Fade_G1::BLEND12_INPUT)); | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(1, i)), module, GtxModule_Fade_G1::imap(GtxModule_Fade_G1::IN1_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(2, i)), module, GtxModule_Fade_G1::imap(GtxModule_Fade_G1::IN2_INPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(1, i), py(1, i)), module, GtxModule_Fade_G1::omap(GtxModule_Fade_G1::OUT1_OUTPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(1, i), py(2, i)), module, GtxModule_Fade_G1::omap(GtxModule_Fade_G1::OUT2_OUTPUT, i))); | |||
} | |||
addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(1)), module, GtxModule_Fade_G1::imap(GtxModule_Fade_G1::IN1_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(2)), module, GtxModule_Fade_G1::imap(GtxModule_Fade_G1::IN2_INPUT, GTX__N))); | |||
for (std::size_t i=0, x=0; x<2; ++x) | |||
{ | |||
for (std::size_t y=0; y<2; ++y) | |||
{ | |||
addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(gx(x)+28, gy(y+1)-47.5), module, i)); i+=2; | |||
} | |||
} | |||
} | |||
}; | |||
} // namespace rack_plugin_Gratrix | |||
using namespace rack_plugin_Gratrix; | |||
RACK_PLUGIN_MODEL_INIT(Gratrix, Fade_G1) { | |||
Model *model = Model::create<GtxModule_Fade_G1, GtxWidget_Fade_G1>("Gratrix", "Fade-G1", "Fade-G1", MIXER_TAG); // right tag? | |||
return model; | |||
} |
@@ -0,0 +1,194 @@ | |||
//============================================================================================================ | |||
//! | |||
//! \file Fade-G2.cpp | |||
//! | |||
//! \brief Fade-G2 is a four input six voice two-dimensional fader. | |||
//! | |||
//============================================================================================================ | |||
#include "Gratrix.hpp" | |||
namespace rack_plugin_Gratrix { | |||
//============================================================================================================ | |||
//! \brief The module. | |||
struct GtxModule_Fade_G2 : Module | |||
{ | |||
enum ParamIds { | |||
BLEND12_PARAM, | |||
BLENDAB_PARAM, | |||
NUM_PARAMS | |||
}; | |||
enum InputIds { | |||
BLEND12_INPUT, | |||
BLENDAB_INPUT, | |||
IN1A_INPUT, | |||
IN1B_INPUT, | |||
IN2A_INPUT, | |||
IN2B_INPUT, | |||
NUM_INPUTS, | |||
OFF_INPUTS = IN1A_INPUT | |||
}; | |||
enum OutputIds { | |||
OUT1A_OUTPUT, | |||
OUT2B_OUTPUT, | |||
NUM_OUTPUTS, | |||
OFF_OUTPUTS = OUT1A_OUTPUT | |||
}; | |||
enum LightIds { | |||
IN_1AP_GREEN, IN_1AP_RED, | |||
IN_1AQ_GREEN, IN_1AQ_RED, | |||
IN_1BP_GREEN, IN_1BP_RED, | |||
IN_1BQ_GREEN, IN_1BQ_RED, | |||
IN_2AP_GREEN, IN_2AP_RED, | |||
IN_2AQ_GREEN, IN_2AQ_RED, | |||
IN_2BP_GREEN, IN_2BP_RED, | |||
IN_2BQ_GREEN, IN_2BQ_RED, | |||
OUT_1AP_GREEN, OUT_1AP_RED, | |||
OUT_1AQ_GREEN, OUT_1AQ_RED, | |||
OUT_2BP_GREEN, OUT_2BP_RED, | |||
OUT_2BQ_GREEN, OUT_2BQ_RED, | |||
NUM_LIGHTS | |||
}; | |||
GtxModule_Fade_G2() | |||
: | |||
Module(NUM_PARAMS, | |||
(GTX__N+1) * (NUM_INPUTS - OFF_INPUTS ) + OFF_INPUTS, | |||
(GTX__N ) * (NUM_OUTPUTS - OFF_OUTPUTS) + OFF_OUTPUTS, | |||
NUM_LIGHTS) | |||
{ | |||
lights[IN_1AP_GREEN].value = 0.0f; lights[IN_1AP_RED].value = 1.0f; | |||
lights[IN_1AQ_GREEN].value = 0.0f; lights[IN_1AQ_RED].value = 1.0f; | |||
lights[IN_1BP_GREEN].value = 1.0f; lights[IN_1BP_RED].value = 0.0f; | |||
lights[IN_1BQ_GREEN].value = 0.0f; lights[IN_1BQ_RED].value = 1.0f; | |||
lights[IN_2AP_GREEN].value = 0.0f; lights[IN_2AP_RED].value = 1.0f; | |||
lights[IN_2AQ_GREEN].value = 1.0f; lights[IN_2AQ_RED].value = 0.0f; | |||
lights[IN_2BP_GREEN].value = 1.0f; lights[IN_2BP_RED].value = 0.0f; | |||
lights[IN_2BQ_GREEN].value = 1.0f; lights[IN_2BQ_RED].value = 0.0f; | |||
} | |||
static constexpr std::size_t imap(std::size_t port, std::size_t bank) | |||
{ | |||
return (port < OFF_INPUTS) ? port : port + bank * (NUM_INPUTS - OFF_INPUTS); | |||
} | |||
static constexpr std::size_t omap(std::size_t port, std::size_t bank) | |||
{ | |||
return port + bank * NUM_OUTPUTS; | |||
} | |||
void step() override | |||
{ | |||
float blend12 = params[BLEND12_PARAM].value; | |||
float blendAB = params[BLENDAB_PARAM].value; | |||
if (inputs[BLEND12_INPUT].active) blend12 *= clamp(inputs[BLEND12_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f); | |||
if (inputs[BLENDAB_INPUT].active) blendAB *= clamp(inputs[BLENDAB_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f); | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
float input1A = inputs[imap(IN1A_INPUT, i)].active ? inputs[imap(IN1A_INPUT, i)].value : inputs[imap(IN1A_INPUT, GTX__N)].value; | |||
float input1B = inputs[imap(IN1B_INPUT, i)].active ? inputs[imap(IN1B_INPUT, i)].value : inputs[imap(IN1B_INPUT, GTX__N)].value; | |||
float input2A = inputs[imap(IN2A_INPUT, i)].active ? inputs[imap(IN2A_INPUT, i)].value : inputs[imap(IN2A_INPUT, GTX__N)].value; | |||
float input2B = inputs[imap(IN2B_INPUT, i)].active ? inputs[imap(IN2B_INPUT, i)].value : inputs[imap(IN2B_INPUT, GTX__N)].value; | |||
float delta1AB = blendAB * (input1B - input1A); | |||
float delta2AB = blendAB * (input2B - input2A); | |||
float temp_1A = input1A + delta1AB; | |||
float temp_1B = input1B - delta1AB; | |||
float temp_2A = input2A + delta2AB; | |||
float temp_2B = input2B - delta2AB; | |||
float delta12A = blend12 * (temp_2A - temp_1A); | |||
float delta12B = blend12 * (temp_2B - temp_1B); | |||
outputs[omap(OUT1A_OUTPUT, i)].value = temp_1A + delta12A; | |||
outputs[omap(OUT2B_OUTPUT, i)].value = temp_2B - delta12B; | |||
} | |||
lights[OUT_1AP_GREEN].value = lights[OUT_2BP_RED].value = blendAB; | |||
lights[OUT_1AQ_GREEN].value = lights[OUT_2BQ_RED].value = blend12; | |||
lights[OUT_2BP_GREEN].value = lights[OUT_1AP_RED].value = 1.0f - blendAB; | |||
lights[OUT_2BQ_GREEN].value = lights[OUT_1AQ_RED].value = 1.0f - blend12; | |||
} | |||
}; | |||
//============================================================================================================ | |||
//! \brief The widget. | |||
struct GtxWidget_Fade_G2 : ModuleWidget | |||
{ | |||
GtxWidget_Fade_G2(GtxModule_Fade_G2 *module) : ModuleWidget(module) | |||
{ | |||
GTX__WIDGET(); | |||
box.size = Vec(18*15, 380); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/Fade-G2.svg"), box.size, "FADE-G2"); | |||
// ― is a horizontal bar see https://en.wikipedia.org/wiki/Dash#Horizontal_bar | |||
pg.prt_in2(0, -0.28, "CV 1―2"); pg.nob_big(1, 0, "1―2"); | |||
pg.prt_in2(0, +0.28, "CV A―B"); pg.nob_big(2, 0, "A―B"); | |||
pg.bus_in(0, 1, "IN 1A"); pg.bus_out(2, 1, "OUT"); | |||
pg.bus_in(1, 1, "IN 1B"); | |||
pg.bus_in(0, 2, "IN 2A"); | |||
pg.bus_in(1, 2, "IN 2B"); pg.bus_out(2, 2, "INV OUT"); | |||
} | |||
#endif | |||
setPanel(SVG::load(assetPlugin(plugin, "res/Fade-G2.svg"))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365))); | |||
addParam(createParamGTX<KnobFreeHug>(Vec(fx(1), fy(0)), module, GtxModule_Fade_G2::BLENDAB_PARAM, 0.0f, 1.0f, 0.0f)); | |||
addParam(createParamGTX<KnobFreeHug>(Vec(fx(2), fy(0)), module, GtxModule_Fade_G2::BLEND12_PARAM, 0.0f, 1.0f, 0.0f)); | |||
addInput(createInputGTX<PortInMed>(Vec(fx(0), fy(-0.28)), module, GtxModule_Fade_G2::BLENDAB_INPUT)); | |||
addInput(createInputGTX<PortInMed>(Vec(fx(0), fy(+0.28)), module, GtxModule_Fade_G2::BLEND12_INPUT)); | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(1, i)), module, GtxModule_Fade_G2::imap(GtxModule_Fade_G2::IN1A_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(2, i)), module, GtxModule_Fade_G2::imap(GtxModule_Fade_G2::IN1B_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(1, i), py(1, i)), module, GtxModule_Fade_G2::imap(GtxModule_Fade_G2::IN2A_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(1, i), py(2, i)), module, GtxModule_Fade_G2::imap(GtxModule_Fade_G2::IN2B_INPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(2, i), py(1, i)), module, GtxModule_Fade_G2::omap(GtxModule_Fade_G2::OUT1A_OUTPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(2, i), py(2, i)), module, GtxModule_Fade_G2::omap(GtxModule_Fade_G2::OUT2B_OUTPUT, i))); | |||
} | |||
addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(1)), module, GtxModule_Fade_G2::imap(GtxModule_Fade_G2::IN1A_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(2)), module, GtxModule_Fade_G2::imap(GtxModule_Fade_G2::IN1B_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(1), gy(1)), module, GtxModule_Fade_G2::imap(GtxModule_Fade_G2::IN2A_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(1), gy(2)), module, GtxModule_Fade_G2::imap(GtxModule_Fade_G2::IN2B_INPUT, GTX__N))); | |||
for (std::size_t i=0, x=0; x<3; ++x) | |||
{ | |||
for (std::size_t y=0; y<2; ++y) | |||
{ | |||
addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(gx(x)+rad_l_s()/2+28, gy(y+1)-47.5-(1+rad_l_s())), module, i)); i+=2; | |||
addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(l_s(gx(x)+rad_l_s()/2+28, gy(y+1)-47.5+(1+rad_l_s())), module, i)); i+=2; | |||
} | |||
} | |||
} | |||
}; | |||
} // namespace rack_plugin_Gratrix | |||
using namespace rack_plugin_Gratrix; | |||
RACK_PLUGIN_MODEL_INIT(Gratrix, Fade_G2) { | |||
Model *model = Model::create<GtxModule_Fade_G2, GtxWidget_Fade_G2>("Gratrix", "Fade-G2", "Fade-G2", MIXER_TAG); // right tag? | |||
return model; | |||
} |
@@ -0,0 +1,45 @@ | |||
#include "Gratrix.hpp" | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, VCO_F1); | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, VCO_F2); | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, VCF_F1); | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, VCA_F1); | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, ADSR_F1); | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, Chord_G1); | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, Octave_G1); | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, Fade_G1); | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, Fade_G2); | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, Binary_G1); | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, Seq_G1); | |||
// RACK_PLUGIN_MODEL_DECLARE(Gratrix, Seq_G2); // assertion failed | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, Keys_G1); | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, VU_G1); | |||
// RACK_PLUGIN_MODEL_DECLARE(Gratrix, Scope_G1); // assertion failed | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, Blank_03); | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, Blank_06); | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, Blank_09); | |||
RACK_PLUGIN_MODEL_DECLARE(Gratrix, Blank_12); | |||
RACK_PLUGIN_INIT(Gratrix) { | |||
RACK_PLUGIN_INIT_ID(); | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, VCO_F1); | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, VCO_F2); | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, VCF_F1); | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, VCA_F1); | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, ADSR_F1); | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, Chord_G1); | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, Octave_G1); | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, Fade_G1); | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, Fade_G2); | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, Binary_G1); | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, Seq_G1); | |||
// RACK_PLUGIN_MODEL_ADD(Gratrix, Seq_G2); // assertion failed | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, Keys_G1); | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, VU_G1); | |||
// RACK_PLUGIN_MODEL_ADD(Gratrix, Scope_G1); // assertion failed | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, Blank_03); | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, Blank_06); | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, Blank_09); | |||
RACK_PLUGIN_MODEL_ADD(Gratrix, Blank_12); | |||
} |
@@ -0,0 +1,206 @@ | |||
//============================================================================================================ | |||
//! | |||
//! \file Keys-G1.cpp | |||
//! | |||
//! \brief Keys-G1 is a six input times six voice note monitoring module. | |||
//! | |||
//============================================================================================================ | |||
#include "Gratrix.hpp" | |||
namespace rack_plugin_Gratrix { | |||
//============================================================================================================ | |||
//! \brief The module. | |||
struct GtxModule_Keys_G1 : Module | |||
{ | |||
enum ParamIds { | |||
NUM_PARAMS | |||
}; | |||
enum InputIds { | |||
GATE_1R_INPUT, // N+1 | |||
GATE_1G_INPUT, // N+1 | |||
GATE_1B_INPUT, // N+1 | |||
GATE_2R_INPUT, // N+1 | |||
GATE_2G_INPUT, // N+1 | |||
GATE_2B_INPUT, // N+1 | |||
VOCT_1R_INPUT, // N | |||
VOCT_1G_INPUT, // N | |||
VOCT_1B_INPUT, // N | |||
VOCT_2R_INPUT, // N | |||
VOCT_2G_INPUT, // N | |||
VOCT_2B_INPUT, // N | |||
NUM_INPUTS, | |||
}; | |||
enum OutputIds { | |||
NUM_OUTPUTS | |||
}; | |||
enum LightIds { | |||
KEY_LIGHT_1 = 0, | |||
KEY_LIGHT_2 = KEY_LIGHT_1 + 6 * 12 * 3, | |||
NUM_LIGHTS = KEY_LIGHT_2 + 6 * 12 * 3 | |||
}; | |||
static constexpr std::size_t imap(std::size_t port, std::size_t bank) | |||
{ | |||
return port + bank * NUM_INPUTS; | |||
} | |||
static void decode(float *lights, int offset, const Input &in_gate, const Input &in_voct) | |||
{ | |||
bool enable = ((in_gate.active && in_gate.value >= 1.0f) || !in_gate.active) && in_voct.active; | |||
if (enable) | |||
{ | |||
int note = static_cast<int>(std::floor(in_voct.value * 12.0f + 0.5f)) + 3*12; | |||
if (note >= 0 && note < 6*12) | |||
{ | |||
lights[note * 3 + offset] = 1.0f; | |||
} | |||
} | |||
} | |||
GtxModule_Keys_G1() | |||
: | |||
Module(NUM_PARAMS, ((GTX__N+1) * NUM_INPUTS/2) + (GTX__N * NUM_INPUTS/2), NUM_OUTPUTS, NUM_LIGHTS) | |||
{} | |||
void step() override | |||
{ | |||
float leds[NUM_LIGHTS] = {}; | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
if (inputs[imap(GATE_1R_INPUT, i)].active) decode(&leds[KEY_LIGHT_1], 0, inputs[imap(GATE_1R_INPUT, i)], inputs[imap(VOCT_1R_INPUT, i)]); | |||
else decode(&leds[KEY_LIGHT_1], 0, inputs[imap(GATE_1R_INPUT, GTX__N)], inputs[imap(VOCT_1R_INPUT, i)]); | |||
if (inputs[imap(GATE_1G_INPUT, i)].active) decode(&leds[KEY_LIGHT_1], 1, inputs[imap(GATE_1G_INPUT, i)], inputs[imap(VOCT_1G_INPUT, i)]); | |||
else decode(&leds[KEY_LIGHT_1], 1, inputs[imap(GATE_1G_INPUT, GTX__N)], inputs[imap(VOCT_1G_INPUT, i)]); | |||
if (inputs[imap(GATE_1B_INPUT, i)].active) decode(&leds[KEY_LIGHT_1], 2, inputs[imap(GATE_1B_INPUT, i)], inputs[imap(VOCT_1B_INPUT, i)]); | |||
else decode(&leds[KEY_LIGHT_1], 2, inputs[imap(GATE_1B_INPUT, GTX__N)], inputs[imap(VOCT_1B_INPUT, i)]); | |||
if (inputs[imap(GATE_2R_INPUT, i)].active) decode(&leds[KEY_LIGHT_2], 0, inputs[imap(GATE_2R_INPUT, i)], inputs[imap(VOCT_2R_INPUT, i)]); | |||
else decode(&leds[KEY_LIGHT_2], 0, inputs[imap(GATE_2R_INPUT, GTX__N)], inputs[imap(VOCT_2R_INPUT, i)]); | |||
if (inputs[imap(GATE_2G_INPUT, i)].active) decode(&leds[KEY_LIGHT_2], 1, inputs[imap(GATE_2G_INPUT, i)], inputs[imap(VOCT_2G_INPUT, i)]); | |||
else decode(&leds[KEY_LIGHT_2], 1, inputs[imap(GATE_2G_INPUT, GTX__N)], inputs[imap(VOCT_2G_INPUT, i)]); | |||
if (inputs[imap(GATE_2B_INPUT, i)].active) decode(&leds[KEY_LIGHT_2], 2, inputs[imap(GATE_2B_INPUT, i)], inputs[imap(VOCT_2B_INPUT, i)]); | |||
else decode(&leds[KEY_LIGHT_2], 2, inputs[imap(GATE_2B_INPUT, GTX__N)], inputs[imap(VOCT_2B_INPUT, i)]); | |||
} | |||
// Write output in one go, seems to prevent flicker | |||
for (std::size_t i=0; i<NUM_LIGHTS; ++i) | |||
{ | |||
lights[i].value = leds[i]; | |||
} | |||
} | |||
}; | |||
//============================================================================================================ | |||
//! \brief The widget. | |||
struct GtxWidget_Keys_G1 : ModuleWidget | |||
{ | |||
GtxWidget_Keys_G1(GtxModule_Keys_G1 *module) : ModuleWidget(module) | |||
{ | |||
GTX__WIDGET(); | |||
box.size = Vec(36*15, 380); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/Keys-G1.svg"), box.size, "KEYS-G1"); | |||
pg.line(Vec(fx(0-.4), fy(0.36)), Vec(fx(2+.4), fy(0.36)), "fill:none;stroke:#7092BE;stroke-width:1"); | |||
pg.line(Vec(fx(3-.4), fy(0.36)), Vec(fx(5+.4), fy(0.36)), "fill:none;stroke:#7092BE;stroke-width:1"); | |||
pg.nob_med(0, 0.7, "RED" ); pg.nob_med(0, -0.28, "C1-B1"); | |||
pg.nob_med(1, 0.55, "UPPER"); pg.nob_med(1, 0.7, "GREEN"); pg.nob_med(1, -0.28, "C2-B2"); | |||
pg.nob_med(2, 0.7, "BLUE" ); pg.nob_med(2, -0.28, "C3-B3"); | |||
pg.nob_med(3, 0.7, "RED" ); pg.nob_med(3, -0.28, "C4-B4"); | |||
pg.nob_med(4, 0.55, "LOWER"); pg.nob_med(4, 0.7, "GREEN"); pg.nob_med(4, -0.28, "C5-B5"); | |||
pg.nob_med(5, 0.7, "BLUE" ); pg.nob_med(5, -0.28, "C6-B6"); | |||
pg.bus_in(0, 1, "GATE"); pg.bus_in(0, 2, "V/OCT"); | |||
pg.bus_in(1, 1, "GATE"); pg.bus_in(1, 2, "V/OCT"); | |||
pg.bus_in(2, 1, "GATE"); pg.bus_in(2, 2, "V/OCT"); | |||
pg.bus_in(3, 1, "GATE"); pg.bus_in(3, 2, "V/OCT"); | |||
pg.bus_in(4, 1, "GATE"); pg.bus_in(4, 2, "V/OCT"); | |||
pg.bus_in(5, 1, "GATE"); pg.bus_in(5, 2, "V/OCT"); | |||
} | |||
#endif | |||
setPanel(SVG::load(assetPlugin(plugin, "res/Keys-G1.svg"))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365))); | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(1, i)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::GATE_1R_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(1, i), py(1, i)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::GATE_1G_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(2, i), py(1, i)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::GATE_1B_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(3, i), py(1, i)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::GATE_2R_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(4, i), py(1, i)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::GATE_2G_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(5, i), py(1, i)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::GATE_2B_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(2, i)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::VOCT_1R_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(1, i), py(2, i)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::VOCT_1G_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(2, i), py(2, i)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::VOCT_1B_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(3, i), py(2, i)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::VOCT_2R_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(4, i), py(2, i)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::VOCT_2G_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(5, i), py(2, i)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::VOCT_2B_INPUT, i))); | |||
} | |||
addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(1)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::GATE_1R_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(1), gy(1)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::GATE_1G_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(2), gy(1)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::GATE_1B_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(3), gy(1)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::GATE_2R_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(4), gy(1)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::GATE_2G_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(5), gy(1)), module, GtxModule_Keys_G1::imap(GtxModule_Keys_G1::GATE_2B_INPUT, GTX__N))); | |||
for (std::size_t i=0; i<6; ++i) | |||
{ | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) - 30, fy(0+0.08) + 5), module, GtxModule_Keys_G1::KEY_LIGHT_2 + 3 * (i * 12 + 0))); // C | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) - 25, fy(0+0.08) - 5), module, GtxModule_Keys_G1::KEY_LIGHT_2 + 3 * (i * 12 + 1))); // C# | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) - 20, fy(0+0.08) + 5), module, GtxModule_Keys_G1::KEY_LIGHT_2 + 3 * (i * 12 + 2))); // D | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) - 15, fy(0+0.08) - 5), module, GtxModule_Keys_G1::KEY_LIGHT_2 + 3 * (i * 12 + 3))); // Eb | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) - 10, fy(0+0.08) + 5), module, GtxModule_Keys_G1::KEY_LIGHT_2 + 3 * (i * 12 + 4))); // E | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) , fy(0+0.08) + 5), module, GtxModule_Keys_G1::KEY_LIGHT_2 + 3 * (i * 12 + 5))); // F | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) + 5, fy(0+0.08) - 5), module, GtxModule_Keys_G1::KEY_LIGHT_2 + 3 * (i * 12 + 6))); // Fs | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) + 10, fy(0+0.08) + 5), module, GtxModule_Keys_G1::KEY_LIGHT_2 + 3 * (i * 12 + 7))); // G | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) + 15, fy(0+0.08) - 5), module, GtxModule_Keys_G1::KEY_LIGHT_2 + 3 * (i * 12 + 8))); // Ab | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) + 20, fy(0+0.08) + 5), module, GtxModule_Keys_G1::KEY_LIGHT_2 + 3 * (i * 12 + 9))); // A | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) + 25, fy(0+0.08) - 5), module, GtxModule_Keys_G1::KEY_LIGHT_2 + 3 * (i * 12 + 10))); // Bb | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) + 30, fy(0+0.08) + 5), module, GtxModule_Keys_G1::KEY_LIGHT_2 + 3 * (i * 12 + 11))); // B | |||
} | |||
for (std::size_t i=0; i<6; ++i) | |||
{ | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) - 30, fy(0-0.28) + 5), module, GtxModule_Keys_G1::KEY_LIGHT_1 + 3 * (i * 12 + 0))); // C | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) - 25, fy(0-0.28) - 5), module, GtxModule_Keys_G1::KEY_LIGHT_1 + 3 * (i * 12 + 1))); // C# | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) - 20, fy(0-0.28) + 5), module, GtxModule_Keys_G1::KEY_LIGHT_1 + 3 * (i * 12 + 2))); // D | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) - 15, fy(0-0.28) - 5), module, GtxModule_Keys_G1::KEY_LIGHT_1 + 3 * (i * 12 + 3))); // Eb | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) - 10, fy(0-0.28) + 5), module, GtxModule_Keys_G1::KEY_LIGHT_1 + 3 * (i * 12 + 4))); // E | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) , fy(0-0.28) + 5), module, GtxModule_Keys_G1::KEY_LIGHT_1 + 3 * (i * 12 + 5))); // F | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) + 5, fy(0-0.28) - 5), module, GtxModule_Keys_G1::KEY_LIGHT_1 + 3 * (i * 12 + 6))); // Fs | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) + 10, fy(0-0.28) + 5), module, GtxModule_Keys_G1::KEY_LIGHT_1 + 3 * (i * 12 + 7))); // G | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) + 15, fy(0-0.28) - 5), module, GtxModule_Keys_G1::KEY_LIGHT_1 + 3 * (i * 12 + 8))); // Ab | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) + 20, fy(0-0.28) + 5), module, GtxModule_Keys_G1::KEY_LIGHT_1 + 3 * (i * 12 + 9))); // A | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) + 25, fy(0-0.28) - 5), module, GtxModule_Keys_G1::KEY_LIGHT_1 + 3 * (i * 12 + 10))); // Bb | |||
addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(l_s(gx(i) + 30, fy(0-0.28) + 5), module, GtxModule_Keys_G1::KEY_LIGHT_1 + 3 * (i * 12 + 11))); // B | |||
} | |||
} | |||
}; | |||
} // namespace rack_plugin_Gratrix | |||
using namespace rack_plugin_Gratrix; | |||
RACK_PLUGIN_MODEL_INIT(Gratrix, Keys_G1) { | |||
Model *model = Model::create<GtxModule_Keys_G1, GtxWidget_Keys_G1>("Gratrix", "Keys-G1", "Keys-G1", VISUAL_TAG); | |||
return model; | |||
} |
@@ -0,0 +1,413 @@ | |||
#if 0 | |||
//============================================================================================================ | |||
//! | |||
//! \file MIDI-C1.cpp | |||
//! | |||
//! \brief MIDI-C1 is a six voice straight clone of the VCV Rack Core module 'Quad MIDI-to-CV Interface'. | |||
//! | |||
//============================================================================================================ | |||
#include <list> | |||
#include <algorithm> | |||
#include "rtmidi/RtMidi.h" | |||
#include "core.hpp" | |||
#include "MidiIO.hpp" | |||
#include "dsp/digital.hpp" | |||
#include "Gratrix.hpp" | |||
namespace rack_plugin_Gratrix { | |||
struct Key { | |||
int pitch = 60; | |||
int at = 0; // aftertouch | |||
int vel = 0; // velocity | |||
int retriggerC = 0; | |||
bool gate = false; | |||
}; | |||
struct Interface : MidiIO, Module { | |||
enum ParamIds { | |||
RESET_PARAM, | |||
NUM_PARAMS | |||
}; | |||
enum InputIds { | |||
NUM_INPUTS | |||
}; | |||
enum OutputIds { | |||
PITCH_OUTPUT, // N | |||
GATE_OUTPUT, // N | |||
VELOCITY_OUTPUT, // N | |||
AT_OUTPUT, // N | |||
NUM_OUTPUTS, | |||
OFF_OUTPUTS = PITCH_OUTPUT | |||
}; | |||
enum LightIds { | |||
RESET_LIGHT, | |||
NUM_LIGHTS | |||
}; | |||
enum Modes { | |||
ROTATE, | |||
RESET, | |||
REASSIGN | |||
}; | |||
static constexpr std::size_t omap(std::size_t port, std::size_t bank) | |||
{ | |||
return port + bank * NUM_OUTPUTS; | |||
} | |||
bool pedal = false; | |||
int mode = REASSIGN; | |||
int getMode() const; | |||
void setMode(int mode); | |||
Key activeKeys[GTX__N]; | |||
std::list<int> open; | |||
SchmittTrigger resetTrigger; | |||
Interface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, GTX__N * (NUM_OUTPUTS - OFF_OUTPUTS) + OFF_OUTPUTS, NUM_LIGHTS) { | |||
} | |||
~Interface() { | |||
}; | |||
void step() override; | |||
void processMidi(std::vector<unsigned char> msg); | |||
json_t *toJson() override { | |||
json_t *rootJ = json_object(); | |||
addBaseJson(rootJ); | |||
return rootJ; | |||
} | |||
void fromJson(json_t *rootJ) override { | |||
baseFromJson(rootJ); | |||
} | |||
void reset() override { | |||
resetMidi(); | |||
} | |||
void resetMidi() override; | |||
}; | |||
void Interface::resetMidi() { | |||
for (int i = 0; i < GTX__N; i++) { | |||
outputs[GATE_OUTPUT + i].value = 0.0; | |||
activeKeys[i].gate = false; | |||
activeKeys[i].vel = 0; | |||
activeKeys[i].at = 0; | |||
} | |||
open.clear(); | |||
pedal = false; | |||
lights[RESET_LIGHT].value = 1.0; | |||
} | |||
void Interface::step() { | |||
if (isPortOpen()) { | |||
std::vector<unsigned char> message; | |||
int msgsProcessed = 0; | |||
// midiIn->getMessage returns empty vector if there are no messages in the queue | |||
// NOTE: For the quadmidi we will process max GTX__N midi messages per step to avoid | |||
// problems with parallel input. | |||
getMessage(&message); | |||
while (msgsProcessed < GTX__N && message.size() > 0) { | |||
processMidi(message); | |||
getMessage(&message); | |||
msgsProcessed++; | |||
} | |||
} | |||
for (int i = 0; i < GTX__N; i++) { | |||
outputs[omap( GATE_OUTPUT, i)].value = activeKeys[i].gate ? 10.0 : 0; | |||
outputs[omap( PITCH_OUTPUT, i)].value = (activeKeys[i].pitch - 60) / 12.0; | |||
outputs[omap(VELOCITY_OUTPUT, i)].value = activeKeys[i].vel / 127.0 * 10.0; | |||
outputs[omap( AT_OUTPUT, i)].value = activeKeys[i].at / 127.0 * 10.0; | |||
} | |||
if (resetTrigger.process(params[RESET_PARAM].value)) { | |||
resetMidi(); | |||
return; | |||
} | |||
lights[RESET_LIGHT].value -= lights[RESET_LIGHT].value / 0.55 / engineGetSampleRate(); // fade out light | |||
} | |||
void Interface::processMidi(std::vector<unsigned char> msg) { | |||
int channel = msg[0] & 0xf; | |||
int status = (msg[0] >> 4) & 0xf; | |||
int data1 = msg[1]; | |||
int data2 = msg[2]; | |||
bool gate; | |||
// Filter channels | |||
if (this->channel >= 0 && this->channel != channel) | |||
return; | |||
switch (status) { | |||
// note off | |||
case 0x8: { | |||
gate = false; | |||
} | |||
break; | |||
case 0x9: // note on | |||
if (data2 > 0) { | |||
gate = true; | |||
} else { | |||
// For some reason, some keyboards send a "note on" event with a velocity of 0 to signal that the key has been released. | |||
gate = false; | |||
} | |||
break; | |||
case 0xa: // channel aftertouch | |||
for (int i = 0; i < GTX__N; i++) { | |||
if (activeKeys[i].pitch == data1) { | |||
activeKeys[i].at = data2; | |||
} | |||
} | |||
return; | |||
case 0xb: // cc | |||
if (data1 == 0x40) { // pedal | |||
pedal = (data2 >= 64); | |||
if (!pedal) { | |||
open.clear(); | |||
for (int i = 0; i < GTX__N; i++) { | |||
activeKeys[i].gate = false; | |||
open.push_back(i); | |||
} | |||
} | |||
} | |||
return; | |||
default: | |||
return; | |||
} | |||
if (pedal && !gate) { | |||
return; | |||
} | |||
if (!gate) { | |||
for (int i = 0; i < GTX__N; i++) { | |||
if (activeKeys[i].pitch == data1) { | |||
activeKeys[i].gate = false; | |||
activeKeys[i].vel = data2; | |||
if (std::find(open.begin(), open.end(), i) != open.end()) { | |||
open.remove(i); | |||
} | |||
open.push_front(i); | |||
} | |||
} | |||
return; | |||
} | |||
if (open.empty()) { | |||
for (int i = 0; i < GTX__N; i++) { | |||
open.push_back(i); | |||
} | |||
} | |||
if (!activeKeys[0].gate && !activeKeys[1].gate && | |||
!activeKeys[2].gate && !activeKeys[3].gate && | |||
!activeKeys[4].gate && !activeKeys[5].gate) { | |||
open.sort(); | |||
} | |||
switch (mode) { | |||
case RESET: | |||
if (open.size() == GTX__N ) { | |||
for (int i = 0; i < GTX__N; i++) { | |||
activeKeys[i].gate = false; | |||
open.push_back(i); | |||
} | |||
} | |||
break; | |||
case REASSIGN: | |||
open.push_back(open.front()); | |||
break; | |||
case ROTATE: | |||
break; | |||
} | |||
int next = open.front(); | |||
open.pop_front(); | |||
for (int i = 0; i < GTX__N; i++) { | |||
if (activeKeys[i].pitch == data1 && activeKeys[i].gate) { | |||
activeKeys[i].vel = data2; | |||
if (std::find(open.begin(), open.end(), i) != open.end()) | |||
open.remove(i); | |||
open.push_front(i); | |||
activeKeys[i].gate = false; | |||
} | |||
} | |||
activeKeys[next].gate = true; | |||
activeKeys[next].pitch = data1; | |||
activeKeys[next].vel = data2; | |||
} | |||
int Interface::getMode() const { | |||
return mode; | |||
} | |||
void Interface::setMode(int mode) { | |||
resetMidi(); | |||
Interface::mode = mode; | |||
} | |||
struct ModeItem : MenuItem { | |||
int mode; | |||
Interface *module; | |||
void onAction(EventAction &e) { | |||
module->setMode(mode); | |||
} | |||
}; | |||
//============================================================================================================ | |||
struct ModeChoice : ChoiceButton { | |||
Interface *module; | |||
const std::vector<std::string> modeNames = {"Rotate mode", "Reset mode", "Reassign mode"}; | |||
void onAction(EventAction &e) { | |||
Menu *menu = gScene->createMenu(); | |||
menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); | |||
menu->box.size.x = box.size.x; | |||
for (unsigned long i = 0; i < modeNames.size(); i++) { | |||
ModeItem *modeItem = new ModeItem(); | |||
modeItem->mode = i; | |||
modeItem->module = module; | |||
modeItem->text = modeNames[i]; | |||
menu->pushChild(modeItem); | |||
} | |||
} | |||
void step() { | |||
text = modeNames[module->getMode()]; | |||
} | |||
}; | |||
//============================================================================================================ | |||
//! \brief Menu for selection the MIDI device. | |||
//! | |||
//! This code derives from MidiIO.{cpp/hpp} MidiChoice altered so the menus fit the MIDI-C1 panel width. | |||
struct MidiChoice2 : MidiChoice | |||
{ | |||
void step() override | |||
{ | |||
if (midiModule->getDeviceName() == "") | |||
{ | |||
text = "No Device"; | |||
return; | |||
} | |||
std::string name = midiModule->getDeviceName(); | |||
text = ellipsize(name, 22); | |||
} | |||
}; | |||
//============================================================================================================ | |||
Widget::Widget() | |||
{ | |||
GTX__WIDGET(); | |||
Interface *module = new Interface(); | |||
setModule(module); | |||
box.size = Vec(12*15, 380); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/MIDI-C1.svg"), box.size, "MIDI-C1"); | |||
pg.but2(0.5, 0.4, "RESET"); | |||
pg.bus_out(0, 1, "VEL"); pg.bus_out(1, 1, "GATE"); | |||
pg.bus_out(0, 2, "AFT"); pg.bus_out(1, 2, "V/OCT"); | |||
} | |||
#endif | |||
{ | |||
SVGPanel *panel = new SVGPanel(); | |||
panel->box.size = box.size; | |||
panel->setBackground(SVG::load(assetPlugin(plugin, "res/MIDI-C1.svg"))); | |||
addChild(panel); | |||
} | |||
addChild(createScrew<ScrewSilver>(Vec(15, 0))); | |||
addChild(createScrew<ScrewSilver>(Vec(box.size.x - 30, 0))); | |||
addChild(createScrew<ScrewSilver>(Vec(15, 365))); | |||
addChild(createScrew<ScrewSilver>(Vec(box.size.x - 30, 365))); | |||
addParam(createParam<LEDButton>( but(fx(0.5), fy(0.4)), module, Interface::RESET_PARAM, 0.0, 1.0, 0.0)); | |||
addChild(createLight<SmallLight<RedLight>>(l_s(fx(0.5), fy(0.4)), module, Interface::RESET_LIGHT)); | |||
{ | |||
float margin = 8; | |||
float yPos = 42; | |||
{ | |||
MidiChoice2 *midiChoice = new MidiChoice2(); | |||
midiChoice->midiModule = dynamic_cast<MidiIO *>(module); | |||
midiChoice->box.pos = Vec(margin, yPos); | |||
midiChoice->box.size.x = box.size.x - margin * 2; | |||
addChild(midiChoice); | |||
yPos += midiChoice->box.size.y + margin; | |||
} | |||
{ | |||
ChannelChoice *channelChoice = new ChannelChoice(); | |||
channelChoice->midiModule = dynamic_cast<MidiIO *>(module); | |||
channelChoice->box.pos = Vec(margin, yPos); | |||
channelChoice->box.size.x = box.size.x - margin * 2; | |||
addChild(channelChoice); | |||
yPos += channelChoice->box.size.y + margin; | |||
} | |||
{ | |||
ModeChoice *modeChoice = new ModeChoice(); | |||
modeChoice->module = module; | |||
modeChoice->box.pos = Vec(margin, yPos); | |||
modeChoice->box.size.x = box.size.x - margin * 2; | |||
addChild(modeChoice); | |||
} | |||
} | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(1, i), py(2, i)), module, Interface::omap(Interface:: PITCH_OUTPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(1, i), py(1, i)), module, Interface::omap(Interface:: GATE_OUTPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(0, i), py(1, i)), module, Interface::omap(Interface::VELOCITY_OUTPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(0, i), py(2, i)), module, Interface::omap(Interface:: AT_OUTPUT, i))); | |||
} | |||
} | |||
void Widget::step() | |||
{ | |||
ModuleWidget::step(); | |||
} | |||
} // namespace rack_plugin_Gratrix | |||
#endif |
@@ -0,0 +1,393 @@ | |||
#if 0 | |||
//============================================================================================================ | |||
//! | |||
//! \file MIDI-G1.cpp | |||
//! | |||
//! \brief MIDI-G1 is a six voice cut-down clone of the VCV Rack Core module 'Quad MIDI-to-CV Interface'. | |||
//! | |||
//============================================================================================================ | |||
#include <list> | |||
#include <algorithm> | |||
#include "rtmidi/RtMidi.h" | |||
#include "core.hpp" | |||
#include "MidiIO.hpp" | |||
#include "dsp/digital.hpp" | |||
#include "Gratrix.hpp" | |||
namespace rack_plugin_Gratrix { | |||
struct Key { | |||
int pitch = 60; | |||
int retriggerC = 0; | |||
bool gate = false; | |||
}; | |||
struct Interface : MidiIO, Module { | |||
enum ParamIds { | |||
RESET_PARAM, | |||
NUM_PARAMS | |||
}; | |||
enum InputIds { | |||
NUM_INPUTS | |||
}; | |||
enum OutputIds { | |||
PITCH_OUTPUT, // N | |||
GATE_OUTPUT, // N | |||
NUM_OUTPUTS, | |||
OFF_OUTPUTS = PITCH_OUTPUT | |||
}; | |||
enum LightIds { | |||
RESET_LIGHT, | |||
NUM_LIGHTS | |||
}; | |||
enum Modes { | |||
ROTATE, | |||
RESET, | |||
REASSIGN | |||
}; | |||
static constexpr std::size_t omap(std::size_t port, std::size_t bank) | |||
{ | |||
return port + bank * NUM_OUTPUTS; | |||
} | |||
bool pedal = false; | |||
int mode = REASSIGN; | |||
int getMode() const; | |||
void setMode(int mode); | |||
Key activeKeys[GTX__N]; | |||
std::list<int> open; | |||
SchmittTrigger resetTrigger; | |||
Interface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, GTX__N * (NUM_OUTPUTS - OFF_OUTPUTS) + OFF_OUTPUTS, NUM_LIGHTS) { | |||
} | |||
~Interface() { | |||
}; | |||
void step() override; | |||
void processMidi(std::vector<unsigned char> msg); | |||
json_t *toJson() override { | |||
json_t *rootJ = json_object(); | |||
addBaseJson(rootJ); | |||
return rootJ; | |||
} | |||
void fromJson(json_t *rootJ) override { | |||
baseFromJson(rootJ); | |||
} | |||
void reset() override { | |||
resetMidi(); | |||
} | |||
void resetMidi() override; | |||
}; | |||
void Interface::resetMidi() { | |||
for (int i = 0; i < GTX__N; i++) { | |||
outputs[GATE_OUTPUT + i].value = 0.0; | |||
activeKeys[i].gate = false; | |||
} | |||
open.clear(); | |||
pedal = false; | |||
lights[RESET_LIGHT].value = 1.0; | |||
} | |||
void Interface::step() { | |||
if (isPortOpen()) { | |||
std::vector<unsigned char> message; | |||
int msgsProcessed = 0; | |||
// midiIn->getMessage returns empty vector if there are no messages in the queue | |||
// NOTE: For the quadmidi we will process max GTX__N midi messages per step to avoid | |||
// problems with parallel input. | |||
getMessage(&message); | |||
while (msgsProcessed < GTX__N && message.size() > 0) { | |||
processMidi(message); | |||
getMessage(&message); | |||
msgsProcessed++; | |||
} | |||
} | |||
for (int i = 0; i < GTX__N; i++) { | |||
outputs[omap( GATE_OUTPUT, i)].value = activeKeys[i].gate ? 10.0 : 0; | |||
outputs[omap( PITCH_OUTPUT, i)].value = (activeKeys[i].pitch - 60) / 12.0; | |||
} | |||
if (resetTrigger.process(params[RESET_PARAM].value)) { | |||
resetMidi(); | |||
return; | |||
} | |||
lights[RESET_LIGHT].value -= lights[RESET_LIGHT].value / 0.55 / engineGetSampleRate(); // fade out light | |||
} | |||
void Interface::processMidi(std::vector<unsigned char> msg) { | |||
int channel = msg[0] & 0xf; | |||
int status = (msg[0] >> 4) & 0xf; | |||
int data1 = msg[1]; | |||
int data2 = msg[2]; | |||
bool gate; | |||
// Filter channels | |||
if (this->channel >= 0 && this->channel != channel) | |||
return; | |||
switch (status) { | |||
// note off | |||
case 0x8: { | |||
gate = false; | |||
} | |||
break; | |||
case 0x9: // note on | |||
if (data2 > 0) { | |||
gate = true; | |||
} else { | |||
// For some reason, some keyboards send a "note on" event with a velocity of 0 to signal that the key has been released. | |||
gate = false; | |||
} | |||
break; | |||
case 0xb: // cc | |||
if (data1 == 0x40) { // pedal | |||
pedal = (data2 >= 64); | |||
if (!pedal) { | |||
open.clear(); | |||
for (int i = 0; i < GTX__N; i++) { | |||
activeKeys[i].gate = false; | |||
open.push_back(i); | |||
} | |||
} | |||
} | |||
return; | |||
default: | |||
return; | |||
} | |||
if (pedal && !gate) { | |||
return; | |||
} | |||
if (!gate) { | |||
for (int i = 0; i < GTX__N; i++) { | |||
if (activeKeys[i].pitch == data1) { | |||
activeKeys[i].gate = false; | |||
if (std::find(open.begin(), open.end(), i) != open.end()) { | |||
open.remove(i); | |||
} | |||
open.push_front(i); | |||
} | |||
} | |||
return; | |||
} | |||
if (open.empty()) { | |||
for (int i = 0; i < GTX__N; i++) { | |||
open.push_back(i); | |||
} | |||
} | |||
if (!activeKeys[0].gate && !activeKeys[1].gate && | |||
!activeKeys[2].gate && !activeKeys[3].gate && | |||
!activeKeys[4].gate && !activeKeys[5].gate) { | |||
open.sort(); | |||
} | |||
switch (mode) { | |||
case RESET: | |||
if (open.size() == GTX__N ) { | |||
for (int i = 0; i < GTX__N; i++) { | |||
activeKeys[i].gate = false; | |||
open.push_back(i); | |||
} | |||
} | |||
break; | |||
case REASSIGN: | |||
open.push_back(open.front()); | |||
break; | |||
case ROTATE: | |||
break; | |||
} | |||
int next = open.front(); | |||
open.pop_front(); | |||
for (int i = 0; i < GTX__N; i++) { | |||
if (activeKeys[i].pitch == data1 && activeKeys[i].gate) { | |||
if (std::find(open.begin(), open.end(), i) != open.end()) | |||
open.remove(i); | |||
open.push_front(i); | |||
activeKeys[i].gate = false; | |||
} | |||
} | |||
activeKeys[next].gate = true; | |||
activeKeys[next].pitch = data1; | |||
} | |||
int Interface::getMode() const { | |||
return mode; | |||
} | |||
void Interface::setMode(int mode) { | |||
resetMidi(); | |||
Interface::mode = mode; | |||
} | |||
struct ModeItem : MenuItem { | |||
int mode; | |||
Interface *module; | |||
void onAction(EventAction &e) { | |||
module->setMode(mode); | |||
} | |||
}; | |||
//============================================================================================================ | |||
struct ModeChoice : ChoiceButton { | |||
Interface *module; | |||
const std::vector<std::string> modeNames = {"Rotate", "Reset", "Reassign"}; | |||
void onAction(EventAction &e) { | |||
Menu *menu = gScene->createMenu(); | |||
menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); | |||
menu->box.size.x = box.size.x; | |||
for (unsigned long i = 0; i < modeNames.size(); i++) { | |||
ModeItem *modeItem = new ModeItem(); | |||
modeItem->mode = i; | |||
modeItem->module = module; | |||
modeItem->text = modeNames[i]; | |||
menu->pushChild(modeItem); | |||
} | |||
} | |||
void step() { | |||
text = modeNames[module->getMode()]; | |||
} | |||
}; | |||
//============================================================================================================ | |||
//! \brief Menu for selection the MIDI device. | |||
//! | |||
//! This code derives from MidiIO.{cpp/hpp} MidiChoice altered so the menus fit the MIDI-G1 panel width. | |||
struct MidiChoice2 : MidiChoice | |||
{ | |||
void step() override | |||
{ | |||
if (midiModule->getDeviceName() == "") | |||
{ | |||
text = "No Dev."; | |||
return; | |||
} | |||
std::string name = midiModule->getDeviceName(); | |||
text = ellipsize(name, 9); | |||
} | |||
}; | |||
//============================================================================================================ | |||
Widget::Widget() | |||
{ | |||
GTX__WIDGET(); | |||
Interface *module = new Interface(); | |||
setModule(module); | |||
box.size = Vec(6*15, 380); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/MIDI-G1.svg"), box.size, "MIDI-G1"); | |||
pg.but2(-0.3, 0.4, "RESET"); | |||
pg.bus_out(0, 1, "GATE"); | |||
pg.bus_out(0, 2, "V/OCT"); | |||
} | |||
#endif | |||
{ | |||
SVGPanel *panel = new SVGPanel(); | |||
panel->box.size = box.size; | |||
panel->setBackground(SVG::load(assetPlugin(plugin, "res/MIDI-G1.svg"))); | |||
addChild(panel); | |||
} | |||
addChild(createScrew<ScrewSilver>(Vec(15, 0))); | |||
addChild(createScrew<ScrewSilver>(Vec(box.size.x - 30, 0))); | |||
addChild(createScrew<ScrewSilver>(Vec(15, 365))); | |||
addChild(createScrew<ScrewSilver>(Vec(box.size.x - 30, 365))); | |||
addParam(createParam<LEDButton>( but(fx(-0.3), fy(0.4)), module, Interface::RESET_PARAM, 0.0, 1.0, 0.0)); | |||
addChild(createLight<SmallLight<RedLight>>(l_s(fx(-0.3), fy(0.4)), module, Interface::RESET_LIGHT)); | |||
{ | |||
float margin = 8; | |||
float yPos = 42; | |||
{ | |||
MidiChoice2 *midiChoice = new MidiChoice2(); | |||
midiChoice->midiModule = dynamic_cast<MidiIO *>(module); | |||
midiChoice->box.pos = Vec(margin, yPos); | |||
midiChoice->box.size.x = box.size.x - margin * 2; | |||
addChild(midiChoice); | |||
yPos += midiChoice->box.size.y + margin; | |||
} | |||
{ | |||
ChannelChoice *channelChoice = new ChannelChoice(); | |||
channelChoice->midiModule = dynamic_cast<MidiIO *>(module); | |||
channelChoice->box.pos = Vec(margin, yPos); | |||
channelChoice->box.size.x = box.size.x - margin * 2; | |||
addChild(channelChoice); | |||
yPos += channelChoice->box.size.y + margin; | |||
} | |||
{ | |||
ModeChoice *modeChoice = new ModeChoice(); | |||
modeChoice->module = module; | |||
modeChoice->box.pos = Vec(margin, yPos); | |||
modeChoice->box.size.x = box.size.x - margin * 2; | |||
addChild(modeChoice); | |||
} | |||
} | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(0, i), py(2, i)), module, Interface::omap(Interface:: PITCH_OUTPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(0, i), py(1, i)), module, Interface::omap(Interface:: GATE_OUTPUT, i))); | |||
} | |||
} | |||
void Widget::step() | |||
{ | |||
ModuleWidget::step(); | |||
} | |||
} // namespace rack_plugin_Gratrix | |||
#endif |
@@ -0,0 +1,220 @@ | |||
//============================================================================================================ | |||
//! | |||
//! \file Octave-G1.cpp | |||
//! | |||
//! \brief Octave-G1 quantises the input to 12-ET and provides an octaves-worth of output. | |||
//! | |||
//============================================================================================================ | |||
#include "Gratrix.hpp" | |||
namespace rack_plugin_Gratrix { | |||
//============================================================================================================ | |||
//! \brief Some settings. | |||
enum Spec | |||
{ | |||
LO_BEGIN = -5, // C-1 | |||
LO_END = 5, // C+9 | |||
LO_SIZE = LO_END - LO_BEGIN + 1, | |||
E = 12, // ET | |||
N = 12, // Number of note outputs | |||
T = 2, | |||
M = 2*T+1 // Number of octave outputs | |||
}; | |||
//============================================================================================================ | |||
//! \brief The module. | |||
struct GtxModule_Octave_G1 : Module | |||
{ | |||
enum ParamIds { | |||
NUM_PARAMS | |||
}; | |||
enum InputIds { | |||
VOCT_INPUT = 0, | |||
NUM_INPUTS = VOCT_INPUT + 1 | |||
}; | |||
enum OutputIds { | |||
NOTE_OUTPUT = 0, | |||
OCT_OUTPUT = NOTE_OUTPUT + N, | |||
NUM_OUTPUTS = OCT_OUTPUT + M | |||
}; | |||
enum LightIds { | |||
KEY_LIGHT = 0, | |||
OCT_LIGHT = KEY_LIGHT + E, | |||
NUM_LIGHTS = OCT_LIGHT + LO_SIZE | |||
}; | |||
struct Decode | |||
{ | |||
/*static constexpr*/ float e = static_cast<float>(E); // Static constexpr gives | |||
/*static constexpr*/ float s = 1.0f / e; // link error on Mac build. | |||
float in = 0; //!< Raw input. | |||
float out = 0; //!< Input quantized. | |||
int note = 0; //!< Integer note (offset midi note). | |||
int key = 0; //!< C, C#, D, D#, etc. | |||
int oct = 0; //!< Octave (C4 = 0). | |||
void step(float input) | |||
{ | |||
int safe, fnote; | |||
in = input; | |||
fnote = std::floor(in * e + 0.5f); | |||
out = fnote * s; | |||
note = static_cast<int>(fnote); | |||
safe = note + (E * 1000); // push away from negative numbers | |||
key = safe % E; | |||
oct = (safe / E) - 1000; | |||
} | |||
}; | |||
Decode input; | |||
//-------------------------------------------------------------------------------------------------------- | |||
//! \brief Constructor. | |||
GtxModule_Octave_G1() | |||
: | |||
Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) | |||
{} | |||
//-------------------------------------------------------------------------------------------------------- | |||
//! \brief Step function. | |||
void step() override | |||
{ | |||
// Clear all lights | |||
float leds[NUM_LIGHTS] = {}; | |||
// Decode inputs and params | |||
input.step(inputs[VOCT_INPUT].value); | |||
for (std::size_t i=0; i<N; ++i) | |||
{ | |||
outputs[i + NOTE_OUTPUT].value = input.out + i * input.s; | |||
} | |||
for (std::size_t i=0; i<M; ++i) | |||
{ | |||
outputs[i + OCT_OUTPUT].value = (input.out - T) + i; | |||
} | |||
// Lights | |||
leds[KEY_LIGHT + input.key] = 1.0f; | |||
if (LO_BEGIN <= input.oct && input.oct <= LO_END) | |||
{ | |||
leds[OCT_LIGHT + input.oct - LO_BEGIN] = 1.0f; | |||
} | |||
// Write output in one go, seems to prevent flicker | |||
for (std::size_t i=0; i<NUM_LIGHTS; ++i) | |||
{ | |||
lights[i].value = leds[i]; | |||
} | |||
} | |||
}; | |||
static int x(std::size_t i, double radius) { return static_cast<int>(6*15 + 0.5 + radius * dx(i, E)); } | |||
static int y(std::size_t i, double radius) { return static_cast<int>(-20+206 + 0.5 + radius * dy(i, E)); } | |||
//============================================================================================================ | |||
//! \brief The widget. | |||
struct GtxWidget_Octave_G1 : ModuleWidget | |||
{ | |||
GtxWidget_Octave_G1(GtxModule_Octave_G1 *module) : ModuleWidget(module) | |||
{ | |||
GTX__WIDGET(); | |||
box.size = Vec(12*15, 380); | |||
// double r1 = 30; | |||
double r2 = 55; | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/Octave-G1.svg"), box.size, "OCTAVE-G1"); | |||
pg.circle(Vec(x(0, 0), y(0, 0)), r2+16, "fill:#7092BE;stroke:none"); | |||
pg.circle(Vec(x(0, 0), y(0, 0)), r2-16, "fill:#CEE1FD;stroke:none"); | |||
/* // Wires | |||
for (std::size_t i=0; i<N; ++i) | |||
{ | |||
pg.line(Vec(x(i, r1), y(i, r1)), Vec(x(i, r2), y(i, r2)), "stroke:#440022;stroke-width:1"); | |||
if (i) { pg.line(Vec(x(i-1, r1), y(i-1, r1)), Vec(x(i, r1), y(i, r1)), "stroke:#440022;stroke-width:1"); } | |||
} | |||
*/ | |||
// Ports | |||
pg.circle(Vec(x(0, 0), y(0, 0)), 10, "stroke:#440022;stroke-width:1"); | |||
for (std::size_t i=0; i<N; ++i) | |||
{ | |||
pg.circle(Vec(x(i, r2), y(i, r2)), 10, "stroke:#440022;stroke-width:1"); | |||
} | |||
pg.prt_out(-0.20, 2, "", "-2"); | |||
pg.prt_out( 0.15, 2, "", "-1"); | |||
pg.prt_out( 0.50, 2, "TRANSPOSE", "0"); | |||
pg.prt_out( 0.85, 2, "", "+1"); | |||
pg.prt_out( 1.20, 2, "", "+2"); | |||
} | |||
#endif | |||
setPanel(SVG::load(assetPlugin(plugin, "res/Octave-G1.svg"))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365))); | |||
addInput(createInputGTX<PortInMed>(Vec(x(0, 0), y(0, 0)), module, GtxModule_Octave_G1::VOCT_INPUT)); | |||
for (std::size_t i=0; i<N; ++i) | |||
{ | |||
addOutput(createOutputGTX<PortOutMed>(Vec(x(i, r2), y(i, r2)), module, i + GtxModule_Octave_G1::NOTE_OUTPUT)); | |||
} | |||
addOutput(createOutputGTX<PortOutMed>(Vec(gx(-0.20), gy(2)), module, 0 + GtxModule_Octave_G1::OCT_OUTPUT)); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(gx( 0.15), gy(2)), module, 1 + GtxModule_Octave_G1::OCT_OUTPUT)); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(gx( 0.50), gy(2)), module, 2 + GtxModule_Octave_G1::OCT_OUTPUT)); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(gx( 0.85), gy(2)), module, 3 + GtxModule_Octave_G1::OCT_OUTPUT)); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(gx( 1.20), gy(2)), module, 4 + GtxModule_Octave_G1::OCT_OUTPUT)); | |||
addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) - 30, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 0)); // C | |||
addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) - 25, fy(0-0.28) - 5), module, GtxModule_Octave_G1::KEY_LIGHT + 1)); // C# | |||
addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) - 20, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 2)); // D | |||
addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) - 15, fy(0-0.28) - 5), module, GtxModule_Octave_G1::KEY_LIGHT + 3)); // Eb | |||
addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) - 10, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 4)); // E | |||
addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) , fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 5)); // F | |||
addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) + 5, fy(0-0.28) - 5), module, GtxModule_Octave_G1::KEY_LIGHT + 6)); // Fs | |||
addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) + 10, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 7)); // G | |||
addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) + 15, fy(0-0.28) - 5), module, GtxModule_Octave_G1::KEY_LIGHT + 8)); // Ab | |||
addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) + 20, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 9)); // A | |||
addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) + 25, fy(0-0.28) - 5), module, GtxModule_Octave_G1::KEY_LIGHT + 10)); // Bb | |||
addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) + 30, fy(0-0.28) + 5), module, GtxModule_Octave_G1::KEY_LIGHT + 11)); // B | |||
for (std::size_t i=0; i<LO_SIZE; ++i) | |||
{ | |||
addChild(ModuleLightWidget::create<SmallLight<RedLight>>(l_s(gx(0.5) + (i - LO_SIZE/2) * 10, fy(0-0.28) + 20), module, GtxModule_Octave_G1::OCT_LIGHT + i)); | |||
} | |||
} | |||
}; | |||
} // namespace rack_plugin_Gratrix | |||
using namespace rack_plugin_Gratrix; | |||
RACK_PLUGIN_MODEL_INIT(Gratrix, Octave_G1) { | |||
Model *model = Model::create<GtxModule_Octave_G1, GtxWidget_Octave_G1>("Gratrix", "Octave-G1", "Octave-G1", SYNTH_VOICE_TAG); // right tag? | |||
return model; | |||
} |
@@ -0,0 +1,387 @@ | |||
//============================================================================================================ | |||
//! | |||
//! \file Scope-G1.cpp | |||
//! | |||
//! \brief Scope-G1 is a... | |||
//! | |||
//============================================================================================================ | |||
#include <string.h> | |||
#include "dsp/digital.hpp" | |||
#include "Gratrix.hpp" | |||
namespace rack_plugin_Gratrix { | |||
#define BUFFER_SIZE 512 | |||
struct Scope : Module { | |||
enum ParamIds { | |||
X_SCALE_PARAM, | |||
X_POS_PARAM, | |||
TIME_PARAM, | |||
TRIG_PARAM, | |||
EXTERNAL_PARAM, | |||
DISP_PARAM, | |||
NUM_PARAMS | |||
}; | |||
enum InputIds { | |||
X_INPUT, // N | |||
TRIG_INPUT, // N | |||
NUM_INPUTS | |||
}; | |||
enum OutputIds { | |||
NUM_OUTPUTS | |||
}; | |||
enum LightIds { | |||
NUM_LIGHTS | |||
}; | |||
struct Voice { | |||
bool active = false; | |||
float bufferX[BUFFER_SIZE] = {}; | |||
int bufferIndex = 0; | |||
float frameIndex = 0; | |||
SchmittTrigger resetTrigger; | |||
void step(bool external, int frameCount, const Param &trig_param, const Input &x_input, const Input &trig_input); | |||
}; | |||
bool external = false; | |||
Voice voice[GTX__N+1]; | |||
Scope() : Module(NUM_PARAMS, GTX__N * NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} | |||
static constexpr std::size_t imap(std::size_t port, std::size_t bank) | |||
{ | |||
return port + bank * NUM_INPUTS; | |||
} | |||
void step() override; | |||
}; | |||
void Scope::step() { | |||
// Modes | |||
external = params[EXTERNAL_PARAM].value <= 0.0f; | |||
// Compute time | |||
float deltaTime = powf(2.0f, params[TIME_PARAM].value); | |||
int frameCount = (int)ceilf(deltaTime * engineGetSampleRate()); | |||
Input x_sum, trig_sum; | |||
int count = 0; | |||
for (int k=0; k<GTX__N; ++k) | |||
{ | |||
voice[k].step(external, frameCount, params[TRIG_PARAM], inputs[imap(X_INPUT, k)], inputs[imap(TRIG_INPUT, k)]); | |||
if (inputs[imap(X_INPUT, k)].active) | |||
{ | |||
x_sum.active = true; | |||
x_sum.value += inputs[imap(X_INPUT, k)].value; | |||
count++; | |||
} | |||
if (inputs[imap(TRIG_INPUT, k)].active) // GTX TODO - may need better logic here | |||
{ | |||
trig_sum.active = true; | |||
trig_sum.value += inputs[imap(TRIG_INPUT, k)].value; | |||
} | |||
} | |||
if (count > 0) | |||
{ | |||
x_sum.value /= static_cast<float>(count); | |||
} | |||
voice[GTX__N].step(external, frameCount, params[TRIG_PARAM], x_sum, trig_sum); | |||
} | |||
void Scope::Voice::step(bool external, int frameCount, const Param &trig_param, const Input &x_input, const Input &trig_input) { | |||
// Copy active state | |||
active = x_input.active; | |||
// Add frame to buffer | |||
if (bufferIndex < BUFFER_SIZE) { | |||
if (++frameIndex > frameCount) { | |||
frameIndex = 0; | |||
bufferX[bufferIndex] = x_input.value; | |||
bufferIndex++; | |||
} | |||
} | |||
// Are we waiting on the next trigger? | |||
if (bufferIndex >= BUFFER_SIZE) { | |||
// Trigger immediately if external but nothing plugged in | |||
if (external && !trig_input.active) { | |||
bufferIndex = 0; | |||
frameIndex = 0; | |||
return; | |||
} | |||
// Reset the Schmitt trigger so we don't trigger immediately if the input is high | |||
if (frameIndex == 0) { | |||
resetTrigger.reset(); | |||
} | |||
frameIndex++; | |||
// Must go below 0.1fV to trigger | |||
float gate = external ? trig_input.value : x_input.value; | |||
// Reset if triggered | |||
float holdTime = 0.1f; | |||
if (resetTrigger.process(rescale(gate, trig_param.value - 0.1f, trig_param.value, 0.f, 1.f)) || (frameIndex >= engineGetSampleRate() * holdTime)) { | |||
bufferIndex = 0; frameIndex = 0; return; | |||
} | |||
// Reset if we've waited too long | |||
if (frameIndex >= engineGetSampleRate() * holdTime) { | |||
bufferIndex = 0; frameIndex = 0; return; | |||
} | |||
} | |||
} | |||
struct Display : TransparentWidget { | |||
Scope *module; | |||
int frame = 0; | |||
std::shared_ptr<Font> font; | |||
struct Stats { | |||
float vrms, vpp, vmin, vmax; | |||
void calculate(float *values) { | |||
vrms = 0.0f; | |||
vmax = -INFINITY; | |||
vmin = INFINITY; | |||
for (int i = 0; i < BUFFER_SIZE; i++) { | |||
float v = values[i]; | |||
vrms += v*v; | |||
vmax = fmaxf(vmax, v); | |||
vmin = fminf(vmin, v); | |||
} | |||
vrms = sqrtf(vrms / BUFFER_SIZE); | |||
vpp = vmax - vmin; | |||
} | |||
}; | |||
Stats statsX[GTX__N + 1]; | |||
Display() { | |||
font = Font::load(assetPlugin(plugin, "res/fonts/Sudo.ttf")); | |||
} | |||
void drawWaveform(NVGcontext *vg, float *valuesX, const Rect &b) { | |||
if (!valuesX) | |||
return; | |||
nvgSave(vg); | |||
nvgScissor(vg, b.pos.x, b.pos.y, b.size.x, b.size.y); | |||
nvgBeginPath(vg); | |||
// Draw maximum display left to right | |||
for (int i = 0; i < BUFFER_SIZE; i++) { | |||
float x = (float)i / (BUFFER_SIZE - 1); | |||
float y = valuesX[i] / 2.0f + 0.5f; | |||
Vec p; | |||
p.x = b.pos.x + b.size.x * x; | |||
p.y = b.pos.y + b.size.y * (1.0f - y); | |||
if (i == 0) | |||
nvgMoveTo(vg, p.x, p.y); | |||
else | |||
nvgLineTo(vg, p.x, p.y); | |||
} | |||
nvgLineCap(vg, NVG_ROUND); | |||
nvgMiterLimit(vg, 2.0); | |||
nvgStrokeWidth(vg, 1.5); | |||
nvgGlobalCompositeOperation(vg, NVG_LIGHTER); | |||
nvgStroke(vg); | |||
nvgResetScissor(vg); | |||
nvgRestore(vg); | |||
} | |||
void drawTrig(NVGcontext *vg, float value, const Rect &b) { | |||
nvgScissor(vg, b.pos.x, b.pos.y, b.size.x, b.size.y); | |||
value = value / 2.0f + 0.5f; | |||
Vec p = Vec(b.pos.x + b.size.x, b.pos.y + b.size.y * (1.0f - value)); | |||
// Draw line | |||
nvgStrokeColor(vg, nvgRGBA(0xff, 0xff, 0xff, 0x10)); | |||
{ | |||
nvgBeginPath(vg); | |||
nvgMoveTo(vg, p.x - 13, p.y); | |||
nvgLineTo(vg, 0, p.y); | |||
nvgClosePath(vg); | |||
} | |||
nvgStroke(vg); | |||
// Draw indicator | |||
nvgFillColor(vg, nvgRGBA(0xff, 0xff, 0xff, 0x60)); | |||
{ | |||
nvgBeginPath(vg); | |||
nvgMoveTo(vg, p.x - 2, p.y - 4); | |||
nvgLineTo(vg, p.x - 9, p.y - 4); | |||
nvgLineTo(vg, p.x - 13, p.y); | |||
nvgLineTo(vg, p.x - 9, p.y + 4); | |||
nvgLineTo(vg, p.x - 2, p.y + 4); | |||
nvgClosePath(vg); | |||
} | |||
nvgFill(vg); | |||
nvgFontSize(vg, 9); | |||
nvgFontFaceId(vg, font->handle); | |||
nvgFillColor(vg, nvgRGBA(0x1e, 0x28, 0x2b, 0xff)); | |||
nvgText(vg, p.x - 8, p.y + 3, "T", NULL); | |||
nvgResetScissor(vg); | |||
} | |||
void drawStats(NVGcontext *vg, Vec pos, const char *title, const Stats &stats) { | |||
nvgFontSize(vg, 13); | |||
nvgFontFaceId(vg, font->handle); | |||
nvgTextLetterSpacing(vg, -2); | |||
nvgFillColor(vg, nvgRGBA(0xff, 0xff, 0xff, 0x80)); | |||
char text[128]; | |||
snprintf(text, sizeof(text), "%s. %4.1f [%+5.1f %+5.1f]", title, stats.vpp, stats.vmin, stats.vmax); | |||
nvgText(vg, pos.x + 6, pos.y + 11, text, NULL); | |||
} | |||
void draw(NVGcontext *vg) override { | |||
float gainX = powf(2.0, roundf(module->params[Scope::X_SCALE_PARAM].value)); | |||
float offsetX = module->params[Scope::X_POS_PARAM].value; | |||
int disp = static_cast<int>(module->params[Scope::DISP_PARAM].value + 0.5f); | |||
int k0, k1, kM; | |||
if (disp == 0 ) { k0 = 0; k1 = GTX__N; kM = 0; } // six up | |||
else if (disp == GTX__N+1) { k0 = GTX__N; k1 = GTX__N+1; kM = 100; } // sum | |||
else { k0 = disp-1; k1 = disp ; kM = 100; } // individual | |||
static const char *stats_lab[GTX__N+1] = {"1", "2", "3", "4", "5", "6", "SUM"}; | |||
for (int k=k0; k<k1; ++k) | |||
{ | |||
Rect a = Rect(Vec(0, 15), box.size.minus(Vec(0, 15*2))); | |||
Rect b = a; | |||
// GTX TODO - imporve | |||
if (kM < GTX__N) | |||
{ | |||
b.size.x /= (GTX__N/2); | |||
b.size.y /= (GTX__N/3); | |||
b.pos.x += (k%3) * b.size.x; | |||
b.pos.y += (k/3) * b.size.y; | |||
} | |||
float valuesX[BUFFER_SIZE]; | |||
for (int i = 0; i < BUFFER_SIZE; i++) { | |||
valuesX[i] = (module->voice[k].bufferX[i] + offsetX) * gainX / 10.0; | |||
} | |||
// Draw waveforms | |||
if (module->voice[k].active) { | |||
if (k&1) nvgStrokeColor(vg, nvgRGBA(0xe1, 0x02, 0x78, 0xc0)); | |||
else nvgStrokeColor(vg, nvgRGBA(0x28, 0xb0, 0xf3, 0xc0)); | |||
drawWaveform(vg, valuesX, b); | |||
} | |||
float valueTrig = (module->params[Scope::TRIG_PARAM].value + offsetX) * gainX / 10.0; | |||
drawTrig(vg, valueTrig, b); | |||
// Calculate and draw stats | |||
if (frame == 0) { | |||
statsX[k].calculate(module->voice[k].bufferX); | |||
} | |||
Vec stats_pos = b.pos; | |||
if (k >= 3 && k < GTX__N) | |||
{ | |||
stats_pos.y += b.size.y; | |||
} | |||
else | |||
{ | |||
stats_pos.y -= 15; | |||
} | |||
drawStats(vg, stats_pos, stats_lab[k], statsX[k]); | |||
} | |||
if (++frame >= 4) | |||
{ | |||
frame = 0; | |||
} | |||
} | |||
}; | |||
//============================================================================================================ | |||
//! \brief The widget. | |||
struct GtxWidget_Scope_G1 : ModuleWidget | |||
{ | |||
GtxWidget_Scope_G1(Scope *module) : ModuleWidget(module) | |||
{ | |||
GTX__WIDGET(); | |||
box.size = Vec(24*15, 380); | |||
auto screen_pos = Vec(0, 35); | |||
auto screen_size = Vec(box.size.x, 220); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/Scope-G1.svg"), box.size, "SCOPE-G1"); | |||
pg.rect(screen_pos, screen_size, "fill:#222222;stroke:none"); | |||
pg.bus_in(0, 2, "IN"); | |||
pg.bus_in(2, 2, "EXT TRIG"); | |||
pg.nob_sml_raw(gx(1-0.22), gy(2-0.24), "SCALE"); | |||
pg.nob_sml_raw(gx(1-0.22), gy(2+0.22), "POS"); | |||
pg.nob_sml_raw(gx(1+0.22), gy(2-0.24), "TIME"); | |||
pg.nob_sml_raw(gx(1+0.22), gy(2+0.22), "TRIG"); | |||
pg.tog_raw (gx(3-0.22), gy(2-0.24), "INT", "EXT"); | |||
pg.nob_sml_raw(gx(3+0.22), gy(2-0.24), "DISP"); | |||
for (std::size_t i=0; i<=12; i++) | |||
{ | |||
float x = screen_pos.x + screen_size.x * i / 12.0f; | |||
pg.line(Vec(x, screen_pos.y + 15), Vec(x, screen_pos.y + screen_size.y - 15), "fill:none;stroke:#666666;stroke-width:1"); | |||
} | |||
for (std::size_t i=0; i<=8; i++) | |||
{ | |||
float y = screen_pos.y + 15 + (screen_size.y - 30) * i / 8.0f; | |||
pg.line(Vec(screen_pos.x, y), Vec(screen_pos.x + screen_size.x, y), "fill:none;stroke:#666666;stroke-width:1"); | |||
} | |||
} | |||
#endif | |||
setPanel(SVG::load(assetPlugin(plugin, "res/Scope-G1.svg"))); | |||
{ | |||
Display *display = new Display(); | |||
display->module = module; | |||
display->box.pos = screen_pos; | |||
display->box.size = screen_size; | |||
addChild(display); | |||
} | |||
addParam(createParamGTX<KnobSnapSml>(Vec(gx(1-0.22), gy(2-0.24)), module, Scope::X_SCALE_PARAM, -2.0f, 8.0f, 0.0f)); | |||
addParam(createParamGTX<KnobFreeSml>(Vec(gx(1-0.22), gy(2+0.22)), module, Scope::X_POS_PARAM, -10.0f, 10.0f, 0.0f)); | |||
addParam(createParamGTX<KnobFreeSml>(Vec(gx(1+0.22), gy(2-0.24)), module, Scope::TIME_PARAM, -6.0f, -16.0f, -14.0f)); | |||
addParam(createParamGTX<KnobFreeSml>(Vec(gx(1+0.22), gy(2+0.22)), module, Scope::TRIG_PARAM, -10.0f, 10.0f, 0.0f)); | |||
addParam(ParamWidget::create<CKSS> (tog(gx(3-0.22), gy(2-0.24)), module, Scope::EXTERNAL_PARAM, 0.0f, 1.0f, 1.0f)); | |||
addParam(createParamGTX<KnobSnapSml>(Vec(gx(3+0.22), gy(2-0.24)), module, Scope::DISP_PARAM, 0.0f, GTX__N+1, 0.0f)); | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(2, i)), module, Scope::imap(Scope::X_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(2, i), py(2, i)), module, Scope::imap(Scope::TRIG_INPUT, i))); | |||
} | |||
} | |||
}; | |||
} // namespace rack_plugin_Gratrix | |||
using namespace rack_plugin_Gratrix; | |||
RACK_PLUGIN_MODEL_INIT(Gratrix, Scope_G1) { | |||
Model *model = Model::create<Scope, GtxWidget_Scope_G1>("Gratrix", "Scope-G1", "Scope-G1", VISUAL_TAG); | |||
return model; | |||
} |
@@ -0,0 +1,157 @@ | |||
#include "Gratrix.hpp" | |||
namespace rack_plugin_Gratrix { | |||
//============================================================================================================ | |||
struct VCA : MicroModule { | |||
enum ParamIds { | |||
LEVEL_PARAM, | |||
MIX_1_PARAM, | |||
MIX_2_PARAM, | |||
NUM_PARAMS | |||
}; | |||
enum InputIds { | |||
EXP_INPUT, // N+1 | |||
LIN_INPUT, // N+1 | |||
IN_INPUT, // N+1 | |||
NUM_INPUTS, | |||
OFF_INPUTS = EXP_INPUT | |||
}; | |||
enum OutputIds { | |||
MIX_1_OUTPUT, // 1 | |||
MIX_2_OUTPUT, // 1 | |||
OUT_OUTPUT, // N | |||
NUM_OUTPUTS, | |||
OFF_OUTPUTS = OUT_OUTPUT | |||
}; | |||
VCA() : MicroModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {} | |||
void step(); | |||
}; | |||
//============================================================================================================ | |||
void VCA::step() { | |||
float v = inputs[IN_INPUT].value * params[LEVEL_PARAM].value; | |||
if (inputs[LIN_INPUT].active) | |||
v *= clamp(inputs[LIN_INPUT].value / 10.0f, 0.0f, 1.0f); | |||
const float expBase = 50.0f; | |||
if (inputs[EXP_INPUT].active) | |||
v *= rescale(powf(expBase, clamp(inputs[EXP_INPUT].value / 10.0f, 0.0f, 1.0f)), 1.0f, expBase, 0.0f, 1.0f); | |||
outputs[OUT_OUTPUT].value = v; | |||
} | |||
//============================================================================================================ | |||
struct VCABank : Module | |||
{ | |||
std::array<VCA, GTX__N> inst; | |||
VCABank() | |||
: | |||
Module(VCA::NUM_PARAMS, | |||
(GTX__N+1) * (VCA::NUM_INPUTS - VCA::OFF_INPUTS ) + VCA::OFF_INPUTS, | |||
(GTX__N ) * (VCA::NUM_OUTPUTS - VCA::OFF_OUTPUTS) + VCA::OFF_OUTPUTS) | |||
{} | |||
static constexpr std::size_t imap(std::size_t port, std::size_t bank) | |||
{ | |||
return port + bank * VCA::NUM_INPUTS; | |||
} | |||
static constexpr std::size_t omap(std::size_t port, std::size_t bank) | |||
{ | |||
return (port < VCA::OFF_OUTPUTS) ? port : port + bank * (VCA::NUM_OUTPUTS - VCA::OFF_OUTPUTS); | |||
} | |||
void step() override | |||
{ | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
for (std::size_t p=0; p<VCA::NUM_PARAMS; ++p) inst[i].params[p] = params[p]; | |||
for (std::size_t p=0; p<VCA::NUM_INPUTS; ++p) inst[i].inputs[p] = inputs[imap(p, i)].active ? inputs[imap(p, i)] : inputs[imap(p, GTX__N)]; | |||
for (std::size_t p=0; p<VCA::NUM_OUTPUTS; ++p) inst[i].outputs[p] = outputs[omap(p, i)]; | |||
inst[i].step(); | |||
for (std::size_t p=0; p<VCA::NUM_OUTPUTS; ++p) outputs[omap(p, i)].value = inst[i].outputs[p].value; | |||
} | |||
float mix = 0.0f; | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
mix += inst[i].outputs[VCA::OUT_OUTPUT].value; | |||
} | |||
outputs[VCA::MIX_1_OUTPUT].value = mix * params[VCA::MIX_1_PARAM].value; | |||
outputs[VCA::MIX_2_OUTPUT].value = mix * params[VCA::MIX_2_PARAM].value; | |||
} | |||
}; | |||
//============================================================================================================ | |||
//! \brief The widget. | |||
struct GtxWidget_VCA : ModuleWidget | |||
{ | |||
GtxWidget_VCA(VCABank *module) : ModuleWidget(module) | |||
{ | |||
GTX__WIDGET(); | |||
box.size = Vec(12*15, 380); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/VCA-F1.svg"), box.size, "VCA-F1"); | |||
pg.nob_big(0, 0, "LEVEL"); | |||
pg.nob_med(1, -0.28, "MIX OUT 1"); | |||
pg.nob_med(1, +0.28, "MIX OUT 2"); | |||
pg.bus_in (0, 1, "EXP"); pg.bus_in (1, 1, "LIN"); | |||
pg.bus_in (0, 2, "IN"); pg.bus_out(1, 2, "OUT"); | |||
} | |||
#endif | |||
setPanel(SVG::load(assetPlugin(plugin, "res/VCA-F1.svg"))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365))); | |||
addParam(createParamGTX<KnobFreeHug>(Vec(fx(0), fy(0)), module, VCA::LEVEL_PARAM, 0.0f, 1.0f, 0.5f)); | |||
addParam(createParamGTX<KnobFreeMed>(Vec(fx(1-0.18), fy(-0.28)), module, VCA::MIX_1_PARAM, 0.0f, 1.0f, 0.5f)); | |||
addParam(createParamGTX<KnobFreeMed>(Vec(fx(1-0.18), fy(+0.28)), module, VCA::MIX_2_PARAM, 0.0f, 1.0f, 0.5f)); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(fx(1+0.28), fy(-0.28)), module, VCA::MIX_1_OUTPUT)); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(fx(1+0.28), fy(+0.28)), module, VCA::MIX_2_OUTPUT)); | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
addInput(createInputGTX<PortInMed>(Vec(px(1, i), py(1, i)), module, VCABank::imap(VCA::LIN_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(1, i)), module, VCABank::imap(VCA::EXP_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(2, i)), module, VCABank::imap(VCA::IN_INPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(1, i), py(2, i)), module, VCABank::omap(VCA::OUT_OUTPUT, i))); | |||
} | |||
addInput(createInputGTX<PortInMed>(Vec(gx(1), gy(1)), module, VCABank::imap(VCA::LIN_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(1)), module, VCABank::imap(VCA::EXP_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(2)), module, VCABank::imap(VCA::IN_INPUT, GTX__N))); | |||
} | |||
}; | |||
} // namespace rack_plugin_Gratrix | |||
using namespace rack_plugin_Gratrix; | |||
RACK_PLUGIN_MODEL_INIT(Gratrix, VCA_F1) { | |||
Model *model = Model::create<VCABank, GtxWidget_VCA>("Gratrix", "VCA-F1", "VCA-F1", AMPLIFIER_TAG); | |||
return model; | |||
} |
@@ -0,0 +1,257 @@ | |||
/* | |||
The filter DSP code has been derived from | |||
Miller Puckette's code hosted at | |||
https://github.com/ddiakopoulos/MoogLadders/blob/master/src/RKSimulationModel.h | |||
which is licensed for use under the following terms (MIT license): | |||
Copyright (c) 2015, Miller Puckette. All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright notice, this | |||
list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright notice, | |||
this list of conditions and the following disclaimer in the documentation | |||
and/or other materials provided with the distribution. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#include "Gratrix.hpp" | |||
namespace rack_plugin_Gratrix { | |||
// The clipping function of a transistor pair is approximately tanh(x) | |||
// TODO: Put this in a lookup table. 5th order approx doesn't seem to cut it | |||
inline float clip(float x) { | |||
return tanhf(x); | |||
} | |||
struct LadderFilter { | |||
float cutoff = 1000.0f; | |||
float resonance = 1.0f; | |||
float state[4] = {}; | |||
void calculateDerivatives(float input, float *dstate, const float *state) { | |||
float cutoff2Pi = 2*M_PI * cutoff; | |||
float satstate0 = clip(state[0]); | |||
float satstate1 = clip(state[1]); | |||
float satstate2 = clip(state[2]); | |||
dstate[0] = cutoff2Pi * (clip(input - resonance * state[3]) - satstate0); | |||
dstate[1] = cutoff2Pi * (satstate0 - satstate1); | |||
dstate[2] = cutoff2Pi * (satstate1 - satstate2); | |||
dstate[3] = cutoff2Pi * (satstate2 - clip(state[3])); | |||
} | |||
void process(float input, float dt) { | |||
float deriv1[4], deriv2[4], deriv3[4], deriv4[4], tempState[4]; | |||
calculateDerivatives(input, deriv1, state); | |||
for (int i = 0; i < 4; i++) | |||
tempState[i] = state[i] + 0.5f * dt * deriv1[i]; | |||
calculateDerivatives(input, deriv2, tempState); | |||
for (int i = 0; i < 4; i++) | |||
tempState[i] = state[i] + 0.5f * dt * deriv2[i]; | |||
calculateDerivatives(input, deriv3, tempState); | |||
for (int i = 0; i < 4; i++) | |||
tempState[i] = state[i] + dt * deriv3[i]; | |||
calculateDerivatives(input, deriv4, tempState); | |||
for (int i = 0; i < 4; i++) | |||
state[i] += (1.0f / 6.0f) * dt * (deriv1[i] + 2.0f * deriv2[i] + 2.0f * deriv3[i] + deriv4[i]); | |||
} | |||
void reset() { | |||
for (int i = 0; i < 4; i++) { | |||
state[i] = 0.0f; | |||
} | |||
} | |||
}; | |||
//============================================================================================================ | |||
struct VCF : MicroModule { | |||
enum ParamIds { | |||
FREQ_PARAM, | |||
FINE_PARAM, | |||
RES_PARAM, | |||
FREQ_CV_PARAM, | |||
DRIVE_PARAM, | |||
NUM_PARAMS | |||
}; | |||
enum InputIds { | |||
FREQ_INPUT, | |||
RES_INPUT, | |||
DRIVE_INPUT, | |||
IN_INPUT, | |||
NUM_INPUTS | |||
}; | |||
enum OutputIds { | |||
LPF_OUTPUT, | |||
HPF_OUTPUT, | |||
NUM_OUTPUTS | |||
}; | |||
LadderFilter filter; | |||
VCF() : MicroModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {} | |||
void step(); | |||
void onReset() { | |||
filter.reset(); | |||
} | |||
}; | |||
//============================================================================================================ | |||
void VCF::step() { | |||
float input = inputs[IN_INPUT].value / 5.0f; | |||
float drive = params[DRIVE_PARAM].value + inputs[DRIVE_INPUT].value / 10.0f; | |||
float gain = powf(100.0f, drive); | |||
input *= gain; | |||
// Add -60dB noise to bootstrap self-oscillation | |||
input += 1e-6f * (2.0f*randomUniform() - 1.0f); | |||
// Set resonance | |||
float res = params[RES_PARAM].value + inputs[RES_INPUT].value / 5.0f; | |||
res = 5.5f * clamp(res, 0.0f, 1.0f); | |||
filter.resonance = res; | |||
// Set cutoff frequency | |||
float cutoffExp = params[FREQ_PARAM].value + params[FREQ_CV_PARAM].value * inputs[FREQ_INPUT].value / 5.0f; | |||
cutoffExp = clamp(cutoffExp, 0.0f, 1.0f); | |||
const float minCutoff = 15.0f; | |||
const float maxCutoff = 8400.0f; | |||
filter.cutoff = minCutoff * powf(maxCutoff / minCutoff, cutoffExp); | |||
// Push a sample to the state filter | |||
filter.process(input, 1.0f/engineGetSampleRate()); | |||
// Set outputs | |||
outputs[LPF_OUTPUT].value = 5.0f * filter.state[3]; | |||
outputs[HPF_OUTPUT].value = 5.0f * (input - filter.state[3]); | |||
} | |||
//============================================================================================================ | |||
struct VCFBank : Module | |||
{ | |||
std::array<VCF, GTX__N> inst; | |||
VCFBank() : Module(VCF::NUM_PARAMS, (GTX__N+1) * VCF::NUM_INPUTS, GTX__N * VCF::NUM_OUTPUTS) {} | |||
static std::size_t imap(std::size_t port, std::size_t bank) | |||
{ | |||
return port + bank * VCF::NUM_INPUTS; | |||
} | |||
static std::size_t omap(std::size_t port, std::size_t bank) | |||
{ | |||
return port + bank * VCF::NUM_OUTPUTS; | |||
} | |||
void step() override | |||
{ | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
for (std::size_t p=0; p<VCF::NUM_PARAMS; ++p) inst[i].params[p] = params[p]; | |||
for (std::size_t p=0; p<VCF::NUM_INPUTS; ++p) inst[i].inputs[p] = inputs[imap(p, i)].active ? inputs[imap(p, i)] : inputs[imap(p, GTX__N)]; | |||
for (std::size_t p=0; p<VCF::NUM_OUTPUTS; ++p) inst[i].outputs[p] = outputs[omap(p, i)]; | |||
inst[i].step(); | |||
for (std::size_t p=0; p<VCF::NUM_OUTPUTS; ++p) outputs[omap(p, i)].value = inst[i].outputs[p].value; | |||
} | |||
} | |||
void onReset() override | |||
{ | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
inst[i].onReset(); | |||
} | |||
} | |||
}; | |||
//============================================================================================================ | |||
//! \brief The widget. | |||
struct GtxWidget_VCF : ModuleWidget | |||
{ | |||
GtxWidget_VCF(VCFBank *module) : ModuleWidget(module) | |||
{ | |||
GTX__WIDGET(); | |||
box.size = Vec(18*15, 380); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/VCF-F1.svg"), box.size, "VCF-F1"); | |||
pg.nob_big(0, 0, "FREQ"); | |||
pg.nob_med(1.1, -0.28, "FINE"); pg.nob_med(1.9, -0.28, "RES"); | |||
pg.nob_med(1.1, +0.28, "FREQ CV"); pg.nob_med(1.9, +0.28, "DRIVE"); | |||
pg.bus_in(0, 1, "FREQ"); pg.bus_in(1, 1, "RES"); pg.bus_out(2, 1, "HPF"); | |||
pg.bus_in(0, 2, "IN"); pg.bus_in(1, 2, "DRIVE"); pg.bus_out(2, 2, "LPF"); | |||
} | |||
#endif | |||
setPanel(SVG::load(assetPlugin(plugin, "res/VCF-F1.svg"))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365))); | |||
addParam(createParamGTX<KnobFreeHug>(Vec(fx(0.0), fy(+0.00)), module, VCF::FREQ_PARAM, 0.0f, 1.0f, 0.5f)); | |||
addParam(createParamGTX<KnobFreeMed>(Vec(fx(1.1), fy(-0.28)), module, VCF::FINE_PARAM, 0.0f, 1.0f, 0.5f)); | |||
addParam(createParamGTX<KnobFreeMed>(Vec(fx(1.9), fy(-0.28)), module, VCF::RES_PARAM, 0.0f, 1.0f, 0.0f)); | |||
addParam(createParamGTX<KnobFreeMed>(Vec(fx(1.1), fy(+0.28)), module, VCF::FREQ_CV_PARAM, -1.0f, 1.0f, 0.0f)); | |||
addParam(createParamGTX<KnobFreeMed>(Vec(fx(1.9), fy(+0.28)), module, VCF::DRIVE_PARAM, 0.0f, 1.0f, 0.0f)); | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(1, i)), module, VCFBank::imap(VCF::FREQ_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(1, i), py(1, i)), module, VCFBank::imap(VCF::RES_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(1, i), py(2, i)), module, VCFBank::imap(VCF::DRIVE_INPUT, i))); | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(2, i)), module, VCFBank::imap(VCF::IN_INPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(2, i), py(2, i)), module, VCFBank::omap(VCF::LPF_OUTPUT, i))); | |||
addOutput(createOutputGTX<PortOutMed>(Vec(px(2, i), py(1, i)), module, VCFBank::omap(VCF::HPF_OUTPUT, i))); | |||
} | |||
addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(1)), module, VCFBank::imap(VCF::FREQ_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(1), gy(1)), module, VCFBank::imap(VCF::RES_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(1), gy(2)), module, VCFBank::imap(VCF::DRIVE_INPUT, GTX__N))); | |||
addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(2)), module, VCFBank::imap(VCF::IN_INPUT, GTX__N))); | |||
} | |||
}; | |||
} // namespace rack_plugin_Gratrix | |||
using namespace rack_plugin_Gratrix; | |||
RACK_PLUGIN_MODEL_INIT(Gratrix, VCF_F1) { | |||
Model *model = Model::create<VCFBank, GtxWidget_VCF>("Gratrix", "VCF-F1", "VCF-F1", FILTER_TAG); | |||
return model; | |||
} |
@@ -0,0 +1,120 @@ | |||
//============================================================================================================ | |||
//! | |||
//! \file VU-G1.cpp | |||
//! | |||
//! \brief VU-G1 is a simple six input volume monitoring module. | |||
//! | |||
//============================================================================================================ | |||
#include "Gratrix.hpp" | |||
namespace rack_plugin_Gratrix { | |||
//============================================================================================================ | |||
//! \brief The module. | |||
struct GtxModule_VU_G1 : Module | |||
{ | |||
enum ParamIds { | |||
NUM_PARAMS | |||
}; | |||
enum InputIds { | |||
IN1_INPUT, // N+1 | |||
NUM_INPUTS | |||
}; | |||
enum OutputIds { | |||
NUM_OUTPUTS, | |||
}; | |||
enum LightIds { | |||
NUM_LIGHTS = 10 // N | |||
}; | |||
GtxModule_VU_G1() | |||
: | |||
Module(NUM_PARAMS, (GTX__N+1) * NUM_INPUTS, NUM_OUTPUTS, GTX__N * NUM_LIGHTS) | |||
{ | |||
} | |||
static constexpr std::size_t imap(std::size_t port, std::size_t bank) | |||
{ | |||
return port + bank * NUM_INPUTS; | |||
} | |||
void step() override | |||
{ | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
float input = inputs[imap(IN1_INPUT, i)].active ? inputs[imap(IN1_INPUT, i)].value : inputs[imap(IN1_INPUT, GTX__N)].value; | |||
float dB = logf(fabsf(input * 0.1f)) * (10.0f / logf(20.0f)); | |||
float dB2 = dB * (1.0f / 3.0f); | |||
for (int j = 0; j < NUM_LIGHTS; j++) | |||
{ | |||
float b = clamp(dB2 + (j+1), 0.0f, 1.0f); | |||
lights[NUM_LIGHTS * i + j].setBrightnessSmooth(b * 0.9f); | |||
} | |||
} | |||
} | |||
}; | |||
//============================================================================================================ | |||
//! \brief The widget. | |||
struct GtxWidget_VU_G1 : ModuleWidget | |||
{ | |||
GtxWidget_VU_G1(GtxModule_VU_G1 *module) : ModuleWidget(module) | |||
{ | |||
GTX__WIDGET(); | |||
box.size = Vec(6*15, 380); | |||
#if GTX__SAVE_SVG | |||
{ | |||
PanelGen pg(assetPlugin(plugin, "build/res/VU-G1.svg"), box.size, "VU-G1"); | |||
pg.nob_big(0, 0, "VOLUME"); | |||
pg.bus_in (0, 2, "IN"); | |||
} | |||
#endif | |||
setPanel(SVG::load(assetPlugin(plugin, "res/VU-G1.svg"))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0))); | |||
addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365))); | |||
for (std::size_t i=0; i<GTX__N; ++i) | |||
{ | |||
addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(2, i)), module, GtxModule_VU_G1::imap(GtxModule_VU_G1::IN1_INPUT, i))); | |||
} | |||
addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(2)), module, GtxModule_VU_G1::imap(GtxModule_VU_G1::IN1_INPUT, GTX__N))); | |||
for (std::size_t i=0, k=0; i<GTX__N; ++i) | |||
{ | |||
for (std::size_t j=0; j<GtxModule_VU_G1::NUM_LIGHTS; ++j, ++k) | |||
{ | |||
switch (j) | |||
{ | |||
case 0 : addChild(ModuleLightWidget::create<SmallLight< RedLight>>(l_s(gx(0)+(i-2.5f)*13.0f, gy(0.5)+(j-4.5f)*11.0f), module, k)); break; | |||
case 1 : | |||
case 2 : addChild(ModuleLightWidget::create<SmallLight<YellowLight>>(l_s(gx(0)+(i-2.5f)*13.0f, gy(0.5)+(j-4.5f)*11.0f), module, k)); break; | |||
default : addChild(ModuleLightWidget::create<SmallLight< GreenLight>>(l_s(gx(0)+(i-2.5f)*13.0f, gy(0.5)+(j-4.5f)*11.0f), module, k)); break; | |||
} | |||
} | |||
} | |||
} | |||
}; | |||
} // namespace rack_plugin_Gratrix | |||
using namespace rack_plugin_Gratrix; | |||
RACK_PLUGIN_MODEL_INIT(Gratrix, VU_G1) { | |||
Model *model = Model::create<GtxModule_VU_G1, GtxWidget_VU_G1>("Gratrix", "VU-G1", "VU-G1", VISUAL_TAG); | |||
return model; | |||
} |
@@ -0,0 +1,300 @@ | |||
<html lang="en-GB"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<head> | |||
<title>Gratrix.net - Gratrix Modules for VCV Rack</title> | |||
<style type="text/css"> | |||
body { | |||
font-family: Cambria; font-size: 15px; | |||
} | |||
p { | |||
max-width: 960px; | |||
/* text-align: justify; */ | |||
line-height: 133%; | |||
} | |||
ul { | |||
padding-left: 15px; | |||
/* text-align: justify; */ | |||
line-height: 150%; | |||
} | |||
li { | |||
padding:5px 0px 5px 0px; | |||
} | |||
img { | |||
margin: 0px; | |||
padding: 0px; | |||
border: 0px; | |||
} | |||
table { | |||
margin: 0px; | |||
padding: 0xp; | |||
border-collapse: collapse; | |||
} | |||
td { | |||
margin: 0px; | |||
padding: 0px; | |||
} | |||
.content { | |||
max-width: 990px; | |||
margin: auto; | |||
/* border: 1px solid red; */ | |||
} | |||
.wrapper { | |||
display: grid; | |||
grid-template-columns: 500px 480px; | |||
grid-gap: 10px; | |||
color: #444; | |||
} | |||
.box { | |||
background-color: #eee; | |||
color: #000; | |||
border-radius: 5px; | |||
padding: 20px; | |||
} | |||
.soon { | |||
color: #900; | |||
font-style: italic; | |||
} | |||
</style> | |||
</head> | |||
<body style="background-color: #FCFCFC;"> | |||
<div class="content"> | |||
<h1>Gratrix Modules for VCV Rack</h1> | |||
<i>by Sam Gratrix</i></i> | |||
<h2>Introduction</h2> | |||
<p>I've been a fan of polysynths for a while and recently I've had an itch to develop one of my own in software. | |||
And then came along VCV Rack with all it's open source VCOs, VCFs and VCAs. So here I am, creating a | |||
polyphonic modular synth!</p> | |||
<table> | |||
<tr> | |||
<td width="90"> </td><td width="90"> </td><td width="90"> </td><td width="90"> </td> | |||
<td width="90"> </td><td width="90"> </td><td width="90"> </td> | |||
<td width="90"> </td><td width="90"> </td><td width="90"> </td><td width="90"> </td> | |||
</tr><tr> | |||
<td width="360" colspan="4"><img src="res/VCO-F1.png"></td> | |||
<td width="180" colspan="2"><img src="res/VCO-F2.png"></td> | |||
<td width="270" colspan="3"><img src="res/VCF-F1.png"></td> | |||
<td width="180" colspan="2"><img src="res/VCA-F1.png"></td> | |||
</tr><tr> | |||
<td width="180" colspan="2"><img src="res/Env-F1.png"></td> | |||
<td width="180" colspan="2"><img src="res/MIDI-C1.png"></td> | |||
<td width="90" colspan="1"><img src="res/MIDI-G1.png"></td> | |||
<td width="90" colspan="1"><img src="res/Blank06.png"></td> | |||
<td width="180" colspan="2"><img src="res/Fade-G1.png"></td> | |||
<td width="270" colspan="3"><img src="res/Fade-G2.png"></td> | |||
</tr><tr> | |||
<td width="180" colspan="2"><img src="res/Octave-G1.png"></td> | |||
<td width="270" colspan="3"><img src="res/Chord-G1.png"></td> | |||
<td width="90" colspan="1"><img src="res/Blank06.png"></td> | |||
<td width="450" colspan="5"><img src="res/Seq-G1.png"></td> | |||
</tr><tr> | |||
<td width="180" colspan="2"><img src="res/Binary-G1.png"></td> | |||
<td width="810" colspan="9"><img src="res/Seq-G2.png"></td> | |||
</tr><tr> | |||
<td width="90" colspan="1"><img src="res/VU-G1.png"></td> | |||
<td width="360" colspan="4"><img src="res/Scope-G1.png"></td> | |||
<td width="540" colspan="6"><img src="res/Keys-G1.png"></td> | |||
</tr><tr> | |||
<td width="90"> </td><td width="90"> </td><td width="90"> </td><td width="90"> </td> | |||
<td width="90"> </td><td width="90"> </td><td width="90"> </td> | |||
<td width="90"> </td><td width="90"> </td><td width="90"> </td><td width="90"> </td> | |||
</tr> | |||
</table> | |||
<h2>Design Philosophy</h2> | |||
<p>When designing these modules I'm working along the following lines:</p> | |||
<ul> | |||
<li>It should look like and feel like a real Eurorack module.</li> | |||
<li>If possible generalize to six voice polyphony, even at the expense of lots of wires!</li> | |||
<li>Build on the work of others, especially if I can turn a monosynth into a polysynth.</li> | |||
<li>Learn some stuff along the way. (I'm starting with very little music, synthesis and Eurorack knowledge.)</li> | |||
<li>Try out daft things and have some fun...</li> | |||
</ul> | |||
<h2>Inputs and Outputs</h2> | |||
<p>Polyphonic inputs and outputs are arranged in a circle. There wasn't a particularity strong reason to do | |||
thus other than I felt it looks like a socket for a six prong plug and I quite like it. Port number one | |||
is at 12 o'clock and then they count up in a clockwise fashion.</p> | |||
<p>In a lot of cases the inputs have an additional seventh port in the centre. Should an outer input not be | |||
connected, then it will inherit the center input (if it's connected). In other words, it's just a time-saving | |||
fanout option resulting in less wiring should you want all inputs to work in the same way.</p> | |||
<h2>Modules</h2> | |||
<p>I would like to mention that in a lot of these modules I have simply duplicated the work of others to | |||
create a poly module out of a mono module.</p> | |||
<ul> | |||
<li>A module ending with <tt>-C</tt> is based heavily on a <i>VCV Rack Core</i> module.</li> | |||
<li>A module ending with <tt>-F</tt> is based heavily on a <i>VCV Rack Fundamental</i> module.</li> | |||
<li>Modules ending with <tt>-G</tt> vary on how much they use the work of others. Sometimes they may be a modification | |||
of something else, or, it may be entirely original design on my part.</li> | |||
</ul> | |||
<h4>Oscillators and Filters</h4> | |||
<div class="wrapper"> | |||
<div class="box a"> | |||
<img height="190px" src="res/VCO-F1.png"> | |||
<img height="190px" src="res/VCO-F2.png"> | |||
<img height="190px" src="res/VCF-F1.png"> | |||
</div> | |||
<div class="box b"> | |||
<ul> | |||
<li><tt>VCO-F1</tt> is a six voice straight clone of <i>Fundamental VCO-1</i>.</li> | |||
<li><tt>VCO-F2</tt> is a six voice straight clone of <i>Fundamental VCO-2</i>.</li> | |||
<li><tt>VCF-F1</tt> is a six voice straight clone of <i>Fundamental VCF</i>.</li> | |||
</div> | |||
</div> | |||
<h4>Amplifiers and Envelopes</h4> | |||
<div class="wrapper"> | |||
<div class="box a"> | |||
<img height="190px" src="res/VCA-F1.png"> | |||
<img height="190px" src="res/Env-F1.png"> | |||
</div> | |||
<div class="box b"> | |||
<ul> | |||
<li><tt>VCA-F1</tt> is a six voice straight clone of the <i>Fundamental VCA</i> with a basic mixer to combine | |||
the voices to single outputs.</li> | |||
<li><tt>ENV-F1</tt> is a six voice straight clone of the <i>Fundamental ADSR</i> with an additional inverted | |||
output.</li> | |||
</div> | |||
</div> | |||
<h4>Faders and Logic</h4> | |||
<div class="wrapper"> | |||
<div class="box a"> | |||
<img height="190px" src="res/Fade-G1.png"> | |||
<img height="190px" src="res/Fade-G2.png"> | |||
<img height="190px" src="res/Binary-G1.png"> | |||
</div> | |||
<div class="box b"> | |||
<ul> | |||
<li><tt>FADE-G1</tt> is a two input six voice one-dimensional fader.</li> | |||
<li><tt>FADE-G2</tt> is a four input six voice two-dimensional fader.</li> | |||
<li><tt>BINARY-G1</tt> is a configurable binary logic gate. <span class="soon">Coming soon!</span></li> | |||
</li> | |||
</div> | |||
</div> | |||
<h4>Sequencers</h4> | |||
<div class="wrapper"> | |||
<div class="box a"> | |||
<img height="190px" src="res/Seq-G1.png"> | |||
<img height="190px" src="res/Seq-G2.png"> | |||
</div> | |||
<div class="box b"> | |||
<ul> | |||
<li><tt>SEQ-G1</tt> is a sequencer. <span class="soon">Coming soon!</span></li> | |||
<li><tt>SEQ-G2</tt> is a sequencer. <span class="soon">Coming soon!</span></li> | |||
</li> | |||
</div> | |||
</div> | |||
<h4>Generators</h4> | |||
<div class="wrapper"> | |||
<div class="box a"> | |||
<img height="190px" src="res/Octave-G1.png" > | |||
<img height="190px" src="res/Chord-G1.png"> | |||
</div> | |||
<div class="box b"> | |||
<ul> | |||
<li><tt>OCTAVE</tt> quantises the input to 12-ET and provides an octaves-worth of output with the input value | |||
used as the fundamental. Additionally, several whole-octave transpositions of the input are also provided at output. | |||
<br><i>TODO: I am probably going to redesign this.</i></li> | |||
<li><tt>CHORD-G1</tt> genearates chords via a CV program selection and a fundamental bass note V/octave input. | |||
Upto 12 different chords can be programmed, each with up to six voices.</li> | |||
</div> | |||
</div> | |||
<h4>Interfaces</h4> | |||
<div class="wrapper"> | |||
<div class="box a"> | |||
<img height="190px" src="res/MIDI-C1.png" > | |||
<img height="190px" src="res/MIDI-G1.png" > | |||
</div> | |||
<div class="box b"> | |||
<ul> | |||
<li><tt>MIDI-C1</tt> is a six voice straight clone of the <i>Core Quad MIDI-to-CV Interface</i>.</li> | |||
<li><tt>MIDI-G1</tt> is a simplified version <i>MIDI-C1</i> for those tight on rack space.</li> | |||
</div> | |||
</div> | |||
<!-- | |||
<h4>Utilities</h4> | |||
<div class="wrapper"> | |||
<div class="box a"> | |||
<img height="190px" src="res/Mux.png" > | |||
</div> | |||
<div class="box b"> | |||
<ul> | |||
<li><tt>...</tt> is a ...</li> | |||
</div> | |||
</div> | |||
--> | |||
<h4>Diagnostics</h4> | |||
<div class="wrapper"> | |||
<div class="box a"> | |||
<img height="190px" src="res/VU-G1.png" > | |||
<img height="190px" src="res/Scope-G1.png" > | |||
<img height="190px" src="res/Keys-G1.png" > | |||
</div> | |||
<div class="box b"> | |||
<ul> | |||
<li><tt>VU-G1</tt> is a simple six input volume monitoring module.</li> | |||
<li><tt>SCOPE-G1</tt> is based on the <i>Fundamental Scope</i> module.</li> | |||
<li><tt>KEYS-G1</tt> is a six input times six voice note monitoring module.</li> | |||
</div> | |||
</div> | |||
<h4>Blanks</h4> | |||
<div class="wrapper"> | |||
<div class="box a"> | |||
<img height="190px" src="res/Blank03.png"> | |||
<img height="190px" src="res/Blank06.png"> | |||
<img height="190px" src="res/Blank09.png"> | |||
<img height="190px" src="res/Blank12.png"> | |||
</div> | |||
<div class="box b"> | |||
<ul> | |||
<li>Simple do nothing 3-hole high quality blank.</li> | |||
<li>Simple do nothing 6-hole high quality blank.</li> | |||
<li>Simple do nothing 9-hole high quality blank.</li> | |||
<li>Simple do nothing 12-hole high quality blank.</li> | |||
</div> | |||
</div> | |||
<h2>Download</h2> | |||
<p>Current release is 0.5.0 and requires VCV Rack 0.5.x:</p> | |||
<ul> | |||
<li>Mac: <a href="downloads/Gratrix-0.5.0-mac.zip">Gratrix-0.5.0-mac.zip</a> [670,913 bytes]</li> | |||
<li>Windows: <a href="downloads/Gratrix-0.5.0-win.zip">Gratrix-0.5.0-win.zip</a> [3,844,673 bytes]</li> | |||
</ul> | |||
<p>I hope to add a build for Linux soon. Older releases can be found <a href="downloads">here</a>. | |||
<h2>Source</h2> | |||
<p>The source code is avaliable on <a href="https://github.com/gratrix/vcv-gratrix">GitHub</a>.</p> | |||
</div> | |||
<hr> | |||
<p>© Sam Gratrix, <a href="http://gratrix.net">Gratrix.net</a>.</p> | |||
</body> | |||
</html> |
@@ -152,6 +152,6 @@ VoltMeterWidget::VoltMeterWidget(VoltMeter *module) : ModuleWidget(module) { | |||
using namespace rack_plugin_ML_modules; | |||
RACK_PLUGIN_MODEL_INIT(ML_modules, VoltMeter) { | |||
Model *modelVoltMeter = Model::create<VoltMeter, VoltMeterWidget>("ML modules", "VoltMeter", "Volt Meter", UTILITY_TAG); | |||
Model *modelVoltMeter = Model::create<VoltMeter, VoltMeterWidget>("ML modules", "VoltMeter", "Volt Meter", VISUAL_TAG, UTILITY_TAG); | |||
return modelVoltMeter; | |||
} |
@@ -0,0 +1,7 @@ | |||
Copyright (c) 2017 Rich Jones | |||
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. |
@@ -0,0 +1,19 @@ | |||
SLUG = RJModules | |||
VERSION = 0.6.0 | |||
# FLAGS will be passed to both the C and C++ compiler | |||
FLAGS += | |||
CFLAGS += | |||
CXXFLAGS += | |||
# Careful about linking to libraries, since you can't assume much about the user's environment and library search path. | |||
# Static libraries are fine. | |||
LDFLAGS += | |||
# Add .cpp and .c files to the build | |||
SOURCES += $(wildcard src/*.cpp) | |||
DISTRIBUTABLES += $(wildcard LICENSE*) res | |||
RACK_DIR ?= ../.. | |||
include $(RACK_DIR)/plugin.mk |
@@ -0,0 +1,215 @@ | |||
<img src="https://i.imgur.com/mksL6UX.png" width="100%"> | |||
# RJModules [](https://github.com/Miserlou/RJModules/releases) [](https://www.youtube.com/watch?v=qkEjmZZbGGo) | |||
Various DIY modules made by Rich Jones for use with [VCV Rack](https://github.com/VCVRack/Rack). So far, mostly simple utilities and effects, hopefully some more interesting ones soon! | |||
<!-- START doctoc generated TOC please keep comment here to allow auto update --> | |||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> | |||
- [Contents](#contents) | |||
- [Generators](#generators) | |||
- [Supersaw](#supersaw) | |||
- [Twin LFO](#twin-lfo) | |||
- [Noise](#noise) | |||
- [Range LFO](#range-lfo) | |||
- [FX](#fx) | |||
- [Bit Crusher](#bit-crusher) | |||
- [Filter Delay](#filter-delay) | |||
- [Sidechain](#sidechain) | |||
- [Widener](#widener) | |||
- [Stutter](#stutter) | |||
- [Filters](#filters) | |||
- [Filter](#filter) | |||
- [Filters](#filters-1) | |||
- [Notch](#notch) | |||
- [Numerical](#numerical) | |||
- [Integers](#integers) | |||
- [Floats](#floats) | |||
- [Randoms](#randoms) | |||
- [Mixers](#mixers) | |||
- [Left Right Mixer](#left-right-mixer) | |||
- [Mono](#mono) | |||
- [Volumes](#volumes) | |||
- [Panner](#panner) | |||
- [Panners](#panners) | |||
- [Live](#live) | |||
- [BPM](#bpm) | |||
- [Button](#button) | |||
- [Buttons](#buttons) | |||
- [Utilities](#utilities) | |||
- [Splitter](#splitter) | |||
- [Splitters](#splitters) | |||
- [Displays](#displays) | |||
- [Range](#range) | |||
- [Future Plans](#future-plans) | |||
- [Building](#building) | |||
- [Related Projects](#related-projects) | |||
- [License](#license) | |||
<!-- END doctoc generated TOC please keep comment here to allow auto update --> | |||
## Contents | |||
### Generators | |||
#### Supersaw | |||
<img src='https://i.imgur.com/ACIUKI0.png' width="25%" /> | |||
It's a supersaw! Frequency, detune and mix are all voltage controlled, and there's switches for phase, inversion and 2/3 OSC. There's also a reset button. | |||
#### Twin LFO | |||
<img src="https://i.imgur.com/dsEUqse.png" width="50%" /> | |||
Two oscillators, one output! This thing generates crazy wubs - it's super fun! The first LFO is the "main" LFO output, the second one controls the rate of the first. Set the first one higher than the second to get crazy wub effects. | |||
Also has a shape wheel for mixing the sin/saw shape, and has knobs for offset and inversion. All parameters are voltage controllable! | |||
#### Noise | |||
<img src="https://i.imgur.com/l9yj0jt.png" width="25%"> | |||
Noise generates pink and white noise! It also has an integreted high pass and low pass filter. Everything is voltage controlled, and there's a bonus volume knob. | |||
#### Range LFO | |||
<img src="https://i.imgur.com/wtTzimg.png" width="50%" /> | |||
Range LFO is an LFO which can be explictly mapped to a specific (controllable) range. Very handy! | |||
### FX | |||
#### Bit Crusher | |||
<img src='https://i.imgur.com/tjKYMUn.png' width="50%" /> | |||
It's a bit crusher! Accepts control voltage, and sets a (voltage controlled) minimum bit depth for fine tuning. | |||
#### Filter Delay | |||
<img src="https://i.imgur.com/9CPtg6R.png" width="25%" /> | |||
A modification of the basic delay that filters each feedbacking pass. Kind of reggaeish, good for pads too. | |||
#### Sidechain | |||
<img src="https://i.imgur.com/3bQONmT.png" width="25%"> | |||
Based on a trigger signal, lower the volume of the input/output signal. CV controllable decay and ratio. Use a kick or a button to make some awesome wooshy noises or hard-knocking beats! I think there's a bug in this module but it works pretty good for me anyway. | |||
#### Widener | |||
<img src="https://i.imgur.com/KL50fgV.png" width="25%" /> | |||
Widener is a CV-controlled Haas-effect stereo widener with integrated high pass/low pass filter and a mix knob. Really useful for adding motion to a lead or for making drums rumble! | |||
#### Stutter | |||
<img src="https://i.imgur.com/oHHdCHF.png" width="25%" /> | |||
It's a digital glitch effect! Use the main on/off button (and related input) to turn the looper on and off, then use the time knob (controllable with CV) to adjust the size of the stutter. Also has a mix knob. | |||
### Filters | |||
#### Filter | |||
<img src="https://i.imgur.com/xv2GyWO.png" width="25%"> | |||
Filter is a voltage-controlled integrated high-pass and low-pass filter. Also includes a voltage-controlled res and mix paramater knobs. It's a really good VCF. | |||
#### Filters | |||
<img src="https://i.imgur.com/ApBCVaC.png" width="25%"> | |||
Filters is like Volumes or Panners, but for Filters. Each knob controls both a low pass and high pass filter. Super handy! | |||
#### Notch | |||
<img src="https://i.imgur.com/AzhKPZ1.png" width="25%"> | |||
Notch is a notch filter! You can play with the frequency, depth and width. All voltage controlled. | |||
### Numerical | |||
#### Integers | |||
<img src='https://i.imgur.com/NRQjpmZ.png' width="25%" /> | |||
It generates three (voltage controlled) integers from -12 to +12! | |||
#### Floats | |||
<img src='https://i.imgur.com/spQgKmr.png' width="25%" /> | |||
It generates three (voltage controlled) floats from -12 to +12! | |||
#### Randoms | |||
<img src='https://i.imgur.com/CuM471K.png' width="50%" /> | |||
Generates three random values. The range of the values can be controlled via CV, but will default to (-12, +12) if CV values are empty/equal. | |||
### Mixers | |||
#### Left Right Mixer | |||
<img src="https://i.imgur.com/UOidGVr.png" width="25%" /> | |||
A simple 12-to-2 mixer for mixing multiple stereo signals. With an additional overall voume knob. | |||
#### Mono | |||
<img src="https://i.imgur.com/tmSFepy.png" width="25%" /> | |||
A voltage-controlled mono-izer. Given a wide dual input signal, convert to mono outputs based on a knob and CV. Has two outputs, but only one is need if you're just going to 100% mono. | |||
#### Volumes | |||
<img src="https://i.imgur.com/KqWUEvB.png" width="25%" /> | |||
A modification of 'Mutes' that adds the ability to adjust the volume of 10 different input-output pairs. Can be used to quiet and amplify. | |||
#### Panner | |||
<img src="https://i.imgur.com/4z5li8u.png" width="25%" /> | |||
Panner is a voltage controlled panner. Without CV, it pans a mono signal into left and right channels based on the value of the knob. Combine with an LFO to build an autopanner! | |||
#### Panners | |||
<img src="https://i.imgur.com/Z53pj0S.png" width="25%" /> | |||
Panners is a bank of 5 panners. Each takes a stereo input and a stereo output. Pretty simple but handy for placing lots of elements around a stereo space. | |||
### Live | |||
#### BPM | |||
<img src='https://i.imgur.com/A5MbJJq.png' width="25%"> | |||
BPM lets you set a voltage-controllable beats per minute, with an array of outputs that get a +12 signal. There is also a CV reset with a connected button. | |||
You can get some weird polyrhythmic stuff by putting an LFO on the CV, which gives a variable BPM. Even weirder if you start using a bunch! | |||
#### Button | |||
<img src='https://i.imgur.com/msNcs07.png' width="25%" /> | |||
It's literally just a big ass button with six outputs. You hit it, it sends a +12 reset signal. | |||
#### Buttons | |||
<img src='https://i.imgur.com/A3SD0WT.png' width="25%" /> | |||
It's not one big button - it's lot of little butons! | |||
They're arranged a drum pad, so it's fun and easy to make a playable drum pad simulator by building a circuit like this: | |||
<img src='https://i.imgur.com/qdBbvFD.jpg' width="100%" /> | |||
### Utilities | |||
#### Splitter | |||
<img src="https://i.imgur.com/bvJKVEn.png" width="25%" /> | |||
It's a 1 to 9-way splitter! You've got a signal - now send it everywhere! | |||
#### Splitters | |||
<img src="https://i.imgur.com/NVWwfnZ.png" width="25%" /> | |||
If splitting one signal to many isn't your fancy, Splitters gives you a 5:10 splitter instead! Handy! | |||
#### Displays | |||
<img src="https://i.imgur.com/JVVs2fg.png" width="25%"> | |||
Three digital displays. Useful for debugging. Provides a passthrough output as well. | |||
#### Range | |||
<img src="https://i.imgur.com/3EgRCQ6.png" width="50%" /> | |||
Range will map an input from one range of values to another. So, if you have an oscillator which outputs from 0/2, you can map it to a -5/5 audio signal or a -10/10 CV. Handy! | |||
## Future Plans | |||
None of them actually exist yet, but I'm hoping this will project eventually contain: | |||
* FFTTuner - FFT / Tuner | |||
* VCDryWet - A simple dry/wet mixer | |||
* DubEcho - Two delays and a spring. | |||
* Ping Pong Delay (or maybe just a delay with seperate dry/wet outs that can feed to the panner?) | |||
* Vocoder, maybe? | |||
* Dedicated 808/kick circuit with click | |||
* Reverb - It's a reverb! | |||
* Phaser - Pssshheeeeeooooooowwwwwwoooowowwaaaaaahhhhhh | |||
* Harmonic Saturator | |||
* Ring Modulator | |||
* Granulator | |||
## Building | |||
First, clone and [make Rack for yourself](https://github.com/VCVRack/Rack#building). | |||
Then, clone this repo into the `plugins` directory and run `make` from this directory. | |||
## Related Projects | |||
* [Autopan](https://github.com/Miserlou/Autopan) | |||
## License | |||
(c) Rich Jones 2017, BSD. |
@@ -0,0 +1,33 @@ | |||
ALL_OBJ= \ | |||
src/BigButton.o \ | |||
src/BitCrush.o \ | |||
src/BPM.o \ | |||
src/Buttons.o \ | |||
src/common.o \ | |||
src/Displays.o \ | |||
src/DSPUtilities.o \ | |||
src/FFTuner.o \ | |||
src/Filter.o \ | |||
src/FilterDelay.o \ | |||
src/Filters.o \ | |||
src/Floats.o \ | |||
src/Integers.o \ | |||
src/LRMixer.o \ | |||
src/Mono.o \ | |||
src/Noise.o \ | |||
src/Notch.o \ | |||
src/Panner.o \ | |||
src/Panners.o \ | |||
src/Randoms.o \ | |||
src/Range.o \ | |||
src/RangeLFO.o \ | |||
src/RJModules.o \ | |||
src/Sidechain.o \ | |||
src/Splitter.o \ | |||
src/Splitters.o \ | |||
src/Stutter.o \ | |||
src/Supersaw.o \ | |||
src/TwinLFO.o \ | |||
src/VAStateVariableFilter.o \ | |||
src/Volumes.o \ | |||
src/Widener.o |
@@ -0,0 +1,7 @@ | |||
SLUG=RJModules | |||
include ../../../../dep/yac/install_msvc.mk | |||
include make.objects | |||
include ../../../build_plugin.mk |
@@ -0,0 +1,519 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<!-- Created with Inkscape (http://www.inkscape.org/) --> | |||
<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" | |||
width="150.22649" | |||
height="379.99997" | |||
viewBox="0 0 39.747425 100.54168" | |||
version="1.1" | |||
id="svg4541" | |||
sodipodi:docname="BPM.svg" | |||
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"> | |||
<defs | |||
id="defs4535" /> | |||
<sodipodi:namedview | |||
id="base" | |||
pagecolor="#ffffff" | |||
bordercolor="#666666" | |||
borderopacity="1.0" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:zoom="1.4" | |||
inkscape:cx="159.17899" | |||
inkscape:cy="181.61002" | |||
inkscape:document-units="mm" | |||
inkscape:current-layer="layer3" | |||
showgrid="false" | |||
fit-margin-top="0" | |||
fit-margin-left="0" | |||
fit-margin-right="0" | |||
fit-margin-bottom="0" | |||
inkscape:window-width="1440" | |||
inkscape:window-height="851" | |||
inkscape:window-x="178" | |||
inkscape:window-y="23" | |||
inkscape:window-maximized="0" | |||
units="px" /> | |||
<metadata | |||
id="metadata4538"> | |||
<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 /> | |||
</cc:Work> | |||
</rdf:RDF> | |||
</metadata> | |||
<g | |||
inkscape:groupmode="layer" | |||
id="layer3" | |||
inkscape:label="Layer 0"> | |||
<g | |||
transform="matrix(0.27602378,0,0,0.27602378,359.65593,-41.231947)" | |||
id="g13122" | |||
style="stroke-width:0.9585526"> | |||
<g | |||
transform="translate(-167.07644,-20.557569)" | |||
id="g13178" | |||
style="stroke-width:0.91882312"> | |||
<g | |||
transform="translate(-99.2314,6.0949065)" | |||
id="g13224" | |||
style="stroke-width:0.88074034"> | |||
<g | |||
transform="translate(-315.65411,137.78158)" | |||
id="g13271" | |||
style="stroke-width:0.84423596"> | |||
<g | |||
transform="translate(-332.2261,26.059316)" | |||
id="g13383" | |||
style="stroke-width:0.80924457"> | |||
<path | |||
style="fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80924457" | |||
d="m -388.5352,0.265625 h 143.46875 V 363.98828 H -388.5352 Z m 0,0" | |||
id="path25069" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path12226" | |||
d="m -276.57518,211.05859 c 1.40625,0 2.4375,-1.0625 2.4375,-2.35937 0,-1.29688 -1.01562,-2.34375 -2.42187,-2.34375 -1.40625,0 -2.42188,1.0625 -2.42188,2.34375 v 0.0156 c 0,1.29688 1.01563,2.34375 2.40625,2.34375 z m 0.0156,-0.92187 c -0.79688,0 -1.375,-0.65625 -1.375,-1.4375 0,-0.78125 0.5625,-1.42188 1.35937,-1.42188 0.8125,0 1.39063,0.64063 1.39063,1.42188 v 0.0156 c 0,0.78125 -0.5625,1.42188 -1.375,1.42188 z m 0,0" | |||
style="fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:0.80924457" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path12222" | |||
d="m -271.14238,211.05859 c 1.23438,0 2,-0.6875 2,-2.0625 v -2.10937 c 0,-0.28125 -0.21875,-0.5 -0.5,-0.5 -0.28125,0 -0.5,0.21875 -0.5,0.5 v 2.15625 c 0,0.71875 -0.375,1.09375 -0.98437,1.09375 -0.60938,0 -0.98438,-0.39063 -0.98438,-1.125 v -2.125 c 0,-0.28125 -0.21875,-0.5 -0.5,-0.5 -0.26562,0 -0.5,0.21875 -0.5,0.5 v 2.14062 c 0,1.34375 0.75,2.03125 1.96875,2.03125 z m 0,0" | |||
style="fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:0.80924457" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path12218" | |||
d="m -266.8745,210.51172 c 0,0.28125 0.21875,0.5 0.5,0.5 0.28125,0 0.5,-0.21875 0.5,-0.5 v -3.15625 h 0.95313 c 0.26562,0 0.46875,-0.20313 0.46875,-0.46875 0,-0.25 -0.20313,-0.45313 -0.46875,-0.45313 h -2.92188 c -0.25,0 -0.45312,0.20313 -0.45312,0.45313 0,0.26562 0.20312,0.46875 0.45312,0.46875 h 0.96875 z m 0,0" | |||
style="fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:0.80924457" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path12214" | |||
d="m -276.57518,288.43838 c 1.40625,0 2.4375,-1.0625 2.4375,-2.35937 0,-1.29688 -1.01562,-2.34375 -2.42187,-2.34375 -1.40625,0 -2.42188,1.0625 -2.42188,2.34375 v 0.0156 c 0,1.29688 1.01563,2.34375 2.40625,2.34375 z m 0.0156,-0.92187 c -0.79688,0 -1.375,-0.65625 -1.375,-1.4375 0,-0.78125 0.5625,-1.42188 1.35937,-1.42188 0.8125,0 1.39063,0.64063 1.39063,1.42188 v 0.0156 c 0,0.78125 -0.5625,1.42188 -1.375,1.42188 z m 0,0" | |||
style="fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:0.80924457" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path12210" | |||
d="m -271.14238,288.43838 c 1.23438,0 2,-0.6875 2,-2.0625 v -2.10937 c 0,-0.28125 -0.21875,-0.5 -0.5,-0.5 -0.28125,0 -0.5,0.21875 -0.5,0.5 v 2.15625 c 0,0.71875 -0.375,1.09375 -0.98437,1.09375 -0.60938,0 -0.98438,-0.39063 -0.98438,-1.125 v -2.125 c 0,-0.28125 -0.21875,-0.5 -0.5,-0.5 -0.26562,0 -0.5,0.21875 -0.5,0.5 v 2.14062 c 0,1.34375 0.75,2.03125 1.96875,2.03125 z m 0,0" | |||
style="fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:0.80924457" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path12206" | |||
d="m -266.8745,287.89151 c 0,0.28125 0.21875,0.5 0.5,0.5 0.28125,0 0.5,-0.21875 0.5,-0.5 v -3.15625 h 0.95313 c 0.26562,0 0.46875,-0.20313 0.46875,-0.46875 0,-0.25 -0.20313,-0.45313 -0.46875,-0.45313 h -2.92188 c -0.25,0 -0.45312,0.20313 -0.45312,0.45313 0,0.26562 0.20312,0.46875 0.45312,0.46875 h 0.96875 z m 0,0" | |||
style="fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:0.80924457" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path12202" | |||
d="m -276.57518,61.623993 c 1.40625,0 2.4375,-1.0625 2.4375,-2.359375 0,-1.296875 -1.01562,-2.34375 -2.42187,-2.34375 -1.40625,0 -2.42188,1.0625 -2.42188,2.34375 v 0.01563 c 0,1.296875 1.01563,2.34375 2.40625,2.34375 z m 0.0156,-0.921875 c -0.79688,0 -1.375,-0.65625 -1.375,-1.4375 0,-0.78125 0.5625,-1.421875 1.35937,-1.421875 0.8125,0 1.39063,0.640625 1.39063,1.421875 v 0.01563 c 0,0.78125 -0.5625,1.421875 -1.375,1.421875 z m 0,0" | |||
style="fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:0.80924457" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path12198" | |||
d="m -271.14238,61.623993 c 1.23438,0 2,-0.6875 2,-2.0625 v -2.109375 c 0,-0.28125 -0.21875,-0.5 -0.5,-0.5 -0.28125,0 -0.5,0.21875 -0.5,0.5 v 2.15625 c 0,0.71875 -0.375,1.09375 -0.98437,1.09375 -0.60938,0 -0.98438,-0.390625 -0.98438,-1.125 v -2.125 c 0,-0.28125 -0.21875,-0.5 -0.5,-0.5 -0.26562,0 -0.5,0.21875 -0.5,0.5 v 2.140625 c 0,1.34375 0.75,2.03125 1.96875,2.03125 z m 0,0" | |||
style="fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:0.80924457" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path12194" | |||
d="m -266.8745,61.077118 c 0,0.28125 0.21875,0.5 0.5,0.5 0.28125,0 0.5,-0.21875 0.5,-0.5 v -3.15625 h 0.95313 c 0.26562,0 0.46875,-0.203125 0.46875,-0.46875 0,-0.25 -0.20313,-0.453125 -0.46875,-0.453125 h -2.92188 c -0.25,0 -0.45312,0.203125 -0.45312,0.453125 0,0.265625 0.20312,0.46875 0.45312,0.46875 h 0.96875 z m 0,0" | |||
style="fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:0.80924457" /> | |||
<g | |||
aria-label="IN" | |||
transform="scale(1,-1)" | |||
style="font-style:normal;font-weight:normal;font-size:10.8135519px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21877021" | |||
id="text202" /> | |||
<g | |||
aria-label="CV" | |||
style="font-style:normal;font-weight:normal;font-size:10.81355095px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21877019" | |||
id="text202-7" /> | |||
<g | |||
aria-label="OUT" | |||
style="font-style:normal;font-weight:normal;font-size:10.81355px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.21877018" | |||
id="text202-7-8" /> | |||
<g | |||
aria-label="RJModules" | |||
style="font-style:normal;font-weight:normal;font-size:10.81355px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21877018" | |||
id="text202-7-7" | |||
transform="translate(0,-1.9171053)"> | |||
<path | |||
d="m -337.92427,346.5215 h 0.93428 q 0.43492,0 0.69264,-0.11276 0.25774,-0.12886 0.38661,-0.35439 0.14494,-0.22551 0.19329,-0.54767 0.0483,-0.33828 0.0483,-0.77319 0,-0.43493 -0.0483,-0.75709 -0.0483,-0.33826 -0.20941,-0.56378 -0.14494,-0.24163 -0.41881,-0.35438 -0.27384,-0.11276 -0.72487,-0.11276 h -0.85373 z m -1.64303,-5.12239 h 2.64173 q 2.89947,0 2.89947,3.3666 0,0.9987 -0.32216,1.72357 -0.30604,0.70876 -1.09535,1.14369 l 1.77189,5.23514 h -1.73967 l -1.53028,-4.89687 h -0.9826 v 4.89687 h -1.64303 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';stroke-width:0.32588577" | |||
id="path79" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
d="m -328.89112,350.16194 q 0,0.56379 -0.19329,1.07925 -0.1933,0.49935 -0.5638,0.88595 -0.35436,0.38659 -0.86983,0.61211 -0.51546,0.22551 -1.1759,0.22551 -0.78929,0 -1.32087,-0.33826 -0.51545,-0.35439 -0.82151,-0.69267 l 1.28866,-1.03091 q 0.17718,0.17719 0.40269,0.30605 0.24163,0.11276 0.49935,0.11276 0.14494,0 0.33828,-0.0483 0.1933,-0.0645 0.35438,-0.20941 0.17719,-0.16108 0.28994,-0.41881 0.12886,-0.27384 0.12886,-0.70877 v -8.53731 h 1.64303 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';stroke-width:0.32588577" | |||
id="path81" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
d="m -327.32887,341.39911 h 1.57858 l 2.11018,6.07277 h 0.0322 l 2.09406,-6.07277 h 1.5947 v 11.469 h -1.64302 v -6.97483 h -0.0322 l -1.62693,4.9291 h -0.82151 l -1.61081,-4.9291 h -0.0322 v 6.97483 h -1.64303 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';stroke-width:0.32588577" | |||
id="path83" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
d="m -318.60406,347.43966 q 0,-0.49935 0.0645,-0.91816 0.0645,-0.41881 0.24162,-0.74097 0.28995,-0.53157 0.83763,-0.85373 0.54768,-0.32216 1.30475,-0.32216 0.75709,0 1.30476,0.32216 0.54768,0.32216 0.83763,0.85373 0.17719,0.32216 0.24162,0.74097 0.0645,0.41881 0.0645,0.91816 v 2.69007 q 0,0.49936 -0.0645,0.91816 -0.0645,0.41881 -0.24162,0.74097 -0.28995,0.53158 -0.83763,0.85374 -0.54767,0.32216 -1.30476,0.32216 -0.75707,0 -1.30475,-0.32216 -0.54768,-0.32216 -0.83763,-0.85374 -0.17719,-0.32216 -0.24162,-0.74097 -0.0645,-0.4188 -0.0645,-0.91816 z m 1.64304,2.94779 q 0,0.46715 0.2094,0.70877 0.22551,0.22551 0.596,0.22551 0.3705,0 0.5799,-0.22551 0.22551,-0.24162 0.22551,-0.70877 v -3.20551 q 0,-0.46714 -0.22551,-0.69266 -0.2094,-0.24162 -0.5799,-0.24162 -0.37049,0 -0.596,0.24162 -0.2094,0.22552 -0.2094,0.69266 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';stroke-width:0.32588577" | |||
id="path85" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
d="m -310.86988,350.21026 q 0,0.49936 0.1933,0.80541 0.19329,0.30606 0.61211,0.30606 0.37049,0 0.596,-0.27384 0.22552,-0.28994 0.22552,-0.74097 v -3.1733 q 0,-0.3866 -0.24163,-0.62822 -0.22552,-0.25774 -0.57989,-0.25774 -0.46714,0 -0.64433,0.28996 -0.16108,0.28994 -0.16108,0.67653 z m 1.62693,1.91688 q -0.16109,0.17719 -0.30606,0.33827 -0.14494,0.14494 -0.32216,0.25773 -0.17719,0.11277 -0.40271,0.17719 -0.22551,0.0644 -0.53157,0.0644 -1.01481,0 -1.43362,-0.77319 -0.14494,-0.27384 -0.20941,-0.67655 -0.0645,-0.4027 -0.0645,-1.07925 v -3.10886 q 0,-0.88596 0.0483,-1.30477 0.0483,-0.4188 0.2094,-0.67654 0.20941,-0.32216 0.53157,-0.53156 0.33828,-0.20941 0.93428,-0.20941 0.48324,0 0.85372,0.22552 0.38661,0.20941 0.66044,0.6121 h 0.0322 v -4.04315 h 1.64303 v 11.46901 h -1.64303 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';stroke-width:0.32588577" | |||
id="path87" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
d="m -301.33914,352.86811 h -1.64303 v -0.78929 h -0.0322 q -0.25772,0.38659 -0.62822,0.64432 -0.35437,0.24162 -0.91816,0.24162 -0.30604,0 -0.6121,-0.0967 -0.30606,-0.11276 -0.54768,-0.35438 -0.24163,-0.24162 -0.3866,-0.6121 -0.14494,-0.3866 -0.14494,-0.93428 v -6.26607 h 1.64303 v 5.65397 q 0,0.45103 0.20941,0.70875 0.2094,0.25773 0.596,0.25773 0.46713,0 0.64432,-0.28994 0.17719,-0.28995 0.17719,-0.83763 v -5.49288 h 1.64303 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';stroke-width:0.32588577" | |||
id="path89" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
d="m -300.08799,341.39911 h 1.64302 v 9.16553 q 0,0.46715 0.16109,0.64433 0.17719,0.16109 0.64433,0.20941 v 1.54638 q -0.56378,0 -1.03093,-0.0967 -0.45103,-0.0806 -0.77319,-0.32216 -0.30604,-0.25773 -0.48323,-0.70876 -0.16109,-0.45103 -0.16109,-1.15978 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';stroke-width:0.32588577" | |||
id="path91" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
d="m -295.50447,349.40487 v 1.11145 q 0,0.3866 0.20941,0.596 0.22551,0.20941 0.596,0.20941 0.46713,0 0.61212,-0.27384 0.16107,-0.27383 0.19329,-0.54767 h 1.64303 q 0,0.51545 -0.17719,0.96648 -0.16108,0.45103 -0.48325,0.77319 -0.32217,0.33828 -0.77319,0.53158 -0.45103,0.19329 -1.01481,0.19329 -0.75709,0 -1.30477,-0.32216 -0.54767,-0.32216 -0.83761,-0.85374 -0.17719,-0.32216 -0.24162,-0.74097 -0.0645,-0.4188 -0.0645,-0.91816 v -2.69007 q 0,-0.49935 0.0645,-0.91816 0.0645,-0.41881 0.24162,-0.74097 0.28994,-0.53157 0.83761,-0.85373 0.54768,-0.32216 1.30477,-0.32216 0.56378,0 1.01481,0.19329 0.46714,0.19329 0.77319,0.54768 0.32217,0.33827 0.48325,0.80541 0.17719,0.46713 0.17719,0.9987 v 2.25515 z m 0,-1.28866 h 1.61082 v -0.93427 q 0,-0.46714 -0.22552,-0.69266 -0.20941,-0.24162 -0.57989,-0.24162 -0.37049,0 -0.596,0.24162 -0.20941,0.22552 -0.20941,0.69266 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';stroke-width:0.32588577" | |||
id="path93" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
d="m -288.07635,346.98863 q -0.0161,-0.41881 -0.27384,-0.6282 -0.24161,-0.20941 -0.56377,-0.20941 -0.38661,0 -0.596,0.25773 -0.20942,0.24162 -0.20942,0.56378 0,0.22551 0.11277,0.45103 0.11276,0.20941 0.5799,0.3866 l 0.96649,0.38659 q 0.91817,0.35438 1.25643,0.96648 0.35438,0.61212 0.35438,1.33699 0,0.51545 -0.19329,0.96648 -0.17719,0.43493 -0.49935,0.77319 -0.32217,0.33828 -0.7732,0.53158 -0.45102,0.19329 -0.9826,0.19329 -0.48325,0 -0.91816,-0.16107 -0.43492,-0.16109 -0.77319,-0.46715 -0.32216,-0.30604 -0.53157,-0.75707 -0.20941,-0.46715 -0.22552,-1.07925 h 1.54638 q 0.0483,0.33826 0.22552,0.62822 0.19329,0.28994 0.66044,0.28994 0.35438,0 0.62822,-0.22552 0.28994,-0.24161 0.28994,-0.66042 0,-0.33828 -0.17719,-0.5799 -0.17719,-0.24163 -0.64432,-0.41881 l -0.78931,-0.28995 q -0.77319,-0.28994 -1.22422,-0.85374 -0.43491,-0.57988 -0.43491,-1.40141 0,-0.51545 0.19329,-0.95036 0.1933,-0.45103 0.51546,-0.75709 0.33828,-0.32216 0.7732,-0.49935 0.43491,-0.17719 0.93427,-0.17719 0.49935,0 0.91816,0.19329 0.43492,0.17719 0.74098,0.49935 0.30605,0.30606 0.48324,0.75709 0.17719,0.43491 0.17719,0.93426 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';stroke-width:0.32588577" | |||
id="path95" | |||
inkscape:connector-curvature="0" /> | |||
</g> | |||
<flowRoot | |||
xml:space="preserve" | |||
id="flowRoot102" | |||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;" | |||
transform="matrix(0.95855264,0,0,0.95855264,-388.80083,-5.5855677e-7)"><flowRegion | |||
id="flowRegion104" | |||
style="fill:#000000;"><rect | |||
id="rect106" | |||
width="118.92857" | |||
height="41.42857" | |||
x="183.57143" | |||
y="98.214256" | |||
style="fill:#000000;" /></flowRegion><flowPara | |||
id="flowPara108">Cr</flowPara></flowRoot> <g | |||
aria-label="CRUSH" | |||
transform="matrix(0.95855264,0,0,0.95855264,-504.51183,-19.718797)" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none" | |||
id="flowRoot110" /> | |||
<g | |||
transform="translate(-0.52135579,79.911495)" | |||
aria-label="CV" | |||
style="font-style:normal;font-weight:normal;font-size:10.81355095px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21877019" | |||
id="text202-7-4" /> | |||
<g | |||
aria-label="FLOOR" | |||
transform="matrix(0.95855264,0,0,0.95855264,-504.74511,64.909859)" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.80924457" | |||
id="flowRoot110-9" /> | |||
<path | |||
style="fill:#ff0000;fill-opacity:0.205;stroke:#ff0000;stroke-width:0.95855265999999995px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.315" | |||
d="m -388.5352,363.98828 h 143.46875 l 0.73318,-96.27825 z" | |||
id="path905" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cccc" /> | |||
<flowRoot | |||
xml:space="preserve" | |||
id="flowRoot907" | |||
style="fill:black;fill-opacity:1;stroke:none;font-family:sans-serif;font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;letter-spacing:0px;word-spacing:0px"><flowRegion | |||
id="flowRegion909"><rect | |||
id="rect911" | |||
width="123.21429" | |||
height="41.07143" | |||
x="13.928572" | |||
y="7.8571124" /></flowRegion><flowPara | |||
id="flowPara913" /></flowRoot> <flowRoot | |||
xml:space="preserve" | |||
id="flowRoot915" | |||
style="fill:black;fill-opacity:1;stroke:none;font-family:sans-serif;font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;letter-spacing:0px;word-spacing:0px"><flowRegion | |||
id="flowRegion917"><rect | |||
id="rect919" | |||
width="131.42857" | |||
height="50.357143" | |||
x="10" | |||
y="9.2856836" /></flowRegion><flowPara | |||
id="flowPara921" /></flowRoot> <g | |||
aria-label="BUTTON" | |||
transform="matrix(0.95855264,0,0,0.95855264,-388.80083,11.502632)" | |||
style="font-style:normal;font-weight:normal;font-size:14.66666698px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none" | |||
id="flowRoot923" /> | |||
</g> | |||
</g> | |||
</g> | |||
</g> | |||
</g> | |||
<g | |||
id="g1199" /> | |||
<g | |||
id="g548" | |||
transform="translate(-22.678571,36.606994)"> | |||
<path | |||
sodipodi:nodetypes="sssssssss" | |||
style="fill:#212121;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.22337075" | |||
d="m 36.082576,19.407513 c 0,-0.430208 -0.352576,-0.781708 -0.782788,-0.781708 h -6.009984 c -0.43021,0 -0.782787,0.3515 -0.782787,0.781708 v 9.524976 c 0,0.430211 0.352577,0.781708 0.782787,0.781708 h 6.009984 c 0.430212,0 0.782788,-0.351497 0.782788,-0.781708 z" | |||
id="path25479-5" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="scccscccsscccscccssscscsscscss" | |||
id="path67-0" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 30.750669,19.679509 c 0,-0.08556 0.01492,-0.161178 0.04477,-0.226844 0.02985,-0.06567 0.06865,-0.119393 0.116409,-0.161179 0.04975,-0.04378 0.104467,-0.07661 0.164161,-0.0985 0.06169,-0.02189 0.123372,-0.03283 0.185057,-0.03283 0.06169,0 0.122378,0.01094 0.182073,0.03283 0.06169,0.02189 0.116409,0.05472 0.164166,0.0985 0.04975,0.04179 0.08954,0.09551 0.119391,0.161179 0.02985,0.06567 0.04477,0.141281 0.04477,0.226844 v 1.122283 c 0,0.08756 -0.01492,0.164165 -0.04477,0.229831 -0.02985,0.06367 -0.06964,0.117399 -0.119391,0.161178 -0.04776,0.04179 -0.102482,0.07362 -0.164166,0.09551 -0.05969,0.02189 -0.120384,0.03283 -0.182073,0.03283 -0.06169,0 -0.123372,-0.01094 -0.185057,-0.03283 -0.05969,-0.02189 -0.114414,-0.05372 -0.164161,-0.09551 -0.04776,-0.04378 -0.08656,-0.09751 -0.116409,-0.161178 -0.02985,-0.06567 -0.04477,-0.142277 -0.04477,-0.229831 z m 0.304448,1.122283 c 0,0.07362 0.0199,0.128346 0.0597,0.164165 0.04179,0.03383 0.09054,0.05074 0.146254,0.05074 0.05571,0 0.103471,-0.01691 0.143272,-0.05074 0.04179,-0.03582 0.06268,-0.09054 0.06268,-0.164165 v -1.122283 c 0,-0.07362 -0.02089,-0.127351 -0.06268,-0.161178 -0.0398,-0.03582 -0.08756,-0.05373 -0.143272,-0.05373 -0.05571,0 -0.104465,0.01791 -0.146254,0.05373 -0.0398,0.03383 -0.0597,0.08755 -0.0597,0.161178 z" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="scccscccsccscscsccs" | |||
id="path69-3" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 33.024432,20.82567 c 0,0.06965 -0.01293,0.134317 -0.0388,0.194012 -0.02587,0.0597 -0.06169,0.112432 -0.107455,0.158195 -0.04377,0.04378 -0.09551,0.0786 -0.155207,0.104466 -0.0597,0.02587 -0.123376,0.0388 -0.191027,0.0388 -0.06765,0 -0.131332,-0.01293 -0.191029,-0.0388 -0.05969,-0.02587 -0.112424,-0.06069 -0.158192,-0.104466 -0.04378,-0.04577 -0.0786,-0.0985 -0.10447,-0.158195 -0.02587,-0.05969 -0.0388,-0.124364 -0.0388,-0.194012 v -1.647608 h 0.304445 v 1.617762 c 0,0.07561 0.01791,0.13133 0.05373,0.167149 0.03582,0.03582 0.08059,0.05373 0.134315,0.05373 0.05373,0 0.0985,-0.01791 0.134316,-0.05373 0.03581,-0.03582 0.05372,-0.09154 0.05372,-0.167149 v -1.617762 h 0.304453 z" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="ccccccccc" | |||
id="path71-9" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 33.5103,19.464603 h -0.352208 v -0.286541 h 1.008861 v 0.286541 h -0.352205 v 1.838636 H 33.5103 Z" | |||
inkscape:connector-curvature="0" /> | |||
</g> | |||
<g | |||
id="g548-9" | |||
transform="translate(-11.884083,36.532967)"> | |||
<path | |||
sodipodi:nodetypes="sssssssss" | |||
style="fill:#212121;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.22337075" | |||
d="m 36.082576,19.407513 c 0,-0.430208 -0.352576,-0.781708 -0.782788,-0.781708 h -6.009984 c -0.43021,0 -0.782787,0.3515 -0.782787,0.781708 v 9.524976 c 0,0.430211 0.352577,0.781708 0.782787,0.781708 h 6.009984 c 0.430212,0 0.782788,-0.351497 0.782788,-0.781708 z" | |||
id="path25479-5-0" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="scccscccsscccscccssscscsscscss" | |||
id="path67-0-5" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 30.750669,19.679509 c 0,-0.08556 0.01492,-0.161178 0.04477,-0.226844 0.02985,-0.06567 0.06865,-0.119393 0.116409,-0.161179 0.04975,-0.04378 0.104467,-0.07661 0.164161,-0.0985 0.06169,-0.02189 0.123372,-0.03283 0.185057,-0.03283 0.06169,0 0.122378,0.01094 0.182073,0.03283 0.06169,0.02189 0.116409,0.05472 0.164166,0.0985 0.04975,0.04179 0.08954,0.09551 0.119391,0.161179 0.02985,0.06567 0.04477,0.141281 0.04477,0.226844 v 1.122283 c 0,0.08756 -0.01492,0.164165 -0.04477,0.229831 -0.02985,0.06367 -0.06964,0.117399 -0.119391,0.161178 -0.04776,0.04179 -0.102482,0.07362 -0.164166,0.09551 -0.05969,0.02189 -0.120384,0.03283 -0.182073,0.03283 -0.06169,0 -0.123372,-0.01094 -0.185057,-0.03283 -0.05969,-0.02189 -0.114414,-0.05372 -0.164161,-0.09551 -0.04776,-0.04378 -0.08656,-0.09751 -0.116409,-0.161178 -0.02985,-0.06567 -0.04477,-0.142277 -0.04477,-0.229831 z m 0.304448,1.122283 c 0,0.07362 0.0199,0.128346 0.0597,0.164165 0.04179,0.03383 0.09054,0.05074 0.146254,0.05074 0.05571,0 0.103471,-0.01691 0.143272,-0.05074 0.04179,-0.03582 0.06268,-0.09054 0.06268,-0.164165 v -1.122283 c 0,-0.07362 -0.02089,-0.127351 -0.06268,-0.161178 -0.0398,-0.03582 -0.08756,-0.05373 -0.143272,-0.05373 -0.05571,0 -0.104465,0.01791 -0.146254,0.05373 -0.0398,0.03383 -0.0597,0.08755 -0.0597,0.161178 z" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="scccscccsccscscsccs" | |||
id="path69-3-2" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 33.024432,20.82567 c 0,0.06965 -0.01293,0.134317 -0.0388,0.194012 -0.02587,0.0597 -0.06169,0.112432 -0.107455,0.158195 -0.04377,0.04378 -0.09551,0.0786 -0.155207,0.104466 -0.0597,0.02587 -0.123376,0.0388 -0.191027,0.0388 -0.06765,0 -0.131332,-0.01293 -0.191029,-0.0388 -0.05969,-0.02587 -0.112424,-0.06069 -0.158192,-0.104466 -0.04378,-0.04577 -0.0786,-0.0985 -0.10447,-0.158195 -0.02587,-0.05969 -0.0388,-0.124364 -0.0388,-0.194012 v -1.647608 h 0.304445 v 1.617762 c 0,0.07561 0.01791,0.13133 0.05373,0.167149 0.03582,0.03582 0.08059,0.05373 0.134315,0.05373 0.05373,0 0.0985,-0.01791 0.134316,-0.05373 0.03581,-0.03582 0.05372,-0.09154 0.05372,-0.167149 v -1.617762 h 0.304453 z" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="ccccccccc" | |||
id="path71-9-2" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 33.5103,19.464603 h -0.352208 v -0.286541 h 1.008861 v 0.286541 h -0.352205 v 1.838636 H 33.5103 Z" | |||
inkscape:connector-curvature="0" /> | |||
</g> | |||
<g | |||
id="g548-7" | |||
transform="translate(-1.3382038,36.424781)"> | |||
<path | |||
sodipodi:nodetypes="sssssssss" | |||
style="fill:#212121;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.22337075" | |||
d="m 36.082576,19.407513 c 0,-0.430208 -0.352576,-0.781708 -0.782788,-0.781708 h -6.009984 c -0.43021,0 -0.782787,0.3515 -0.782787,0.781708 v 9.524976 c 0,0.430211 0.352577,0.781708 0.782787,0.781708 h 6.009984 c 0.430212,0 0.782788,-0.351497 0.782788,-0.781708 z" | |||
id="path25479-5-3" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="scccscccsscccscccssscscsscscss" | |||
id="path67-0-7" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 30.750669,19.679509 c 0,-0.08556 0.01492,-0.161178 0.04477,-0.226844 0.02985,-0.06567 0.06865,-0.119393 0.116409,-0.161179 0.04975,-0.04378 0.104467,-0.07661 0.164161,-0.0985 0.06169,-0.02189 0.123372,-0.03283 0.185057,-0.03283 0.06169,0 0.122378,0.01094 0.182073,0.03283 0.06169,0.02189 0.116409,0.05472 0.164166,0.0985 0.04975,0.04179 0.08954,0.09551 0.119391,0.161179 0.02985,0.06567 0.04477,0.141281 0.04477,0.226844 v 1.122283 c 0,0.08756 -0.01492,0.164165 -0.04477,0.229831 -0.02985,0.06367 -0.06964,0.117399 -0.119391,0.161178 -0.04776,0.04179 -0.102482,0.07362 -0.164166,0.09551 -0.05969,0.02189 -0.120384,0.03283 -0.182073,0.03283 -0.06169,0 -0.123372,-0.01094 -0.185057,-0.03283 -0.05969,-0.02189 -0.114414,-0.05372 -0.164161,-0.09551 -0.04776,-0.04378 -0.08656,-0.09751 -0.116409,-0.161178 -0.02985,-0.06567 -0.04477,-0.142277 -0.04477,-0.229831 z m 0.304448,1.122283 c 0,0.07362 0.0199,0.128346 0.0597,0.164165 0.04179,0.03383 0.09054,0.05074 0.146254,0.05074 0.05571,0 0.103471,-0.01691 0.143272,-0.05074 0.04179,-0.03582 0.06268,-0.09054 0.06268,-0.164165 v -1.122283 c 0,-0.07362 -0.02089,-0.127351 -0.06268,-0.161178 -0.0398,-0.03582 -0.08756,-0.05373 -0.143272,-0.05373 -0.05571,0 -0.104465,0.01791 -0.146254,0.05373 -0.0398,0.03383 -0.0597,0.08755 -0.0597,0.161178 z" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="scccscccsccscscsccs" | |||
id="path69-3-9" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 33.024432,20.82567 c 0,0.06965 -0.01293,0.134317 -0.0388,0.194012 -0.02587,0.0597 -0.06169,0.112432 -0.107455,0.158195 -0.04377,0.04378 -0.09551,0.0786 -0.155207,0.104466 -0.0597,0.02587 -0.123376,0.0388 -0.191027,0.0388 -0.06765,0 -0.131332,-0.01293 -0.191029,-0.0388 -0.05969,-0.02587 -0.112424,-0.06069 -0.158192,-0.104466 -0.04378,-0.04577 -0.0786,-0.0985 -0.10447,-0.158195 -0.02587,-0.05969 -0.0388,-0.124364 -0.0388,-0.194012 v -1.647608 h 0.304445 v 1.617762 c 0,0.07561 0.01791,0.13133 0.05373,0.167149 0.03582,0.03582 0.08059,0.05373 0.134315,0.05373 0.05373,0 0.0985,-0.01791 0.134316,-0.05373 0.03581,-0.03582 0.05372,-0.09154 0.05372,-0.167149 v -1.617762 h 0.304453 z" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="ccccccccc" | |||
id="path71-9-0" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 33.5103,19.464603 h -0.352208 v -0.286541 h 1.008861 v 0.286541 h -0.352205 v 1.838636 H 33.5103 Z" | |||
inkscape:connector-curvature="0" /> | |||
</g> | |||
<g | |||
id="g548-2" | |||
transform="translate(-1.1117604,50.253503)"> | |||
<path | |||
sodipodi:nodetypes="sssssssss" | |||
style="fill:#212121;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.22337075" | |||
d="m 36.082576,19.407513 c 0,-0.430208 -0.352576,-0.781708 -0.782788,-0.781708 h -6.009984 c -0.43021,0 -0.782787,0.3515 -0.782787,0.781708 v 9.524976 c 0,0.430211 0.352577,0.781708 0.782787,0.781708 h 6.009984 c 0.430212,0 0.782788,-0.351497 0.782788,-0.781708 z" | |||
id="path25479-5-39" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="scccscccsscccscccssscscsscscss" | |||
id="path67-0-9" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 30.750669,19.679509 c 0,-0.08556 0.01492,-0.161178 0.04477,-0.226844 0.02985,-0.06567 0.06865,-0.119393 0.116409,-0.161179 0.04975,-0.04378 0.104467,-0.07661 0.164161,-0.0985 0.06169,-0.02189 0.123372,-0.03283 0.185057,-0.03283 0.06169,0 0.122378,0.01094 0.182073,0.03283 0.06169,0.02189 0.116409,0.05472 0.164166,0.0985 0.04975,0.04179 0.08954,0.09551 0.119391,0.161179 0.02985,0.06567 0.04477,0.141281 0.04477,0.226844 v 1.122283 c 0,0.08756 -0.01492,0.164165 -0.04477,0.229831 -0.02985,0.06367 -0.06964,0.117399 -0.119391,0.161178 -0.04776,0.04179 -0.102482,0.07362 -0.164166,0.09551 -0.05969,0.02189 -0.120384,0.03283 -0.182073,0.03283 -0.06169,0 -0.123372,-0.01094 -0.185057,-0.03283 -0.05969,-0.02189 -0.114414,-0.05372 -0.164161,-0.09551 -0.04776,-0.04378 -0.08656,-0.09751 -0.116409,-0.161178 -0.02985,-0.06567 -0.04477,-0.142277 -0.04477,-0.229831 z m 0.304448,1.122283 c 0,0.07362 0.0199,0.128346 0.0597,0.164165 0.04179,0.03383 0.09054,0.05074 0.146254,0.05074 0.05571,0 0.103471,-0.01691 0.143272,-0.05074 0.04179,-0.03582 0.06268,-0.09054 0.06268,-0.164165 v -1.122283 c 0,-0.07362 -0.02089,-0.127351 -0.06268,-0.161178 -0.0398,-0.03582 -0.08756,-0.05373 -0.143272,-0.05373 -0.05571,0 -0.104465,0.01791 -0.146254,0.05373 -0.0398,0.03383 -0.0597,0.08755 -0.0597,0.161178 z" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="scccscccsccscscsccs" | |||
id="path69-3-7" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 33.024432,20.82567 c 0,0.06965 -0.01293,0.134317 -0.0388,0.194012 -0.02587,0.0597 -0.06169,0.112432 -0.107455,0.158195 -0.04377,0.04378 -0.09551,0.0786 -0.155207,0.104466 -0.0597,0.02587 -0.123376,0.0388 -0.191027,0.0388 -0.06765,0 -0.131332,-0.01293 -0.191029,-0.0388 -0.05969,-0.02587 -0.112424,-0.06069 -0.158192,-0.104466 -0.04378,-0.04577 -0.0786,-0.0985 -0.10447,-0.158195 -0.02587,-0.05969 -0.0388,-0.124364 -0.0388,-0.194012 v -1.647608 h 0.304445 v 1.617762 c 0,0.07561 0.01791,0.13133 0.05373,0.167149 0.03582,0.03582 0.08059,0.05373 0.134315,0.05373 0.05373,0 0.0985,-0.01791 0.134316,-0.05373 0.03581,-0.03582 0.05372,-0.09154 0.05372,-0.167149 v -1.617762 h 0.304453 z" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="ccccccccc" | |||
id="path71-9-03" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 33.5103,19.464603 h -0.352208 v -0.286541 h 1.008861 v 0.286541 h -0.352205 v 1.838636 H 33.5103 Z" | |||
inkscape:connector-curvature="0" /> | |||
</g> | |||
<g | |||
id="g548-9-6" | |||
transform="translate(-11.810555,50.4425)"> | |||
<path | |||
sodipodi:nodetypes="sssssssss" | |||
style="fill:#212121;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.22337075" | |||
d="m 36.082576,19.407513 c 0,-0.430208 -0.352576,-0.781708 -0.782788,-0.781708 h -6.009984 c -0.43021,0 -0.782787,0.3515 -0.782787,0.781708 v 9.524976 c 0,0.430211 0.352577,0.781708 0.782787,0.781708 h 6.009984 c 0.430212,0 0.782788,-0.351497 0.782788,-0.781708 z" | |||
id="path25479-5-0-2" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="scccscccsscccscccssscscsscscss" | |||
id="path67-0-5-7" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 30.750669,19.679509 c 0,-0.08556 0.01492,-0.161178 0.04477,-0.226844 0.02985,-0.06567 0.06865,-0.119393 0.116409,-0.161179 0.04975,-0.04378 0.104467,-0.07661 0.164161,-0.0985 0.06169,-0.02189 0.123372,-0.03283 0.185057,-0.03283 0.06169,0 0.122378,0.01094 0.182073,0.03283 0.06169,0.02189 0.116409,0.05472 0.164166,0.0985 0.04975,0.04179 0.08954,0.09551 0.119391,0.161179 0.02985,0.06567 0.04477,0.141281 0.04477,0.226844 v 1.122283 c 0,0.08756 -0.01492,0.164165 -0.04477,0.229831 -0.02985,0.06367 -0.06964,0.117399 -0.119391,0.161178 -0.04776,0.04179 -0.102482,0.07362 -0.164166,0.09551 -0.05969,0.02189 -0.120384,0.03283 -0.182073,0.03283 -0.06169,0 -0.123372,-0.01094 -0.185057,-0.03283 -0.05969,-0.02189 -0.114414,-0.05372 -0.164161,-0.09551 -0.04776,-0.04378 -0.08656,-0.09751 -0.116409,-0.161178 -0.02985,-0.06567 -0.04477,-0.142277 -0.04477,-0.229831 z m 0.304448,1.122283 c 0,0.07362 0.0199,0.128346 0.0597,0.164165 0.04179,0.03383 0.09054,0.05074 0.146254,0.05074 0.05571,0 0.103471,-0.01691 0.143272,-0.05074 0.04179,-0.03582 0.06268,-0.09054 0.06268,-0.164165 v -1.122283 c 0,-0.07362 -0.02089,-0.127351 -0.06268,-0.161178 -0.0398,-0.03582 -0.08756,-0.05373 -0.143272,-0.05373 -0.05571,0 -0.104465,0.01791 -0.146254,0.05373 -0.0398,0.03383 -0.0597,0.08755 -0.0597,0.161178 z" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="scccscccsccscscsccs" | |||
id="path69-3-2-0" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 33.024432,20.82567 c 0,0.06965 -0.01293,0.134317 -0.0388,0.194012 -0.02587,0.0597 -0.06169,0.112432 -0.107455,0.158195 -0.04377,0.04378 -0.09551,0.0786 -0.155207,0.104466 -0.0597,0.02587 -0.123376,0.0388 -0.191027,0.0388 -0.06765,0 -0.131332,-0.01293 -0.191029,-0.0388 -0.05969,-0.02587 -0.112424,-0.06069 -0.158192,-0.104466 -0.04378,-0.04577 -0.0786,-0.0985 -0.10447,-0.158195 -0.02587,-0.05969 -0.0388,-0.124364 -0.0388,-0.194012 v -1.647608 h 0.304445 v 1.617762 c 0,0.07561 0.01791,0.13133 0.05373,0.167149 0.03582,0.03582 0.08059,0.05373 0.134315,0.05373 0.05373,0 0.0985,-0.01791 0.134316,-0.05373 0.03581,-0.03582 0.05372,-0.09154 0.05372,-0.167149 v -1.617762 h 0.304453 z" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="ccccccccc" | |||
id="path71-9-2-3" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 33.5103,19.464603 h -0.352208 v -0.286541 h 1.008861 v 0.286541 h -0.352205 v 1.838636 H 33.5103 Z" | |||
inkscape:connector-curvature="0" /> | |||
</g> | |||
<g | |||
id="g548-9-6-7" | |||
transform="translate(-22.6942,50.63148)"> | |||
<path | |||
sodipodi:nodetypes="sssssssss" | |||
style="fill:#212121;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.22337075" | |||
d="m 36.082576,19.407513 c 0,-0.430208 -0.352576,-0.781708 -0.782788,-0.781708 h -6.009984 c -0.43021,0 -0.782787,0.3515 -0.782787,0.781708 v 9.524976 c 0,0.430211 0.352577,0.781708 0.782787,0.781708 h 6.009984 c 0.430212,0 0.782788,-0.351497 0.782788,-0.781708 z" | |||
id="path25479-5-0-2-2" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="scccscccsscccscccssscscsscscss" | |||
id="path67-0-5-7-3" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 30.750669,19.679509 c 0,-0.08556 0.01492,-0.161178 0.04477,-0.226844 0.02985,-0.06567 0.06865,-0.119393 0.116409,-0.161179 0.04975,-0.04378 0.104467,-0.07661 0.164161,-0.0985 0.06169,-0.02189 0.123372,-0.03283 0.185057,-0.03283 0.06169,0 0.122378,0.01094 0.182073,0.03283 0.06169,0.02189 0.116409,0.05472 0.164166,0.0985 0.04975,0.04179 0.08954,0.09551 0.119391,0.161179 0.02985,0.06567 0.04477,0.141281 0.04477,0.226844 v 1.122283 c 0,0.08756 -0.01492,0.164165 -0.04477,0.229831 -0.02985,0.06367 -0.06964,0.117399 -0.119391,0.161178 -0.04776,0.04179 -0.102482,0.07362 -0.164166,0.09551 -0.05969,0.02189 -0.120384,0.03283 -0.182073,0.03283 -0.06169,0 -0.123372,-0.01094 -0.185057,-0.03283 -0.05969,-0.02189 -0.114414,-0.05372 -0.164161,-0.09551 -0.04776,-0.04378 -0.08656,-0.09751 -0.116409,-0.161178 -0.02985,-0.06567 -0.04477,-0.142277 -0.04477,-0.229831 z m 0.304448,1.122283 c 0,0.07362 0.0199,0.128346 0.0597,0.164165 0.04179,0.03383 0.09054,0.05074 0.146254,0.05074 0.05571,0 0.103471,-0.01691 0.143272,-0.05074 0.04179,-0.03582 0.06268,-0.09054 0.06268,-0.164165 v -1.122283 c 0,-0.07362 -0.02089,-0.127351 -0.06268,-0.161178 -0.0398,-0.03582 -0.08756,-0.05373 -0.143272,-0.05373 -0.05571,0 -0.104465,0.01791 -0.146254,0.05373 -0.0398,0.03383 -0.0597,0.08755 -0.0597,0.161178 z" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="scccscccsccscscsccs" | |||
id="path69-3-2-0-6" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 33.024432,20.82567 c 0,0.06965 -0.01293,0.134317 -0.0388,0.194012 -0.02587,0.0597 -0.06169,0.112432 -0.107455,0.158195 -0.04377,0.04378 -0.09551,0.0786 -0.155207,0.104466 -0.0597,0.02587 -0.123376,0.0388 -0.191027,0.0388 -0.06765,0 -0.131332,-0.01293 -0.191029,-0.0388 -0.05969,-0.02587 -0.112424,-0.06069 -0.158192,-0.104466 -0.04378,-0.04577 -0.0786,-0.0985 -0.10447,-0.158195 -0.02587,-0.05969 -0.0388,-0.124364 -0.0388,-0.194012 v -1.647608 h 0.304445 v 1.617762 c 0,0.07561 0.01791,0.13133 0.05373,0.167149 0.03582,0.03582 0.08059,0.05373 0.134315,0.05373 0.05373,0 0.0985,-0.01791 0.134316,-0.05373 0.03581,-0.03582 0.05372,-0.09154 0.05372,-0.167149 v -1.617762 h 0.304453 z" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
sodipodi:nodetypes="ccccccccc" | |||
id="path71-9-2-3-5" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
d="m 33.5103,19.464603 h -0.352208 v -0.286541 h 1.008861 v 0.286541 h -0.352205 v 1.838636 H 33.5103 Z" | |||
inkscape:connector-curvature="0" /> | |||
</g> | |||
<g | |||
aria-label="BPM" | |||
transform="matrix(0.26458333,0,0,0.26458333,0.08851987,2.1895217)" | |||
style="font-style:normal;font-weight:normal;font-size:14.66666698px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.80924457" | |||
id="flowRoot923-5"> | |||
<path | |||
d="m 59.845359,15.142578 h 3.576 q 1.176,0 1.992,0.36 0.84,0.36 1.368,0.96 0.528,0.6 0.744,1.392 0.24,0.768 0.24,1.608 v 0.624 q 0,0.696 -0.12,1.176 -0.096,0.48 -0.312,0.84 -0.216,0.36 -0.528,0.648 -0.312,0.264 -0.72,0.504 0.864,0.408 1.272,1.224 0.408,0.792 0.408,2.136 v 0.96 q 0,2.256 -1.104,3.456 -1.08,1.2 -3.48,1.2 h -3.336 z m 2.448,14.64 h 1.056 q 0.744,0 1.152,-0.216 0.432,-0.216 0.648,-0.6 0.216,-0.384 0.264,-0.912 0.048,-0.528 0.048,-1.152 0,-0.648 -0.072,-1.128 -0.072,-0.48 -0.312,-0.792 -0.216,-0.336 -0.624,-0.504 -0.408,-0.168 -1.08,-0.168 h -1.08 z m 0,-7.632 h 1.104 q 1.224,0 1.632,-0.6 0.432,-0.624 0.432,-1.8 0,-1.152 -0.48,-1.728 -0.456,-0.576 -1.68,-0.576 h -1.008 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';text-align:center;text-anchor:middle" | |||
id="path8974" /> | |||
<path | |||
d="m 70.064109,15.142578 h 3.672 q 1.008,0 1.776,0.264 0.768,0.264 1.392,0.936 0.624,0.672 0.864,1.584 0.24,0.888 0.24,2.424 0,1.128 -0.144,1.944 -0.12,0.792 -0.552,1.488 -0.504,0.84 -1.344,1.32 -0.84,0.456 -2.208,0.456 h -1.248 v 6.672 h -2.448 z m 2.448,8.112 h 1.176 q 0.744,0 1.152,-0.216 0.408,-0.216 0.6,-0.576 0.192,-0.384 0.216,-0.912 0.048,-0.528 0.048,-1.176 0,-0.6 -0.048,-1.128 -0.024,-0.552 -0.216,-0.936 -0.168,-0.408 -0.552,-0.624 -0.384,-0.24 -1.104,-0.24 h -1.272 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';text-align:center;text-anchor:middle" | |||
id="path8976" /> | |||
<path | |||
d="m 79.814109,15.142578 h 2.352 l 3.144,9.048 h 0.048 l 3.12,-9.048 h 2.376 v 17.088 h -2.448 v -10.392 h -0.048 l -2.424,7.344 h -1.224 l -2.4,-7.344 h -0.048 v 10.392 h -2.448 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';text-align:center;text-anchor:middle" | |||
id="path8978" /> | |||
</g> | |||
<g | |||
id="g1214-6-6" | |||
transform="translate(0.38524748,13.742015)"> | |||
<path | |||
style="fill:none;stroke:#000000;stroke-width:0.13229166;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" | |||
d="M 19.873725,27.206627 19.821582,14.544425" | |||
id="path25527-7-9-8" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cc" /> | |||
<path | |||
style="fill:none;stroke:#000000;stroke-width:0.13229166;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" | |||
d="M 9.0182285,32.175055 20.038693,27.268084 v 0" | |||
id="path25541-6-5-4" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="ccc" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
d="m 3.0634627,31.941111 q 0,0.0985 -0.038803,0.188044 -0.035817,0.08954 -0.1014829,0.158192 -0.065666,0.06567 -0.155211,0.107454 -0.086558,0.0388 -0.1880412,0.0388 -0.086558,0 -0.1761031,-0.02388 -0.089545,-0.02388 -0.1611786,-0.08059 -0.071637,-0.05969 -0.1193914,-0.155202 -0.044774,-0.09551 -0.044774,-0.241769 v -1.17004 q 0,-0.10447 0.03582,-0.194012 0.035817,-0.08955 0.1014829,-0.155211 0.065666,-0.06566 0.1552082,-0.101483 0.092529,-0.0388 0.2029658,-0.0388 0.1044695,0 0.1940116,0.0388 0.089545,0.03582 0.1552109,0.10447 0.065666,0.06566 0.101483,0.161178 0.038803,0.09253 0.038803,0.202966 v 0.119391 H 2.7590114 v -0.101482 q 0,-0.08954 -0.050741,-0.155209 -0.050741,-0.06567 -0.1372997,-0.06567 -0.1134237,0 -0.1522244,0.07163 -0.035817,0.06865 -0.035817,0.176103 v 1.086469 q 0,0.09253 0.038801,0.155208 0.041787,0.06268 0.1462567,0.06268 0.029846,0 0.06268,-0.009 0.035817,-0.01195 0.062682,-0.03582 0.029846,-0.02388 0.047755,-0.06567 0.017914,-0.04179 0.017914,-0.104467 v -0.104466 h 0.3044515 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355095px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
id="path74-2-4-1" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
d="M 3.9059204,32.415695 H 3.6372885 L 3.2044943,30.290519 h 0.3223571 l 0.2417692,1.483443 h 0.00596 l 0.2447531,-1.483443 h 0.3223599 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.81355095px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.06038577" | |||
id="path76-7-9-7" /> | |||
</g> | |||
<path | |||
style="fill:none;stroke:#000000;stroke-width:0.09710628;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" | |||
d="m 31.28471,38.73313 -0.05214,6.822428" | |||
id="path25527-7-9-8-8" | |||
inkscape:connector-curvature="0" | |||
sodipodi:nodetypes="cc" /> | |||
<g | |||
aria-label="RESET" | |||
transform="matrix(0.26458333,0,0,0.26458333,11.329402,27.702665)" | |||
style="font-style:normal;font-weight:normal;font-size:14.66666698px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.80924457" | |||
id="flowRoot923-4"> | |||
<path | |||
d="m 66.454166,20.605913 h 0.618667 q 0.288,0 0.458667,-0.07467 0.170666,-0.08533 0.256,-0.234667 0.096,-0.149333 0.128,-0.362667 0.032,-0.224 0.032,-0.512 0,-0.288 -0.032,-0.501333 -0.032,-0.224 -0.138667,-0.373333 -0.096,-0.16 -0.277333,-0.234667 -0.181334,-0.07467 -0.48,-0.07467 h -0.565334 z m -1.088,-3.392001 H 67.1155 q 1.92,0 1.92,2.229334 0,0.661333 -0.213334,1.141333 -0.202666,0.469334 -0.725333,0.757334 l 1.173333,3.466666 h -1.152 l -1.013333,-3.242666 h -0.650667 v 3.242666 h -1.088 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';text-align:center;text-anchor:middle" | |||
id="path262" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
d="M 69.907833,17.213912 H 73.1505 v 1.024 h -2.154667 v 2.229334 h 1.877334 v 1.024 h -1.877334 v 2.229333 H 73.1505 v 1.088 h -3.242667 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';text-align:center;text-anchor:middle" | |||
id="path264" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
d="m 77.365333,19.400579 h -1.088 v -0.245333 q 0,-0.373334 -0.181333,-0.64 -0.170667,-0.277334 -0.586667,-0.277334 -0.224,0 -0.373333,0.08533 -0.138667,0.08533 -0.224,0.224 -0.07467,0.128 -0.106667,0.309333 -0.032,0.170667 -0.032,0.362667 0,0.224 0.01067,0.384 0.02133,0.149333 0.08533,0.266666 0.064,0.106667 0.181334,0.192001 0.128,0.08533 0.341333,0.170666 l 0.832,0.330667 q 0.362667,0.138667 0.586667,0.330667 0.224,0.181333 0.341333,0.437333 0.128,0.245333 0.170667,0.576 0.04267,0.32 0.04267,0.736 0,0.48 -0.096,0.896 -0.096,0.405333 -0.32,0.704 -0.213333,0.288 -0.576,0.458667 -0.362666,0.170666 -0.885333,0.170666 -0.394667,0 -0.736,-0.138666 -0.341337,-0.138663 -0.586671,-0.37333 Q 73.92,24.115246 73.770667,23.784579 73.632,23.453913 73.632,23.069913 v -0.405334 h 1.088 v 0.341334 q 0,0.298666 0.170667,0.544 0.181333,0.234666 0.597333,0.234666 0.277333,0 0.426667,-0.07467 0.16,-0.08533 0.234666,-0.224 0.08533,-0.149334 0.106667,-0.362667 0.02133,-0.213333 0.02133,-0.469333 0,-0.298667 -0.02133,-0.490667 -0.02133,-0.192 -0.096,-0.309333 -0.064,-0.117334 -0.192,-0.192 -0.117333,-0.07467 -0.32,-0.16 l -0.778667,-0.32 q -0.704,-0.288 -0.949333,-0.757334 -0.234667,-0.48 -0.234667,-1.194667 0,-0.426666 0.117334,-0.810666 0.117333,-0.384 0.341333,-0.661334 0.234667,-0.277333 0.586667,-0.437333 0.352,-0.170667 0.821333,-0.170667 0.405333,0 0.736,0.149334 0.341333,0.149333 0.576,0.394666 0.245333,0.245334 0.373333,0.554667 0.128,0.298667 0.128,0.618667 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';text-align:center;text-anchor:middle" | |||
id="path266" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
d="m 78.178666,17.213912 h 3.242667 v 1.024 h -2.154667 v 2.229334 H 81.144 v 1.024 h -1.877334 v 2.229333 h 2.154667 v 1.088 h -3.242667 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';text-align:center;text-anchor:middle" | |||
id="path268" | |||
inkscape:connector-curvature="0" /> | |||
<path | |||
d="m 82.830833,18.237912 h -1.258667 v -1.024 H 85.1775 v 1.024 h -1.258667 v 6.570667 h -1.088 z" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, ';text-align:center;text-anchor:middle" | |||
id="path270" | |||
inkscape:connector-curvature="0" /> | |||
</g> | |||
</g> | |||
<g | |||
inkscape:label="Layer 1" | |||
inkscape:groupmode="layer" | |||
id="layer1" | |||
transform="translate(5.559749,-98.968292)" /> | |||
<g | |||
inkscape:groupmode="layer" | |||
id="layer2" | |||
inkscape:label="Layer 2" /> | |||
</svg> |