1use sim_kernel::Expr;
4use sim_lib_music_synth::{
5 INSTRUMENT_EDITOR_DESCRIPTORS, InstrumentEditorDescriptor, SYSTEM700_EDITOR_FIXTURE_NAMES,
6 SYSTEM700_EDITOR_ROUTE_NAME, SYSTEM700_EDITOR_VIEW_ID,
7};
8use sim_lib_scene::{node, sym};
9
10use crate::instrument::{action, editor_root, graph, number, row, slider, table, validation_panel};
11
12pub const SYSTEM700_EDITOR_ROUTE: &str = SYSTEM700_EDITOR_ROUTE_NAME;
14pub const SYSTEM700_EDITOR_VIEW: &str = SYSTEM700_EDITOR_VIEW_ID;
16
17pub fn system700_editor_fixture_names() -> &'static [&'static str] {
19 &SYSTEM700_EDITOR_FIXTURE_NAMES
20}
21
22pub fn system700_editor_snapshot(name: &str) -> Option<Expr> {
24 SYSTEM700_EDITOR_FIXTURE_NAMES
25 .contains(&name)
26 .then(|| system700_editor_view(name))
27}
28
29pub fn system700_editor_view(fixture_name: &str) -> Expr {
31 let invalid = fixture_name == SYSTEM700_EDITOR_FIXTURE_NAMES[2];
32 let empty = fixture_name == SYSTEM700_EDITOR_FIXTURE_NAMES[1];
33 let representative = fixture_name == SYSTEM700_EDITOR_FIXTURE_NAMES[3];
34 let mut children = vec![
35 action("patch-load", "load-patch", "Load patch"),
36 panel_modules(empty, representative),
37 panel_graph(empty, representative),
38 cord_editor(empty, representative),
39 trace_panel(),
40 ];
41 if invalid {
42 children.push(validation_panel("missing-vco-output", "r700-vco-1"));
43 children.push(validation_panel("unpatched-audio-out", "main-out"));
44 }
45 editor_root(
46 descriptor(),
47 "system700-panel-editor",
48 fixture_name,
49 children,
50 )
51}
52
53fn descriptor() -> &'static InstrumentEditorDescriptor {
54 INSTRUMENT_EDITOR_DESCRIPTORS
55 .iter()
56 .find(|descriptor| descriptor.instrument == "system700")
57 .expect("System 700 editor descriptor")
58}
59
60fn panel_modules(empty: bool, representative: bool) -> Expr {
61 let rows = if empty {
62 Vec::new()
63 } else {
64 let mut rows = vec![
65 module_row("r700-vco-1", "vco", 2.0),
66 module_row("r700-vcf", "filter", 1.0),
67 module_row("r700-vca", "amplifier", 1.0),
68 module_row("r700-envelope", "envelope", 2.0),
69 module_row("r700-mixer", "mixer", 1.0),
70 ];
71 if representative {
72 rows.push(module_row("r700-sequencer", "sequencer", 1.0));
73 rows.push(module_row("r700-clock", "clock", 1.0));
74 }
75 rows
76 };
77 table("modular-patch-panel", rows)
78}
79
80fn panel_graph(empty: bool, representative: bool) -> Expr {
81 if empty {
82 return graph("system700-panel-graph", &[], &[]);
83 }
84 let mut nodes = vec!["r700-vco-1", "r700-vcf", "r700-vca", "r700-envelope", "out"];
85 let mut edges = vec![
86 ("r700-vco-1", "r700-vcf"),
87 ("r700-vcf", "r700-vca"),
88 ("r700-vca", "out"),
89 ("r700-envelope", "r700-vca"),
90 ];
91 if representative {
92 nodes.extend(["r700-sequencer", "r700-clock"]);
93 edges.push(("r700-clock", "r700-sequencer"));
94 edges.push(("r700-sequencer", "r700-vco-1"));
95 }
96 graph("system700-panel-graph", &nodes, &edges)
97}
98
99fn cord_editor(empty: bool, representative: bool) -> Expr {
100 let rows = if empty {
101 Vec::new()
102 } else {
103 let mut rows = vec![
104 cord_row("r700-vco-1.audio", "r700-vcf.audio-in"),
105 cord_row("r700-vcf.audio", "r700-vca.audio-in"),
106 cord_row("r700-envelope.cv", "r700-vca.cv"),
107 ];
108 if representative {
109 rows.push(cord_row("r700-sequencer.cv", "r700-vco-1.pitch"));
110 }
111 rows
112 };
113 table("cord-editor", rows)
114}
115
116fn trace_panel() -> Expr {
117 node(
118 "stack",
119 vec![
120 ("role", sym("system700-trace-view")),
121 ("dir", sym("row")),
122 (
123 "children",
124 Expr::List(vec![
125 slider("cv-trace", "sequencer-cv", -5.0, 5.0, 1.2),
126 slider("gate-trace", "gate-width", 0.0, 1.0, 0.5),
127 ]),
128 ),
129 ],
130 )
131}
132
133fn module_row(id: &str, role: &str, count: f64) -> Expr {
134 row(vec![
135 ("module", Expr::String(id.to_owned())),
136 ("role", Expr::String(role.to_owned())),
137 ("count", number(count)),
138 ])
139}
140
141fn cord_row(from: &str, to: &str) -> Expr {
142 row(vec![
143 ("from", Expr::String(from.to_owned())),
144 ("to", Expr::String(to.to_owned())),
145 ])
146}