mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-02-21 16:29:04 +01:00
This commit is contained in:
parent
abf950aea4
commit
817d2a722c
7 changed files with 214 additions and 217 deletions
|
|
@ -991,3 +991,88 @@
|
|||
//})),
|
||||
//take!(TrackCommand |state: Arrangement, iter|state.selected_track().as_ref()
|
||||
//.map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten()));
|
||||
|
||||
|
||||
//macro_rules! impl_port {
|
||||
//($Name:ident : $Spec:ident -> $Pair:ident |$jack:ident, $name:ident|$port:expr) => {
|
||||
//#[derive(Debug)] pub struct $Name {
|
||||
///// Handle to JACK client, for receiving reconnect events.
|
||||
//jack: Jack<'static>,
|
||||
///// Port name
|
||||
//name: Arc<str>,
|
||||
///// Port handle.
|
||||
//port: Port<$Spec>,
|
||||
///// List of ports to connect to.
|
||||
//conn: Vec<PortConnect>
|
||||
//}
|
||||
//impl AsRef<Port<$Spec>> for $Name {
|
||||
//fn as_ref (&self) -> &Port<$Spec> { &self.port }
|
||||
//}
|
||||
//impl $Name {
|
||||
//pub fn new ($jack: &Jack, name: impl AsRef<str>, connect: &[PortConnect])
|
||||
//-> Usually<Self>
|
||||
//{
|
||||
//let $name = name.as_ref();
|
||||
//let jack = $jack.clone();
|
||||
//let port = $port?;
|
||||
//let name = $name.into();
|
||||
//let conn = connect.to_vec();
|
||||
//let port = Self { jack, port, name, conn };
|
||||
//port.connect_to_matching()?;
|
||||
//Ok(port)
|
||||
//}
|
||||
//pub fn name (&self) -> &Arc<str> { &self.name }
|
||||
//pub fn port (&self) -> &Port<$Spec> { &self.port }
|
||||
//pub fn port_mut (&mut self) -> &mut Port<$Spec> { &mut self.port }
|
||||
//pub fn into_port (self) -> Port<$Spec> { self.port }
|
||||
//pub fn close (self) -> Usually<()> {
|
||||
//let Self { jack, port, .. } = self;
|
||||
//Ok(jack.with_client(|client|client.unregister_port(port))?)
|
||||
//}
|
||||
//}
|
||||
//impl HasJack<'static> for $Name {
|
||||
//fn jack (&self) -> &'static Jack<'static> { &self.jack }
|
||||
//}
|
||||
//impl JackPort<'static> for $Name {
|
||||
//type Port = $Spec;
|
||||
//type Pair = $Pair;
|
||||
//fn port (&self) -> &Port<$Spec> { &self.port }
|
||||
//}
|
||||
//impl ConnectTo<'static, &str> for $Name {
|
||||
//fn connect_to (&self, to: &str) -> Usually<PortConnectStatus> {
|
||||
//self.with_client(|c|if let Some(ref port) = c.port_by_name(to.as_ref()) {
|
||||
//self.connect_to(port)
|
||||
//} else {
|
||||
//Ok(Missing)
|
||||
//})
|
||||
//}
|
||||
//}
|
||||
//impl ConnectTo<'static, &Port<Unowned>> for $Name {
|
||||
//fn connect_to (&self, port: &Port<Unowned>) -> Usually<PortConnectStatus> {
|
||||
//self.with_client(|c|Ok(if let Ok(_) = c.connect_ports(&self.port, port) {
|
||||
//Connected
|
||||
//} else if let Ok(_) = c.connect_ports(port, &self.port) {
|
||||
//Connected
|
||||
//} else {
|
||||
//Mismatch
|
||||
//}))
|
||||
//}
|
||||
//}
|
||||
//impl ConnectTo<'static, &Port<$Pair>> for $Name {
|
||||
//fn connect_to (&self, port: &Port<$Pair>) -> Usually<PortConnectStatus> {
|
||||
//self.with_client(|c|Ok(if let Ok(_) = c.connect_ports(&self.port, port) {
|
||||
//Connected
|
||||
//} else if let Ok(_) = c.connect_ports(port, &self.port) {
|
||||
//Connected
|
||||
//} else {
|
||||
//Mismatch
|
||||
//}))
|
||||
//}
|
||||
//}
|
||||
//impl ConnectAuto<'static> for $Name {
|
||||
//fn connections (&self) -> &[PortConnect] {
|
||||
//&self.conn
|
||||
//}
|
||||
//}
|
||||
//};
|
||||
//}
|
||||
|
|
|
|||
205
app/tek.rs
205
app/tek.rs
|
|
@ -7,21 +7,10 @@
|
|||
trait_alias,
|
||||
type_alias_impl_trait,
|
||||
type_changing_struct_update)]
|
||||
|
||||
#[allow(unused)] pub(crate) use ::{
|
||||
std::{
|
||||
cmp::Ord,
|
||||
collections::BTreeMap,
|
||||
error::Error,
|
||||
ffi::OsString,
|
||||
fmt::{Write, Debug, Formatter},
|
||||
fs::File,
|
||||
ops::{Add, Sub, Mul, Div, Rem},
|
||||
path::{Path, PathBuf},
|
||||
sync::{Arc, RwLock, atomic::{AtomicBool, AtomicUsize, Ordering::Relaxed}},
|
||||
thread::{spawn, JoinHandle},
|
||||
},
|
||||
};
|
||||
mod tek_struct; pub use self::tek_struct::*;
|
||||
mod tek_trait; pub use self::tek_trait::*;
|
||||
mod tek_type; pub use self::tek_type::*;
|
||||
mod tek_impls;
|
||||
extern crate xdg;
|
||||
pub(crate) use ::xdg::BaseDirectories;
|
||||
pub extern crate atomic_float;
|
||||
|
|
@ -44,15 +33,11 @@ pub(crate) use tengri::{
|
|||
},
|
||||
};
|
||||
#[cfg(feature = "sampler")] pub(crate) use symphonia::{
|
||||
core::{
|
||||
formats::Packet,
|
||||
codecs::{Decoder, CODEC_TYPE_NULL},
|
||||
//errors::Error as SymphoniaError,
|
||||
io::MediaSourceStream,
|
||||
probe::Hint,
|
||||
audio::SampleBuffer,
|
||||
},
|
||||
default::get_codecs,
|
||||
core::{//errors::Error as SymphoniaError,
|
||||
audio::SampleBuffer, formats::Packet, io::MediaSourceStream, probe::Hint,
|
||||
codecs::{Decoder, CODEC_TYPE_NULL},
|
||||
},
|
||||
};
|
||||
#[cfg(feature = "lv2_gui")] use ::winit::{
|
||||
application::ApplicationHandler,
|
||||
|
|
@ -61,19 +46,20 @@ pub(crate) use tengri::{
|
|||
window::{Window, WindowId},
|
||||
platform::x11::EventLoopBuilderExtX11
|
||||
};
|
||||
|
||||
#[cfg(test)] mod tek_test;
|
||||
|
||||
mod tek_struct;
|
||||
pub use self::tek_struct::*;
|
||||
|
||||
mod tek_trait;
|
||||
pub use self::tek_trait::*;
|
||||
|
||||
mod tek_type;
|
||||
pub use self::tek_type::*;
|
||||
|
||||
mod tek_impls;
|
||||
#[allow(unused)] pub(crate) use ::{
|
||||
std::{
|
||||
cmp::Ord,
|
||||
collections::BTreeMap,
|
||||
error::Error,
|
||||
ffi::OsString,
|
||||
fmt::{Write, Debug, Formatter},
|
||||
fs::File,
|
||||
ops::{Add, Sub, Mul, Div, Rem},
|
||||
path::{Path, PathBuf},
|
||||
sync::{Arc, RwLock, atomic::{AtomicBool, AtomicUsize, Ordering::Relaxed}},
|
||||
thread::{spawn, JoinHandle},
|
||||
},
|
||||
};
|
||||
|
||||
pub(crate) use ConnectName::*;
|
||||
pub(crate) use ConnectScope::*;
|
||||
|
|
@ -92,23 +78,23 @@ pub(crate) use JackState::*;
|
|||
/// let jack = tek::Jack::new(&"test_tek").expect("failed to connect to jack");
|
||||
/// let proj = Default::default();
|
||||
/// let conf = Default::default();
|
||||
/// let tek = tek::tek(&jack, proj, conf, "");
|
||||
/// let tek = tek::tek(&jack, proj, conf, "mode-doctest");
|
||||
/// ```
|
||||
pub fn tek (
|
||||
jack: &Jack<'static>, project: Arrangement, config: Config, mode: impl AsRef<str>
|
||||
) -> App {
|
||||
let mode: &str = mode.as_ref();
|
||||
App {
|
||||
color: ItemTheme::random(),
|
||||
dialog: Dialog::welcome(),
|
||||
jack: jack.clone(),
|
||||
mode: config.get_mode(mode).expect("failed to find mode"),
|
||||
mode: config.get_mode(mode).expect(&format!("failed to find mode '{mode}'")),
|
||||
config,
|
||||
project,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn tek_confirm (state: &mut App) -> Perhaps<AppCommand> {
|
||||
Ok(match &state.dialog {
|
||||
Dialog::Menu(index, items) => {
|
||||
|
|
@ -202,6 +188,7 @@ fn collect_commands (
|
|||
}
|
||||
Ok(commands)
|
||||
}
|
||||
|
||||
fn execute_commands (
|
||||
app: &mut App, commands: Vec<AppCommand>
|
||||
) -> Usually<Vec<(AppCommand, Option<AppCommand>)>> {
|
||||
|
|
@ -213,6 +200,7 @@ fn execute_commands (
|
|||
}
|
||||
Ok(history)
|
||||
}
|
||||
|
||||
pub fn tek_jack_process (app: &mut App, client: &Client, scope: &ProcessScope) -> Control {
|
||||
let t0 = app.perf.get_t0();
|
||||
app.clock().update_from_scope(scope).unwrap();
|
||||
|
|
@ -236,6 +224,7 @@ pub fn tek_jack_process (app: &mut App, client: &Client, scope: &ProcessScope) -
|
|||
app.perf.update_from_jack_scope(t0, scope);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn tek_jack_event (app: &mut App, event: JackEvent) {
|
||||
use JackEvent::*;
|
||||
match event {
|
||||
|
|
@ -258,9 +247,11 @@ pub fn tek_jack_event (app: &mut App, event: JackEvent) {
|
|||
_ => { panic!("{event:?}"); }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tek_show_version () {
|
||||
println!("todo version");
|
||||
}
|
||||
|
||||
pub fn tek_print_config (config: &Config) {
|
||||
use ::ansi_term::Color::*;
|
||||
println!("{:?}", config.dirs);
|
||||
|
|
@ -313,6 +304,7 @@ pub fn tek_print_config (config: &Config) {
|
|||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tek_print_status (project: &Arrangement) {
|
||||
println!("Name: {:?}", &project.name);
|
||||
println!("JACK: {:?}", &project.jack);
|
||||
|
|
@ -432,94 +424,6 @@ pub fn note_pitch_to_name (n: usize) -> &'static str {
|
|||
NOTE_NAMES[n]
|
||||
}
|
||||
|
||||
|
||||
//macro_rules! impl_port {
|
||||
//($Name:ident : $Spec:ident -> $Pair:ident |$jack:ident, $name:ident|$port:expr) => {
|
||||
//#[derive(Debug)] pub struct $Name {
|
||||
///// Handle to JACK client, for receiving reconnect events.
|
||||
//jack: Jack<'static>,
|
||||
///// Port name
|
||||
//name: Arc<str>,
|
||||
///// Port handle.
|
||||
//port: Port<$Spec>,
|
||||
///// List of ports to connect to.
|
||||
//conn: Vec<PortConnect>
|
||||
//}
|
||||
//impl AsRef<Port<$Spec>> for $Name {
|
||||
//fn as_ref (&self) -> &Port<$Spec> { &self.port }
|
||||
//}
|
||||
//impl $Name {
|
||||
//pub fn new ($jack: &Jack, name: impl AsRef<str>, connect: &[PortConnect])
|
||||
//-> Usually<Self>
|
||||
//{
|
||||
//let $name = name.as_ref();
|
||||
//let jack = $jack.clone();
|
||||
//let port = $port?;
|
||||
//let name = $name.into();
|
||||
//let conn = connect.to_vec();
|
||||
//let port = Self { jack, port, name, conn };
|
||||
//port.connect_to_matching()?;
|
||||
//Ok(port)
|
||||
//}
|
||||
//pub fn name (&self) -> &Arc<str> { &self.name }
|
||||
//pub fn port (&self) -> &Port<$Spec> { &self.port }
|
||||
//pub fn port_mut (&mut self) -> &mut Port<$Spec> { &mut self.port }
|
||||
//pub fn into_port (self) -> Port<$Spec> { self.port }
|
||||
//pub fn close (self) -> Usually<()> {
|
||||
//let Self { jack, port, .. } = self;
|
||||
//Ok(jack.with_client(|client|client.unregister_port(port))?)
|
||||
//}
|
||||
//}
|
||||
//impl HasJack<'static> for $Name {
|
||||
//fn jack (&self) -> &'static Jack<'static> { &self.jack }
|
||||
//}
|
||||
//impl JackPort<'static> for $Name {
|
||||
//type Port = $Spec;
|
||||
//type Pair = $Pair;
|
||||
//fn port (&self) -> &Port<$Spec> { &self.port }
|
||||
//}
|
||||
//impl ConnectTo<'static, &str> for $Name {
|
||||
//fn connect_to (&self, to: &str) -> Usually<PortConnectStatus> {
|
||||
//self.with_client(|c|if let Some(ref port) = c.port_by_name(to.as_ref()) {
|
||||
//self.connect_to(port)
|
||||
//} else {
|
||||
//Ok(Missing)
|
||||
//})
|
||||
//}
|
||||
//}
|
||||
//impl ConnectTo<'static, &Port<Unowned>> for $Name {
|
||||
//fn connect_to (&self, port: &Port<Unowned>) -> Usually<PortConnectStatus> {
|
||||
//self.with_client(|c|Ok(if let Ok(_) = c.connect_ports(&self.port, port) {
|
||||
//Connected
|
||||
//} else if let Ok(_) = c.connect_ports(port, &self.port) {
|
||||
//Connected
|
||||
//} else {
|
||||
//Mismatch
|
||||
//}))
|
||||
//}
|
||||
//}
|
||||
//impl ConnectTo<'static, &Port<$Pair>> for $Name {
|
||||
//fn connect_to (&self, port: &Port<$Pair>) -> Usually<PortConnectStatus> {
|
||||
//self.with_client(|c|Ok(if let Ok(_) = c.connect_ports(&self.port, port) {
|
||||
//Connected
|
||||
//} else if let Ok(_) = c.connect_ports(port, &self.port) {
|
||||
//Connected
|
||||
//} else {
|
||||
//Mismatch
|
||||
//}))
|
||||
//}
|
||||
//}
|
||||
//impl ConnectAuto<'static> for $Name {
|
||||
//fn connections (&self) -> &[PortConnect] {
|
||||
//&self.conn
|
||||
//}
|
||||
//}
|
||||
//};
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
pub fn swap_value <T: Clone + PartialEq, U> (
|
||||
target: &mut T, value: &T, returned: impl Fn(T)->U
|
||||
) -> Perhaps<U> {
|
||||
|
|
@ -1104,10 +1008,13 @@ mod size {
|
|||
def_sizes_iter!(TracksSizes => Track);
|
||||
}
|
||||
|
||||
pub(crate) use self::view::*;
|
||||
pub use self::view::*;
|
||||
mod view {
|
||||
use crate::*;
|
||||
|
||||
/// ```
|
||||
/// let _ = tek::view_logo();
|
||||
/// ```
|
||||
pub fn view_logo () -> impl Content<TuiOut> {
|
||||
Fixed::XY(32, 7, Tui::bold(true, Tui::fg(Rgb(240,200,180), col!{
|
||||
Fixed::Y(1, ""),
|
||||
|
|
@ -1118,6 +1025,11 @@ mod view {
|
|||
})))
|
||||
}
|
||||
|
||||
/// ```
|
||||
/// let x = std::sync::Arc::<std::sync::RwLock<String>>::default();
|
||||
/// let _ = tek::view_transport(true, x.clone(), x.clone(), x.clone());
|
||||
/// let _ = tek::view_transport(false, x.clone(), x.clone(), x.clone());
|
||||
/// ```
|
||||
pub fn view_transport (
|
||||
play: bool,
|
||||
bpm: Arc<RwLock<String>>,
|
||||
|
|
@ -1135,6 +1047,11 @@ mod view {
|
|||
)))
|
||||
}
|
||||
|
||||
/// ```
|
||||
/// let x = std::sync::Arc::<std::sync::RwLock<String>>::default();
|
||||
/// let _ = tek::view_status(None, x.clone(), x.clone(), x.clone());
|
||||
/// let _ = tek::view_status(Some("".into()), x.clone(), x.clone(), x.clone());
|
||||
/// ```
|
||||
pub fn view_status (
|
||||
sel: Option<Arc<str>>,
|
||||
sr: Arc<RwLock<String>>,
|
||||
|
|
@ -1152,6 +1069,9 @@ mod view {
|
|||
)))
|
||||
}
|
||||
|
||||
/// ```
|
||||
/// let _ = tek::button_play_pause(true);
|
||||
/// ```
|
||||
pub fn button_play_pause (playing: bool) -> impl Content<TuiOut> {
|
||||
let compact = true;//self.is_editing();
|
||||
Tui::bg(if playing { Rgb(0, 128, 0) } else { Rgb(128, 64, 0) },
|
||||
|
|
@ -1178,12 +1098,21 @@ mod view {
|
|||
Bsp::e(Fixed::X(20, Fill::Y(Align::nw(button))), Fill::XY(Align::c(content))))
|
||||
}
|
||||
|
||||
pub fn wrap (bg: Color, fg: Color, content: impl Content<TuiOut>) -> impl Content<TuiOut> {
|
||||
/// ```
|
||||
/// let bg = tengri::ratatui::style::Color::Red;
|
||||
/// let fg = tengri::ratatui::style::Color::Green;
|
||||
/// let _ = tek::view_wrap(bg, fg, "and then blue, too!");
|
||||
/// ```
|
||||
pub fn view_wrap (bg: Color, fg: Color, content: impl Content<TuiOut>) -> impl Content<TuiOut> {
|
||||
let left = Tui::fg_bg(bg, Reset, Fixed::X(1, Repeat::Y("▐")));
|
||||
let right = Tui::fg_bg(bg, Reset, Fixed::X(1, Repeat::Y("▌")));
|
||||
Bsp::e(left, Bsp::w(right, Tui::fg_bg(fg, bg, content)))
|
||||
}
|
||||
|
||||
/// ```
|
||||
/// let _ = tek::view_meter("", 0.0);
|
||||
/// let _ = tek::view_meters(&[0.0, 0.0]);
|
||||
/// ```
|
||||
pub fn view_meter <'a> (label: &'a str, value: f32) -> impl Content<TuiOut> + 'a {
|
||||
col!(
|
||||
FieldH(ItemTheme::G[128], label, format!("{:>+9.3}", value)),
|
||||
|
|
@ -1331,3 +1260,21 @@ mod view {
|
|||
Ok(label1.len() + label2.len() + 4)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)] mod test_view_meter {
|
||||
use super::*;
|
||||
use proptest::prelude::*;
|
||||
proptest! {
|
||||
#[test] fn proptest_view_meter (
|
||||
label in "\\PC*", value in f32::MIN..f32::MAX
|
||||
) {
|
||||
let _ = view_meter(&label, value);
|
||||
}
|
||||
#[test] fn proptest_view_meters (
|
||||
value1 in f32::MIN..f32::MAX,
|
||||
value2 in f32::MIN..f32::MAX
|
||||
) {
|
||||
let _ = view_meters(&[value1, value2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -894,8 +894,8 @@ impl Timebase {
|
|||
/// Specify sample rate, BPM and PPQ
|
||||
pub fn new (
|
||||
s: impl Into<SampleRate>,
|
||||
b: impl Into<BeatsPerMinute>,
|
||||
p: impl Into<PulsesPerQuaver>
|
||||
b: impl Into<Bpm>,
|
||||
p: impl Into<Ppq>
|
||||
) -> Self {
|
||||
Self { sr: s.into(), bpm: b.into(), ppq: p.into() }
|
||||
}
|
||||
|
|
@ -1077,9 +1077,9 @@ impl_time_unit!(SampleCount);
|
|||
impl_time_unit!(SampleRate);
|
||||
impl_time_unit!(Microsecond);
|
||||
impl_time_unit!(Quantize);
|
||||
impl_time_unit!(PulsesPerQuaver);
|
||||
impl_time_unit!(Ppq);
|
||||
impl_time_unit!(Pulse);
|
||||
impl_time_unit!(BeatsPerMinute);
|
||||
impl_time_unit!(Bpm);
|
||||
impl_time_unit!(LaunchSync);
|
||||
|
||||
/// Implement [Jack] constructor and methods
|
||||
|
|
@ -1769,11 +1769,11 @@ impl Clock {
|
|||
&self.timebase.sr
|
||||
}
|
||||
/// Current tempo
|
||||
pub fn bpm (&self) -> &BeatsPerMinute {
|
||||
pub fn bpm (&self) -> &Bpm {
|
||||
&self.timebase.bpm
|
||||
}
|
||||
/// Current MIDI resolution
|
||||
pub fn ppq (&self) -> &PulsesPerQuaver {
|
||||
pub fn ppq (&self) -> &Ppq {
|
||||
&self.timebase.ppq
|
||||
}
|
||||
/// Next pulse that matches launch sync (for phrase switchover)
|
||||
|
|
@ -3856,7 +3856,7 @@ fn sampler_jack_process (
|
|||
|
||||
/// Create [Voice]s from [Sample]s in response to MIDI input.
|
||||
fn sampler_midi_in (
|
||||
samples: &Samples<128>, voices: &Arc<RwLock<Vec<Voice>>>, RawMidi { time, bytes }: RawMidi
|
||||
samples: &SampleKit<128>, voices: &Arc<RwLock<Vec<Voice>>>, RawMidi { time, bytes }: RawMidi
|
||||
) {
|
||||
if let Ok(LiveEvent::Midi { message, .. }) = LiveEvent::parse(bytes) {
|
||||
match message {
|
||||
|
|
@ -4438,7 +4438,7 @@ impl Track {
|
|||
}
|
||||
|
||||
|
||||
impl<const N: usize> Samples<N> {
|
||||
impl<const N: usize> SampleKit<N> {
|
||||
fn get (&self, index: usize) -> &Option<Arc<RwLock<Sample>>> {
|
||||
if index < self.0.len() {
|
||||
&self.0[index]
|
||||
|
|
@ -4448,7 +4448,7 @@ impl<const N: usize> Samples<N> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Default for Samples<N> {
|
||||
impl<const N: usize> Default for SampleKit<N> {
|
||||
fn default () -> Self {
|
||||
Self([const { None }; N])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,22 @@ pub struct JackNotify<T: Fn(JackEvent) + Send>(pub T);
|
|||
/// Configuration: mode, view, and bind definitions.
|
||||
///
|
||||
/// ```
|
||||
/// let conf = tek::Config::default();
|
||||
/// let config = tek::Config::default();
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// // Some dizzle.
|
||||
/// // What indentation to use here lol?
|
||||
/// let source = stringify!((mode :menu (name Menu)
|
||||
/// (info Mode selector.) (keys :axis/y :confirm)
|
||||
/// (view (bg (g 0) (bsp/s :ports/out
|
||||
/// (bsp/n :ports/in
|
||||
/// (bg (g 30) (bsp/s (fixed/y 7 :logo)
|
||||
/// (fill :dialog/menu)))))))));
|
||||
/// // Add this definition to the config and try to load it.
|
||||
/// // A "mode" is basically a state machine
|
||||
/// // with associated input and output definitions.
|
||||
/// tek::Config::default().add(&source).unwrap().get_mode(":menu").unwrap();
|
||||
/// ```
|
||||
#[derive(Default, Debug)] pub struct Config {
|
||||
/// XDG base directories of running user.
|
||||
|
|
@ -293,9 +308,9 @@ pub struct JackNotify<T: Fn(JackEvent) + Send>(pub T);
|
|||
/// Audio samples per second
|
||||
pub sr: SampleRate,
|
||||
/// MIDI beats per minute
|
||||
pub bpm: BeatsPerMinute,
|
||||
pub bpm: Bpm,
|
||||
/// MIDI ticks per beat
|
||||
pub ppq: PulsesPerQuaver,
|
||||
pub ppq: Ppq,
|
||||
}
|
||||
|
||||
/// Iterator that emits subsequent ticks within a range.
|
||||
|
|
@ -387,7 +402,7 @@ pub struct JackNotify<T: Fn(JackEvent) + Send>(pub T);
|
|||
/// ```
|
||||
///
|
||||
/// ```
|
||||
#[derive(Debug, Default)] pub struct PulsesPerQuaver (pub(crate) AtomicF64);
|
||||
#[derive(Debug, Default)] pub struct Ppq (pub(crate) AtomicF64);
|
||||
|
||||
/// Timestamp in MIDI pulses
|
||||
///
|
||||
|
|
@ -401,7 +416,7 @@ pub struct JackNotify<T: Fn(JackEvent) + Send>(pub T);
|
|||
/// ```
|
||||
///
|
||||
/// ```
|
||||
#[derive(Debug, Default)] pub struct BeatsPerMinute (pub(crate) AtomicF64);
|
||||
#[derive(Debug, Default)] pub struct Bpm (pub(crate) AtomicF64);
|
||||
|
||||
/// Quantization setting for launching clips
|
||||
///
|
||||
|
|
@ -828,7 +843,7 @@ pub struct PoolView<'a>(pub &'a Pool);
|
|||
/// Recording buffer.
|
||||
pub buffer: Vec<Vec<f32>>,
|
||||
/// Samples mapped to MIDI notes.
|
||||
pub samples: Samples<128>,
|
||||
pub samples: SampleKit<128>,
|
||||
/// Samples that are not mapped to MIDI notes.
|
||||
pub unmapped: Vec<Arc<RwLock<Sample>>>,
|
||||
/// Sample currently being edited.
|
||||
|
|
@ -861,14 +876,12 @@ pub struct PoolView<'a>(pub &'a Pool);
|
|||
|
||||
/// Collection of samples, one per slot, fixed number of slots.
|
||||
///
|
||||
/// TODO: Map more than one sample per slot.
|
||||
///
|
||||
/// History: Separated to cleanly implement [Default].
|
||||
///
|
||||
/// ```
|
||||
/// let samples = tek::Samples([None, None, None, None]);
|
||||
/// let samples = tek::SampleKit([None, None, None, None]);
|
||||
/// ```
|
||||
#[derive(Debug)] pub struct Samples<const N: usize>(
|
||||
#[derive(Debug)] pub struct SampleKit<const N: usize>(
|
||||
pub [Option<Arc<RwLock<Sample>>>;N]
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
#[cfg(test)] #[test] fn test_menu () -> Usually<()> {
|
||||
|
||||
// Some dizzle.
|
||||
// What indentation to use here lol?
|
||||
let source = stringify!((mode :menu
|
||||
(name Menu)
|
||||
(info Mode selector.)
|
||||
(keys :axis/y :confirm)
|
||||
(view (bg (g 0) (bsp/s
|
||||
:ports/out
|
||||
(bsp/n
|
||||
:ports/in
|
||||
(bg (g 30) (bsp/s
|
||||
(fixed/y 7 :logo)
|
||||
(fill :dialog/menu)))))))));
|
||||
|
||||
// Load this definition into the config.
|
||||
// A "mode" is basically a state machine
|
||||
// with associated input and output definitions.
|
||||
let mode = Config::new(None).add(&source)?.get_mode(":menu");
|
||||
|
||||
Ok(())
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)] #[test] fn test_view_layout () {
|
||||
let _ = button_play_pause(true);
|
||||
let _ = button_2("", "", true);
|
||||
let _ = button_2("", "", false);
|
||||
let _ = button_3("", "", "", true);
|
||||
let _ = button_3("", "", "", false);
|
||||
//let _ = heading("", "", 0, "", true);
|
||||
//let _ = heading("", "", 0, "", false);
|
||||
let _ = wrap(Reset, Reset, "");
|
||||
}
|
||||
|
||||
#[cfg(test)] mod test_view_meter {
|
||||
use super::*;
|
||||
use proptest::prelude::*;
|
||||
#[test] fn test_view_meter () {
|
||||
let _ = view_meter("", 0.0);
|
||||
let _ = view_meters(&[0.0, 0.0]);
|
||||
}
|
||||
proptest! {
|
||||
#[test] fn proptest_view_meter (
|
||||
label in "\\PC*", value in f32::MIN..f32::MAX
|
||||
) {
|
||||
let _ = view_meter(&label, value);
|
||||
}
|
||||
#[test] fn proptest_view_meters (
|
||||
value1 in f32::MIN..f32::MAX,
|
||||
value2 in f32::MIN..f32::MAX
|
||||
) {
|
||||
let _ = view_meters(&[value1, value2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)] #[test] fn test_midi_edit () {
|
||||
}
|
||||
|
|
@ -849,19 +849,13 @@ pub trait TracksView: ScenesView + HasMidiIns + HasMidiOuts + HasTrackScroll + M
|
|||
}
|
||||
|
||||
pub trait ScenesView: HasEditor + HasSelection + HasSceneScroll + HasClipsSize + Send + Sync {
|
||||
|
||||
/// Default scene height.
|
||||
const H_SCENE: usize = 2;
|
||||
|
||||
/// Default editor height.
|
||||
const H_EDITOR: usize = 15;
|
||||
|
||||
fn h_scenes (&self) -> u16;
|
||||
|
||||
fn w_side (&self) -> u16;
|
||||
|
||||
fn w_mid (&self) -> u16;
|
||||
|
||||
fn scenes_with_sizes (&self) -> impl ScenesSizes<'_> {
|
||||
let mut y = 0;
|
||||
self.scenes().iter().enumerate().skip(self.scene_scroll()).map_while(move|(s, scene)|{
|
||||
|
|
@ -930,32 +924,46 @@ pub trait RegisterPorts: HasJack<'static> {
|
|||
}
|
||||
|
||||
pub trait JackPort: HasJack<'static> {
|
||||
|
||||
type Port: PortSpec + Default;
|
||||
|
||||
type Pair: PortSpec + Default;
|
||||
|
||||
fn new (jack: &Jack<'static>, name: &impl AsRef<str>, connect: &[Connect])
|
||||
-> Usually<Self> where Self: Sized;
|
||||
|
||||
fn register (jack: &Jack<'static>, name: &impl AsRef<str>) -> Usually<Port<Self::Port>> {
|
||||
jack.with_client(|c|c.register_port::<Self::Port>(name.as_ref(), Default::default()))
|
||||
.map_err(|e|e.into())
|
||||
}
|
||||
|
||||
fn port_name (&self) -> &Arc<str>;
|
||||
|
||||
fn connections (&self) -> &[Connect];
|
||||
|
||||
fn port (&self) -> &Port<Self::Port>;
|
||||
|
||||
fn port_mut (&mut self) -> &mut Port<Self::Port>;
|
||||
|
||||
fn into_port (self) -> Port<Self::Port> where Self: Sized;
|
||||
|
||||
fn close (self) -> Usually<()> where Self: Sized {
|
||||
let jack = self.jack().clone();
|
||||
Ok(jack.with_client(|c|c.unregister_port(self.into_port()))?)
|
||||
}
|
||||
|
||||
fn ports (&self, re_name: Option<&str>, re_type: Option<&str>, flags: PortFlags) -> Vec<String> {
|
||||
self.with_client(|c|c.ports(re_name, re_type, flags))
|
||||
}
|
||||
|
||||
fn port_by_id (&self, id: u32) -> Option<Port<Unowned>> {
|
||||
self.with_client(|c|c.port_by_id(id))
|
||||
}
|
||||
|
||||
fn port_by_name (&self, name: impl AsRef<str>) -> Option<Port<Unowned>> {
|
||||
self.with_client(|c|c.port_by_name(name.as_ref()))
|
||||
}
|
||||
|
||||
fn connect_to_matching <'k> (&'k self) -> Usually<()> {
|
||||
for connect in self.connections().iter() {
|
||||
match &connect.name {
|
||||
|
|
@ -970,6 +978,7 @@ pub trait JackPort: HasJack<'static> {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn connect_exact <'k> (&'k self, name: &str) ->
|
||||
Usually<Vec<(Port<Unowned>, Arc<str>, ConnectStatus)>>
|
||||
{
|
||||
|
|
@ -990,6 +999,7 @@ pub trait JackPort: HasJack<'static> {
|
|||
Ok(status)
|
||||
})
|
||||
}
|
||||
|
||||
fn connect_regexp <'k> (
|
||||
&'k self, re: &str, scope: Option<ConnectScope>
|
||||
) -> Usually<Vec<(Port<Unowned>, Arc<str>, ConnectStatus)>> {
|
||||
|
|
@ -1009,6 +1019,7 @@ pub trait JackPort: HasJack<'static> {
|
|||
Ok(status)
|
||||
})
|
||||
}
|
||||
|
||||
/** Connect to a matching port by name. */
|
||||
fn connect_to_name (&self, name: impl AsRef<str>) -> Usually<ConnectStatus> {
|
||||
self.with_client(|c|if let Some(ref port) = c.port_by_name(name.as_ref()) {
|
||||
|
|
@ -1017,6 +1028,7 @@ pub trait JackPort: HasJack<'static> {
|
|||
Ok(Missing)
|
||||
})
|
||||
}
|
||||
|
||||
/** Connect to a matching port by reference. */
|
||||
fn connect_to_unowned (&self, port: &Port<Unowned>) -> Usually<ConnectStatus> {
|
||||
self.with_client(|c|Ok(if let Ok(_) = c.connect_ports(self.port(), port) {
|
||||
|
|
@ -1027,6 +1039,7 @@ pub trait JackPort: HasJack<'static> {
|
|||
Mismatch
|
||||
}))
|
||||
}
|
||||
|
||||
/** Connect to an owned matching port by reference. */
|
||||
fn connect_to_owned (&self, port: &Port<Self::Pair>) -> Usually<ConnectStatus> {
|
||||
self.with_client(|c|Ok(if let Ok(_) = c.connect_ports(self.port(), port) {
|
||||
|
|
@ -1037,4 +1050,5 @@ pub trait JackPort: HasJack<'static> {
|
|||
Mismatch
|
||||
}))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue