Skip to content

Référence du langage Neuroscript (Rust v3)

Neuroscript est le DSL canonique (Rust) pour les transformations MIDI dans Neurode MIDI. Les scripts sont compilés hors des threads temps réel en programmes déterministes.

Exemple rapide

neuroscript
# Garder les notes du canal 1 et limiter la vélocité
keep note where ch == 1
when vel > 110: event(vel=110)

Instructions

Déclarations

neuroscript
var threshold
const max_vel=110

keep / drop

neuroscript
keep note, cc
drop clock, realtime
keep note where ch == 2 and vel > 80

when

neuroscript
when note in C3..C4: event(note=note + 12)
when type == cc and cc == 1: emit.cc(74, value)

event

Modifier l'événement courant :

neuroscript
event(note=clamp(note + 12, 0, 127))
event(vel=clamp(vel + 10, 1, 127))
event(ch=2)

emit

Créer de nouveaux événements :

neuroscript
emit.cc(74, value)
emit.noteOn(note, vel)
emit.noteOff(note)
emit.bend(0)
emit.pc(12)
emit.aftertouch(64)

send

Envoyer l'événement courant (optionnellement en retard) :

neuroscript
send
send through
send after 1/8

drop (événement)

Supprimer l'événement courant :

neuroscript
drop

destinations de routage

Acheminer des valeurs vers des registres, compteurs, variables ou champs :

neuroscript
counter("notes") + 1 -> counter("notes")
42 -> r("global", "latch")
note + 12 -> note
vel -> value

Sélecteurs

Les sélecteurs sont des filtres par type d'événement pour keep/drop :

  • note, cc, pc, bend, aftertouch
  • clock, start, stop, continue, realtime
  • all

Combiner avec des virgules :

neuroscript
drop clock, start, stop, continue, realtime

Conditions

Champs

  • type — Type d'événement
  • ch — Canal (1-16)
  • note — Numéro de note
  • vel — Vélocité
  • cc — Numéro de CC
  • value — Valeur de CC
  • prog — Numéro de programme
  • bend — Valeur de pitch bend

Opérateurs

  • Égalité : ==, !=
  • Comparaison : <, <=, >, >=
  • Appartenance : in
  • Booléens : and, or, not

Exemples :

neuroscript
keep note where ch == 1 and vel > 90
drop note where vel < 20
drop cc
when note in 60..72: event(vel=clamp(vel + 5, 1, 127))

Expressions

Littéraux

  • Entiers : 0, 127, -1
  • Notes : C4, F#3, Bb-1
  • Chaînes : "global", "latch"

Fonctions intégrées

Fonctions de transformation musicale

transpose(semitones) - Transposer la note de n demi-tons (limité à 0-127)

neuroscript
when type == note : {
  transpose(+12)  # Monter d'une octave
  send
}

transposeWrap(semitones) - Transposer la note avec bouclage

neuroscript
transposeWrap(+15)  # Boucle si résultat > 127

transposeReject(semitones) - Transposer la note, supprimer l'événement si hors limites

neuroscript
transposeReject(-5)  # Supprime l'événement si résultat < 0 ou > 127

transposeMode(semitones, mode) - Transposer avec constante de mode explicite

Constantes de mode : clamp (0), wrap (1), reject (2)

neuroscript
transposeMode(+12, wrap)    # Boucler si hors limites
transposeMode(-5, reject)   # Supprimer si hors limites

octave(n) - Déplacer de n octaves (limité à 0-127)

neuroscript
when type == note : {
  octave(+1)  # Monter d'une octave (équivalent à transpose(+12))
  send
}

octaveWrap(n) - Déplacer de n octaves avec bouclage

neuroscript
octaveWrap(+2)  # Boucle si résultat > 127

octaveReject(n) - Déplacer de n octaves, supprimer si hors limites

neuroscript
octaveReject(-2)  # Supprime l'événement si résultat < 0 ou > 127

octaveMode(n, mode) - Déplacer de n octaves avec constante de mode explicite

neuroscript
octaveMode(+1, wrap)    # Boucler si hors limites
octaveMode(-1, reject)  # Supprimer si hors limites

clampNote(min, max) - Limiter la note à une plage

neuroscript
clampNote(C2, C6)  # Contraindre à une plage de deux octaves

wrapNote(min, max) - Boucler la note dans une plage

neuroscript
wrapNote(C3, C5)  # Boucler dans la plage

Fonctions de transformation de vélocité

velScale(factor) - Multiplier la vélocité par un facteur (limité à 1-127)

neuroscript
when type == note : {
  velScale(0.8)  # Réduire à 80%
  send
}

velAdd(delta) - Ajouter à la vélocité (limité à 1-127)

neuroscript
velAdd(-10)  # Réduire la vélocité de 10

velClamp(min, max) - Limiter la vélocité à une plage

neuroscript
velClamp(30, 100)  # Contraindre la dynamique de vélocité

velFixed(value) - Définir la vélocité à une valeur fixe

neuroscript
velFixed(80)  # Toutes les notes à vélocité 80

Fonctions de transformation de canal

chSet(channel) - Définir le canal MIDI (1-16)

neuroscript
chSet(2)  # Forcer tous les événements sur le canal 2

chClamp(min, max) - Limiter le canal à une plage

neuroscript
chClamp(1, 8)  # Contraindre aux canaux 1-8

Fonctions utilitaires

clamp(value, min, max) - Limiter une valeur à la plage [min, max]

neuroscript
event(vel=clamp(vel + 20, 1, 127))

scale(value, inMin, inMax, outMin, outMax) - Mettre à l'échelle une valeur d'une plage d'entrée à une plage de sortie

neuroscript
# Mettre à l'échelle la valeur CC 0-127 à la plage de vélocité 40-127
event(vel=scale(value, 0, 127, 40, 127))

wrap(value, min, max) - Boucler une valeur de manière circulaire dans une plage

neuroscript
event(note=wrap(note + 12, 0, 127))

min(a, b) - Retourner le minimum de deux valeurs

max(a, b) - Retourner le maximum de deux valeurs

abs(value) - Retourner la valeur absolue

Fonctions de compteur

counter(name) - Lire et incrémenter un compteur nommé

neuroscript
when type == note : {
  # N'émettre qu'une note sur 4
  when counter("every4") % 4 == 0 : send
}

Fonctions de registre

r(scope, key) - Lire la valeur du registre avec portée

neuroscript
r("global", "lastNote")
r("source", "accumulator")
r("channel", "count")

r(key) - Lire le registre dans la portée par défaut (locale à la route)

neuroscript
r("lastVel")

Portées de registre

Les registres sont isolés par portée pour éviter les fuites d'état entre routes, sources et destinations.

PortéeDurée de vieIsolationCas d'usage
globalDurée de vie de l'appPartagé entre toutes les routesCompteurs globaux, état de l'app
sourcePar source MIDIIsolé par appareil d'entréeSuivre l'état par source
routePar routeIsolé par config de routePortée par défaut, état local à la route
localPar routeAlias pour routeIdentique à route
channelPar source+canalIsolé par canal d'entréeSuivi d'état par canal
destPar destinationIsolé par appareil de sortieSuivre l'état par dest
dest_channelPar dest+canalIsolé par canal de sortieÉtat par canal de sortie
pathPar chemin de routeIsolé par paire source→destSuivre l'état par connexion
path_channelPar chemin+canalIsolé par source→dest+canalÉtat de chemin à grain fin

Exemples de portée de registre

neuroscript
# Compteur global (partagé entre toutes les routes)
when type == note : {
  r("global", "totalNotes") = r("global", "totalNotes") + 1
}

# État spécifique à la source
when type == note : {
  r("source", "lastNote") = note
}

# État isolé par canal
when type == note and ch == 1 : {
  r("channel", "leadCount") = r("channel", "leadCount") + 1
}

# État de routage spécifique au chemin
when type == cc : {
  r("path", "lastCC") = cc
}

Fonctions d'émission

Les fonctions d'émission créent de nouveaux événements MIDI indépendants de l'événement courant.

Événements de note

emit.noteOn(channel, note, velocity) - Envoyer Note On

neuroscript
emit.noteOn(1, note + 12, vel)  # Doubleur d'octave

emit.noteOff(channel, note, velocity) - Envoyer Note Off

neuroscript
emit.noteOff(1, note, 0)

Changement de contrôle

emit.cc(channel, controller, value) - Envoyer un changement de contrôle 7 bits

neuroscript
when type == cc and cc == 1: emit.cc(74, value)  # Mod wheel → cutoff

emit.cc14(channel, controller, value) - Envoyer un changement de contrôle 14 bits (haute résolution)

neuroscript
emit.cc14(1, 1, 16383)  # Plage complète de modulation 14 bits

Pitch et programme

emit.bend(channel, value) - Envoyer Pitch Bend (-8192 à 8191)

neuroscript
emit.bend(1, 0)  # Centrer le pitch

emit.pc(channel, program) - Envoyer Program Change (0-127)

neuroscript
emit.pc(1, 5)  # Sélectionner le programme 5

emit.bank(channel, msb, lsb) - Envoyer Bank Select (CC#0 + CC#32)

neuroscript
emit.bank(1, 0, 8)  # Banque 0, sous-banque 8

Pression

emit.aftertouch(channel, value) - Envoyer Channel Pressure/Aftertouch

neuroscript
emit.aftertouch(1, 64)

System Exclusive

emit.sysex(bytes) - Envoyer un message System Exclusive

neuroscript
emit.sysex([0xF0, 0x43, 0x10, 0x7F, 0x00, 0xF7])

NRPN

emit.nrpn(channel, parameter, value) - Envoyer Non-Registered Parameter Number

neuroscript
emit.nrpn(1, 128, 64)

Comportement de send

send

Émet l'événement courant et arrête le traitement des règles suivantes.

neuroscript
when type == note and note < 60 : {
  event(ch=2)
  send  # Envoyer à la destination, arrêter le traitement
}
# Les règles ci-dessous ne s'exécuteront pas pour les notes < 60

send through

Émet l'événement courant et continue le traitement des règles suivantes.

neuroscript
when type == note and note < 60 : {
  emit.noteOn(1, note + 12, vel)  # Ajouter une octave
  send through  # Continuer aux règles suivantes
}

# Cette règle S'EXÉCUTERA même pour les notes < 60
when type == note : {
  event(vel=velScale(0.8))
  send
}

Utilisez send through lorsque vous voulez :

  • Ajouter des notes d'harmonie tout en gardant l'original
  • Appliquer plusieurs transformations en séquence
  • Router vers plusieurs destinations avec un traitement différent

send after

Planifier un envoi retardé (nécessite une synchronisation de tempo ou un délai en millisecondes) :

neuroscript
send after 100ms
send after 1/8   # Délai d'une croche
send after 1/4   # Délai d'une noire

Exemples complets

Zone lead avec boost

neuroscript
keep note where ch == 1
event(note=clamp(note + 12, 0, 127))
event(vel=clamp(vel + 10, 1, 127))

Supprimer les drums et le bruit CC

neuroscript
drop note where ch == 10
drop cc where cc in 64..127

Mod wheel vers cutoff

neuroscript
when type == cc and cc == 1: emit.cc(74, value)

Pour tester un événement unique, utilisez le Simulateur Neuroscript.

Créé avec ❤️ pour les musiciens