caw_midi/
lib.rs

1use caw_core::{sig_shared, Buf, Sig, SigCtx, SigShared, SigT};
2use caw_keyboard::{KeyEvent, KeyEvents, Note, TONE_RATIO};
3use midly::{num::u7, MidiMessage};
4use smallvec::{smallvec, SmallVec};
5
6fn u7_to_01(u7: u7) -> f32 {
7    u7.as_int() as f32 / 127.0
8}
9
10fn midi_note_message_to_key_event(key: u7, vel: u7, pressed: bool) -> KeyEvent {
11    KeyEvent {
12        note: Note::from_midi_index(key),
13        velocity_01: u7_to_01(vel),
14        pressed,
15    }
16}
17
18fn midi_message_to_key_event(midi_message: MidiMessage) -> Option<KeyEvent> {
19    match midi_message {
20        MidiMessage::NoteOn { key, vel } => {
21            Some(midi_note_message_to_key_event(key, vel, true))
22        }
23        MidiMessage::NoteOff { key, vel } => {
24            Some(midi_note_message_to_key_event(key, vel, false))
25        }
26        _ => None,
27    }
28}
29
30/// A collection of simultaneous midi events. When dealing with streams of midi events it's
31/// necessary to group them into a collection because multiple midi events may occur during the
32/// same frame. This collection only uses the heap when more than one event occurred on the same
33/// sample which is very unlikely.
34#[derive(Clone, Debug, Default)]
35pub struct MidiMessages(SmallVec<[MidiMessage; 1]>);
36
37impl MidiMessages {
38    pub fn empty() -> Self {
39        Self(smallvec![])
40    }
41
42    pub fn push(&mut self, midi_event: MidiMessage) {
43        self.0.push(midi_event);
44    }
45
46    pub fn iter(&self) -> impl Iterator<Item = &MidiMessage> {
47        self.0.iter()
48    }
49
50    pub fn key_events(&self) -> KeyEvents {
51        self.iter()
52            .cloned()
53            .filter_map(midi_message_to_key_event)
54            .collect()
55    }
56}
57
58impl IntoIterator for MidiMessages {
59    type Item = MidiMessage;
60
61    type IntoIter = smallvec::IntoIter<[MidiMessage; 1]>;
62
63    fn into_iter(self) -> Self::IntoIter {
64        self.0.into_iter()
65    }
66}
67
68#[derive(Clone)]
69pub struct MidiControllers<M>
70where
71    M: SigT<Item = MidiMessages>,
72{
73    messages: Sig<SigShared<M>>,
74}
75
76pub struct MidiController01<M>
77where
78    M: SigT<Item = MidiMessages>,
79{
80    index: u7,
81    state: f32,
82    messages: SigShared<M>,
83    buf: Vec<f32>,
84}
85
86impl<M> SigT for MidiController01<M>
87where
88    M: SigT<Item = MidiMessages>,
89{
90    type Item = f32;
91
92    fn sample(&mut self, ctx: &SigCtx) -> impl Buf<Self::Item> {
93        self.buf.resize(ctx.num_samples, 0.0);
94        let messages = self.messages.sample(ctx);
95        for (out, messages) in self.buf.iter_mut().zip(messages.iter()) {
96            for message in messages {
97                if let MidiMessage::Controller { controller, value } = message {
98                    if controller == self.index {
99                        self.state = value.as_int() as f32 / 127.0;
100                    }
101                }
102            }
103            *out = self.state;
104        }
105        &self.buf
106    }
107}
108
109impl<M> MidiControllers<M>
110where
111    M: SigT<Item = MidiMessages>,
112{
113    pub fn get_with_initial_value_01(
114        &self,
115        index: u8,
116        initial_value: f32,
117    ) -> Sig<MidiController01<M>> {
118        Sig(MidiController01 {
119            index: index.into(),
120            state: initial_value.clamp(0., 1.),
121            messages: self.messages.clone().0,
122            buf: Vec::new(),
123        })
124    }
125
126    pub fn get_01(&self, index: u8) -> Sig<MidiController01<M>> {
127        self.get_with_initial_value_01(index, 0.0)
128    }
129
130    pub fn volume(&self) -> Sig<MidiController01<M>> {
131        self.get_01(7)
132    }
133
134    pub fn modulation(&self) -> Sig<MidiController01<M>> {
135        self.get_01(1)
136    }
137}
138
139pub trait MidiMessagesT<M>
140where
141    M: SigT<Item = MidiMessages>,
142{
143    fn key_events(self) -> Sig<impl SigT<Item = KeyEvents>>;
144
145    /// The pitch bend value interpolated between -1 and 1
146    fn pitch_bend_raw(self) -> Sig<impl SigT<Item = f32>>;
147
148    /// The pitch bend value as a value that can be multiplied by a frequence to scale it up or
149    /// down by at most one tone.
150    fn pitch_bend_freq_mult(self) -> Sig<impl SigT<Item = f32>>;
151
152    fn controllers(self) -> MidiControllers<M>;
153}
154
155impl<M> MidiMessagesT<M> for Sig<M>
156where
157    M: SigT<Item = MidiMessages>,
158{
159    fn key_events(self) -> Sig<impl SigT<Item = KeyEvents>> {
160        self.map(|midi_messages| midi_messages.key_events())
161    }
162
163    fn pitch_bend_raw(self) -> Sig<impl SigT<Item = f32>> {
164        let mut state = 0.0;
165        self.map_mut(move |midi_messages| {
166            for midi_message in midi_messages {
167                if let MidiMessage::PitchBend { bend } = midi_message {
168                    state = bend.as_f32();
169                }
170            }
171            state
172        })
173    }
174
175    fn pitch_bend_freq_mult(self) -> Sig<impl SigT<Item = f32>> {
176        self.pitch_bend_raw().map(|bend| TONE_RATIO.powf(bend))
177    }
178
179    fn controllers(self) -> MidiControllers<M> {
180        MidiControllers {
181            messages: sig_shared(self.0),
182        }
183    }
184}