mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
impl all froms (8263loc)
This commit is contained in:
parent
f921260f6f
commit
48f83fa94d
13 changed files with 110 additions and 143 deletions
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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|{
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue