Skip to main content

sim_lib_midi_live/
session.rs

1use std::convert::Infallible;
2
3use sim_lib_midi_core::{MidiEvent, MidiSink, MidiSource};
4
5use crate::{LiveMidiError, RingMidiBuffer};
6
7const DEFAULT_TPQ: u32 = 480;
8const DEFAULT_CAPACITY: usize = 1024;
9
10/// Direction exposed by a live MIDI session.
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub enum LiveMidiDirection {
13    /// Session produces MIDI events.
14    Source,
15    /// Session consumes MIDI events.
16    Sink,
17    /// Session both produces and consumes MIDI events.
18    Duplex,
19}
20
21impl LiveMidiDirection {
22    fn sink_enabled(self) -> bool {
23        matches!(self, Self::Sink | Self::Duplex)
24    }
25}
26
27/// Public handle for an active live MIDI stream.
28///
29/// The handle owns the bounded live ring used by host callbacks. Callback-side
30/// entry points enqueue into the ring only; evaluation code consumes the ring
31/// through the [`MidiSource`] and [`MidiSink`] accessors.
32#[derive(Debug)]
33pub struct LiveMidiSession {
34    ring: RingMidiBuffer,
35    direction: LiveMidiDirection,
36}
37
38impl LiveMidiSession {
39    /// Creates a modeled session with the default MIDI tick resolution and ring
40    /// capacity.
41    pub fn modeled(direction: LiveMidiDirection) -> Result<Self, LiveMidiError> {
42        Self::with_ring(DEFAULT_TPQ, DEFAULT_CAPACITY, direction)
43    }
44
45    /// Creates a session backed by a bounded ring buffer.
46    pub fn with_ring(
47        tpq: u32,
48        capacity: usize,
49        direction: LiveMidiDirection,
50    ) -> Result<Self, LiveMidiError> {
51        Ok(Self {
52            ring: RingMidiBuffer::new(tpq, capacity)?,
53            direction,
54        })
55    }
56
57    /// Returns the stream direction exposed by this session.
58    pub fn direction(&self) -> LiveMidiDirection {
59        self.direction
60    }
61
62    /// Returns the live source side.
63    pub fn source_mut(&mut self) -> &mut dyn MidiSource<Err = Infallible> {
64        &mut self.ring
65    }
66
67    /// Returns the live sink side when the session supports output.
68    pub fn sink_mut(&mut self) -> Option<&mut dyn MidiSink<Err = Infallible>> {
69        if self.direction.sink_enabled() {
70            Some(&mut self.ring)
71        } else {
72            None
73        }
74    }
75
76    /// Enqueues one event from a host callback into the bounded live ring.
77    pub fn enqueue_from_callback(&mut self, event: &MidiEvent) -> Result<(), Infallible> {
78        self.ring.write(event)
79    }
80
81    /// Closes the session.
82    pub fn close(self) -> Result<(), LiveMidiError> {
83        Ok(())
84    }
85}