Přeskočit na obsah

SEB scény a Event Player ve FW 0.12.11

Jak ve firmware 0.12.11 použít Berry SEB.land a SEB.emit pro kauzální scény a časované segmenty eventových hodnot.

SEB (Spectoda Event Batch) je malý binární soubor s diskrétními eventovými hodnotami/záznamy. Každý záznam obsahuje nativní hodnotu, label, Spectoda ID, prioritu a absolutní časový offset uvnitř segmentu. Landing nebo emit záznamu vyvolá běžné zpracování EventStateUpdate přes EventStore.

SEB není celý Player ani formát projektu. Neobsahuje název scény, název Tracku, loop nebo seek pravidla. Tyto informace drží projektový Berry script. Statický soubor player.show je omezený adresář deterministických per-ID SEB řetězců v NetworkStorage.

Jeden SEB segment má nejvýše 340 záznamů, velikost nejvýše 4 092 bajtů a délku nejvýše 65 535 ms. Tím využije jeden 4 096B datový blok LittleFS; metadata souboru jsou uložena samostatně. Runtime nadále přijme v jednom atomickém příspěvku nejvýše 340 splatných eventů, takže jeden celý maximální Cue lze commitnout atomicky. Celkový 341. pending event selže před změnou fronty, EventStore nebo cursoru. Delší Track se skládá z více seřazených segmentů. Normativní byte layout a všechna validační pravidla udržuje firmware v souboru components/spectoda-library/docs/SEB_V1.md; zde je přesná review verze pro FW 0.12.11.

Pro distribuovaný Player používejte na všech připravených kontrolerech SEB.land. Události vstoupí do lokálního EventStore se stejným síťovým časem, ale nevznikne okamžitý broadcast execute bytecode. Běžná synchronizace EventStore později dorovná kontroler, který událost ve správný okamžik nelandnul.

SEB.emit použijte jen tehdy, když existuje právě jeden autoritativní zdroj. Pouštět SEB.emit na všech kontrolerech by zbytečně násobilo síťové události.

Skalární API zůstává ve FW 0.12.11 zachované:

spectoda.landEvent(label, value, ids, vtype)
spectoda.landEvent(label, value, ids, vtype, event_millis)
spectoda.emitEvent(label, value, ids, vtype)
spectoda.emitEvent(label, value, ids, vtype, event_millis)

ids může být jedno ID, seznam ID nebo nil pro broadcast. Volitelný event_millis zachová přesný kauzální lokální čas původní události. Pro dávky používejte komponentu SEB; nejde o plural variantu skalární metody.

var result = SEB.land("segment-000.seb", {
"source": "networkStorage",
"at": segment_at,
"cursor": cursor,
"until": position
})
if result["ok"]
cursor = result["cursor"]
else
print("SEB error", result["error"])
end
  • at je lokální wrapping controller.millis() token odpovídající offsetu nula. Pro časovaný segment je povinný.
  • cursor je index prvního dosud nespotřebovaného zdrojového záznamu. Výchozí hodnota je 0.
  • until je včetně zahrnutý offset, po který se mají zpracovat splatné záznamy. Výchozí hodnota je 0.
  • source: "networkStorage" určuje, že první argument je název souboru. Bez něj zůstává první argument Berry hodnota bytes.

Jedno volání vezme maximální splatný prefix. Nejdřív jej celý ověří a rezervuje a teprve potom atomicky zapíše. Při chybě zůstane EventStore, fronta i cursor beze změny, takže Berry může volání bezpečně zopakovat.

Jeden kontrakt args.at pokrývá tři explicitní časové domény:

  • timeline.at(segmentStart) převede pozici Player timeline na lokální wrapping millis token;
  • event_millis z triggeru EVS.cb zachová Network-clock kauzalitu události při vyvolání scény;
  • controller.millis() znamená právě teď na tomto Controlleru.

Network clock zůstává autoritou pro řazení EventStore. SEB přijímá pouze lokální token a nemá žádný timeline-specific overload.

SEB si neponechá Berry pointer, filename, file handle, cursor ani Player stav. Projekt musí zachovat bitově stejné at pro přesný pár zdroje a cursoru. Při změně segmentu, seeku, loopu nebo změně časové projekce musí cursor resetovat nebo nahradit.

Referenční Player řeší pause/resume jako explicitní vnější policy. S novou projekcí odvodí nový pár filename/at a přenese jen známý index prvního nespotřebovaného zdrojového záznamu. Toto číslo nepoužívejte s jiným zdrojem ani s libovolným at.

Scéna je obyčejný mixed-ID SEB s duration_ms = 0 a všemi offsety nula. Trigger Event může nést label scény. Callback EVS.cb předá také přesný lokální čas původní události; ten použijte jako at.

var scene = EVS("scene", ID255)
scene.cb = def(value, event_id, event_millis)
if event_millis == nil || !value.is(31)
return
end
var name = value.get(31) + ".seb"
var result = SEB.land(name, {
"source": "networkStorage",
"at": event_millis
})
if !result["ok"]
print("Invalid scene", result["error"])
end
end

Trigger $scene[ID255] samotný do souboru scény nekompilujte, jinak by vznikla rekurze.

Scene recall vůbec nevolá timeline.at(). Zůstává kauzální i při pozastavené timeline, protože callback dostal event_millis z trigger události.

Malý copy-ready Player načte <base>.show a polluje timeline.getState(). Při paused: true nevolá SEB. Běžný dopředný běh vybere další kompletní Cue z per-ID segmentu, spočítá jeho at přes timeline.at(segmentStart) a předává aktuální relativní pozici jako until.

timeline.at(position) uchovává, že aktuální referenční pozice timeline P platila v Network clock čase C, vypočte C + (position - P) a tento clock převede na signed wrapping lokální token Controlleru. Stejný výpočet platí při běhu i pauze, takže Controllery s rozdílnou latencí zpracování příkazu získají stejný Network timestamp. Funkce vrací nil, pokud cílový clock není platný nebo leží mimo jednoznačné wrapping okno ±2^31 ms.

Timeline pozice je samostatný 24hodinový kruh 0..86 399 999; hodnota 86 400 000 se normalizuje na 0. Přechod přes půlnoc proto zůstává spojitý pro Player, Layer i animace. Projekce vybírá nejbližší výskyt v rozsahu ±12 hodin; přesný rozdíl 12 hodin je nejednoznačný a vrátí nil.

Pause/resume zachovává epoch, ale resume vytváří novou kauzální projekci; Player znovu otevře časování zbývající části segmentu a ponechá již spotřebovaný zdrojový prefix. Seek a loop epoch změní. Staré časování a cursory se potom musí zahodit a obnovit z kompletního checkpointu.

Seek není zpětné přehrání všech přeskočených událostí. Statický adresář player.show dovolí projektovému Berry najít pro každý relevantní Track poslední úplné Cue v čase menším nebo rovném cíli. Tyto hodnoty landne v čase seeku a potom pokračuje za nimi. Vedlejší účinky přeskočené minulosti se znovu nevyvolají.

SEB nemění EventState mimo EventStore. Poslední EventStateUpdate proto zůstává rozhodující i po pozdější synchronizaci historie a externě emitovaná událost může stav Playeru změnit běžnou cestou.

Příklady používají jen syntetická ID a přesné NetworkStorage artefakty pro FW 0.12.11. Pro tvorbu show ve Studiu pokračujte na návod Event Player ve Spectoda Studiu.