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()
}
}
impl From<Color> for ItemPalette {
fn from (base: Color) -> Self {
Self::from(ItemColor::from(base))
}
}
impl From<ItemColor> for ItemPalette {
fn from (base: ItemColor) -> Self {
let mut light = base.okhsl.clone();
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());
from!(|base: Color|ItemPalette = Self::from(ItemColor::from(base)));
from!(|base: ItemColor|ItemPalette = {
let mut light = base.okhsl.clone();
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();
dark.lightness = (dark.lightness * 0.75).max(Okhsl::<f32>::min_lightness());
dark.saturation = (dark.saturation * 0.75).max(Okhsl::<f32>::min_saturation());
let mut darker = dark.clone();
darker.lightness = (darker.lightness * 0.66).max(Okhsl::<f32>::min_lightness());
darker.saturation = (darker.saturation * 0.66).max(Okhsl::<f32>::min_saturation());
let mut darkest = darker.clone();
darkest.lightness = (darkest.lightness * 0.50).max(Okhsl::<f32>::min_lightness());
darkest.saturation = (darkest.saturation * 0.50).max(Okhsl::<f32>::min_saturation());
let mut dark = base.okhsl.clone();
dark.lightness = (dark.lightness * 0.75).max(Okhsl::<f32>::min_lightness());
dark.saturation = (dark.saturation * 0.75).max(Okhsl::<f32>::min_saturation());
let mut darker = dark.clone();
darker.lightness = (darker.lightness * 0.66).max(Okhsl::<f32>::min_lightness());
darker.saturation = (darker.saturation * 0.66).max(Okhsl::<f32>::min_saturation());
let mut darkest = darker.clone();
darkest.lightness = (darkest.lightness * 0.50).max(Okhsl::<f32>::min_lightness());
darkest.saturation = (darkest.saturation * 0.50).max(Okhsl::<f32>::min_saturation());
Self {
base,
light: light.into(),
lighter: lighter.into(),
lightest: lightest.into(),
dark: dark.into(),
darker: darker.into(),
darkest: darkest.into(),
}
Self {
base,
light: light.into(),
lighter: lighter.into(),
lightest: lightest.into(),
dark: dark.into(),
darker: darker.into(),
darkest: darkest.into(),
}
}
});
impl ItemPalette {
pub fn random () -> Self {
ItemColor::random().into()

View file

@ -1,10 +1,31 @@
pub(crate) mod activate;
pub use ::jack as libjack;
pub(crate) mod activate; pub(crate) use self::activate::*;
pub(crate) mod audio; pub(crate) use self::audio::*;
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 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::*;
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.
#[derive(Debug)]
pub enum JackClient {
@ -10,7 +12,17 @@ pub enum JackClient {
/// After activation. Must not be dropped for JACK thread to persist.
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 {
fn client(&self) -> &Client {
match self {
@ -36,26 +48,3 @@ impl AudioEngine for JackClient {
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}
};
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(crate) use ::midly::{
Smf,

View file

@ -63,25 +63,23 @@ pub struct ClockModel {
pub chunk: Arc<AtomicUsize>,
}
impl From<&Arc<RwLock<JackClient>>> for ClockModel {
fn from (jack: &Arc<RwLock<JackClient>>) -> Self {
let jack = jack.read().unwrap();
let chunk = jack.client().buffer_size();
let transport = jack.client().transport();
let timebase = Arc::new(Timebase::default());
Self {
quant: Arc::new(24.into()),
sync: Arc::new(384.into()),
transport: Arc::new(transport),
chunk: Arc::new((chunk as usize).into()),
global: Arc::new(Moment::zero(&timebase)),
playhead: Arc::new(Moment::zero(&timebase)),
offset: Arc::new(Moment::zero(&timebase)),
started: RwLock::new(None).into(),
timebase,
}
from!(|jack: &Arc<RwLock<JackClient>>| ClockModel = {
let jack = jack.read().unwrap();
let chunk = jack.client().buffer_size();
let transport = jack.client().transport();
let timebase = Arc::new(Timebase::default());
Self {
quant: Arc::new(24.into()),
sync: Arc::new(384.into()),
transport: Arc::new(transport),
chunk: Arc::new((chunk as usize).into()),
global: Arc::new(Moment::zero(&timebase)),
playhead: Arc::new(Moment::zero(&timebase)),
offset: Arc::new(Moment::zero(&timebase)),
started: RwLock::new(None).into(),
timebase,
}
}
});
impl std::fmt::Debug for ClockModel {
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_sequencer; pub(crate) use app_sequencer::*;
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::*;
///////////////////////////////////////////////////////

View file

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

View file

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

View file

@ -207,22 +207,18 @@ impl PhraseEditorModel {
}
}
impl From<&Arc<RwLock<Phrase>>> for PhraseEditorModel {
fn from (phrase: &Arc<RwLock<Phrase>>) -> Self {
let mut model = Self::from(Some(phrase.clone()));
model.redraw();
model
}
}
from!(|phrase: &Arc<RwLock<Phrase>>|PhraseEditorModel = {
let mut model = Self::from(Some(phrase.clone()));
model.redraw();
model
});
impl From<Option<Arc<RwLock<Phrase>>>> for PhraseEditorModel {
fn from (phrase: Option<Arc<RwLock<Phrase>>>) -> Self {
let mut model = Self::default();
*model.phrase_mut() = phrase;
model.redraw();
model
}
}
from!(|phrase: Option<Arc<RwLock<Phrase>>>|PhraseEditorModel = {
let mut model = Self::default();
*model.phrase_mut() = phrase;
model.redraw();
model
});
impl std::fmt::Debug for PhraseEditorModel {
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();
model.phrases.push(phrase.clone());
model.phrase.store(1, Relaxed);

View file

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