OMNi

OmniDAW API · 9 min

Protokół i konwencje

OmniDAW API na kablu: wyszukiwanie Omni, uścisk dłoni, żądania i błędy, jednostki, odniesienia, efekty i cofanie, zadania, limity i wersjonowanie.

OmniDAW API to JSON-RPC 2.0 przez lokalne gniazdo TCP, jeden obiekt JSON w linii. Wszystko, co potrafi otworzyć gniazdo i sparsować JSON, może sterować Omni. Ta strona to kompletna specyfikacja; referencja metod wymienia, co można wywołać.

Transport

  • Adres: TCP wyłącznie na 127.0.0.1. Połączenia z innych adresów są odrzucane.
  • Ramkowanie: jeden obiekt JSON-RPC 2.0 w linii, UTF-8, każda linia kończy się \n. Odpowiedzi wracają po kolei, jedna na żądanie.
  • Limity: linia dłuższa niż 8 MiB zamyka połączenie. Naraz obsługiwanych jest do 8 połączeń.
  • Powiadomienia: żądanie bez id jest wykonywane, ale nie dostaje odpowiedzi.

Znalezienie Omni

Gdy API jest włączone, Omni zapisuje api/endpoint.json w swoim folderze ustawień i usuwa go przy zamknięciu:

json
{
  "protocol": "omnidaw-api",
  "api_version": "0.21.0",
  "host": "127.0.0.1",
  "port": 50123,
  "token": "9f2c...64 znaki szesnastkowe...",
  "pid": 4242
}
SystemFolder ustawień
Windows%APPDATA%\omni
macOS~/Library/Application Support/omni
Linux$XDG_CONFIG_HOME/omni, a jeśli brak, ~/.config/omni

Port jest losowy, chyba że przed startem Omni ustawisz zmienną środowiskową OMNI_API_PORT. Klient może pominąć plik, ustawiając OMNI_API_ENDPOINT=host:port razem z OMNI_API_TOKEN, na przykład w testach. Token jest nowy przy każdym uruchomieniu, a plik może czytać tylko użytkownik, który uruchomił Omni.

Uścisk dłoni

Pierwszym wywołaniem na każdym połączeniu musi być api.hello z tokenem. Dopóki się nie powiedzie, wszystko poza api.ping dostaje odpowiedź unauthorized.

json
{"jsonrpc":"2.0","id":1,"method":"api.hello","params":{"token":"9f2c...","api_version":"0.21.0","client":{"name":"my-tool","version":"1.0"}}}
json
{"jsonrpc":"2.0","id":1,"result":{"protocol":"omnidaw-api","api_version":"0.21.0","app":{"name":"Omni","version":"0.1.0"},"method_count":102,"capabilities":["jobs","analysis","render","plugins","audio"]}}

api_version w żądaniu to wersja, względem której Twój klient został zbudowany. Jeśli nie jest zgodna, dostaniesz incompatible (zob. Wersjonowanie). client to dowolny tekst pokazywany w logu Omni.

Capabilities

capabilities mówi klientowi, co ten host oferuje poza listą metod, żeby mógł się dostosować bez prób i błędów:

CapabilityZnaczenie
jobsDługie operacje działają jako zadania (jobs.get, jobs.wait)
analysisNagranie i analiza mastera lub toru
renderEksport offline i stemy, szybciej niż w czasie rzeczywistym
pluginsZewnętrzne instrumenty i efekty VST3 oraz CLAP
audioKlipy audio: sampler, slicer, transkrypcja, rozdzielanie stemów
filesObecne tylko wtedy, gdy użytkownik zezwolił klientom na czytanie plików audio (zob. Bezpieczeństwo)

Metody spoza katalogu

Trzy metody należą do samego połączenia i nie dotykają projektu:

MetodaRobi
api.helloUścisk dłoni opisany wyżej
api.methodsKompletny dokument katalogu
api.pingOdpowiada "pong"; dozwolone przed uściskiem dłoni. Służy do sprawdzenia bezczynnego połączenia

Dokument katalogu

api.methods zwraca wszystko, czego klient potrzebuje, żeby przedstawić API bez wpisywania go na sztywno:

json
{
  "protocol": "omnidaw-api",
  "api_version": "0.21.0",
  "units": { "time": "beats (quarter notes)", "level": "dB / dBFS, null = silence", "...": "..." },
  "errors": [ { "code": -32602, "name": "invalid_params" }, "..." ],
  "methods": [ { "name": "tracks.update", "...": "..." } ]
}

Każdy wpis methods ma:

PoleZnaczenie
namedomena.czasownik, snake_case, na przykład clips.write_midi
domainCzęść przed kropką
titleKrótki tytuł dla człowieka
summaryOpis napisany dla modelu językowego: co robi, co przekazać, czego się spodziewać
effectread, control, edit, destructive lub history (zob. niżej)
idempotentCzy powtórzenie wywołania z tymi samymi parametrami nic więcej nie zmienia
sinceWersja API, w której metoda się pojawiła
paramsSchemat JSON parametrów (obiekty zamknięte, zakresy, enumy, elementy zagnieżdżone)
exampleObiekt parametrów, który jest przyjmowany bez zmian

Serwer MCP zamienia każdy wpis w narzędzie; Budowa serwera MCP pokazuje jak.

Żądania, wyniki i błędy

Żądanie:

json
{"jsonrpc":"2.0","id":7,"method":"tracks.update","params":{"track":0,"volume_db":-6}}

Udana odpowiedź niesie result, nieudana error:

json
{"jsonrpc":"2.0","id":7,"error":{"code":-32003,"message":"slot 0 holds no audio (audio.import a file first)"}}

error.data jest opcjonalne. Kody to kody JSON-RPC plus kody Omni:

KodNazwaKiedy
-32700parse_errorLinia nie jest JSON-em
-32600invalid_requestTo nie jest żądanie JSON-RPC 2.0
-32601method_not_foundNieznana metoda
-32602invalid_paramsParametry nie pasują do schematu lub zakresu; nic nie zostało zmienione
-32603internalBłąd w Omni
-32001unauthorizedBrak udanego api.hello na tym połączeniu
-32002not_foundTor, slot, klip lub urządzenie nie istnieje
-32003invalid_stateIstnieje, ale nie może tego zrobić (nuty na torze audio, brak wczytanego audio)
-32004busyOmni nie odpowiedziało w czasie albo trwa już eksport lub nagranie
-32005incompatibleWersje API się nie zgadzają
-32006unavailableSilnik audio nie działa

Komunikaty błędów są pisane tak, by czytał je model: mówią, co było nie tak, a tam, gdzie to pomaga, jakiej metody użyć zamiast tej. Przekazuj je dalej bez zmian.

Konwencje

RzeczReguła
Nazwy metoddomena.czasownik, snake_case. Nazwa narzędzia MCP zamienia kropkę na podkreślnik
CzasZawsze w beatach (ćwierćnutach). Takt 4/4 to 4 beaty. Sekundy pojawiają się tylko tam, gdzie zaznaczono (długość nagrania, pozycje w pliku audio)
PoziomydB lub dBFS. Cisza albo „niezmierzone” to null, nigdy minus nieskończoność
GłośnośćLUFS (EBU R128), true peak w dBTP, zakres głośności w LU
Panoramaod -1 (lewo) do +1 (prawo)
Wysokość dźwiękuNumer nuty MIDI, 60 to środkowe C
ParametryObiekty zamknięte. Nieznane lub źle napisane pole to invalid_params, nigdy nie jest ignorowane. Wszystko jest sprawdzane, zanim cokolwiek się zmieni
WynikiOtwarte. Klienci muszą ignorować pola, których nie znają; nowe wersje dodają pola

Odniesienia

  • Tor: id (UUID jako tekst z tracks.list, stabilny) albo 0-bazowy index (przesuwa się, gdy tory są dodawane lub przesuwane). Preferuj id.
  • Slot: 0-bazowy slot klipu na torze, czyli wiersz sceny siatki sesji.
  • Łańcuch efektów: {"track": <id lub index>} dla insertów toru, {"return_bus": <index>} albo napis "master". Slot w łańcuchu to 0-bazowa pozycja w kolejności sygnału.
  • Klucz parametru: instrument:<id> dla parametru instrumentu toru i fx:<slot>:<index> dla insertu, tak jak zwraca params.list. automation.write przyjmuje te same klucze oraz volume i pan.

Efekty i cofanie

Każda metoda deklaruje efekt. Klient na tej podstawie decyduje o uprawnieniach, potwierdzeniach i adnotacjach MCP.

EfektZnaczenieCofanie
readCzyta stan, nic nie zmienianiepotrzebne
controlZmienia stan na żywo, który nie jest danymi projektu: transport, uruchamianie klipów, nagrania, eksportynie jest zapisywane
editZmienia projektjeden krok w Historii Cofania Omni z etykietą API: <tytuł>
destructiveUsuwa zawartośćjeden krok
historySame edit.undo i edit.redobrak

Skoro każda edycja to zwykły krok historii, człowiek cofa to, co zrobił asystent, przez Ctrl+Z, a asystent może zrobić to samo przez edit.undo. Wywołanie, które edytuje wiele rzeczy naraz, na przykład arrangement.build_song, to nadal jeden krok.

Zadania

Praca trwająca sekundy (nagranie, eksport, transkrypcja, rozdzielanie stemów) nie blokuje połączenia. Wywołanie wraca od razu:

json
{"jsonrpc":"2.0","id":9,"result":{"job":3}}

Potem pytasz o wynik:

json
{"jsonrpc":"2.0","id":10,"method":"jobs.wait","params":{"job":3,"timeout_seconds":9}}

jobs.wait wraca, gdy zadanie się skończy albo po najwyżej 9 sekundach, co nastąpi wcześniej; wywołuj je ponownie, dopóki state to running. jobs.get zwraca bieżący stan natychmiast. Oba są obsługiwane bez udziału wątku UI Omni, więc czekanie nie spowalnia aplikacji. Zadanie ma:

PoleZnaczenie
jobId zadania
kindMetoda, która je rozpoczęła, na przykład analysis.capture
staterunning, done lub failed
progressod 0 do 1
resultWynik po zakończeniu: dla nagrania analiza, dla eksportu ścieżka pliku i analiza zapisanego pliku
errorPowód po failed, w przeciwnym razie null

Naraz może działać tylko jedno nagranie i jeden eksport; drugie dostaje odpowiedź busy.

Limity czasu i ponawianie

  • Wywołanie czeka na wątek UI Omni najwyżej 10 sekund. Jeśli Omni jest zajęte (na przykład otwarte jest okno modalne), odpowiedzią jest busy; spróbuj ponownie, gdy się zwolni.
  • Jeśli połączenie zerwie się w trakcie wywołania, nie wiesz, czy edit się wykonał. Nie wysyłaj go na ślepo ponownie: najpierw odczytaj stan (tracks.list, clips.list, arrangement.get) i zdecyduj. Odczyty i idempotentne edycje można bezpiecznie powtarzać.
  • Połącz się ponownie po restarcie Omni: przeczytaj endpoint.json jeszcze raz, bo port i token się zmieniają.
  • Wyślij api.ping przed ponownym użyciem połączenia, które było bezczynne.

Wersjonowanie

Wersja to major.minor.patch. Reguła jest prosta:

  • Klient zbudowany względem wersji A działa z hostem w wersji B, gdy numery major są równe, a B nie jest starsze od A.
  • Wersje minor tylko dodają metody i pola. W obrębie jednej wersji major nic nie jest usuwane ani zmieniane tak, by zepsuć starszego klienta.
  • Dlatego: ignoruj nieznane pola wyników i buduj listę narzędzi z api.methods przy starcie zamiast wpisywać ją na sztywno, a każdą nową metodę dostaniesz za darmo.

since w każdym wpisie katalogu mówi, w której wersji metoda się pojawiła.

Wypróbuj ręcznie

Nie potrzebujesz niczego poza narzędziem TCP. W PowerShellu odczytaj token:

powershell
$ep = Get-Content "$env:APPDATA\omni\api\endpoint.json" | ConvertFrom-Json
$ep.port; $ep.token

Połącz się dowolnym liniowym klientem TCP (ncat 127.0.0.1 <port> albo telnet z lokalnym echem), wklej linię api.hello ze swoim tokenem, a potem:

json
{"jsonrpc":"2.0","id":2,"method":"theory.scale","params":{"root":"A","mode":"minor"}}