Skip to main content

sim_lib_stream_host/
midi_live_eval_site.rs

1//! Live MIDI stream evaluation-site adapter.
2
3use std::convert::Infallible;
4
5use sim_kernel::{Error, Result, Symbol};
6use sim_lib_midi_core::{MidiSink, MidiSource};
7use sim_lib_midi_live::{LiveMidiDirection, LiveMidiError, LiveMidiSession};
8
9use crate::eval_site::StreamEvalSite;
10use crate::placement::{DeviceDirection, DeviceKind, DeviceRecord, Placement};
11
12/// Live MIDI evaluation site opened from a cataloged device record.
13pub struct MidiLiveEvalSite {
14    record: DeviceRecord,
15    session: LiveMidiSession,
16    site: Box<dyn StreamEvalSite>,
17}
18
19impl MidiLiveEvalSite {
20    /// Wraps an opened catalog site in a live MIDI session.
21    pub fn from_eval_site(id: &Symbol, site: Box<dyn StreamEvalSite>) -> Result<Self> {
22        let record = site.device_record().clone();
23        if record.kind != DeviceKind::Midi {
24            site.close()?;
25            return Err(Error::Eval(format!("open_live: device '{id}' is not MIDI")));
26        }
27        let direction = live_direction(record.direction);
28        let session = LiveMidiSession::modeled(direction).map_err(live_error)?;
29        Ok(Self {
30            record,
31            session,
32            site,
33        })
34    }
35
36    /// Returns the live MIDI source side.
37    pub fn source_mut(&mut self) -> &mut dyn MidiSource<Err = Infallible> {
38        self.session.source_mut()
39    }
40
41    /// Returns the live MIDI sink side when this site supports output.
42    pub fn sink_mut(&mut self) -> Option<&mut dyn MidiSink<Err = Infallible>> {
43        self.session.sink_mut()
44    }
45}
46
47impl StreamEvalSite for MidiLiveEvalSite {
48    fn placement(&self) -> &Placement {
49        &self.record.placement
50    }
51
52    fn device_record(&self) -> &DeviceRecord {
53        &self.record
54    }
55
56    fn close(self: Box<Self>) -> Result<()> {
57        let Self { session, site, .. } = *self;
58        session.close().map_err(live_error)?;
59        site.close()
60    }
61}
62
63fn live_direction(direction: DeviceDirection) -> LiveMidiDirection {
64    match direction {
65        DeviceDirection::Input => LiveMidiDirection::Source,
66        DeviceDirection::Output => LiveMidiDirection::Sink,
67        DeviceDirection::Duplex => LiveMidiDirection::Duplex,
68    }
69}
70
71fn live_error(err: LiveMidiError) -> Error {
72    Error::Eval(format!("midi live: {err}"))
73}