wip: refactor pt.22: api traits in snd

This commit is contained in:
🪞👃🪞 2024-11-13 19:49:52 +01:00
parent 029614631e
commit e7e57cea1e
8 changed files with 100 additions and 67 deletions

View file

@ -2,9 +2,10 @@ use crate::*;
pub trait ArrangerModelApi: JackModelApi + ClockModelApi { pub trait ArrangerModelApi: JackModelApi + ClockModelApi {
fn name (&self) -> &Arc<RwLock<String>>; fn name (&self) -> &Arc<RwLock<String>>;
fn phrases (&self) -> &Arc<RwLock<PhrasePool>>;
fn tracks (&self) -> &Vec<ArrangerTrack>; fn tracks (&self) -> &Vec<ArrangerTrack>;
fn tracks_mut (&mut self) -> &mut Vec<ArrangerTrack>; fn tracks_mut (&mut self) -> &mut Vec<ArrangerTrack>;
fn scenes (&self) -> &Vec<ArrangerScene>; fn scenes (&self) -> &Vec<ArrangerScene>;
fn scenes_mut (&mut self) -> &mut Vec<ArrangerScene>; fn scenes_mut (&mut self) -> &mut Vec<ArrangerScene>;
@ -54,13 +55,31 @@ pub trait ArrangerModelApi: JackModelApi + ClockModelApi {
impl JackModelApi for ArrangerModel { impl JackModelApi for ArrangerModel {
fn jack (&self) -> &Arc<RwLock<JackClient>> { fn jack (&self) -> &Arc<RwLock<JackClient>> {
&self.jack &self.transport.jack()
} }
} }
impl ClockModelApi for ArrangerModel { impl ClockModelApi for ArrangerModel {
fn clock (&self) -> &Arc<Clock> { fn clock (&self) -> &Arc<Clock> {
&self.clock &self.transport.clock()
}
}
impl TransportModelApi for ArrangerModel {
fn transport (&self) -> &jack::Transport {
&self.transport.transport()
}
fn metronome (&self) -> bool {
self.transport.metronome()
}
}
impl PhrasePoolModelApi for ArrangerModel {
fn phrases (&self) -> &Vec<Arc<RwLock<Phrase>>> {
&self.phrases
}
fn phrases_mut (&mut self) -> &mut Vec<Arc<RwLock<Phrase>>> {
&mut self.phrases
} }
} }
@ -68,9 +87,6 @@ impl ArrangerModelApi for ArrangerModel {
fn name (&self) -> &Arc<RwLock<String>> { fn name (&self) -> &Arc<RwLock<String>> {
&self.name &self.name
} }
fn phrases (&self) -> &Arc<RwLock<PhrasePool>> {
&self.phrases
}
fn tracks (&self) -> &Vec<ArrangerTrack> { fn tracks (&self) -> &Vec<ArrangerTrack> {
&self.tracks &self.tracks
} }
@ -87,18 +103,16 @@ impl ArrangerModelApi for ArrangerModel {
#[derive(Debug)] #[derive(Debug)]
pub struct ArrangerModel { pub struct ArrangerModel {
/// JACK client handle (needs to not be dropped for standalone mode to work). /// State of the JACK transport.
jack: Arc<RwLock<JackClient>>, transport: TransportModel,
/// Global timebase
clock: Arc<Clock>,
/// Name of arranger
name: Arc<RwLock<String>>,
/// Collection of phrases. /// Collection of phrases.
phrases: Arc<RwLock<PhrasePool>>, phrases: Vec<Arc<RwLock<Phrase>>>,
/// Collection of tracks. /// Collection of tracks.
tracks: Vec<ArrangerTrack>, tracks: Vec<ArrangerTrack>,
/// Collection of scenes. /// Collection of scenes.
scenes: Vec<ArrangerScene>, scenes: Vec<ArrangerScene>,
/// Name of arranger
name: Arc<RwLock<String>>,
} }
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,8 +1,22 @@
use crate::*; use crate::*;
pub trait PhrasePoolModelApi {
fn phrases (&self) -> &Vec<Arc<RwLock<Phrase>>>;
fn phrases_mut (&mut self) -> &mut Vec<Arc<RwLock<Phrase>>>;
}
impl PhrasePoolModelApi for PhrasePoolModel {
fn phrases (&self) -> &Vec<Arc<RwLock<Phrase>>> {
&self.phrases
}
fn phrases_mut (&mut self) -> &mut Vec<Arc<RwLock<Phrase>>> {
&mut self.phrases
}
}
/// Contains all phrases in a project /// Contains all phrases in a project
#[derive(Debug)] #[derive(Debug)]
pub struct PhrasePool { pub struct PhrasePoolModel {
/// Phrases in the pool /// Phrases in the pool
pub phrases: Vec<Arc<RwLock<Phrase>>>, pub phrases: Vec<Arc<RwLock<Phrase>>>,
} }
@ -20,8 +34,8 @@ pub enum PhrasePoolCommand {
SetLength(usize, usize), SetLength(usize, usize),
} }
impl Command<PhrasePool> for PhrasePoolCommand { impl Command<PhrasePoolModel> for PhrasePoolCommand {
fn execute (self, state: &mut PhrasePool) -> Perhaps<Self> { fn execute (self, model: &mut PhrasePoolModel) -> Perhaps<Self> {
match self { match self {
Self::Add(index) => { Self::Add(index) => {
//Self::Append => { view.append_new(None, None) }, //Self::Append => { view.append_new(None, None) },
@ -29,8 +43,8 @@ impl Command<PhrasePool> for PhrasePoolCommand {
}, },
Self::Delete(index) => { Self::Delete(index) => {
//if view.phrase > 0 { //if view.phrase > 0 {
//view.state.phrases.remove(view.phrase); //view.model.phrases.remove(view.phrase);
//view.phrase = view.phrase.min(view.state.phrases.len().saturating_sub(1)); //view.phrase = view.phrase.min(view.model.phrases.len().saturating_sub(1));
//} //}
}, },
Self::Duplicate(index) => { Self::Duplicate(index) => {

View file

@ -1,8 +1,8 @@
use crate::*; use crate::*;
pub trait SequencerModelApi: JackModelApi + ClockModelApi { pub trait SequencerModelApi: JackModelApi + ClockModelApi + TransportModelApi {
fn phrases (&self) -> &PhrasePool;
fn player (&self) -> &MIDIPlayer; fn player (&self) -> &MIDIPlayer;
fn player_mut (&mut self) -> &mut MIDIPlayer;
} }
impl JackModelApi for SequencerModel { impl JackModelApi for SequencerModel {
@ -26,20 +26,29 @@ impl TransportModelApi for SequencerModel {
} }
} }
impl SequencerModelApi for SequencerModel { impl PhrasePoolModelApi for SequencerModel {
fn phrases (&self) -> &PhrasePool { fn phrases (&self) -> &Vec<Arc<RwLock<Phrase>>> {
&self.phrases &self.phrases
} }
fn phrases_mut (&mut self) -> &mut Vec<Arc<RwLock<Phrase>>> {
&mut self.phrases
}
}
impl SequencerModelApi for SequencerModel {
fn player (&self) -> &MIDIPlayer { fn player (&self) -> &MIDIPlayer {
&self.player &self.player
} }
fn player_mut (&mut self) -> &mut MIDIPlayer {
&mut self.player
}
} }
pub struct SequencerModel { pub struct SequencerModel {
/// State of the JACK transport. /// State of the JACK transport.
transport: TransportModel, transport: TransportModel,
/// State of the phrase pool. /// State of the phrase pool.
phrases: PhrasePool, phrases: Vec<Arc<RwLock<Phrase>>>,
/// State of the phrase player. /// State of the phrase player.
player: MIDIPlayer, player: MIDIPlayer,
} }

View file

@ -12,18 +12,18 @@ pub enum TransportCommand {
SetSync(f64), SetSync(f64),
} }
impl Command<Transport> for TransportCommand { impl<T: TransportModelApi> Command<T> for TransportCommand {
fn execute (self, state: &mut Transport) -> Perhaps<Self> { fn execute (self, state: &mut T) -> Perhaps<Self> {
use TransportCommand::*; use TransportCommand::*;
match self.translate(&state) { match self {
Play(start) => {todo!()}, Play(start) => {todo!()},
Pause(start) => {todo!()}, Pause(start) => {todo!()},
SeekUsec(usec) => {state.clock.current.update_from_usec(usec);}, SeekUsec(usec) => {state.clock().current.update_from_usec(usec);},
SeekSample(sample) => {state.clock.current.update_from_sample(sample);}, SeekSample(sample) => {state.clock().current.update_from_sample(sample);},
SeekPulse(pulse) => {state.clock.current.update_from_pulse(pulse);}, SeekPulse(pulse) => {state.clock().current.update_from_pulse(pulse);},
SetBpm(bpm) => {return Ok(Some(Self::SetBpm(state.clock.timebase().bpm.set(bpm))))}, SetBpm(bpm) => {return Ok(Some(Self::SetBpm(state.clock().timebase().bpm.set(bpm))))},
SetQuant(quant) => {return Ok(Some(Self::SetQuant(state.clock.quant.set(quant))))}, SetQuant(quant) => {return Ok(Some(Self::SetQuant(state.clock().quant.set(quant))))},
SetSync(sync) => {return Ok(Some(Self::SetSync(state.clock.sync.set(sync))))}, SetSync(sync) => {return Ok(Some(Self::SetSync(state.clock().sync.set(sync))))},
_ => { unreachable!() } _ => { unreachable!() }
} }
Ok(None) Ok(None)

View file

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

View file

@ -1,8 +1,16 @@
use crate::*; use crate::*;
impl<T: ArrangerModelApi + Send + Sync> Audio for T { impl Audio for ArrangerModel {
fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
ArrangerRefAudio(self).process(client, scope)
}
}
pub struct ArrangerRefAudio<'a, T: ArrangerModelApi + Send + Sync>(&'a mut T);
impl<'a, T: ArrangerModelApi + Send + Sync> Audio for ArrangerRefAudio<'a, T> {
#[inline] fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control { #[inline] fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
for track in self.tracks_mut().iter_mut() { for track in self.0.tracks_mut().iter_mut() {
if MIDIPlayerAudio::from(&mut track.player).process(client, scope) == Control::Quit { if MIDIPlayerAudio::from(&mut track.player).process(client, scope) == Control::Quit {
return Control::Quit return Control::Quit
} }

View file

@ -1,27 +1,19 @@
use crate::*; use crate::*;
pub struct SequencerAudio(pub Arc<RwLock<Transport>>, pub Arc<RwLock<MIDIPlayer>>); impl Audio for SequencerModel {
/// JACK process callback for sequencer app
impl<'a> Audio for SequencerAudio {
fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control { fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
SequencerRefAudio( SequencerRefAudio(self).process(client, scope)
&mut*self.0.write().unwrap(),
&mut*self.1.write().unwrap()
).process(client, scope)
} }
} }
pub struct SequencerRefAudio<'a, T: SequencerModelApi + Send + Sync>(&'a mut T);
pub struct SequencerRefAudio<'a>(pub &'a mut Transport, pub &'a mut MIDIPlayer); impl<'a, T: SequencerModelApi + Send + Sync> Audio for SequencerRefAudio<'a, T> {
#[inline] fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
/// JACK process callback for sequencer embed
impl<'a> Audio for SequencerRefAudio<'a> {
fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
if TransportRefAudio(&mut*self.0).process(client, scope) == Control::Quit { if TransportRefAudio(&mut*self.0).process(client, scope) == Control::Quit {
return Control::Quit return Control::Quit
} }
if MIDIPlayerAudio::from(&mut*self.1).process(client, scope) == Control::Quit { if MIDIPlayerAudio::from(&mut*self.0.player_mut()).process(client, scope) == Control::Quit {
return Control::Quit return Control::Quit
} }
Control::Continue Control::Continue

View file

@ -1,27 +1,23 @@
use crate::*; use crate::*;
pub struct TransportAudio(pub Arc<RwLock<Transport>>); impl Audio for TransportModel {
impl Audio for TransportAudio {
fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control { fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
TransportRefAudio( TransportRefAudio(self).process(client, scope)
&mut*self.0.write().unwrap()
).process(client, scope)
} }
} }
pub struct TransportRefAudio<'a>(pub &'a mut Transport); pub struct TransportRefAudio<'a, T: TransportModelApi + Send + Sync>(pub(crate) &'a mut T);
impl<'a> Audio for TransportRefAudio<'a> { impl<'a, T: TransportModelApi + Send + Sync> Audio for TransportRefAudio<'a, T> {
fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control { #[inline] fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
let ref state = self.0; let state = &mut self.0;
let times = scope.cycle_times().unwrap(); let times = scope.cycle_times().unwrap();
let CycleTimes { current_frames, current_usecs, next_usecs: _, period_usecs: _ } = times; let CycleTimes { current_frames, current_usecs, next_usecs: _, period_usecs: _ } = times;
let _chunk_size = scope.n_frames() as usize; let _chunk_size = scope.n_frames() as usize;
let transport = state.transport.query().unwrap(); let transport = state.transport().query().unwrap();
state.clock.current.sample.set(transport.pos.frame() as f64); state.clock().current.sample.set(transport.pos.frame() as f64);
let mut playing = state.clock.playing.write().unwrap(); let mut playing = state.clock().playing.write().unwrap();
let mut started = state.clock.started.write().unwrap(); let mut started = state.clock().started.write().unwrap();
if *playing != Some(transport.state) { if *playing != Some(transport.state) {
match transport.state { match transport.state {
TransportState::Rolling => { TransportState::Rolling => {
@ -37,7 +33,7 @@ impl<'a> Audio for TransportRefAudio<'a> {
if *playing == Some(TransportState::Stopped) { if *playing == Some(TransportState::Stopped) {
*started = None; *started = None;
} }
state.clock.current.update_from_usec(match *started { state.clock().current.update_from_usec(match *started {
Some((_, usecs)) => current_usecs as f64 - usecs as f64, Some((_, usecs)) => current_usecs as f64 - usecs as f64,
None => 0. None => 0.
}); });