mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
wip: refactor pt.21: api traits
This commit is contained in:
parent
b8708d6b2d
commit
029614631e
10 changed files with 626 additions and 490 deletions
|
|
@ -1,19 +1,104 @@
|
|||
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>;
|
||||
|
||||
fn track_default_name (&self) -> String {
|
||||
format!("Track {}", self.tracks().len() + 1)
|
||||
}
|
||||
fn track_add (
|
||||
&mut self, name: Option<&str>, color: Option<ItemColor>
|
||||
) -> Usually<&mut ArrangerTrack> {
|
||||
let name = name.map_or_else(||self.track_default_name(), |x|x.to_string());
|
||||
let track = ArrangerTrack {
|
||||
width: name.len() + 2,
|
||||
color: color.unwrap_or_else(||ItemColor::random()),
|
||||
player: MIDIPlayer::new(&self.jack(), &self.clock(), name.as_str())?,
|
||||
name: Arc::new(name.into()),
|
||||
};
|
||||
self.tracks_mut().push(track);
|
||||
let index = self.tracks().len() - 1;
|
||||
Ok(&mut self.tracks_mut()[index])
|
||||
}
|
||||
fn track_del (&mut self, index: usize) {
|
||||
self.tracks_mut().remove(index);
|
||||
for scene in self.scenes_mut().iter_mut() {
|
||||
scene.clips.remove(index);
|
||||
}
|
||||
}
|
||||
fn scene_default_name (&self) -> String {
|
||||
format!("Scene {}", self.scenes().len() + 1)
|
||||
}
|
||||
fn scene_add (
|
||||
&mut self, name: Option<&str>, color: Option<ItemColor>
|
||||
) -> Usually<&mut ArrangerScene> {
|
||||
let name = name.map_or_else(||self.scene_default_name(), |x|x.to_string());
|
||||
let scene = ArrangerScene {
|
||||
name: Arc::new(name.into()),
|
||||
clips: vec![None;self.tracks().len()],
|
||||
color: color.unwrap_or_else(||ItemColor::random()),
|
||||
};
|
||||
self.scenes_mut().push(scene);
|
||||
let index = self.scenes().len() - 1;
|
||||
Ok(&mut self.scenes_mut()[index])
|
||||
}
|
||||
fn scene_del (&mut self, index: usize) {
|
||||
self.scenes_mut().remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
impl JackModelApi for ArrangerModel {
|
||||
fn jack (&self) -> &Arc<RwLock<JackClient>> {
|
||||
&self.jack
|
||||
}
|
||||
}
|
||||
|
||||
impl ClockModelApi for ArrangerModel {
|
||||
fn clock (&self) -> &Arc<Clock> {
|
||||
&self.clock
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
fn tracks_mut (&mut self) -> &mut Vec<ArrangerTrack> {
|
||||
&mut self.tracks
|
||||
}
|
||||
fn scenes (&self) -> &Vec<ArrangerScene> {
|
||||
&self.scenes
|
||||
}
|
||||
fn scenes_mut (&mut self) -> &mut Vec<ArrangerScene> {
|
||||
&mut self.scenes
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ArrangerModel {
|
||||
/// JACK client handle (needs to not be dropped for standalone mode to work).
|
||||
pub jack: Arc<RwLock<JackClient>>,
|
||||
jack: Arc<RwLock<JackClient>>,
|
||||
/// Global timebase
|
||||
pub clock: Arc<Clock>,
|
||||
clock: Arc<Clock>,
|
||||
/// Name of arranger
|
||||
pub name: Arc<RwLock<String>>,
|
||||
name: Arc<RwLock<String>>,
|
||||
/// Collection of phrases.
|
||||
pub phrases: Arc<RwLock<PhrasePool>>,
|
||||
phrases: Arc<RwLock<PhrasePool>>,
|
||||
/// Collection of tracks.
|
||||
pub tracks: Vec<ArrangerTrack>,
|
||||
tracks: Vec<ArrangerTrack>,
|
||||
/// Collection of scenes.
|
||||
pub scenes: Vec<ArrangerScene>,
|
||||
scenes: Vec<ArrangerScene>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -38,50 +123,21 @@ pub struct ArrangerScene {
|
|||
pub color: ItemColor,
|
||||
}
|
||||
|
||||
impl ArrangerModel {
|
||||
pub fn is_stopped (&self) -> bool {
|
||||
*self.clock.playing.read().unwrap() == Some(TransportState::Stopped)
|
||||
impl ArrangerTrack {
|
||||
pub fn longest_name (tracks: &[Self]) -> usize {
|
||||
tracks.iter().map(|s|s.name.read().unwrap().len()).fold(0, usize::max)
|
||||
}
|
||||
pub fn track_default_name (&self) -> String {
|
||||
format!("Track {}", self.tracks.len() + 1)
|
||||
|
||||
pub const MIN_WIDTH: usize = 3;
|
||||
|
||||
pub fn width_inc (&mut self) {
|
||||
self.width += 1;
|
||||
}
|
||||
pub fn scene_default_name (&self) -> String {
|
||||
format!("Scene {}", self.scenes.len() + 1)
|
||||
}
|
||||
pub fn track_add (
|
||||
&mut self, name: Option<&str>, color: Option<ItemColor>
|
||||
) -> Usually<&mut ArrangerTrack> {
|
||||
let name = name.map_or_else(||self.track_default_name(), |x|x.to_string());
|
||||
self.tracks.push(ArrangerTrack {
|
||||
width: name.len() + 2,
|
||||
color: color.unwrap_or_else(||ItemColor::random()),
|
||||
player: MIDIPlayer::new(&self.jack, &self.clock, name.as_str())?,
|
||||
name: Arc::new(name.into()),
|
||||
});
|
||||
let index = self.tracks.len() - 1;
|
||||
Ok(&mut self.tracks[index])
|
||||
}
|
||||
pub fn scene_add (
|
||||
&mut self, name: Option<&str>, color: Option<ItemColor>
|
||||
) -> Usually<&mut ArrangerScene> {
|
||||
let name = name.map_or_else(||self.scene_default_name(), |x|x.to_string());
|
||||
self.scenes.push(ArrangerScene {
|
||||
name: Arc::new(name.into()),
|
||||
clips: vec![None;self.tracks.len()],
|
||||
color: color.unwrap_or_else(||ItemColor::random()),
|
||||
});
|
||||
let index = self.scenes.len() - 1;
|
||||
Ok(&mut self.scenes[index])
|
||||
}
|
||||
pub fn track_del (&mut self, index: usize) {
|
||||
self.tracks.remove(index);
|
||||
for scene in self.scenes.iter_mut() {
|
||||
scene.clips.remove(index);
|
||||
pub fn width_dec (&mut self) {
|
||||
if self.width > Self::MIN_WIDTH {
|
||||
self.width -= 1;
|
||||
}
|
||||
}
|
||||
pub fn scene_del (&mut self, index: usize) {
|
||||
self.scenes.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
impl ArrangerScene {
|
||||
|
|
@ -160,19 +216,3 @@ impl ArrangerScene {
|
|||
//})
|
||||
//}
|
||||
}
|
||||
|
||||
impl ArrangerTrack {
|
||||
pub fn longest_name (tracks: &[Self]) -> usize {
|
||||
tracks.iter().map(|s|s.name.read().unwrap().len()).fold(0, usize::max)
|
||||
}
|
||||
|
||||
pub const MIN_WIDTH: usize = 3;
|
||||
pub fn width_inc (&mut self) {
|
||||
self.width += 1;
|
||||
}
|
||||
pub fn width_dec (&mut self) {
|
||||
if self.width > Self::MIN_WIDTH {
|
||||
self.width -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,3 +38,15 @@ submod! {
|
|||
transport
|
||||
transport_cmd
|
||||
}
|
||||
|
||||
pub trait JackModelApi {
|
||||
fn jack (&self) -> &Arc<RwLock<JackClient>>;
|
||||
}
|
||||
|
||||
pub trait ClockModelApi {
|
||||
fn clock (&self) -> &Arc<Clock>;
|
||||
fn is_stopped (&self) -> bool {
|
||||
*self.clock().playing.read().unwrap() == Some(TransportState::Stopped)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ impl Sampler {
|
|||
},
|
||||
_ => panic!("unexpected in sampler {name}: {edn:?}")
|
||||
});
|
||||
let midi_in = jack.read().unwrap().client().register_port("in", MidiIn::default())?;
|
||||
Ok(Sampler {
|
||||
jack: jack.clone(),
|
||||
name: name.into(),
|
||||
|
|
@ -48,7 +49,7 @@ impl Sampler {
|
|||
unmapped: Default::default(),
|
||||
voices: Default::default(),
|
||||
buffer: Default::default(),
|
||||
midi_in: jack.read().unwrap().register_port("in", MidiIn::default())?,
|
||||
midi_in: midi_in,
|
||||
audio_outs: vec![],
|
||||
output_gain: 0.
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,5 +1,49 @@
|
|||
use crate::*;
|
||||
|
||||
pub trait SequencerModelApi: JackModelApi + ClockModelApi {
|
||||
fn phrases (&self) -> &PhrasePool;
|
||||
fn player (&self) -> &MIDIPlayer;
|
||||
}
|
||||
|
||||
impl JackModelApi for SequencerModel {
|
||||
fn jack (&self) -> &Arc<RwLock<JackClient>> {
|
||||
self.transport.jack()
|
||||
}
|
||||
}
|
||||
|
||||
impl ClockModelApi for SequencerModel {
|
||||
fn clock (&self) -> &Arc<Clock> {
|
||||
self.transport.clock()
|
||||
}
|
||||
}
|
||||
|
||||
impl TransportModelApi for SequencerModel {
|
||||
fn transport (&self) -> &jack::Transport {
|
||||
&self.transport.transport()
|
||||
}
|
||||
fn metronome (&self) -> bool {
|
||||
self.transport.metronome()
|
||||
}
|
||||
}
|
||||
|
||||
impl SequencerModelApi for SequencerModel {
|
||||
fn phrases (&self) -> &PhrasePool {
|
||||
&self.phrases
|
||||
}
|
||||
fn player (&self) -> &MIDIPlayer {
|
||||
&self.player
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SequencerModel {
|
||||
/// State of the JACK transport.
|
||||
transport: TransportModel,
|
||||
/// State of the phrase pool.
|
||||
phrases: PhrasePool,
|
||||
/// State of the phrase player.
|
||||
player: MIDIPlayer,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MIDIPlayer {
|
||||
/// Global timebase
|
||||
|
|
|
|||
|
|
@ -1,16 +1,42 @@
|
|||
use crate::*;
|
||||
|
||||
pub struct Transport {
|
||||
pub jack: Arc<RwLock<JackClient>>,
|
||||
/// JACK transport handle.
|
||||
pub transport: jack::Transport,
|
||||
/// Current sample rate, tempo, and PPQ.
|
||||
pub clock: Arc<Clock>,
|
||||
/// Enable metronome?
|
||||
pub metronome: bool,
|
||||
pub trait TransportModelApi: JackModelApi + ClockModelApi {
|
||||
fn transport (&self) -> &jack::Transport;
|
||||
fn metronome (&self) -> bool;
|
||||
}
|
||||
|
||||
impl Debug for Transport {
|
||||
impl JackModelApi for TransportModel {
|
||||
fn jack (&self) -> &Arc<RwLock<JackClient>> {
|
||||
&self.jack
|
||||
}
|
||||
}
|
||||
|
||||
impl ClockModelApi for TransportModel {
|
||||
fn clock (&self) -> &Arc<Clock> {
|
||||
&self.clock
|
||||
}
|
||||
}
|
||||
|
||||
impl TransportModelApi for TransportModel {
|
||||
fn transport (&self) -> &jack::Transport {
|
||||
&self.transport
|
||||
}
|
||||
fn metronome (&self) -> bool {
|
||||
self.metronome
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TransportModel {
|
||||
jack: Arc<RwLock<JackClient>>,
|
||||
/// Current sample rate, tempo, and PPQ.
|
||||
clock: Arc<Clock>,
|
||||
/// JACK transport handle.
|
||||
transport: jack::Transport,
|
||||
/// Enable metronome?
|
||||
metronome: bool,
|
||||
}
|
||||
|
||||
impl Debug for TransportModel {
|
||||
fn fmt (&self, f: &mut Formatter<'_>) -> std::result::Result<(), Error> {
|
||||
f.debug_struct("transport")
|
||||
.field("jack", &self.jack)
|
||||
|
|
@ -21,7 +47,7 @@ impl Debug for Transport {
|
|||
}
|
||||
}
|
||||
|
||||
impl Transport {
|
||||
impl TransportModel {
|
||||
pub fn toggle_play (&mut self) -> Usually<()> {
|
||||
let playing = self.clock.playing.read().unwrap().expect("1st sample has not been processed yet");
|
||||
let playing = match playing {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue