Salta ai contenuti

Run cue lists and show control

Questa pagina è in inglese: in italiano ci sono per ora i tutorial e il glossario; menu, ricerca e navigazione sono in italiano.

A play, a dance piece or an installation is run from a cue list: GO starts the cue on standby and its chain; fades move levels; waits space the cues out. Show control sends what other machines expect (MIDI, OSC, UDP, TCP, timecode) from a song timeline or an action matrix. Both are driven by commands and read through snapshots. Capabilities by priority: Theatre and show-control capabilities.

Uses: core/cues (USES cues), core/showcontrol (USES showcontrol), core/osc (USES osc). Runnable versions: examples/cues/list, examples/showcontrol/actions, examples/osc/echo.

cues::Show show;
cues::CueEngine engine (show, { clock, &parameters, &music, &civil, &recorder });
engine.registerTarget ("audio", audioTarget); // one CueTarget per output domain
cues::CueCommandTarget target (engine); // hand it to the CommandSession

parameters (CueParameters) is what fades move; music, civil and the recorder are optional. Tests use cues::testing::FakeCueTarget and FakeCueParameters.

Every change is a cues.* command (CU-R105); names are enough:

run ("cues.add_list", R"({"name":"Act 1"})");
run ("cues.add_cue", R"({"kind":"target","domain":"audio","name":"Thunder"})");
run ("cues.add_cue", R"({"kind":"fade","name":"Dim thunder","duration":4})");
run ("cues.set_fade_target", R"({"cue":"2","owner":"Thunder","value":-20})");
run ("cues.set_property", R"({"property":"continue","value":"\"auto-continue\"","cues":"1"})");

A cue waits its pre-wait, starts its action, and its continue rule (none, auto-continue after the post-wait, auto-follow when the action ends) starts the next one (CU-R6 to CU-R9). Every instant is computed from the scheduled instants before it, so a long chain does not drift (CU-R10).

cues.go starts the standby cue and moves the playhead past its chain, after GO protection and show mode in commands (CU-R14, CU-R15, CU-R20). cues.trigger_cue and cues.start_cue are direct triggers that leave the playhead alone (CU-R19). cues.stop_all, cues.pause_all, cues.resume_all, cues.reset and cues.panic act on everything running; a second panic stops at once (CU-R68, CU-R69).

On the control thread, from a timer (10 ms is plenty: starts carry their instant):

engine.advanceTo (clock.absoluteNow().time);
for (auto& c : engine.takeCommands()) // key and timecode bindings, wall clock
session.submit (c, midi::showControlTriggerProfile(), {});

Bindings (cues.bind_trigger) fire with the source “show-control trigger” (CU-R145; the profile comes from core/midi). Output domains report back with engine.report (domain, report). On the audio thread, once per block:

engine.fades().process (blockStartSample, blockSize); // noexcept SHUFFLE_RT

FadeEngine has a fixed capacity and a lock-free request ring: the block path never allocates or locks (CU-R58, CU-R60).

5. Show control: destinations, actions, the matrix

Section titled “5. Show control: destinations, actions, the matrix”
showcontrol::Engine engine ({ .clock = clock, .midi = &midi, .network = &network, .timeline = &timeline });
showcontrol::ShowControlTarget target (state, services);
target.attach (&engine, nullptr, nullptr, &clock);
run ("showcontrol.add_destination", R"({"name":"desk","kind":"osc","host":"10.0.0.20","port":8000})");
run ("showcontrol.add_action", R"({"name":"house lights","kind":"osc","target":"desk"})");
run ("showcontrol.map_cell", R"({"action":"house lights","page":"Page 1","row":1,"column":1})");
run ("showcontrol.fire_cell", R"({"page":"Page 1","row":1,"column":1})");

An OSC action’s address and typed arguments are set with showcontrol.edit_action (fields address, arguments; SC-R27, SC-R28). showcontrol.place_action puts an action on a song’s timeline; it fires sample-accurately from TimelinePlayer::timelineBlock on the audio thread (noexcept SHUFFLE_RT). A matrix cell fires live, optionally quantised (SC-R76 to SC-R81). On the control timer call engine.tick() and publish engine.takeEvents(). showcontrol.set_inhibit (osc_out, …) blocks a protocol without editing the show; a panic always passes (SC-R89 to SC-R92).

osc::OscEndpoint endpoint (clock);
endpoint.dispatcher().addMethod ("/mixer/1/gain", [] (const osc::ReceivedMessage& m) {
// m.arguments, m.time (when its bundle is due), m.source
});
endpoint.receiveDatagrams (socket); // network thread: read and decode only
endpoint.process(); // control thread: dispatch, run due bundles

/mixer/*/gain reaches every matching handler (OS-R29). A timed bundle is held until the Clock reaches its time tag, then runs in one step; late bundles follow the LatePolicy (OS-R41 to OS-R44). To send, encode into a fixed buffer with osc::encodeMessage or osc::PacketWriter, then call endpoint.sendDatagram (socket, destination, bytes); from the audio thread, queueDatagram (noexcept SHUFFLE_RT) hands the bytes to sendQueued on the network thread. Real sockets come from shuffle::net_sockets: examples/net/osc_udp. The osc core has no commands of its own (OS-R63).

session.snapshot (commands::SnapshotLevel::brief, 600).text shows running cues, standby, inhibit banners and the fallbacks in effect (CU-R110, SC-R91); endpoint.counters() gives the OSC packet and dispatch counts.

Reference: specs/cues.md, specs/showcontrol.md, specs/osc.md; core/cues, core/showcontrol, core/osc.