refactor audio.rs

This commit is contained in:
🪞👃🪞 2025-05-10 20:45:18 +03:00
parent 5fab1af138
commit 7f255eaea8
4 changed files with 88 additions and 68 deletions

View file

@ -1,76 +1,14 @@
use crate::*; use crate::*;
impl HasJack for App { fn jack (&self) -> &Jack { &self.jack } }
audio!( audio!(
|self: App, client, scope|{ |self: App, client, scope|{
// Start profiling cycle
let t0 = self.perf.get_t0(); let t0 = self.perf.get_t0();
// Update transport clock
self.clock().update_from_scope(scope).unwrap(); self.clock().update_from_scope(scope).unwrap();
let midi_in = self.collect_midi_input(scope);
// Collect MIDI input (TODO preallocate large buffers) self.update_editor_cursor(&midi_in);
let midi_in = self.midi_ins.iter() let result = self.render_tracks(client, scope);
.map(|port|port.port().iter(scope)
.map(|RawMidi { time, bytes }|(time, LiveEvent::parse(bytes)))
.collect::<Vec<_>>())
.collect::<Vec<_>>();
// 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
self.perf.update_from_jack_scope(t0, scope); self.perf.update_from_jack_scope(t0, scope);
Control::Continue result
}; };
|self, event|{ |self, event|{
use JackEvent::*; use JackEvent::*;
@ -95,3 +33,60 @@ audio!(
} }
} }
); );
type CollectedMidiInput<'a> = Vec<Vec<(u32, Result<LiveEvent<'a>, 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::<Vec<_>>())
.collect::<Vec<_>>()
}
/// Update cursor in MIDI editor
fn update_editor_cursor (&self, midi_in: &CollectedMidiInput) {
if let Some(editor) = &self.editor {
let mut pitch: Option<u7> = 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
}
}

View file

@ -61,7 +61,7 @@ impl Track {
)?; )?;
track.devices.push(Device::Sampler(Sampler::new( track.devices.push(Device::Sampler(Sampler::new(
jack, jack,
&"sampler", &format!("{}/sampler", name.as_ref()),
&[PortConnect::exact(format!("{}:{}", &[PortConnect::exact(format!("{}:{}",
jack.with_client(|c|c.name().to_string()), jack.with_client(|c|c.name().to_string()),
track.sequencer.midi_outs[0].name() track.sequencer.midi_outs[0].name()

View file

@ -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)
//}
//}
//_ =>{}
//},
//_ =>{}
//}
//}
//}

View file

@ -4,6 +4,7 @@ pub use ::midly::{
Smf, Smf,
TrackEventKind, TrackEventKind,
MidiMessage, MidiMessage,
Error as MidiError,
num::*, num::*,
live::*, live::*,
}; };