Skip to main content

sim_lib_view_daw/
player_rack.rs

1//! Player-rack Scene descriptors for live player chains.
2
3use sim_kernel::{Expr, Symbol};
4use sim_lib_scene::{data_map, node, sym};
5use sim_value::build::{list, text, uint};
6
7use crate::keyboard::performance_keyboard_demo_scene;
8use crate::piano_roll::piano_roll_demo_scene;
9
10/// Stable lens id for the player-rack view.
11pub const PLAYER_RACK_VIEW_ID: &str = "view:player-rack";
12
13/// Editing actions exposed by the player-rack scene.
14pub const PLAYER_RACK_ACTIONS: &[&str] = &[
15    "add",
16    "remove",
17    "reorder",
18    "bypass",
19    "direct-record",
20    "freeze",
21    "trace",
22    "route",
23    "placement-hint",
24];
25
26/// One player device in a rack.
27#[derive(Clone, Debug, PartialEq, Eq)]
28pub struct PlayerRackDevice {
29    /// Stable player id.
30    pub id: Symbol,
31    /// Display label.
32    pub label: String,
33    /// Player family.
34    pub player_kind: Symbol,
35    /// Zero-based order in the chain.
36    pub order: u64,
37    /// Bypass state.
38    pub bypassed: bool,
39    /// Whether direct recording is armed.
40    pub direct_record: bool,
41    /// Whether output is frozen for deterministic replay.
42    pub frozen: bool,
43    /// Whether trace inspection is enabled.
44    pub trace: bool,
45    /// Routing target after the player.
46    pub route: Symbol,
47    /// Placement hint for this player.
48    pub placement_hint: String,
49}
50
51/// Complete player-rack descriptor.
52#[derive(Clone, Debug, PartialEq, Eq)]
53pub struct PlayerRackView {
54    /// Intent target edited by rack actions.
55    pub target: Symbol,
56    /// Player chain represented by the rack.
57    pub player_chain: Symbol,
58    /// Instrument target at the end of the chain.
59    pub instrument: Symbol,
60    /// Performance source feeding the chain.
61    pub source: Symbol,
62    /// Stream bridge route for live capture.
63    pub stream: Symbol,
64    /// Rack-level placement hint.
65    pub placement_hint: String,
66    /// Player devices.
67    pub players: Vec<PlayerRackDevice>,
68}
69
70/// Render a player rack as `scene/player-rack`.
71pub fn player_rack_view(view: &PlayerRackView) -> Expr {
72    node(
73        "player-rack",
74        vec![
75            ("lens", sym(PLAYER_RACK_VIEW_ID)),
76            ("role", sym("player-rack")),
77            ("target", Expr::Symbol(view.target.clone())),
78            ("player-chain", Expr::Symbol(view.player_chain.clone())),
79            ("instrument", Expr::Symbol(view.instrument.clone())),
80            ("source", Expr::Symbol(view.source.clone())),
81            ("stream", Expr::Symbol(view.stream.clone())),
82            ("placement-hint", text(view.placement_hint.clone())),
83            (
84                "actions",
85                list(
86                    PLAYER_RACK_ACTIONS
87                        .iter()
88                        .map(|action| text(*action))
89                        .collect(),
90                ),
91            ),
92            (
93                "players",
94                list(view.players.iter().map(player_rack_device_expr).collect()),
95            ),
96        ],
97    )
98}
99
100/// Deterministic rack fixture over the keyboard performance source.
101pub fn player_rack_demo_view() -> PlayerRackView {
102    let chain = Symbol::qualified("music/player-chain", "onscreen-keyboard");
103    let source = Symbol::qualified("music/performance-source", "keyboard");
104    PlayerRackView {
105        target: chain.clone(),
106        player_chain: chain.clone(),
107        instrument: Symbol::qualified("audio-synth/instrument", "dx7"),
108        source,
109        stream: Symbol::qualified("stream/browser", "performance-keyboard"),
110        placement_hint: "browser-wasm".to_owned(),
111        players: vec![
112            PlayerRackDevice {
113                id: Symbol::qualified("music/player", "scales-chords"),
114                label: "Scales and chords".to_owned(),
115                player_kind: Symbol::qualified("music/player-kind", "scales-chords"),
116                order: 0,
117                bypassed: false,
118                direct_record: false,
119                frozen: false,
120                trace: true,
121                route: chain.clone(),
122                placement_hint: "browser-wasm".to_owned(),
123            },
124            PlayerRackDevice {
125                id: Symbol::qualified("music/player", "dual-arpeggio"),
126                label: "Dual arpeggio".to_owned(),
127                player_kind: Symbol::qualified("music/player-kind", "dual-arpeggio"),
128                order: 1,
129                bypassed: false,
130                direct_record: true,
131                frozen: false,
132                trace: true,
133                route: chain.clone(),
134                placement_hint: "worker".to_owned(),
135            },
136            PlayerRackDevice {
137                id: Symbol::qualified("music/player", "note-echo"),
138                label: "Note echo".to_owned(),
139                player_kind: Symbol::qualified("music/player-kind", "note-echo"),
140                order: 2,
141                bypassed: true,
142                direct_record: false,
143                frozen: true,
144                trace: false,
145                route: Symbol::qualified("audio-synth/instrument", "dx7"),
146                placement_hint: "audio-worklet".to_owned(),
147            },
148        ],
149    }
150}
151
152/// Deterministic player-rack demo scene.
153pub fn player_rack_demo_scene() -> Expr {
154    player_rack_view(&player_rack_demo_view())
155}
156
157/// Shell demo with keyboard input feeding a rack and piano roll.
158pub fn performance_workbench_demo_scene() -> Expr {
159    node(
160        "stack",
161        vec![
162            ("role", sym("performance-workbench")),
163            ("dir", sym("column")),
164            (
165                "children",
166                list(vec![
167                    performance_keyboard_demo_scene(),
168                    player_rack_demo_scene(),
169                    piano_roll_demo_scene(),
170                ]),
171            ),
172        ],
173    )
174}
175
176fn player_rack_device_expr(device: &PlayerRackDevice) -> Expr {
177    data_map(vec![
178        ("id", Expr::Symbol(device.id.clone())),
179        ("label", text(device.label.clone())),
180        ("player-kind", Expr::Symbol(device.player_kind.clone())),
181        ("order", uint(device.order)),
182        ("bypassed", Expr::Bool(device.bypassed)),
183        ("direct-record", Expr::Bool(device.direct_record)),
184        ("frozen", Expr::Bool(device.frozen)),
185        ("trace", Expr::Bool(device.trace)),
186        ("route", Expr::Symbol(device.route.clone())),
187        ("placement-hint", text(device.placement_hint.clone())),
188    ])
189}