From 7f255eaea89b838dc99c0f2a398e669caa06576a Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sat, 10 May 2025 20:45:18 +0300 Subject: [PATCH] refactor audio.rs --- crates/app/src/audio.rs | 129 +++++++++++----------- crates/app/src/model/track.rs | 2 +- crates/device/src/sampler/sampler_midi.rs | 24 ++++ crates/engine/src/midi.rs | 1 + 4 files changed, 88 insertions(+), 68 deletions(-) diff --git a/crates/app/src/audio.rs b/crates/app/src/audio.rs index 0081d093..39d23f13 100644 --- a/crates/app/src/audio.rs +++ b/crates/app/src/audio.rs @@ -1,76 +1,14 @@ use crate::*; -impl HasJack for App { fn jack (&self) -> &Jack { &self.jack } } + audio!( |self: App, client, scope|{ - - // Start profiling cycle let t0 = self.perf.get_t0(); - - // Update transport clock self.clock().update_from_scope(scope).unwrap(); - - // Collect MIDI input (TODO preallocate large buffers) - let midi_in = self.midi_ins.iter() - .map(|port|port.port().iter(scope) - .map(|RawMidi { time, bytes }|(time, LiveEvent::parse(bytes))) - .collect::>()) - .collect::>(); - - // Update standalone sampler - //if let Some(sampler) = self.sampler.as_mut() { - //if Control::Quit == SamplerAudio(sampler).process(client, scope) { - //return Control::Quit - //} - //for port in midi_in.iter() { - //for message in port.iter() { - //match message { - //Ok(M - //} - //} - //} - //} - - // TODO move these to editor and sampler?: - //for port in midi_in.iter() { - //for event in port.iter() { - //match event { - //(time, Ok(LiveEvent::Midi {message, ..})) => match message { - //MidiMessage::NoteOn {ref key, ..} if let Some(editor) = self.editor.as_ref() => { - //editor.set_note_pos(key.as_int() as usize); - //}, - //MidiMessage::Controller {controller, value} if let (Some(editor), Some(sampler)) = ( - //self.editor.as_ref(), - //self.sampler.as_ref(), - //) => { - //// TODO: give sampler its own cursor - //if let Some(sample) = &sampler.mapped[editor.note_pos()] { - //sample.write().unwrap().handle_cc(*controller, *value) - //} - //} - //_ =>{} - //}, - //_ =>{} - //} - //} - //} - - // Update track sequencers and devices - for track in self.tracks.iter_mut() { - if Control::Quit == PlayerAudio( - track.sequencer_mut(), &mut self.note_buf, &mut self.midi_buf - ).process(client, scope) { - return Control::Quit - } - for device in track.devices.iter_mut() { - if Control::Quit == DeviceAudio(device).process(client, scope) { - return Control::Quit - } - } - } - - // End profiling cycle + let midi_in = self.collect_midi_input(scope); + self.update_editor_cursor(&midi_in); + let result = self.render_tracks(client, scope); self.perf.update_from_jack_scope(t0, scope); - Control::Continue + result }; |self, event|{ use JackEvent::*; @@ -95,3 +33,60 @@ audio!( } } ); + +type CollectedMidiInput<'a> = Vec, MidiError>)>>; + +impl App { + + /// Collect MIDI input from app ports (TODO preallocate large buffers) + fn collect_midi_input <'a> (&'a self, scope: &'a ProcessScope) -> CollectedMidiInput<'a> { + self.midi_ins.iter() + .map(|port|port.port().iter(scope) + .map(|RawMidi { time, bytes }|(time, LiveEvent::parse(bytes))) + .collect::>()) + .collect::>() + } + + /// Update cursor in MIDI editor + fn update_editor_cursor (&self, midi_in: &CollectedMidiInput) { + if let Some(editor) = &self.editor { + let mut pitch: Option = None; + for port in midi_in.iter() { + for event in port.iter() { + if let (_, Ok(LiveEvent::Midi {message: MidiMessage::NoteOn {ref key, ..}, ..})) + = event + { + pitch = Some(key.clone()); + } + } + } + if let Some(pitch) = pitch { + editor.set_note_pos(pitch.as_int() as usize); + } + } + } + + /// Run audio callbacks for every track and every device + fn render_tracks (&mut self, client: &Client, scope: &ProcessScope) -> Control { + for track in self.tracks.iter_mut() { + if Control::Quit == PlayerAudio( + track.sequencer_mut(), &mut self.note_buf, &mut self.midi_buf + ).process(client, scope) { + return Control::Quit + } + for device in track.devices.iter_mut() { + if Control::Quit == DeviceAudio(device).process(client, scope) { + return Control::Quit + } + } + } + Control::Continue + } + +} + +impl HasJack for App { + fn jack (&self) -> &Jack { + &self.jack + } +} diff --git a/crates/app/src/model/track.rs b/crates/app/src/model/track.rs index 5e68b04d..2d91244a 100644 --- a/crates/app/src/model/track.rs +++ b/crates/app/src/model/track.rs @@ -61,7 +61,7 @@ impl Track { )?; track.devices.push(Device::Sampler(Sampler::new( jack, - &"sampler", + &format!("{}/sampler", name.as_ref()), &[PortConnect::exact(format!("{}:{}", jack.with_client(|c|c.name().to_string()), track.sequencer.midi_outs[0].name() diff --git a/crates/device/src/sampler/sampler_midi.rs b/crates/device/src/sampler/sampler_midi.rs index 56885cc4..7a875e2e 100644 --- a/crates/device/src/sampler/sampler_midi.rs +++ b/crates/device/src/sampler/sampler_midi.rs @@ -52,3 +52,27 @@ impl Sample { } } } + +// TODO: +//for port in midi_in.iter() { + //for event in port.iter() { + //match event { + //(time, Ok(LiveEvent::Midi {message, ..})) => match message { + //MidiMessage::NoteOn {ref key, ..} if let Some(editor) = self.editor.as_ref() => { + //editor.set_note_pos(key.as_int() as usize); + //}, + //MidiMessage::Controller {controller, value} if let (Some(editor), Some(sampler)) = ( + //self.editor.as_ref(), + //self.sampler.as_ref(), + //) => { + //// TODO: give sampler its own cursor + //if let Some(sample) = &sampler.mapped[editor.note_pos()] { + //sample.write().unwrap().handle_cc(*controller, *value) + //} + //} + //_ =>{} + //}, + //_ =>{} + //} + //} +//} diff --git a/crates/engine/src/midi.rs b/crates/engine/src/midi.rs index b58425c8..216e253c 100644 --- a/crates/engine/src/midi.rs +++ b/crates/engine/src/midi.rs @@ -4,6 +4,7 @@ pub use ::midly::{ Smf, TrackEventKind, MidiMessage, + Error as MidiError, num::*, live::*, };