Skip to content

Script Engine Overview

Neurode MIDI v2 uses NeuroScript 2.0 as the canonical way to express routing/transforms.

Canonical encoding (v2)

  • NeuroScript 2.0 source is canonical (presets export/import as source).
  • Visual authoring is allowed, but it compiles to NeuroScript (no TransformGraph/DAG runtime requirement).
  • Lua scripting is supported, but NeuroScript remains canonical for v2 encoding/export.

What is the Script Engine?

The Script Engine lets you write custom MIDI effects using code. Every MIDI event enters your script, you process it, and return the transformed output.

Languages:

  • NeuroScript 2.0 — Canonical, bounded, deterministic
  • Lua — Fully supported alternative (non-canonical encoding)

Quick Validation

Try the Neuroscript Simulator for quick, single-event tests without creating a full route.

How It Works

NeuroScript compiles to an immutable execution plan. Each MIDI event flows through your script's filter, transform, and routing statements. The script operates on messages deterministically with bounded execution.

Lua scripts can be used as an alternative, providing a function body that processes each event in real-time.

Quick Start

Try a quick transform

Here's a simple NeuroScript example:

neuroscript
# Keep notes on channel 1, transpose up an octave
keep note where ch == 1
transpose +12
vel clamp 50..110
pass

For more advanced control, you can use Lua:

lua
-- Drop notes below C3
if event.type == "noteOn" and event.data1 < 48 then
  return {} -- Drop event
end
return event
Which Language Should I Use?
  • NeuroScript 2.0 — Preferred: deterministic, compiles to an immutable execution plan with bounded execution guarantees
  • Lua — Supported alternative for custom scripting needs

If you're building or sharing presets, prefer NeuroScript so the preset is portable and auditable.

State & Memory (v2)

NeuroScript 2.0 provides fixed-size Int32 register banks that scripts can read/write deterministically.

Scopes:

  • stream — Per MIDI stream
  • channel — Per channel (1–16)
  • source — Per input source
  • global — Shared across all routing

Example

neuroscript
# Count note-on events in a stream-scoped register
when type == note_on {
    register("noteCount") + 1 -> register("noteCount")
}
pass

Use cases:

  • Count events for patterns (every Nth note)
  • Share coarse state between routes (global)
  • Coordinate per-channel behavior without locks

Next Steps


Performance

The engine tracks per-event execution time. Keep loops tight and prefer numeric operations for best results.

Built with ❤️ for musicians