OMNi
Dokumentacja/Wtyczki i Zaawansowane

Język Skryptowy OmniScript

Podręcznik pisania własnych algorytmów generatywnych, procesorów MIDI, modulatorów i prostych efektów DSP w zintegrowanym języku skryptowym OmniScript.

~5 min czytania
Oficjalny Podręcznik OMNI
Precyzja 960 PPQ

📜 Język Skryptowy OmniScript

WSKAZÓWKA

[!TIP] OmniScript to zintegrowany język skryptowy kompilowany do bezpiecznego kodu maszyny wirtualnej (bez alokacji, bez paniki), pozwalający pisać własne procesory MIDI, modulatory oraz proste efekty DSP bez kompilowania zewnętrznych wtyczek. Gotowe przykłady znajdziesz w omni_engine/examples/scripts/*.omfx.


💡 1. Trzy Rodzaje Skryptów (.omfx)

Plik .omfx deklaruje w nagłówku swój rodzaj przez @mode:, co decyduje o tym, gdzie skrypt jest dostępny i jakie zmienne wbudowane widzi:

  • @mode: audio — prosty efekt DSP wpięty w łańcuch insertowy (np. gain, bitcrusher, filtr).
  • @mode: midi — generatywny procesor MIDI (arpeggiator, generator akordów, humanizator, kwantyzator do skali).
  • @mode: modulator — własny modulator w racku modulacji (patrz /docs/modulators).

Skrypt nie definiuje własnej funkcji wejściowej w stylu fn process_note(). Zamiast tego host wywołuje bezpośrednio ustandaryzowane sekcje pliku, jeśli są obecne:

| Sekcja | Kiedy jest wywoływana | | :--- | :--- | | @init | Raz, przy wczytaniu/resecie skryptu. | | @block | Raz na każdy bufor audio. | | @sample | Raz na każdą próbkę (sample-accurate). | | @midi_note_on / @midi_note_off | Przy każdym przychodzącym zdarzeniu MIDI (tylko @mode: midi). | | @modulate | Starszy, pojedynczy punkt wejścia modulatora — zastąpiony przez @block/@sample zapisujące do zmiennej output. |


💻 2. Prawdziwe Przykłady

Przykład A: Prosty efekt DSP (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];

Przykład B: Modulator z własną funkcją (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);

Uwaga składniowa: OmniScript nie ma słowa kluczowego let — pierwsze przypisanie do nazwy automatycznie ją deklaruje (nazwa = wyrażenie;). Pętle for mają składnię zakresową w stylu Rust: for i in 0..8 { ... }, a nie klasyczną C-ową for(;;).


🛠️ 3. Zmienne Wbudowane

Wszystkie zmienne w OmniScript są liczbami zmiennoprzecinkowymi (f64) — nie ma osobnych typów u8/f32 widocznych ze skryptu (np. note/velocity to po prostu liczby 0–127).

| Zmienna | Dostępna w trybie | Opis | | :--- | :--- | :--- | | sample_rate | wszystkie | Częstotliwość próbkowania silnika audio. | | tempo | wszystkie | Aktualne tempo projektu w BPM. | | beat_pos | wszystkie | Bieżąca pozycja odtwarzania w takcie. | | frames | wszystkie | Rozmiar bieżącego bufora audio (liczba próbek). | | play_state | wszystkie | 1.0 gdy transport gra, 0.0 gdy jest zatrzymany. | | param[0]param[63] | wszystkie | Wartości parametrów zdefiniowanych przez @param[n] w nagłówku pliku — do odczytu i zapisu. | | spl0 / spl1 | tylko audio | Próbka sygnału audio, kanał lewy/prawy. | | note | tylko midi | Wysokość przetwarzanej nuty MIDI (0–127). | | velocity | tylko midi | Dynamika przetwarzanej nuty MIDI (0–127). | | sample_offset | tylko midi | Przesunięcie zdarzenia MIDI w próbkach względem początku bufora. | | output | tylko modulator | Wartość modulacji zapisywana przez skrypt, odczytywana przez rack modulacji. |


⚙️ 4. Wbudowane Funkcje

| Funkcja | Opis | | :--- | :--- | | sin(x), cos(x), tan(x), atan(x), atan2(y, x) | Funkcje trygonometryczne. | | sqrt(x), abs(x), floor(x), ceil(x) | Funkcje matematyczne podstawowe. | | exp(x), log(x), pow(x, y) | Wykładnicza, logarytm naturalny, potęgowanie. | | min(a, b), max(a, b), clamp(val, min, max) | Ograniczanie wartości. | | rand() | Pseudolosowa liczba z przedziału [0.0, 1.0). | | emit_note(note, velocity, offset) | Emituje nutę MIDI o zadanej wysokości i dynamice, offset to przesunięcie w próbkach w obrębie bieżącego bufora (tylko @mode: midi). | | emit_note_off(note, offset) | Emituje komunikat wyłączenia nuty, offset jak wyżej (tylko @mode: midi). |

Dodatkowo dostępne są stałe PI, TWO_PI, E oraz literały logiczne true/false (1.0/0.0), a także własne funkcje użytkownika zadeklarowane przez fn nazwa(argumenty) { ... return wyrażenie; }.


⚡ 5. Płynność w Czasie Rzeczywistym

Kod OmniScript jest kompilowany do bytecode'u i wykonywany przez wbudowaną maszynę wirtualną (nie interpreter chodzący po drzewie składniowym), z ograniczeniami liczby operacji, głębokości stosu i iteracji pętli gwarantującymi bezpieczeństwo wątku audio. Sekcja @sample wykonuje się raz na każdą próbkę, co zapewnia precyzję rzędu pojedynczej próbki (Sample-Accurate Timing).