NSL - NGEN SCRIPTING LANGUAGE
The NSL Engine Generator is a powerful tool that lets you create your own custom algorithms using a simple scripting language.
At it's core, the NSL Engine features a 32-step sequence (with individual pitch, velocity, length (in beats) and density per step) and standard parameters such Shift, Length and Density to control playback.
Instead of using a pre-defined algorithm to fill the 32-step sequence, the NSL Engine lets you load a script to generate it using your own custom algorithm.
Each NSL script consists of a series of hex values that are parsed into commands and values. Hex values of 160 (0xA0) or higher trigger new commands and values below 160 are assigned as values / parameters for these commands. The engine also includes 32 registers (Memory Buffer) that can be used to store values and use them later in the script and 4 generic parameters (Param 1-4) with ranges from 0-100.
Warning
The NSL Engine is still in beta and it's not fully documented and implemented yet. This section of the manual will be updated as we continue to develop the NSL Engine. Scripts that run out of control are stopped by the engine's execution limits (see Execution Limits) instead of freezing the generator, but faulty scripts can still produce unexpected sequences.
ngen_nsl Rust Library
ngen_nsl is a custom Rust library available via cargo / crates.io that make it easier to create and parse NSL scripts for the NSL Engine.
To add it to your Rust project, run the command cargo add ngen_nsl in your project's directory.
Documentation for ngen_nsl is available at https://docs.rs/ngen_nsl.
NSL Programming Reference
Script File Format
NSL scripts are stored as binary files in the /NSL folder of your microSD card (see File Management). Each file starts with a 4 byte header followed by the program itself:
| Position | Content | Description |
|---|---|---|
| 0 - 2 | NSL |
File identifier (0x4E 0x53 0x4C) |
| 3 | Version | NSL script version marker |
| 4 - end | Program | Series of commands and values |
A program can be up to 65535 bytes long and the file name is limited to 15 characters. Files shorter than 4 bytes or files that don't start with the NSL identifier are rejected and the previously loaded script is kept.
Parameter Types
NSL commands require set of different parameters to execute correctly and each parameter's value is used according to the list below:
VALUE
The VALUE parameter type returns a constant values from 0x00 to 0x7F (0-127) and values stored in the NSL Engine's memory buffer from 0x80 to 0x9F (128-159).
DESTINATION / SOURCE
The DESTINATION / SOURCE parameters consists of 2 x VALUE parameters that are used in pair to retrieve values from different parts and features of the NSL Engine.
SOURCE parameters are used to retrieve data while DESTINATION parameters are used to set data.
The first VALUE in the pair (aka VALUE 1) is used to indicate the type / location of the value that follows it (VALUE 2) according to the table below:
| PART / FEATURE | VALUE 1 (Address) | VALUE 2 (Value / Index) | VALUE 2 RANGE | SOURCE | DESTINATION | DESTINATION RANGE |
|---|---|---|---|---|---|---|
| Constant Value | 0x00 | Value | 0-127 | ✔︎ | ✕ | N/A |
| Random Value | 0x01 | Random Range | 0-127 | ✔︎ | ✕ | N/A |
| Step Pitch | 0x02 | Step Number (Zero-Indexed) | 0-31 | ✔︎ | ✔︎ | 0-127 (MIDI PITCH) |
| Step Velocity | 0x03 | Step Number (Zero-Indexed) | 0-31 | ✔︎ | ✔︎ | 0-127 (MIDI VELOCITY) |
| Step Length | 0x04 | Step Number (Zero-Indexed) | 0-31 | ✔︎ | ✔︎ | 0-7 (BEATS) |
| Step Density | 0x05 | Step Number (Zero-Indexed) | 0-31 | ✔︎ | ✔︎ | 0-49 |
| Memory Buffer | 0x06 | Memory Index (Zero-Indexed) | 0-31 | ✔︎ | ✔︎ | 0-255 |
| Params 1-4 | 0x07 | Parameter Number (Zero-Indexed) | 0-3 | ✔︎ | ✔︎ | 0-99 |
| Scale | 0x08 | Note position in scale | 0-127 | ✔︎ | ✕ | N/A |
| Scale (Quantized) | 0x09 | Note position in scale | 0-127 | ✔︎ | ✕ | N/A |
| Random Note | 0x0A | Probability (Root Note Chance) | 0-100 | ✔︎ | ✕ | N/A |
Some features such as Constant and Random use the second VALUE in the pair (VALUE 2) as the actual value while the other types use it as an index to indicate the location of the value in the NSL Engine's memory.
Examples:
0x00 0x05: Returns a constant value (ORIGIN=0x00) of 5 (VALUE=0x05).0x02 0x10: Returns the step pitch (ORIGIN=0x02) at index 16 (VALUE=0x10).0x01 0x20: Returns a random value (ORIGIN=0x01) between 0 and 31 (VALUE=0x20). The upper limit is exclusive, so the range is always0toVALUE - 1.0x07 0x02: Returns the value of Param 3 (ORIGIN=0x07) at parameter index 2 (VALUE=0x02).
INT16
The INT16 parameter type uses a pair (x and y) of 8-bit values (0-255) to create a 16-bit value (0-65535) by shifting the first value 8 bits to the left and adding the second value to it ((x << 8) + y).
Execution Limits
Every time you run Generate, the NSL Engine clears all step sequences and the memory buffer before running the program. Scripts always start from an empty state, so a script must build the whole sequence by itself.
To keep faulty scripts from locking up the generator, the engine stops the program when it reaches any of the limits below. The rest of the program is skipped and the sequence generated so far is kept.
| Limit | Value | Behavior |
|---|---|---|
| Instructions per generation | 20000 | Program stops (watchdog) |
| Nested loops | 4 | Program stops |
| Nested conditions | 4 | Program stops |
| JUMP position | Must be smaller than the program size | Program stops |
List of Commands
0xA1 SET
Description: Sets the value of a destination to the value of a source.
Parameters: DESTINATION SOURCE
Examples:
-
0xA1 0x02 0x00 0x01 0x10: Sets the pitch of step 1 to a random value between 0 and 15. -
0xA1 0x03 0x00 0x03 0x01: Sets the velocity of step 1 (0x03 0x00) to the velocity of step 2 (0x03 0x01). -
0xA1 0x06 0x00 0x05 0x04: Sets the value of the memory buffer at index 0 to the density of step 5.
0xA3 CLEAR TRACK
Description: Clears the pitch, velocity, length and density sequences (all 32 steps).
Parameters: None
Examples:
0xA3: Clears the sequence of the current track.
0xA4 CLEAR MEMORY
Description: Clears the memory buffer, setting all 32 registers to 0.
Parameters: None
Examples:
0xA4: Clears the memory buffer.
0xA5 CLEAR ALL
Description: Clears the track and the memory buffer, returning the sequence to the same empty state used at the start of a generation.
Parameters: None
Examples:
0xA5: Clears everything.
0xB0 ADD
Description: Adds the value of a source to a destionation.
Parameters: DESTINATION SOURCE
Examples:
0xB0 0x02 0x00 0x00 0x02: Add 2 (0x00 0x02) to the pitch of the first step (0x02 0x00).
0xB1 SUBTRACT
Description: Subtracts the value of a source from a destination.
Parameters: DESTINATION SOURCE
Examples:
0xB1 0x02 0x00 0x01 0x10: Subtract a random value between 0 - 15 (0x01 0x10) from the pitch of the first step (0x02 0x00).
0xB2 MULTIPLY
Description: Multiplies the value of a destination by the value of a source.
Parameters: DESTINATION SOURCE
Examples:
0xB2 0x03 0x00 0x00 0x02: Doubles the velocity of the first step (0x03 0x00).
0xB3 DIVIDE
Description: Divides the value of a destination by the value of a source. If the source value is 0, the command is ignored to avoid division by zero.
Parameters: DESTINATION SOURCE
Examples:
0xB3 0x02 0x00 0x00 0x02: Halves the pitch of the first step (0x02 0x00).
0xB4 PITCH QUANTIZE
Description: Quantizes the pitch of all 32 steps of the current track to the active scale.
Parameters: None
Examples:
0xB4: Snaps every pitch value of the current track to the nearest note of the active scale.
0xB5 GENERATE PROGRESSION
Description: Generates a chord progression and stores its 4 degrees in the memory buffer at index 0 to 3. These are the same progression degrees used by the Arpeggiator, POP and LUAR generators.
Each degree is a position in the active scale, so you read them back as a Scale source (0x08) combined with an indirect address from 0x80 to 0x83.
Parameters: None
Examples:
0xB5 0xA1 0x02 0x00 0x08 0x80: Generates a progression and sets the pitch of the first step to the note of the first degree.
0xB6 GENERATE EUCLID
Description: Builds a Euclidean rhythm over the 32 steps of the current track and writes it as the velocity sequence. Steps that receive a hit get a velocity of 127, all other steps are set to 0.
Parameters: SOURCE (Number of Pulses) SOURCE (Rotation Offset)
Examples:
0xB6 0x00 0x05 0x00 0x00: Distributes 5 pulses evenly over the 32 steps of the current track.
0xC0 LOOP SET
Description: Starts a loop and sets the loop count to the value of a source. The first pass counts as one run, so a loop count of 3 executes the commands between LOOP SET and LOOP END 3 times in total.
Parameters: SOURCE (Loop Count)
Examples:
0xC0 0x00 0x03: Repeats the commands until the nextLOOP END3 times.
Loops can be nested up to 4 levels deep. A LOOP END without a matching LOOP SET is ignored.
0xC1 LOOP END
Description: Ends the current loop and jumps back to the matching LOOP SET until the loop count is reached.
Parameters: None
0xC2 JUMP
Description: Jumps to a specific position in the program. The jump position must be smaller than the size of the program, otherwise the program stops.
Parameters: INT16 (Jump Position)
Examples:
0xC2 0x02 0x24: Jumps to position 548.
0xD0 EQUAL
Description: Starts a condition that only runs the commands that follow when both values are equal. Both values are read again before each command, so a condition can react to changes made by the script itself. Conditions stay active until END COND.
Parameters: SOURCE (Left Value) SOURCE (Right Value)
Examples:
0xD0 0x06 0x00 0x00 0x01 0xA1 0x02 0x00 0x00 0x42: Sets the pitch of the first step to 66 only while the memory buffer at index 0 is equal to 1.
0xD1 NOT EQUAL
Description: Starts a condition that only runs the commands that follow when both values are different.
Parameters: SOURCE (Left Value) SOURCE (Right Value)
Examples:
0xD1 0x06 0x00 0x00 0x00: Runs the following commands while the memory buffer at index 0 is not 0.
0xD2 GREATER THAN
Description: Starts a condition that only runs the commands that follow when the left value is greater than the right value.
Parameters: SOURCE (Left Value) SOURCE (Right Value)
Examples:
0xD2 0x03 0x00 0x00 0x64: Runs the following commands while the velocity of the first step is greater than 100.
0xD3 LESS THAN
Description: Starts a condition that only runs the commands that follow when the left value is smaller than the right value.
Parameters: SOURCE (Left Value) SOURCE (Right Value)
Examples:
0xD3 0x03 0x00 0x00 0x64: Runs the following commands while the velocity of the first step is smaller than 100.
0xD4 GREATER OR EQUAL
Description: Starts a condition that only runs the commands that follow when the left value is greater than or equal to the right value.
Parameters: SOURCE (Left Value) SOURCE (Right Value)
Examples:
0xD4 0x07 0x00 0x00 0x32: Runs the following commands while Param 1 is greater than or equal to 50.
0xD5 LESS OR EQUAL
Description: Starts a condition that only runs the commands that follow when the left value is smaller than or equal to the right value.
Parameters: SOURCE (Left Value) SOURCE (Right Value)
Examples:
0xD5 0x07 0x00 0x00 0x32: Runs the following commands while Param 1 is smaller than or equal to 50.
0xD6 END COND
Description: Ends the current condition. When conditions are nested, END COND closes the innermost one and returns to the condition that contains it. Conditions can be nested up to 4 levels deep.
Loop and condition commands always run, even when a condition is not met, so the structure of a script is never broken by a condition.
Parameters: None
Examples:
0xD6: Ends the active condition.
0xFF END
Description: Ends the program.
Parameters: None
Script Playback
A script only builds the sequence. The generator parameters decide how that sequence is played:
| Parameter | Effect during playback |
|---|---|
| Length | Sets how many steps are played (1-32). Steps after the Length are never triggered. |
| Density | Works as a threshold. A step only sounds when its own density value is smaller than the Density parameter, so higher values let more steps play. |
| Shift | Transposes the pitch of every step by up to 12 semitones in each direction. |
| Quantize | When enabled, every pitch is quantized to the active scale during playback. |
A step is triggered when all of these are true:
- Velocity is greater than 0.
- Step length is greater than 0.
- The density value of the step is smaller than the Density parameter.
The duration of each note is the step length multiplied by the note length of the track, reduced by 10% so that repeated notes are always separated.