use std::convert::Infallible;
use sim_kernel::{Error, Result, Symbol};
use sim_lib_midi_core::{MidiSink, MidiSource};
use sim_lib_midi_live::{LiveMidiDirection, LiveMidiError, LiveMidiSession};
use crate::eval_site::StreamEvalSite;
use crate::placement::{DeviceDirection, DeviceKind, DeviceRecord, Placement};
pub struct MidiLiveEvalSite {
record: DeviceRecord,
session: LiveMidiSession,
site: Box<dyn StreamEvalSite>,
}
impl MidiLiveEvalSite {
pub fn from_eval_site(id: &Symbol, site: Box<dyn StreamEvalSite>) -> Result<Self> {
let record = site.device_record().clone();
if record.kind != DeviceKind::Midi {
site.close()?;
return Err(Error::Eval(format!("open_live: device '{id}' is not MIDI")));
}
let direction = live_direction(record.direction);
let session = LiveMidiSession::modeled(direction).map_err(live_error)?;
Ok(Self {
record,
session,
site,
})
}
pub fn source_mut(&mut self) -> &mut dyn MidiSource<Err = Infallible> {
self.session.source_mut()
}
pub fn sink_mut(&mut self) -> Option<&mut dyn MidiSink<Err = Infallible>> {
self.session.sink_mut()
}
}
impl StreamEvalSite for MidiLiveEvalSite {
fn placement(&self) -> &Placement {
&self.record.placement
}
fn device_record(&self) -> &DeviceRecord {
&self.record
}
fn close(self: Box<Self>) -> Result<()> {
let Self { session, site, .. } = *self;
session.close().map_err(live_error)?;
site.close()
}
}
fn live_direction(direction: DeviceDirection) -> LiveMidiDirection {
match direction {
DeviceDirection::Input => LiveMidiDirection::Source,
DeviceDirection::Output => LiveMidiDirection::Sink,
DeviceDirection::Duplex => LiveMidiDirection::Duplex,
}
}
fn live_error(err: LiveMidiError) -> Error {
Error::Eval(format!("midi live: {err}"))
}