1use crate::{
2 keyboard::KeyEvent,
3 music::{self, Note},
4 signal::{Sf64, Signal, SignalCtx},
5};
6pub use midly::{
7 num::{u14, u4, u7},
8 MidiMessage,
9};
10use midly::{MetaMessage, PitchBend, Timing, TrackEvent, TrackEventKind};
11use std::{
12 cell::{Cell, RefCell},
13 rc::Rc,
14};
15
16#[derive(Debug, Clone, Copy)]
17pub struct MidiEvent {
18 pub channel: u4,
19 pub message: MidiMessage,
20}
21
22#[derive(Debug, Clone, Default)]
23pub struct MidiEvents {
24 events: Vec<MidiEvent>,
25}
26
27impl MidiEvents {
28 fn add(&mut self, midi_event: MidiEvent) {
29 self.events.push(midi_event);
30 }
31
32 pub fn for_each_event<F: FnMut(MidiEvent)>(&self, f: F) {
33 self.events.iter().cloned().for_each(f)
34 }
35
36 pub fn for_each_message_on_channel<F: FnMut(MidiMessage)>(&self, channel: u8, mut f: F) {
37 self.for_each_event(|event| {
38 if event.channel.as_int() == channel {
39 f(event.message);
40 }
41 })
42 }
43
44 pub fn filter_channel(&self, channel: u8) -> MidiMessages {
45 let mut midi_messages = MidiMessages::default();
46 self.for_each_message_on_channel(channel, |message| midi_messages.add(message));
47 midi_messages
48 }
49}
50
51#[derive(Debug, Clone, Default)]
52pub struct MidiMessages {
53 messages: Vec<MidiMessage>,
54}
55
56impl MidiMessages {
57 fn add(&mut self, midi_message: MidiMessage) {
58 self.messages.push(midi_message);
59 }
60
61 pub fn for_each<F: FnMut(MidiMessage)>(&self, f: F) {
62 self.messages.iter().cloned().for_each(f)
63 }
64}
65
66fn u7_to_01(u7: u7) -> f64 {
67 u7.as_int() as f64 / 127.0
68}
69
70fn signal_u7_to_01(s: &Signal<u7>) -> Sf64 {
71 s.map(u7_to_01)
72}
73
74pub struct MidiControllerTableRaw {
75 values: Vec<Signal<u7>>,
76}
77
78#[derive(Clone)]
79pub struct MidiControllerTable {
80 values_01: Vec<Sf64>,
81}
82
83impl MidiControllerTableRaw {
84 pub fn get(&self, i: u8) -> Signal<u7> {
85 self.values[i as usize].clone()
86 }
87
88 pub fn to_controller_table(&self) -> MidiControllerTable {
89 MidiControllerTable {
90 values_01: self.values.iter().map(signal_u7_to_01).collect(),
91 }
92 }
93}
94
95impl MidiControllerTable {
96 pub fn get_01(&self, i: u8) -> Sf64 {
97 self.values_01[i as usize].clone()
98 }
99
100 pub fn volume(&self) -> Sf64 {
101 self.get_01(7)
102 }
103
104 pub fn modulation(&self) -> Sf64 {
105 self.get_01(1)
106 }
107}
108
109pub trait MidiEventSource {
111 fn for_each_new_event<F>(&mut self, ctx: &SignalCtx, f: F)
112 where
113 F: FnMut(MidiEvent);
114}
115
116pub struct TrackEventSource {
117 track: Vec<TrackEvent<'static>>,
118 timing: Timing,
119 tick_duration_s: f64,
120 next_index: usize,
121 next_tick: u32,
122 current_time_s: f64,
123 next_tick_time_s: f64,
124}
125
126impl TrackEventSource {
127 pub fn new<'a>(track: &[TrackEvent<'a>], timing: Timing, default_s_per_beat: f64) -> Self {
128 let track = track
129 .into_iter()
130 .map(|event| event.to_static())
131 .collect::<Vec<_>>();
132 let tick_duration_s = match timing {
133 Timing::Metrical(ticks_per_beat) => {
134 default_s_per_beat / (ticks_per_beat.as_int() as f64)
135 }
136 Timing::Timecode(frames_per_second, ticks_per_frame) => {
137 1.0 / (frames_per_second.as_f32() as f64 * ticks_per_frame as f64)
138 }
139 };
140 Self {
141 track,
142 timing,
143 tick_duration_s,
144 next_index: 0,
145 next_tick: 0,
146 current_time_s: 0.0,
147 next_tick_time_s: 0.0,
148 }
149 }
150}
151
152impl MidiEventSource for TrackEventSource {
153 fn for_each_new_event<F>(&mut self, ctx: &SignalCtx, mut f: F)
154 where
155 F: FnMut(MidiEvent),
156 {
157 let time_since_prev_tick_s = 1.0 / ctx.sample_rate_hz;
158 self.current_time_s += time_since_prev_tick_s;
159 while self.next_tick_time_s < self.current_time_s {
160 self.next_tick_time_s += self.tick_duration_s;
161 while let Some(event) = self.track.get(self.next_index) {
162 let tick = self.next_tick;
163 if event.delta == tick {
164 self.next_tick = 0;
165 self.next_index += 1;
166 match event.kind {
167 TrackEventKind::Midi { channel, message } => {
168 f(MidiEvent { channel, message })
169 }
170 TrackEventKind::Meta(MetaMessage::Tempo(us_per_beat)) => {
171 if let Timing::Metrical(ticks_per_beat) = self.timing {
172 self.tick_duration_s = us_per_beat.as_int() as f64
173 / (ticks_per_beat.as_int() as f64 * 1_000_000.0);
174 }
175 }
176 _ => (),
177 }
178 } else {
179 break;
180 }
181 }
182 self.next_tick += 1;
183 }
184 }
185}
186
187pub fn event_source_to_signal(event_source: impl MidiEventSource + 'static) -> Signal<MidiEvents> {
188 let event_source = RefCell::new(event_source);
189 Signal::from_fn(move |ctx| {
190 let mut midi_events = MidiEvents::default();
191 event_source
192 .borrow_mut()
193 .for_each_new_event(ctx, |midi_event| midi_events.add(midi_event));
194 midi_events
195 })
196}
197
198impl Signal<MidiEvents> {
199 pub fn filter_channel(&self, channel: u8) -> Signal<MidiMessages> {
200 self.map(move |events| events.filter_channel(channel))
201 }
202}
203
204pub fn event_source_to_signal_single_channel(
205 event_source: impl MidiEventSource + 'static,
206 channel: u8,
207) -> Signal<MidiMessages> {
208 let event_source = RefCell::new(event_source);
209 Signal::from_fn(move |ctx| {
210 let mut midi_messages = MidiMessages::default();
211 event_source
212 .borrow_mut()
213 .for_each_new_event(ctx, |midi_event| {
214 if midi_event.channel == channel {
215 midi_messages.add(midi_event.message);
216 }
217 });
218 midi_messages
219 })
220}
221
222fn midi_note_message_to_key_event(key: u7, vel: u7, pressed: bool) -> KeyEvent {
223 KeyEvent {
224 note: Note::from_midi_index(key),
225 velocity_01: u7_to_01(vel),
226 pressed,
227 }
228}
229
230fn midi_pitch_bend_to_pitch_bend_multiplier_hz(midi_pitch_bend: u14) -> f64 {
231 music::TONE_RATIO
232 .powf(((midi_pitch_bend.as_int() as i32 - 0x2000) as f64 * 2.0) / 0x3FFF as f64)
233}
234
235impl Signal<MidiMessages> {
236 pub fn key_events(&self) -> Signal<Vec<KeyEvent>> {
237 self.map(|messages| {
238 let mut ret = Vec::new();
239 messages.for_each(|message| match message {
240 MidiMessage::NoteOn { key, vel } => {
241 ret.push(midi_note_message_to_key_event(key, vel, true))
242 }
243 MidiMessage::NoteOff { key, vel } => {
244 ret.push(midi_note_message_to_key_event(key, vel, false))
245 }
246 _ => (),
247 });
248 ret
249 })
250 }
251
252 pub fn pitch_bend_multiplier_hz(&self) -> Sf64 {
253 let state = Rc::new(Cell::new(1.0));
254 self.map({
255 let state = Rc::clone(&state);
256 move |messages| {
257 messages.for_each(|message| match message {
258 MidiMessage::PitchBend {
259 bend: PitchBend(pitch_bend),
260 } => state.set(midi_pitch_bend_to_pitch_bend_multiplier_hz(pitch_bend)),
261 _ => (),
262 });
263 }
264 })
265 .then({
266 let state = Rc::clone(&state);
267 move || state.get()
268 })
269 }
270
271 pub fn controller_table(&self) -> MidiControllerTable {
272 let table = Rc::new(RefCell::new(vec![0.0; 128]));
273 let update_table = Signal::from_fn({
274 let table = Rc::clone(&table);
275 let signal = self.clone();
276 move |ctx| {
277 let mut table = table.borrow_mut();
278 signal.sample(ctx).for_each(|message| match message {
279 MidiMessage::Controller { controller, value } => {
280 table[controller.as_int() as usize] = value.as_int() as f64 / 127.0;
281 }
282 _ => (),
283 });
284 }
285 });
286 MidiControllerTable {
287 values_01: (0..128)
288 .map(|i| {
289 update_table.map({
290 let table = Rc::clone(&table);
291 move |()| table.borrow()[i]
292 })
293 })
294 .collect(),
295 }
296 }
297}