Voltage Programmer's Guide 1.0.6
Voltage Programmer's Guide 1.0.6
Voltage Programmer's Guide 1.0.6
Version 1.0.6
www.cherryaudio.com
Table of Contents
Theory of Operation 4
Processing Samples 4
Technical Specifications 5
Creating a Module 11
Module Controls 32
Library Classes 33
Voltage Modules are written in Java, and all code is Java 8 SE compliant. All of the capabilities
of the Java language are at your disposal, including multithreading, encryption, networking
capabilities, and more. Voltage is powered by a highly optimized “hot spot” virtual machine that
compiles the Java functions directly to machine language, so modules run at essentially the
same speed as compiled native code.
Processing Samples
The Initialize() function gets called once, when a module is first created. Any default values can
be set up in this function. For example, filters and oscillators can be configured, effect
algorithms can be set to their default values, lists can be populated, etc.
For every sample that is generated by Voltage Modular, a module’s ProcessSample() function
is called. This is the most important function of any module, as it does the core work of the
module. Typically, the primary operation of a module involves reading one or more input signals
from input jacks, processing these signals, and outputting the processed values to output jacks.
Of course, some modules, such as oscilloscopes, may not have output jacks, and other
modules, such as simple oscillators, may not have input jacks.
While controls such as knobs, sliders, jacks, buttons, etc., are drawn natively by the Voltage
application, they are created by calls from the Java code, and notifications are sent to the Java
module when controls are modified. By processing these notifications, controls such as gain
knobs, frequency sliders, etc. can alter the sound of a module. The Notify() function gets called
whenever controls are modified. In addition, notifications can be sent for mouse events,
connecting and disconnecting cables, GUI updating, and other events.
Initialize(), ProcessSample() and Notify() are the critical functions necessary to build almost
any module. However, there are additional functions that you can use to save and restore
custom settings, format custom tooltip text, handle custom undo/redo commands, and more.
With many simple modules it may not be necessary to write code for these additional functions,
but advanced modules will find that these extra functions will allow you to customize your
modules in many useful ways.
Technical Specifications
All samples within Voltage module are 64-bit floating-point doubles at 48Khz. Audio coming into
and going out of Voltage will be seamlessly resampled to match the sample rate of the host
application with a high-quality resampling algorithm.
Floating-point denormals are deactivated (flushed-to-zero) on the CPU level by Voltage, so your
DSP code does not need to worry about correcting for denormals.
Voltage modules are designed to process a nominal input and output range of +/- 5.0 “volts.”
Incoming audio is mapped from (-1.0, 1.0) to (-5.0, 5.0) and outgoing audio is mapped from
(-5.0, 5.0) to (-1.0, 1.0) when it is returned to the sound device or to your DAW. Modules can
certainly output higher or lower voltages - there is no limit - but some modules, such as filters,
are likely to clip when signals above (-5.0, 5.0) are received.
In this way, audio and control signals can be used completely interchangeably. LFOs and
oscillators output (-5.0, 5.0) and audio signals coming in to Voltage have the same range. You
can use audio to modulate values, or run an LFO through a filter to create an unusual wave
shape. There should be no distinction whatsoever between audio signals and control signals,
and your modules should function with any signals.
Installing the Module Designer
Installing the Module Designer tool requires two main steps:
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
The current JDK SE 8 is Build 8u181. Be sure to download and install the correct JDK version
for your computer. “macOS” and “Windows x64” will be the most common downloads.
Please note: Windows Users will need to modify their Path to point to the Java JDK’s bin folder.
Please see
https://docs.oracle.com/javase/7/docs/webnotes/install/windows/jdk-installation-windows.html for
instructions. You’ll want to add something like C:\Program Files\Java\jdk1.8.0_181\bin to your
Path environment variable.
Once you’ve run the JDK installer, open a Command Prompt in Windows or a Terminal on OSX,
and type in the following command:
java -version
javac -version
javac 1.8.0_181
Be sure the version shown in both of these tests is at least 1.8. If the java or javac
commands cannot be found, there may be an issue with your installation. If you’re using
Windows, you probably forget to add the Java folder to your system path. See the link above for
instructions.
Please note: If you have a newer Java JDK installer, that’s probably OK, but be careful not to
use any JDK9+ commands in your Java module, because they won’t run in our Java 8 virtual
machine.
If your Java version is correct, and you’ve installed the Voltage Module Designer, then you’re
done! Let’s start building modules!
Configuring the Module Designer
Before we begin programming, let’s first configure the Module Designer’s settings. To do so,
click on the Edit menu and select Preferences.
Audio Settings
In the Audio Settings section, you’ll select your Input and Output devices, set your sample rate
and buffer size/latency, and choose any MIDI devices that you want to use when testing a
module.
Code Editor
The Code Editor preferences allow you to customize your font and spacing choices.
Miscellaneous
The Miscellaneous settings allow you to choose a JDK location and modify some additional
settings. Note that it is not necessary to choose a JDK location unless you wish to use a JDK
other than the default JDK installed on your system.
Creating a Module
The basic steps for creating a module are:
1. Setting the basic parameters for a module, including module name, Java class name,
Package Name, module width, etc.
3. Placing controls, such as jacks, knobs, buttons, text labels, etc. onto the module.
4. Writing the Java code for the module to hook up all the controls.
To configure the basic properties of a module, click on the background of a module and you will
see the Module Properties in the Properties Pane. (If you don’t see the Properties Pane, click
View->Properties Pane to ensure that it is visible.)
Module Name
This is the full name of the module. The module will be listed in a user’s module library and in
the Voltage Module Store with this name.
Package Name
This is the name of the unique package that this specific module belongs to. The package for
every module you create should be unique. Java package naming conventions can be found
here.
Manufacturer
This should be your name, or the name of your company. Modules will be listed in a user’s
module library and in the Voltage Module Store with this manufacturer name.
Type of Module
This allows you to choose one of five main categories for your module. The categories are:
It is very important that you select the best category for your module. Modules will be listed in a
user’s module library and in the Voltage Module Store with this selection. In addition, choosing
the correct module type helps Voltage mix audio in the most efficient manner.
The module shown is 3.2 inches wide, which is 16 HP. At 100% zoom, the module will be 230
pixels wide by 360 pixels high. You can use these dimensions to create custom background art
for your module.
Background
This launches a dialog that lets you select your module’s background. It can be either a solid
color or an image file.
Extra Resources
This lets you embed additional resources (such as audio files in a sampling module, to name
one likely example) in your module. Use the GetBinaryResource function to obtain ByteBuffers
resources you’ve added to the Extra Resources section.
Copyright
This field allows you to declare a copyright statement that will be embedded in your published
module.
Notes
You can use this field to store any notes about this module. These notes won’t be added to your
published module; they’re there strictly for your benefit.
Placing Controls
To place controls onto your module, make sure that the Controls Pane is visible. If it isn’t, click
View->Controls Pane to show the pane.
On the Controls Pane, you will see a list of various controls that can be added to a module.
Adding these controls is as simple as dragging and dropping them onto your module.
For example, to add a knob to your module, simply click on the “Knob” text and drag the control
onto your module. When you release the mouse button, a knob will be created on your module.
The red outline indicates that this control is currently selected. To resize the control, click on the
red outline and drag in any direction. Note that some controls, such as jacks, cannot be resized,
and other controls, such as knobs, will always have a fixed ratio of width to height. Controls in
Voltage use vector graphics, so it is safe to resize them to any size that you want.
When a control is selected, the control’s properties will be shown in the Properties Pane.
Every control will have the following properties:
Name
This is the visible name of the control. It is important to name every control well, because these
names are often visible to the user. For example, a volume control should be given a
descriptive name, such as “Master Volume”. Note that every control name must be unique.
In addition, once you have published your module, you should not change the control
names, as they are used to save & restore the settings of a module. So please take care to
name every control well from the start.
Variable Name
Every control is represented by a variable in the Java code. To make programming easier, it is
recommended that you give controls a descriptive variable name. For example, a volume
control might be given a variable name of volumeKnob. A variable will be automatically created
for each control. It will look like this:
Left
This is the X position of the control on the module.
Top
This is the Y position of the control on the module.
Width
This is the width of the control.
Height
This is the height of the control.
There are multiple ways to change the position of a control. You can drag it with your mouse;
you can select it and use your arrow keys to position it; or you can manually type in new values
into the Left and Top property fields.
Likewise, there are multiple ways to resize a control. You can drag the red outline to resize a
control; or you can type new size values into the Width and Height property fields.
Every control will have automatically-generated code that creates the control, sets its position,
and sets any flags and properties. When you change any property of a control, including its
variable name, all of the automatically generated code will be instantly updated to match the
new settings.
Each controls type will have many additional properties that will be discussed in more detail in
the documentation for each control type.
Module Functions and Variables
While the code to create a module’s controls is automatically generated, it is up to the
programmer to write the code that makes the module actually do something useful. The
following functions are available to the module programmer.
If you wanted to create your own function to set the current volume, you might write:
If we have a knob called masterVolume, we might write the following Initialize code to read the
start position of the knob:
It is likely that many additional notifications will be added to Voltage Modular over time.
It is always a good idea to write intelligent and efficient code in your ProcessSample() algorithm.
If a module is not connected to any outputs, for example, it may be possible to skip sections of
CPU-intensive DSP processing. You will always want to write a value of 0 to any outputs, even
if you’re skipping DSP processing, so that values do not get “stuck” on a cable when a module’s
inputs are disconnected.
outputJack.SetValue(outputSignal);
}
In some cases, you may wish to show a different value. For example, you may wish to show a
value with particular units. Or, for example, filter cutoff frequency knobs work best when they
operate logarithmically instead of linearly. In these cases, you can add code to the
GetTooltipText() function to return a custom tooltip for a specific control.
As in GetTooltipText, certain controls may display tooltip values that do not line up directly with
the minimum and maximum values of the control. For example, a filter knob may have a min of
0 and a max of 1.0, but may display values from 20 to 20000, with a logarithmic response. In
these cases, if a user types in a frequency that they want to set the knob to, e.g. 10000, this
function can be used to map the value that is typed in to the correct linear mapping. For
example, the value 10000 may map to a linear value of .20 on a knob.
In this case, your code must change the newValue variable to a correct linear mapping between
the Min and Max values of the control.
However, many more complex modules have have controls that affect internal values. For
example, there might be buttons for transposing an octave setting up or down, or for setting a
MIDI channel, or for loading a sample. In these cases, storing the knob, slider, and toggle button
positions won’t be enough to restore the state of a module.
In these cases, additional module information, such as the selected octave, MIDI channel, file
path, etc., can be saved and restored using the GetStateInformation() and SetStateInformation()
functions. GetStateInformation() returns a byte array that can contain any sort of information
that you want to store, in any format. SetStateInformation() receives that same byte array back
and must decode it.
We recommend using the java.util.Properties class to easily store various properties for your
module, and the java.io.ByteArrayOutputStream and java.io.ByteArrayInputStream classes
to convert the Properties object into a byte array, and later convert the byte array back to a
Properties object. However, you can use any method you’d like to store and restore the data.
For example, a String can be turned into a byte array as follows:
Note: any Java imports that you wish to add to the project, such as
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
The first function stores the previous value and the new value as a double. The second function
allows you to store the previous value and new value as a generic Object. You can pass in any
object, such as a String.
That’s all you need to do. The first string, “changeMidiChannel”, identifies the undo operation.
This label will be passed in to OnUndoRedo() as the String undoType. The second string,
“Change Midi Channel”, is the description of the undo event, and is shown to the user if they
hover over Voltage Modular’s undo or redo buttons. Finally, currentChannel and
currentChannel+1 are the “before” and “after” values. The “before” value will be passed in to
OnUndoRedo() when a user hits Undo. The “after” value will be passed in to OnUndoRedo()
when a user hits Redo.
To create this simple module, we will start by setting the module’s properties. We will give the
module a name (“Volume Module”), a Java Class Name (“VolumeModule”), a package name
(“com.cherryaudio.volumemodule” in our case -- but you would want to use your own package
name), and set its width (10 HP, or 2.0 inches). If you want to add a custom background skin,
you can, but for this example we’ll just use the default grey background.
We will drag in a knob, an input jack, and an output jack. We’ve also added three text labels,
which read “Volume”, “Input”, and “Output”:
Next, we’ll set up the properties for the Input Jack and the Output Jack. We’ll want to name the
jacks (“Input Jack” and “Output Jack”) and give them proper variable names (“inputJack” and
“outputJack”) as shown:
Likewise, we’ll configure the volume knob. We’ll name it (“Volume Knob”) and give it a variable
name (“volumeKnob”). We’ll choose a skin for it, too (we’ve chosen “Cosmo Large”).
Now, we’ll want our volume module to go from 0 to 200%, so we’ll set the Min Value to 0.0 and
the Max Value to 2.0. We’ll also check the “Display Values In Percent” checkbox so that tooltips
will multiply the number by 100 and display the volume in percent (0 to 200%):
In the User Variables & Functions section of the Source Code, we’ll create a private variable
called volumeValue, of type double, to store the current volume value:
Next, we’ll modify the Initialize function. We want the volumeValue variable to be set to the
volume knob’s default value when the module is first created. We can call the GetValue()
function on the knob to get its current value:
Now, when the user turns the Volume Knob, our module’s Notify() f unction will get called. The
notification will be Knob_Changed, the specific component (volumeKnob) that changed will be
passed in to the Notify() f unction’s component variable, and the new value will be passed in to
the Notify() f unction’s doubleValue parameter.
We’ll modify the Notify() f unction to check for a Knob_Changed message coming from our knob
with the variable name of volumeKnob. If this notification comes in, we’ll store the new volume
value, which will be between 0 and 2.0, in our volumeValue v ariable.
Now that all of the elements are in place, we just need to write our ProcessSample() function!
This function needs to read a signal from the input jack, adjust the signal’s volume, and write the
modified signal to the output jack. Since adjusting a signal’s volume is just a matter of
multiplying the signal by the volume, this can be very easily accomplished with just a few lines
of simple code:
At this point, we should have a fully functioning Volume module. Let’s compile it to make sure
our code is correct. To compile the module, we’ll click on the Build menu and select the “Build”
menu option. If everything worked correctly, we should see something like this in the Output
Pane:
However, if there’s an error, the output pane will show you exactly what’s wrong. If you don’t
see any output at all, then there is an issue with your Java Development Kit installation.
Please follow the instructions in the “Installing the Module Designer” section to resolve this
issue.
Once the module builds correctly, we’ll want to test it. To do this, click on the Build menu and
select “Run without Debugger”. This will compile the module and then actually load and run your
module in a test environment. This will allow you to instantly test your module to make sure it
works. Pretty cool, right?
If the module builds correctly, it should show up next to the Module Design’s Test Module, which
creates test signals that you can use to test your module. Connect the “L” or “Mono” Test Signal
Output to your Volume Module’s input jack, and connect your Volume Module’s output jack to
the “Audio Ret To Host” L jack, as shown below. Make sure the Square Wave output is
selected, and adjust the Oscillator Frequency knob to something audio, perhaps around 100 Hz.
If you’ve done everything correctly, you should now be hear a square wave. And, you should be
able to turn your Volume knob to increase or decrease its volume, or to silence it altogether.
When you’re done, click on the Build menu and select “Stop Running” to end test mode.
Now that we have a functional module, let’s discuss two ways that we can improve the design of
this module.
When running this module in Test Mode, you may notice that the volume can jump from one
value to another pretty quickly, especially if you turn the volume knob very fast. Quick changes
in volume can create unpleasant distortion in the sound, and the module might not feel as
professional as it could be.
To correct this, we’re going to use a SmoothValue object, one of the many helpful tools that
you’ll find in Voltage’s Audio Processing library. You’ll find SmoothValue and many other tools
listed in the “Library” section of the Source Code Pane, as shown:
SmoothValue is a very useful tool. We call SetValue() to change the SmoothValue’s value, and
GetSmoothValue() to read its value. The SmoothValue class will then glide quickly from one
value to another. The glide is, by default, very fast (25 milliseconds), but it will ensure smooth
changes from one value to another.
To use SmoothValue, we’ll replace our volumeValue variable, which was a double, with a
SmoothValue object:
With these changes made, we can select “Build and Run” in the Build menu and test our
module. No matter how quickly we move the Volume knob, volume adjustments will always be
smooth.
For our second improvement, let’s make the ProcessSample() f unction more efficient. There are
two key improvements we can make:
#2 is particularly interesting. If there’s no cable plugged into the Output jack, then there’s no
reason to perform any calculations at all in this module. We can save valuable CPU resources
by checking to see if anything is connected to the output jack, and skipping our signal
processing if there’s nothing there. The new code looks like this:
It’s always a good idea to write efficient ProcessSample() code. Remember, your module will be
sharing the CPU with dozens, or maybe hundreds, of other modules in a patch. There’s no
reason to use CPU resources if the module isn’t doing anything useful.
Functions like IsConnected() can be found in the “Library” section of the Source Code Pane,
under GUI Controls, VoltageAudioJack:
There are all sorts of useful functions available that you can call on various components. In fact,
you can even drag these functions from the library directly into your code. You can also hover
the cursor over any function name in the library to see a tooltip listing its return and argument
types.
Module Examples Included In Developer Kit
In the Sample Modules folder in the Voltage Developer Kit, you’ll find several useful demo
projects that will show you how to use various aspects of the software.
● LFO Demo Module - This simple demo module shows how to use Voltage’s LFO class
to generate a square wave and triangle wave LFO signal. The module demonstrates
how to light an LED and how to use a knob to change the frequency of an oscillator.
● Filter Module - Demonstrates how to use the SaturatedAnalogFilter class to filter audio.
Features adjustable cutoff and resonance, and both a lowpass and highpass output.
This module also includes a modulation input with modulation amount knob, and
demonstrates how to read a CV signal and use it as a modulation source.
● Limiter Module - This demo shows how to incorporate additional class files into a
Voltage Module project. The audio limiter DSP is contained in a class called
SignalLimiter in the file SignalLimiter.java, and has been added to the Addition Java
Files list in the module properties. The module features an adjustable limit level and an
optional volume boost button.
● GUI Update Timer - This less-than-practical example module demonstrates how to use
a GUI timer to update graphical elements of a module. An LFO running at 1 Hz is used
to generate values from 0 to 1.0. A GUI timer fires every 100 milliseconds and sends a
GUI_Update_Timer message to the module’s Notify function. When this message is
received, we set all these controls to the LFO’s current value.
● VU Meter - A simple demo, illustrating how to use a GUI timer to update an Analog VU
Meter. We store the highest amplitude signal that comes into the input and use its value
to update the meter when the GUI timer fires.
● Oscilloscope - This project demonstrates how to use a Canvas object to draw custom
artwork from Java. Waveform data is stored in a buffer, and a GUI timer is used to draw
the waveform onto the Canvas control.
● Sound File Player - This project demonstrates how to binary embed resources into a
module - in this case, an MP3 file - and how to use the VoltageSound class to decode
the MP3 to access the raw samples. When the module is switched to On, it will decode
the MP3 in a continuous loop. The VoltageSound class ensures the audio is decoded to
stereo audio at Voltage’s internal sample rate.
Module Controls
Name: the name of the control as it will appear in Voltage Modular when it’s used in automation
or gets mapped to the Performance Module. As mentioned earlier, it’s also used when saving &
restoring the control’s state when your module gets saved in a Voltage Modular preset, so avoid
changing this name after you’ve published the module.
Variable Name: the control’s Java variable name. It needs to meet Java standards for variable
names or your code won’t compile.
Left, Top, Width, and Height: The control’s size and position. Some controls (notably audio
and MIDI jacks) don’t allow you to change their sizes.
Lock Size: If checked, you won’t be able to change the control’s size
Lock Aspect Ratio: If checked, changing the control’s width will also automatically change its
height (and vice versa) to match the control’s skin’s original aspect ratio.
Skin: The skin that governs the control’s appearance. Voltage Module Designer comes with a
variety of skins for most control types, and you can use the Skin Editor Dialog (accessible from
the Edit menu) to add skins of your own.
Notes: A catch-all repository for any notes to yourself about the control. (These notes won’t be
part of the published module.)
Knobs
Notable APIs:
void SetValue( double newValue ) : This will set the knob’s value. newValue should be within
the knob’s min and max ranges.
Notifications:
Display Values in Percent: If checked, tooltips that display the knob’s value will multiply the
knob’s actual value by 100 and display it as a percentage (i.e., if the knob value is 0.5, the
tooltip will say “50%”). If unchecked, tooltips will display the knob’s actual value.
Tooltip Units: If you enter text here, it’ll get appended (with an intervening space) to the knob’s
tooltip. If you set it to “volts”, for instance, and the knob’s value is 4.2, its tooltip will be “4.2
volts”.
Has Outer Dial: if checked, the knob will have a dial ring around it that changes color to reflect
the knob’s current value.
Ring Levels Start From Center: If unchecked, dial ring colors will progress from min to max. If
checked, they’ll progress from center out.
Min, Max, and Default Values: the valid range of values for the knob and the default value for
a brand new knob. Max must be greater than Min and Default should be somewhere in the
range from Min to Max.
Num Discrete Steps: Set this to a value of two or larger if you want your knob to have a finite
number of fixed settings instead of scrolling continuously. If your knob is a waveform selector
with sine, saw, and triangle settings, for instance, set Num Discrete Steps to 3, and the knob will
effectively act as a three-state switch and only allow you to switch between three possible
values. If Min Value is set to 0 and Max Value to 2 in this case, the knob’s value will always be
0, 1, or 2.
Start and End Angles: These specify the angles to which the knob will be rotated when set to
its min and max values, respectively. Angles progress clockwise in degrees starting from zero at
12 o’clock (straight up).
Sliders
Sliders are basically knobs that have been uncurled and laid out in a line, so they share nearly
all their properties with knobs. They tend to get less love from module designers than knobs do
because they take up more space, but they’re awesome if you’ve got room for them - just ask
the designers of some of the vintage ARP synthesizers like the Odyssey and the Axxe, which
eschewed knobs for sliders entirely. Sliders are well suited for when you need to compare a
series of values at a glance, as happens with the track volumes on a mixer, or when you need a
series of controls to display a graph-like value, such as with an ADSR envelope.
Notable APIs:
void SetValue( double newValue ) : This will set the slider’s value. newValue should be within
slider’s min and max ranges.
Notifications:
See the Knobs section above for descriptions of several additional properties.
Buttons
“Button” controls are conventional push buttons that depress when you click on them and return
to their unpressed states when you stop clicking on them. If you want a button that stays down
after you stop clicking (and possibly one that’s part of a set of radio buttons), use the “Toggle
Button” control instead. While toggle buttons are great for showing state, regular buttons are
better options if you want to start an action - play or stop buttons, for instance.
Notifications:
Save/Restore State: Voltage Modular doesn’t save or restore the states of regular buttons
when users save presets. If your button has some custom state - maybe you’ve called
SetValue(1) to set it permanently down (though you probably want a toggle button instead if this
is the case) or you’re using button presses to cycle through a series of states - you’ll need to
save the state in internal variables and add code to GetStateInformation() and
SetStateInformation() to save/restore.
Auto Repeat: If checked, holding down the button will send out continuous button up & button
down notifications at a regular interval. We added this so that we could put up & down buttons
next to digital counter controls and continuously increment or decrement the counters by holding
one of the arrow buttons down (in a case like this, you’d increment the counter’s value each
time you received a button-down notification).
Has Image Overlay: If checked, you can select an image that will display on top of the button,
such as a ‘play’ or ‘stop’ icon. The module designer comes with a variety of overlays (all the
overlays that are used in any of Cherry Audio’s modules, basically), and it will also add to the
“Image Overlay” dropdown any image files that you copy to the user overlays folder (requires
version 1.06 or higher). On Windows, this folder will be [my documents]\Voltage Module
Designer\Resources\Overlays . On the Mac, this will be Documents/Voltage Module
Designer/Resources/Overlays.
Image Overlay: The dropdown that lets you select an image overlay for the button (only visible
if “Has Image Overlay” is checked.
Overlay Has Custom Rect: By default, image and text overlays will occupy a bounding
rectangle the size of the button. Image overlays will get centered within that rectangle and text
overlays will get aligned within that rectangle according to the text orientation settings. If you
want to position the image or text in a particular location on top of the button, you can specify a
custom rectangle in which the overlay will display. For image overlays, this can also result in
reducing the size at which the overlay displays, depending on how much smaller than the
original button you make the overlay’s custom rectangle.
Overlay Left, Top, Width, and Height: If you’ve enabled a custom rectangle for an overlay,
these settings will size and position that rectangle relative to the button’s upper left corner.
Preserve Overlay Image Aspect Ratio: If the button has an image overlay and this option is
checked, the image overlay’s original aspect ratio will always be preserved when it gets resized
to fit on the button. If unchecked, the overlay image could get stretched or squashed.
Has Text Overlay: If checked, you can add text to display on the button.
Overlay Text: The text to display on the button when you’ve checked the “Has Text Overlay:
option.
Font, Font Height (pixels), Bold, Italic, and Text Color: If you’ve checked the “Has Text
Overlay” option, these controls will let you edit the basic properties of your text overlay’s
appearance.
Horizontal and Vertical Orientation: specifies alignment for the text in a text overlay, either
within a custom overlay rectangle, if you’ve specified one of those, or within the entire button if
you haven’t.
Toggle Buttons
Toggle buttons will stay clicked when you click on them, making them handy as the interfaces
for features that are always either on or off - the “loop” button on the module designer’s Test
Signals module, which turns loop mode on or off, is a typical example. You can also use the
“Group ID” field to group multiple toggle buttons as radio buttons, with the result that clicking on
any toggle button in the group will unclick all other toggle buttons in the group.
Notifications:
A Button_Changed notification will arrive in Notify() whenever a toggle button gets pressed or
unpressed:
Save/Restore State: Voltage Modular will save and restore the states of any toggle buttons
that get saved in presets. When Voltage Modular loads a preset, it’ll send a Button_Changed
notification at module startup (but after your Initialize function has been called) for each of your
toggle buttons, with doubleValue = 1 (the button is down) or doubleValue = 0 (the button is up).
Most of the toggle button properties are shared with the regular button control (above), so we’ll
just list the ones that are unique to toggle buttons here:
Group ID: If you want this button to be part of a group of radio buttons, set the Group ID to a
number larger than zero. Clicking on any toggle button with a group ID > 0 will automatically
unclick any other toggle buttons with the same group ID.
Is Initially Toggled: If checked, this button will be in its toggled state when your module gets
added to a Voltage Modular cabinet. (Though if you save a preset with the button untoggled, it’ll
still be untoggled when you reload that preset.)
Audio Input and Output Jacks
Notable APIs:
boolean IsConnected() : This function will return true if any cables are connected to this jack.
void SetValue( double newValue ) : sets a new value for this jack (only applicable to output
jacks); if another module has an input jack connected to this jack, they can call GetValue() to
retrieve the value you’ve set. Audio jack GetValue and SetValue calls are the primary way that
modules communicate with each other. You’ll generally want to check the values of any input
jacks and set the values of any output jacks (at least if they’ve changed) in every call to
ProcessSample().
double GetValue() : retrieves the current value arriving at the jack (only applicable to input
jacks).
Notifications:
A Jack_Connected notification will arrive in Notify() whenever a new cable gets connected to a
jack, and a Jack_Disconnected notification will arrive when all cables have been disconnected
from a jack:
Save/Restore State: When loading a preset, Voltage Modular will reconnect any cables that
were attached to a jack when the preset got saved.
VU Meters
VU Meters have a valid range from 0 to 1, but you can set the value to be interpreted in either
linear or logarithmic fashion.
Notable APIs:
void SetLinearMode( boolean linMode ) : Set this to true for the meter to operate in linear mode,
false for it to behave logarithmically.
void SetValue( double newValue ) : Sets the meter’s value, valid range is from 0 to 1.
Analog VU Meters start at 0 and will redline at 1, with the needle maxing at 2.
Notable APIs:
Save/Restore State: Voltage Modular doesn’t save state for analog VU meters.
LEDs
Notable APIs:
void SetValue( double value ) : This sets the LED “brightness” (actually a state image), with a
valid range from 0 to 1. If it’s a simple on/off LED skin, it’ll be in the ‘off’ state if the value is less
than 0.4 and in the ‘on’ state otherwise. If the LED skin has more than two states, the state to
display will be the number of states multiplied by the LED value and then rounded off to an
integer, which will be used as a zero-based index into the array of state images. Here’s a
screenshot of a module showing the “Red” LED skin, which only has on and off states, and the
“Blue and Red” skin, which has off, red, and blue states, with each skin at various values from 0
to 1:
double GetValue() : This returns the LED’s current value.
void SetMomentaryBlink( int milsToBlink ) : This turns the LED on for milsToBlink milliseconds,
then turns it off again.
void SetBlinkEvery( int blinkIntervalMils, int blinkOnMils ) : Makes the LED blink. The blink cycle
will be blinkIntervalMils milliseconds long, and the LED will be lit for blinkOnMils milliseconds of
the cycle. The button-lit intensity will be whatever the value was in your last call to SetValue(),
so call SetValue() just before calling SetBlinkEvery() to make sure it lights up during the blink-on
part of the cycle.
Notifications:
A Jack_Connected notification will arrive in Notify() whenever a new cable gets connected to a
jack, and a Jack_Disconnected notification will arrive when all cables have been disconnected
from a jack:
Save/Restore State: When loading a preset, Voltage Modular will reconnect any cables that
were attached to a jack when the preset got saved.
Digital Counters
Notable APIs:
void SetValue( double newValue ) : This sets the number (truncated to an integer) displayed in
the counter. If you set it to a number larger than the counter can hold, it’ll display all 9’s.
void SetBarsForDigit( int digitIndex, EnumSet<Flags> flags ) : This lets you turn off and on
individual segments of a digit so you can emulate things other than numbers. For instance,
here’s the code that Voltage Modular’s MIDI Out module uses to make the MIDI channel
selector say “All”:
digitIndex starts from 0 at the rightmost digit and increases from right to left.
To use SetBarsForDigit, you’ll need to either use the fully qualified name for EnumSet or import
java.util.EnumSet:
void ClearBarsForDigit( int digit ) : This clears the custom bar art you set via SetBarsForDigit for
a given digit.
Save/Restore State: Voltage Modular doesn’t save state for digital counters.
Canvases
A canvas is a control that, in its default form, doesn’t do anything at all. It’s up to you to paint it
and handle any mouse interactions that occur. Use a canvas when you want to draw something
(a graph or waveform, for instance), create a custom control, or just generally do something that
the module designer’s native controls aren’t capable of. Voltage Modular’s Oscilloscope module,
to cite one example, uses a canvas control to draw a graph of the input signal.
If you’re using a canvas, you’ll want to handle the canvas notifications that arrive in the Notify
function. At least some of these will be important to you:
Here’s a simple example of a function that clears a canvas to a solid color - you’d call this
function from your Canvas_Painting handler (and ONLY from your Canvas_Painting handler):
Though the setRenderingHint call isn’t necessary here, it gives us a chance to mention that if
the things you’re drawing in your canvas seem aliased and pixelated, inserting the
setRenderingHint call listed above is likely to help.
The Graphics2D object in the above code is native to Java, rather than Cherry Audio; you can
find more information about it at
https://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html .
For any of the mouse-related notifications shown above, the x and y parameters to Notify() will
contain the mouse’s current position relative to your canvas’s top left corner.
Save/Restore State: Voltage Modular doesn’t save state for canvases. Like everything else to
do with these controls, it’s a roll-your-own affair. Add your own code to save & load data in
GetStateInformation & SetStateInformation if you need to store data with your canvas.
Switches
Notable APIs:
void SetValue( double value ) : Sets the switch’s position. For a 2-stage switch, the valid values
are 0 and 1; for a 3-stage switch, the valid values are 0, 1, and 2, etc.
Save/Restore State: Voltage Modular will save & restore the states of switches when users
save & load presets. When a preset loads, you’ll receive Switch_Changed notifications at
module startup (just after your Initialize() function has run) for each of the switches on your
module that aren’t set to their default states.
Images
The image control displays a still image on your module. If you’re displaying a raster-based
image (JPG, PNG, etc.), we recommend you use an image with double the dimensions of your
display size so that it won’t look pixelated at higher zoom levels - so if you want an image to
display at width of 100 and height of 150, for instance, use a 200 x 300 image as the source.
The API will likely change to allow you to provide separate low and high-resolution images at
some point.
Notable APIs: Both images and animations use the VoltageImage class, so you could
technically use VoltageImage’s APIs to write code to add multiple frames and animate them, but
if you want to do that, it would be much easier to just use an Animation control instead.
Animations
Notable APIs:
Animate(boolean bLoop) : Starts your animation playing. Only necessary if you don’t have the
“Auto Play” option checked.
SetAnimateMode( AnimationMode animMode) : Sets the animation direction. Valid values for
animMode are Forward, Backward, ForwardAndBack, and BackAndForth.
void SetCurrentFrame(int curFrame) : Sets the current foreground frame for the animation.
curFrame is a zero-based index into the array of total frames in the animation.
void SetCurrentImage( String resourceName ) : Also sets the current foreground frame, but
takes a resource name instead of a frame index.
void SetAnimationSpeed( int milsPerFrame, boolean bReset ) : Sets the animation speed, in
milliseconds per frame.
void AddImageFromMemory( byte[] data ) : Adds a new image to the animation from a memory
buffer. The buffer should be the contents of an image file (PNG, JPG, etc.) rather than a table of
pixels.
Frame Rate: The rate at which the animation will animate. Note that this is in milliseconds/frame
rather than the conventional frames per second.
Auto Play: If checked, the animation will start playing as soon as your module gets instantiated.
If not, you’ll have to start animation yourself by calling StartAnimation() or Animate().
Text Labels
Notable APIs:
void SetText( String newText ) : Sets the text for the label.
void SetColor( Color color ) : Sets the text color. color is a Java Color object and can include an
alpha value.
void SetBkColor( Color color ) : Sets the background color for the label control (by default, it has
an alpha value of zero).
void SetBorderColor( Color color ) : Sets the color of the control’s border (alpha = zero by
default).
void SetBorderSize( int pixSize ) : Sets the width of the border, in pxiels.
void SetFont( String typeface, int fontSize, boolean bBold, boolean bItalic ) : Sets various
properties of the control’s font. fontSize is height in pixels.
void SetJustificationFlags( Justification justificationFlag ) : Sets the text’s horizontal and vertical
justification.
void SetMultiLineEdit( boolean bMultiLineEdit ) : Set to true to make this a multi-line text control.
void SetHorizontalScale( double scale ) : Allows you to change the widths of the characters in
the text control. 1.0 = normal, 2.0 = double width, 0.5 = half width, etc.
Save/Restore State: Voltage Modular doesn’t save or restore state information for text labels
with presets.
Text: The text that will be displayed in the label.
Font, Font Height, Bold, and Italic: These set basic font properties for the text. The Font
dropdown will only show typefaces that are preinstalled on both Windows and Mac computers..
Horizontal and Vertical Orientation: How the text will be aligned within its bounding rectangle.
Multi Line: if checked, the text can be more than one line tall.
Background Color: color and opacity for the background of the text label’s bounding rectangle.
Border Color: color and opacity of a border drawn around the text label’s bounding rectangle.
Border Width: width, in pixels, of the text label’s border. Only applicable if the border color
property specifies a non-zero opacity.
Editable Text Labels
Editable text labels are nearly identical to regular text labels, with the important exception that
users can edit the text in them. All the knob and button labels on Voltage Modular’s
Performance Module are editable text labels, for instance. Voltage Modular will automatically
handle save/restore when user change an editable text label’s text and then saves a preset.
Notable APIs:
void SetEditTextColor( Color color ) : Sets the text color to use during edit mode.
void SetEditBackColor( Color color ) : Sets the color to use for the control’s background during
edit mode.
void SetEditOutlineColor( Color color ) : Sets the color to use for the control’s border during edit
mode.
See also the APIs section for non-editable text labels, above.
Notifications: A Label_Changed notification will arrive in Notify() whenever a user has changed
the contents of an editable text label:
Save/Restore State: Voltage Modular will save the text in an editable label and restore it when
users save and restore presets.
Start Editing On: This lets you specify whether single clicking or double clicking on the control
initiates editing mode.
Edit Mode Text, Background, and Border Colors: Colors used when the control enters
editing mode.
See the Text Label control above for descriptions of the other properties.
Library Classes
Module Designer Features
To test your module with the debugger, choose the “Debug” option from the “Build” menu. The
module designer will build your module and, assuming no compile errors, launch a child process
with a cabinet containing your module and the Test Signals module:
The Test Signals Module contains a variety of inputs and outputs to help you test your module.
It includes five sections, from top to bottom:
From Host: A variety of CV and MIDI inputs from the MIDI devices you’ve chosen in the
module designer’s Preferences dialog.
File Playback: If you specify the “File” option from the Sound Source section (just below this
one), you can use this section to load an audio file (MP3, WAV, OGG, FLAC, or AIFF) and use it
as a sound source for processing in your module.
Sound Source: This lets you choose an audio source for sending to the module via the “Test
Signal Outputs” section below. You can use a square wave, a sine wave, an audio file, or an
external input such as a microphone (see the module designer’s Preferences dialog for
available inputs). If you select the sine or square waves, the “Osc Freq” knob sets the
waveform’s frequency.
Test Signal Outputs: This section contains mono and stereo output jacks for sending your
chosen sound source to your module.
Audio Ret To Host: Hook the output from your module back to these input jacks; they’ll get
routed to the audio outputs (your speakers, probably) specified in the module designer’s
Preferences dialog.
The menu in the debugger child process lets you test your module’s undo/redo capabilities (via
the “Edit” menu) and how it looks at varying zoom levels (via the “View” menu). The “Add
Modules” menu allows you to add other Voltage modules to your test cabinet:
The module designer will remember your cable connections, extra modules, and control settings
from session to session. If you need to clear them, select the “Clear Test/Debug Mode Settings”
option from the module designer’s “Build” menu.
Note that if you hit a breakpoint or otherwise pause debug execution, it’ll halt execution of the
entire debugger child process, including the interface thread, so the Edit/View/Add Modules
menus won’t be accessible when execution is paused.
When the debugger launches, the title bar for the output pane (the pane at the bottom of the
module designer in the default setup) will sprout a series of tabs along its left edge:
When execution of your module has paused due to hitting a breakpoint, pausing, etc., the
buttons allow you to resume execution in various ways:
resume: resumes execution unconditionally, either until another breakpoint is hit or you pause
execution via the “Pause” option on the Debug menu.
step in: If the line of code where execution is paused includes a function call, step into the
function. If it doesn’t, skip to the next line of code.
step over: execute the current line of code without stepping into any function calls it contains
step out: execute code until execution has exited the current function.
The “Output” tab shows the normal contents of the Output pane, including the results of any Log
statements in your code:
“Oscillator”: This tab will be labeled with your module’s variable name and will show the values
of all the variables in your module:
The first column shows variable names, the second column their values, and the third column
their types. Most non-primitive types will have empty value columns; click the little expansion
arrows to the left of their names to show all their child members, which will have filled-in value
columns if they’re not themselves complex types.
The “Locals” tab has the same layout as the Module tab, but shows values for all the local
variables at the current point of execution:
The “Threads” tab shows all the active threads and the call stacks for each, with threads in the
left column and the selected thread’s call stack, if available, in the right column:
Click on a stack frame and then switch to the Locals tab to see local values for that stack frame,
if any are available.
The Module, Locals, and Threads tabs will be disabled unless debug execution is paused.
Breakpoints: To set a breakpoint at a particular line of code, either click in the line’s left margin,
right-click and select the “Toggle Breakpoint” option, or click the toggle-breakpoint hotkey (F9 on
Windows, Command-Backslash on Mac). A red circle will appear in the left margin to indicate
that the line has a breakpoint:
Use the same process to remove breakpoints. There’s also a “Remove All Breakpoints” option
on the Debug menu.
When execution stops at a breakpoint, the line will be highlighted in the code editor and a yellow
arrow will appear in the margin:
The Module Background Dialog
Use Solid Color: Check this item to use a color rather than an image for your module’s
background. The “Choose Color” button will launch a color-chooser dialog. This option won’t
actually result in a background rendered with a single color; instead, it’ll have a slight gradient
that darkens the bottom and a thin black border, both so that it will more closely match the
appearance of Cherry Audio’s own modules.
Use Image: Choose this item to use images for your module’s background. You should add
two versions of your background image, one at normal resolution (360 pixels tall) and one at
high resolution (720 pixels tall and twice the module’s original width). The high-resolution
version will be used on retina displays and when the zoom level is > 100%. Modules without
hi-res backgrounds tend to look fuzzy at high zoom. If your source image is an SVG file with no
embedded bitmaps, you only need to specify one background image.
Add Screws: This will add screws to the corners of your module to keep it from falling out of
the cabinet. This is optional - if your module is magnetized or has wads of gum on the back or
something else equally effective, you can leave this unchecked.
The Skin Editor Dialog
The Skin Editor Dialog lets you create your own skins for the module designer’s various control
types. Once you’ve created a skin and saved it, it’ll appear in the “Skin” dropdown for that
control type along with all the presupplied skin types.
We highly recommend that you use SVG files for your skins so that they’ll scale to any size
without aliasing.
New Skin, Open Skin, and Save Skin Buttons: These allow you to save your skins and open
existing skin projects. On Windows, your skins will get saved in Documents\Voltage Module
Designer\Resources\Skins, On Mac (version 1.06 and higher) they’ll get saved in
Documents/Voltage Module Designer/Resources/Skins. The skin editor will copy any source
image files it needs to the save folder, so you don’t need to keep copies of them in their original
locations in order for the skin to keep working.
Control Value: This allows you to emulate SetValue() calls to LED and VU meter skins so you
can see how your skin looks throughout its range. This control will also work on knob and slider
skins, though you can just click on the knobs and sliders themselves, and will even work on
button and switch skins in the unlikely event you want to use a slider to turn them on and off.
For other kinds of control skins, it’ll have no meaningful effect (technically, you can use it to
count from 0 to 1 on a digital counter).
Skin Type: The module designer currently supports user skins for audio and MIDI jacks,
regular and toggle buttons, knobs, horizontal and vertical sliders, digital counters, LEDs,
switches, and VU meters.
Skin Name: This is the name your skin will have in the property panel’s “Skins” dropdown.
Default Width and Height: When you set a control to use this skin, the control will
automatically get reset to this size if you don’t have its “Lock Size” option set.
Normal: used when a given control is enabled and the user isn’t interacting with it in any way
(clicking on it or hovering the mouse over it being the most common sorts of interactions).
Disabled: used when the control is disabled. The disabled state is currently only used for audio
and MIDI jacks, but will probably get added for other kinds of controls in an upcoming release.
Skin Editor - Audio Jacks
Normal: the image to use when the jack is enabled and the user isn’t currently interacting with
it.
Hover: the image to use when the mouse is hovering over the jack.
Disabled: the image to use when the jack is disabled. When a user is dragging a cable from an
input jack, all other input jacks will be drawn in their disabled states, and likewise for output
jacks when a user is dragging a cable from an output jack.
Skin Editor - Buttons
Normal: the image to use when the button is enabled and the user isn’t interacting with it.
Hover: the image to use when the mouse is hovering over the button.
Pushed: the image to use when the user has clicked on the button.
Disabled: used when the button is disabled. There’s currently no interface for disabling
buttons, but this will probably get added at some point.
Skin Editor - Digital Counters
Numbers, 0 - 9 and Off: the images to use for the various integers.
Lines: the images to use for drawing individual line segments (see the SetBarsForDigit() API,
discussed in the controls|digital counters section above).
Skin Editor - Horizontal Sliders
Filled: art to use for portions of the slider background that are to the left of the slider thumb, for
cases in which you want a slider with a progress-bar-style appearance. (See the file-playback
slider on the Test Signals module for an example.)
Back: Art to use for the knob’s background, which will remain stationary.
Top: Art to use for the knob’s top, which will rotate as the knob’s value changes.
Skin Editor - LEDs
Extra States: These controls allow you to add art for intermediate states between off and on,
such as for an LED that glows at varying intensities.
Skin Editor - MIDI Jacks
Normal: image to use when the MIDI jack is enabled and the user isn’t interacting with it.
Hover: image to use when the mouse is hovering over the jack.
Disabled: image to use when the jack is disabled (when the user is dragging a cable from a
MIDI input jack, all other MIDI input jacks will be disabled; likewise with MIDI output jacks when
user is dragging a cable from a MIDI output jack).
States: Lets you specify how many states the switch has - two for a simple on/off switch, etc.
state0 - n: The images to use for each of the switch states.
Skin Editor - Toggle Buttons
Up and Down states: art to display when the button is in its off and on states, respectively.
Note that the ‘pushed’ states are created by buttons in the opposite state - i.e., when the button
is in its down state and you click on it, it’ll switch to the up-state pushed art, and when the button
is in its up state and you click on it, it’ll switch to the down-state pushed art.
Skin Editor - Vertical Sliders
Filled: art to use for portions of the slider background that are to the left of the slider thumb, for
cases in which you want a slider with a progress-bar-style appearance.
Background Image: the image to use for the meter background. This should include
everything but the needle.
Signal Image: the foreground image showing the amount of signal preset. At a control value of
0, the signal image will be completely invisible. At a control value of 1, the signal image will
completely cover the background image.
Assorted Shortcuts and Hotkeys
Alt-drag any control to create a duplicate of it (and any other selected controls as well); hold
down the shift key during this process to limit the initial drag to either the horizontal or vertical
directions.
Hold down the shift key while dragging any control to restrict its movement to either the
horizontal or vertical directions.
Select a control and press the up/down/left/right arrow keys to move the control 1 pixel in
those directions; hold down the shift key while pressing the arrow keys to move the control
by 10 pixels per click instead. If you have the grid visible and horizontal or vertical snap-to-grid
options selected (right-click or, on the Mac, control click, on the module background to set grid
options), the arrow keys will move the control by units of the grid size (i.e., if the grid size is set
to 20 pixels, controls will move 20 pixels per key press).
Select a control, hold down the control key, and press the left/right/up/down arrow keys to
resize the control by one pixel per key press - right and down arrows to make it larger, left and
up arrows to make it smaller. This won’t resize the control if its size is locked or if it’s a control
for which resizing isn’t allowed, such as audio and MIDI jacks.
Select a control and press the tab key to make the next control in the z-order the selected
foreground control. Shift-tab cycles in the opposite direction.
Hold down the control key while clicking on a control to select it without deselecting any
other selected controls.
Click on the module background and drag to generate a bounding rectangle; after releasing
the mouse button, any controls partially or fully within that rectangle will be selected. Hold down
the control key while dragging to select controls inside the bounding rectangle without
deselecting controls outside the rectangle.
Click on a control and press the “Delete” key (on the Mac, the Delete key on the numeric
keypad) to delete the control.
Right-click or control-click (Mac) on a control for a popup menu that lets you bring the
selected control to the front or back of the z-order, lock or unlock the control’s position or size,
duplicate or delete the control, and link selected controls so that selecting one will always select
the other as well.
Right-click or control-click (Mac) on the module background for a popup menu that lets you
lock or unlock the sizes or positions of all controls on the module at once; edit grid visibility, size,
and snap-to-grid settings; or select all the controls on the module.
F3 (Windows) or Command-G (Mac) to select the next search result; Shift-F3 (Windows) or
Command-Shift G (Mac) to select the previous one. Only applicable when the search interface
is open.
Tab (WIndows) or Command-] (Mac) to indent selected text if the current selection
encompasses multiple lines; Shift-Tab (Windows) or Command-[ (Mac) to unindent in the
same circumstances