Skip to content

Neuroscript Language Reference

Neuroscript is a musician-focused DSL for MIDI transformations. It uses a simple line-based syntax where each line represents a processing step applied to incoming MIDI events.

Design Philosophy

  • Declarative: Describe what you want, not how to achieve it
  • Line-based: One transformation per line, executed in order
  • Permissive: Unmatched events pass through by default
  • Readable: Syntax mirrors musical terminology (note, ch, transpose, vel)
  • Safe: Compile-time validation prevents runtime errors

Basic Structure

neuroscript
# Comments start with #
keep note             # Keep only note events
transpose +12 clamp   # Shift up an octave, clamp out-of-range
pass                  # Explicitly pass remaining events

Each line is a statement. Events flow top-to-bottom through the script. If an event doesn't match a filter, it passes to the next line.


Core Concepts

Event Flow

  1. MIDI events enter the script
  2. Each statement processes the event stream
  3. Statements can filter (keep/drop), transform (modify), or pass through
  4. Final events exit to the next node in the pipeline

Filtering vs. Transforming

  • Filtering: keep/drop select which events proceed
  • Transforming: transpose, vel scale, note map modify event data
  • Control flow: when, pass, mute control execution

Statement Types

Filtering: keep / drop

Select events by type, channel, note range, or CC number.

Syntax:

neuroscript
keep <selectors> [where <condition>]
drop <selectors> [where <condition>]

Selectors:

  • note — Note On/Off messages
  • cc — Control Change messages
  • pc — Program Change
  • bend — Pitch Bend
  • aftertouch — Channel Aftertouch
  • clock, start, stop, continue, realtime — System messages
  • all — Match everything
  • ch <spec> — Channel filter (see Channel Spec below)
  • note <range> — Note range filter
  • cc <range> — CC number range filter

Examples:

neuroscript
keep note                      # Only note events
keep note, ch 1                # Notes on channel 1
keep note, ch 1..4             # Notes on channels 1-4
keep note C3..C5               # Notes from C3 to C5
drop cc 64..127                # Drop CC 64 and above
drop clock, start, stop        # Drop all clock messages

Channel Specification

Channels can be specified as:

  • all — All 16 channels
  • <n> — Single channel (1-16)
  • <n>..<m> — Channel range (e.g., ch 1..4)

Examples:

neuroscript
keep ch 1          # Channel 1 only
keep ch all        # All channels
keep note, ch 1..8 # Notes on channels 1-8

Transformations

transpose

Shift note pitches by semitones.

Syntax:

neuroscript
transpose <semitones> [mode]

Modes:

  • clamp (default) — Clamp to MIDI range (0-127)
  • wrap — Wrap around (128 → 0)
  • drop — Drop out-of-range notes

Examples:

neuroscript
transpose +12           # Up one octave
transpose -7 clamp      # Down 7 semitones, clamp
transpose +2 drop       # Up 2 semitones, drop overflow

octave

Convenience shorthand for transpose by octaves (12 semitones).

Syntax:

neuroscript
octave <octaves> [mode]

Examples:

neuroscript
octave +1        # Up one octave (same as transpose +12)
octave -2 clamp  # Down two octaves, clamp

vel (velocity)

Modify note velocity in three ways:

scale — Map velocity to a range:

neuroscript
vel scale 50..100    # Scale velocity to 50-100 range
vel scale 80..127    # Boost to 80-127 range

fixed — Set constant velocity:

neuroscript
vel fixed 80         # All notes at velocity 80
vel fixed 100        # All notes at velocity 100

clamp — Limit velocity range:

neuroscript
vel clamp 30..110    # Clamp between 30-110
vel clamp 64..127    # Remove quiet notes

note map

Remap individual notes (useful for scale corrections, alternate tunings).

Syntax:

neuroscript
note map {
  <from> -> <to>
  <from> -> <to>
  ...
}

Shorthand (single mapping):

neuroscript
note C4 -> note D4

Examples:

neuroscript
# Flatten scale tones for bluesy feel
note map {
  E3 -> Eb3
  E4 -> Eb4
  A3 -> Bb3
  A4 -> Bb4
}

# Single note mapping
note Bb3 -> note B3

ch map (channel remap)

Remap MIDI channels.

Syntax:

neuroscript
ch <from> -> ch <to>

Examples:

neuroscript
ch 2 -> ch 1        # Route channel 2 to channel 1
ch 10 -> ch 1       # Drums (ch 10) to melodic channel

cc map (CC remap)

Remap CC controller numbers.

Syntax:

neuroscript
cc <from> -> cc <to>

Examples:

neuroscript
cc 1 -> cc 74        # Mod wheel to filter cutoff
cc 11 -> cc 7        # Expression to volume

Control Flow

when

Conditional execution: apply action only when condition is true.

Syntax:

neuroscript
when <condition>: <action>

Examples:

neuroscript
when vel > 100: vel clamp 80..100     # Tame loud notes
when note in C3..C4: transpose +12    # Shift low octave
when ch = 10: drop                    # Drop drum channel

pass

Explicitly pass events through (optional, events pass by default).

neuroscript
pass

mute

Drop all remaining events (useful as final statement or in conditionals).

neuroscript
mute

Conditions (where / when)

Conditions use predicates and boolean operators.

Fields

  • type — Event type (note, cc, pc, bend, etc.)
  • ch — Channel (1-16)
  • note — Note number (0-127)
  • vel — Velocity (0-127)
  • cc — CC number (0-127)
  • value — CC value (0-127)
  • prog — Program number (0-127)
  • bend — Pitch bend value

Operators

  • =, != — Equality
  • <, <=, >, >= — Comparison
  • in — Range/set membership

Boolean Logic

  • and — Both conditions must be true
  • or — Either condition can be true
  • not — Negate condition

Examples

neuroscript
# Keep only loud notes on channel 1
keep note where ch = 1 and vel > 90

# Drop quiet notes or CC
drop where (type = note and vel < 20) or type = cc

# Keep notes in specific range
keep note where note in 60..72

# Complex condition
when vel > 110 and ch in [1, 2, 3]: vel clamp 80..110

Note Literals

Notes can be specified as:

  • C, C#, Db, D, ... B (middle C octave)
  • C3, D#4, Bb-1 (specific octaves)

Examples:

  • C4 — Middle C (MIDI 60)
  • A3 — A below middle C (MIDI 57)
  • Eb3 — E-flat in octave 3
  • F#5 — F-sharp in octave 5

Complete Examples

Lead Zone with Boost

neuroscript
# Keep lead notes on channel 1, lift an octave, tame peaks
keep note, ch 1
transpose +12 clamp
vel clamp 50..110
pass

Drop Drums and CC Noise

neuroscript
# Clean mix: remove drums and unnecessary CC
drop note, ch 10      # Drop drum channel
drop cc 64..127       # Drop high CC numbers
pass

Blues Note Mapping

neuroscript
# Add bluesy flavor by flattening scale tones
note map {
  E3 -> Eb3
  E4 -> Eb4
  A3 -> Bb3
  A4 -> Bb4
}
pass

Channel Split with Transpose

neuroscript
# Route channels 1-4 up, channels 5-8 down
when ch in 1..4: transpose +12
when ch in 5..8: transpose -12
pass

MIDI Glue (Cleanup)

neuroscript
# Glue multiple tracks: remove clock spam, standardize CC
drop clock, start, stop, continue, realtime
cc 1 -> cc 74         # Mod wheel to filter
pass

Conditional Velocity Scaling

neuroscript
# Boost quiet notes, tame loud ones
when vel < 50: vel scale 50..90
when vel > 110: vel clamp 80..110
pass

Dynamic Layer Switching

neuroscript
# Loud notes get one sound, quiet notes another
when vel > 90: ch 1 -> ch 2
when vel <= 90: ch 1 -> ch 3
pass

Comparison: Neuroscript vs. Lua

FeatureNeuroscriptLua
SyntaxLine-based, declarativeProcedural, imperative
Learning CurveLow (musician-friendly)Medium (programming knowledge)
FlexibilityFixed MIDI operationsArbitrary logic
SafetyCompile-time checksRuntime errors possible
PerformanceOptimized for MIDIInterpreted overhead
Use CaseCommon MIDI tasks (transpose, filter, remap)Complex custom logic

When to use Neuroscript:

  • Standard MIDI operations (transpose, velocity scaling, filtering)
  • Readable, maintainable scripts for musicians
  • Fast prototyping without programming knowledge

When to use Lua:

  • Complex stateful logic (arpeggios, sequencing)
  • Custom algorithms not covered by Neuroscript
  • Integration with external data or calculations

Error Handling

Neuroscript validates scripts at compile time before execution.

Common Errors

Out-of-range channel:

neuroscript
keep ch 17           # Error: Channel 17 is out of range (1-16)

Invalid velocity:

neuroscript
vel fixed 150        # Error: Velocity 150 is out of range (0-127)

Invalid note range:

neuroscript
keep note 128..140   # Error: Note range out of MIDI bounds (0-127)

Empty selector:

neuroscript
keep                 # Error: Expected at least one selector

Error Messages

Errors include line and column numbers:

3:6 Channel 17 is out of range (1-16).

This means: Line 3, column 6 — check your channel specification.


Best Practices

1. Start Simple

Begin with basic filters, add complexity gradually:

neuroscript
# v1: Just filter
keep note, ch 1

# v2: Add transpose
keep note, ch 1
transpose +12

# v3: Add velocity control
keep note, ch 1
transpose +12
vel clamp 50..110

2. Use Comments Liberally

Explain why, not just what:

neuroscript
# Bass zone: low keys only, boost quiet notes
keep note C1..C3
when vel < 60: vel scale 60..90
pass

3. Explicit pass for Clarity

End scripts with pass to make intent clear:

neuroscript
keep note, ch 1
transpose +12
pass   # All other events pass through

4. Test Incrementally

Add one statement at a time, test with the MIDI visualizer:

neuroscript
keep note             # Does this keep the right events?
# transpose +12       # Uncomment once filter is correct

5. Prefer clamp Over drop

For live performance, clamping avoids unexpected silence:

neuroscript
transpose +12 clamp   # Safer
# transpose +12 drop  # Risky: high notes disappear

6. Name Your Scripts

Save scripts with descriptive names:

  • bass_zone_boost.ns
  • lead_octave_up.ns
  • drum_channel_cleanup.ns

7. Keep Scripts Short

If a script exceeds 10-15 lines, consider refactoring into clearer sections (comments + focused when blocks), or splitting into multiple presets/routes.

# Prefer clarity within one script (canonical), or split by preset/route.

If you use a visual editor, treat it as an authoring UI that compiles to NeuroScript (no graph runtime required).


Advanced Patterns

Layering (Split to Multiple Channels)

neuroscript
# Duplicate to channels 1 and 2 based on velocity
when vel > 90: ch 1 -> ch 2
pass

Velocity Zones

neuroscript
# Route to different synths based on dynamics
when vel < 60: ch 1 -> ch 3     # Soft layer
when vel >= 60 and vel < 100: ch 1 -> ch 2  # Medium layer
when vel >= 100: ch 1 -> ch 1   # Loud layer (original)
pass

Note Range Splits (Keyboard Zones)

neuroscript
# Bass on left, lead on right
when note < 60: ch 1 -> ch 2
when note >= 60: ch 1 -> ch 3
pass

CC Remapping for Different Gear

neuroscript
# Adapt mod wheel to different synth expectations
cc 1 -> cc 74   # Mod wheel to filter cutoff
cc 11 -> cc 7   # Expression to volume
pass

Humanize (Subtle Velocity Variation)

Not directly supported in Neuroscript — use Lua for randomization.

lua
-- Lua alternative for humanization
if event.type == "noteOn" then
  local delta = (math.random() * 10) - 5
  event.data2 = MIDI.clamp(math.floor(event.data2 + delta))
end
return event

Limitations

No State Between Events

Each MIDI event is processed independently. For stateful logic (arpeggios, sequencing), use Lua scripting.

No Timing/Delay

Neuroscript processes events synchronously. For delays or timing effects, use multiple routes with separate timing nodes (future feature).

No Random/Math Functions

For random velocity, probability-based routing, or complex math, use Lua.

No MIDI Output Selection

Neuroscript transforms events within a single route. Route-level destination selection happens in the graph editor.


Grammar Reference (ANTLR)

For implementers: Neuroscript is defined by an ANTLR grammar at:

Sources/NeuroScriptKit/Grammar/NeuroScript.g4

Key Productions:

  • scriptstatementList
  • statementkeep | drop | when | transpose | octave | vel* | *map | pass | mute
  • selectoreventType | channel | note | cc
  • exprorExpr → andExpr → notExpr → predicate

Next Steps


Neuroscript is part of Neurode MIDI, a MIDI routing and transformation system for iOS and macOS.

Built with ❤️ for musicians