refactor: merge plugin, sampler -> mixer; transport -> sequencer; time -> core

This commit is contained in:
🪞👃🪞 2024-08-10 21:23:20 +03:00
parent 6206a43b4a
commit a659062dbc
46 changed files with 128 additions and 198 deletions

View file

@ -9,11 +9,8 @@ microxdg = "0.1.2"
tek_core = { path = "../tek_core" }
tek_jack = { path = "../tek_jack" }
tek_plugin = { path = "../tek_plugin" }
tek_sampler = { path = "../tek_sampler" }
tek_sequencer = { path = "../tek_sequencer" }
tek_timer = { path = "../tek_timer" }
tek_mixer = { path = "../tek_mixer", features = ["standalone_devices"] }
tek_mixer = { path = "../tek_mixer" }
#jack = "0.10"
#crossterm = "0.27"
#ratatui = { version = "0.26.3", features = [ "unstable-widget-ref", "underline-color" ] }

View file

@ -1,7 +1,6 @@
use crate::*;
use tek_core::Direction;
use tek_timer::TransportToolbar;
use tek_sequencer::Arranger;
use tek_sequencer::{TransportToolbar, Arranger};
use tek_mixer::Mixer;
/// Root of application state.
@ -108,7 +107,7 @@ render!(App |self, buf, area| {
focused: self.section == AppFocus::Chain,
chain: self.mixer.track()
},
&self.arranger.sequencer,
&self.arranger.sequencer(),
]))
]).render(buf, area)?;
if let Some(ref modal) = *MODAL.lock().unwrap() {

View file

@ -39,8 +39,8 @@ fn handle_modal (e: &AppEvent) -> Usually<bool> {
fn handle_focused (state: &mut App, e: &AppEvent) -> Usually<bool> {
match state.section {
AppFocus::Transport => state.transport.handle(e),
AppFocus::Arranger => state.arranger.sequencer.handle(e),
AppFocus::Sequencer => state.arranger.sequencer.handle(e),
AppFocus::Arranger => state.arranger.sequencer_mut().map(|s|s.handle(e)),
AppFocus::Sequencer => state.arranger.sequencer_mut().map(|s|s.handle(e)),
AppFocus::Chain => Ok(false)/*if state.entered {
handle_device(state, e)? ||
handle_keymap(state, e, crate::control::KEYMAP_CHAIN)?
@ -85,11 +85,11 @@ pub const KEYMAP_GLOBAL: &'static [KeyBinding<App>] = keymap!(App {
Ok(true)
}],
[Char('='), NONE, "zoom_in", "show fewer ticks per block", |app: &mut App| {
app.arranger.sequencer.time_axis.scale_mut(&prev_note_length);
app.arranger.sequencer_mut().map(|s|s.time_axis.scale_mut(&prev_note_length));
Ok(true)
}],
[Char('-'), NONE, "zoom_out", "show more ticks per block", |app: &mut App| {
app.arranger.sequencer.time_axis.scale_mut(&next_note_length);
app.arranger.sequencer_mut().map(|s|s.time_axis.scale_mut(&next_note_length));
Ok(true)
}],
[Char('x'), NONE, "extend", "double the current clip", |app: &mut App| {
@ -144,14 +144,14 @@ pub const KEYMAP_FOCUS: &'static [KeyBinding<App>] = keymap!(App {
app.entered = false;
app.transport.entered = app.entered;
app.arranger.entered = app.entered;
app.arranger.sequencer.entered = app.entered;
app.arranger.sequencer_mut().map(|s|s.entered = app.entered);
Ok(true)
}],
[Enter, NONE, "focus_enter", "activate item at cursor", |app: &mut App|{
app.entered = true;
app.transport.entered = app.entered;
app.arranger.entered = app.entered;
app.arranger.sequencer.entered = app.entered;
app.arranger.sequencer_mut().map(|s|s.entered = app.entered);
Ok(true)
}],
});
@ -162,8 +162,10 @@ pub fn focus_next (app: &mut App) -> Usually<bool> {
app.transport.entered = app.entered;
app.arranger.focused = app.section == AppFocus::Arranger;
app.arranger.entered = app.entered;
app.arranger.sequencer.focused = app.section == AppFocus::Sequencer;
app.arranger.sequencer.entered = app.entered;
app.arranger.sequencer_mut().map(|s|{
s.focused = app.section == AppFocus::Sequencer;
s.entered = app.entered;
});
Ok(true)
}
@ -173,7 +175,9 @@ pub fn focus_prev (app: &mut App) -> Usually<bool> {
app.transport.entered = app.entered;
app.arranger.focused = app.section == AppFocus::Arranger;
app.arranger.entered = app.entered;
app.arranger.sequencer.focused = app.section == AppFocus::Sequencer;
app.arranger.sequencer.entered = app.entered;
app.arranger.sequencer_mut().map(|s|{
s.focused = app.section == AppFocus::Sequencer;
s.entered = app.entered;
});
Ok(true)
}

View file

@ -9,7 +9,7 @@
pub(crate) use tek_core::*;
pub(crate) use tek_jack::{*, jack::*};
pub(crate) use tek_timer::*;
pub(crate) use tek_sequencer::*;
pub(crate) use microxdg::XdgApp;
submod! {

View file

@ -13,3 +13,4 @@ midly = "0.5"
clap = { version = "4.5.4", features = [ "derive" ] }
clojure-reader = "0.1.0"
once_cell = "1.19.0"
atomic_float = "1.0.0"

View file

@ -9,12 +9,13 @@ 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 use once_cell::sync::Lazy;
pub use std::sync::atomic::{Ordering, AtomicBool};
pub(crate) use std::error::Error;
pub(crate) use std::io::{stdout};
pub(crate) use std::thread::{spawn, JoinHandle};
pub(crate) use std::time::Duration;
pub(crate) use std::sync::atomic::{Ordering, AtomicBool};
pub(crate) use atomic_float::*;
//, LockResult, RwLockReadGuard, RwLockWriteGuard};
//pub(crate) use std::path::PathBuf;
//pub(crate) use std::fs::read_dir;
@ -41,7 +42,12 @@ use crossterm::terminal::{
}
submod! {
exit render handle
exit
render
handle
time_base
time_note
time_tick
}
/// EDN parsing helper.

View file

@ -145,6 +145,15 @@ impl Render for () {
}
}
impl<T: Render> Render for Option<T> {
fn render (&self, b: &mut Buffer, a: Rect) -> Usually<Rect> {
match self {
Some(widget) => widget.render(b, a),
None => ().render(b, a),
}
}
}
impl<T: Fn(&mut Buffer, Rect) -> Usually<Rect> + Send> Render for T {
fn render (&self, b: &mut Buffer, a: Rect) -> Usually<Rect> {
(*self)(b, a)

View file

@ -1,17 +1,3 @@
pub(crate) use tek_core::*;
pub(crate) use tek_core::crossterm::event::{KeyCode, KeyModifiers};
pub(crate) use tek_jack::{*, jack::*};
pub(crate) use std::sync::{Arc, atomic::Ordering};
pub(crate) use atomic_float::AtomicF64;
submod! {
timebase
ticks
transport
transport_focus
transport_handle
transport_render
}
/// (pulses, name)
pub const NOTE_DURATIONS: [(usize, &str);26] = [
(1, "1/384"),

View file

@ -1,5 +1,3 @@
use crate::*;
/// Defines frames per tick.
pub struct Ticks(pub f64);

View file

@ -6,13 +6,14 @@ version = "0.1.0"
[dependencies]
tek_core = { path = "../tek_core" }
tek_jack = { path = "../tek_jack" }
tek_sampler = { path = "../tek_sampler", optional = true }
tek_plugin = { path = "../tek_plugin", optional = true }
[features]
standalone_devices = [ "sampler", "plugin" ]
sampler = [ "tek_sampler" ]
plugin = [ "tek_plugin" ]
livi = "0.7.4"
suil-rs = { path = "../suil" }
symphonia = { version = "0.5.4", features = [ "all" ] }
vst = "0.4.0"
#vst3 = "0.1.0"
wavers = "1.4.3"
winit = { version = "0.30.4", features = [ "x11" ] }
[lib]
path = "src/lib.rs"
@ -24,3 +25,11 @@ path = "src/mixer_main.rs"
[[bin]]
name = "tek_track"
path = "src/track_main.rs"
[[bin]]
name = "tek_sampler"
path = "src/sampler_main.rs"
[[bin]]
name = "tek_plugin"
path = "src/sampler_main.rs"

View file

@ -1,6 +1,15 @@
# `tek_mixer` and `tek_track`
# `tek_mixer`
// TODO:
// - Meters: propagate clipping:
// - If one stage clips, all stages after it are marked red
// - If one track clips, all tracks that feed from it are marked red?
# `tek_track`
# `tek_sampler`
This crate implements a sampler device which plays audio files
in response to MIDI notes.
# `tek_plugin`

View file

@ -1,7 +1,15 @@
pub(crate) use tek_core::*;
pub(crate) use tek_core::ratatui::prelude::*;
pub(crate) use tek_core::crossterm::event::{KeyCode, KeyModifiers};
pub(crate) use tek_core::midly::{num::u7, live::LiveEvent, MidiMessage};
pub(crate) use tek_jack::{*, jack::*};
pub(crate) use std::collections::BTreeMap;
pub(crate) use std::sync::{Arc, Mutex, RwLock};
pub(crate) use std::path::PathBuf;
pub(crate) use std::ffi::OsString;
pub(crate) use std::fs::read_dir;
submod! {
mixer
mixer_cli
@ -10,4 +18,14 @@ submod! {
track
track_view
track_handle
plugin
plugin_lv2
plugin_lv2_gui
plugin_vst2
plugin_vst3
sample
sample_add
sampler
sampler_edn
voice
}

View file

@ -0,0 +1 @@
//! TODO

View file

@ -1,20 +0,0 @@
[package]
name = "tek_plugin"
edition = "2021"
version = "0.1.0"
[dependencies]
tek_core = { path = "../tek_core" }
tek_jack = { path = "../tek_jack" }
livi = "0.7.4"
winit = { version = "0.30.4", features = [ "x11" ] }
suil-rs = { path = "../suil" }
vst = "0.4.0"
#vst3 = "0.1.0"
[lib]
path = "src/lib.rs"
[[bin]]
name = "tek_plugin"
path = "src/main.rs"

View file

@ -1,4 +0,0 @@
# `tek_plugin`
This crate allows plugins to be loaded.

View file

@ -1,16 +0,0 @@
pub(crate) use tek_core::*;
pub(crate) use tek_core::ratatui::prelude::*;
pub(crate) use tek_core::crossterm::event::{KeyCode, KeyModifiers};
pub(crate) use tek_jack::*;
pub(crate) use tek_jack::jack::*;
use std::sync::Arc;
use std::sync::Mutex;
submod! {
plugin
lv2
lv2_gui
vst2
vst3
}

View file

@ -1 +0,0 @@
use crate::*;

View file

@ -1,17 +0,0 @@
[package]
name = "tek_sampler"
edition = "2021"
version = "0.1.0"
[dependencies]
tek_core = { path = "../tek_core" }
tek_jack = { path = "../tek_jack" }
symphonia = { version = "0.5.4", features = [ "all" ] }
wavers = "1.4.3"
[lib]
path = "src/lib.rs"
[[bin]]
name = "tek_sampler"
path = "src/main.rs"

View file

@ -1,4 +0,0 @@
# `tek_sampler`
This crate implements a sampler device which plays audio files
in response to MIDI notes.

View file

@ -1,20 +0,0 @@
// Sampler (currently 16bit WAVs at system rate; TODO convert/resample)
pub(crate) use tek_core::*;
pub(crate) use tek_core::ratatui::prelude::*;
pub(crate) use tek_core::crossterm::event::{KeyCode, KeyModifiers};
pub(crate) use tek_core::midly::{num::u7, live::LiveEvent, MidiMessage};
pub(crate) use tek_jack::{*, jack::*};
pub(crate) use std::collections::BTreeMap;
pub(crate) use std::sync::{Arc, Mutex, RwLock};
pub(crate) use std::path::PathBuf;
pub(crate) use std::ffi::OsString;
pub(crate) use std::fs::read_dir;
submod! {
sampler
sample
sample_add
voice
}

View file

@ -6,7 +6,6 @@ version = "0.1.0"
[dependencies]
tek_core = { path = "../tek_core" }
tek_jack = { path = "../tek_jack" }
tek_timer = { path = "../tek_timer" }
[lib]
path = "src/lib.rs"
@ -18,3 +17,7 @@ path = "src/sequencer_main.rs"
[[bin]]
name = "tek_arranger"
path = "src/arranger_main.rs"
[[bin]]
name = "tek_transport"
path = "src/transport_main.rs"

View file

@ -1,3 +1,23 @@
# `tek_sequencer`
This crate implements a MIDI sequencer and arranger with clip launching.
---
# `tek_arranger`
---
# `tek_timer`
This crate implements time sync and JACK transport control.
* Warning: If transport is set rolling by qjackctl, this program can't pause it
* Todo: bpm: shift +/- 0.001
* Todo: quant/sync: shift = next/prev value of same type (normal, triplet, dotted)
* Or: use shift to switch between inc/dec top/bottom value?
* Todo: focus play button
* Todo: focus time position
* Todo: edit numeric values
* Todo: jump to time/bbt markers
* Todo: count xruns

View file

@ -49,6 +49,16 @@ impl Arranger {
_ => {}
}
}
pub fn sequencer (&self) -> Option<&Sequencer> {
self.selected.track()
.map(|track|self.tracks.get(track))
.flatten()
}
pub fn sequencer_mut (&mut self) -> Option<&mut Sequencer> {
self.selected.track()
.map(|track|self.tracks.get_mut(track))
.flatten()
}
pub fn show_phrase (&mut self) -> Usually<()> {
unimplemented!()
//let phrase = self.phrase();

View file

@ -1,5 +1,4 @@
use tek_core::clap::{self, Parser};
use tek_timer::TransportToolbar;
use crate::*;
#[derive(Debug, Parser)]

View file

@ -4,24 +4,27 @@ pub(crate) use tek_core::*;
pub(crate) use tek_core::ratatui::prelude::*;
pub(crate) use tek_core::crossterm::event::{KeyCode, KeyModifiers};
pub(crate) use tek_core::midly::{num::u7, live::LiveEvent, MidiMessage};
pub(crate) use tek_jack::jack::*;
pub(crate) use tek_timer::*;
pub(crate) use tek_jack::{*, jack::*};
pub(crate) use std::sync::{Arc, RwLock};
submod! {
midi
phrase
sequencer
sequencer_cli
sequencer_handle
sequencer_render
arranger
arranger_cli
arranger_focus
arranger_handle
arranger_track
arranger_view
midi
phrase
scene
sequencer
sequencer_cli
sequencer_handle
sequencer_render
transport
transport_focus
transport_handle
transport_render
}
pubmod! {

View file

@ -1,5 +1,4 @@
use tek_core::clap::{self, Parser};
use tek_timer::TransportToolbar;
use crate::*;
#[derive(Debug, Parser)]

View file

@ -1,16 +0,0 @@
[package]
name = "tek_timer"
edition = "2021"
version = "0.1.0"
[dependencies]
tek_core = { path = "../tek_core" }
tek_jack = { path = "../tek_jack" }
atomic_float = "1.0.0"
[lib]
path = "src/lib.rs"
[[bin]]
name = "tek_timer"
path = "src/transport_main.rs"

View file

@ -1,13 +0,0 @@
# `tek_timer`
This crate implements time sync and JACK transport control.
* Warning: If transport is set rolling by qjackctl, this program can't pause it
* Todo: bpm: shift +/- 0.001
* Todo: quant/sync: shift = next/prev value of same type (normal, triplet, dotted)
* Or: use shift to switch between inc/dec top/bottom value?
* Todo: focus play button
* Todo: focus time position
* Todo: edit numeric values
* Todo: jump to time/bbt markers
* Todo: count xruns