Skip to main content

sim_lib_midi_core/
runtime.rs

1use sim_kernel::{
2    Cx, ExportKind, ExportRecord, ExportState, Lib, LibManifest, Linker, LoadCx, Result, RuntimeId,
3    Symbol,
4};
5use sim_lib_core::{SurfaceField, SurfacePackLib, SurfacePackSpec, SurfaceValueSpec, install_once};
6
7const MIDI_IO_LIB_ID: &str = "midi-io";
8const SOURCE_EXPORT_KIND: &str = "MidiSourceFactory";
9const SINK_EXPORT_KIND: &str = "MidiSinkFactory";
10const TRACKED_SOURCE_EXPORT_KIND: &str = "TrackedMidiSourceFactory";
11const REGISTRY_SYMBOL_NAME: &str = "MidiIoRegistry";
12
13/// Host-registered lib exporting the in-memory MIDI I/O cards and registry,
14/// built on the shared [`SurfacePackLib`] substrate.
15pub struct MidiIoLib;
16
17impl Lib for MidiIoLib {
18    fn manifest(&self) -> LibManifest {
19        midi_io_pack().manifest()
20    }
21
22    fn load(&self, cx: &mut LoadCx, linker: &mut Linker<'_>) -> Result<()> {
23        midi_io_pack().load(cx, linker)
24    }
25}
26
27/// Installs [`MidiIoLib`] into `cx` once and registers the in-memory source,
28/// sink, and tracked-source export records.
29///
30/// Returns `Ok(())` immediately if the lib is already installed.
31pub fn install_midi_io_lib(cx: &mut Cx) -> Result<()> {
32    if !install_once(cx, &MidiIoLib)? {
33        return Ok(());
34    }
35    let lib = Symbol::new(MIDI_IO_LIB_ID);
36    for symbol in source_symbols() {
37        cx.registry_mut().append_export_record(
38            &lib,
39            ExportRecord {
40                kind: ExportKind::named(SOURCE_EXPORT_KIND),
41                symbol,
42                state: ExportState::Resolved {
43                    id: RuntimeId::Value,
44                },
45            },
46        )?;
47    }
48    for symbol in sink_symbols() {
49        cx.registry_mut().append_export_record(
50            &lib,
51            ExportRecord {
52                kind: ExportKind::named(SINK_EXPORT_KIND),
53                symbol,
54                state: ExportState::Resolved {
55                    id: RuntimeId::Value,
56                },
57            },
58        )?;
59    }
60    for symbol in tracked_source_symbols() {
61        cx.registry_mut().append_export_record(
62            &lib,
63            ExportRecord {
64                kind: ExportKind::named(TRACKED_SOURCE_EXPORT_KIND),
65                symbol,
66                state: ExportState::Resolved {
67                    id: RuntimeId::Value,
68                },
69            },
70        )?;
71    }
72    Ok(())
73}
74
75fn source_symbols() -> Vec<Symbol> {
76    vec![Symbol::qualified("midi", "MemoryMidiSource")]
77}
78
79fn sink_symbols() -> Vec<Symbol> {
80    vec![Symbol::qualified("midi", "MemoryMidiSink")]
81}
82
83fn tracked_source_symbols() -> Vec<Symbol> {
84    vec![Symbol::qualified("midi", "MemoryTrackedMidiSource")]
85}
86
87fn io_symbols() -> Vec<Symbol> {
88    let mut symbols = source_symbols();
89    symbols.extend(sink_symbols());
90    symbols.extend(tracked_source_symbols());
91    symbols
92}
93
94fn registry_symbol() -> Symbol {
95    Symbol::qualified("midi", REGISTRY_SYMBOL_NAME)
96}
97
98fn io_value_spec(symbol: Symbol) -> SurfaceValueSpec {
99    let (shape, mode) = match symbol.name.as_ref() {
100        "MemoryMidiSource" => (
101            Symbol::qualified("midi", "MidiSourceFactory"),
102            "in-memory source",
103        ),
104        "MemoryMidiSink" => (
105            Symbol::qualified("midi", "MidiSinkFactory"),
106            "in-memory sink",
107        ),
108        "MemoryTrackedMidiSource" => (
109            Symbol::qualified("midi", "TrackedMidiSourceFactory"),
110            "in-memory tracked source",
111        ),
112        _ => (Symbol::qualified("midi", "MidiSourceFactory"), "unknown"),
113    };
114    SurfaceValueSpec {
115        symbol: symbol.clone(),
116        fields: vec![
117            (Symbol::new("symbol"), SurfaceField::Symbol(symbol)),
118            (Symbol::new("layer"), SurfaceField::Str("midi".to_owned())),
119            (Symbol::new("kind"), SurfaceField::Str("plugin".to_owned())),
120            (Symbol::new("shape"), SurfaceField::Symbol(shape)),
121            (
122                Symbol::new("dependencies"),
123                SurfaceField::Strs(vec!["midi-core".to_owned()]),
124            ),
125            (Symbol::new("lossless"), SurfaceField::Bool(true)),
126            (Symbol::new("capabilities"), SurfaceField::Symbols(vec![])),
127            (Symbol::new("mode"), SurfaceField::Str(mode.to_owned())),
128        ],
129    }
130}
131
132fn registry_value_spec() -> SurfaceValueSpec {
133    SurfaceValueSpec {
134        symbol: registry_symbol(),
135        fields: vec![
136            (
137                Symbol::new("symbol"),
138                SurfaceField::Symbol(registry_symbol()),
139            ),
140            (Symbol::new("layer"), SurfaceField::Str("midi".to_owned())),
141            (Symbol::new("kind"), SurfaceField::Str("plugin".to_owned())),
142            (
143                Symbol::new("shape"),
144                SurfaceField::Symbol(Symbol::qualified("midi", "MidiSourceFactory")),
145            ),
146            (Symbol::new("dependencies"), SurfaceField::Symbols(vec![])),
147            (Symbol::new("lossless"), SurfaceField::Bool(true)),
148            (Symbol::new("capabilities"), SurfaceField::Symbols(vec![])),
149            (
150                Symbol::new("sources"),
151                SurfaceField::Symbols(source_symbols()),
152            ),
153            (Symbol::new("sinks"), SurfaceField::Symbols(sink_symbols())),
154            (
155                Symbol::new("tracked-sources"),
156                SurfaceField::Symbols(tracked_source_symbols()),
157            ),
158        ],
159    }
160}
161
162fn midi_io_pack() -> SurfacePackLib {
163    let mut values: Vec<SurfaceValueSpec> = io_symbols().into_iter().map(io_value_spec).collect();
164    values.push(registry_value_spec());
165    SurfacePackLib {
166        spec: SurfacePackSpec {
167            lib_id: Symbol::new(MIDI_IO_LIB_ID),
168            values,
169        },
170    }
171}