1use sim_kernel::{
2 AbiVersion, Cx, Export, ExportKind, ExportRecord, ExportState, Lib, LibManifest, LibTarget,
3 Linker, Result, RuntimeId, Symbol, Version,
4};
5
6const MIDI_LIVE_LIB_ID: &str = "midi-live";
7const SOURCE_EXPORT_KIND: &str = "MidiSourceFactory";
8const SINK_EXPORT_KIND: &str = "MidiSinkFactory";
9const TRACKED_SOURCE_EXPORT_KIND: &str = "TrackedMidiSourceFactory";
10const REGISTRY_SYMBOL_NAME: &str = "MidiLiveRegistry";
11
12pub struct MidiLiveLib;
15
16impl Lib for MidiLiveLib {
17 fn manifest(&self) -> LibManifest {
18 LibManifest {
19 id: Symbol::new(MIDI_LIVE_LIB_ID),
20 version: Version(env!("CARGO_PKG_VERSION").to_owned()),
21 abi: AbiVersion { major: 0, minor: 1 },
22 target: LibTarget::HostRegistered,
23 requires: Vec::new(),
24 capabilities: Vec::new(),
25 exports: live_symbols()
26 .into_iter()
27 .chain(std::iter::once(registry_symbol()))
28 .map(|symbol| Export::Value { symbol })
29 .collect(),
30 }
31 }
32
33 fn load(&self, cx: &mut sim_kernel::LoadCx, linker: &mut Linker<'_>) -> Result<()> {
34 for symbol in live_symbols() {
35 linker.value(symbol.clone(), live_value(cx, symbol.clone())?)?;
36 }
37 linker.value(registry_symbol(), registry_value(cx)?)?;
38 Ok(())
39 }
40}
41
42pub fn install_midi_live_lib(cx: &mut Cx) -> Result<()> {
45 let lib = Symbol::new(MIDI_LIVE_LIB_ID);
46 if !sim_lib_core::install_once(cx, &MidiLiveLib)? {
47 return Ok(());
48 }
49 for symbol in source_symbols() {
50 cx.registry_mut().append_export_record(
51 &lib,
52 ExportRecord {
53 kind: ExportKind::named(SOURCE_EXPORT_KIND),
54 symbol,
55 state: ExportState::Resolved {
56 id: RuntimeId::Value,
57 },
58 },
59 )?;
60 }
61 for symbol in sink_symbols() {
62 cx.registry_mut().append_export_record(
63 &lib,
64 ExportRecord {
65 kind: ExportKind::named(SINK_EXPORT_KIND),
66 symbol,
67 state: ExportState::Resolved {
68 id: RuntimeId::Value,
69 },
70 },
71 )?;
72 }
73 for symbol in tracked_source_symbols() {
74 cx.registry_mut().append_export_record(
75 &lib,
76 ExportRecord {
77 kind: ExportKind::named(TRACKED_SOURCE_EXPORT_KIND),
78 symbol,
79 state: ExportState::Resolved {
80 id: RuntimeId::Value,
81 },
82 },
83 )?;
84 }
85 Ok(())
86}
87
88fn source_symbols() -> Vec<Symbol> {
89 vec![Symbol::qualified("midi", "RingMidiBuffer")]
90}
91
92fn sink_symbols() -> Vec<Symbol> {
93 vec![Symbol::qualified("midi", "RingMidiBuffer")]
94}
95
96fn tracked_source_symbols() -> Vec<Symbol> {
97 vec![Symbol::qualified("midi", "RingTrackedMidiBuffer")]
98}
99
100fn live_symbols() -> Vec<Symbol> {
101 vec![
102 Symbol::qualified("midi", "RingMidiBuffer"),
103 Symbol::qualified("midi", "RingTrackedMidiBuffer"),
104 ]
105}
106
107fn registry_symbol() -> Symbol {
108 Symbol::qualified("midi", REGISTRY_SYMBOL_NAME)
109}
110
111fn registry_value(cx: &mut sim_kernel::LoadCx) -> Result<sim_kernel::Value> {
112 let buffers = cx.factory().list(
113 live_symbols()
114 .into_iter()
115 .map(|symbol| cx.factory().symbol(symbol))
116 .collect::<Result<Vec<_>>>()?,
117 )?;
118 cx.factory().table(vec![
119 (
120 Symbol::new("symbol"),
121 cx.factory().symbol(registry_symbol())?,
122 ),
123 (
124 Symbol::new("layer"),
125 cx.factory().string("midi".to_owned())?,
126 ),
127 (
128 Symbol::new("kind"),
129 cx.factory().string("plugin".to_owned())?,
130 ),
131 (
132 Symbol::new("shape"),
133 cx.factory()
134 .symbol(Symbol::qualified("midi", "TrackedMidiSourceFactory"))?,
135 ),
136 (Symbol::new("dependencies"), cx.factory().list(Vec::new())?),
137 (Symbol::new("lossless"), cx.factory().bool(true)?),
138 (Symbol::new("capabilities"), cx.factory().list(Vec::new())?),
139 (Symbol::new("buffers"), buffers),
140 ])
141}
142
143fn live_value(cx: &mut sim_kernel::LoadCx, symbol: Symbol) -> Result<sim_kernel::Value> {
144 let (shape, role) = match symbol.name.as_ref() {
145 "RingMidiBuffer" => (
146 Symbol::qualified("midi", "MidiSinkFactory"),
147 "ring buffer source/sink",
148 ),
149 "RingTrackedMidiBuffer" => (
150 Symbol::qualified("midi", "TrackedMidiSourceFactory"),
151 "ring buffer tracked source",
152 ),
153 _ => (Symbol::qualified("midi", "MidiSourceFactory"), "unknown"),
154 };
155 cx.factory().table(vec![
156 (Symbol::new("symbol"), cx.factory().symbol(symbol)?),
157 (
158 Symbol::new("layer"),
159 cx.factory().string("midi".to_owned())?,
160 ),
161 (
162 Symbol::new("kind"),
163 cx.factory().string("plugin".to_owned())?,
164 ),
165 (Symbol::new("shape"), cx.factory().symbol(shape)?),
166 (
167 Symbol::new("dependencies"),
168 cx.factory().list(vec![
169 cx.factory().string("midi-core".to_owned())?,
170 cx.factory().string("midi-live".to_owned())?,
171 ])?,
172 ),
173 (Symbol::new("lossless"), cx.factory().bool(true)?),
174 (Symbol::new("capabilities"), cx.factory().list(Vec::new())?),
175 (Symbol::new("role"), cx.factory().string(role.to_owned())?),
176 ])
177}