wip: adding edn parsing to mixer track

This commit is contained in:
🪞👃🪞 2024-08-09 11:23:12 +03:00
parent 10f191282e
commit a819e042c7
9 changed files with 89 additions and 74 deletions

View file

@ -41,12 +41,12 @@ fn handle_focused (state: &mut App, e: &AppEvent) -> Usually<bool> {
AppFocus::Transport => state.transport.handle(e),
AppFocus::Arranger => state.arranger.sequencer.handle(e),
AppFocus::Sequencer => state.arranger.sequencer.handle(e),
AppFocus::Chain => Ok(if state.entered {
AppFocus::Chain => Ok(false)/*if state.entered {
handle_device(state, e)? ||
handle_keymap(state, e, crate::control::KEYMAP_CHAIN)?
} else {
handle_keymap(state, e, crate::control::KEYMAP_CHAIN)? || handle_device(state, e)?
})
})*/
}
}

View file

@ -69,10 +69,10 @@ impl App {
}
},
Some(Edn::Symbol("scene")) => {
Scene::load_edn(self, &items[1..])?;
tek_sequencer::Scene::load_edn(self, &items[1..])?;
},
Some(Edn::Symbol("track")) => {
Track::load_edn(self, &items[1..])?;
tek_mixer::Track::load_edn(self, &items[1..])?;
},
Some(Edn::Symbol("midi-in")) => {
self.midi_ins = items[1..].iter().map(|x|match x {
@ -107,75 +107,6 @@ impl App {
}
}
impl Scene {
fn load_edn <'a, 'e> (app: &'a mut App, args: &[Edn<'e>]) -> Usually<&'a mut Self> {
let mut name = None;
let mut clips = vec![];
edn!(edn in args {
Edn::Map(map) => {
let key = map.get(&Edn::Key(":name"));
if let Some(Edn::Str(n)) = key {
name = Some(*n);
} else {
panic!("unexpected key in scene '{name:?}': {key:?}")
}
},
Edn::Symbol("_") => {
clips.push(None);
},
Edn::Int(i) => {
clips.push(Some(*i as usize));
},
_ => panic!("unexpected in scene '{name:?}': {edn:?}")
});
let scene = app.arranger.scene_add(name)?;
scene.clips = clips;
Ok(scene)
}
}
impl Track {
fn load_edn <'a, 'e> (app: &'a mut App, args: &[Edn<'e>]) -> Usually<&'a mut Self> {
let ppq = app.transport.ppq();
let mut name = None;
let mut _gain = 0.0f64;
let mut devices: Vec<JackDevice> = vec![];
let mut phrases: Vec<Phrase> = vec![];
edn!(edn in args {
Edn::Map(map) => {
if let Some(Edn::Str(n)) = map.get(&Edn::Key(":name")) {
name = Some(*n);
}
if let Some(Edn::Double(g)) = map.get(&Edn::Key(":gain")) {
_gain = f64::from(*g)
}
},
Edn::List(args) => match args.get(0) {
Some(Edn::Symbol("phrase")) => {
phrases.push(Phrase::load_edn(ppq, &args[1..])?)
},
Some(Edn::Symbol("sampler")) => {
devices.push(Sampler::load_edn(&args[1..])?)
},
Some(Edn::Symbol("lv2")) => {
devices.push(LV2Plugin::load_edn(&args[1..])?)
},
None => panic!("empty list track {}",
name.unwrap_or("")
),
_ => panic!("unexpected in track {}: {:?}",
name.unwrap_or(""),
args.get(0).unwrap()
)
},
_ => {}
});
let track = app.arranger.track_add(name)?;
for phrase in phrases { track.phrases.push(Arc::new(RwLock::new(phrase))); }
for device in devices { track.add_device(device)?; }
Ok(track)
}
}
impl Phrase {
fn load_edn <'e> (ppq: usize, args: &[Edn<'e>]) -> Usually<Self> {

View file

@ -11,3 +11,4 @@ toml = "0.8.12"
better-panic = "0.3.0"
midly = "0.5"
clap = { version = "4.5.4", features = [ "derive" ] }
clojure-reader = "0.1.0"

View file

@ -7,6 +7,7 @@ pub use std::collections::BTreeMap;
pub use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers};
pub use ratatui::prelude::{Rect, Style, Color, Buffer};
pub use ratatui::style::Stylize;
pub use clojure_reader::{edn::{read, Edn}, error::Error as EdnError};
pub(crate) use std::error::Error;
pub(crate) use std::io::{stdout};
@ -42,6 +43,18 @@ submod! {
exit render handle
}
/// EDN parsing helper.
#[macro_export] macro_rules! edn {
($edn:ident { $($pat:pat => $expr:expr),* $(,)? }) => {
match $edn { $($pat => $expr),* }
};
($edn:ident in $args:ident { $($pat:pat => $expr:expr),* $(,)? }) => {
for $edn in $args {
edn!($edn { $($pat => $expr),* })
}
};
}
/// Standard result type.
pub type Usually<T> = Result<T, Box<dyn Error>>;

View file

@ -0,0 +1,12 @@
(mixer
(track
(name "Drums")
(sampler
(dir "/home/user/Lab/Music/pak")
(sample (midi 34) (name "808 D") (file "808.wav"))))
(track
(name "Lead")
(lv2
(name "Odin2")
(path "file:///home/user/.lv2/Odin2.lv2"))
(gain 0.0)))

View file

@ -1,4 +1,5 @@
use crate::*;
use tek_core::edn;
/// TODO: A track in the mixer. (Integrate with [crate::model::Track]?)
pub struct MixerTrack {
@ -52,6 +53,44 @@ impl MixerTrack {
}
}
impl MixerTrack {
fn load_edn <'a, 'e> (app: &'a mut App, args: &[Edn<'e>]) -> Usually<&'a mut Self> {
let ppq = app.transport.ppq();
let mut name = None;
let mut _gain = 0.0f64;
let mut devices: Vec<JackDevice> = vec![];
edn!(edn in args {
Edn::Map(map) => {
if let Some(Edn::Str(n)) = map.get(&Edn::Key(":name")) {
name = Some(*n);
}
if let Some(Edn::Double(g)) = map.get(&Edn::Key(":gain")) {
_gain = f64::from(*g)
}
},
Edn::List(args) => match args.get(0) {
Some(Edn::Symbol("sampler")) => {
devices.push(Sampler::load_edn(&args[1..])?)
},
Some(Edn::Symbol("lv2")) => {
devices.push(LV2Plugin::load_edn(&args[1..])?)
},
None => panic!("empty list track {}",
name.unwrap_or("")
),
_ => panic!("unexpected in track {}: {:?}",
name.unwrap_or(""),
args.get(0).unwrap()
)
},
_ => {}
});
let track = app.arranger.track_add(name)?;
for device in devices { track.add_device(device)?; }
Ok(track)
}
}
//impl<W: Write> Input<TUI<W>, bool> for Mixer {
//fn handle (&mut self, engine: &mut TUI<W>) -> Result<Option<bool>> {
//Ok(None)

View file

@ -0,0 +1,18 @@
(arranger
(track
(name "Drums")
(phrase
(name "4 kicks")
(beats 4)
(steps 16)
(:00 (36 128))
(:04 (36 100))
(:08 (36 100))
(:12 (36 100))))
(track
(name "Bass")
(phrase
(beats 4)
(steps 16)
(:04 (36 100))
(:12 (36 100)))))

View file

@ -1,7 +1,7 @@
use crate::*;
impl Scene {
fn load_edn <'a, 'e> (app: &'a mut App, args: &[Edn<'e>]) -> Usually<&'a mut Self> {
pub fn load_edn <'a, 'e> (app: &'a mut App, args: &[Edn<'e>]) -> Usually<&'a mut Self> {
let mut name = None;
let mut clips = vec![];
edn!(edn in args {