Skip to main content

sim_lib_view_daw/
system700.rs

1//! Roland System 700 instrument editor scenes.
2
3use 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
12/// Roland System 700 editor route name.
13pub const SYSTEM700_EDITOR_ROUTE: &str = SYSTEM700_EDITOR_ROUTE_NAME;
14/// Roland System 700 editor view id.
15pub const SYSTEM700_EDITOR_VIEW: &str = SYSTEM700_EDITOR_VIEW_ID;
16
17/// Return Roland System 700 editor fixture names.
18pub fn system700_editor_fixture_names() -> &'static [&'static str] {
19    &SYSTEM700_EDITOR_FIXTURE_NAMES
20}
21
22/// Build a deterministic Roland System 700 editor snapshot.
23pub fn system700_editor_snapshot(name: &str) -> Option<Expr> {
24    SYSTEM700_EDITOR_FIXTURE_NAMES
25        .contains(&name)
26        .then(|| system700_editor_view(name))
27}
28
29/// Build the Roland System 700 panel editor view.
30pub 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}