Browse Source

add Gratrix, moDllz, RJModules, SerialRacker modules

pull/1639/head
bsp2 6 years ago
parent
commit
b0d29f0086
100 changed files with 180105 additions and 5 deletions
  1. +54
    -4
      README.md
  2. +26
    -0
      plugins/community/repos/Gratrix/LICENSE-dist.txt
  3. +7
    -0
      plugins/community/repos/Gratrix/LICENSE.txt
  4. +11
    -0
      plugins/community/repos/Gratrix/Makefile
  5. +5
    -0
      plugins/community/repos/Gratrix/README.md
  6. +13
    -0
      plugins/community/repos/Gratrix/gen_ui.sh
  7. +22
    -0
      plugins/community/repos/Gratrix/make.objects
  8. +7
    -0
      plugins/community/repos/Gratrix/makefile.msvc
  9. +9761
    -0
      plugins/community/repos/Gratrix/res/ADSR-F1.svg
  10. +9937
    -0
      plugins/community/repos/Gratrix/res/Binary-G1.svg
  11. +45
    -0
      plugins/community/repos/Gratrix/res/Blank03.svg
  12. +45
    -0
      plugins/community/repos/Gratrix/res/Blank06.svg
  13. +45
    -0
      plugins/community/repos/Gratrix/res/Blank09.svg
  14. +45
    -0
      plugins/community/repos/Gratrix/res/Blank12.svg
  15. +11754
    -0
      plugins/community/repos/Gratrix/res/Chord-G1.svg
  16. +9671
    -0
      plugins/community/repos/Gratrix/res/Fade-G1.svg
  17. +9779
    -0
      plugins/community/repos/Gratrix/res/Fade-G2.svg
  18. +10219
    -0
      plugins/community/repos/Gratrix/res/Keys-G1.svg
  19. +9658
    -0
      plugins/community/repos/Gratrix/res/MIDI-C1.svg
  20. +9596
    -0
      plugins/community/repos/Gratrix/res/MIDI-G1.svg
  21. +9745
    -0
      plugins/community/repos/Gratrix/res/Octave-G1.svg
  22. +9921
    -0
      plugins/community/repos/Gratrix/res/Scope-G1.svg
  23. +10226
    -0
      plugins/community/repos/Gratrix/res/Seq-G1.svg
  24. +10438
    -0
      plugins/community/repos/Gratrix/res/Seq-G2.svg
  25. +9696
    -0
      plugins/community/repos/Gratrix/res/VCA-F1.svg
  26. +9776
    -0
      plugins/community/repos/Gratrix/res/VCF-F1.svg
  27. +9874
    -0
      plugins/community/repos/Gratrix/res/VCO-F1.svg
  28. +9748
    -0
      plugins/community/repos/Gratrix/res/VCO-F2.svg
  29. +9537
    -0
      plugins/community/repos/Gratrix/res/VU-G1.svg
  30. +8
    -0
      plugins/community/repos/Gratrix/res/components/KnobFreeHuge.svg
  31. +8
    -0
      plugins/community/repos/Gratrix/res/components/KnobFreeLarge.svg
  32. +8
    -0
      plugins/community/repos/Gratrix/res/components/KnobFreeMedium.svg
  33. +8
    -0
      plugins/community/repos/Gratrix/res/components/KnobFreeSmall.svg
  34. +8
    -0
      plugins/community/repos/Gratrix/res/components/KnobFreeTiny.svg
  35. +8
    -0
      plugins/community/repos/Gratrix/res/components/KnobSnapHuge.svg
  36. +8
    -0
      plugins/community/repos/Gratrix/res/components/KnobSnapLarge.svg
  37. +8
    -0
      plugins/community/repos/Gratrix/res/components/KnobSnapMedium.svg
  38. +8
    -0
      plugins/community/repos/Gratrix/res/components/KnobSnapSmall.svg
  39. +8
    -0
      plugins/community/repos/Gratrix/res/components/KnobSnapTiny.svg
  40. +11
    -0
      plugins/community/repos/Gratrix/res/components/PortInMedium.svg
  41. +11
    -0
      plugins/community/repos/Gratrix/res/components/PortInSmall.svg
  42. +11
    -0
      plugins/community/repos/Gratrix/res/components/PortOutMedium.svg
  43. +11
    -0
      plugins/community/repos/Gratrix/res/components/PortOutSmall.svg
  44. +93
    -0
      plugins/community/repos/Gratrix/res/fonts/Sudo-LICENSE.txt
  45. BIN
      plugins/community/repos/Gratrix/res/fonts/Sudo.ttf
  46. BIN
      plugins/community/repos/Gratrix/res/fonts/lcd-solid/LCD_Solid.ttf
  47. +1
    -0
      plugins/community/repos/Gratrix/res/fonts/lcd-solid/ReadMe.txt
  48. +201
    -0
      plugins/community/repos/Gratrix/src/ADSR.cpp
  49. +213
    -0
      plugins/community/repos/Gratrix/src/Binary-G1.cpp
  50. +55
    -0
      plugins/community/repos/Gratrix/src/Blank03.cpp
  51. +55
    -0
      plugins/community/repos/Gratrix/src/Blank06.cpp
  52. +55
    -0
      plugins/community/repos/Gratrix/src/Blank09.cpp
  53. +55
    -0
      plugins/community/repos/Gratrix/src/Blank12.cpp
  54. +374
    -0
      plugins/community/repos/Gratrix/src/Chord-G1.cpp
  55. +150
    -0
      plugins/community/repos/Gratrix/src/Fade-G1.cpp
  56. +194
    -0
      plugins/community/repos/Gratrix/src/Fade-G2.cpp
  57. +45
    -0
      plugins/community/repos/Gratrix/src/Gratrix.cpp
  58. +2415
    -0
      plugins/community/repos/Gratrix/src/Gratrix.hpp
  59. +206
    -0
      plugins/community/repos/Gratrix/src/Keys-G1.cpp
  60. +413
    -0
      plugins/community/repos/Gratrix/src/MIDI-C1.cpp
  61. +393
    -0
      plugins/community/repos/Gratrix/src/MIDI-G1.cpp
  62. +220
    -0
      plugins/community/repos/Gratrix/src/Octave-G1.cpp
  63. +387
    -0
      plugins/community/repos/Gratrix/src/Scope-G1.cpp
  64. +1309
    -0
      plugins/community/repos/Gratrix/src/Seq-G1.cpp
  65. +1359
    -0
      plugins/community/repos/Gratrix/src/Seq-G2.cpp
  66. +157
    -0
      plugins/community/repos/Gratrix/src/VCA.cpp
  67. +257
    -0
      plugins/community/repos/Gratrix/src/VCF.cpp
  68. +492
    -0
      plugins/community/repos/Gratrix/src/VCO.cpp
  69. +120
    -0
      plugins/community/repos/Gratrix/src/VU-G1.cpp
  70. +300
    -0
      plugins/community/repos/Gratrix/www/index.html
  71. BIN
      plugins/community/repos/Gratrix/www/res/Binary-G1.png
  72. BIN
      plugins/community/repos/Gratrix/www/res/Blank03.png
  73. BIN
      plugins/community/repos/Gratrix/www/res/Blank06.png
  74. BIN
      plugins/community/repos/Gratrix/www/res/Blank09.png
  75. BIN
      plugins/community/repos/Gratrix/www/res/Blank12.png
  76. BIN
      plugins/community/repos/Gratrix/www/res/Chord-G1.png
  77. BIN
      plugins/community/repos/Gratrix/www/res/Env-F1.png
  78. BIN
      plugins/community/repos/Gratrix/www/res/Fade-G1.png
  79. BIN
      plugins/community/repos/Gratrix/www/res/Fade-G2.png
  80. BIN
      plugins/community/repos/Gratrix/www/res/Keys-G1.png
  81. BIN
      plugins/community/repos/Gratrix/www/res/MIDI-C1.png
  82. BIN
      plugins/community/repos/Gratrix/www/res/MIDI-G1.png
  83. BIN
      plugins/community/repos/Gratrix/www/res/Mux.png
  84. BIN
      plugins/community/repos/Gratrix/www/res/Octave-G1.png
  85. BIN
      plugins/community/repos/Gratrix/www/res/Scope-G1.png
  86. BIN
      plugins/community/repos/Gratrix/www/res/Seq-G1.png
  87. BIN
      plugins/community/repos/Gratrix/www/res/Seq-G2.png
  88. BIN
      plugins/community/repos/Gratrix/www/res/VCA-F1.png
  89. BIN
      plugins/community/repos/Gratrix/www/res/VCF-F1.png
  90. BIN
      plugins/community/repos/Gratrix/www/res/VCO-F1.png
  91. BIN
      plugins/community/repos/Gratrix/www/res/VCO-F2.png
  92. BIN
      plugins/community/repos/Gratrix/www/res/VU-G1.png
  93. BIN
      plugins/community/repos/Gratrix/www/shot.png
  94. +1
    -1
      plugins/community/repos/ML_modules/src/VoltMeter.cpp
  95. +7
    -0
      plugins/community/repos/RJModules/LICENSE.txt
  96. +19
    -0
      plugins/community/repos/RJModules/Makefile
  97. +215
    -0
      plugins/community/repos/RJModules/README.md
  98. +33
    -0
      plugins/community/repos/RJModules/make.objects
  99. +7
    -0
      plugins/community/repos/RJModules/makefile.msvc
  100. +519
    -0
      plugins/community/repos/RJModules/res/BPM.svg

+ 54
- 4
README.md View File

@@ -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


+ 26
- 0
plugins/community/repos/Gratrix/LICENSE-dist.txt View File

@@ -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.

+ 7
- 0
plugins/community/repos/Gratrix/LICENSE.txt View File

@@ -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.

+ 11
- 0
plugins/community/repos/Gratrix/Makefile View File

@@ -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

+ 5
- 0
plugins/community/repos/Gratrix/README.md View File

@@ -0,0 +1,5 @@
# Gratrix Modules for VCV Rack

Please head over to [gratrix.net/vcvrack](http://gratrix.net/vcvrack/) for details.

![Gratrix Modules screenshot](http://gratrix.net/vcvrack/shot.png)

+ 13
- 0
plugins/community/repos/Gratrix/gen_ui.sh View File

@@ -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

+ 22
- 0
plugins/community/repos/Gratrix/make.objects View File

@@ -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

+ 7
- 0
plugins/community/repos/Gratrix/makefile.msvc View File

@@ -0,0 +1,7 @@
SLUG=Gratrix

include ../../../../dep/yac/install_msvc.mk

include make.objects

include ../../../build_plugin.mk

+ 9761
- 0
plugins/community/repos/Gratrix/res/ADSR-F1.svg
File diff suppressed because it is too large
View File


+ 9937
- 0
plugins/community/repos/Gratrix/res/Binary-G1.svg
File diff suppressed because it is too large
View File


+ 45
- 0
plugins/community/repos/Gratrix/res/Blank03.svg View File

@@ -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>

+ 45
- 0
plugins/community/repos/Gratrix/res/Blank06.svg View File

@@ -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>

+ 45
- 0
plugins/community/repos/Gratrix/res/Blank09.svg View File

@@ -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>

+ 45
- 0
plugins/community/repos/Gratrix/res/Blank12.svg View File

@@ -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>

+ 11754
- 0
plugins/community/repos/Gratrix/res/Chord-G1.svg
File diff suppressed because it is too large
View File


+ 9671
- 0
plugins/community/repos/Gratrix/res/Fade-G1.svg
File diff suppressed because it is too large
View File


+ 9779
- 0
plugins/community/repos/Gratrix/res/Fade-G2.svg
File diff suppressed because it is too large
View File


+ 10219
- 0
plugins/community/repos/Gratrix/res/Keys-G1.svg
File diff suppressed because it is too large
View File


+ 9658
- 0
plugins/community/repos/Gratrix/res/MIDI-C1.svg
File diff suppressed because it is too large
View File


+ 9596
- 0
plugins/community/repos/Gratrix/res/MIDI-G1.svg
File diff suppressed because it is too large
View File


+ 9745
- 0
plugins/community/repos/Gratrix/res/Octave-G1.svg
File diff suppressed because it is too large
View File


+ 9921
- 0
plugins/community/repos/Gratrix/res/Scope-G1.svg
File diff suppressed because it is too large
View File


+ 10226
- 0
plugins/community/repos/Gratrix/res/Seq-G1.svg
File diff suppressed because it is too large
View File


+ 10438
- 0
plugins/community/repos/Gratrix/res/Seq-G2.svg
File diff suppressed because it is too large
View File


+ 9696
- 0
plugins/community/repos/Gratrix/res/VCA-F1.svg
File diff suppressed because it is too large
View File


+ 9776
- 0
plugins/community/repos/Gratrix/res/VCF-F1.svg
File diff suppressed because it is too large
View File


+ 9874
- 0
plugins/community/repos/Gratrix/res/VCO-F1.svg
File diff suppressed because it is too large
View File


+ 9748
- 0
plugins/community/repos/Gratrix/res/VCO-F2.svg
File diff suppressed because it is too large
View File


+ 9537
- 0
plugins/community/repos/Gratrix/res/VU-G1.svg
File diff suppressed because it is too large
View File


+ 8
- 0
plugins/community/repos/Gratrix/res/components/KnobFreeHuge.svg View File

@@ -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>

+ 8
- 0
plugins/community/repos/Gratrix/res/components/KnobFreeLarge.svg View File

@@ -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>

+ 8
- 0
plugins/community/repos/Gratrix/res/components/KnobFreeMedium.svg View File

@@ -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>

+ 8
- 0
plugins/community/repos/Gratrix/res/components/KnobFreeSmall.svg View File

@@ -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>

+ 8
- 0
plugins/community/repos/Gratrix/res/components/KnobFreeTiny.svg View File

@@ -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>

+ 8
- 0
plugins/community/repos/Gratrix/res/components/KnobSnapHuge.svg View File

@@ -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>

+ 8
- 0
plugins/community/repos/Gratrix/res/components/KnobSnapLarge.svg View File

@@ -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>

+ 8
- 0
plugins/community/repos/Gratrix/res/components/KnobSnapMedium.svg View File

@@ -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>

+ 8
- 0
plugins/community/repos/Gratrix/res/components/KnobSnapSmall.svg View File

@@ -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>

+ 8
- 0
plugins/community/repos/Gratrix/res/components/KnobSnapTiny.svg View File

@@ -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>

+ 11
- 0
plugins/community/repos/Gratrix/res/components/PortInMedium.svg View File

@@ -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>



+ 11
- 0
plugins/community/repos/Gratrix/res/components/PortInSmall.svg View File

@@ -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>



+ 11
- 0
plugins/community/repos/Gratrix/res/components/PortOutMedium.svg View File

@@ -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>



+ 11
- 0
plugins/community/repos/Gratrix/res/components/PortOutSmall.svg View File

@@ -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>



+ 93
- 0
plugins/community/repos/Gratrix/res/fonts/Sudo-LICENSE.txt View File

@@ -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.

BIN
plugins/community/repos/Gratrix/res/fonts/Sudo.ttf View File


BIN
plugins/community/repos/Gratrix/res/fonts/lcd-solid/LCD_Solid.ttf View File


+ 1
- 0
plugins/community/repos/Gratrix/res/fonts/lcd-solid/ReadMe.txt View File

@@ -0,0 +1 @@
Font is public domain and was obtained from http://www.fontspace.com/lcd-solid/lcd-solid

+ 201
- 0
plugins/community/repos/Gratrix/src/ADSR.cpp View File

@@ -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;
}

+ 213
- 0
plugins/community/repos/Gratrix/src/Binary-G1.cpp View File

@@ -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;
}

+ 55
- 0
plugins/community/repos/Gratrix/src/Blank03.cpp View File

@@ -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;
}

+ 55
- 0
plugins/community/repos/Gratrix/src/Blank06.cpp View File

@@ -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;
}

+ 55
- 0
plugins/community/repos/Gratrix/src/Blank09.cpp View File

@@ -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;
}

+ 55
- 0
plugins/community/repos/Gratrix/src/Blank12.cpp View File

@@ -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;
}

+ 374
- 0
plugins/community/repos/Gratrix/src/Chord-G1.cpp View File

@@ -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;
}

+ 150
- 0
plugins/community/repos/Gratrix/src/Fade-G1.cpp View File

@@ -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;
}

+ 194
- 0
plugins/community/repos/Gratrix/src/Fade-G2.cpp View File

@@ -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;
}

+ 45
- 0
plugins/community/repos/Gratrix/src/Gratrix.cpp View File

@@ -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);
}

+ 2415
- 0
plugins/community/repos/Gratrix/src/Gratrix.hpp
File diff suppressed because it is too large
View File


+ 206
- 0
plugins/community/repos/Gratrix/src/Keys-G1.cpp View File

@@ -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;
}

+ 413
- 0
plugins/community/repos/Gratrix/src/MIDI-C1.cpp View File

@@ -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

+ 393
- 0
plugins/community/repos/Gratrix/src/MIDI-G1.cpp View File

@@ -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

+ 220
- 0
plugins/community/repos/Gratrix/src/Octave-G1.cpp View File

@@ -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;
}

+ 387
- 0
plugins/community/repos/Gratrix/src/Scope-G1.cpp View File

@@ -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;
}

+ 1309
- 0
plugins/community/repos/Gratrix/src/Seq-G1.cpp
File diff suppressed because it is too large
View File


+ 1359
- 0
plugins/community/repos/Gratrix/src/Seq-G2.cpp
File diff suppressed because it is too large
View File


+ 157
- 0
plugins/community/repos/Gratrix/src/VCA.cpp View File

@@ -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;
}

+ 257
- 0
plugins/community/repos/Gratrix/src/VCF.cpp View File

@@ -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;
}

+ 492
- 0
plugins/community/repos/Gratrix/src/VCO.cpp
File diff suppressed because it is too large
View File


+ 120
- 0
plugins/community/repos/Gratrix/src/VU-G1.cpp View File

@@ -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;
}

+ 300
- 0
plugins/community/repos/Gratrix/www/index.html View File

@@ -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">&nbsp;</td><td width="90">&nbsp;</td><td width="90">&nbsp;</td><td width="90">&nbsp;</td>
<td width="90">&nbsp;</td><td width="90">&nbsp;</td><td width="90">&nbsp;</td>
<td width="90">&nbsp;</td><td width="90">&nbsp;</td><td width="90">&nbsp;</td><td width="90">&nbsp;</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">&nbsp;</td><td width="90">&nbsp;</td><td width="90">&nbsp;</td><td width="90">&nbsp;</td>
<td width="90">&nbsp;</td><td width="90">&nbsp;</td><td width="90">&nbsp;</td>
<td width="90">&nbsp;</td><td width="90">&nbsp;</td><td width="90">&nbsp;</td><td width="90">&nbsp;</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>&copy; Sam Gratrix, <a href="http://gratrix.net">Gratrix.net</a>.</p>
</body>
</html>

BIN
plugins/community/repos/Gratrix/www/res/Binary-G1.png View File

Before After
Width: 180  |  Height: 380  |  Size: 30KB

BIN
plugins/community/repos/Gratrix/www/res/Blank03.png View File

Before After
Width: 45  |  Height: 380  |  Size: 1.3KB

BIN
plugins/community/repos/Gratrix/www/res/Blank06.png View File

Before After
Width: 90  |  Height: 380  |  Size: 1.8KB

BIN
plugins/community/repos/Gratrix/www/res/Blank09.png View File

Before After
Width: 135  |  Height: 380  |  Size: 1.9KB

BIN
plugins/community/repos/Gratrix/www/res/Blank12.png View File

Before After
Width: 180  |  Height: 380  |  Size: 2.0KB

BIN
plugins/community/repos/Gratrix/www/res/Chord-G1.png View File

Before After
Width: 270  |  Height: 380  |  Size: 43KB

BIN
plugins/community/repos/Gratrix/www/res/Env-F1.png View File

Before After
Width: 180  |  Height: 380  |  Size: 29KB

BIN
plugins/community/repos/Gratrix/www/res/Fade-G1.png View File

Before After
Width: 180  |  Height: 380  |  Size: 27KB

BIN
plugins/community/repos/Gratrix/www/res/Fade-G2.png View File

Before After
Width: 270  |  Height: 380  |  Size: 36KB

BIN
plugins/community/repos/Gratrix/www/res/Keys-G1.png View File

Before After
Width: 540  |  Height: 380  |  Size: 28KB

BIN
plugins/community/repos/Gratrix/www/res/MIDI-C1.png View File

Before After
Width: 180  |  Height: 380  |  Size: 18KB

BIN
plugins/community/repos/Gratrix/www/res/MIDI-G1.png View File

Before After
Width: 90  |  Height: 380  |  Size: 14KB

BIN
plugins/community/repos/Gratrix/www/res/Mux.png View File

Before After
Width: 135  |  Height: 380  |  Size: 3.2KB

BIN
plugins/community/repos/Gratrix/www/res/Octave-G1.png View File

Before After
Width: 180  |  Height: 380  |  Size: 19KB

BIN
plugins/community/repos/Gratrix/www/res/Scope-G1.png View File

Before After
Width: 360  |  Height: 380  |  Size: 20KB

BIN
plugins/community/repos/Gratrix/www/res/Seq-G1.png View File

Before After
Width: 450  |  Height: 380  |  Size: 38KB

BIN
plugins/community/repos/Gratrix/www/res/Seq-G2.png View File

Before After
Width: 810  |  Height: 380  |  Size: 59KB

BIN
plugins/community/repos/Gratrix/www/res/VCA-F1.png View File

Before After
Width: 180  |  Height: 380  |  Size: 27KB

BIN
plugins/community/repos/Gratrix/www/res/VCF-F1.png View File

Before After
Width: 270  |  Height: 380  |  Size: 31KB

BIN
plugins/community/repos/Gratrix/www/res/VCO-F1.png View File

Before After
Width: 360  |  Height: 380  |  Size: 35KB

BIN
plugins/community/repos/Gratrix/www/res/VCO-F2.png View File

Before After
Width: 180  |  Height: 380  |  Size: 26KB

BIN
plugins/community/repos/Gratrix/www/res/VU-G1.png View File

Before After
Width: 90  |  Height: 380  |  Size: 10KB

BIN
plugins/community/repos/Gratrix/www/shot.png View File

Before After
Width: 495  |  Height: 570  |  Size: 130KB

+ 1
- 1
plugins/community/repos/ML_modules/src/VoltMeter.cpp View File

@@ -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;
}

+ 7
- 0
plugins/community/repos/RJModules/LICENSE.txt View File

@@ -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.

+ 19
- 0
plugins/community/repos/RJModules/Makefile View File

@@ -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

+ 215
- 0
plugins/community/repos/RJModules/README.md View File

@@ -0,0 +1,215 @@
<img src="https://i.imgur.com/mksL6UX.png" width="100%">

# RJModules [![](https://img.shields.io/badge/version-0.5.0-brightgreen.svg)](https://github.com/Miserlou/RJModules/releases) [![](https://img.shields.io/badge/youtube-demo-red.svg)](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.

+ 33
- 0
plugins/community/repos/RJModules/make.objects View File

@@ -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

+ 7
- 0
plugins/community/repos/RJModules/makefile.msvc View File

@@ -0,0 +1,7 @@
SLUG=RJModules

include ../../../../dep/yac/install_msvc.mk

include make.objects

include ../../../build_plugin.mk

+ 519
- 0
plugins/community/repos/RJModules/res/BPM.svg View File

@@ -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>

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save