VCVRack
VCV Rack.montage un peu sympa.png VCV Rack is a free and open-source cross-platform software modular synthesizer.
Overview[edit]
VCV Rack is a free open-source virtual modular synthesizer: multiple modules can be connected to synthesize a sound. By default the software contains several VCOs, LFOs, mixers, and other standard synthesizer modules, however more can be added as plugins through the VCV Rack website.[1][2]
Version 1.0.0 added a stable API, a multithreading engine[3] and support for polyphonic signals.[4]
Interconnectivity[edit]
In addition to the above features, VCV rack can also connect to other hardware and software by outputting analog CV/gate and digital USB or MIDI signals. The software can also connect to other VST plugins though the module host.
On the Satellite Of Love we Expert sleepers ES9 to connect VCVrack to "waveyLines the Eurorack system. Software versions of some of the most popular Eurorack modules on the market is available to download for free.
VCV Rack Basics[edit]
This chapter provides an overview of VCV Rack. It is not meant as a tutorial on synthesis with Rack, nor as a guide about all available modules. There are hundreds of modules and tens of developers, thus making it barely possible to track all of them down. Furthermore, the development community is very lively and active, and the modules are often updated or redesigned. The chapter just provides a common ground for the rest of the book regarding the platform, the user interface, and how a user expects to interact with it. It shall therefore introduce the terminology and get you started as a regular user, with the aim of helping you design your own modules with an informed view on the Rack user experience.
So, what is VCV Rack exactly? VCV Rack is a standalone software, meant to emulate a modular Eurorack system. It can also host VST instruments employing a paid module called VCV Host. In future releases, a paid VST/AU plugin version of Rack will be available, to be loaded into a DAW. According to VCV founder Andrew Belt, however, the standalone version will always be free of charge. At the moment, Rack can be connected to a DAW using a module called Bridge; however, its support will be discontinued as soon as the VST/AU plugin version is out. To record audio in VCV, the simplest option is to use the VCV Recorder module.
At the first launch, Rack opens up showing a template patch, a simple synthesizer, where modules can be added, removed, and connected. Patches can be saved and loaded, allowing reuse, exchange, and quick switch for performances.
Modules are available from the plugin store. In addition, they can be loaded from a local folder. This is the case for modules that you are developing and are not yet public but you need to test on your machine. Modules can be divided into a few families:
Core modules. Built-in modules that are installed together with Rack, for audio and MIDI connectivity. Fundamental modules. Basic building blocks provided by VCV for free. These include oscillators, filters, amplifiers, and utilities. VCV modules. Advanced modules from VCV. These are not free; their price sustains the VCV Rack project. Third-party modules. These are developed independently by the community and are available under the online plugin store. Some of them are free, some of them are paid, some are open-source, and some are not. If you are reading this book, you are probably willing to build new third-party plugins. Some developers provide both a commercial and a smaller free package (e.g. see Vult Premium and Free plugins, which provide exceptional virtual analog modelling of real hardware circuits). Eurorack replicas. Some modules available on the store are authorized replicas of existing Eurorack modules. These are free and include, among others, Audible Instrument, Befaco, Synthesis Technology (E-series), and Grayscale modules.
Overview of the System[edit]
Figure 3.1 shows a screen of Rack. Its interface is minimal, with just a few items on the top menu and the rest of the screen free for patching. Audio and MIDI settings, different from other music production software, are not hidden in a menu, but are directly available from the core modules.
Figure 3.1: The Rack GUI shows modules mounted on the rack rails. When launching the software for the first time, this template patch shows up, implementing a basic monophonic synthesizer.
Developing with VCV Rack[edit]
In Rack parlance, the term “module” refers to the DSP implementation of a virtual Eurorack-style module, while we use the term “plugin” to indicate a collection of modules, all bundled in a folder containing one compiled file, the shared object or dynamic library. Table 4.1 resumes all the terms in the Rack jargon.
Table 4.1: Some common terms in the Rack jargon plugin A collection of Eurorack-style modules implemented in a single dynamic library, developed by a single author or company. The Rack browser lists all plugins and allows you to explore all the modules contained in a plugin. Not to be confused with the term as used in the DAW and VST jargon, where it usually refers to one single virtual instrument. Plugin A C++ struct implementing the plugin. We shall use Plugin in monospaced font only when explicitly referring to the C++ struct. Model A C++ struct that collects the DSP and the GUI of a Eurorack-style module. module Not to be confused with the C++ struct Module. We shall use the generic term “module” to indicate either real or virtual Eurorack-style modules. Module A C++ struct that implements the guts of a module (i.e. the DSP part). ModuleWidget A C++ struct that implements the graphical aspects of a module.
VCV Rack modules are similar to the “plugins” or “externals” or “opcodes” used in other popular open-source or commercial standards in that they are compiled into a dynamic library that is loaded at runtime by the application (provided that it passes a first sanity check). However, Rack modules differ in all other regards. We shall highlight some of the differences in Section 4.1, then we shall go straight to showing the components required to create a module (Section 4.2), and then give an overview of basic APIs and classes used to define it and make it work (Section 4.3). At the end of this chapter, we shall start the practical work of setting up your coding environment (Section 4.4) and building your first “Hello world” module (Section 4.5).
Please note that some programming basics are assumed along this part of the book. You should have some experience with C++. We will recall some basic properties of the language at different points of the book as a reminder for users with little experience in C++ or developers who are used to working with other programming languages. 4.1 Comparison with Other Platforms
Music programming platforms have existed since the 1950s, starting with the first efforts from Max Mathews at Bell Labs USA with MUSIC I. Mathews had a clear vision of how a comprehensive music computing language needed to be designed. For this reason, by the first half of the 1960s, most of the basic concepts were already implemented in his works, with little variations up to these days. Notwithstanding this, in the decades since, there has been a lot of work to design new music computing platforms, to integrate them with new tools, to make them easier to work with, and to update them to the latest programming standards and languages. A lot of these platforms were born in the academic world and are open-source, usually based on C or C++ (think about Pure Data, Csound, SuperCollider, etc.), while some others are commercial (e.g. Steinberg’s VST and Apple AU). Others were born in an academic context but later taken as a full-fledged commercial project (e.g. Cycling ’74 Max/MSP).
VCV Rack is a commercial project with an open-source codebase, which makes it quite different from the others.
4.1.1 Audio Processing[edit]
All the aforementioned music platforms comprise a client application where audio processing objects can be loaded and executed. The client application is made of several parallel tasks, managing audio streams, the user interface, handling network connections – for remote audio (Gabrielli and Squartini, 2016) or for licensing and updating – and more. The musical objects usually do the fun stuff. The term “musical object” is just an umbrella term we need here for generalizing all musical programming platforms. In Pure Data, these objects are called externals, in Csound opcodes, and in VST plugins. In Rack, a plugin is rather a collection of objects, and these objects are often called modules, although the proper name for us programmers is Models.
All musical platforms are based on the concept of dynamic linking of dynamic libraries (i.e. libraries implementing additional functionalities – effects, synthesizers, etc. – that are loaded in the same virtual address space of the client application).
In all the classical music programming platforms, there is an audio engine that handles audio I/O and schedules the execution of the audio processing objects in an order that depends on their connections. The audio engine periodically invokes a special function that each audio processing object implements. This function, which for now we will simply call the audio processing function, is called periodically for signal processing to take place. The audio processing function feeds the object with new audio data and expects processed audio data to be returned. Of course, this is not mandatory. Some objects only take input data (e.g. a VU meter) and do not process it. Other objects have no audio input, but return audio data (e.g. function generators).
The audio engine period is determined by the data rate (i.e.
The Graphical User Interface: A Quick Introduction[edit]
We all recognize how much the look and feel of hardware synthesizer modules influence the user at first sight. This applies to software modules as well. They should look nice, clear to understand, and possibly have a touch of craze together with a “trademark” color scheme or a logo that makes all the modules from the same developer instantly recognizable. Ugly, uninspiring panels are often disregarded, especially in the Rack third-party plugins list, where there’s already so much stuff. A good mix of creativity and design experience makes the GUI catchy and inspiring, improving the user experience (UX).
In this chapter, we will deal with the practical details of creating a user interface. With Rack, the user interface is created in two stages:
Graphical design of the panel background (SVG file) using vector drawing software. Code development to add components and bind them to parameters and ports of the module.
The SVG file is used as a simple background for the panel. All the interactive parts, such as knobs, connectors, and so on, are added in C++. You will be guided in the design of the background file in Section 5.1.
As reported in Section 4.5.2, the whole module is contained into a ModuleWidget subclass widget that collects all the “physical” elements (knobs, inputs, outputs, and other graphical widgets) and links them to the signals in the Module subclass. The widget class fills the front panel with the dynamic components that are required for interaction or graphical components that may change over time (e.g. a graphic display, an LCD display, or an LED). There is a fair choice of components that you can draw from the Rack APIs (see Section 5.2), but in order to design your customized user interface you will need to create new widgets. This last topic is postponed to Chapter 9. 5.1 Generating SVG Files with Inkscape
All modules require one background image, stored as a scalable vector graphics (SVG) file. The file is stored in the ModuleWidget subclass. SVG is an open-standard vector graphic format required to obtain the best results in terms of graphical rendering with different screen resolutions. A vector graphic file describes the graphics in terms of shapes and vector, while a raster graphic file describes the graphic in terms of pixels. Any graphic file in VCV Rack will require different rescaling for each different monitor or screen resolution. Alternatively, doing this with raster graphic formats such as PNG or JPG requires interpolation, introducing an inherent quality reduction and reducing the readability of the front panel texts.
SVG files can be drawn with several vector graphics applications. However, we will show how to do that using an open-source software, Inkscape. Inkscape is available for all platforms and generates SVG files that are ready to use with Rack. It can be downloaded from https://inkscape.org/ or from the software store available with some operating systems.
We will refer to the graphical design of the ABC plugins. These are extremely simple and clean in their aspect to make the learning curve quick. The ABC plugins adopt the following graphical specifications1:
Light gray background fill with full opacity (RGBA color: 0xF0F0F0FF). A small 5 px-high blue band on bottom (RGBA color: #AACCFFFF). Title on top using a “sans serif” font (DejaVu Sans Mono, in our case, which is open-source) with font size 20 (RGBA color: #AACCFFFF). Minor texts (ports and knobs) will be all uppercase with DejaVu Sans Mono font but font size 14. Major texts (sections of a module, important knobs or ports) will be white in a blue box (RGBA color: #AACCFFFF).
Creating the Panel and the Background[edit]
First, we need to create a new file in Inkscape (File → New) and set some of its properties. Go to File → Document Properties (or Shift+Ctrl+D) and:
Make “mm” the Default Units. Make “mm” the Units (under Custom Size line). Set the Height to 128.5 mm and the Width to a multiple of 5.08 mm (1 HP), according to the width of the module you want to create.
It is suggested to use a grid for better alignment, snapping, and positioning of objects. In the Document Properties, go to the Grid tab, create a New Rectangular Grid, and verify that the spacing for both X and Y is 1 px and the origin is at 0, 0. Checking the “Show dots instead of lines” box is suggested for improved visibility.
Now we have an empty page whose limits are those of our module front panel. We can now create the background as a rectangle (shortcut: F4) of size equal to the page size. Hint: In order to avoid displacement errors, we suggest using snapping, which automatically snaps the rectangle corners to the page corners. To do this, enable the following options: “Enable Snapping,” “Snap bounding boxes,” “Snap bounding box corners,” and “Snap to the page border” (on the “Snap Control” bar).
We can open the “Fill and Stroke” dialog (shortcut: Ctrl+Shift+F) to set the color of the box. You can just input the RGBA color code that we decided at the beginning of this chapter. We also remove any stroke.
Finally, we decided to add a small colored band at the bottom of the panel as our “trademark,” and to make the panel a bit less dull. We create another rectangle (shortcut: F4) and we snap it to the bottom of the page. This time in the “Fill and Stroke,” we set a nice blue color as in the RGBA color code we decided at the beginning of this chapter.
The empty panel looks like Figure 5.1 now.
Figure 5.1: An empty panel of width 12 HP designed with Inkscape.
CHAPTER 6 Let’s Start Programming:
The Easy Ones[edit]
The boring part is over; from here on. we are going to build and test modules!
If you followed the previous chapters, you are already able to compile a module and edit its graphical user interface. In this chapter, we start with coding. The easiest way to take acquaintance with coding with VCV Rack is to build “utility” modules that are functional but do not require extensive DSP knowledge or complex APIs. We are going to set up a comparator module, a multiplexer/demultiplexer (in short, mux and demux), and a binary frequency divider, shown in Figure 6.1.
Figure 6.1: The modules presented in this chapter.
CHAPTER 7
Getting Serious:
DSP “Classroom” Modules[edit]
By now, you have the basics to develop Rack modules. In this chapter, we will start delving into DSP stuff, which is ultimately what we are aiming for when we program in VCV. This chapter will guide you into several examples and will report, along the way, useful tips for DSP programming. Finally, one of the modules will be modified to allow for polyphony.
The modules presented in this chapter are shown in Figure 7.1.
Figure 7.1: The modules presented in this chapter.
CHAPTER 8
Crunching Numbers: Advanced DSP Modules[edit]
This section deals with some more advanced topics that may be useful to start designing Rack modules. Since the range of topics to cover is incredibly wide, three selected topics have been covered that open endless exploration:
modal synthesis; virtual analog oscillators with limited aliasing; and waveshaping with reduced aliasing.
The latter two are surely very complex, especially in their mathematical details. For this reason, we will cover some theoretical background, but we will limit the complexity of the discussion, resorting to intuition as much as possible.
The modules in this section can get computationally expensive (see Figure 8.1). Each section discusses computational cost issues.
Figure 8.1: The modules presented in this chapter.
CHAPTER 9
The Graphical User Interface: Creating Custom Widgets[edit]
While Chapter 5 was meant to give a quick introduction to the creation of a GUI in Rack, using ready-made widgets and allowing the reader to move quickly to the development of the first plugins, this chapter discusses the development of new widgets. We start by introducing the rendering library, NanoVG, used to draw user-defined lines and shapes and to render SVG files, then we suggest how to customize available classes to get custom knobs and text labels. At the end of the chapter, we propose a variation of the Modal Synthesis plugin that adds an interactive GUI element for sound generation. 9.1 The Rendering Library: NanoVG
The rendering library used in VCV Rack is a third-party C library called NanoVG by Mikko Mononen. NanoVG is a light and thin interface layer between OpenGL and the application core, providing 2D anti-aliased rendering only, and it has been used by several other commercial and open-source projects. The Rack GUI is designed on top of NanoVG, and each GUI component has a draw function that is called periodically to perform its fancy stuff making use of NanoVG. Among the possibilities allowed by NanoVG library, we have:
drawing paths by nodes, arcs, beziers, and so on; drawing shapes (rectangles, rounded rectangles, rounds, etc.); striking and filling paths and shapes with solid colors or gradients; drawing text; and rendering SVG images.
All drawing operations with NanoVG are conducted referring to an object, the NVGcontext, which is passed as a pointer to each draw function and initialized by the nvgCreateGL2 function.
For instance, a draw function that implements the drawing of a rectangle is done as follows:
nvgBeginPath(vg); nvgRect(vg, 100,100, 120,30); nvgFillColor(vg, nvgRGBA(255,192,0,255)); nvgFill(vg);
The nvgRect defines a rectangle in the NVGcontext * vg starting at the coordinates defined by the 2nd and 3rd arguments, with width and height defined by the 4th and 5th arguments. A fill color is defined by nvgFillColor and the rectangle is filled with nvgFill. All these operations are preceded by nvgBeginPath, which must be called before each path or shape is created.
Colors are declared as NVGcolor objects, and have red, green, blue, and alpha floating-point values. However, an NVGcolor can be created using several utility functions:
nvgRGB (or nvgRGBf for floats) taking unsigned char (or float) red, green, and blue and settings by default the alpha to the maximum (no transparency); nvgRGBA (nvgRGBAf) taking unsigned char (float) red, green, blue, and alpha arguments; NvgLerpRGBA returning a NVGcolor interpolating from two NVGcolors given as input arguments; and nvgHSL (nvgHSLA) taking floating point hue, saturation lightness (and alpha) as input and transforming these to a regular RGBA NVGcolor.
Moving beyond the concept of color, we have the concept of paint (i.e. of a varied stroke or fill). The NVGpaint object allows for gradients or patterns. Gradients can be linear, boxed, or radial, while a pattern is a repetition of an image in both the horizontal and vertical axes.
Some example images are shown in Figure 9.1.
Figure 9.1: Examples of objects rendered in NanoVG: a solid color square (left) and a rounded rectangle with linear gradient paint (right).
CHAPTER 10
Additional Topics[edit]
10.1 Debugging the Code
No matter what, you will always need to debug your code. Debugging DSP code in general is not very straightforward. Parts of your application code are event-driven – code is executed when an event happens (e.g. when a user clicks on a widget) – and some parts are called at sampling rate. The former can be debugged easily; they allow you to stop the execution at any time to inspect variable values, check the call stack, or follow the execution flow. However, with the signal processing routines, you can’t always do that, as these run too fast for inspection, and sometimes getting in the way (stopping the execution) may alter the execution flow, resulting in unwanted behaviors or making bugs disappear.
If the information you need to inspect can be analyzed at key events, such as the change of a parameter, or if the event happens at a low frequency, you have options to debug the code easily. In these cases, you can stop a debugger or write the debug data to a console at key events.
Inspecting the code with the GNU Debugger (gdb) is quite easy, but let us cover some basics first.
Rack and the plugins are compiled from C++ into binaries, containing the program translated into assembler and the data (e.g. hard-coded constant values). Only the machine is able to read this stuff.
A debugger is a software application that allows the user to alter the execution of its application, for example, by stopping it into specific lines of code (using so-called breakpoints), inspecting the values of variables, or stopping when they are read or written (so-called watchpoints). Furthermore, the user is able to step the code line by line, read and alter the content of the memory, or inspect the call stack (i.e. the stack of active function calls). The debugger, however, needs extra information to help the user in his or her task, including:
the list of symbols (variables, functions, classes), their names, and their memory address; and the code and its correspondence to the assembly to be executed by the machine.
Debug symbols can be generated at compile time. These are necessary to perform a meaningful debug session and are generally embedded in the compiled application binary. The vanilla Rack binary that you can download from the website does not contain debug symbols. However, the makefile that comes with the development version that you clone from Git instructs the compiler to add the debug symbols using the “-g” flag. This is added to the FLAGS variable in the compile.mk makefile include file, in the Rack root folder. Thus, the Rack binary you are now using for development has debug symbols, and similarly all the plugins you compiled have debug symbols. 10.1.1 Running a Debug Session
The debugger is an application that runs your application and controls its execution. In other words, it wraps the application (or debugee). To execute Rack into GDB, you can issue the following command:
gdb –– args ./Rack -d
The “--args” flag tells GDB to call the application with the arguments provided after its name, in this case the “-d” flag. The debugger will start and load Rack and its symbols. If it finds these, it will show “Reading symbols from ./Rack…done.”
Now a prompt appears and you can start the debug session. If you have never used GDB, a few commands will come in handy. A non-exhaustive list is reported in Table 10.1.
Table 10.1: A list of basic GDB commands Command Abbreviation Arguments Description run r Starts the application break b <filename>:<line> Sets a breakpoint at the specified line in the source code break b <class>::<method> Sets a breakpoint at the start of the method delete d <breakpoint number> Deletes a previously set breakpoint print p <variable> Prints the value of a variable or array next n Advances by one line of code without entering into functions step s Advances by one line of code possibly entering into called functions continue c Resumes normal execution until next break event happens or until the end of the application life where / Shows the call stack quit q Stops the debugee and the debugger
You will usually set some breakpoints before you start running the application. At this point, the debugger only knows symbols from Rack. Since your plugins will be loaded dynamically by Rack after you start it, their symbols are not yet known. If you ask GDB to set a breakpoint at:
break ADPWOsc<double>::process
the debugger will tell you to “Make breakpoint pending on future shared library load?” If you are sure that you spelled the filename and the line correctly, you can answer “y”. Indeed, when Rack will load the libraries, their symbols will be visible to the debugger as well, and GDB will be able to make use of them. Now you can run the debuggee:
run
Rack is running and you can interact with it as usual. Now load ADPWOsc. Rack will load it, and as soon as the process function is called for the first time GDB will stop the execution at the
CHAPTER 11 After Reading This Book
The first aim of this book is to leverage the fun and simplicity of VCV Rack to help the reader get involved with programming, digital signal processing, and music experimentation. This book is thus not only a quick guide to Rack, but also a bridge toward in-depth learning of many other subjects. With this in mind, some suggestions for further reading are left to the reader, in the hope that his or her next read will be a deeper and more complex book on one of the suggested topics. Other suggestions are also provided for those who prefer to play with electronics. Have fun! 11.1 Forking the ABC Collection
The ABC plugin provides a few essential modules that I found useful to gradually introduce the reader to basic concepts of musical signal processing. However, there is much more to experiment with. First of all, the modules only provide basic functionalities to avoid introducing unnecessary complexity that would deviate the reader from the main point of the discussion. As an example, a real-world sequencer would have many more sequencing options, such as a swing control, tempo signature control, sequence save and recall, auxiliary inputs and outputs, and maybe an internal quantizer to play notes on the equal temperament.
Now that you have learned the basics, you can fork the ABC project and make your own experiments. Some examples to enhance the modules functionalities are provided in the exercises. A few more suggestions for creating new modules that could complement the ones already provided by ABC are:
a sample and hold (S&H) module; a generator of constant CV values; an LFO module; a VCA module; a delay module; a chord generator; a sample reader or a wavetable oscillator; a drum sequencer; a linear-FM synthesizer; and basic physical modeling modules to interconnect.
You can take inspiration from the huge collection of plugins available from the plugin manager or invent something new. 11.2 Learn More about Virtual Analog Algorithms
There are many resources, by now, on electronic circuits modeling by virtual analog algorithms.
For what concerns basic alias-free oscillator algorithms, you should go on reading about BLEP and related methods. In this book, we covered some basics of oscillators with suppressed aliasing, giving priority to the intuitive DPW method. If you are interested in more oscillator algorithms, you may start reading the tutorial article (Välimäki and Huovilainen, 2007). A family of anti-aliasing algorithms that you need to learn about is the quasi-band-limited algorithms, starting with BLIT (Stilson and Smith, 1996) and further expanded with the BLEP (Brandt, 2001) and BLAMP techniques (Esqueda et al., 2016). Please note that in Välimäki et al. (2010a), the DPW technique is found to be strictly related to the BLIT technique. The minBLEP technique is implemented in include/dsp/minblep.hpp and src/dsp/minblep.cpp so you can implement a minBLEP oscillator starting from it after you are acquainted with its foundations.
A conceptually simpler implementation of oscillators is based on wavetables (Massie, 1998). These require frequent access to the memory and accurate interpolation. The waveshape can be morphed by mixing different wavetables, and a lot of great digital synthesizers from the 1990s on used this technique (and many still do). Aliasing is not an issue with these oscillators as long as you follow some precautions, and once you have set up a working wavetable oscillator it will be ready to take any wavetable you feed to it.
Many other filter topologies not covered here can be studied in Pirkle (2014). The state-variable filter can include nonlinearities. Other filter topologies, including Sallen-Key and the Moog ladder filter, are found on many hardware and software synthesizers. For those who are interested in the discrete-time modeling of analog filter topologies, a fundamental reference is Zavalishin (2018).
More generally, any electronic circuit can now be transposed to the digital domain thanks to the advances in the field. One approach for solving the differential equation of a circuit is the wave method (W-method) (Bilbao, 2004; Sarti and De Sanctis, 2009; de Sanctis and Sarti, 2010), also known as the wave-digital method. Other methods are based on Kirchoff variables, and are hence named Kirchoff methods (K-methods). These were first introduced in Borin et al. (2000), where they are shown to extend previous techniques for delay-free loop elimination (Härmä, 1998) to any sort of nonlinear circuits. Finally, Port-Hamiltonian approaches have recently been proposed in the audio field (Falaize-Skrzek and Hélie, 2013), drawing from the Hamiltonian formulation of systems (Maschke et al., 1992). All these methods and others are resumed in D’Angelo (2014).
Many recent works from Julian Parker discuss West Coast modules such as wavefolders and low-pass gates (Esqueda et al., 2017; Gormond et al., 2018). Other interesting analog effects to emulate are spring reverbs (Välimäki et al., 2010b; Parker, 2011) and tape delays (Zavalishin, 2018). Keep track of the DAFx conferences, held yearly, for updates on the virtual analog field. Their proceedings are available online. 11.3 Experiment with Novel Digital Algorithms
There are a lot of interesting and novel algorithms that could be great to have implemented on a virtual modular synthesizer. First things first, traditional DSP techniques should be the object of thorough study. The classic digital audio effects reference by Udo Zölzer covers all sorts of effects (Zölzer, 2011), while another book by Will Pirkle explains how to implement them in C++ (
References[edit]
- ↑ Ted Pallas, ed. (7 December 2017). "A guide to VCV Rack, a software Eurorack modular you can use for free". CDM.
- ↑ Mark Strauss, ed. (6 March 2018). "VCV Rack - Open-source modular synthesiser". residentadvisor.net.
- ↑ "Rack/CHANGELOG.md". VCV Rack on Github.
- ↑ Peter Kirn, ed. (19 June 2019). "VCV Rack hits 1.0; why you need this free modular now". cdm.link.