Skip to main content

sim_lib_sound_bridge/
runtime.rs

1use sim_kernel::{
2    AbiVersion, Cx, Export, ExportKind, ExportRecord, ExportState, Lib, LibManifest, LibTarget,
3    Linker, Result, RuntimeId, Symbol, Version,
4};
5
6const SOUND_BRIDGE_LIB_ID: &str = "sound-bridge";
7const BRIDGE_EXPORT_KIND: &str = "Bridge";
8const REGISTRY_SYMBOL_NAME: &str = "BridgeRegistry";
9
10/// Host-registered lib exporting the MIDI-to-sound bridge cards and registry.
11pub struct SoundBridgeLib;
12
13impl Lib for SoundBridgeLib {
14    fn manifest(&self) -> LibManifest {
15        LibManifest {
16            id: Symbol::new(SOUND_BRIDGE_LIB_ID),
17            version: Version(env!("CARGO_PKG_VERSION").to_owned()),
18            abi: AbiVersion { major: 0, minor: 1 },
19            target: LibTarget::HostRegistered,
20            requires: Vec::new(),
21            capabilities: Vec::new(),
22            exports: bridge_symbols()
23                .into_iter()
24                .chain(std::iter::once(registry_symbol()))
25                .map(|symbol| Export::Value { symbol })
26                .collect(),
27        }
28    }
29
30    fn load(&self, cx: &mut sim_kernel::LoadCx, linker: &mut Linker<'_>) -> Result<()> {
31        for symbol in bridge_symbols() {
32            linker.value(symbol.clone(), bridge_value(cx, symbol.clone())?)?;
33        }
34        linker.value(registry_symbol(), registry_value(cx)?)?;
35        Ok(())
36    }
37}
38
39/// Installs the sound-bridge lib into `cx`, registering the bridge cards and
40/// registry export records (idempotent).
41pub fn install_sound_bridge_lib(cx: &mut Cx) -> Result<()> {
42    let lib = Symbol::new(SOUND_BRIDGE_LIB_ID);
43    if !sim_lib_core::install_once(cx, &SoundBridgeLib)? {
44        return Ok(());
45    }
46    for symbol in bridge_symbols() {
47        cx.registry_mut().append_export_record(
48            &lib,
49            ExportRecord {
50                kind: ExportKind::named(BRIDGE_EXPORT_KIND),
51                symbol,
52                state: ExportState::Resolved {
53                    id: RuntimeId::Value,
54                },
55            },
56        )?;
57    }
58    Ok(())
59}
60
61fn bridge_symbols() -> Vec<Symbol> {
62    vec![
63        Symbol::qualified("sound", "MidiToSoundBridge"),
64        Symbol::qualified("sound", "VoicePool"),
65        Symbol::qualified("sound", "TimbreBank"),
66    ]
67}
68
69fn registry_symbol() -> Symbol {
70    Symbol::qualified("sound", REGISTRY_SYMBOL_NAME)
71}
72
73fn registry_value(cx: &mut sim_kernel::LoadCx) -> Result<sim_kernel::Value> {
74    let bridges = cx.factory().list(
75        bridge_symbols()
76            .into_iter()
77            .map(|symbol| cx.factory().symbol(symbol))
78            .collect::<Result<Vec<_>>>()?,
79    )?;
80    cx.factory().table(vec![
81        (
82            Symbol::new("symbol"),
83            cx.factory().symbol(registry_symbol())?,
84        ),
85        (
86            Symbol::new("layer"),
87            cx.factory().string("sound".to_owned())?,
88        ),
89        (
90            Symbol::new("kind"),
91            cx.factory().string("bridge".to_owned())?,
92        ),
93        (
94            Symbol::new("shape"),
95            cx.factory()
96                .symbol(Symbol::qualified("sound", "MidiToSoundBridge"))?,
97        ),
98        (Symbol::new("dependencies"), cx.factory().list(Vec::new())?),
99        (Symbol::new("lossless"), cx.factory().bool(false)?),
100        (Symbol::new("capabilities"), cx.factory().list(Vec::new())?),
101        (Symbol::new("bridges"), bridges),
102    ])
103}
104
105fn bridge_value(cx: &mut sim_kernel::LoadCx, symbol: Symbol) -> Result<sim_kernel::Value> {
106    let dependencies = match &*symbol.name {
107        "MidiToSoundBridge" => vec![
108            cx.factory().string("midi-core".to_owned())?,
109            cx.factory().string("sound-timbre".to_owned())?,
110            cx.factory().string("sound-tuning".to_owned())?,
111        ],
112        "VoicePool" => vec![cx.factory().string("sound-core".to_owned())?],
113        "TimbreBank" => vec![cx.factory().string("sound-timbre".to_owned())?],
114        _ => Vec::new(),
115    };
116    cx.factory().table(vec![
117        (Symbol::new("symbol"), cx.factory().symbol(symbol)?),
118        (
119            Symbol::new("layer"),
120            cx.factory().string("sound".to_owned())?,
121        ),
122        (
123            Symbol::new("kind"),
124            cx.factory().string("bridge".to_owned())?,
125        ),
126        (
127            Symbol::new("shape"),
128            cx.factory()
129                .symbol(Symbol::qualified("sound", "MidiToSoundBridge"))?,
130        ),
131        (
132            Symbol::new("dependencies"),
133            cx.factory().list(dependencies)?,
134        ),
135        (Symbol::new("lossless"), cx.factory().bool(false)?),
136        (Symbol::new("capabilities"), cx.factory().list(Vec::new())?),
137    ])
138}