wip: refactor pt.12, separate tek_snd

This commit is contained in:
🪞👃🪞 2024-11-10 22:24:58 +01:00
parent 47c9cd2fe8
commit 2be7aee002
28 changed files with 955 additions and 766 deletions

View file

@ -0,0 +1,8 @@
[package]
name = "tek_snd"
edition = "2021"
version = "0.1.0"
[dependencies]
tek_core = { path = "../tek_core" }
tek_api = { path = "../tek_api" }

View file

@ -0,0 +1,9 @@
pub use tek_core::{*, jack::{*, Transport as JackTransport}};
pub use tek_api::{*, Transport};
pub(crate) use tek_core::midly::{*, live::LiveEvent, num::u7};
submod! {
snd_arrange
snd_mixer
snd_sampler
}

View file

@ -0,0 +1,22 @@
use crate::*;
pub struct ArrangementAudio {
model: Arc<RwLock<Arrangement>>
}
impl From<&Arc<RwLock<Arrangement>>> for ArrangementAudio {
fn from (model: &Arc<RwLock<Arrangement>>) -> Self {
Self { model: model.clone() }
}
}
impl Audio for ArrangementAudio {
#[inline] fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
for track in self.model.write().unwrap().tracks.iter_mut() {
if track.player.process(client, scope) == Control::Quit {
return Control::Quit
}
}
Control::Continue
}
}

View file

@ -0,0 +1,17 @@
use crate::*;
pub struct MixerAudio {
model: Arc<RwLock<Mixer>>
}
impl From<&Arc<RwLock<Mixer>>> for MixerAudio {
fn from (model: &Arc<RwLock<Mixer>>) -> Self {
Self { model: model.clone() }
}
}
impl Audio for MixerAudio {
fn process (&mut self, _: &Client, _: &ProcessScope) -> Control {
Control::Continue
}
}

View file

@ -0,0 +1,65 @@
use crate::*;
pub struct PluginAudio {
model: Arc<RwLock<Plugin>>
}
impl From<&Arc<RwLock<Plugin>>> for PluginAudio {
fn from (model: &Arc<RwLock<Plugin>>) -> Self {
Self { model: model.clone() }
}
}
impl Audio for PluginAudio {
fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
match self.plugin.as_mut() {
Some(PluginKind::LV2(LV2Plugin {
features,
ref mut instance,
ref mut input_buffer,
..
})) => {
let urid = features.midi_urid();
input_buffer.clear();
for port in self.midi_ins.iter() {
let mut atom = ::livi::event::LV2AtomSequence::new(
&features,
scope.n_frames() as usize
);
for event in port.iter(scope) {
match event.bytes.len() {
3 => atom.push_midi_event::<3>(
event.time as i64,
urid,
&event.bytes[0..3]
).unwrap(),
_ => {}
}
}
input_buffer.push(atom);
}
let mut outputs = vec![];
for _ in self.midi_outs.iter() {
outputs.push(::livi::event::LV2AtomSequence::new(
&features,
scope.n_frames() as usize
));
}
let ports = ::livi::EmptyPortConnections::new()
.with_atom_sequence_inputs(input_buffer.iter())
.with_atom_sequence_outputs(outputs.iter_mut())
.with_audio_inputs(
self.audio_ins.iter().map(|o|o.as_slice(scope))
)
.with_audio_outputs(
self.audio_outs.iter_mut().map(|o|o.as_mut_slice(scope))
);
unsafe {
instance.run(scope.n_frames() as usize, ports).unwrap()
};
},
_ => {}
}
Control::Continue
}
}

View file

@ -0,0 +1,79 @@
use crate::*;
pub struct SamplerAudio {
model: Arc<RwLock<Sampler>>
}
impl From<&Arc<RwLock<Sampler>>> for SamplerAudio {
fn from (model: &Arc<RwLock<Sampler>>) -> Self {
Self { model: model.clone() }
}
}
impl Audio for SamplerAudio {
#[inline] fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
self.process_midi_in(scope);
self.clear_output_buffer();
self.process_audio_out(scope);
self.write_output_buffer(scope);
Control::Continue
}
}
impl SamplerAudio {
/// Create [Voice]s from [Sample]s in response to MIDI input.
pub fn process_midi_in (&mut self, scope: &ProcessScope) {
let Sampler { midi_in, mapped, voices, .. } = &*self.model.read().unwrap();
for RawMidi { time, bytes } in midi_in.iter(scope) {
if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() {
if let MidiMessage::NoteOn { ref key, ref vel } = message {
if let Some(sample) = mapped.get(key) {
voices.write().unwrap().push(Sample::play(sample, time as usize, vel));
}
}
}
}
}
/// Zero the output buffer.
pub fn clear_output_buffer (&mut self) {
for buffer in self.model.write().unwrap().buffer.iter_mut() {
buffer.fill(0.0);
}
}
/// Mix all currently playing samples into the output.
pub fn process_audio_out (&mut self, scope: &ProcessScope) {
let Sampler { ref mut buffer, voices, output_gain, .. } = &mut*self.model.write().unwrap();
let channel_count = buffer.len();
voices.write().unwrap().retain_mut(|voice|{
for index in 0..scope.n_frames() as usize {
if let Some(frame) = voice.next() {
for (channel, sample) in frame.iter().enumerate() {
// Averaging mixer:
//self.buffer[channel % channel_count][index] = (
//(self.buffer[channel % channel_count][index] + sample * self.output_gain) / 2.0
//);
buffer[channel % channel_count][index] += sample * *output_gain;
}
} else {
return false
}
}
return true
});
}
/// Write output buffer to output ports.
pub fn write_output_buffer (&mut self, scope: &ProcessScope) {
let Sampler { ref mut audio_outs, buffer, .. } = &mut*self.model.write().unwrap();
for (i, port) in audio_outs.iter_mut().enumerate() {
let buffer = &buffer[i];
for (i, value) in port.as_mut_slice(scope).iter_mut().enumerate() {
*value = *buffer.get(i).unwrap_or(&0.0);
}
}
}
}

View file

@ -0,0 +1,37 @@
use crate::*;
pub struct MIDIPlayerAudio {
model: Arc<RwLock<MIDIPlayer>>
}
impl From<&Arc<RwLock<MIDIPlayer>>> for MIDIPlayerAudio {
fn from (model: &Arc<RwLock<MIDIPlayer>>) -> Self {
Self { model: model.clone() }
}
}
/// JACK process callback for a sequencer's phrase player/recorder.
impl Audio for MIDIPlayer {
fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
let has_midi_outputs = self.has_midi_outputs();
let has_midi_inputs = self.has_midi_inputs();
// Clear output buffer(s)
self.clear(scope, false);
// Write chunk of phrase to output, handle switchover
if self.play(scope) {
self.switchover(scope);
}
if has_midi_inputs {
if self.recording || self.monitoring {
// Record and/or monitor input
self.record(scope)
} else if has_midi_outputs && self.monitoring {
// Monitor input to output
self.monitor(scope)
}
}
// Write to output port(s)
self.write(scope);
Control::Continue
}
}

View file

@ -0,0 +1,43 @@
use crate::*;
pub struct TransportAudio {
model: Transport
}
impl From<&Arc<RwLock<Transport>>> for TransportAudio {
fn from (model: &Arc<RwLock<Transport>>) -> Self {
Self { model: model.clone() }
}
}
impl Audio for Transport {
fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
let times = scope.cycle_times().unwrap();
let CycleTimes { current_frames, current_usecs, next_usecs: _, period_usecs: _ } = times;
let _chunk_size = scope.n_frames() as usize;
let transport = self.transport.query().unwrap();
self.clock.current.sample.set(transport.pos.frame() as f64);
let mut playing = self.clock.playing.write().unwrap();
let mut started = self.clock.started.write().unwrap();
if *playing != Some(transport.state) {
match transport.state {
TransportState::Rolling => {
*started = Some((current_frames as usize, current_usecs as usize))
},
TransportState::Stopped => {
*started = None
},
_ => {}
}
};
*playing = Some(transport.state);
if *playing == Some(TransportState::Stopped) {
*started = None;
}
self.clock.current.update_from_usec(match *started {
Some((_, usecs)) => current_usecs as f64 - usecs as f64,
None => 0.
});
Control::Continue
}
}