OMNi

Plugins and Advanced · 5 min

OmniScript Scripting Language

A manual for writing custom generative algorithms, MIDI processors, modulators, and simple DSP effects in the integrated OmniScript language.

📜 OmniScript Scripting Language

WSKAZÓWKA

[!TIP] OmniScript is an integrated scripting language compiled to a safe virtual machine bytecode (no allocation, no panicking), allowing you to write custom MIDI processors, modulators, and simple DSP effects without compiling external plugins. You can find ready-to-use examples in omni_engine/examples/scripts/*.omfx.


💡 1. Three Types of Scripts (.omfx)

An .omfx file declares its type in the header via @mode:, which determines where the script is available and what built-in variables it can see:

  • @mode: audio — a simple DSP effect inserted into an insert chain (e.g., gain, bitcrusher, filter).
  • @mode: midi — a generative MIDI processor (arpeggiator, chord generator, humanizer, scale quantizer).
  • @mode: modulator — a custom modulator in the modulation rack (see /docs/modulators).

A script does not define its own entry function like fn process_note(). Instead, the host directly calls standardized sections of the file if they are present:

| Section | When it is called | | :--- | :--- | | @init | Once, upon loading/resetting the script. | | @block | Once per audio buffer. | | @sample | Once per sample (sample-accurate). | | @midi_note_on / @midi_note_off | Upon every incoming MIDI event (only @mode: midi). | | @modulate | Older, single entry point for a modulator — replaced by @block/@sample writing to the output variable. |


💻 2. Real Examples

Example A: Simple DSP Effect (fx_simple_gain.omfx)

code
@name: Simple Gain
@desc: Volume control
@mode: audio

@param[0] name="Gain" min=0.0 max=2.0 default=1.0 unit="x"

@sample
  spl0 = spl0 * param[0];
  spl1 = spl1 * param[0];

Example B: Modulator with Custom Function (mod_step_lfo.omfx)

code
@name: Step LFO
@mode: modulator

@param[0] name="Rate"   min=0.1  max=20.0 default=2.0  unit="Hz"
@param[1] name="Steps"  min=2    max=16   default=8

fn saw_wave(p) {
    return p * 2.0 - 1.0;
}

@init
  phase = 0.0;

@block
  n_steps = floor(param[1] + 0.5);

@sample
  phase = phase + param[0] / sample_rate;
  if phase >= 1.0 { phase = phase - 1.0; }
  output = saw_wave(phase);

Syntax note: OmniScript does not have a let keyword — the first assignment to a name automatically declares it (name = expression;). for loops use a Rust-like range syntax: for i in 0..8 { ... }, rather than a classic C-style for(;;).


🛠️ 3. Built-in Variables

All variables in OmniScript are floating-point numbers (f64) — there are no separate u8/f32 types visible from the script (e.g., note/velocity are simply numbers 0–127).

| Variable | Available in mode | Description | | :--- | :--- | :--- | | sample_rate | all | The audio engine's sample rate. | | tempo | all | The current project tempo in BPM. | | beat_pos | all | The current playback position in the bar. | | frames | all | The size of the current audio buffer (number of samples). | | play_state | all | 1.0 when transport is playing, 0.0 when stopped. | | param[0]param[63] | all | Parameter values defined by @param[n] in the file header — for reading and writing. | | spl0 / spl1 | audio only | Audio signal sample, left/right channel. | | note | midi only | Pitch of the processed MIDI note (0–127). | | velocity | midi only | Dynamics of the processed MIDI note (0–127). | | sample_offset | midi only | The offset of the MIDI event in samples relative to the start of the buffer. | | output | modulator only | The modulation value written by the script, read by the modulation rack. |


⚙️ 4. Built-in Functions

| Function | Description | | :--- | :--- | | sin(x), cos(x), tan(x), atan(x), atan2(y, x) | Trigonometric functions. | | sqrt(x), abs(x), floor(x), ceil(x) | Basic mathematical functions. | | exp(x), log(x), pow(x, y) | Exponential, natural logarithm, power. | | min(a, b), max(a, b), clamp(val, min, max) | Value clamping. | | rand() | Pseudorandom number from the range [0.0, 1.0). | | emit_note(note, velocity, offset) | Emits a MIDI note with a given pitch and velocity, offset is the sample offset within the current buffer (only @mode: midi). | | emit_note_off(note, offset) | Emits a note-off message, offset as above (only @mode: midi). |

Additionally, there are constants PI, TWO_PI, E, boolean literals true/false (1.0/0.0), as well as custom user functions declared via fn name(arguments) { ... return expression; }.


⚡ 5. Real-Time Smoothness

OmniScript code is compiled to bytecode and executed by a built-in virtual machine (not an interpreter walking an abstract syntax tree), with limits on operation counts, stack depth, and loop iterations to guarantee audio thread safety. The @sample section is executed once for every sample, ensuring Sample-Accurate Timing.