AbleSet's canvas allows you to write scripts that are triggered by pressing a button, moving a slider, etc. The script editor provides autocompletion for available functions and variables and automatically highlights incorrect code.
These scripts are written in JavaScript and support all features of ES2023. If you're already familiar with writing JavaScript, you can skip the next section and go straight to the list of available functions.
The following script prints "Hello World!" to the console. The log
function is
a handy tool to debug your scripts by showing values while your script runs.
log("Hello World!");
This is a function call. Each function call consists of the function name, and
braces containing arguments. These arguments depend on which function you call.
In this case, we're passing the text "Hello World!" to the log
function.
You can end each function call with a semicolon (recommended) or write one function call per line without semicolons.
If you'd like to add comments to your code, you can do so like this:
// This is a single-line comment
/*
This is a multi-line comment
*/
To store and re-use values in your scripts, you can define variables. There are two types
of variables, const
and let
. Use const
when the value won't change (recommended),
and let
when you need to modify it later:
// This variable can be re-assigned
let name = "Léo";
name = "The other Léo";
// This one can't be re-assigned - use this when possible
const answer = 42;
answer = 41; // <- this would result in an error
// Variables can't be defined twice
const app = "AbleSet";
const app = "AbleSet 2"; // <- this would fail
Variables only exist while your script runs and will be cleared afterwards.
If you need to store values between script runs, use the setLocal
and local
functions described here.
JavaScript supports a range of primitive data types: number
, string
,
boolean
, undefined
, and null
:
// A number:
const num = 1234.56;
// Strings can use double or single quotes:
const hello = "Hello";
const world = 'World';
// Booleans are either true or false:
const yes = true;
const no = false;
The values undefined
and null
are special values representing no data.
Template strings are a special string type that use backticks (`
) as quotes
and allow you to include variables:
const name = "Léo";
const message = `Hello, ${name}!`;
Operators allow you to manipulate and check data and variables:
// You can use +, -, *, /, and % (modulo) on numbers
const result = (3 + 5) / 2; // <- result will be 4
// To modify number variables, you can use ++, --, +=, -=, *=, and /=
let num = 3;
num++; // num is increased by 1
num--; // num is decreased by 1
num += 3; // 3 is added to num, same as num = num + 3
num -= 2; // 2 is subtracted from num, same as num = num -3
// Use + to concatenate a string with other variables
const message = "The result is " + result;
To compare two or more values with each other, you can use these operators:
const name = "Léo";
const answer = 42;
// Use === (equal) and !== (not equal) to compare two values
const equal = answer === 42; // <- will be true
const unequal = name !== "Tom"; // <- will also be true
// Use && (AND), || (OR), and ! (NOT) to combine comparisons
const and = equal && name === "Léo"; // <- will be true
const or = equal || name === "Tom"; // <- will also be true
const not = !equal; // <- will be false
Conditional (if) statements allow you to decide which code to run based on given conditions:
const song = "Roads";
const artist = "Small Strides";
if (song === "Follow Night") {
log("The song is Follow Night");
} else if (artist === "Small Strides") {
// This code will run since the song condition wasn't satisfied,
// but this one (artist) was
log("The song is not Follow Night, but the artist is Small Strides");
} else {
log("Neither song nor artist match");
}
The ternary operator allows you to get a value based on a condition:
const number = 9001;
// This message variable will be "It's over 9000!".
const message = number > 9000 ? "It's over 9000!" : "Value is too small";
// Ternary operators can be used anywhere, e.g. in arguments:
const answer = 42;
log(answer === 42 ? "Correct" : "Wrong");
To run a block of code multiple times, you can use loops:
// This runs the loop 10 times, starting with 1
// and increasing the variable i by 1 each time
for (let i = 1; i <= 10; i++) {
log(`Hello, number ${i}`); // Logs "Hello, number 1", "Hello, number 2", etc.
}
Note that we have to use let i = 1
instead of const i = 1
here because the
variable needs to be modified on each run.
Alternatively, you can use while
and do...while
loops, but I'll skip them
here for brevity.
Arrays allow you to store a list of values in a variable. They can contain all primitive data types and other arrays.
// This is how you define an array:
const songs = ["Roads", "Follow Night", "Why We Are"];
// Accessing array items can be done like this. Note that the index starts at 0:
const firstSong = songs[0]; // <- "Roads"
const lastSong = songs[2]; // <- "Why We Are"
// You can also access the length of the array:
const songCount = songs.length; // <- 3
To learn more about JavaScript, you might find the Mozilla Docs helpful.
When writing scripts in AbleSet, you can access all objects and functions available in JavaScript, including Math, Date, and JSON. You can find an overview here.
Additionally, AbleSet offers a number of built-in functions to interact with the app and other devices.
Here's a list of them. Arguments marked with a ?
are optional, a ...
before
arguments means you can add as many arguments of this type as you like.
log(...values)
logs all values to the consoleawait sleep(time)
waits for the given number of millisecondsTo store values between script runs and access them from other scripts and components, you can use these functions:
setLocal(key, value, persist?)
stores the given value under the given key
persist
is true, the value is stored in your browser's storage and
persisted between page refresheslocal(key, fallback?)
returns the value at the given key
key
yet, fallback
is returnedresetLocal(key?)
deletes the variable stored at key
key
is defined, all local variables are deletedExample:
// Gets a counter and increases it by 1
const counter = local("counter", 0);
setLocal("counter", counter + 1);
osc(key, index?)
returns the OSC value for the given key
index
argumentindex
to "all"sendOsc(command, ...args)
sends an OSC command with the given arguments
await waitForOscChange(key)
waits until the value for the given key changesExample:
// Jumps to the next song if AbleSet isn't playing, waits
// for the name to change, and logs the value of the new song
if (!osc("/global/isPlaying")) {
sendOsc("/setlist/jumpBySongs", 1);
await waitForOscChange("/setlist/activeSongName");
log("New song:", osc("/setlist/activeSongName"));
}
A list of all available OSC values and commands is available here.
These functions are aliases for the /midi/send
OSC commands. You can use these
commands to send notes:
sendMidiNote(output, channel, note, velocity?, duration?)
sends a MIDI note on followed by a note off to the given output
sendMidiNoteOn(output, channel, note, velocity?)
sends a note on with the given velocity to the specified output
sendMidiNoteOff(output, channel, note, velocity?)
sends a note off with the given velocity to the specified output
The note can either be a number between 0 and 127, or a string like E#0
or Cb-1
.
To send CC and PC, you can use these commands:
sendMidiCc(output, channel, controller, value)
sends a CC to the given output
sendMidiPc(output, channel, program)
sends a PC to the given output
You can also send raw MIDI data to an output, for example for SysEx:
sendMidiRaw(output, ...data)
navigate(path)
navigates the browser to the given path
pathname
contains the current pathname (e.g. "/canvas/main")formatDuration(seconds)
formats a given number of seconds into a more readable string
formatDuration(135)
returns "02:15"