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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,8 +1,16 @@
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 {
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 {
return Control::Quit
}

View file

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

View file

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