mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-03-13 11:50:44 +01:00
use new AsRefOpt/AsMutOpt glue traits
This commit is contained in:
parent
6295f2e601
commit
ab90129f4c
7 changed files with 661 additions and 740 deletions
|
|
@ -50,7 +50,6 @@ proptest-derive = { version = "^0.5.1" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["cli", "arranger", "sampler"]
|
default = ["cli", "arranger", "sampler"]
|
||||||
|
|
||||||
arranger = ["port", "editor", "sequencer", "track", "scene", "clip", "select"]
|
arranger = ["port", "editor", "sequencer", "track", "scene", "clip", "select"]
|
||||||
browse = []
|
browse = []
|
||||||
clap = []
|
clap = []
|
||||||
|
|
|
||||||
2
Justfile
2
Justfile
|
|
@ -2,7 +2,7 @@ export RUSTFLAGS := "--cfg procmacro2_semver_exempt -Zmacro-backtrace -Clink-arg
|
||||||
export RUST_BACKTRACE := "1"
|
export RUST_BACKTRACE := "1"
|
||||||
|
|
||||||
default +ARGS="new":
|
default +ARGS="new":
|
||||||
target/debug/tek {{ARGS}}
|
cargo run -- {{ARGS}}
|
||||||
|
|
||||||
doc +ARGS="":
|
doc +ARGS="":
|
||||||
cargo doc --open -j4 --document-private-items {{ARGS}}
|
cargo doc --open -j4 --document-private-items {{ARGS}}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,6 @@ pub(crate) use tengri::{
|
||||||
pub(crate) use ConnectName::*;
|
pub(crate) use ConnectName::*;
|
||||||
pub(crate) use ConnectScope::*;
|
pub(crate) use ConnectScope::*;
|
||||||
pub(crate) use ConnectStatus::*;
|
pub(crate) use ConnectStatus::*;
|
||||||
pub(crate) use JackState::*;
|
|
||||||
|
|
||||||
/// Command-line entrypoint.
|
/// Command-line entrypoint.
|
||||||
#[cfg(feature = "cli")] pub fn main () -> Usually<()> {
|
#[cfg(feature = "cli")] pub fn main () -> Usually<()> {
|
||||||
|
|
@ -70,7 +69,7 @@ pub(crate) use JackState::*;
|
||||||
/// Create a new application from a backend, project, config, and mode
|
/// Create a new application from a backend, project, config, and mode
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let jack = tek::Jack::new(&"test_tek").expect("failed to connect to jack");
|
/// let jack = tek::tengri::Jack::new(&"test_tek").expect("failed to connect to jack");
|
||||||
/// let proj = tek::Arrangement::default();
|
/// let proj = tek::Arrangement::default();
|
||||||
/// let mut conf = tek::Config::default();
|
/// let mut conf = tek::Config::default();
|
||||||
/// conf.add("(mode hello)");
|
/// conf.add("(mode hello)");
|
||||||
|
|
|
||||||
1221
app/tek_impls.rs
1221
app/tek_impls.rs
File diff suppressed because it is too large
Load diff
|
|
@ -5,7 +5,7 @@ use builder_pattern::Builder;
|
||||||
/// Total state
|
/// Total state
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use tek::{TracksView, ScenesView, AddScene};
|
/// use tek::{HasTracks, HasScenes, TracksView, ScenesView};
|
||||||
/// let mut app = tek::App::default();
|
/// let mut app = tek::App::default();
|
||||||
/// let _ = app.scene_add(None, None).unwrap();
|
/// let _ = app.scene_add(None, None).unwrap();
|
||||||
/// let _ = app.update_clock();
|
/// let _ = app.update_clock();
|
||||||
|
|
|
||||||
150
app/tek_trait.rs
150
app/tek_trait.rs
|
|
@ -125,24 +125,55 @@ pub trait HasMidiClip {
|
||||||
fn clip (&self) -> Option<Arc<RwLock<MidiClip>>>;
|
fn clip (&self) -> Option<Arc<RwLock<MidiClip>>>;
|
||||||
}
|
}
|
||||||
pub trait HasClock: AsRef<Clock> + AsMut<Clock> {
|
pub trait HasClock: AsRef<Clock> + AsMut<Clock> {
|
||||||
fn clock_mut (&mut self) -> &mut Clock { self.as_mut() }
|
|
||||||
fn clock (&self) -> &Clock { self.as_ref() }
|
fn clock (&self) -> &Clock { self.as_ref() }
|
||||||
|
fn clock_mut (&mut self) -> &mut Clock { self.as_mut() }
|
||||||
}
|
}
|
||||||
pub trait HasDevices: AsRef<Vec<Device>> + AsMut<Vec<Device>> {
|
pub trait HasDevices: AsRef<Vec<Device>> + AsMut<Vec<Device>> {
|
||||||
fn devices_mut (&mut self) -> &mut Vec<Device> { self.as_mut() }
|
|
||||||
fn devices (&self) -> &Vec<Device> { self.as_ref() }
|
fn devices (&self) -> &Vec<Device> { self.as_ref() }
|
||||||
}
|
fn devices_mut (&mut self) -> &mut Vec<Device> { self.as_mut() }
|
||||||
pub trait HasSelection: AsRef<Selection> + AsMut<Selection> {
|
|
||||||
fn selection_mut (&mut self) -> &mut Selection { self.as_mut() }
|
|
||||||
fn selection (&self) -> &Selection { self.as_ref() }
|
|
||||||
}
|
}
|
||||||
pub trait HasSequencer: AsRef<Sequencer> + AsMut<Sequencer> {
|
pub trait HasSequencer: AsRef<Sequencer> + AsMut<Sequencer> {
|
||||||
fn sequencer_mut (&mut self) -> &mut Sequencer { self.as_mut() }
|
fn sequencer_mut (&mut self) -> &mut Sequencer { self.as_mut() }
|
||||||
fn sequencer (&self) -> &Sequencer { self.as_ref() }
|
fn sequencer (&self) -> &Sequencer { self.as_ref() }
|
||||||
}
|
}
|
||||||
pub trait HasScene: AsRef<Option<Scene>> + AsMut<Option<Scene>> {
|
pub trait HasSceneScroll: HasScenes { fn scene_scroll (&self) -> usize; }
|
||||||
fn scene_mut (&mut self) -> &mut Option<Scene> { self.as_mut() }
|
pub trait HasTrackScroll: HasTracks { fn track_scroll (&self) -> usize; }
|
||||||
fn scene (&self) -> Option<&Scene> { self.as_ref() }
|
pub trait HasScene: AsRefOpt<Scene> + AsMutOpt<Scene> {
|
||||||
|
fn scene_mut (&mut self) -> Option<&mut Scene> { self.as_mut_opt() }
|
||||||
|
fn scene (&self) -> Option<&Scene> { self.as_ref_opt() }
|
||||||
|
}
|
||||||
|
pub trait HasSelection: AsRef<Selection> + AsMut<Selection> {
|
||||||
|
fn selection (&self) -> &Selection { self.as_ref() }
|
||||||
|
fn selection_mut (&mut self) -> &mut Selection { self.as_mut() }
|
||||||
|
/// Get the active track
|
||||||
|
#[cfg(feature = "track")]
|
||||||
|
fn selected_track (&self) -> Option<&Track> where Self: HasTracks {
|
||||||
|
let index = self.selection().track()?;
|
||||||
|
self.tracks().get(index)
|
||||||
|
}
|
||||||
|
/// Get a mutable reference to the active track
|
||||||
|
#[cfg(feature = "track")]
|
||||||
|
fn selected_track_mut (&mut self) -> Option<&mut Track> where Self: HasTracks {
|
||||||
|
let index = self.selection().track()?;
|
||||||
|
self.tracks_mut().get_mut(index)
|
||||||
|
}
|
||||||
|
/// Get the active scene
|
||||||
|
#[cfg(feature = "scene")]
|
||||||
|
fn selected_scene (&self) -> Option<&Scene> where Self: HasScenes {
|
||||||
|
let index = self.selection().scene()?;
|
||||||
|
self.scenes().get(index)
|
||||||
|
}
|
||||||
|
/// Get a mutable reference to the active scene
|
||||||
|
#[cfg(feature = "scene")]
|
||||||
|
fn selected_scene_mut (&mut self) -> Option<&mut Scene> where Self: HasScenes {
|
||||||
|
let index = self.selection().scene()?;
|
||||||
|
self.scenes_mut().get_mut(index)
|
||||||
|
}
|
||||||
|
/// Get the active clip
|
||||||
|
#[cfg(feature = "clip")]
|
||||||
|
fn selected_clip (&self) -> Option<Arc<RwLock<MidiClip>>> where Self: HasScenes + HasTracks {
|
||||||
|
self.selected_scene()?.clips.get(self.selection().track()?)?.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub trait HasScenes: AsRef<Vec<Scene>> + AsMut<Vec<Scene>> {
|
pub trait HasScenes: AsRef<Vec<Scene>> + AsMut<Vec<Scene>> {
|
||||||
fn scenes (&self) -> &Vec<Scene> { self.as_ref() }
|
fn scenes (&self) -> &Vec<Scene> { self.as_ref() }
|
||||||
|
|
@ -150,12 +181,30 @@ pub trait HasScenes: AsRef<Vec<Scene>> + AsMut<Vec<Scene>> {
|
||||||
/// Generate the default name for a new scene
|
/// Generate the default name for a new scene
|
||||||
fn scene_default_name (&self) -> Arc<str> { format!("s{:3>}", self.scenes().len() + 1).into() }
|
fn scene_default_name (&self) -> Arc<str> { format!("s{:3>}", self.scenes().len() + 1).into() }
|
||||||
fn scene_longest_name (&self) -> usize { self.scenes().iter().map(|s|s.name.len()).fold(0, usize::max) }
|
fn scene_longest_name (&self) -> usize { self.scenes().iter().map(|s|s.name.len()).fold(0, usize::max) }
|
||||||
|
/// Add multiple scenes
|
||||||
|
fn scenes_add (&mut self, n: usize) -> Usually<()> where Self: HasTracks {
|
||||||
|
let scene_color_1 = ItemColor::random();
|
||||||
|
let scene_color_2 = ItemColor::random();
|
||||||
|
for i in 0..n {
|
||||||
|
let _ = self.scene_add(None, Some(
|
||||||
|
scene_color_1.mix(scene_color_2, i as f32 / n as f32).into()
|
||||||
|
))?;
|
||||||
}
|
}
|
||||||
pub trait HasSceneScroll: HasScenes {
|
Ok(())
|
||||||
fn scene_scroll (&self) -> usize;
|
}
|
||||||
|
/// Add a scene
|
||||||
|
fn scene_add (&mut self, name: Option<&str>, color: Option<ItemTheme>)
|
||||||
|
-> Usually<(usize, &mut Scene)> where Self: HasTracks
|
||||||
|
{
|
||||||
|
let scene = Scene {
|
||||||
|
name: name.map_or_else(||self.scene_default_name(), |x|x.to_string().into()),
|
||||||
|
clips: vec![None;self.tracks().len()],
|
||||||
|
color: color.unwrap_or_else(ItemTheme::random),
|
||||||
|
};
|
||||||
|
self.scenes_mut().push(scene);
|
||||||
|
let index = self.scenes().len() - 1;
|
||||||
|
Ok((index, &mut self.scenes_mut()[index]))
|
||||||
}
|
}
|
||||||
pub trait HasTrackScroll: HasTracks {
|
|
||||||
fn track_scroll (&self) -> usize;
|
|
||||||
}
|
}
|
||||||
pub trait HasWidth {
|
pub trait HasWidth {
|
||||||
const MIN_WIDTH: usize;
|
const MIN_WIDTH: usize;
|
||||||
|
|
@ -170,39 +219,26 @@ pub trait HasMidiBuffers {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```
|
/// ```
|
||||||
/// use tek::{MidiEditor, HasEditor, tengri::Has};
|
/// use tek::{*, tengri::*};
|
||||||
///
|
///
|
||||||
/// let mut host = TestEditorHost(Some(MidiEditor::default()));
|
/// struct Test(Option<MidiEditor>);
|
||||||
/// struct TestEditorHost(Option<MidiEditor>);
|
/// impl_as_ref_opt!(MidiEditor: |self: Test|self.0.as_ref());
|
||||||
/// impl AsRef<Option<MidiEditor>> for TestEditorHost {
|
/// impl_as_mut_opt!(MidiEditor: |self: Test|self.0.as_mut());
|
||||||
/// fn get (&self) -> &Option<MidiEditor> { &self.0 }
|
|
||||||
/// fn get_mut (&mut self) -> &mut Option<MidiEditor> { &mut self.0 }
|
|
||||||
/// }
|
|
||||||
///
|
///
|
||||||
|
/// let mut host = Test(Some(MidiEditor::default()));
|
||||||
/// let _ = host.editor();
|
/// let _ = host.editor();
|
||||||
/// let _ = host.editor_mut();
|
/// let _ = host.editor_mut();
|
||||||
/// let _ = host.is_editing();
|
/// let _ = host.is_editing();
|
||||||
/// let _ = host.editor_w();
|
/// let _ = host.editor_w();
|
||||||
/// let _ = host.editor_h();
|
/// let _ = host.editor_h();
|
||||||
/// ```
|
/// ```
|
||||||
pub trait HasEditor: AsRef<Option<MidiEditor>> {
|
pub trait HasEditor: AsRefOpt<MidiEditor> + AsMutOpt<MidiEditor> {
|
||||||
fn editor (&self) -> Option<&MidiEditor> {
|
fn editor (&self) -> Option<&MidiEditor> { self.as_ref_opt() }
|
||||||
self.get().as_ref()
|
fn editor_mut (&mut self) -> Option<&mut MidiEditor> { self.as_mut_opt() }
|
||||||
|
fn is_editing (&self) -> bool { self.editor().is_some() }
|
||||||
|
fn editor_w (&self) -> usize { self.editor().map(|e|e.size.w()).unwrap_or(0) as usize }
|
||||||
|
fn editor_h (&self) -> usize { self.editor().map(|e|e.size.h()).unwrap_or(0) as usize }
|
||||||
}
|
}
|
||||||
fn editor_mut (&mut self) -> Option<&mut MidiEditor> {
|
|
||||||
self.get_mut().as_mut()
|
|
||||||
}
|
|
||||||
fn is_editing (&self) -> bool {
|
|
||||||
self.editor().is_some()
|
|
||||||
}
|
|
||||||
fn editor_w (&self) -> usize {
|
|
||||||
self.editor().map(|e|e.size.w()).unwrap_or(0) as usize
|
|
||||||
}
|
|
||||||
fn editor_h (&self) -> usize {
|
|
||||||
self.editor().map(|e|e.size.h()).unwrap_or(0) as usize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait HasClips {
|
pub trait HasClips {
|
||||||
fn clips <'a> (&'a self) -> std::sync::RwLockReadGuard<'a, ClipPool>;
|
fn clips <'a> (&'a self) -> std::sync::RwLockReadGuard<'a, ClipPool>;
|
||||||
fn clips_mut <'a> (&'a self) -> std::sync::RwLockWriteGuard<'a, ClipPool>;
|
fn clips_mut <'a> (&'a self) -> std::sync::RwLockWriteGuard<'a, ClipPool>;
|
||||||
|
|
@ -212,7 +248,6 @@ pub trait HasClips {
|
||||||
(self.clips().len() - 1, clip)
|
(self.clips().len() - 1, clip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for thing that may receive MIDI.
|
/// Trait for thing that may receive MIDI.
|
||||||
pub trait HasMidiIns {
|
pub trait HasMidiIns {
|
||||||
fn midi_ins (&self) -> &Vec<MidiInput>;
|
fn midi_ins (&self) -> &Vec<MidiInput>;
|
||||||
|
|
@ -237,7 +272,6 @@ pub trait HasMidiIns {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for thing that may output MIDI.
|
/// Trait for thing that may output MIDI.
|
||||||
pub trait HasMidiOuts {
|
pub trait HasMidiOuts {
|
||||||
fn midi_outs (&self) -> &Vec<MidiOutput>;
|
fn midi_outs (&self) -> &Vec<MidiOutput>;
|
||||||
|
|
@ -259,9 +293,7 @@ pub trait HasMidiOuts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub trait HasTracks: AsRef<Vec<Track>> + AsMut<Vec<Track>> {
|
||||||
impl<T: AsRef<Vec<Track>> + AsMut<Vec<Track>> + Send + Sync> HasTracks for T {}
|
|
||||||
pub trait HasTracks: AsRef<Vec<Track>> + AsMut<Vec<Track>> + Send + Sync {
|
|
||||||
fn tracks (&self) -> &Vec<Track> { self.as_ref() }
|
fn tracks (&self) -> &Vec<Track> { self.as_ref() }
|
||||||
fn tracks_mut (&mut self) -> &mut Vec<Track> { self.as_mut() }
|
fn tracks_mut (&mut self) -> &mut Vec<Track> { self.as_mut() }
|
||||||
/// Run audio callbacks for every track and every device
|
/// Run audio callbacks for every track and every device
|
||||||
|
|
@ -292,10 +324,9 @@ pub trait HasTracks: AsRef<Vec<Track>> + AsMut<Vec<Track>> + Send + Sync {
|
||||||
/// Spacing between tracks.
|
/// Spacing between tracks.
|
||||||
const TRACK_SPACING: usize = 0;
|
const TRACK_SPACING: usize = 0;
|
||||||
}
|
}
|
||||||
|
pub trait HasTrack: AsRefOpt<Track> + AsMutOpt<Track> {
|
||||||
pub trait HasTrack {
|
fn track (&self) -> Option<&Track> { self.as_ref_opt() }
|
||||||
fn track (&self) -> Option<&Track>;
|
fn track_mut (&mut self) -> Option<&mut Track> { self.as_mut_opt() }
|
||||||
fn track_mut (&mut self) -> Option<&mut Track>;
|
|
||||||
#[cfg(feature = "port")] fn view_midi_ins_status <'a> (&'a self, theme: ItemTheme) -> impl Content<TuiOut> + 'a {
|
#[cfg(feature = "port")] fn view_midi_ins_status <'a> (&'a self, theme: ItemTheme) -> impl Content<TuiOut> + 'a {
|
||||||
self.track().map(move|track|view_ports_status(theme, "MIDI ins: ", &track.sequencer.midi_ins))
|
self.track().map(move|track|view_ports_status(theme, "MIDI ins: ", &track.sequencer.midi_ins))
|
||||||
}
|
}
|
||||||
|
|
@ -523,33 +554,6 @@ pub trait MidiViewer: Measured<TuiOut> + MidiRange + MidiPoint + Debug + Send +
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AddScene: HasScenes + HasTracks {
|
|
||||||
/// Add multiple scenes
|
|
||||||
fn scenes_add (&mut self, n: usize) -> Usually<()> {
|
|
||||||
let scene_color_1 = ItemColor::random();
|
|
||||||
let scene_color_2 = ItemColor::random();
|
|
||||||
for i in 0..n {
|
|
||||||
let _ = self.scene_add(None, Some(
|
|
||||||
scene_color_1.mix(scene_color_2, i as f32 / n as f32).into()
|
|
||||||
))?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// Add a scene
|
|
||||||
fn scene_add (&mut self, name: Option<&str>, color: Option<ItemTheme>)
|
|
||||||
-> Usually<(usize, &mut Scene)>
|
|
||||||
{
|
|
||||||
let scene = Scene {
|
|
||||||
name: name.map_or_else(||self.scene_default_name(), |x|x.to_string().into()),
|
|
||||||
clips: vec![None;self.tracks().len()],
|
|
||||||
color: color.unwrap_or_else(ItemTheme::random),
|
|
||||||
};
|
|
||||||
self.scenes_mut().push(scene);
|
|
||||||
let index = self.scenes().len() - 1;
|
|
||||||
Ok((index, &mut self.scenes_mut()[index]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ClipsView: TracksView + ScenesView {
|
pub trait ClipsView: TracksView + ScenesView {
|
||||||
|
|
||||||
fn view_scenes_clips <'a> (&'a self)
|
fn view_scenes_clips <'a> (&'a self)
|
||||||
|
|
|
||||||
2
tengri
2
tengri
|
|
@ -1 +1 @@
|
||||||
Subproject commit c1b727bafc27dc715d7239a0bc63a1cdfe962bc2
|
Subproject commit d1c08df5351ce8c3913723602a05268d593c9a45
|
||||||
Loading…
Add table
Add a link
Reference in a new issue