impl all froms (8263loc)

This commit is contained in:
🪞👃🪞 2024-12-20 13:06:05 +01:00
parent f921260f6f
commit 48f83fa94d
13 changed files with 110 additions and 143 deletions

View file

@ -50,41 +50,35 @@ impl ItemColor {
self.okhsl.mix(other.okhsl, distance).into() self.okhsl.mix(other.okhsl, distance).into()
} }
} }
impl From<Color> for ItemPalette { from!(|base: Color|ItemPalette = Self::from(ItemColor::from(base)));
fn from (base: Color) -> Self { from!(|base: ItemColor|ItemPalette = {
Self::from(ItemColor::from(base)) let mut light = base.okhsl.clone();
} light.lightness = (light.lightness * 1.3).min(Okhsl::<f32>::max_lightness());
} let mut lighter = light.clone();
impl From<ItemColor> for ItemPalette { lighter.lightness = (lighter.lightness * 1.3).min(Okhsl::<f32>::max_lightness());
fn from (base: ItemColor) -> Self { let mut lightest = lighter.clone();
let mut light = base.okhsl.clone(); lightest.lightness = (lightest.lightness * 1.3).min(Okhsl::<f32>::max_lightness());
light.lightness = (light.lightness * 1.3).min(Okhsl::<f32>::max_lightness());
let mut lighter = light.clone();
lighter.lightness = (lighter.lightness * 1.3).min(Okhsl::<f32>::max_lightness());
let mut lightest = lighter.clone();
lightest.lightness = (lightest.lightness * 1.3).min(Okhsl::<f32>::max_lightness());
let mut dark = base.okhsl.clone(); let mut dark = base.okhsl.clone();
dark.lightness = (dark.lightness * 0.75).max(Okhsl::<f32>::min_lightness()); dark.lightness = (dark.lightness * 0.75).max(Okhsl::<f32>::min_lightness());
dark.saturation = (dark.saturation * 0.75).max(Okhsl::<f32>::min_saturation()); dark.saturation = (dark.saturation * 0.75).max(Okhsl::<f32>::min_saturation());
let mut darker = dark.clone(); let mut darker = dark.clone();
darker.lightness = (darker.lightness * 0.66).max(Okhsl::<f32>::min_lightness()); darker.lightness = (darker.lightness * 0.66).max(Okhsl::<f32>::min_lightness());
darker.saturation = (darker.saturation * 0.66).max(Okhsl::<f32>::min_saturation()); darker.saturation = (darker.saturation * 0.66).max(Okhsl::<f32>::min_saturation());
let mut darkest = darker.clone(); let mut darkest = darker.clone();
darkest.lightness = (darkest.lightness * 0.50).max(Okhsl::<f32>::min_lightness()); darkest.lightness = (darkest.lightness * 0.50).max(Okhsl::<f32>::min_lightness());
darkest.saturation = (darkest.saturation * 0.50).max(Okhsl::<f32>::min_saturation()); darkest.saturation = (darkest.saturation * 0.50).max(Okhsl::<f32>::min_saturation());
Self { Self {
base, base,
light: light.into(), light: light.into(),
lighter: lighter.into(), lighter: lighter.into(),
lightest: lightest.into(), lightest: lightest.into(),
dark: dark.into(), dark: dark.into(),
darker: darker.into(), darker: darker.into(),
darkest: darkest.into(), darkest: darkest.into(),
}
} }
} });
impl ItemPalette { impl ItemPalette {
pub fn random () -> Self { pub fn random () -> Self {
ItemColor::random().into() ItemColor::random().into()

View file

@ -1,10 +1,31 @@
pub use ::jack as libjack;
pub(crate) mod activate; pub(crate) mod activate; pub(crate) use self::activate::*;
pub(crate) mod audio; pub(crate) use self::audio::*; pub(crate) mod audio; pub(crate) use self::audio::*;
pub(crate) mod client; pub(crate) use self::client::*; pub(crate) mod client; pub(crate) use self::client::*;
pub(crate) mod from_jack;
pub(crate) mod jack_event; pub(crate) use self::jack_event::*; pub(crate) mod jack_event; pub(crate) use self::jack_event::*;
pub(crate) mod ports; pub(crate) use self::ports::*; pub(crate) mod ports; pub(crate) use self::ports::*;
pub(crate) use ::jack::{
contrib::ClosureProcessHandler,
Client, AsyncClient, ClientOptions, ClientStatus,
ProcessScope, Control, CycleTimes,
Port, PortId,
PortSpec, MidiIn, MidiOut, AudioIn, AudioOut, Unowned,
Transport, TransportState, MidiIter, RawMidi,
Frames,
NotificationHandler,
};
/// Implement [TryFrom<&Arc<RwLock<JackClient>>>]: create app state from wrapped JACK handle.
#[macro_export] macro_rules! from_jack {
(|$jack:ident|$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)? $cb:expr) => {
impl $(<$($L),*$($T $(: $U)?),*>)? TryFrom<&Arc<RwLock<JackClient>>> for $Struct $(<$($L),*$($T),*>)? {
type Error = Box<dyn std::error::Error>;
fn try_from ($jack: &Arc<RwLock<JackClient>>) -> Usually<Self> {
Ok($cb)
}
}
};
}
//////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////

View file

@ -1,5 +1,7 @@
use crate::*; use crate::*;
pub type DynamicAsyncClient = AsyncClient<DynamicNotifications, DynamicAudioHandler>;
pub type DynamicAudioHandler = ClosureProcessHandler<(), BoxedAudioHandler>;
pub type BoxedAudioHandler = Box<dyn FnMut(&Client, &ProcessScope) -> Control + Send>;
/// Wraps [Client] or [DynamicAsyncClient] in place. /// Wraps [Client] or [DynamicAsyncClient] in place.
#[derive(Debug)] #[derive(Debug)]
pub enum JackClient { pub enum JackClient {
@ -10,7 +12,17 @@ pub enum JackClient {
/// After activation. Must not be dropped for JACK thread to persist. /// After activation. Must not be dropped for JACK thread to persist.
Active(DynamicAsyncClient), Active(DynamicAsyncClient),
} }
from!(|jack: JackClient|Client = match jack {
JackClient::Inactive(client) => client,
JackClient::Activating => panic!("jack client still activating"),
JackClient::Active(_) => panic!("jack client already activated"),
});
impl JackClient {
pub fn new (name: &str) -> Usually<Self> {
let (client, _) = Client::new(name, ClientOptions::NO_START_SERVER)?;
Ok(Self::Inactive(client))
}
}
impl AudioEngine for JackClient { impl AudioEngine for JackClient {
fn client(&self) -> &Client { fn client(&self) -> &Client {
match self { match self {
@ -36,26 +48,3 @@ impl AudioEngine for JackClient {
Ok(state) Ok(state)
} }
} }
pub type DynamicAsyncClient = AsyncClient<DynamicNotifications, DynamicAudioHandler>;
pub type DynamicAudioHandler = ClosureProcessHandler<(), BoxedAudioHandler>;
pub type BoxedAudioHandler = Box<dyn FnMut(&Client, &ProcessScope) -> Control + Send>;
impl JackClient {
pub fn new (name: &str) -> Usually<Self> {
let (client, _) = Client::new(name, ClientOptions::NO_START_SERVER)?;
Ok(Self::Inactive(client))
}
}
impl From<JackClient> for Client {
fn from (jack: JackClient) -> Client {
match jack {
JackClient::Inactive(client) => client,
JackClient::Activating => panic!("jack client still activating"),
JackClient::Active(_) => panic!("jack client already activated"),
}
}
}

View file

@ -1,13 +0,0 @@
/// Implement [TryFrom<&Arc<RwLock<JackClient>>>]: create app state from wrapped JACK handle.
#[macro_export] macro_rules! from_jack {
(|$jack:ident|$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)? $cb:expr) => {
impl $(<$($L),*$($T $(: $U)?),*>)? TryFrom<&Arc<RwLock<JackClient>>> for $Struct $(<$($L),*$($T),*>)? {
type Error = Box<dyn std::error::Error>;
fn try_from ($jack: &Arc<RwLock<JackClient>>) -> Usually<Self> {
Ok($cb)
}
}
};
}

View file

@ -65,18 +65,6 @@ pub(crate) use ratatui::{
backend::{Backend, CrosstermBackend, ClearType} backend::{Backend, CrosstermBackend, ClearType}
}; };
pub use ::jack as libjack;
pub(crate) use ::jack::{
contrib::ClosureProcessHandler,
Client, AsyncClient, ClientOptions, ClientStatus,
ProcessScope, Control, CycleTimes,
Port, PortId,
PortSpec, MidiIn, MidiOut, AudioOut, Unowned,
Transport, TransportState, MidiIter, RawMidi,
Frames,
NotificationHandler,
};
pub use ::midly; pub use ::midly;
pub(crate) use ::midly::{ pub(crate) use ::midly::{
Smf, Smf,

View file

@ -63,25 +63,23 @@ pub struct ClockModel {
pub chunk: Arc<AtomicUsize>, pub chunk: Arc<AtomicUsize>,
} }
impl From<&Arc<RwLock<JackClient>>> for ClockModel { from!(|jack: &Arc<RwLock<JackClient>>| ClockModel = {
fn from (jack: &Arc<RwLock<JackClient>>) -> Self { let jack = jack.read().unwrap();
let jack = jack.read().unwrap(); let chunk = jack.client().buffer_size();
let chunk = jack.client().buffer_size(); let transport = jack.client().transport();
let transport = jack.client().transport(); let timebase = Arc::new(Timebase::default());
let timebase = Arc::new(Timebase::default()); Self {
Self { quant: Arc::new(24.into()),
quant: Arc::new(24.into()), sync: Arc::new(384.into()),
sync: Arc::new(384.into()), transport: Arc::new(transport),
transport: Arc::new(transport), chunk: Arc::new((chunk as usize).into()),
chunk: Arc::new((chunk as usize).into()), global: Arc::new(Moment::zero(&timebase)),
global: Arc::new(Moment::zero(&timebase)), playhead: Arc::new(Moment::zero(&timebase)),
playhead: Arc::new(Moment::zero(&timebase)), offset: Arc::new(Moment::zero(&timebase)),
offset: Arc::new(Moment::zero(&timebase)), started: RwLock::new(None).into(),
started: RwLock::new(None).into(), timebase,
timebase,
}
} }
} });
impl std::fmt::Debug for ClockModel { impl std::fmt::Debug for ClockModel {
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {

View file

@ -21,7 +21,7 @@ pub(crate) use tui_border::*;
mod app_transport; pub(crate) use app_transport::*; mod app_transport; pub(crate) use app_transport::*;
mod app_sequencer; pub(crate) use app_sequencer::*; mod app_sequencer; pub(crate) use app_sequencer::*;
mod app_sampler; pub(crate) use app_sampler::*; mod app_sampler; pub(crate) use app_sampler::*;
mod app_groovebox; mod app_groovebox; pub(crate) use app_groovebox::*;
mod app_arranger; pub(crate) use app_arranger::*; mod app_arranger; pub(crate) use app_arranger::*;
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////

View file

@ -27,8 +27,8 @@ from_jack!(|jack| ArrangerTui {
))); )));
Self { Self {
clock, clock,
phrases: PhraseListModel::from(&phrase), phrases: (&phrase).into(),
editor: PhraseEditorModel::from(&phrase), editor: (&phrase).into(),
selected: ArrangerSelection::Clip(0, 0), selected: ArrangerSelection::Clip(0, 0),
scenes: vec![], scenes: vec![],
tracks: vec![], tracks: vec![],
@ -282,13 +282,13 @@ fn any_size <E: Engine> (_: E::Size) -> Perhaps<E::Size>{
Ok(Some([0.into(),0.into()].into())) Ok(Some([0.into(),0.into()].into()))
} }
impl ArrangerTui { impl ArrangerTui {
fn selected (&self) -> ArrangerSelection { pub fn selected (&self) -> ArrangerSelection {
self.selected self.selected
} }
fn selected_mut (&mut self) -> &mut ArrangerSelection { pub fn selected_mut (&mut self) -> &mut ArrangerSelection {
&mut self.selected &mut self.selected
} }
fn activate (&mut self) -> Usually<()> { pub fn activate (&mut self) -> Usually<()> {
if let ArrangerSelection::Scene(s) = self.selected { if let ArrangerSelection::Scene(s) = self.selected {
for (t, track) in self.tracks.iter_mut().enumerate() { for (t, track) in self.tracks.iter_mut().enumerate() {
let phrase = self.scenes[s].clips[t].clone(); let phrase = self.scenes[s].clips[t].clone();
@ -305,15 +305,15 @@ impl ArrangerTui {
}; };
Ok(()) Ok(())
} }
fn selected_phrase (&self) -> Option<Arc<RwLock<Phrase>>> { pub fn selected_phrase (&self) -> Option<Arc<RwLock<Phrase>>> {
self.selected_scene()?.clips.get(self.selected.track()?)?.clone() self.selected_scene()?.clips.get(self.selected.track()?)?.clone()
} }
fn toggle_loop (&mut self) { pub fn toggle_loop (&mut self) {
if let Some(phrase) = self.selected_phrase() { if let Some(phrase) = self.selected_phrase() {
phrase.write().unwrap().toggle_loop() phrase.write().unwrap().toggle_loop()
} }
} }
fn randomize_color (&mut self) { pub fn randomize_color (&mut self) {
match self.selected { match self.selected {
ArrangerSelection::Mix => { ArrangerSelection::Mix => {
self.color = ItemPalette::random() self.color = ItemPalette::random()

View file

@ -9,14 +9,14 @@ pub struct TransportTui {
pub clock: ClockModel, pub clock: ClockModel,
pub size: Measure<Tui>, pub size: Measure<Tui>,
pub cursor: (usize, usize), pub cursor: (usize, usize),
pub focus: FocusState<TransportFocus>, pub focus: TransportFocus,
} }
from_jack!(|jack|TransportTui Self { from_jack!(|jack|TransportTui Self {
jack: jack.clone(), jack: jack.clone(),
clock: ClockModel::from(jack), clock: ClockModel::from(jack),
size: Measure::new(), size: Measure::new(),
cursor: (0, 0), cursor: (0, 0),
focus: FocusState::Entered(TransportFocus::PlayPause) focus: TransportFocus::PlayPause
}); });
has_clock!(|self:TransportTui|&self.clock); has_clock!(|self:TransportTui|&self.clock);
audio!(|self:TransportTui,client,scope|ClockAudio(self).process(client, scope)); audio!(|self:TransportTui,client,scope|ClockAudio(self).process(client, scope));
@ -131,10 +131,10 @@ render!(<Tui>|self: PlayPause|Tui::bg(
impl HasFocus for TransportTui { impl HasFocus for TransportTui {
type Item = TransportFocus; type Item = TransportFocus;
fn focused (&self) -> Self::Item { fn focused (&self) -> Self::Item {
self.focus.inner() self.focus
} }
fn set_focused (&mut self, to: Self::Item) { fn set_focused (&mut self, to: Self::Item) {
self.focus.set_inner(to) self.focus = to
} }
} }
@ -147,8 +147,6 @@ pub enum TransportFocus {
Clock, Clock,
Quant, Quant,
} }
from!(|state: &TransportTui|Option<TransportTui> = Some(state.focus.inner()));
impl FocusWrap<TransportFocus> for TransportFocus { impl FocusWrap<TransportFocus> for TransportFocus {
fn wrap <'a, W: Render<Tui>> (self, focus: TransportFocus, content: &'a W) fn wrap <'a, W: Render<Tui>> (self, focus: TransportFocus, content: &'a W)
-> impl Render<Tui> + 'a -> impl Render<Tui> + 'a
@ -177,7 +175,7 @@ pub trait TransportControl<T>: HasClock + {
impl TransportControl<TransportFocus> for TransportTui { impl TransportControl<TransportFocus> for TransportTui {
fn transport_focused (&self) -> Option<TransportFocus> { fn transport_focused (&self) -> Option<TransportFocus> {
Some(self.focus.inner()) Some(self.focus)
} }
} }

View file

@ -48,11 +48,11 @@ pub struct ArrangerVCursor {
header_h: u16, header_h: u16,
} }
from!(|args:(&ArrangerTui, usize)|ArrangerVCursor = Self { from!(|args:(&ArrangerTui, usize)|ArrangerVCursor = Self {
cols: track_widths(state.tracks()), cols: track_widths(args.0.tracks()),
rows: ArrangerScene::ppqs(args.0.scenes(), args.1), rows: ArrangerScene::ppqs(args.0.scenes(), args.1),
focused: true, focused: true,
selected: state.selected, selected: args.0.selected(),
scenes_w: 3 + ArrangerScene::longest_name(state.scenes()) as u16, scenes_w: 3 + ArrangerScene::longest_name(args.0.scenes()) as u16,
header_h: 3, header_h: 3,
}); });
render!(<Tui>|self: ArrangerVCursor|render(move|to: &mut TuiOutput|{ render!(<Tui>|self: ArrangerVCursor|render(move|to: &mut TuiOutput|{

View file

@ -207,22 +207,18 @@ impl PhraseEditorModel {
} }
} }
impl From<&Arc<RwLock<Phrase>>> for PhraseEditorModel { from!(|phrase: &Arc<RwLock<Phrase>>|PhraseEditorModel = {
fn from (phrase: &Arc<RwLock<Phrase>>) -> Self { let mut model = Self::from(Some(phrase.clone()));
let mut model = Self::from(Some(phrase.clone())); model.redraw();
model.redraw(); model
model });
}
}
impl From<Option<Arc<RwLock<Phrase>>>> for PhraseEditorModel { from!(|phrase: Option<Arc<RwLock<Phrase>>>|PhraseEditorModel = {
fn from (phrase: Option<Arc<RwLock<Phrase>>>) -> Self { let mut model = Self::default();
let mut model = Self::default(); *model.phrase_mut() = phrase;
*model.phrase_mut() = phrase; model.redraw();
model.redraw(); model
model });
}
}
impl std::fmt::Debug for PhraseEditorModel { impl std::fmt::Debug for PhraseEditorModel {
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {

View file

@ -167,7 +167,7 @@ impl Default for PhraseListModel {
} }
} }
} }
from!(|phrase:<&Arc<RwLock<Phrase>>>| PhraseListModel = { from!(|phrase:&Arc<RwLock<Phrase>>|PhraseListModel = {
let mut model = Self::default(); let mut model = Self::default();
model.phrases.push(phrase.clone()); model.phrases.push(phrase.clone());
model.phrase.store(1, Relaxed); model.phrase.store(1, Relaxed);

View file

@ -91,11 +91,7 @@ impl BigBuffer {
} }
} }
impl From<(usize, usize)> for BigBuffer { // cuteness overload from!(|size:(usize, usize)| BigBuffer = Self::new(size.0, size.1));
fn from ((width, height): (usize, usize)) -> Self {
Self::new(width, height)
}
}
pub fn buffer_update (buf: &mut Buffer, area: [u16;4], callback: &impl Fn(&mut Cell, u16, u16)) { pub fn buffer_update (buf: &mut Buffer, area: [u16;4], callback: &impl Fn(&mut Cell, u16, u16)) {
for row in 0..area.h() { for row in 0..area.h() {