mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-03-13 11:50:44 +01:00
closer and closer to testing it away
This commit is contained in:
parent
817d2a722c
commit
4aef21f60d
10 changed files with 1782 additions and 2028 deletions
82
Cargo.lock
generated
82
Cargo.lock
generated
|
|
@ -140,9 +140,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.101"
|
||||
version = "1.0.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea"
|
||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||
|
||||
[[package]]
|
||||
name = "approx"
|
||||
|
|
@ -398,7 +398,7 @@ dependencies = [
|
|||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -476,7 +476,7 @@ checksum = "eb0240417fe20ccf13397fa25e6f0a987dbbfaf27d9e13532419df7f593e65e8"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
|
|
@ -613,7 +613,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -642,7 +642,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -653,7 +653,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
|
|||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -675,7 +675,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -815,7 +815,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -880,7 +880,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1046,7 +1046,7 @@ dependencies = [
|
|||
"indoc",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1148,9 +1148,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.85"
|
||||
version = "0.3.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3"
|
||||
checksum = "93f0862381daaec758576dcc22eb7bbf4d7efd67328553f3b45a412a51a3fb21"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -1416,7 +1416,7 @@ dependencies = [
|
|||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1684,7 +1684,7 @@ dependencies = [
|
|||
"by_address",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1777,7 +1777,7 @@ dependencies = [
|
|||
"phf_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1806,7 +1806,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1851,7 +1851,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1899,7 +1899,7 @@ checksum = "4ee1c9ac207483d5e7db4940700de86a9aae46ef90c48b57f99fe7edb8345e49"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2253,7 +2253,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2404,7 +2404,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2615,9 +2615,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.116"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -2704,7 +2704,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2715,7 +2715,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2946,9 +2946,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.108"
|
||||
version = "0.2.110"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566"
|
||||
checksum = "1de241cdc66a9d91bd84f097039eb140cdc6eec47e0cdbaf9d932a1dd6c35866"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
|
|
@ -2959,9 +2959,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.58"
|
||||
version = "0.4.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f"
|
||||
checksum = "a42e96ea38f49b191e08a1bab66c7ffdba24b06f9995b39a9dd60222e5b6f1da"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
|
|
@ -2973,9 +2973,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.108"
|
||||
version = "0.2.110"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608"
|
||||
checksum = "e12fdf6649048f2e3de6d7d5ff3ced779cdedee0e0baffd7dff5cdfa3abc8a52"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
|
@ -2983,22 +2983,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.108"
|
||||
version = "0.2.110"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55"
|
||||
checksum = "0e63d1795c565ac3462334c1e396fd46dbf481c40f51f5072c310717bc4fb309"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.108"
|
||||
version = "0.2.110"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12"
|
||||
checksum = "e9f9cdac23a5ce71f6bf9f8824898a501e511892791ea2a0c6b8568c68b9cb53"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
|
@ -3161,9 +3161,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.85"
|
||||
version = "0.3.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598"
|
||||
checksum = "f2c7c5718134e770ee62af3b6b4a84518ec10101aad610c024b64d6ff29bb1ff"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -3464,7 +3464,7 @@ dependencies = [
|
|||
"heck",
|
||||
"indexmap",
|
||||
"prettyplease",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
"wasm-metadata",
|
||||
"wit-bindgen-core",
|
||||
"wit-component",
|
||||
|
|
@ -3480,7 +3480,7 @@ dependencies = [
|
|||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
"wit-bindgen-core",
|
||||
"wit-bindgen-rust",
|
||||
]
|
||||
|
|
@ -3602,7 +3602,7 @@ checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.116",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
8
Justfile
8
Justfile
|
|
@ -13,8 +13,8 @@ bacon:
|
|||
check:
|
||||
reset && cargo check
|
||||
|
||||
test:
|
||||
cargo test --workspace --exclude jack
|
||||
test +ARGS="":
|
||||
cargo test --workspace --exclude jack --exclude jack-sys {{ARGS}}
|
||||
|
||||
covfig := "CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' RUSTDOCFLAGS='-Cinstrument-coverage' LLVM_PROFILE_FILE='cov/cargo-test-%p-%m.profraw'"
|
||||
grcov-binary := "--binary-path ./target/coverage/deps/"
|
||||
|
|
@ -130,3 +130,7 @@ plugin:
|
|||
rg 'TODO' app/ | cat
|
||||
rg 'TODO' app/ | wc -l
|
||||
echo
|
||||
|
||||
new:
|
||||
cargo build
|
||||
target/debug/tek new
|
||||
|
|
|
|||
|
|
@ -1076,3 +1076,64 @@
|
|||
//}
|
||||
//};
|
||||
//}
|
||||
//take!(MidiInputCommand |state: Arrangement, iter|state.selected_midi_in().as_ref()
|
||||
//.map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten()));
|
||||
//take!(MidiOutputCommand |state: Arrangement, iter|state.selected_midi_out().as_ref()
|
||||
//.map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten()));
|
||||
|
||||
//impl<T, U: Has<Option<T>>> MaybeHas<T> for U {
|
||||
//fn get (&self) -> Option<&T> {
|
||||
//Has::<Option<T>>::get(self).as_ref()
|
||||
//}
|
||||
//}
|
||||
//
|
||||
//// DRAW SAMPLE ADD:
|
||||
//let area = to.area();
|
||||
//to.make_dim();
|
||||
//let area = center_box(
|
||||
//area,
|
||||
//64.max(area.w().saturating_sub(8)),
|
||||
//20.max(area.w().saturating_sub(8)),
|
||||
//);
|
||||
//to.fill_fg(area, Color::Reset);
|
||||
//to.fill_bg(area, Nord::bg_lo(true, true));
|
||||
//to.fill_char(area, ' ');
|
||||
//to.blit(&format!("{}", &self.dir.to_string_lossy()), area.x()+2, area.y()+1, Some(Style::default().bold()))?;
|
||||
//to.blit(&"Select sample:", area.x()+2, area.y()+2, Some(Style::default().bold()))?;
|
||||
//for (i, (is_dir, name)) in self.subdirs.iter()
|
||||
//.map(|path|(true, path))
|
||||
//.chain(self.files.iter().map(|path|(false, path)))
|
||||
//.enumerate()
|
||||
//.skip(self.offset)
|
||||
//{
|
||||
//if i >= area.h() as usize - 4 {
|
||||
//break
|
||||
//}
|
||||
//let t = if is_dir { "" } else { "" };
|
||||
//let line = format!("{t} {}", name.to_string_lossy());
|
||||
//let line = &line[..line.len().min(area.w() as usize - 4)];
|
||||
//to.blit(&line, area.x() + 2, area.y() + 3 + i as u16, Some(if i == self.cursor {
|
||||
//Style::default().green()
|
||||
//} else {
|
||||
//Style::default().white()
|
||||
//}))?;
|
||||
//}
|
||||
//Lozenge(Style::default()).draw(to)
|
||||
//let cells_x = 8u16;
|
||||
//let cells_y = 8u16;
|
||||
//let cell_width = 10u16;
|
||||
//let cell_height = 2u16;
|
||||
//let width = cells_x * cell_width;
|
||||
//let height = cells_y * cell_height;
|
||||
//let cols = Map::east(
|
||||
//cell_width,
|
||||
//move||0..cells_x,
|
||||
//move|x, _|Map::south(
|
||||
//cell_height,
|
||||
//move||0..cells_y,
|
||||
//move|y, _|self.view_grid_cell("........", x, y, cell_width, cell_height)
|
||||
//)
|
||||
//);
|
||||
//cols
|
||||
//Thunk::new(|to: &mut TuiOut|{
|
||||
//})
|
||||
|
|
|
|||
167
app/tek.rs
167
app/tek.rs
|
|
@ -22,6 +22,10 @@ pub(crate) use ::midly::{Smf, TrackEventKind, MidiMessage, Error as MidiError, n
|
|||
pub extern crate tengri;
|
||||
pub(crate) use tengri::{
|
||||
*,
|
||||
dizzle::{
|
||||
self,
|
||||
*
|
||||
},
|
||||
ratatui::{
|
||||
self,
|
||||
prelude::{Rect, Style, Stylize, Buffer, Modifier, buffer::Cell, Color::{self, *}},
|
||||
|
|
@ -76,9 +80,10 @@ pub(crate) use JackState::*;
|
|||
///
|
||||
/// ```
|
||||
/// let jack = tek::Jack::new(&"test_tek").expect("failed to connect to jack");
|
||||
/// let proj = Default::default();
|
||||
/// let conf = Default::default();
|
||||
/// let tek = tek::tek(&jack, proj, conf, "mode-doctest");
|
||||
/// let proj = tek::Arrangement::default();
|
||||
/// let mut conf = tek::Config::default();
|
||||
/// conf.add("(mode hello)");
|
||||
/// let tek = tek::tek(&jack, proj, conf, "hello");
|
||||
/// ```
|
||||
pub fn tek (
|
||||
jack: &Jack<'static>, project: Arrangement, config: Config, mode: impl AsRef<str>
|
||||
|
|
@ -124,55 +129,22 @@ fn tek_dec (state: &mut App, axis: &ControlAxis) -> Perhaps<AppCommand> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn load_view (views: &Views, name: &impl AsRef<str>, body: &impl Language) -> Usually<()> {
|
||||
pub(crate) fn load_view (views: &Views, name: &impl AsRef<str>, body: &impl Language) -> Usually<()> {
|
||||
views.write().unwrap().insert(name.as_ref().into(), body.src()?.unwrap_or_default().into());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_mode (modes: &Modes, name: &impl AsRef<str>, body: &impl Language) -> Usually<()> {
|
||||
pub(crate) fn load_mode (modes: &Modes, name: &impl AsRef<str>, body: &impl Language) -> Usually<()> {
|
||||
let mut mode = Mode::default();
|
||||
body.each(|item|mode.add(item))?;
|
||||
modes.write().unwrap().insert(name.as_ref().into(), Arc::new(mode));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_bind (binds: &Binds, name: &impl AsRef<str>, body: &impl Language) -> Usually<()> {
|
||||
let mut map = Bind::new();
|
||||
body.each(|item|if item.expr().head() == Ok(Some("see")) {
|
||||
// TODO
|
||||
Ok(())
|
||||
} else if let Ok(Some(_word)) = item.expr().head().word() {
|
||||
if let Some(key) = TuiEvent::from_dsl(item.expr()?.head()?)? {
|
||||
map.add(key, Binding {
|
||||
commands: [item.expr()?.tail()?.unwrap_or_default().into()].into(),
|
||||
condition: None,
|
||||
description: None,
|
||||
source: None
|
||||
});
|
||||
Ok(())
|
||||
} else if Some(":char") == item.expr()?.head()? {
|
||||
// TODO
|
||||
return Ok(())
|
||||
} else {
|
||||
return Err(format!("Config::load_bind: invalid key: {:?}", item.expr()?.head()?).into())
|
||||
}
|
||||
} else {
|
||||
return Err(format!("Config::load_bind: unexpected: {item:?}").into())
|
||||
})?;
|
||||
binds.write().unwrap().insert(name.as_ref().into(), map);
|
||||
pub(crate) fn load_bind (binds: &Binds, name: &impl AsRef<str>, body: &impl Language) -> Usually<()> {
|
||||
binds.write().unwrap().insert(name.as_ref().into(), Bind::load(body)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// CLI banner.
|
||||
pub(crate) const HEADER: &'static str = r#"
|
||||
|
||||
~ █▀█▀█ █▀▀█ █ █ ~~~ ~ ~ ~~ ~ ~ ~ ~~ ~ ~ ~ ~
|
||||
█ █▀ █▀▀▄ ~ v0.4.0, 2026 winter (or is it) ~
|
||||
~ ▀ █▀▀█ ▀ ▀ ~ ~~~ ~ ~ ~ ~ ~~~ ~~~ ~ ~~ "#;
|
||||
|
||||
fn collect_commands (
|
||||
app: &App, input: &TuiIn
|
||||
) -> Usually<Vec<AppCommand>> {
|
||||
fn collect_commands (app: &App, input: &TuiIn) -> Usually<Vec<AppCommand>> {
|
||||
let mut commands = vec![];
|
||||
for id in app.mode.keys.iter() {
|
||||
if let Some(event_map) = app.config.binds.clone().read().unwrap().get(id.as_ref())
|
||||
|
|
@ -335,42 +307,6 @@ pub fn tek_print_status (project: &Arrangement) {
|
|||
// TODO dawvert integration
|
||||
}
|
||||
|
||||
pub const DEFAULT_PPQ: f64 = 96.0;
|
||||
|
||||
/// FIXME: remove this and use PPQ from timebase everywhere:
|
||||
pub const PPQ: usize = 96;
|
||||
|
||||
/// (pulses, name), assuming 96 PPQ
|
||||
pub const NOTE_DURATIONS: [(usize, &str);26] = [
|
||||
(1, "1/384"), (2, "1/192"),
|
||||
(3, "1/128"), (4, "1/96"),
|
||||
(6, "1/64"), (8, "1/48"),
|
||||
(12, "1/32"), (16, "1/24"),
|
||||
(24, "1/16"), (32, "1/12"),
|
||||
(48, "1/8"), (64, "1/6"),
|
||||
(96, "1/4"), (128, "1/3"),
|
||||
(192, "1/2"), (256, "2/3"),
|
||||
(384, "1/1"), (512, "4/3"),
|
||||
(576, "3/2"), (768, "2/1"),
|
||||
(1152, "3/1"), (1536, "4/1"),
|
||||
(2304, "6/1"), (3072, "8/1"),
|
||||
(3456, "9/1"), (6144, "16/1"),
|
||||
];
|
||||
|
||||
pub const NOTE_NAMES: [&str; 128] = [
|
||||
"C0", "C#0", "D0", "D#0", "E0", "F0", "F#0", "G0", "G#0", "A0", "A#0", "B0",
|
||||
"C1", "C#1", "D1", "D#1", "E1", "F1", "F#1", "G1", "G#1", "A1", "A#1", "B1",
|
||||
"C2", "C#2", "D2", "D#2", "E2", "F2", "F#2", "G2", "G#2", "A2", "A#2", "B2",
|
||||
"C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", "G#3", "A3", "A#3", "B3",
|
||||
"C4", "C#4", "D4", "D#4", "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4",
|
||||
"C5", "C#5", "D5", "D#5", "E5", "F5", "F#5", "G5", "G#5", "A5", "A#5", "B5",
|
||||
"C6", "C#6", "D6", "D#6", "E6", "F6", "F#6", "G6", "G#6", "A6", "A#6", "B6",
|
||||
"C7", "C#7", "D7", "D#7", "E7", "F7", "F#7", "G7", "G#7", "A7", "A#7", "B7",
|
||||
"C8", "C#8", "D8", "D#8", "E8", "F8", "F#8", "G8", "G#8", "A8", "A#8", "B8",
|
||||
"C9", "C#9", "D9", "D#9", "E9", "F9", "F#9", "G9", "G#9", "A9", "A#9", "B9",
|
||||
"C10", "C#10", "D10", "D#10", "E10", "F10", "F#10", "G10",
|
||||
];
|
||||
|
||||
/// Return boxed iterator of MIDI events
|
||||
pub fn parse_midi_input <'a> (input: ::jack::MidiIter<'a>)
|
||||
-> Box<dyn Iterator<Item=(usize, LiveEvent<'a>, &'a [u8])> + 'a>
|
||||
|
|
@ -1261,15 +1197,49 @@ mod view {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn sampler_jack_process (
|
||||
state: &mut Sampler, _: &Client, scope: &ProcessScope
|
||||
) -> Control {
|
||||
if let Some(midi_in) = &state.midi_in {
|
||||
for midi in midi_in.port().iter(scope) {
|
||||
sampler_midi_in(&state.samples, &state.voices, midi)
|
||||
}
|
||||
}
|
||||
state.process_audio_out(scope);
|
||||
state.process_audio_in(scope);
|
||||
Control::Continue
|
||||
}
|
||||
|
||||
/// Create [Voice]s from [Sample]s in response to MIDI input.
|
||||
pub(crate) fn sampler_midi_in (
|
||||
samples: &SampleKit<128>, voices: &Arc<RwLock<Vec<Voice>>>, RawMidi { time, bytes }: RawMidi
|
||||
) {
|
||||
if let Ok(LiveEvent::Midi { message, .. }) = LiveEvent::parse(bytes) {
|
||||
match message {
|
||||
MidiMessage::NoteOn { ref key, ref vel } => {
|
||||
if let Some(sample) = samples.get(key.as_int() as usize) {
|
||||
voices.write().unwrap().push(Sample::play(sample, time as usize, vel));
|
||||
}
|
||||
},
|
||||
MidiMessage::Controller { controller: _, value: _ } => {
|
||||
// TODO
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)] mod test_view_meter {
|
||||
use super::*;
|
||||
use proptest::prelude::*;
|
||||
proptest! {
|
||||
|
||||
#[test] fn proptest_view_meter (
|
||||
label in "\\PC*", value in f32::MIN..f32::MAX
|
||||
) {
|
||||
let _ = view_meter(&label, value);
|
||||
}
|
||||
|
||||
#[test] fn proptest_view_meters (
|
||||
value1 in f32::MIN..f32::MAX,
|
||||
value2 in f32::MIN..f32::MAX
|
||||
|
|
@ -1278,3 +1248,46 @@ mod view {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const DEFAULT_PPQ: f64 = 96.0;
|
||||
|
||||
/// FIXME: remove this and use PPQ from timebase everywhere:
|
||||
pub const PPQ: usize = 96;
|
||||
|
||||
/// (pulses, name), assuming 96 PPQ
|
||||
pub const NOTE_DURATIONS: [(usize, &str);26] = [
|
||||
(1, "1/384"), (2, "1/192"),
|
||||
(3, "1/128"), (4, "1/96"),
|
||||
(6, "1/64"), (8, "1/48"),
|
||||
(12, "1/32"), (16, "1/24"),
|
||||
(24, "1/16"), (32, "1/12"),
|
||||
(48, "1/8"), (64, "1/6"),
|
||||
(96, "1/4"), (128, "1/3"),
|
||||
(192, "1/2"), (256, "2/3"),
|
||||
(384, "1/1"), (512, "4/3"),
|
||||
(576, "3/2"), (768, "2/1"),
|
||||
(1152, "3/1"), (1536, "4/1"),
|
||||
(2304, "6/1"), (3072, "8/1"),
|
||||
(3456, "9/1"), (6144, "16/1"),
|
||||
];
|
||||
|
||||
pub const NOTE_NAMES: [&str; 128] = [
|
||||
"C0", "C#0", "D0", "D#0", "E0", "F0", "F#0", "G0", "G#0", "A0", "A#0", "B0",
|
||||
"C1", "C#1", "D1", "D#1", "E1", "F1", "F#1", "G1", "G#1", "A1", "A#1", "B1",
|
||||
"C2", "C#2", "D2", "D#2", "E2", "F2", "F#2", "G2", "G#2", "A2", "A#2", "B2",
|
||||
"C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", "G#3", "A3", "A#3", "B3",
|
||||
"C4", "C#4", "D4", "D#4", "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4",
|
||||
"C5", "C#5", "D5", "D#5", "E5", "F5", "F#5", "G5", "G#5", "A5", "A#5", "B5",
|
||||
"C6", "C#6", "D6", "D#6", "E6", "F6", "F#6", "G6", "G#6", "A6", "A#6", "B6",
|
||||
"C7", "C#7", "D7", "D#7", "E7", "F7", "F#7", "G7", "G#7", "A7", "A#7", "B7",
|
||||
"C8", "C#8", "D8", "D#8", "E8", "F8", "F#8", "G8", "G#8", "A8", "A#8", "B8",
|
||||
"C9", "C#9", "D9", "D#9", "E9", "F9", "F#9", "G9", "G#9", "A9", "A#9", "B9",
|
||||
"C10", "C#10", "D10", "D#10", "E10", "F10", "F#10", "G10",
|
||||
];
|
||||
|
||||
/// CLI banner.
|
||||
pub(crate) const HEADER: &'static str = r#"
|
||||
|
||||
~ █▀█▀█ █▀▀█ █ █ ~~~ ~ ~ ~~ ~ ~ ~ ~~ ~ ~ ~ ~
|
||||
█ █▀ █▀▀▄ ~ v0.4.0, 2026 winter (or is it) ~
|
||||
~ ▀ █▀▀█ ▀ ▀ ~ ~~~ ~ ~ ~ ~ ~~~ ~~~ ~ ~~ "#;
|
||||
|
|
|
|||
3358
app/tek_impls.rs
3358
app/tek_impls.rs
File diff suppressed because it is too large
Load diff
|
|
@ -147,10 +147,13 @@ pub struct JackNotify<T: Fn(JackEvent) + Send>(pub T);
|
|||
pub modes: Modes,
|
||||
}
|
||||
|
||||
/// An input binding.
|
||||
/// An map of input events (e.g. [TuiEvent]) to [Binding]s.
|
||||
///
|
||||
/// ```
|
||||
/// let bind = tek::Bind::<(), ()>::default();
|
||||
/// let lang = "(@x (nop)) (@y (nop) (nop))";
|
||||
/// let bind = tek::Bind::<tek::tengri::TuiEvent, std::sync::Arc<str>>::load(&lang).unwrap();
|
||||
/// assert_eq!(bind.query(&'x'.into()).map(|x|x.len()), Some(1));
|
||||
/// //assert_eq!(bind.query(&'y'.into()).map(|x|x.len()), Some(2));
|
||||
/// ```
|
||||
#[derive(Debug)] pub struct Bind<E, C>(
|
||||
/// Map of each event (e.g. key combination) to
|
||||
|
|
@ -159,10 +162,12 @@ pub struct JackNotify<T: Fn(JackEvent) + Send>(pub T);
|
|||
pub BTreeMap<E, Vec<Binding<C>>>
|
||||
);
|
||||
|
||||
/// An input binding.
|
||||
/// A sequence of zero or more commands (e.g. [AppCommand]),
|
||||
/// optionally filtered by [Condition] to form layers.
|
||||
///
|
||||
/// ```
|
||||
/// let binding: tek::Binding<()> = Default::default();
|
||||
/// //FIXME: Why does it overflow?
|
||||
/// //let binding: Binding<()> = tek::Binding { ..Default::default() };
|
||||
/// ```
|
||||
#[derive(Debug, Clone)] pub struct Binding<C> {
|
||||
pub commands: Arc<[C]>,
|
||||
|
|
@ -302,7 +307,7 @@ pub struct JackNotify<T: Fn(JackEvent) + Send>(pub T);
|
|||
/// Temporal resolutions: sample rate, tempo, MIDI pulses per quaver (beat)
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// let _ = tek::Timebase::default();
|
||||
/// ```
|
||||
#[derive(Debug, Clone)] pub struct Timebase {
|
||||
/// Audio samples per second
|
||||
|
|
@ -316,15 +321,28 @@ pub struct JackNotify<T: Fn(JackEvent) + Send>(pub T);
|
|||
/// Iterator that emits subsequent ticks within a range.
|
||||
///
|
||||
/// ```
|
||||
/// let iter = tek::TicksIterator::default();
|
||||
/// let iter = tek::Ticker::default();
|
||||
/// ```
|
||||
#[derive(Debug, Default)] pub struct TicksIterator {
|
||||
#[derive(Debug, Default)] pub struct Ticker {
|
||||
pub spp: f64,
|
||||
pub sample: usize,
|
||||
pub start: usize,
|
||||
pub end: usize,
|
||||
}
|
||||
|
||||
///
|
||||
/// ```
|
||||
/// let _ = tek::MidiCursor::default();
|
||||
/// ```
|
||||
#[derive(Debug, Clone)] pub struct MidiCursor {
|
||||
/// Time coordinate of cursor
|
||||
pub time_pos: Arc<AtomicUsize>,
|
||||
/// Note coordinate of cursor
|
||||
pub note_pos: Arc<AtomicUsize>,
|
||||
/// Length of note that will be inserted, in pulses
|
||||
pub note_len: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
///
|
||||
/// ```
|
||||
/// use tek::{TimeRange, NoteRange};
|
||||
|
|
@ -341,19 +359,6 @@ pub struct JackNotify<T: Fn(JackEvent) + Send>(pub T);
|
|||
/// let _ = model.get_note_axis();
|
||||
/// let _ = model.get_note_hi();
|
||||
/// ```
|
||||
#[derive(Debug, Clone)] pub struct MidiCursor {
|
||||
/// Time coordinate of cursor
|
||||
pub time_pos: Arc<AtomicUsize>,
|
||||
/// Note coordinate of cursor
|
||||
pub note_pos: Arc<AtomicUsize>,
|
||||
/// Length of note that will be inserted, in pulses
|
||||
pub note_len: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Default)] pub struct MidiSelection {
|
||||
pub time_len: Arc<AtomicUsize>,
|
||||
/// Length of visible time axis
|
||||
|
|
@ -373,7 +378,7 @@ pub struct JackNotify<T: Fn(JackEvent) + Send>(pub T);
|
|||
/// A point in time in all time scales (microsecond, sample, MIDI pulse)
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// let _ = tek::Moment::default();
|
||||
/// ```
|
||||
#[derive(Debug, Default, Clone)] pub struct Moment {
|
||||
pub timebase: Arc<Timebase>,
|
||||
|
|
@ -387,7 +392,7 @@ pub struct JackNotify<T: Fn(JackEvent) + Send>(pub T);
|
|||
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// let _ = tek::Moment2::default();
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Default)] pub enum Moment2 {
|
||||
#[default] None,
|
||||
|
|
@ -834,28 +839,18 @@ pub struct PoolView<'a>(pub &'a Pool);
|
|||
pub name: Arc<str>,
|
||||
/// Device color.
|
||||
pub color: ItemTheme,
|
||||
/// Audio input ports. Samples get recorded here.
|
||||
#[cfg(feature = "port")] pub audio_ins: Vec<AudioInput>,
|
||||
/// Audio input meters.
|
||||
#[cfg(feature = "meter")] pub input_meters: Vec<f32>,
|
||||
/// Sample currently being recorded.
|
||||
pub recording: Option<(usize, Option<Arc<RwLock<Sample>>>)>,
|
||||
/// Recording buffer.
|
||||
pub buffer: Vec<Vec<f32>>,
|
||||
/// Samples mapped to MIDI notes.
|
||||
pub samples: SampleKit<128>,
|
||||
/// Collection of currently playing instances of samples.
|
||||
pub voices: Arc<RwLock<Vec<Voice>>>,
|
||||
/// Samples that are not mapped to MIDI notes.
|
||||
pub unmapped: Vec<Arc<RwLock<Sample>>>,
|
||||
/// Sample currently being edited.
|
||||
pub editing: Option<Arc<RwLock<Sample>>>,
|
||||
/// MIDI input port. Triggers sample playback.
|
||||
#[cfg(feature = "port")] pub midi_in: Option<MidiInput>,
|
||||
/// Collection of currently playing instances of samples.
|
||||
pub voices: Arc<RwLock<Vec<Voice>>>,
|
||||
/// Audio output ports. Voices get played here.
|
||||
#[cfg(feature = "port")] pub audio_outs: Vec<AudioOutput>,
|
||||
/// Audio output meters.
|
||||
#[cfg(feature = "meter")] pub output_meters: Vec<f32>,
|
||||
/// How to mix the voices.
|
||||
pub mixing_mode: MixingMode,
|
||||
/// How to meter the inputs and outputs.
|
||||
|
|
@ -872,6 +867,16 @@ pub struct PoolView<'a>(pub &'a Pool);
|
|||
pub note_pt: AtomicUsize,
|
||||
/// Selected note as row/col.
|
||||
pub cursor: (AtomicUsize, AtomicUsize),
|
||||
/// Audio input meters.
|
||||
#[cfg(feature = "meter")] pub input_meters: Vec<f32>,
|
||||
/// Audio input ports. Samples are recorded from here.
|
||||
#[cfg(feature = "port")] pub audio_ins: Vec<AudioInput>,
|
||||
/// MIDI input port. Sampler are triggered from here.
|
||||
#[cfg(feature = "port")] pub midi_in: Option<MidiInput>,
|
||||
/// Audio output ports. Voices are played into here.
|
||||
#[cfg(feature = "port")] pub audio_outs: Vec<AudioOutput>,
|
||||
/// Audio output meters.
|
||||
#[cfg(feature = "meter")] pub output_meters: Vec<f32>,
|
||||
}
|
||||
|
||||
/// Collection of samples, one per slot, fixed number of slots.
|
||||
|
|
@ -909,7 +914,7 @@ pub struct PoolView<'a>(pub &'a Pool);
|
|||
pub velocity: f32,
|
||||
}
|
||||
|
||||
pub struct AddSampleModal {
|
||||
#[derive(Default, Debug)] pub struct SampleAdd {
|
||||
pub exited: bool,
|
||||
pub dir: PathBuf,
|
||||
pub subdirs: Vec<OsString>,
|
||||
|
|
|
|||
|
|
@ -318,9 +318,14 @@ pub trait HasScenes: Has<Vec<Scene>> + Send + Sync {
|
|||
|
||||
/// ```
|
||||
/// use tek::{MidiEditor, HasEditor, tengri::Has};
|
||||
/// struct TestEditorHost(Option<MidiEditor>);
|
||||
/// tek::tengri::has!(Option<MidiEditor>: |self: TestEditorHost|self.0);
|
||||
///
|
||||
/// let mut host = TestEditorHost(Some(MidiEditor::default()));
|
||||
/// struct TestEditorHost(Option<MidiEditor>);
|
||||
/// impl Has<Option<MidiEditor>> for TestEditorHost {
|
||||
/// fn get (&self) -> &Option<MidiEditor> { &self.0 }
|
||||
/// fn get_mut (&mut self) -> &mut Option<MidiEditor> { &mut self.0 }
|
||||
/// }
|
||||
///
|
||||
/// let _ = host.editor();
|
||||
/// let _ = host.editor_mut();
|
||||
/// let _ = host.is_editing();
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ command = ["cargo", "clippy", "--all-targets"]
|
|||
need_stdout = false
|
||||
watch = ["dizzle", "tengri", "app"]
|
||||
[jobs.test]
|
||||
command = ["cargo", "test", "--workspace", "--exclude", "jack"]
|
||||
command = ["cargo", "test", "--workspace", "--exclude", "jack", "--exclude", "jack-sys"]
|
||||
need_stdout = true
|
||||
watch = ["dizzle", "tengri", "app"]
|
||||
[jobs.nextest]
|
||||
|
|
|
|||
2
dizzle
2
dizzle
|
|
@ -1 +1 @@
|
|||
Subproject commit 624ac97274fbf974f1196864bb93093c31cb0fd7
|
||||
Subproject commit f6fb8c844a31b35f5739297272250ff9c7fee345
|
||||
2
tengri
2
tengri
|
|
@ -1 +1 @@
|
|||
Subproject commit c1011ddb7f8061c5fe242b6eab62a66537ae671b
|
||||
Subproject commit b294f2e62b970cf4e1cb133346132a0a113af575
|
||||
Loading…
Add table
Add a link
Reference in a new issue