VCV

Prototype

Scripting language host for VCV Rack

Create your own VCV Rack module in JavaScript or Lua. (More languages coming soon.)

Prototype your idea, and share it by sending others your patch.

Learn or teach programming and digital signal processing.

Play a live-coding performance with automatic script reloading.

Prototype Manual

VCV Prototype offers 6 inputs, 6 outputs, 6 knobs, 6 RGB LEDs, 6 switches with RGB LEDs, and a console display for your script to interact with the VCV Rack world.

Currently Prototype supports scripts in JavaScript and Lua.

Loading scripts

To load a script, click the top section of Prototype’s display or right-click the panel and choose “Load script”. If the script fails to run, an error message will appear on the display, and a more detailed error message will be written to <Rack user folder>/log.txt.

Automatic reloading

When Prototype detects that the currently-running script file has changed (e.g. when you save the file in your text editor), the script is automatically reloaded and re-run. You can use this feature to perform live coding by writing code during the course of a musical performance.

Script embedding in patches

If you save a patch (or module preset) containing a VCV Prototype script, its source code is embedded in the patch. Your script can be shared by simply giving others your .vcv patch file.

When opening a patch containing a VCV Prototype script, a security warning is displayed before it runs. Only load scripts from patch artists you trust. Running Prototype scripts from untrusted sources may compromise your computer and personal information.

Scripting tutorial

It is recommended to learn Prototype scripting by using the “gain” script as a first example. This simple script applies gain (attenuation) to all 6 inputs with level knobs and mute buttons.

  1. Add a Prototype module to your rack and load gain.js or gain.lua from Prototype’s example folder.
  2. Right-click the panel and choose “Save script as”.
  3. Save a copy of the script to a convenient folder location (such as the Desktop) and useful filename (such as MyGain.js).
  4. Open the script with your favorite text editor, such as Sublime Text, Atom, Visual Studio Code, Notepad++, TextMate, vim, or Emacs.

You can review the script, edit the source code, save the file, and immediately see/hear the changes while VCV Rack is running.

Processing

VCV Prototype periodically calls your script’s process(block) function to read input voltages and parameters, and write output voltages and LEDs.

In your process() function, you can read the following values.

block.inputs[i][bufferIndex] // voltage of input port
block.knobs[i] // value of knob, between 0 and 1
block.switches[i] // pressed state of switch, true/false

The index i is the row of the input/knob/switch from 0 to 5 (1 to 6 in Lua). If no buffering is used (see config.bufferSize in the next section), use 0 for bufferIndex (1 in Lua).

You can write the following values.

block.outputs[i][bufferIndex] // voltage of output port

block.lights[i][0] // red, between 0 and 1
block.lights[i][1] // green
block.lights[i][2] // blue

block.switchLights[i][0] // red
block.switchLights[i][1] // green
block.switchLights[i][2] // blue

Knobs are also writable, although this usage is rare.

You can mix RGB colors, so to make the first LED yellow for example, use

block.lights[0][0] = 1
block.lights[0][1] = 1
block.lights[0][2] = 0

Note: Avoid setting arrays like block.lights[0] = [1, 1, 0] because the JavaScript blocks are actually TypedArrays tied to internal data.

Additionally, you can read the following settings.

block.sampleRate // Rack's sample rate
block.sampleTime // Inverse of Rack's sample rate
block.bufferSize // Number of values in the input/output buffer
Configuring

Before your script is run, you can set a few configuration options to specify the behavior of your script.

config.frameDivider

By default, a Prototype script processes voltage samples (frames) every 32 audio samples. If Rack’s engine sample rate is set to 44.1 kHz, this means your script will process a sample every ~0.7 ms, just enough to capture 1 ms clock triggers and fast enough to cause no audible “stepping” when modulating other modules.

For audio-rate scripts, you should set config.frameDivider = 1 in order to process every audio sample. However, calling process() 44,100 times per second will consume lots of CPU, so it is recommended to use buffering (below) to process multiple frames in a single process() call.

config.bufferSize

This sets the number of input/output frames to process per process() call.

Setting a buffer size of 8-32 is recommended for audio-rate scripts, as there is a lot of overhead in calling your script’s process() function. However, using buffering adds latency to your script, equal to buffer size * frame divider / Rack's sample rate seconds.

Script ideas

Here are a few module concepts for practicing script programming with VCV Prototype.

  • 6-input mixer: using the 6 knobs for levels, just like “gain”.
  • Quantizer: using the formula out = Math.round(in * 12) / 12.
  • VU meter: using the 6 (or 12) LEDs and console display to show decibels.
  • Clock divider: using a Schmitt trigger for detecting trigger inputs.
  • 6-step sequencer: using input 1 as a clock trigger, the 6 knobs for each step value, and the LEDs for displaying the current step.
  • Kick drum generator: by mixing a ~100 Hz sine wave with a long envelope and a noise source with a short envelope.
  • Double pendulum simulator using JW Modules Thing Thing for visualization.
  • AI for unless games piong.

Sharing your scripts

Join the VCV Community forum and post your script/preset in the Share your prototypes thread.

For C++ developers: Adding a scripting language

If you would like to add your favorite language to Prototype’s embedded interpreter, see Adding a script engine.


Source code on GitHub