├── .gitignore
├── .gitmodules
├── CHANGELOG.md
├── Faust.md
├── LICENSE-GPLv3.txt
├── LICENSE-dist.txt
├── LICENSE.md
├── Makefile
├── README.md
├── examples
├── factorial_router.js
├── gain.js
├── gain.lua
├── gain.pd
├── gain.scd
├── organ.dsp
├── physicalmodel.dsp
├── rainbow.js
├── rainbow.lua
├── rainbow.pd
├── rainbow.scd
├── synth.dsp
├── synth.vult
├── template.js
├── template.lua
├── template.pd
├── template.vult
├── vco.js
├── vco.lua
├── vco.pd
├── vco.scd
└── vco.vult
├── faust_libraries
└── rack.lib
├── plugin.json
├── res
└── Prototype.svg
├── src
├── DuktapeEngine.cpp
├── FaustEngine.cpp
├── LibPDEngine.cpp
├── LuaJITEngine.cpp
├── Prototype.cpp
├── PythonEngine.cpp
├── QuickJSEngine.cpp
├── ScriptEngine.hpp
├── SuperColliderEngine.cpp
└── VultEngine.cpp
├── support
└── supercollider_extensions
│ └── VcvPrototypeProcessBlock.sc
└── tests
├── fall.js
├── hello.lua
├── hello.py
├── process_error.js
├── run_error.js
├── sandbox.js
└── syntax_error.js
/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /dist
3 | /dep
4 | /plugin.so
5 | /plugin.dylib
6 | /plugin.dll
7 | .DS_Store
8 | /faust_libraries
9 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "dep/efsw"]
2 | path = efsw
3 | url = https://github.com/SpartanJ/efsw.git
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### 1.3.0 (in development)
2 | - Add libpd (Pure Data) engine.
3 | - Add Vult engine.
4 | - Add "New script" and "Edit script" menu items to make script creation easier.
5 | - Allow copying display message to clipboard.
6 | - Improve LuaJIT performance by enabling JIT compilation.
7 | - Add `bit` library to LuaJIT engine.
8 |
9 | ### 1.2.0 (2019-11-15)
10 | - Add Lua script engine.
11 | - Add security warning when loading script from patch or module preset.
12 |
13 | ### 1.1.1 (2019-09-27)
14 | - Switch JavaScript engine to QuickJS from Duktape. Supports ES2020 and is ~2x faster.
15 | - Automatically reload script when script file changes.
16 | - Make knobs writable.
17 | - Allow script to be loaded by dragging-and-dropping on the panel.
18 | - Add "Save script as" in panel context menu.
19 | - Reload script on initialize.
20 |
21 | ### 1.1.0 (2019-09-15)
22 | - Add block buffering with `config.bufferSize`.
23 | - Scripts must change `inputs[i]` to `inputs[i][0]` and `outputs[i]` to `outputs[i][0]`.
24 | - Allow multiple lines of text in LED display.
25 | - Duktape (JavaScript):
26 | - Use array instead of object for RGB lights and switch lights.
27 | - Scripts must change `.r` to `[0]`, `.g` to `[1]`, and `.b` to `[2]` for `lights` and `switchLights`.
28 | - Use ArrayBuffers instead of arrays, improving performance \~5x.
29 |
30 | ### 1.0.0 (2019-09-15)
31 | - Initial release.
32 |
--------------------------------------------------------------------------------
/Faust.md:
--------------------------------------------------------------------------------
1 | # Using Faust DSP language in VCV Prototype
2 |
3 | The [Faust audio DSP language](https://faust.grame.fr) can be used in VCV Prototype. The compiler can be embedded in applications or plugins using [libfaust](https://faustdoc.grame.fr/manual/embedding/), and DSP code can be edited and JIT compiled on the fly.
4 |
5 | Note that to facilitate compilation and deployement, the interpreter backend is used instead of the [LLVM IR](https://llvm.org) backend (faster produced DSP code).
6 |
7 | ## Compilation
8 |
9 | - type `make && make install` to build it
10 | - you can now add a Faust aware VCV Prototype in your Rack session and start coding in Faust
11 |
12 | ## Loading/editing/compiling .dsp files
13 |
14 | Faust DSP files have to be loaded in VCV Prototype and edited in a external editor (Visual Studio Code, Atom...). Each time the file is saved, it will be recompiled and executed. To possibly save compilation time, the DSP machine code is saved in a cache, and possibly restored the next time the session will be loaded.
15 |
16 | The 6 *switches*, *knobs* as well as the *lights* and *switchLights* can be connected to UI controllers using metadata:
17 |
18 | - `[switch:N]` (with N from 1 to 6) has to be used in a `button` or `checkbox` item to connect it to the prototype interface switch number N. Pushed buttons will become red when on, and checkboxes will become white when on.
19 | - `[knob:N]` (with N from 1 to 6) has to be used in a `vslider`, `hslider` or `nentry` item to connect it to the prototype interface knob number N. The knob [0..1] range will be mapped to the slider/nentry [min..max] range.
20 | - `[light_red|green|red:N]` (with N from 1 to 6) has to be used in a `vbargraph` or `hbargraph` item to connect it to the prototype interface light number N.
21 | - `[switchlight_red|green|red:N]` (with N from 1 to 6) has to be used in a `vbargraph` or `hbargraph` to connect it to the prototype interface switchLight number N.
22 |
23 | Other metadata:
24 | - `[scale:lin|log|exp]` metadata is implemented.
25 |
26 | The [faust_libraries/rack.lib](https://github.com/sletz/VCV-Prototype/blob/master/faust_libraries/rack.lib) Faust library contains useful functions to convert VC signals, and can be enriched if needed.
27 |
28 | ## DSP examples
29 |
30 | Here is a simple example showing how oscillators can be controlled by UI items:
31 |
32 | ```
33 | import("stdfaust.lib");
34 |
35 | // UI controllers connected using metadata
36 | freq = hslider("freq [knob:1]", 200, 50, 5000, 0.01);
37 | gain = hslider("gain [knob:2]", 0.5, 0, 1, 0.01);
38 | gate = button("gate [switch:1]");
39 |
40 | // DSP processor
41 | process = os.osc(freq) * gain, os.sawtooth(freq) * gain * gate;
42 | ```
43 |
44 | Some additional files can be seen in the examples folder:
45 |
46 | - [synth.dsp](https://github.com/VCVRack/VCV-Prototype/blob/v1/examples/synth.dsp) demonstrates how to use all different VCV Prototype UI items
47 | - [organ.dsp](https://github.com/VCVRack/VCV-Prototype/blob/v1/examples/organ.dsp) demonstrates a MIDI controllable additive synthesis based organ
48 | - [physicalmodel.dsp](https://github.com/VCVRack/VCV-Prototype/blob/v1/examples/physicalmodel.dsp) demonstrates a modal synthesis based bell connected to a reverb
49 |
--------------------------------------------------------------------------------
/LICENSE-dist.txt:
--------------------------------------------------------------------------------
1 | # Duktape
2 |
3 | Copyright (c) 2013-2019 by Duktape authors (see AUTHORS.rst)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | All **source code** is copyright © 2019-2020 Andrew Belt and VCV Prototype contributors.
2 |
3 | This program is free software: you can redistribute it and/or modify it under the terms of the [GNU General Public License](https://www.gnu.org/licenses/gpl-3.0.en.html) as published by the [Free Software Foundation](https://www.fsf.org/), either version 3 of the License, or (at your option) any later version.
4 |
5 | All **example scripts** in the `examples` directory are licensed under [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode) (public domain).
6 |
7 | The **panel graphics** in the `res` directory are copyright © 2019 [Grayscale](http://grayscale.info/) and licensed under [CC BY-NC-ND 4.0](https://creativecommons.org/licenses/by-nc-nd/4.0/).
8 | You may not distribute modified adaptations of these graphics.
9 |
10 | **Dependencies** included in the binary distributable may have other licenses.
11 | See [LICENSE-dist.txt](LICENSE-dist.txt) for a full list.
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | RACK_DIR ?= ../..
2 |
3 | FLAGS += -Idep/include
4 | CFLAGS +=
5 | CXXFLAGS +=
6 |
7 | LDFLAGS +=
8 | SOURCES += src/Prototype.cpp
9 |
10 | DISTRIBUTABLES += res examples
11 | DISTRIBUTABLES += $(wildcard LICENSE*)
12 |
13 | include $(RACK_DIR)/arch.mk
14 |
15 | DUKTAPE ?= 0
16 | QUICKJS ?= 1
17 | LUAJIT ?= 1
18 | PYTHON ?= 0
19 | SUPERCOLLIDER ?= 1
20 | VULT ?= 1
21 | LIBPD ?= 1
22 | FAUST ?= 1
23 |
24 | # Vult depends on both LuaJIT and QuickJS
25 | ifeq ($(VULT), 1)
26 | QUICKJS := 1
27 | LUAJIT := 1
28 | endif
29 |
30 |
31 | # Entropia File System Watcher
32 | ifdef ARCH_WIN
33 | efsw := dep/lib/efsw-static-release.lib
34 | else
35 | efsw := dep/lib/libefsw-static-release.a
36 | endif
37 | DEPS += $(efsw)
38 | OBJECTS += $(efsw)
39 | $(efsw):
40 | ifdef ARCH_WIN
41 | cd efsw && premake5 gmake
42 | cd efsw && $(MAKE) -C make/* config=release_x86_64 efsw-static-lib
43 | else
44 | cd efsw && premake4 gmake
45 | cd efsw && $(MAKE) -C make/* config=release efsw-static-lib
46 | endif
47 | mkdir -p dep/lib dep/include
48 | ifdef ARCH_WIN
49 | cd efsw && cp lib/efsw-static-release.lib $(DEP_PATH)/lib/
50 | else
51 | cd efsw && cp lib/libefsw-static-release.a $(DEP_PATH)/lib/
52 | endif
53 | cd efsw && cp -R include/efsw $(DEP_PATH)/include/
54 |
55 |
56 | # Duktape
57 | ifeq ($(DUKTAPE), 1)
58 | SOURCES += src/DuktapeEngine.cpp
59 | duktape := dep/duktape-2.4.0/src/duktape.c
60 | DEPS += $(duktape)
61 | SOURCES += $(duktape)
62 | FLAGS += -Idep/duktape-2.4.0/src
63 | $(duktape):
64 | $(WGET) "https://duktape.org/duktape-2.4.0.tar.xz"
65 | $(SHA256) duktape-2.4.0.tar.xz 86a89307d1633b5cedb2c6e56dc86e92679fc34b05be551722d8cc69ab0771fc
66 | cd dep && $(UNTAR) ../duktape-2.4.0.tar.xz
67 | endif
68 |
69 |
70 | # QuickJS
71 | ifeq ($(QUICKJS), 1)
72 | SOURCES += src/QuickJSEngine.cpp
73 | quickjs := dep/lib/quickjs/libquickjs.a
74 | DEPS += $(quickjs)
75 | OBJECTS += $(quickjs)
76 | QUICKJS_MAKE_FLAGS += prefix="$(DEP_PATH)"
77 | ifdef ARCH_WIN
78 | QUICKJS_MAKE_FLAGS += CONFIG_WIN32=y
79 | endif
80 | $(quickjs):
81 | cd dep && git clone "https://github.com/JerrySievert/QuickJS.git"
82 | cd dep/QuickJS && git checkout 807adc8ca9010502853d471bd8331cdc1d376b94
83 | cd dep/QuickJS && $(MAKE) $(QUICKJS_MAKE_FLAGS) install
84 | endif
85 |
86 |
87 | # LuaJIT
88 | ifeq ($(LUAJIT), 1)
89 | SOURCES += src/LuaJITEngine.cpp
90 | luajit := dep/lib/libluajit-5.1.a
91 | OBJECTS += $(luajit)
92 | DEPS += $(luajit)
93 | $(luajit):
94 | $(WGET) "http://luajit.org/download/LuaJIT-2.0.5.tar.gz"
95 | $(SHA256) LuaJIT-2.0.5.tar.gz 874b1f8297c697821f561f9b73b57ffd419ed8f4278c82e05b48806d30c1e979
96 | cd dep && $(UNTAR) ../LuaJIT-2.0.5.tar.gz
97 | cd dep/LuaJIT-2.0.5 && $(MAKE) BUILDMODE=static PREFIX="$(DEP_PATH)" install
98 | endif
99 |
100 |
101 | # SuperCollider
102 | ifeq ($(SUPERCOLLIDER), 1)
103 | SOURCES += src/SuperColliderEngine.cpp
104 | FLAGS += -Idep/supercollider/include -Idep/supercollider/include/common -Idep/supercollider/lang -Idep/supercollider/common -Idep/supercollider/include/plugin_interface
105 | # FLAGS += -DSC_VCV_ENGINE_TIMING # uncomment to turn on timing printing while running
106 | supercollider := dep/supercollider/build/lang/libsclang.a
107 | OBJECTS += $(supercollider)
108 | DEPS += $(supercollider)
109 | DISTRIBUTABLES += dep/supercollider/SCClassLibrary
110 | DISTRIBUTABLES += support/supercollider_extensions
111 | SUPERCOLLIDER_CMAKE_FLAGS += -DSUPERNOVA=0 -DSC_EL=0 -DSC_VIM=0 -DSC_ED=0 -DSC_IDE=0 -DSC_ABLETON_LINK=0 -DSC_QT=0 -DCMAKE_BUILD_TYPE=Release -DSCLANG_SERVER=0 -DBUILD_TESTING=0 -DNO_LIBSNDFILE=1
112 | SUPERCOLLIDER_SUBMODULES += external_libraries/hidapi external_libraries/nova-simd external_libraries/nova-tt external_libraries/portaudio_sc_org external_libraries/yaml-cpp
113 | SUPERCOLLIDER_BRANCH := topic/vcv-prototype-support
114 |
115 | OBJECTS += dep/supercollider/build/external_libraries/libtlsf.a
116 | OBJECTS += dep/supercollider/build/external_libraries/hidapi/linux/libhidapi.a
117 | OBJECTS += dep/supercollider/build/external_libraries/hidapi/hidapi_parser/libhidapi_parser.a
118 | OBJECTS += dep/supercollider/build/external_libraries/libboost_thread_lib.a
119 | OBJECTS += dep/supercollider/build/external_libraries/libboost_system_lib.a
120 | OBJECTS += dep/supercollider/build/external_libraries/libboost_regex_lib.a
121 | OBJECTS += dep/supercollider/build/external_libraries/libboost_filesystem_lib.a
122 | OBJECTS += dep/supercollider/build/external_libraries/libyaml.a
123 |
124 | LDFLAGS += -lpthread -lasound -ludev
125 |
126 | $(supercollider):
127 | cd dep && git clone "https://github.com/supercollider/supercollider" --branch $(SUPERCOLLIDER_BRANCH) --depth 1
128 | cd dep/supercollider && git checkout 84b14d10d49edce6dd8303045a884fb7f2bc92e8
129 | cd dep/supercollider && git submodule update --depth 1 --init -- $(SUPERCOLLIDER_SUBMODULES)
130 | cd dep/supercollider && mkdir build
131 | cd dep/supercollider/build && $(CMAKE) .. $(SUPERCOLLIDER_CMAKE_FLAGS)
132 | cd dep/supercollider/build && $(MAKE) libsclang
133 | endif
134 |
135 |
136 | # Python
137 | ifeq ($(PYTHON), 1)
138 | SOURCES += src/PythonEngine.cpp
139 | # Note this is a dynamic library, not static.
140 | python := dep/lib/libpython3.8.so.1.0
141 | DEPS += $(python) $(numpy)
142 | FLAGS += -Idep/include/python3.8
143 | # TODO Test these flags on all platforms
144 | # Make dynamic linker look in the plugin folder for libpython.
145 | LDFLAGS += -Wl,-rpath,'$$ORIGIN'/dep/lib
146 | LDFLAGS += -Ldep/lib -lpython3.8
147 | LDFLAGS += -lcrypt -lpthread -ldl -lutil -lm
148 | DISTRIBUTABLES += $(python)
149 | DISTRIBUTABLES += dep/lib/python3.8
150 | $(python):
151 | $(WGET) "https://www.python.org/ftp/python/3.8.0/Python-3.8.0.tar.xz"
152 | $(SHA256) Python-3.8.0.tar.xz b356244e13fb5491da890b35b13b2118c3122977c2cd825e3eb6e7d462030d84
153 | cd dep && $(UNTAR) ../Python-3.8.0.tar.xz
154 | cd dep/Python-3.8.0 && $(CONFIGURE) --build=$(MACHINE) --enable-shared --enable-optimizations
155 | cd dep/Python-3.8.0 && $(MAKE) build_all
156 | cd dep/Python-3.8.0 && $(MAKE) install
157 |
158 | numpy := dep/lib/python3.8/site-packages/numpy
159 | FLAGS += -Idep/lib/python3.8/site-packages/numpy/core/include
160 | $(numpy): $(python)
161 | $(WGET) "https://github.com/numpy/numpy/releases/download/v1.17.3/numpy-1.17.3.tar.gz"
162 | $(SHA256) numpy-1.17.3.tar.gz c93733dbebc2599d2747ceac4b18825a73767d289176ed8e02090325656d69aa
163 | cd dep && $(UNTAR) ../numpy-1.17.3.tar.gz
164 | # Don't try to find an external BLAS and LAPACK library.
165 | # Don't install to an egg folder.
166 | # Make sure to use our built Python.
167 | cd dep/numpy-1.17.3 && LD_LIBRARY_PATH=../lib NPY_BLAS_ORDER= NPY_LAPACK_ORDER= "$(DEP_PATH)"/bin/python3.8 setup.py build -j4 install --single-version-externally-managed --root=/
168 |
169 | # scipy: $(numpy)
170 | # $(WGET) "https://github.com/scipy/scipy/releases/download/v1.3.1/scipy-1.3.1.tar.xz"
171 | # $(SHA256) scipy-1.3.1.tar.xz 326ffdad79f113659ed0bca80f5d0ed5e28b2e967b438bb1f647d0738073a92e
172 | # cd dep && $(UNTAR) ../scipy-1.3.1.tar.xz
173 | # cd dep/scipy-1.3.1 && "$(DEP_PATH)"/bin/python3.7 setup.py build -j4 install
174 | endif
175 |
176 | # # Julia
177 | # julia := dep/lib/libjulia.a
178 | # DEPS += $(julia)
179 | # $(julia):
180 | # $(WGET) "https://github.com/JuliaLang/julia/releases/download/v1.2.0/julia-1.2.0-full.tar.gz"
181 | # $(SHA256) julia-1.2.0-full.tar.gz 2419b268fc5c3666dd9aeb554815fe7cf9e0e7265bc9b94a43957c31a68d9184
182 | # cd dep && $(UNTAR) ../julia-1.2.0-full.tar.gz
183 |
184 | # # Csound
185 | # csound := dep/lib/libcsound.a
186 | # DEPS += $(csound)
187 | # $(csound):
188 | # $(WGET) "https://github.com/csound/csound/archive/6.13.0.tar.gz"
189 | # $(SHA256) 6.13.0.tar.gz 183beeb3b720bfeab6cc8af12fbec0bf9fef2727684ac79289fd12d0dfee728b
190 | # cd dep && $(UNTAR) ../6.13.0.tar.gz
191 |
192 | # # LLVM
193 | # llvm := dep/lib/libllvm.a
194 | # DEPS += $(llvm)
195 | # $(llvm):
196 | # $(WGET) "https://github.com/llvm/llvm-project/releases/download/llvmorg-8.0.1/llvm-8.0.1.src.tar.xz"
197 | # $(SHA256) llvm-8.0.1.src.tar.xz 44787a6d02f7140f145e2250d56c9f849334e11f9ae379827510ed72f12b75e7
198 | # cd dep && $(UNTAR) ../llvm-8.0.1.src.tar.xz
199 | # cd dep/llvm-8.0.1.src && mkdir -p build
200 | # cd dep/llvm-8.0.1.src/build && $(CMAKE) ..
201 | # cd dep/llvm-8.0.1.src/build && $(MAKE)
202 | # cd dep/llvm-8.0.1.src/build && $(MAKE) install
203 |
204 |
205 | # Vult
206 | ifeq ($(VULT), 1)
207 | SOURCES += src/VultEngine.cpp
208 | vult := dep/vult/vultc.h
209 | $(vult):
210 | cd dep && mkdir -p vult
211 | cd dep/vult && $(WGET) "https://github.com/modlfo/vult/releases/download/v0.4.12/vultc.h"
212 | $(SHA256) $(vult) 3e80f6d30defe7df2804568f0314dbb33e6bf69d53d18a804c8b8132cf5ad146
213 | FLAGS += -Idep/vult
214 | DEPS += $(vult)
215 | endif
216 |
217 |
218 | # LibPD
219 | ifeq ($(LIBPD), 1)
220 | libpd := dep/lib/libpd.a
221 | SOURCES += src/LibPDEngine.cpp
222 | OBJECTS += $(libpd)
223 | DEPS += $(libpd)
224 | FLAGS += -Idep/include/libpd -DHAVE_LIBDL
225 |
226 | ifdef ARCH_WIN
227 | # PD_INTERNAL leaves the function declarations for libpd unchanged
228 | # not specifying that flag would enable the "EXTERN __declspec(dllexport) extern" macro
229 | # which throws a linker error. I guess this macro should only be used for the windows
230 | # specific .dll dynamic linking format.
231 | # The corresponding #define resides in "m_pd.h" inside th Pure Data sources
232 | FLAGS += -DPD_INTERNAL -Ofast
233 | LDFLAGS += -Wl,--export-all-symbols
234 | LDFLAGS += -lws2_32
235 | endif
236 |
237 | $(libpd):
238 | cd dep && git clone "https://github.com/libpd/libpd.git" --recursive
239 | cd dep/libpd && git checkout 5772a612527f06597d44d195843307ad0e3578fe
240 |
241 | ifdef ARCH_MAC
242 | # libpd's Makefile is handmade, and it doesn't honor CFLAGS and LDFLAGS environments.
243 | # So in order for Mac 10.15 (for example) to make a build that works on Mac 10.7+, we have to manually add DEP_MAC_SDK_FLAGS to CFLAGS and LDFLAGS.
244 | # We can't just add the environment's CFLAGS/LDFLAGS because `-march=nocona` makes libpd segfault when initialized.
245 | # Perhaps inline assembly is used in libpd? Who knows.
246 | cd dep/libpd && $(MAKE) MULTI=true STATIC=true ADDITIONAL_CFLAGS='-DPD_LONGINTTYPE="long long" $(DEP_MAC_SDK_FLAGS) -stdlib=libc++' ADDITIONAL_LDFLAGS='$(DEP_MAC_SDK_FLAGS) -stdlib=libc++'
247 | else
248 | cd dep/libpd && $(MAKE) MULTI=true STATIC=true ADDITIONAL_CFLAGS='-DPD_LONGINTTYPE="long long"'
249 | endif
250 | cd dep/libpd && $(MAKE) install prefix="$(DEP_PATH)"
251 | endif
252 |
253 |
254 | # Faust
255 | ifeq ($(FAUST), 1)
256 | libfaust := dep/lib/libfaust.a
257 | SOURCES += src/FaustEngine.cpp
258 | OBJECTS += $(libfaust)
259 | DEPS += $(libfaust)
260 | FLAGS += -DINTERP
261 | DISTRIBUTABLES += faust_libraries
262 |
263 | # Test using LLVM
264 | #LDFLAGS += -L/usr/local/lib -lfaust
265 |
266 | # Test using MIR
267 | #LDFLAGS += -L/usr/local/lib -lfaust dep/lib/mir-gen.o dep/lib/mir.o
268 |
269 | $(libfaust):
270 | cd dep && git clone "https://github.com/grame-cncm/faust.git" --recursive
271 | cd dep/faust && git checkout 1dfc452a8250f3123b5100edf8c882e1cea407a1
272 | cd dep/faust/build && make cmake BACKENDS=interp.cmake TARGETS=interp.cmake
273 | cd dep/faust/build && make install PREFIX="$(DEP_PATH)"
274 | cp -r dep/faust/libraries/* faust_libraries/
275 | rm -rf faust_libraries/doc
276 | rm -rf faust_libraries/docs
277 |
278 | endif
279 |
280 | include $(RACK_DIR)/plugin.mk
281 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # VCV Prototype
2 |
3 | Scripting language host for [VCV Rack](https://vcvrack.com/) containing:
4 | - 6 inputs
5 | - 6 outputs
6 | - 6 knobs
7 | - 6 lights (RGB LEDs)
8 | - 6 switches with RGB LEDs
9 |
10 | Supported scripting languages:
11 | - JavaScript (ES2020) (.js)
12 | - [Lua](https://www.lua.org/) (.lua)
13 | - [Vult](https://github.com/modlfo/vult) (.vult)
14 | - [Pure Data](https://puredata.info) (.pd)
15 | - [Faust](https://faust.grame.fr) (.dsp)
16 | - [SuperCollider](https://supercollider.github.io) (.scd)
17 | - [Add your own below](#adding-a-script-engine)
18 |
19 | [Discussion thread](https://community.vcvrack.com/t/vcv-prototype/3271)
20 |
21 | ## Scripting API
22 |
23 | This is the reference API for the JavaScript script engine, along with default property values.
24 | Other script engines may vary in their syntax (e.g. `block.inputs[i][j]` vs `block.getInput(i, j)` vs `input(i, j)`), but the functionality should be similar.
25 |
26 | ```js
27 | /** Display message on LED display.
28 | */
29 | display(message)
30 |
31 | /** Skip this many sample frames before running process().
32 | For CV generators and processors, 256 is reasonable.
33 | For sequencers, 32 is reasonable since process() will be called every 0.7ms with
34 | a 44100kHz sample rate, which will capture 1ms-long triggers.
35 | For audio generators and processors, 1 is recommended, but use `bufferSize` below.
36 | If this is too slow for your purposes, consider writing a C++ plugin, since
37 | native VCV Rack plugins have 10-100x better performance.
38 | */
39 | config.frameDivider // 32
40 |
41 | /** Instead of calling process() every sample frame, hold this many input/output
42 | voltages in a buffer and call process() when it is full.
43 | This decreases CPU usage, since processing buffers is faster than processing one
44 | frame at a time.
45 | The total latency of your script in seconds is
46 | `config.frameDivider * config.bufferSize * block.sampleTime`.
47 | */
48 | config.bufferSize // 1
49 |
50 | /** Called when the next block is ready to be processed.
51 | */
52 | function process(block) {
53 | /** Engine sample rate in Hz. Read-only.
54 | */
55 | block.sampleRate
56 |
57 | /** Engine sample timestep in seconds. Equal to `1 / sampleRate`. Read-only.
58 | Note that the actual time between process() calls is
59 | `block.sampleTime * config.frameDivider`.
60 | */
61 | block.sampleTime
62 |
63 | /** The actual size of the input/output buffers.
64 | */
65 | block.bufferSize
66 |
67 | /** Voltage of the input port of column `i`. Read-only.
68 | */
69 | block.inputs[i][bufferIndex] // 0.0
70 |
71 | /** Voltage of the output port of column `i`. Read/write.
72 | */
73 | block.outputs[i][bufferIndex] // 0.0
74 |
75 | /** Value of the knob of column `i`. Between 0 and 1. Read/write.
76 | */
77 | block.knobs[i] // 0.0
78 |
79 | /** Pressed state of the switch of column `i`. Read-only.
80 | */
81 | block.switches[i] // false
82 |
83 | /** Brightness of the RGB LED of column `i`, between 0 and 1. Read/write.
84 | */
85 | block.lights[i][0] // 0.0 (red)
86 | block.lights[i][1] // 0.0 (green)
87 | block.lights[i][2] // 0.0 (blue)
88 |
89 | /** Brightness of the switch RGB LED of column `i`. Read/write.
90 | */
91 | block.switchLights[i][0] // 0.0 (red)
92 | block.switchLights[i][1] // 0.0 (green)
93 | block.switchLights[i][2] // 0.0 (blue)
94 | }
95 | ```
96 |
97 | *The Vult API is slightly different than Prototype's scripting API.
98 | See `examples/template.vult` for a reference of the Vult API.*
99 |
100 | ## Build dependencies
101 |
102 | Set up your build environment like described here, including the dependencies: https://vcvrack.com/manual/Building
103 |
104 | Additionally:
105 |
106 | ### Windows
107 | ```bash
108 | pacman -S mingw-w64-x86_64-premake
109 | ```
110 |
111 | ### Mac
112 | ```bash
113 | brew install premake
114 | ```
115 |
116 | ### Ubuntu 16.04+
117 | ```bash
118 | sudo apt install premake4
119 | ```
120 |
121 | ### Arch Linux
122 | ```bash
123 | sudo pacman -S premake
124 | ```
125 |
126 | ## Build
127 | ### Add path to Rack-SDK
128 | ```bash
129 | export RACK_DIR=/set/path/to/Rack-SDK/
130 | ```
131 |
132 | ### load submodules
133 | ```bash
134 | git submodule update --init --recursive
135 | ```
136 |
137 | ### Make
138 | ```bash
139 | make dep
140 | make
141 | ```
142 |
143 | ## Adding a script engine
144 |
145 | - Add your scripting language library to the build system so it builds with `make dep`, following the Duktape example in `Makefile`.
146 | - Create a `MyEngine.cpp` file (for example) in `src/` with a `ScriptEngine` subclass defining the virtual methods, using `src/DuktapeEngine.cpp` as an example.
147 | - Build and test the plugin.
148 | - Add a few example scripts and tests to `examples/`. These will be included in the plugin package for the user.
149 | - Add your name to the Contributors list below.
150 | - Send a pull request. Once merged, you will be added as a repo maintainer. Be sure to "watch" this repo to be notified of bug reports and feature requests for your engine.
151 |
152 | ## Contributors
153 |
154 | - [Wes Milholen](https://grayscale.info/): panel design
155 | - [Andrew Belt](https://github.com/AndrewBelt): host code, Duktape (JavaScript, not used), LuaJIT (Lua), Python (in development)
156 | - [Jerry Sievert](https://github.com/JerrySievert): QuickJS (JavaScript)
157 | - [Leonardo Laguna Ruiz](https://github.com/modlfo): Vult
158 | - [CHAIR](https://chair.audio) (Clemens Wegener, Max Neupert): libpd
159 | - [GRAME](https://github.com/grame-cncm): Faust
160 | - [Moss Heim](https://github.com/mossheim): Supercollider
161 | - add your name here
162 |
--------------------------------------------------------------------------------
/examples/factorial_router.js:
--------------------------------------------------------------------------------
1 | /**
2 | Factorial router
3 | by Andrew Belt
4 |
5 | There are 120 ways to route 5 inputs into 5 outputs.
6 | This uses input 6 as a CV control to choose the particular permutation.
7 | The CV is split into 120 intervals, each corresponding to a permutation of the inputs 1 through 5.
8 | */
9 |
10 | function permutation(arr, k) {
11 | let n = arr.length
12 | // Clone array
13 | arr = arr.slice(0)
14 | // Compute n!
15 | let factorial = 1
16 | for (let i = 2; i <= n; i++) {
17 | factorial *= i
18 | }
19 |
20 | // Build permutation array by selecting the j'th element from the remaining elements until all are chosen.
21 | let perm = []
22 | for (let i = n; i >= 1; i--) {
23 | factorial /= i
24 | let j = Math.floor(k / factorial)
25 | k %= factorial
26 | let el = arr[j]
27 | arr.splice(j, 1)
28 | perm.push(el)
29 | }
30 |
31 | return perm
32 | }
33 |
34 | config.bufferSize = 16
35 |
36 | function process(block) {
37 | // Get factorial index from input 6
38 | let k = Math.floor(block.inputs[5][0] / 10 * 120)
39 | k = Math.min(Math.max(k, 0), 120 - 1)
40 | // Get index set permutation
41 | let perm = permutation([1, 2, 3, 4, 5], k)
42 | display(perm.join(", "))
43 | for (let i = 0; i < 5; i++) {
44 | // Permute input i
45 | for (let j = 0; j < block.bufferSize; j++) {
46 | block.outputs[i][j] = block.inputs[perm[i] - 1][j]
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/examples/gain.js:
--------------------------------------------------------------------------------
1 | // Simplest possible script using all variables, demonstrating buffering
2 | // by Andrew Belt
3 |
4 | config.frameDivider = 1
5 | config.bufferSize = 32
6 |
7 | function process(block) {
8 | // Loop through each column
9 | for (let i = 0; i < 6; i++) {
10 | // Get gain knob
11 | let gain = block.knobs[i]
12 | // Set gain light (red = 0)
13 | block.lights[i][0] = gain
14 | // Check mute switch
15 | if (block.switches[i]) {
16 | // Mute output
17 | gain = 0
18 | // Enable mute light (red = 0)
19 | block.switchLights[i][0] = 1
20 | }
21 | else {
22 | // Disable mute light
23 | block.switchLights[i][0] = 0
24 | }
25 | // Iterate input/output buffer
26 | for (let j = 0; j < block.bufferSize; j++) {
27 | // Get input
28 | let x = block.inputs[i][j]
29 | // Apply gain to input
30 | let y = x * gain
31 | // Set output
32 | block.outputs[i][j] = y
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/examples/gain.lua:
--------------------------------------------------------------------------------
1 | -- Simplest possible script using all variables, demonstrating buffering
2 | -- by Andrew Belt
3 |
4 | config.frameDivider = 1
5 | config.bufferSize = 32
6 |
7 | function process(block)
8 | -- Loop through each column
9 | for i=1,6 do
10 | -- Get gain knob
11 | gain = block.knobs[i]
12 | -- Set gain light (red = 1)
13 | block.lights[i][1] = gain
14 | -- Check mute switch
15 | if block.switches[i] then
16 | -- Mute output
17 | gain = 0
18 | -- Enable mute light (red = 1)
19 | block.switchLights[i][1] = 1
20 | else
21 | -- Disable mute light
22 | block.switchLights[i][1] = 0
23 | end
24 | -- Iterate input/output buffer
25 | for j=1,block.bufferSize do
26 | -- Get input
27 | x = block.inputs[i][j]
28 | -- Apply gain to input
29 | y = x * gain
30 | -- Set output
31 | block.outputs[i][j] = y
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/examples/gain.pd:
--------------------------------------------------------------------------------
1 | #N canvas 837 209 813 659 12;
2 | #X obj 104 30 adc~ 1 2 3 4 5 6, f 47;
3 | #X obj 105 261 dac~ 1 2 3 4 5 6, f 47;
4 | #X obj 104 98 *~ 1;
5 | #X obj 169 98 *~ 1;
6 | #X obj 233 98 *~ 1;
7 | #X obj 299 98 *~ 1;
8 | #X obj 363 98 *~ 1;
9 | #X obj 429 98 *~ 1;
10 | #X msg 171 365 L3 \$1 0 0;
11 | #X msg 247 365 L4 \$1 0 0;
12 | #X msg 397 365 L6 \$1 0 0;
13 | #X msg 21 365 L1 \$1 0 0;
14 | #X msg 96 365 L2 \$1 0 0;
15 | #X msg 322 365 L5 \$1 0 0;
16 | #X obj 105 229 *~ 1;
17 | #X obj 170 228 *~ 1;
18 | #X obj 234 228 *~ 1;
19 | #X obj 300 228 *~ 1;
20 | #X obj 364 228 *~ 1;
21 | #X obj 430 228 *~ 1;
22 | #X msg 21 521 S1 \$1 0 0;
23 | #X msg 96 522 S2 \$1 0 0;
24 | #X msg 171 522 S3 \$1 0 0;
25 | #X msg 247 523 S4 \$1 0 0;
26 | #X msg 322 523 S5 \$1 0 0;
27 | #X msg 397 523 S6 \$1 0 0;
28 | #X obj 129 70 route K1 K2 K3 K4 K5 K6, f 56;
29 | #X obj 130 169 route S1 S2 S3 S4 S5 S6, f 56;
30 | #X obj 130 198 == 0;
31 | #X obj 195 198 == 0;
32 | #X obj 259 198 == 0;
33 | #X obj 325 198 == 0;
34 | #X obj 389 198 == 0;
35 | #X obj 455 198 == 0;
36 | #X obj 21 336 route K1 K2 K3 K4 K5 K6, f 65;
37 | #X obj 21 492 route S1 S2 S3 S4 S5 S6, f 65;
38 | #X text 541 368 Just using the red channels in the RGB triplet for
39 | the LED., f 35;
40 | #X text 542 492 Same for the switch., f 35;
41 | #X obj 21 569 print toRack;
42 | #X obj 20 30 r fromRack;
43 | #X obj 19 134 r fromRack;
44 | #X obj 21 307 r fromRack;
45 | #X obj 21 422 print toRack;
46 | #X obj 21 463 r fromRack;
47 | #X text 539 52 Usually we'd interpolate here with line~ but VCVRack
48 | is already sending one message per sample so there seems hardly a point
49 | to complicate this example., f 38;
50 | #X connect 0 0 2 0;
51 | #X connect 0 1 3 0;
52 | #X connect 0 2 4 0;
53 | #X connect 0 3 5 0;
54 | #X connect 0 4 6 0;
55 | #X connect 0 5 7 0;
56 | #X connect 2 0 14 0;
57 | #X connect 3 0 15 0;
58 | #X connect 4 0 16 0;
59 | #X connect 5 0 17 0;
60 | #X connect 6 0 18 0;
61 | #X connect 7 0 19 0;
62 | #X connect 8 0 42 0;
63 | #X connect 9 0 42 0;
64 | #X connect 10 0 42 0;
65 | #X connect 11 0 42 0;
66 | #X connect 12 0 42 0;
67 | #X connect 13 0 42 0;
68 | #X connect 14 0 1 0;
69 | #X connect 15 0 1 1;
70 | #X connect 16 0 1 2;
71 | #X connect 17 0 1 3;
72 | #X connect 18 0 1 4;
73 | #X connect 19 0 1 5;
74 | #X connect 20 0 38 0;
75 | #X connect 21 0 38 0;
76 | #X connect 22 0 38 0;
77 | #X connect 23 0 38 0;
78 | #X connect 24 0 38 0;
79 | #X connect 25 0 38 0;
80 | #X connect 26 0 2 1;
81 | #X connect 26 1 3 1;
82 | #X connect 26 2 4 1;
83 | #X connect 26 3 5 1;
84 | #X connect 26 4 6 1;
85 | #X connect 26 5 7 1;
86 | #X connect 27 0 28 0;
87 | #X connect 27 1 29 0;
88 | #X connect 27 2 30 0;
89 | #X connect 27 3 31 0;
90 | #X connect 27 4 32 0;
91 | #X connect 27 5 33 0;
92 | #X connect 28 0 14 1;
93 | #X connect 29 0 15 1;
94 | #X connect 30 0 16 1;
95 | #X connect 31 0 17 1;
96 | #X connect 32 0 18 1;
97 | #X connect 33 0 19 1;
98 | #X connect 34 0 11 0;
99 | #X connect 34 1 12 0;
100 | #X connect 34 2 8 0;
101 | #X connect 34 3 9 0;
102 | #X connect 34 4 13 0;
103 | #X connect 34 5 10 0;
104 | #X connect 35 0 20 0;
105 | #X connect 35 1 21 0;
106 | #X connect 35 2 22 0;
107 | #X connect 35 3 23 0;
108 | #X connect 35 4 24 0;
109 | #X connect 35 5 25 0;
110 | #X connect 39 0 26 0;
111 | #X connect 40 0 27 0;
112 | #X connect 41 0 34 0;
113 | #X connect 43 0 35 0;
114 |
--------------------------------------------------------------------------------
/examples/gain.scd:
--------------------------------------------------------------------------------
1 | // Simplest possible script using all variables, demonstrating buffering
2 | // by Andrew Belt
3 | // adapted for SC by Brian Heim
4 |
5 | ~vcv_frameDivider = 1;
6 | ~vcv_bufferSize = 32;
7 |
8 | ~vcv_process = { |block|
9 | // Loop through each row
10 | VcvPrototypeProcessBlock.numRows.do { |i|
11 | // Get gain knob
12 | var gain = block.knobs[i];
13 | // Set gain light (red = 0)
14 | block.lights[i][0] = gain;
15 |
16 | // Check mute switch
17 | block.switchLights[i][0] = if (block.switches[i]) {
18 | // Mute output
19 | gain = 0;
20 | // Enable mute light (red = 0)
21 | 1
22 | } {
23 | // Disable mute light
24 | 0
25 | };
26 |
27 | // Iterate input/output buffer
28 | block.outputs[i] = block.inputs[i] * gain;
29 | };
30 |
31 | block
32 | }
33 |
--------------------------------------------------------------------------------
/examples/organ.dsp:
--------------------------------------------------------------------------------
1 | import("stdfaust.lib");
2 | import("rack.lib");
3 |
4 | vol = hslider("vol [knob:1]", 0.3, 0, 10, 0.01);
5 | pan = hslider("pan [knob:2]", 0.5, 0, 1, 0.01);
6 |
7 | attack = hslider("attack", 0.01, 0, 1, 0.001);
8 | decay = hslider("decay", 0.3, 0, 1, 0.001);
9 | sustain = hslider("sustain", 0.5, 0, 1, 0.01);
10 | release = hslider("release", 0.2, 0, 1, 0.001);
11 |
12 | panner(c) = _ <: *(1-c), *(c);
13 |
14 | voice(freq) = os.osc(freq) + 0.5*os.osc(2*freq) + 0.25*os.osc(3*freq);
15 |
16 | /*
17 | Additive synth: 3 sine oscillators with adsr envelop.
18 | Use the 3 first VC inputs to control pitch, gate and velocity.
19 | */
20 |
21 | process(pitch, gate, vel) = voice(freq) * en.adsr(attack, decay, sustain, release, gate) * vel : *(vol) : panner(pan)
22 | with {
23 | freq = cv_pitch2freq(pitch);
24 | };
--------------------------------------------------------------------------------
/examples/physicalmodel.dsp:
--------------------------------------------------------------------------------
1 | import("stdfaust.lib");
2 | import("rack.lib");
3 |
4 | frenchBell_ui = pm.frenchBell(strikePosition,strikeCutoff,strikeSharpness,gain,gate)
5 | with {
6 | strikePosition = nentry("v:frenchBell/[0]strikePosition", 0,0,4,1);
7 | strikeCutoff = hslider("v:frenchBell/[1]strikeCutOff", 6500,20,20000,1);
8 | strikeSharpness = hslider("v:frenchBell/[2]strikeSharpness", 0.5,0.01,5,0.01);
9 |
10 | // Connection with VCV knob and switch
11 | gain = hslider("v:frenchBell/[3]gain [knob:1]",1,0,1,0.01);
12 | gate = button("v:frenchBell/[4]gate [switch:1]");
13 | };
14 |
15 | freeverb_demo = _,_ <: (*(g)*fixedgain,*(g)*fixedgain :
16 | re.stereo_freeverb(combfeed, allpassfeed, damping, spatSpread)),
17 | *(1-g), *(1-g) :> _,_
18 | with{
19 | scaleroom = 0.28;
20 | offsetroom = 0.7;
21 | allpassfeed = 0.5;
22 | scaledamp = 0.4;
23 | fixedgain = 0.1;
24 | origSR = 44100;
25 |
26 | parameters(x) = hgroup("Freeverb",x);
27 | knobGroup(x) = parameters(vgroup("[0]",x));
28 |
29 | // Connection with VCV knobs
30 | damping = knobGroup(vslider("[0] Damp [knob:2] [style: knob] [tooltip: Somehow control the
31 | density of the reverb.]",0.5, 0, 1, 0.025)*scaledamp*origSR/ma.SR);
32 |
33 | combfeed = knobGroup(vslider("[1] RoomSize [knob:3] [style: knob] [tooltip: The room size
34 | between 0 and 1 with 1 for the largest room.]", 0.5, 0, 1, 0.025)*scaleroom*
35 | origSR/ma.SR + offsetroom);
36 |
37 | spatSpread = knobGroup(vslider("[2] Stereo Spread [knob:4] [style: knob] [tooltip: Spatial
38 | spread between 0 and 1 with 1 for maximum spread.]",0.5,0,1,0.01)*46*ma.SR/origSR
39 | : int);
40 | g = parameters(vslider("[1] Wet [knob:5] [tooltip: The amount of reverb applied to the signal
41 | between 0 and 1 with 1 for the maximum amount of reverb.]", 0.3333, 0, 1, 0.025));
42 | };
43 |
44 | process = frenchBell_ui <: freeverb_demo;
45 |
--------------------------------------------------------------------------------
/examples/rainbow.js:
--------------------------------------------------------------------------------
1 | // Rainbow RGB LED example
2 | // by Andrew Belt
3 |
4 | // Call process() every 256 audio samples
5 | config.frameDivider = 256
6 |
7 |
8 | // From https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
9 | function hsvToRgb(h, s, v) {
10 | h *= 6
11 | let c = v * s
12 | let x = c * (1 - Math.abs(h % 2 - 1))
13 | let rgb;
14 | if (h < 1) rgb = [c, x, 0]
15 | else if (h < 2) rgb = [x, c, 0]
16 | else if (h < 3) rgb = [0, c, x]
17 | else if (h < 4) rgb = [0, x, c]
18 | else if (h < 5) rgb = [x, 0, c]
19 | else rgb = [c, 0, x]
20 | let m = v - c
21 | rgb[0] += m
22 | rgb[1] += m
23 | rgb[2] += m
24 | return rgb
25 | }
26 |
27 |
28 | let phase = 0
29 | function process(block) {
30 | phase += block.sampleTime * config.frameDivider * 0.5
31 | phase %= 1
32 |
33 | for (let i = 0; i < 6; i++) {
34 | let h = (1 - i / 6 + phase) % 1
35 | let rgb = hsvToRgb(h, 1, 1)
36 | for (let c = 0; c < 3; c++) {
37 | block.lights[i][c] = rgb[c]
38 | block.switchLights[i][c] = rgb[c]
39 | }
40 | block.outputs[i][0] = Math.sin(2 * Math.PI * h) * 5 + 5
41 | }
42 | }
43 |
44 | display("Hello, world!")
45 |
--------------------------------------------------------------------------------
/examples/rainbow.lua:
--------------------------------------------------------------------------------
1 | -- Rainbow RGB LED example
2 | -- by Andrew Belt
3 |
4 | -- Call process() every 256 audio samples
5 | config.frameDivider = 256
6 |
7 |
8 | -- From https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
9 | function hsvToRgb(h, s, v)
10 | h = h * 6
11 | c = v * s
12 | x = c * (1 - math.abs(h % 2 - 1))
13 | if (h < 1) then rgb = {c, x, 0}
14 | elseif (h < 2) then rgb = {x, c, 0}
15 | elseif (h < 3) then rgb = {0, c, x}
16 | elseif (h < 4) then rgb = {0, x, c}
17 | elseif (h < 5) then rgb = {x, 0, c}
18 | else rgb = {c, 0, x}
19 | end
20 | m = v - c
21 | rgb[1] = rgb[1] + m
22 | rgb[2] = rgb[2] + m
23 | rgb[3] = rgb[3] + m
24 | return rgb
25 | end
26 |
27 |
28 | phase = 0
29 | function process(block)
30 | phase = phase + block.sampleTime * config.frameDivider * 0.5
31 | phase = phase % 1
32 |
33 | for i=1,6 do
34 | h = (1 - i / 6 + phase) % 1
35 | rgb = hsvToRgb(h, 1, 1)
36 | for c=1,3 do
37 | block.lights[i][c] = rgb[c]
38 | block.switchLights[i][c] = rgb[c]
39 | end
40 | block.outputs[i][1] = math.sin(2 * math.pi * h) * 5 + 5
41 | end
42 | end
43 |
44 | display("Hello, world!")
45 |
--------------------------------------------------------------------------------
/examples/rainbow.pd:
--------------------------------------------------------------------------------
1 | #N canvas 698 177 821 731 12;
2 | #N canvas 250 355 563 749 hsv2rgb 0;
3 | #X obj 20 64 route 0;
4 | #X msg 20 36 \$2 \$3 \$1;
5 | #X obj 20 552 f;
6 | #X obj 66 92 unpack 0 0 0, f 27;
7 | #X text 87 37 svh;
8 | #X obj 20 8 inlet hsv;
9 | #X obj 20 663 outlet rgb;
10 | #X obj 303 166 * 6;
11 | #X obj 284 213 % 6;
12 | #X obj 252 190 t f f;
13 | #X msg 252 166 0;
14 | #X text 308 213 i;
15 | #X obj 252 264 -;
16 | #X obj 66 501 *;
17 | #X obj 66 169 - 1;
18 | #X obj 66 196 * -1;
19 | #X obj 103 502 *;
20 | #X obj 103 399 - 1;
21 | #X obj 103 424 * -1;
22 | #X obj 103 377 *;
23 | #X obj 252 288 t f f;
24 | #X obj 282 311 - 1;
25 | #X obj 282 334 * -1;
26 | #X obj 140 503 *;
27 | #X obj 140 400 - 1;
28 | #X obj 140 425 * -1;
29 | #X obj 140 378 *;
30 | #X obj 66 142 t f f f, f 11;
31 | #X obj 66 535 pack 0 0 0 0, f 16;
32 | #N canvas 1219 718 529 336 select 0;
33 | #X obj 290 37 inlet;
34 | #X obj 16 281 outlet;
35 | #X obj 16 58 t b l, f 20;
36 | #X obj 152 176 unpack 0 0 0 0;
37 | #X obj 16 29 inlet p q t v;
38 | #X obj 16 123 i;
39 | #X obj 16 175 select 0 1 2 3 4 5;
40 | #X obj 16 239 pack 0 0 0;
41 | #X obj 16 209 f;
42 | #X obj 96 239 pack 0 0 0;
43 | #X obj 96 209 f;
44 | #X obj 176 239 pack 0 0 0;
45 | #X obj 176 209 f;
46 | #X obj 256 239 pack 0 0 0;
47 | #X obj 256 209 f;
48 | #X obj 336 239 pack 0 0 0;
49 | #X obj 336 209 f;
50 | #X obj 416 239 pack 0 0 0;
51 | #X obj 416 209 f;
52 | #X connect 0 0 5 1;
53 | #X connect 2 0 5 0;
54 | #X connect 2 1 3 0;
55 | #X connect 3 0 7 2;
56 | #X connect 3 0 9 2;
57 | #X connect 3 0 12 1;
58 | #X connect 3 0 14 1;
59 | #X connect 3 0 15 1;
60 | #X connect 3 0 17 1;
61 | #X connect 3 1 10 1;
62 | #X connect 3 1 13 1;
63 | #X connect 3 1 17 2;
64 | #X connect 3 2 7 1;
65 | #X connect 3 2 11 2;
66 | #X connect 3 2 16 1;
67 | #X connect 3 3 8 1;
68 | #X connect 3 3 9 1;
69 | #X connect 3 3 11 1;
70 | #X connect 3 3 13 2;
71 | #X connect 3 3 15 2;
72 | #X connect 3 3 18 1;
73 | #X connect 4 0 2 0;
74 | #X connect 5 0 6 0;
75 | #X connect 6 0 8 0;
76 | #X connect 6 1 10 0;
77 | #X connect 6 2 12 0;
78 | #X connect 6 3 14 0;
79 | #X connect 6 4 16 0;
80 | #X connect 6 5 18 0;
81 | #X connect 7 0 1 0;
82 | #X connect 8 0 7 0;
83 | #X connect 9 0 1 0;
84 | #X connect 10 0 9 0;
85 | #X connect 11 0 1 0;
86 | #X connect 12 0 11 0;
87 | #X connect 13 0 1 0;
88 | #X connect 14 0 13 0;
89 | #X connect 15 0 1 0;
90 | #X connect 16 0 15 0;
91 | #X connect 17 0 1 0;
92 | #X connect 18 0 17 0;
93 | #X restore 66 560 pd select;
94 | #X f 28;
95 | #X msg 20 621 \$1 \$1 \$1;
96 | #X obj 20 593 clip 0 1;
97 | #X obj 66 117 clip 0 1;
98 | #X obj 175 119 clip 0 1;
99 | #X obj 252 118 clip 0 1;
100 | #X obj 252 142 select 1;
101 | #X obj 175 462 t f f f f;
102 | #X obj 260 237 t f f;
103 | #X text 26 699 taken from the GEM helpfile hsv2rgb-help;
104 | #X connect 0 0 2 0;
105 | #X connect 0 1 3 0;
106 | #X connect 1 0 0 0;
107 | #X connect 2 0 31 0;
108 | #X connect 3 0 32 0;
109 | #X connect 3 1 33 0;
110 | #X connect 3 2 34 0;
111 | #X connect 5 0 1 0;
112 | #X connect 7 0 9 0;
113 | #X connect 8 0 37 0;
114 | #X connect 9 0 12 0;
115 | #X connect 9 1 8 0;
116 | #X connect 10 0 9 0;
117 | #X connect 12 0 20 0;
118 | #X connect 13 0 28 0;
119 | #X connect 14 0 15 0;
120 | #X connect 15 0 13 0;
121 | #X connect 16 0 28 1;
122 | #X connect 17 0 18 0;
123 | #X connect 18 0 16 0;
124 | #X connect 19 0 17 0;
125 | #X connect 20 0 19 1;
126 | #X connect 20 1 21 0;
127 | #X connect 21 0 22 0;
128 | #X connect 22 0 26 1;
129 | #X connect 23 0 28 2;
130 | #X connect 24 0 25 0;
131 | #X connect 25 0 23 0;
132 | #X connect 26 0 24 0;
133 | #X connect 27 0 14 0;
134 | #X connect 27 1 19 0;
135 | #X connect 27 2 26 0;
136 | #X connect 28 0 29 0;
137 | #X connect 29 0 6 0;
138 | #X connect 30 0 6 0;
139 | #X connect 31 0 30 0;
140 | #X connect 32 0 27 0;
141 | #X connect 33 0 36 0;
142 | #X connect 34 0 35 0;
143 | #X connect 35 0 10 0;
144 | #X connect 35 1 7 0;
145 | #X connect 36 0 13 1;
146 | #X connect 36 1 16 1;
147 | #X connect 36 2 23 1;
148 | #X connect 36 3 28 3;
149 | #X connect 37 0 29 1;
150 | #X connect 37 1 12 1;
151 | #X restore 29 343 pd hsv2rgb;
152 | #X msg 29 400 S1 \$1 \$2 \$3;
153 | #X obj 30 16 loadbang;
154 | #X msg 30 41 1;
155 | #X msg 29 315 \$1 1 1;
156 | #X obj 30 67 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 1
157 | ;
158 | #X obj 30 143 line;
159 | #N canvas 250 355 563 749 hsv2rgb 0;
160 | #X obj 20 64 route 0;
161 | #X msg 20 36 \$2 \$3 \$1;
162 | #X obj 20 552 f;
163 | #X obj 66 92 unpack 0 0 0, f 27;
164 | #X text 87 37 svh;
165 | #X obj 20 8 inlet hsv;
166 | #X obj 20 663 outlet rgb;
167 | #X obj 303 166 * 6;
168 | #X obj 284 213 % 6;
169 | #X obj 252 190 t f f;
170 | #X msg 252 166 0;
171 | #X text 308 213 i;
172 | #X obj 252 264 -;
173 | #X obj 66 501 *;
174 | #X obj 66 169 - 1;
175 | #X obj 66 196 * -1;
176 | #X obj 103 502 *;
177 | #X obj 103 399 - 1;
178 | #X obj 103 424 * -1;
179 | #X obj 103 377 *;
180 | #X obj 252 288 t f f;
181 | #X obj 282 311 - 1;
182 | #X obj 282 334 * -1;
183 | #X obj 140 503 *;
184 | #X obj 140 400 - 1;
185 | #X obj 140 425 * -1;
186 | #X obj 140 378 *;
187 | #X obj 66 142 t f f f, f 11;
188 | #X obj 66 535 pack 0 0 0 0, f 16;
189 | #N canvas 1219 718 529 336 select 0;
190 | #X obj 290 37 inlet;
191 | #X obj 16 281 outlet;
192 | #X obj 16 58 t b l, f 20;
193 | #X obj 152 176 unpack 0 0 0 0;
194 | #X obj 16 29 inlet p q t v;
195 | #X obj 16 123 i;
196 | #X obj 16 175 select 0 1 2 3 4 5;
197 | #X obj 16 239 pack 0 0 0;
198 | #X obj 16 209 f;
199 | #X obj 96 239 pack 0 0 0;
200 | #X obj 96 209 f;
201 | #X obj 176 239 pack 0 0 0;
202 | #X obj 176 209 f;
203 | #X obj 256 239 pack 0 0 0;
204 | #X obj 256 209 f;
205 | #X obj 336 239 pack 0 0 0;
206 | #X obj 336 209 f;
207 | #X obj 416 239 pack 0 0 0;
208 | #X obj 416 209 f;
209 | #X connect 0 0 5 1;
210 | #X connect 2 0 5 0;
211 | #X connect 2 1 3 0;
212 | #X connect 3 0 7 2;
213 | #X connect 3 0 9 2;
214 | #X connect 3 0 12 1;
215 | #X connect 3 0 14 1;
216 | #X connect 3 0 15 1;
217 | #X connect 3 0 17 1;
218 | #X connect 3 1 10 1;
219 | #X connect 3 1 13 1;
220 | #X connect 3 1 17 2;
221 | #X connect 3 2 7 1;
222 | #X connect 3 2 11 2;
223 | #X connect 3 2 16 1;
224 | #X connect 3 3 8 1;
225 | #X connect 3 3 9 1;
226 | #X connect 3 3 11 1;
227 | #X connect 3 3 13 2;
228 | #X connect 3 3 15 2;
229 | #X connect 3 3 18 1;
230 | #X connect 4 0 2 0;
231 | #X connect 5 0 6 0;
232 | #X connect 6 0 8 0;
233 | #X connect 6 1 10 0;
234 | #X connect 6 2 12 0;
235 | #X connect 6 3 14 0;
236 | #X connect 6 4 16 0;
237 | #X connect 6 5 18 0;
238 | #X connect 7 0 1 0;
239 | #X connect 8 0 7 0;
240 | #X connect 9 0 1 0;
241 | #X connect 10 0 9 0;
242 | #X connect 11 0 1 0;
243 | #X connect 12 0 11 0;
244 | #X connect 13 0 1 0;
245 | #X connect 14 0 13 0;
246 | #X connect 15 0 1 0;
247 | #X connect 16 0 15 0;
248 | #X connect 17 0 1 0;
249 | #X connect 18 0 17 0;
250 | #X restore 66 560 pd select;
251 | #X f 28;
252 | #X msg 20 621 \$1 \$1 \$1;
253 | #X obj 20 593 clip 0 1;
254 | #X obj 66 117 clip 0 1;
255 | #X obj 175 119 clip 0 1;
256 | #X obj 252 118 clip 0 1;
257 | #X obj 252 142 select 1;
258 | #X obj 175 462 t f f f f;
259 | #X obj 260 237 t f f;
260 | #X text 26 699 taken from the GEM helpfile hsv2rgb-help;
261 | #X connect 0 0 2 0;
262 | #X connect 0 1 3 0;
263 | #X connect 1 0 0 0;
264 | #X connect 2 0 31 0;
265 | #X connect 3 0 32 0;
266 | #X connect 3 1 33 0;
267 | #X connect 3 2 34 0;
268 | #X connect 5 0 1 0;
269 | #X connect 7 0 9 0;
270 | #X connect 8 0 37 0;
271 | #X connect 9 0 12 0;
272 | #X connect 9 1 8 0;
273 | #X connect 10 0 9 0;
274 | #X connect 12 0 20 0;
275 | #X connect 13 0 28 0;
276 | #X connect 14 0 15 0;
277 | #X connect 15 0 13 0;
278 | #X connect 16 0 28 1;
279 | #X connect 17 0 18 0;
280 | #X connect 18 0 16 0;
281 | #X connect 19 0 17 0;
282 | #X connect 20 0 19 1;
283 | #X connect 20 1 21 0;
284 | #X connect 21 0 22 0;
285 | #X connect 22 0 26 1;
286 | #X connect 23 0 28 2;
287 | #X connect 24 0 25 0;
288 | #X connect 25 0 23 0;
289 | #X connect 26 0 24 0;
290 | #X connect 27 0 14 0;
291 | #X connect 27 1 19 0;
292 | #X connect 27 2 26 0;
293 | #X connect 28 0 29 0;
294 | #X connect 29 0 6 0;
295 | #X connect 30 0 6 0;
296 | #X connect 31 0 30 0;
297 | #X connect 32 0 27 0;
298 | #X connect 33 0 36 0;
299 | #X connect 34 0 35 0;
300 | #X connect 35 0 10 0;
301 | #X connect 35 1 7 0;
302 | #X connect 36 0 13 1;
303 | #X connect 36 1 16 1;
304 | #X connect 36 2 23 1;
305 | #X connect 36 3 28 3;
306 | #X connect 37 0 29 1;
307 | #X connect 37 1 12 1;
308 | #X restore 125 343 pd hsv2rgb;
309 | #N canvas 250 355 563 749 hsv2rgb 0;
310 | #X obj 20 64 route 0;
311 | #X msg 20 36 \$2 \$3 \$1;
312 | #X obj 20 552 f;
313 | #X obj 66 92 unpack 0 0 0, f 27;
314 | #X text 87 37 svh;
315 | #X obj 20 8 inlet hsv;
316 | #X obj 20 663 outlet rgb;
317 | #X obj 303 166 * 6;
318 | #X obj 284 213 % 6;
319 | #X obj 252 190 t f f;
320 | #X msg 252 166 0;
321 | #X text 308 213 i;
322 | #X obj 252 264 -;
323 | #X obj 66 501 *;
324 | #X obj 66 169 - 1;
325 | #X obj 66 196 * -1;
326 | #X obj 103 502 *;
327 | #X obj 103 399 - 1;
328 | #X obj 103 424 * -1;
329 | #X obj 103 377 *;
330 | #X obj 252 288 t f f;
331 | #X obj 282 311 - 1;
332 | #X obj 282 334 * -1;
333 | #X obj 140 503 *;
334 | #X obj 140 400 - 1;
335 | #X obj 140 425 * -1;
336 | #X obj 140 378 *;
337 | #X obj 66 142 t f f f, f 11;
338 | #X obj 66 535 pack 0 0 0 0, f 16;
339 | #N canvas 1219 718 529 336 select 0;
340 | #X obj 290 37 inlet;
341 | #X obj 16 281 outlet;
342 | #X obj 16 58 t b l, f 20;
343 | #X obj 152 176 unpack 0 0 0 0;
344 | #X obj 16 29 inlet p q t v;
345 | #X obj 16 123 i;
346 | #X obj 16 175 select 0 1 2 3 4 5;
347 | #X obj 16 239 pack 0 0 0;
348 | #X obj 16 209 f;
349 | #X obj 96 239 pack 0 0 0;
350 | #X obj 96 209 f;
351 | #X obj 176 239 pack 0 0 0;
352 | #X obj 176 209 f;
353 | #X obj 256 239 pack 0 0 0;
354 | #X obj 256 209 f;
355 | #X obj 336 239 pack 0 0 0;
356 | #X obj 336 209 f;
357 | #X obj 416 239 pack 0 0 0;
358 | #X obj 416 209 f;
359 | #X connect 0 0 5 1;
360 | #X connect 2 0 5 0;
361 | #X connect 2 1 3 0;
362 | #X connect 3 0 7 2;
363 | #X connect 3 0 9 2;
364 | #X connect 3 0 12 1;
365 | #X connect 3 0 14 1;
366 | #X connect 3 0 15 1;
367 | #X connect 3 0 17 1;
368 | #X connect 3 1 10 1;
369 | #X connect 3 1 13 1;
370 | #X connect 3 1 17 2;
371 | #X connect 3 2 7 1;
372 | #X connect 3 2 11 2;
373 | #X connect 3 2 16 1;
374 | #X connect 3 3 8 1;
375 | #X connect 3 3 9 1;
376 | #X connect 3 3 11 1;
377 | #X connect 3 3 13 2;
378 | #X connect 3 3 15 2;
379 | #X connect 3 3 18 1;
380 | #X connect 4 0 2 0;
381 | #X connect 5 0 6 0;
382 | #X connect 6 0 8 0;
383 | #X connect 6 1 10 0;
384 | #X connect 6 2 12 0;
385 | #X connect 6 3 14 0;
386 | #X connect 6 4 16 0;
387 | #X connect 6 5 18 0;
388 | #X connect 7 0 1 0;
389 | #X connect 8 0 7 0;
390 | #X connect 9 0 1 0;
391 | #X connect 10 0 9 0;
392 | #X connect 11 0 1 0;
393 | #X connect 12 0 11 0;
394 | #X connect 13 0 1 0;
395 | #X connect 14 0 13 0;
396 | #X connect 15 0 1 0;
397 | #X connect 16 0 15 0;
398 | #X connect 17 0 1 0;
399 | #X connect 18 0 17 0;
400 | #X restore 66 560 pd select;
401 | #X f 28;
402 | #X msg 20 621 \$1 \$1 \$1;
403 | #X obj 20 593 clip 0 1;
404 | #X obj 66 117 clip 0 1;
405 | #X obj 175 119 clip 0 1;
406 | #X obj 252 118 clip 0 1;
407 | #X obj 252 142 select 1;
408 | #X obj 175 462 t f f f f;
409 | #X obj 260 237 t f f;
410 | #X text 26 699 taken from the GEM helpfile hsv2rgb-help;
411 | #X connect 0 0 2 0;
412 | #X connect 0 1 3 0;
413 | #X connect 1 0 0 0;
414 | #X connect 2 0 31 0;
415 | #X connect 3 0 32 0;
416 | #X connect 3 1 33 0;
417 | #X connect 3 2 34 0;
418 | #X connect 5 0 1 0;
419 | #X connect 7 0 9 0;
420 | #X connect 8 0 37 0;
421 | #X connect 9 0 12 0;
422 | #X connect 9 1 8 0;
423 | #X connect 10 0 9 0;
424 | #X connect 12 0 20 0;
425 | #X connect 13 0 28 0;
426 | #X connect 14 0 15 0;
427 | #X connect 15 0 13 0;
428 | #X connect 16 0 28 1;
429 | #X connect 17 0 18 0;
430 | #X connect 18 0 16 0;
431 | #X connect 19 0 17 0;
432 | #X connect 20 0 19 1;
433 | #X connect 20 1 21 0;
434 | #X connect 21 0 22 0;
435 | #X connect 22 0 26 1;
436 | #X connect 23 0 28 2;
437 | #X connect 24 0 25 0;
438 | #X connect 25 0 23 0;
439 | #X connect 26 0 24 0;
440 | #X connect 27 0 14 0;
441 | #X connect 27 1 19 0;
442 | #X connect 27 2 26 0;
443 | #X connect 28 0 29 0;
444 | #X connect 29 0 6 0;
445 | #X connect 30 0 6 0;
446 | #X connect 31 0 30 0;
447 | #X connect 32 0 27 0;
448 | #X connect 33 0 36 0;
449 | #X connect 34 0 35 0;
450 | #X connect 35 0 10 0;
451 | #X connect 35 1 7 0;
452 | #X connect 36 0 13 1;
453 | #X connect 36 1 16 1;
454 | #X connect 36 2 23 1;
455 | #X connect 36 3 28 3;
456 | #X connect 37 0 29 1;
457 | #X connect 37 1 12 1;
458 | #X restore 221 343 pd hsv2rgb;
459 | #N canvas 250 355 563 749 hsv2rgb 0;
460 | #X obj 20 64 route 0;
461 | #X msg 20 36 \$2 \$3 \$1;
462 | #X obj 20 552 f;
463 | #X obj 66 92 unpack 0 0 0, f 27;
464 | #X text 87 37 svh;
465 | #X obj 20 8 inlet hsv;
466 | #X obj 20 663 outlet rgb;
467 | #X obj 303 166 * 6;
468 | #X obj 284 213 % 6;
469 | #X obj 252 190 t f f;
470 | #X msg 252 166 0;
471 | #X text 308 213 i;
472 | #X obj 252 264 -;
473 | #X obj 66 501 *;
474 | #X obj 66 169 - 1;
475 | #X obj 66 196 * -1;
476 | #X obj 103 502 *;
477 | #X obj 103 399 - 1;
478 | #X obj 103 424 * -1;
479 | #X obj 103 377 *;
480 | #X obj 252 288 t f f;
481 | #X obj 282 311 - 1;
482 | #X obj 282 334 * -1;
483 | #X obj 140 503 *;
484 | #X obj 140 400 - 1;
485 | #X obj 140 425 * -1;
486 | #X obj 140 378 *;
487 | #X obj 66 142 t f f f, f 11;
488 | #X obj 66 535 pack 0 0 0 0, f 16;
489 | #N canvas 1219 718 529 336 select 0;
490 | #X obj 290 37 inlet;
491 | #X obj 16 281 outlet;
492 | #X obj 16 58 t b l, f 20;
493 | #X obj 152 176 unpack 0 0 0 0;
494 | #X obj 16 29 inlet p q t v;
495 | #X obj 16 123 i;
496 | #X obj 16 175 select 0 1 2 3 4 5;
497 | #X obj 16 239 pack 0 0 0;
498 | #X obj 16 209 f;
499 | #X obj 96 239 pack 0 0 0;
500 | #X obj 96 209 f;
501 | #X obj 176 239 pack 0 0 0;
502 | #X obj 176 209 f;
503 | #X obj 256 239 pack 0 0 0;
504 | #X obj 256 209 f;
505 | #X obj 336 239 pack 0 0 0;
506 | #X obj 336 209 f;
507 | #X obj 416 239 pack 0 0 0;
508 | #X obj 416 209 f;
509 | #X connect 0 0 5 1;
510 | #X connect 2 0 5 0;
511 | #X connect 2 1 3 0;
512 | #X connect 3 0 7 2;
513 | #X connect 3 0 9 2;
514 | #X connect 3 0 12 1;
515 | #X connect 3 0 14 1;
516 | #X connect 3 0 15 1;
517 | #X connect 3 0 17 1;
518 | #X connect 3 1 10 1;
519 | #X connect 3 1 13 1;
520 | #X connect 3 1 17 2;
521 | #X connect 3 2 7 1;
522 | #X connect 3 2 11 2;
523 | #X connect 3 2 16 1;
524 | #X connect 3 3 8 1;
525 | #X connect 3 3 9 1;
526 | #X connect 3 3 11 1;
527 | #X connect 3 3 13 2;
528 | #X connect 3 3 15 2;
529 | #X connect 3 3 18 1;
530 | #X connect 4 0 2 0;
531 | #X connect 5 0 6 0;
532 | #X connect 6 0 8 0;
533 | #X connect 6 1 10 0;
534 | #X connect 6 2 12 0;
535 | #X connect 6 3 14 0;
536 | #X connect 6 4 16 0;
537 | #X connect 6 5 18 0;
538 | #X connect 7 0 1 0;
539 | #X connect 8 0 7 0;
540 | #X connect 9 0 1 0;
541 | #X connect 10 0 9 0;
542 | #X connect 11 0 1 0;
543 | #X connect 12 0 11 0;
544 | #X connect 13 0 1 0;
545 | #X connect 14 0 13 0;
546 | #X connect 15 0 1 0;
547 | #X connect 16 0 15 0;
548 | #X connect 17 0 1 0;
549 | #X connect 18 0 17 0;
550 | #X restore 66 560 pd select;
551 | #X f 28;
552 | #X msg 20 621 \$1 \$1 \$1;
553 | #X obj 20 593 clip 0 1;
554 | #X obj 66 117 clip 0 1;
555 | #X obj 175 119 clip 0 1;
556 | #X obj 252 118 clip 0 1;
557 | #X obj 252 142 select 1;
558 | #X obj 175 462 t f f f f;
559 | #X obj 260 237 t f f;
560 | #X text 26 699 taken from the GEM helpfile hsv2rgb-help;
561 | #X connect 0 0 2 0;
562 | #X connect 0 1 3 0;
563 | #X connect 1 0 0 0;
564 | #X connect 2 0 31 0;
565 | #X connect 3 0 32 0;
566 | #X connect 3 1 33 0;
567 | #X connect 3 2 34 0;
568 | #X connect 5 0 1 0;
569 | #X connect 7 0 9 0;
570 | #X connect 8 0 37 0;
571 | #X connect 9 0 12 0;
572 | #X connect 9 1 8 0;
573 | #X connect 10 0 9 0;
574 | #X connect 12 0 20 0;
575 | #X connect 13 0 28 0;
576 | #X connect 14 0 15 0;
577 | #X connect 15 0 13 0;
578 | #X connect 16 0 28 1;
579 | #X connect 17 0 18 0;
580 | #X connect 18 0 16 0;
581 | #X connect 19 0 17 0;
582 | #X connect 20 0 19 1;
583 | #X connect 20 1 21 0;
584 | #X connect 21 0 22 0;
585 | #X connect 22 0 26 1;
586 | #X connect 23 0 28 2;
587 | #X connect 24 0 25 0;
588 | #X connect 25 0 23 0;
589 | #X connect 26 0 24 0;
590 | #X connect 27 0 14 0;
591 | #X connect 27 1 19 0;
592 | #X connect 27 2 26 0;
593 | #X connect 28 0 29 0;
594 | #X connect 29 0 6 0;
595 | #X connect 30 0 6 0;
596 | #X connect 31 0 30 0;
597 | #X connect 32 0 27 0;
598 | #X connect 33 0 36 0;
599 | #X connect 34 0 35 0;
600 | #X connect 35 0 10 0;
601 | #X connect 35 1 7 0;
602 | #X connect 36 0 13 1;
603 | #X connect 36 1 16 1;
604 | #X connect 36 2 23 1;
605 | #X connect 36 3 28 3;
606 | #X connect 37 0 29 1;
607 | #X connect 37 1 12 1;
608 | #X restore 317 343 pd hsv2rgb;
609 | #N canvas 250 355 563 749 hsv2rgb 0;
610 | #X obj 20 64 route 0;
611 | #X msg 20 36 \$2 \$3 \$1;
612 | #X obj 20 552 f;
613 | #X obj 66 92 unpack 0 0 0, f 27;
614 | #X text 87 37 svh;
615 | #X obj 20 8 inlet hsv;
616 | #X obj 20 663 outlet rgb;
617 | #X obj 303 166 * 6;
618 | #X obj 284 213 % 6;
619 | #X obj 252 190 t f f;
620 | #X msg 252 166 0;
621 | #X text 308 213 i;
622 | #X obj 252 264 -;
623 | #X obj 66 501 *;
624 | #X obj 66 169 - 1;
625 | #X obj 66 196 * -1;
626 | #X obj 103 502 *;
627 | #X obj 103 399 - 1;
628 | #X obj 103 424 * -1;
629 | #X obj 103 377 *;
630 | #X obj 252 288 t f f;
631 | #X obj 282 311 - 1;
632 | #X obj 282 334 * -1;
633 | #X obj 140 503 *;
634 | #X obj 140 400 - 1;
635 | #X obj 140 425 * -1;
636 | #X obj 140 378 *;
637 | #X obj 66 142 t f f f, f 11;
638 | #X obj 66 535 pack 0 0 0 0, f 16;
639 | #N canvas 1219 718 529 336 select 0;
640 | #X obj 290 37 inlet;
641 | #X obj 16 281 outlet;
642 | #X obj 16 58 t b l, f 20;
643 | #X obj 152 176 unpack 0 0 0 0;
644 | #X obj 16 29 inlet p q t v;
645 | #X obj 16 123 i;
646 | #X obj 16 175 select 0 1 2 3 4 5;
647 | #X obj 16 239 pack 0 0 0;
648 | #X obj 16 209 f;
649 | #X obj 96 239 pack 0 0 0;
650 | #X obj 96 209 f;
651 | #X obj 176 239 pack 0 0 0;
652 | #X obj 176 209 f;
653 | #X obj 256 239 pack 0 0 0;
654 | #X obj 256 209 f;
655 | #X obj 336 239 pack 0 0 0;
656 | #X obj 336 209 f;
657 | #X obj 416 239 pack 0 0 0;
658 | #X obj 416 209 f;
659 | #X connect 0 0 5 1;
660 | #X connect 2 0 5 0;
661 | #X connect 2 1 3 0;
662 | #X connect 3 0 7 2;
663 | #X connect 3 0 9 2;
664 | #X connect 3 0 12 1;
665 | #X connect 3 0 14 1;
666 | #X connect 3 0 15 1;
667 | #X connect 3 0 17 1;
668 | #X connect 3 1 10 1;
669 | #X connect 3 1 13 1;
670 | #X connect 3 1 17 2;
671 | #X connect 3 2 7 1;
672 | #X connect 3 2 11 2;
673 | #X connect 3 2 16 1;
674 | #X connect 3 3 8 1;
675 | #X connect 3 3 9 1;
676 | #X connect 3 3 11 1;
677 | #X connect 3 3 13 2;
678 | #X connect 3 3 15 2;
679 | #X connect 3 3 18 1;
680 | #X connect 4 0 2 0;
681 | #X connect 5 0 6 0;
682 | #X connect 6 0 8 0;
683 | #X connect 6 1 10 0;
684 | #X connect 6 2 12 0;
685 | #X connect 6 3 14 0;
686 | #X connect 6 4 16 0;
687 | #X connect 6 5 18 0;
688 | #X connect 7 0 1 0;
689 | #X connect 8 0 7 0;
690 | #X connect 9 0 1 0;
691 | #X connect 10 0 9 0;
692 | #X connect 11 0 1 0;
693 | #X connect 12 0 11 0;
694 | #X connect 13 0 1 0;
695 | #X connect 14 0 13 0;
696 | #X connect 15 0 1 0;
697 | #X connect 16 0 15 0;
698 | #X connect 17 0 1 0;
699 | #X connect 18 0 17 0;
700 | #X restore 66 560 pd select;
701 | #X f 28;
702 | #X msg 20 621 \$1 \$1 \$1;
703 | #X obj 20 593 clip 0 1;
704 | #X obj 66 117 clip 0 1;
705 | #X obj 175 119 clip 0 1;
706 | #X obj 252 118 clip 0 1;
707 | #X obj 252 142 select 1;
708 | #X obj 175 462 t f f f f;
709 | #X obj 260 237 t f f;
710 | #X text 26 699 taken from the GEM helpfile hsv2rgb-help;
711 | #X connect 0 0 2 0;
712 | #X connect 0 1 3 0;
713 | #X connect 1 0 0 0;
714 | #X connect 2 0 31 0;
715 | #X connect 3 0 32 0;
716 | #X connect 3 1 33 0;
717 | #X connect 3 2 34 0;
718 | #X connect 5 0 1 0;
719 | #X connect 7 0 9 0;
720 | #X connect 8 0 37 0;
721 | #X connect 9 0 12 0;
722 | #X connect 9 1 8 0;
723 | #X connect 10 0 9 0;
724 | #X connect 12 0 20 0;
725 | #X connect 13 0 28 0;
726 | #X connect 14 0 15 0;
727 | #X connect 15 0 13 0;
728 | #X connect 16 0 28 1;
729 | #X connect 17 0 18 0;
730 | #X connect 18 0 16 0;
731 | #X connect 19 0 17 0;
732 | #X connect 20 0 19 1;
733 | #X connect 20 1 21 0;
734 | #X connect 21 0 22 0;
735 | #X connect 22 0 26 1;
736 | #X connect 23 0 28 2;
737 | #X connect 24 0 25 0;
738 | #X connect 25 0 23 0;
739 | #X connect 26 0 24 0;
740 | #X connect 27 0 14 0;
741 | #X connect 27 1 19 0;
742 | #X connect 27 2 26 0;
743 | #X connect 28 0 29 0;
744 | #X connect 29 0 6 0;
745 | #X connect 30 0 6 0;
746 | #X connect 31 0 30 0;
747 | #X connect 32 0 27 0;
748 | #X connect 33 0 36 0;
749 | #X connect 34 0 35 0;
750 | #X connect 35 0 10 0;
751 | #X connect 35 1 7 0;
752 | #X connect 36 0 13 1;
753 | #X connect 36 1 16 1;
754 | #X connect 36 2 23 1;
755 | #X connect 36 3 28 3;
756 | #X connect 37 0 29 1;
757 | #X connect 37 1 12 1;
758 | #X restore 413 343 pd hsv2rgb;
759 | #N canvas 250 355 563 749 hsv2rgb 0;
760 | #X obj 20 64 route 0;
761 | #X msg 20 36 \$2 \$3 \$1;
762 | #X obj 20 552 f;
763 | #X obj 66 92 unpack 0 0 0, f 27;
764 | #X text 87 37 svh;
765 | #X obj 20 8 inlet hsv;
766 | #X obj 20 663 outlet rgb;
767 | #X obj 303 166 * 6;
768 | #X obj 284 213 % 6;
769 | #X obj 252 190 t f f;
770 | #X msg 252 166 0;
771 | #X text 308 213 i;
772 | #X obj 252 264 -;
773 | #X obj 66 501 *;
774 | #X obj 66 169 - 1;
775 | #X obj 66 196 * -1;
776 | #X obj 103 502 *;
777 | #X obj 103 399 - 1;
778 | #X obj 103 424 * -1;
779 | #X obj 103 377 *;
780 | #X obj 252 288 t f f;
781 | #X obj 282 311 - 1;
782 | #X obj 282 334 * -1;
783 | #X obj 140 503 *;
784 | #X obj 140 400 - 1;
785 | #X obj 140 425 * -1;
786 | #X obj 140 378 *;
787 | #X obj 66 142 t f f f, f 11;
788 | #X obj 66 535 pack 0 0 0 0, f 16;
789 | #N canvas 1219 718 529 336 select 0;
790 | #X obj 290 37 inlet;
791 | #X obj 16 281 outlet;
792 | #X obj 16 58 t b l, f 20;
793 | #X obj 152 176 unpack 0 0 0 0;
794 | #X obj 16 29 inlet p q t v;
795 | #X obj 16 123 i;
796 | #X obj 16 175 select 0 1 2 3 4 5;
797 | #X obj 16 239 pack 0 0 0;
798 | #X obj 16 209 f;
799 | #X obj 96 239 pack 0 0 0;
800 | #X obj 96 209 f;
801 | #X obj 176 239 pack 0 0 0;
802 | #X obj 176 209 f;
803 | #X obj 256 239 pack 0 0 0;
804 | #X obj 256 209 f;
805 | #X obj 336 239 pack 0 0 0;
806 | #X obj 336 209 f;
807 | #X obj 416 239 pack 0 0 0;
808 | #X obj 416 209 f;
809 | #X connect 0 0 5 1;
810 | #X connect 2 0 5 0;
811 | #X connect 2 1 3 0;
812 | #X connect 3 0 7 2;
813 | #X connect 3 0 9 2;
814 | #X connect 3 0 12 1;
815 | #X connect 3 0 14 1;
816 | #X connect 3 0 15 1;
817 | #X connect 3 0 17 1;
818 | #X connect 3 1 10 1;
819 | #X connect 3 1 13 1;
820 | #X connect 3 1 17 2;
821 | #X connect 3 2 7 1;
822 | #X connect 3 2 11 2;
823 | #X connect 3 2 16 1;
824 | #X connect 3 3 8 1;
825 | #X connect 3 3 9 1;
826 | #X connect 3 3 11 1;
827 | #X connect 3 3 13 2;
828 | #X connect 3 3 15 2;
829 | #X connect 3 3 18 1;
830 | #X connect 4 0 2 0;
831 | #X connect 5 0 6 0;
832 | #X connect 6 0 8 0;
833 | #X connect 6 1 10 0;
834 | #X connect 6 2 12 0;
835 | #X connect 6 3 14 0;
836 | #X connect 6 4 16 0;
837 | #X connect 6 5 18 0;
838 | #X connect 7 0 1 0;
839 | #X connect 8 0 7 0;
840 | #X connect 9 0 1 0;
841 | #X connect 10 0 9 0;
842 | #X connect 11 0 1 0;
843 | #X connect 12 0 11 0;
844 | #X connect 13 0 1 0;
845 | #X connect 14 0 13 0;
846 | #X connect 15 0 1 0;
847 | #X connect 16 0 15 0;
848 | #X connect 17 0 1 0;
849 | #X connect 18 0 17 0;
850 | #X restore 66 560 pd select;
851 | #X f 28;
852 | #X msg 20 621 \$1 \$1 \$1;
853 | #X obj 20 593 clip 0 1;
854 | #X obj 66 117 clip 0 1;
855 | #X obj 175 119 clip 0 1;
856 | #X obj 252 118 clip 0 1;
857 | #X obj 252 142 select 1;
858 | #X obj 175 462 t f f f f;
859 | #X obj 260 237 t f f;
860 | #X text 26 699 taken from the GEM helpfile hsv2rgb-help;
861 | #X connect 0 0 2 0;
862 | #X connect 0 1 3 0;
863 | #X connect 1 0 0 0;
864 | #X connect 2 0 31 0;
865 | #X connect 3 0 32 0;
866 | #X connect 3 1 33 0;
867 | #X connect 3 2 34 0;
868 | #X connect 5 0 1 0;
869 | #X connect 7 0 9 0;
870 | #X connect 8 0 37 0;
871 | #X connect 9 0 12 0;
872 | #X connect 9 1 8 0;
873 | #X connect 10 0 9 0;
874 | #X connect 12 0 20 0;
875 | #X connect 13 0 28 0;
876 | #X connect 14 0 15 0;
877 | #X connect 15 0 13 0;
878 | #X connect 16 0 28 1;
879 | #X connect 17 0 18 0;
880 | #X connect 18 0 16 0;
881 | #X connect 19 0 17 0;
882 | #X connect 20 0 19 1;
883 | #X connect 20 1 21 0;
884 | #X connect 21 0 22 0;
885 | #X connect 22 0 26 1;
886 | #X connect 23 0 28 2;
887 | #X connect 24 0 25 0;
888 | #X connect 25 0 23 0;
889 | #X connect 26 0 24 0;
890 | #X connect 27 0 14 0;
891 | #X connect 27 1 19 0;
892 | #X connect 27 2 26 0;
893 | #X connect 28 0 29 0;
894 | #X connect 29 0 6 0;
895 | #X connect 30 0 6 0;
896 | #X connect 31 0 30 0;
897 | #X connect 32 0 27 0;
898 | #X connect 33 0 36 0;
899 | #X connect 34 0 35 0;
900 | #X connect 35 0 10 0;
901 | #X connect 35 1 7 0;
902 | #X connect 36 0 13 1;
903 | #X connect 36 1 16 1;
904 | #X connect 36 2 23 1;
905 | #X connect 36 3 28 3;
906 | #X connect 37 0 29 1;
907 | #X connect 37 1 12 1;
908 | #X restore 509 343 pd hsv2rgb;
909 | #X msg 125 400 S2 \$1 \$2 \$3;
910 | #X msg 221 400 S3 \$1 \$2 \$3;
911 | #X msg 317 400 S4 \$1 \$2 \$3;
912 | #X msg 413 400 S5 \$1 \$2 \$3;
913 | #X msg 509 400 S6 \$1 \$2 \$3;
914 | #X obj 30 92 metro 2000;
915 | #X msg 62 426 L1 \$1 \$2 \$3;
916 | #X msg 158 426 L2 \$1 \$2 \$3;
917 | #X msg 254 426 L3 \$1 \$2 \$3;
918 | #X msg 350 426 L4 \$1 \$2 \$3;
919 | #X msg 447 426 L5 \$1 \$2 \$3;
920 | #X msg 542 426 L6 \$1 \$2 \$3;
921 | #X obj 29 619 dac~ 1 2 3 4 5 6, f 69;
922 | #X obj 29 369 t l l;
923 | #X obj 125 369 t l l;
924 | #X obj 221 369 t l l;
925 | #X obj 317 369 t l l;
926 | #X obj 413 369 t l l;
927 | #X obj 509 369 t l l;
928 | #X msg 125 316 \$1 1 1;
929 | #X obj 125 201 + 16.6667;
930 | #X obj 125 227 % 100;
931 | #X obj 29 249 / 100;
932 | #X obj 125 252 / 100;
933 | #X obj 221 224 % 100;
934 | #X obj 221 249 / 100;
935 | #X msg 221 315 \$1 1 1;
936 | #X obj 317 225 % 100;
937 | #X obj 317 250 / 100;
938 | #X msg 317 316 \$1 1 1;
939 | #X obj 413 226 % 100;
940 | #X obj 413 251 / 100;
941 | #X msg 413 317 \$1 1 1;
942 | #X obj 509 226 % 100;
943 | #X obj 509 251 / 100;
944 | #X msg 509 317 \$1 1 1;
945 | #X obj 221 198 + 33.3334;
946 | #X obj 413 200 + 66.6667;
947 | #X obj 509 200 + 83.3334;
948 | #X obj 29 167 t f f f f f f, f 69;
949 | #X obj 317 199 + 50;
950 | #X obj 40 281 s out1;
951 | #X obj 30 511 r out1;
952 | #X obj 127 511 r out2;
953 | #X obj 316 509 r out4;
954 | #X obj 223 509 r out3;
955 | #X obj 413 509 r out5;
956 | #X obj 508 507 r out6;
957 | #X obj 136 282 s out2;
958 | #X obj 229 283 s out3;
959 | #X obj 328 283 s out4;
960 | #X obj 427 286 s out5;
961 | #X obj 529 284 s out6;
962 | #X obj 127 536 cos~;
963 | #X obj 222 534 cos~;
964 | #X obj 316 534 cos~;
965 | #X obj 413 534 cos~;
966 | #X obj 508 532 cos~;
967 | #X obj 30 564 +~ 1;
968 | #X obj 30 536 cos~;
969 | #X obj 126 562 +~ 1;
970 | #X obj 222 561 +~ 1;
971 | #X obj 316 559 +~ 1;
972 | #X obj 413 560 +~ 1;
973 | #X obj 508 560 +~ 1;
974 | #X msg 30 118 100 \, 0 2000;
975 | #X obj 30 590 *~ 5;
976 | #X obj 125 589 *~ 5;
977 | #X obj 222 588 *~ 5;
978 | #X obj 317 587 *~ 5;
979 | #X obj 413 588 *~ 5;
980 | #X obj 508 588 *~ 5;
981 | #X obj 251 17 loadbang;
982 | #X msg 251 41 display Hello world!;
983 | #X text 608 326 This should be an abstraction \, but to keep the example
984 | directory tidy it is duplicated code here (subpatches)., f 28;
985 | #X obj 29 478 print toRack;
986 | #X obj 251 66 print toRack;
987 | #X connect 0 0 25 0;
988 | #X connect 1 0 87 0;
989 | #X connect 2 0 3 0;
990 | #X connect 3 0 5 0;
991 | #X connect 4 0 0 0;
992 | #X connect 5 0 17 0;
993 | #X connect 6 0 51 0;
994 | #X connect 7 0 26 0;
995 | #X connect 8 0 27 0;
996 | #X connect 9 0 28 0;
997 | #X connect 10 0 29 0;
998 | #X connect 11 0 30 0;
999 | #X connect 12 0 87 0;
1000 | #X connect 13 0 87 0;
1001 | #X connect 14 0 87 0;
1002 | #X connect 15 0 87 0;
1003 | #X connect 16 0 87 0;
1004 | #X connect 17 0 77 0;
1005 | #X connect 18 0 87 0;
1006 | #X connect 19 0 87 0;
1007 | #X connect 20 0 87 0;
1008 | #X connect 21 0 87 0;
1009 | #X connect 22 0 87 0;
1010 | #X connect 23 0 87 0;
1011 | #X connect 25 0 1 0;
1012 | #X connect 25 1 18 0;
1013 | #X connect 26 0 12 0;
1014 | #X connect 26 1 19 0;
1015 | #X connect 27 0 13 0;
1016 | #X connect 27 1 20 0;
1017 | #X connect 28 0 14 0;
1018 | #X connect 28 1 21 0;
1019 | #X connect 29 0 15 0;
1020 | #X connect 29 1 22 0;
1021 | #X connect 30 0 16 0;
1022 | #X connect 30 1 23 0;
1023 | #X connect 31 0 7 0;
1024 | #X connect 32 0 33 0;
1025 | #X connect 33 0 35 0;
1026 | #X connect 34 0 4 0;
1027 | #X connect 34 0 53 0;
1028 | #X connect 35 0 31 0;
1029 | #X connect 35 0 60 0;
1030 | #X connect 36 0 37 0;
1031 | #X connect 37 0 38 0;
1032 | #X connect 37 0 61 0;
1033 | #X connect 38 0 8 0;
1034 | #X connect 39 0 40 0;
1035 | #X connect 40 0 41 0;
1036 | #X connect 40 0 62 0;
1037 | #X connect 41 0 9 0;
1038 | #X connect 42 0 43 0;
1039 | #X connect 43 0 44 0;
1040 | #X connect 43 0 63 0;
1041 | #X connect 44 0 10 0;
1042 | #X connect 45 0 46 0;
1043 | #X connect 46 0 47 0;
1044 | #X connect 46 0 64 0;
1045 | #X connect 47 0 11 0;
1046 | #X connect 48 0 36 0;
1047 | #X connect 49 0 42 0;
1048 | #X connect 50 0 45 0;
1049 | #X connect 51 0 34 0;
1050 | #X connect 51 1 32 0;
1051 | #X connect 51 2 48 0;
1052 | #X connect 51 3 52 0;
1053 | #X connect 51 4 49 0;
1054 | #X connect 51 5 50 0;
1055 | #X connect 52 0 39 0;
1056 | #X connect 54 0 71 0;
1057 | #X connect 55 0 65 0;
1058 | #X connect 56 0 67 0;
1059 | #X connect 57 0 66 0;
1060 | #X connect 58 0 68 0;
1061 | #X connect 59 0 69 0;
1062 | #X connect 65 0 72 0;
1063 | #X connect 66 0 73 0;
1064 | #X connect 67 0 74 0;
1065 | #X connect 68 0 75 0;
1066 | #X connect 69 0 76 0;
1067 | #X connect 70 0 78 0;
1068 | #X connect 71 0 70 0;
1069 | #X connect 72 0 79 0;
1070 | #X connect 73 0 80 0;
1071 | #X connect 74 0 81 0;
1072 | #X connect 75 0 82 0;
1073 | #X connect 76 0 83 0;
1074 | #X connect 77 0 6 0;
1075 | #X connect 78 0 24 0;
1076 | #X connect 79 0 24 1;
1077 | #X connect 80 0 24 2;
1078 | #X connect 81 0 24 3;
1079 | #X connect 82 0 24 4;
1080 | #X connect 83 0 24 5;
1081 | #X connect 84 0 85 0;
1082 | #X connect 85 0 88 0;
1083 |
--------------------------------------------------------------------------------
/examples/rainbow.scd:
--------------------------------------------------------------------------------
1 | // Rainbow RGB LED example
2 | // by Andrew Belt
3 | // adapted for SC by Brian Heim
4 |
5 | // Call process() every 256 audio samples
6 | ~vcv_frameDivider = 256;
7 | ~vcv_bufferSize = 1;
8 |
9 | // From https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
10 | ~hsvToRgb = { |h, s, v|
11 | var c, x, rgb, m;
12 | h = h * 6;
13 | c = v * s;
14 | x = c * (1 - abs(h % 2 - 1));
15 | rgb = case
16 | { h < 1 } { [c, x, 0] }
17 | { h < 2 } { [x, c, 0] }
18 | { h < 3 } { [0, c, x] }
19 | { h < 4 } { [0, x, c] }
20 | { h < 5 } { [x, 0, c] }
21 | { [c, 0, x] };
22 |
23 | rgb + (v - c);
24 | };
25 |
26 | ~phase = 0;
27 | ~vcv_process = { |block|
28 | ~phase = ~phase + block.sampleTime * ~vcv_frameDivider * 0.5;
29 | ~phase = ~phase % 1.0;
30 |
31 | VcvPrototypeProcessBlock.numRows.do { |i|
32 | var h = (1 - i / 6 + ~phase) % 1;
33 | var rgb = ~hsvToRgb.value(h, 1, 1);
34 | 3.do { |c|
35 | block.lights[i][c] = rgb[c];
36 | block.switchLights[i][c] = rgb[c];
37 | };
38 | block.outputs[i][0] = sin(2pi * h) * 5 + 5;
39 | };
40 |
41 | block
42 | }
43 |
--------------------------------------------------------------------------------
/examples/synth.dsp:
--------------------------------------------------------------------------------
1 | /*
2 | All controllers of the VCV Prototype are accessed using metadata.
3 | */
4 |
5 | import("stdfaust.lib");
6 | import("rack.lib");
7 |
8 | // Using knobs ([knob:N] metadata with N from 1 to 6). Knob [0..1] range is mapped on [min..max] slider range, taking 'scale' metadata in account
9 |
10 | vol1 = hslider("volume1 [knob:1]", 0.1, 0, 1, 0.01);
11 | freq1 = hslider("freq1 [knob:2] [unit:Hz] [scale:lin]", 300, 200, 300, 1);
12 |
13 | vol2 = hslider("volume2 [knob:3]", 0.1, 0, 1, 0.01);
14 | freq2 = hslider("freq2 [knob:4] [unit:Hz] ", 300, 200, 300, 1);
15 |
16 | // Using switches ([switch:N] metadata with N from 1 to 6)
17 |
18 | gate = button("gate [switch:1]");
19 |
20 | // Checkbox can be used, the switch button will go be white when checked
21 |
22 | check = checkbox("check [switch:2]");
23 |
24 | // Using bargraph to control lights ([light_red|green|blue:N] metadata with N from 1 to 6, to control 3 colors)
25 |
26 | light_1_r = vbargraph("[light_red:1]", 0, 1);
27 | light_1_g = vbargraph("[light_green:1]", 0, 1);
28 | light_1_b = vbargraph("[light_blue:1]", 0, 1);
29 |
30 | // Using bargraph to control switchlights ([switchlight_red|green|blue:N] metadata with N from 1 to 6, to control 3 colors)
31 |
32 | swl_2_r = vbargraph("[switchlight_red:3]", 0, 1);
33 | swl_2_g = vbargraph("[switchlight_green:3]", 0, 1);
34 | swl_2_b = vbargraph("[switchlight_blue:3]", 0, 1);
35 |
36 | process = os.osc(freq1) * vol1,
37 | os.sawtooth(freq2) * vol2 * gate,
38 | os.square(freq2) * vol2 * check,
39 | (os.osc(1):light_1_r + os.osc(1.4):light_1_g + os.osc(1.7):light_1_b),
40 | (os.osc(1):swl_2_r + os.osc(1.2):swl_2_g + os.osc(1.7):swl_2_b);
41 |
--------------------------------------------------------------------------------
/examples/synth.vult:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Simple synthesizer with one oscillator, LFO and envelope.
4 |
5 | Author: Leonardo Laguna Ruiz - leonardo@vult-dsp.com
6 |
7 | Check the API documentation in the basic.vult example
8 |
9 | */
10 |
11 | fun env(gate) {
12 | mem x;
13 | val k = if gate > x then 0.05 else 0.0002;
14 | x = x + (gate - x) * k;
15 | return x;
16 | }
17 |
18 | fun edge(x):bool {
19 | mem pre_x;
20 | val v:bool = (pre_x <> x) && (pre_x == false);
21 | pre_x = x;
22 | return v;
23 | }
24 |
25 | fun pitchToFreq(cv) {
26 | return 261.6256 * exp(cv * 0.69314718056);
27 | }
28 |
29 | fun phasor(pitch, reset){
30 | mem phase;
31 | val rate = pitchToFreq(pitch) * sampletime();
32 | phase = phase + rate;
33 | if(phase > 1.0)
34 | phase = phase - 1.0;
35 | if(reset)
36 | phase = 0.0;
37 | return phase;
38 | }
39 |
40 | fun oscillator(pitch, mod) {
41 | mem pre_phase1;
42 | // Implements the resonant filter simulation as shown in
43 | // http://en.wikipedia.org/wiki/Phase_distortion_synthesis
44 | val phase1 = phasor(pitch, false);
45 | val comp = 1.0 - phase1;
46 | val reset = edge((pre_phase1 - phase1) > 0.5);
47 | pre_phase1 = phase1;
48 | val phase2 = phasor(pitch + mod, reset);
49 | val sine = sin(2.0 * pi() * phase2);
50 | return sine * comp;
51 | }
52 |
53 | fun lfo(f, gate){
54 | mem phase;
55 | val rate = f * 10.0 * sampletime();
56 | if(edge(gate > 0.0))
57 | phase = 0.0;
58 | phase = phase + rate;
59 | if(phase > 1.0)
60 | phase = phase - 1.0;
61 | return sin(phase * 2.0 * pi()) - 0.5;
62 | }
63 |
64 | // Main processing function
65 | fun process(cv, gate){
66 | // LFO
67 | val lfo_rate = getKnob(3);
68 | val lfo_amt = getKnob(4);
69 | val lfo_val = lfo(lfo_rate, gate) * lfo_amt;
70 | // Oscillator
71 | val pitch = getKnob(1) + 10.0 * cv - 2.0;
72 | val mod = getKnob(2) * 2.0 + lfo_val;
73 | val o = oscillator(pitch, mod);
74 | // Envelope
75 | val e = env(gate);
76 | return o * e;
77 | }
78 | and update() {
79 | _ = display("IN1: CV, IN2: GATE");
80 | }
--------------------------------------------------------------------------------
/examples/template.js:
--------------------------------------------------------------------------------
1 | config.frameDivider = 1
2 | config.bufferSize = 32
3 |
4 | function process(block) {
5 | // Per-block inputs:
6 | // block.knobs[i]
7 | // block.switches[i]
8 |
9 | for (let j = 0; j < block.bufferSize; j++) {
10 | // Per-sample inputs:
11 | // block.inputs[i][j]
12 |
13 | // Per-sample outputs:
14 | // block.outputs[i][j]
15 | }
16 |
17 | // Per-block outputs:
18 | // block.lights[i][color]
19 | // block.switchLights[i][color]
20 | }
21 |
--------------------------------------------------------------------------------
/examples/template.lua:
--------------------------------------------------------------------------------
1 | config.frameDivider = 1
2 | config.bufferSize = 32
3 |
4 | function process(block)
5 | -- Per-block inputs:
6 | -- block.knobs[i]
7 | -- block.switches[i]
8 |
9 | for j=1,block.bufferSize do
10 | -- Per-sample inputs:
11 | -- block.inputs[i][j]
12 |
13 | -- Per-sample outputs:
14 | -- block.outputs[i][j]
15 | end
16 |
17 | -- Per-block outputs:
18 | -- block.lights[i][color]
19 | -- block.switchLights[i][color]
20 | end
21 |
--------------------------------------------------------------------------------
/examples/template.pd:
--------------------------------------------------------------------------------
1 | #N canvas 589 332 483 581 12;
2 | #X obj 32 525 dac~ 1 2 3 4 5 6;
3 | #X obj 32 401 adc~ 1 2 3 4 5 6;
4 | #X obj 36 62 route K1 K2 K3 K4 K5 K6;
5 | #X obj 194 106 route S1 S2 S3 S4 S5 S6;
6 | #X text 214 60 knobs;
7 | #X text 369 104 buttons;
8 | #X msg 54 333 display this text will print;
9 | #X msg 32 259 L1 \$1 \$2 \$3;
10 | #X obj 32 230 pack f f f;
11 | #X obj 47 202 t b f;
12 | #X obj 89 203 t b f;
13 | #X obj 32 123 vsl 15 50 0 1 0 0 empty empty empty 0 -9 0 10 -258113
14 | -1 -1 0 1;
15 | #X obj 47 123 vsl 15 50 0 1 0 0 empty empty empty 0 -9 0 10 -4034 -1
16 | -1 0 1;
17 | #X obj 62 123 vsl 15 50 0 1 0 0 empty empty empty 0 -9 0 10 -4160 -1
18 | -1 0 1;
19 | #X obj 36 25 r fromRack;
20 | #X obj 32 367 print toRack;
21 | #X text 263 332 to the display;
22 | #X text 121 25 receiving control data from VCV Prototype module;
23 | #X text 129 368 sending control data from VCV Prototype module;
24 | #X text 158 401 receiving audio from VCV Prototype module;
25 | #X text 158 525 sending audio to VCV Prototype module;
26 | #X connect 2 6 3 0;
27 | #X connect 6 0 15 0;
28 | #X connect 7 0 15 0;
29 | #X connect 8 0 7 0;
30 | #X connect 9 0 8 0;
31 | #X connect 9 1 8 1;
32 | #X connect 10 0 8 0;
33 | #X connect 10 1 8 2;
34 | #X connect 11 0 8 0;
35 | #X connect 12 0 9 0;
36 | #X connect 13 0 10 0;
37 | #X connect 14 0 2 0;
38 |
--------------------------------------------------------------------------------
/examples/template.vult:
--------------------------------------------------------------------------------
1 | /*
2 | Vult API documentation.
3 |
4 | Author: Leonardo Laguna Ruiz - leonardo@vult-dsp.com
5 |
6 | The main difference of the Vult API compared to the JavaScript and Lua is that all interactions
7 | happen through functions rather than accessing to the block arrays.
8 |
9 | A Vult script requires the following two functions:
10 |
11 | fun process() { }
12 | and update() { }
13 |
14 | The 'process' function is called every audio sample. As inputs, it will receive the values from
15 | the input jacks but normalized to 1.0. This means that a value of 10.0 V in VCV Rack is received
16 | as 1.0. Similarly, when you return a value of 1.0 it will be output by the prototype as 10.0V.
17 |
18 | You can use the input and output jacks by adding or removing arguments to the function. For example,
19 | to pass all the inputs to the outputs you can declare the function as follows:
20 |
21 | fun process(i1, i2, i3, i4, i5, i6) {
22 | return i1, i2, i3, i4, i5, i6;
23 | }
24 |
25 | The 'update' function is called once every 32 samples. You can use this function to perform actions
26 | that do not require audio rate speed e.g. setting light colors or displying characters in the screen.
27 | The function 'update' do not takes or returns any value.
28 |
29 | Important: Notice that the 'update' function is declared with the keyword 'and'. In Vult language,
30 | this means that they share context. At the moment, declaring them differently could have an undefined
31 | behavior.
32 |
33 | To interact with knobs, switches, lights the following builtin functions are provided.
34 | NOTE: the knobs, switches and lights are numbered from 1 to 6
35 |
36 | getKnob(n:int) : real // value of the nth knob range: 0.0-1.0
37 | getSwitch(n:int) : bool // value of the nth switch: true/false
38 |
39 | setLight(n:int, r:real, g:real, b:real) // r, g, b range: 0.0-1.0
40 | setSwitchLight(n:int, r:real, g:real, b:real) // r, g, b range: 0.0-1.0
41 |
42 | samplerate() : real // current sample rate
43 | sampletime() : real // current time step (1.0 / samplerate())
44 | display(text:string) // display text in the screen
45 |
46 | */
47 |
48 |
49 | // Returns the r,g,b values for a given voltage
50 | fun getRGB(v) {
51 | if (v > 0.0)
52 | return v, 0.0, 0.0;
53 | else
54 | return 0.0, -v, 0.0;
55 | }
56 |
57 | // Takes two inputs and returns the result of different operations on them
58 | fun process(in1, in2) {
59 | // theses are declared as 'mem' so we can remember them and use them in 'update'
60 | mem sum = clip(in1 + in2, -1.0, 1.0); // use 'clip' to keep the signals in the specified range
61 | mem sub = clip(in1 - in2, -1.0, 1.0);
62 | mem mul = clip(in1 * in2, -1.0, 1.0);
63 | return sum, sub, mul;
64 | }
65 | and update() {
66 | _ = display("Add two LFO to IN1 and IN2");
67 | val r, g, b;
68 | // Set the light no 1 with the 'sum' value
69 | r, g, b = getRGB(sum);
70 | _ = setLight(1, r, g, b);
71 | _ = setSwitchLight(1, r, g, b);
72 |
73 | // Set the light no 2 with the 'sub' value
74 | r, g, b = getRGB(sub);
75 | _ = setLight(2, r, g, b);
76 | _ = setSwitchLight(2, r, g, b);
77 |
78 | // Set the light no 2 with the 'mul' value
79 | r, g, b = getRGB(mul);
80 | _ = setLight(3, r, g, b);
81 | _ = setSwitchLight(3, r, g, b);
82 |
83 | }
--------------------------------------------------------------------------------
/examples/vco.js:
--------------------------------------------------------------------------------
1 | // Voltage-controlled oscillator example
2 | // by Andrew Belt
3 |
4 | // For audio synthesis and process, JavaScript is 10-100x less efficient than C++, but it's still an easy way to learn to program DSP.
5 |
6 | config.frameDivider = 1
7 | config.bufferSize = 16
8 |
9 | let phase = 0
10 | function process(block) {
11 | // Knob ranges from -5 to 5 octaves
12 | let pitch = block.knobs[0] * 10 - 5
13 | // Input follows 1V/oct standard
14 | // Take the first input's first buffer value
15 | pitch += block.inputs[0][0]
16 |
17 | // The relationship between 1V/oct pitch and frequency is `freq = 2^pitch`.
18 | // Default frequency is middle C (C4) in Hz.
19 | // https://vcvrack.com/manual/VoltageStandards.html#pitch-and-frequencies
20 | let freq = 261.6256 * Math.pow(2, pitch)
21 | display("Freq: " + freq.toFixed(3) + " Hz")
22 |
23 | // Set all samples in output buffer
24 | let deltaPhase = config.frameDivider * block.sampleTime * freq
25 | for (let i = 0; i < block.bufferSize; i++) {
26 | // Accumulate phase
27 | phase += deltaPhase
28 | // Wrap phase around range [0, 1]
29 | phase %= 1
30 |
31 | // Convert phase to sine output
32 | block.outputs[0][i] = Math.sin(2 * Math.PI * phase) * 5
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/examples/vco.lua:
--------------------------------------------------------------------------------
1 | -- Voltage-controlled oscillator example
2 | -- by Andrew Belt
3 |
4 | -- For audio synthesis and process, Lua is 10-100x less efficient than C++, but it's still an easy way to learn to program DSP.
5 |
6 | config.frameDivider = 1
7 | config.bufferSize = 16
8 |
9 | phase = 0
10 | function process(block)
11 | -- Knob ranges from -5 to 5 octaves
12 | pitch = block.knobs[1] * 10 - 5
13 | -- Input follows 1V/oct standard
14 | -- Take the first input's first buffer value
15 | pitch = pitch + block.inputs[1][1]
16 |
17 | -- The relationship between 1V/oct pitch and frequency is `freq = 2^pitch`.
18 | -- Default frequency is middle C (C4) in Hz.
19 | -- https://vcvrack.com/manual/VoltageStandards.html#pitch-and-frequencies
20 | freq = 261.6256 * math.pow(2, pitch)
21 | display("Freq: " .. string.format("%.3f", freq) .. " Hz")
22 |
23 | -- Set all samples in output buffer
24 | deltaPhase = config.frameDivider * block.sampleTime * freq
25 | for i=1,block.bufferSize do
26 | -- Accumulate phase
27 | phase = phase + deltaPhase
28 | -- Wrap phase around range [0, 1]
29 | phase = phase % 1
30 |
31 | -- Convert phase to sine output
32 | block.outputs[1][i] = math.sin(2 * math.pi * phase) * 5
33 | end
34 | end
--------------------------------------------------------------------------------
/examples/vco.pd:
--------------------------------------------------------------------------------
1 | #N canvas 150 332 439 466 12;
2 | #X obj 69 34 route K1;
3 | #X obj 16 321 osc~;
4 | #X msg 101 346 display Freq: \$1 Hz;
5 | #X obj 115 112 adc~ 1;
6 | #X obj 69 111 sig~;
7 | #X obj 120 201 loadbang;
8 | #X msg 120 226 1;
9 | #X obj 120 251 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1
10 | 1;
11 | #X obj 120 272 metro 50;
12 | #X obj 101 297 snapshot~;
13 | #X obj 101 323 change;
14 | #X obj 69 138 +~, f 7;
15 | #X obj 69 60 * 10;
16 | #X obj 69 85 - 5;
17 | #X obj 16 185 *~ 261.626;
18 | #X obj 16 161 pow~ 2, f 8;
19 | #X obj 16 137 sig~ 2;
20 | #X obj 16 370 dac~ 1;
21 | #X text 145 162 <--- FM with CV signal from IN1;
22 | #X obj 16 346 *~ 5;
23 | #X obj 69 8 r fromRack;
24 | #X obj 101 370 print toRack;
25 | #X connect 0 0 12 0;
26 | #X connect 1 0 19 0;
27 | #X connect 2 0 21 0;
28 | #X connect 3 0 11 1;
29 | #X connect 4 0 11 0;
30 | #X connect 5 0 6 0;
31 | #X connect 6 0 7 0;
32 | #X connect 7 0 8 0;
33 | #X connect 8 0 9 0;
34 | #X connect 9 0 10 0;
35 | #X connect 10 0 2 0;
36 | #X connect 11 0 15 1;
37 | #X connect 12 0 13 0;
38 | #X connect 13 0 4 0;
39 | #X connect 14 0 1 0;
40 | #X connect 14 0 9 0;
41 | #X connect 15 0 14 0;
42 | #X connect 16 0 15 0;
43 | #X connect 19 0 17 0;
44 | #X connect 20 0 0 0;
45 |
--------------------------------------------------------------------------------
/examples/vco.scd:
--------------------------------------------------------------------------------
1 | // Voltage-controlled oscillator example
2 | // by Andrew Belt
3 | // adapted for SC by Brian Heim
4 |
5 | ~vcv_frameDivider = 1;
6 | ~vcv_bufferSize = 32;
7 |
8 | ~phase = 0;
9 | ~vcv_process = { |block|
10 |
11 | var pitch, freq, deltaPhase;
12 |
13 | // Knob ranges from -5 to 5 octaves
14 | pitch = block.knobs[0] * 10 - 5;
15 | // Input follows 1V/oct standard
16 | // Take the first input's first buffer value
17 | pitch = pitch + block.inputs[0][0];
18 |
19 | // The relationship between 1V/oct pitch and frequency is `freq = 2^pitch`.
20 | // Default frequency is middle C (C4) in Hz.
21 | // https://vcvrack.com/manual/VoltageStandards.html#pitch-and-frequencies
22 | freq = 261.6256 * pow(2, pitch);
23 | postf("Freq: % Hz", freq);
24 |
25 | deltaPhase = ~vcv_frameDivider * block.sampleTime * freq;
26 |
27 | // Set all samples in output buffer
28 | block.bufferSize.do { |i|
29 | // Accumulate phase & wrap around range [0, 1]
30 | ~phase = (~phase + deltaPhase) % 1.0;
31 |
32 | // Convert phase to sine output
33 | block.outputs[0][i] = sin(2pi * ~phase) * 5;
34 | };
35 |
36 | block
37 | }
38 |
--------------------------------------------------------------------------------
/examples/vco.vult:
--------------------------------------------------------------------------------
1 |
2 | /*
3 |
4 | Simple wave table VCO.
5 |
6 | Author: Leonardo Laguna Ruiz - leonardo@vult-dsp.com
7 |
8 | Check the API documentation in the basic.vult example
9 |
10 | */
11 |
12 | fun pitchToFreq(cv) @[table(size=128, min=-10.0, max=10.0)] {
13 | return 261.6256 * exp(cv * 0.69314718056);
14 | }
15 |
16 | // Generates (at compile time) a wave table based on the provided harmonics
17 | // To change the wave table, change the 'harmonics' array
18 | fun wavetable(phase) @[table(size=128, min=0.0, max=1.0)] {
19 | val harmonics = [0.0, 1.0, 0.7, 0.5, 0.3];
20 | val n = size(harmonics);
21 | val acc = 0.0;
22 | val i = 0;
23 | while(i < n) {
24 | acc = acc + harmonics[i] * sin(2.0 * pi() * real(i) * phase);
25 | i = i + 1;
26 | }
27 | return acc / sqrt(real(n));
28 | }
29 |
30 | fun process(input_cv:real) {
31 | mem phase;
32 | val knob_cv = getKnob(1) - 0.5;
33 | val cv = 10.0 * (input_cv + knob_cv);
34 | val freq = pitchToFreq(cv);
35 | val delta = sampletime() * freq;
36 | phase = phase + delta;
37 | if(phase > 1.0) {
38 | phase = phase - 1.0;
39 | }
40 |
41 | return wavetable(phase);
42 | }
43 | and update() {
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/faust_libraries/rack.lib:
--------------------------------------------------------------------------------
1 | /* ----------------------------------------------------------------------------
2 |
3 | ProtoFaust
4 | ==========
5 | DSP prototyping in Faust for VCV Rack
6 |
7 | Copyright (c) 2019-2020 Martin Zuther (http://www.mzuther.de/) and
8 | contributors
9 |
10 | This program is free software: you can redistribute it and/or modify
11 | it under the terms of the GNU General Public License as published by
12 | the Free Software Foundation, either version 3 of the License, or
13 | (at your option) any later version.
14 |
15 | This program is distributed in the hope that it will be useful,
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | GNU General Public License for more details.
19 |
20 | You should have received a copy of the GNU General Public License
21 | along with this program. If not, see .
22 |
23 | Thank you for using free software!
24 |
25 | ---------------------------------------------------------------------------- */
26 |
27 |
28 | // Converts 1 V/oct to frequency in Hertz.
29 | //
30 | // The conversion formula is: 440 * 2 ^ (volts - 0.75)
31 | // The factor 0.75 shifts 0 V to C-4 (261.6256 Hz)
32 | cv_pitch2freq(cv_pitch) = 440 * 2 ^ (cv_pitch - 0.75);
33 |
34 |
35 | // Converts frequency in Hertz to 1 V/oct.
36 | //
37 | // The conversion formula is: log2(hertz / 440) + 0.75
38 | // The factor 0.75 shifts 0 V to C-4 (261.6256 Hz)
39 | freq2cv_pitch(freq) = ma.log2(freq / 440) + 0.75;
40 |
41 |
42 | // Converts 200 mV/oct to frequency in Hertz.
43 | i_cv_pitch2freq(i_cv_pitch) = i_cv_pitch : internal2cv_pitch : cv_pitch2freq;
44 |
45 |
46 | // Converts frequency in Hertz to 200 mV/oct.
47 | freq2i_cv_pitch(freq) = freq : freq2cv_pitch : cv_pitch2internal;
48 |
49 |
50 | // Converts Eurorack's 1 V/oct to internal 200 mv/oct.
51 | cv_pitch2internal(cv_pitch) = cv_pitch / 5;
52 |
53 |
54 | // Converts internal 200 mv/oct to Eurorack's 1 V/oct.
55 | internal2cv_pitch(i_cv_pitch) = i_cv_pitch * 5;
56 |
57 |
58 | // Converts Eurorack's CV (range of 10V) to internal CV (range of 1V)
59 | cv2internal(cv) = cv / 10;
60 |
61 |
62 | // Converts internal CV (range of 1V) to Eurorack's CV (range of 10V)
63 | internal2cv(i_cv) = i_cv * 10;
64 |
--------------------------------------------------------------------------------
/plugin.json:
--------------------------------------------------------------------------------
1 | {
2 | "slug": "VCV-Prototype",
3 | "name": "Prototype",
4 | "version": "1.3.0",
5 | "license": "GPL-3.0-or-later",
6 | "brand": "VCV",
7 | "author": "VCV",
8 | "authorEmail": "contact@vcvrack.com",
9 | "authorUrl": "https://vcvrack.com/",
10 | "pluginUrl": "https://vcvrack.com/Prototype.html",
11 | "manualUrl": "https://vcvrack.com/Prototype.html#manual",
12 | "sourceUrl": "https://github.com/VCVRack/VCV-Prototype",
13 | "donateUrl": "",
14 | "changelogUrl": "https://github.com/VCVRack/VCV-Prototype/blob/master/CHANGELOG.md",
15 | "modules": [
16 | {
17 | "slug": "Prototype",
18 | "name": "Prototype",
19 | "description": "Run scripting languages for prototyping, learning, and live coding.",
20 | "tags": [
21 | "External"
22 | ]
23 | }
24 | ]
25 | }
--------------------------------------------------------------------------------
/src/DuktapeEngine.cpp:
--------------------------------------------------------------------------------
1 | #include "ScriptEngine.hpp"
2 | #include
3 |
4 |
5 | struct DuktapeEngine : ScriptEngine {
6 | duk_context* ctx = NULL;
7 |
8 | ~DuktapeEngine() {
9 | if (ctx)
10 | duk_destroy_heap(ctx);
11 | }
12 |
13 | std::string getEngineName() override {
14 | return "JavaScript";
15 | }
16 |
17 | int run(const std::string& path, const std::string& script) override {
18 | assert(!ctx);
19 | ProcessBlock* block = getProcessBlock();
20 |
21 | // Create duktape context
22 | ctx = duk_create_heap_default();
23 | if (!ctx) {
24 | display("Could not create duktape context");
25 | return -1;
26 | }
27 |
28 | // Initialize globals
29 | // user pointer
30 | duk_push_pointer(ctx, this);
31 | duk_put_global_string(ctx, DUK_HIDDEN_SYMBOL("engine"));
32 |
33 | // console
34 | duk_idx_t consoleIdx = duk_push_object(ctx);
35 | {
36 | // log
37 | duk_push_c_function(ctx, native_console_log, 1);
38 | duk_put_prop_string(ctx, consoleIdx, "log");
39 | }
40 | duk_put_global_string(ctx, "console");
41 |
42 | // display
43 | duk_push_c_function(ctx, native_display, 1);
44 | duk_put_global_string(ctx, "display");
45 |
46 | // config: Set defaults
47 | duk_idx_t configIdx = duk_push_object(ctx);
48 | {
49 | // frameDivider
50 | duk_push_int(ctx, 32);
51 | duk_put_prop_string(ctx, configIdx, "frameDivider");
52 | // bufferSize
53 | duk_push_int(ctx, 1);
54 | duk_put_prop_string(ctx, configIdx, "bufferSize");
55 | }
56 | duk_put_global_string(ctx, "config");
57 |
58 | // Compile string
59 | duk_push_string(ctx, path.c_str());
60 | if (duk_pcompile_lstring_filename(ctx, 0, script.c_str(), script.size()) != 0) {
61 | const char* s = duk_safe_to_string(ctx, -1);
62 | WARN("duktape: %s", s);
63 | display(s);
64 | duk_pop(ctx);
65 | return -1;
66 | }
67 | // Execute function
68 | if (duk_pcall(ctx, 0)) {
69 | const char* s = duk_safe_to_string(ctx, -1);
70 | WARN("duktape: %s", s);
71 | display(s);
72 | duk_pop(ctx);
73 | return -1;
74 | }
75 | // Ignore return value
76 | duk_pop(ctx);
77 |
78 | // config: Read values
79 | duk_get_global_string(ctx, "config");
80 | {
81 | // frameDivider
82 | duk_get_prop_string(ctx, -1, "frameDivider");
83 | setFrameDivider(duk_get_int(ctx, -1));
84 | duk_pop(ctx);
85 | // bufferSize
86 | duk_get_prop_string(ctx, -1, "bufferSize");
87 | setBufferSize(duk_get_int(ctx, -1));
88 | duk_pop(ctx);
89 | }
90 | duk_pop(ctx);
91 |
92 | // Keep process function on stack for faster calling
93 | duk_get_global_string(ctx, "process");
94 | if (!duk_is_function(ctx, -1)) {
95 | display("No process() function");
96 | return -1;
97 | }
98 |
99 | // block (keep on stack)
100 | duk_idx_t blockIdx = duk_push_object(ctx);
101 | {
102 | // inputs
103 | duk_idx_t inputsIdx = duk_push_array(ctx);
104 | for (int i = 0; i < NUM_ROWS; i++) {
105 | duk_push_external_buffer(ctx);
106 | duk_config_buffer(ctx, -1, block->inputs[i], sizeof(float) * block->bufferSize);
107 | duk_push_buffer_object(ctx, -1, 0, sizeof(float) * block->bufferSize, DUK_BUFOBJ_FLOAT32ARRAY);
108 | duk_put_prop_index(ctx, inputsIdx, i);
109 | duk_pop(ctx);
110 | }
111 | duk_put_prop_string(ctx, blockIdx, "inputs");
112 |
113 | // outputs
114 | duk_idx_t outputsIdx = duk_push_array(ctx);
115 | for (int i = 0; i < NUM_ROWS; i++) {
116 | duk_push_external_buffer(ctx);
117 | duk_config_buffer(ctx, -1, block->outputs[i], sizeof(float) * block->bufferSize);
118 | duk_push_buffer_object(ctx, -1, 0, sizeof(float) * block->bufferSize, DUK_BUFOBJ_FLOAT32ARRAY);
119 | duk_put_prop_index(ctx, outputsIdx, i);
120 | duk_pop(ctx);
121 | }
122 | duk_put_prop_string(ctx, blockIdx, "outputs");
123 |
124 | // knobs
125 | duk_push_external_buffer(ctx);
126 | duk_config_buffer(ctx, -1, block->knobs, sizeof(float) * NUM_ROWS);
127 | duk_push_buffer_object(ctx, -1, 0, sizeof(float) * NUM_ROWS, DUK_BUFOBJ_FLOAT32ARRAY);
128 | duk_put_prop_string(ctx, blockIdx, "knobs");
129 | duk_pop(ctx);
130 |
131 | // switches
132 | duk_push_external_buffer(ctx);
133 | duk_config_buffer(ctx, -1, block->switches, sizeof(bool) * NUM_ROWS);
134 | duk_push_buffer_object(ctx, -1, 0, sizeof(bool) * NUM_ROWS, DUK_BUFOBJ_UINT8ARRAY);
135 | duk_put_prop_string(ctx, blockIdx, "switches");
136 | duk_pop(ctx);
137 |
138 | // lights
139 | duk_idx_t lightsIdx = duk_push_array(ctx);
140 | for (int i = 0; i < NUM_ROWS; i++) {
141 | duk_push_external_buffer(ctx);
142 | duk_config_buffer(ctx, -1, block->lights[i], sizeof(float) * 3);
143 | duk_push_buffer_object(ctx, -1, 0, sizeof(float) * 3, DUK_BUFOBJ_FLOAT32ARRAY);
144 | duk_put_prop_index(ctx, lightsIdx, i);
145 | duk_pop(ctx);
146 | }
147 | duk_put_prop_string(ctx, blockIdx, "lights");
148 |
149 | // switchLights
150 | duk_idx_t switchLightsIdx = duk_push_array(ctx);
151 | for (int i = 0; i < NUM_ROWS; i++) {
152 | duk_push_external_buffer(ctx);
153 | duk_config_buffer(ctx, -1, block->switchLights[i], sizeof(float) * 3);
154 | duk_push_buffer_object(ctx, -1, 0, sizeof(float) * 3, DUK_BUFOBJ_FLOAT32ARRAY);
155 | duk_put_prop_index(ctx, switchLightsIdx, i);
156 | duk_pop(ctx);
157 | }
158 | duk_put_prop_string(ctx, blockIdx, "switchLights");
159 | }
160 |
161 | return 0;
162 | }
163 |
164 | int process() override {
165 | // block
166 | ProcessBlock* block = getProcessBlock();
167 | duk_idx_t blockIdx = duk_get_top(ctx) - 1;
168 | {
169 | // sampleRate
170 | duk_push_number(ctx, block->sampleRate);
171 | duk_put_prop_string(ctx, blockIdx, "sampleRate");
172 |
173 | // sampleTime
174 | duk_push_number(ctx, block->sampleTime);
175 | duk_put_prop_string(ctx, blockIdx, "sampleTime");
176 |
177 | // bufferSize
178 | duk_push_int(ctx, block->bufferSize);
179 | duk_put_prop_string(ctx, blockIdx, "bufferSize");
180 | }
181 |
182 | // Duplicate process function
183 | duk_dup(ctx, -2);
184 | // Duplicate block object
185 | duk_dup(ctx, -2);
186 | // Call process function
187 | if (duk_pcall(ctx, 1)) {
188 | const char* s = duk_safe_to_string(ctx, -1);
189 | WARN("duktape: %s", s);
190 | display(s);
191 | duk_pop(ctx);
192 | return -1;
193 | }
194 | // return value
195 | duk_pop(ctx);
196 |
197 | return 0;
198 | }
199 |
200 | static DuktapeEngine* getDuktapeEngine(duk_context* ctx) {
201 | duk_get_global_string(ctx, DUK_HIDDEN_SYMBOL("engine"));
202 | DuktapeEngine* engine = (DuktapeEngine*) duk_get_pointer(ctx, -1);
203 | duk_pop(ctx);
204 | return engine;
205 | }
206 |
207 | static duk_ret_t native_console_log(duk_context* ctx) {
208 | const char* s = duk_safe_to_string(ctx, -1);
209 | INFO("Duktape: %s", s);
210 | return 0;
211 | }
212 | static duk_ret_t native_display(duk_context* ctx) {
213 | const char* s = duk_safe_to_string(ctx, -1);
214 | getDuktapeEngine(ctx)->display(s);
215 | return 0;
216 | }
217 | };
218 |
219 |
220 | __attribute__((constructor(1000)))
221 | static void constructor() {
222 | addScriptEngine("js");
223 | }
224 |
--------------------------------------------------------------------------------
/src/FaustEngine.cpp:
--------------------------------------------------------------------------------
1 | /************************************************************************
2 | FAUST Architecture File
3 | Copyright (C) 2020 GRAME, Centre National de Creation Musicale
4 | ---------------------------------------------------------------------
5 | This Architecture section is free software; you can redistribute it
6 | and/or modify it under the terms of the GNU General Public License
7 | as published by the Free Software Foundation; either version 3 of
8 | the License, or (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program; If not, see .
17 |
18 | EXCEPTION : As a special exception, you may create a larger work
19 | that contains this FAUST architecture section and distribute
20 | that work under terms of your choice, so long as this FAUST
21 | architecture section is not modified.
22 | ************************************************************************/
23 |
24 | #include "ScriptEngine.hpp"
25 |
26 | #include
27 | #include
28 | #include