Compare commits

..

4 commits

Author SHA1 Message Date
fb99128650 groovebox: reenable sampler record_finish
Some checks are pending
/ build (push) Waiting to run
2025-05-10 16:38:00 +03:00
5648c96c6a groovebox: record at selected pitch 2025-05-10 16:10:52 +03:00
7b09d97473 groovebox: reenable sampling but only at pitch 0 2025-05-10 16:03:06 +03:00
986e0a42a1 groovebox: don't crash on 'r' 2025-05-10 15:50:35 +03:00
10 changed files with 105 additions and 77 deletions

30
Cargo.lock generated
View file

@ -40,7 +40,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"getrandom 0.3.2", "getrandom 0.3.3",
"once_cell", "once_cell",
"version_check", "version_check",
"zerocopy", "zerocopy",
@ -302,9 +302,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.21" version = "1.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1"
dependencies = [ dependencies = [
"jobserver", "jobserver",
"libc", "libc",
@ -720,9 +720,9 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.3.2" version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@ -897,7 +897,7 @@ version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
dependencies = [ dependencies = [
"getrandom 0.3.2", "getrandom 0.3.3",
"libc", "libc",
] ]
@ -1939,9 +1939,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]] [[package]]
name = "signal-hook" name = "signal-hook"
version = "0.3.17" version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
dependencies = [ dependencies = [
"libc", "libc",
"signal-hook-registry", "signal-hook-registry",
@ -2325,7 +2325,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
dependencies = [ dependencies = [
"fastrand", "fastrand",
"getrandom 0.3.2", "getrandom 0.3.3",
"once_cell", "once_cell",
"rustix 1.0.7", "rustix 1.0.7",
"windows-sys 0.59.0", "windows-sys 0.59.0",
@ -2335,18 +2335,24 @@ dependencies = [
name = "tengri" name = "tengri"
version = "0.13.0" version = "0.13.0"
dependencies = [ dependencies = [
"tengri_core",
"tengri_dsl", "tengri_dsl",
"tengri_input", "tengri_input",
"tengri_output", "tengri_output",
"tengri_tui", "tengri_tui",
] ]
[[package]]
name = "tengri_core"
version = "0.13.0"
[[package]] [[package]]
name = "tengri_dsl" name = "tengri_dsl"
version = "0.13.0" version = "0.13.0"
dependencies = [ dependencies = [
"itertools 0.14.0", "itertools 0.14.0",
"konst", "konst",
"tengri_core",
"thiserror 2.0.12", "thiserror 2.0.12",
] ]
@ -2354,6 +2360,7 @@ dependencies = [
name = "tengri_input" name = "tengri_input"
version = "0.13.0" version = "0.13.0"
dependencies = [ dependencies = [
"tengri_core",
"tengri_dsl", "tengri_dsl",
] ]
@ -2361,6 +2368,7 @@ dependencies = [
name = "tengri_output" name = "tengri_output"
version = "0.13.0" version = "0.13.0"
dependencies = [ dependencies = [
"tengri_core",
"tengri_dsl", "tengri_dsl",
] ]
@ -2372,6 +2380,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
"tengri_core",
] ]
[[package]] [[package]]
@ -2386,6 +2395,7 @@ dependencies = [
"quanta", "quanta",
"rand", "rand",
"ratatui", "ratatui",
"tengri_core",
"tengri_dsl", "tengri_dsl",
"tengri_input", "tengri_input",
"tengri_output", "tengri_output",
@ -2588,7 +2598,7 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
dependencies = [ dependencies = [
"getrandom 0.3.2", "getrandom 0.3.3",
] ]
[[package]] [[package]]

View file

@ -1,5 +1,6 @@
(@up sampler select :sample-up) (@up sampler select :sample-above)
(@down sampler select :sample-down) (@down sampler select :sample-below)
(@left sampler select :sample-left) (@left sampler select :sample-to-left)
(@right sampler select :sample-right) (@right sampler select :sample-to-right)
(@r sampler record/toggle :sample) (@r sampler record-toggle :sample-selected)
(@shift-R sampler record-cancel)

View file

@ -287,29 +287,6 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm
app.toggle_editor(Some(value)); app.toggle_editor(Some(value));
Ok(None) Ok(None)
} }
fn editor (app: &mut App, command: MidiEditCommand) -> Perhaps<Self> {
Ok(app.editor.as_mut().map(|editor|command.execute(editor))
.transpose()?
.flatten()
.map(|undo|Self::Editor { command: undo }))
}
fn pool (app: &mut App, command: PoolCommand) -> Perhaps<Self> {
Ok(if let Some(pool) = app.pool.as_mut() {
let undo = command.clone().delegate(pool, |command|AppCommand::Pool{command})?;
// update linked editor after pool action
app.editor.as_mut().map(|editor|match command {
// autoselect: automatically load selected clip in editor
PoolCommand::Select { .. } |
// autocolor: update color in all places simultaneously
PoolCommand::Clip { command: PoolClipCommand::SetColor { .. } } =>
editor.set_clip(pool.clip().as_ref()),
_ => {}
});
undo
} else {
None
})
}
fn color (app: &mut App, theme: ItemTheme) -> Perhaps<Self> { fn color (app: &mut App, theme: ItemTheme) -> Perhaps<Self> {
Ok(app.set_color(Some(theme)).map(|theme|Self::Color{theme})) Ok(app.set_color(Some(theme)).map(|theme|Self::Color{theme}))
} }
@ -369,6 +346,37 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm
fn message (app: &mut App, command: MessageCommand) -> Perhaps<Self> { fn message (app: &mut App, command: MessageCommand) -> Perhaps<Self> {
Ok(command.delegate(app, |command|Self::Message{command})?) Ok(command.delegate(app, |command|Self::Message{command})?)
} }
fn editor (app: &mut App, command: MidiEditCommand) -> Perhaps<Self> {
Ok(if let Some(editor) = app.editor.as_mut() {
let undo = command.clone().delegate(editor, |command|AppCommand::Editor{command})?;
// update linked sampler after editor action
app.sampler_mut().map(|sampler|match command {
// autoselect: automatically select sample in sampler
MidiEditCommand::NotePos { pos } => { sampler.set_note_pos(pos); },
_ => {}
});
undo
} else {
None
})
}
fn pool (app: &mut App, command: PoolCommand) -> Perhaps<Self> {
Ok(if let Some(pool) = app.pool.as_mut() {
let undo = command.clone().delegate(pool, |command|AppCommand::Pool{command})?;
// update linked editor after pool action
app.editor.as_mut().map(|editor|match command {
// autoselect: automatically load selected clip in editor
PoolCommand::Select { .. } |
// autocolor: update color in all places simultaneously
PoolCommand::Clip { command: PoolClipCommand::SetColor { .. } } =>
editor.set_clip(pool.clip().as_ref()),
_ => {}
});
undo
} else {
None
})
}
} }
impl<'state> Context<'state, ClockCommand> for App { impl<'state> Context<'state, ClockCommand> for App {

View file

@ -129,8 +129,9 @@ impl Configuration {
} }
print!("{path:?}..."); print!("{path:?}...");
let keys = read_and_leak(path)?.into(); let keys = read_and_leak(path)?.into();
println!("ok");
let cond = cond.unwrap(); let cond = cond.unwrap();
print!("{exp:?}...");
println!("ok");
map.add_layer_if( map.add_layer_if(
Box::new(move |state|{ Box::new(move |state|{
let mut exp = exp.clone(); let mut exp = exp.clone();

View file

@ -9,7 +9,7 @@ pub(crate) use std::path::PathBuf;
pub(crate) use std::error::Error; pub(crate) use std::error::Error;
pub(crate) use std::ffi::OsString; pub(crate) use std::ffi::OsString;
pub(crate) use ::tengri::{dsl::*, input::*, output::*, tui::{*, ratatui::prelude::*}}; pub(crate) use ::tengri::{Usually, Perhaps, dsl::*, input::*, output::*, tui::{*, ratatui::prelude::*}};
pub(crate) use ::tek_engine::*; pub(crate) use ::tek_engine::*;
pub(crate) use ::tek_engine::midi::{u7, LiveEvent, MidiMessage}; pub(crate) use ::tek_engine::midi::{u7, LiveEvent, MidiMessage};
pub(crate) use ::tek_engine::jack::{Control, ProcessScope, MidiWriter, RawMidi}; pub(crate) use ::tek_engine::jack::{Control, ProcessScope, MidiWriter, RawMidi};
@ -43,8 +43,7 @@ pub(crate) use ratatui::{prelude::Rect, widgets::{Widget, canvas::{Canvas, Line}
pub enum Device { pub enum Device {
#[cfg(feature = "sequencer")] Sequencer(MidiPlayer), #[cfg(feature = "sequencer")] Sequencer(MidiPlayer),
#[cfg(feature = "sampler")] Sampler(Sampler), #[cfg(feature = "sampler")] Sampler(Sampler),
#[cfg(feature = "plugin")] Plugin(Plugin), #[cfg(feature = "lv2")] Lv2(Lv2), // TODO
#[cfg(feature = "lv2")] Lv2, // TODO
#[cfg(feature = "vst2")] Vst2, // TODO #[cfg(feature = "vst2")] Vst2, // TODO
#[cfg(feature = "vst3")] Vst3, // TODO #[cfg(feature = "vst3")] Vst3, // TODO
#[cfg(feature = "clap")] Clap, // TODO #[cfg(feature = "clap")] Clap, // TODO

View file

@ -43,13 +43,50 @@ impl Sampler {
//fn selected_pitch () -> u7 { //fn selected_pitch () -> u7 {
//(self.note_pos() as u8).into() // TODO //(self.note_pos() as u8).into() // TODO
//} //}
//fn selected_sample () -> u7 { // TODO fn sample_selected (&self) -> usize {
//(self.note_pos() as u8).into() (self.get_note_pos() as u8).into()
//} }
fn sample_selected_pitch (&self) -> u7 {
(self.get_note_pos() as u8).into()
}
} }
#[tengri_proc::command(Sampler)] #[tengri_proc::command(Sampler)]
impl SamplerCommand { impl SamplerCommand {
fn record_toggle (sampler: &mut Sampler, sample: usize) -> Perhaps<Self> {
if sampler.recording.is_some() {
Self::record_finish(sampler)
} else {
Self::record_begin(sampler, sample)
}
}
fn record_begin (sampler: &mut Sampler, sample: usize) -> Perhaps<Self> {
sampler.recording = Some((
sample,
Arc::new(RwLock::new(Sample::new(
"Sample",
0,
0,
vec![vec![];sampler.audio_ins.len()]
)))
));
Ok(None)
}
fn record_finish (sampler: &mut Sampler) -> Perhaps<Self> {
let recording = sampler.recording.take();
let _sample = if let Some((index, sample)) = recording {
let old = sampler.mapped[index].clone();
sampler.mapped[index] = Some(sample);
old
} else {
None
};
Ok(None)
}
fn record_cancel (sampler: &mut Sampler) -> Perhaps<Self> {
sampler.recording = None;
Ok(None)
}
//fn select (&self, state: &mut Sampler, i: usize) -> Option<Self> { //fn select (&self, state: &mut Sampler, i: usize) -> Option<Self> {
//Self::Select(state.set_note_pos(i)) //Self::Select(state.set_note_pos(i))
//} //}
@ -60,28 +97,6 @@ impl SamplerCommand {
//self.mapped[i] = sample; //self.mapped[i] = sample;
//Some(Self::Set(old)) //Some(Self::Set(old))
//} //}
//fn record_begin (&self, state: &mut Sampler, pitch: u7) -> Option<Self> {
//self.recording = Some((
//pitch.as_int() as usize,
//Arc::new(RwLock::new(Sample::new("Sample", 0, 0, vec![vec![];self.audio_ins.len()])))
//));
//None
//}
//fn record_cancel (&self, state: &mut Sampler) -> Option<Self> {
//self.recording = None;
//None
//}
//fn record_finish (&self, state: &mut Sampler) -> Option<Self> {
//let recording = self.recording.take();
//let _sample = if let Some((index, sample)) = recording {
//let old = self.mapped[index].clone();
//self.mapped[index] = Some(sample);
//old
//} else {
//None
//};
//None
//}
//fn set_start (&self, state: &mut Sampler, pitch: u7, frame: usize) -> Option<Self> { //fn set_start (&self, state: &mut Sampler, pitch: u7, frame: usize) -> Option<Self> {
//todo!() //todo!()
//} //}

View file

@ -144,7 +144,7 @@ fn scan (dir: &PathBuf) -> Usually<(Vec<OsString>, Vec<OsString>)> {
} }
impl Content<TuiOut> for AddSampleModal { impl Content<TuiOut> for AddSampleModal {
fn render (&self, to: &mut TuiOut) { fn render (&self, _to: &mut TuiOut) {
todo!() todo!()
//let area = to.area(); //let area = to.area();
//to.make_dim(); //to.make_dim();

View file

@ -16,7 +16,7 @@ impl Sampler {
voices.write().unwrap().push(Sample::play(sample, time as usize, vel)); voices.write().unwrap().push(Sample::play(sample, time as usize, vel));
} }
}, },
MidiMessage::Controller { controller, value } => { MidiMessage::Controller { controller: _, value: _ } => {
// TODO // TODO
} }
_ => {} _ => {}

View file

@ -9,16 +9,10 @@ pub(crate) use std::sync::{Arc, atomic::{AtomicUsize, AtomicBool, Ordering::Rela
pub(crate) use std::fmt::Debug; pub(crate) use std::fmt::Debug;
pub(crate) use std::ops::{Add, Sub, Mul, Div, Rem}; pub(crate) use std::ops::{Add, Sub, Mul, Div, Rem};
pub(crate) use ::tengri::tui::*; pub(crate) use ::tengri::{Usually, tui::*};
pub use ::atomic_float; pub(crate) use atomic_float::*; pub use ::atomic_float; pub(crate) use atomic_float::*;
/// Standard result type.
pub(crate) type Usually<T> = std::result::Result<T, Box<dyn std::error::Error>>;
/// Standard optional result type.
pub(crate) type Perhaps<T> = std::result::Result<Option<T>, Box<dyn std::error::Error>>;
pub trait Gettable<T> { pub trait Gettable<T> {
/// Returns current value /// Returns current value
fn get (&self) -> T; fn get (&self) -> T;

2
deps/tengri vendored

@ -1 +1 @@
Subproject commit cb8fd26922fd1cfad4ceadeb89e48544531a178e Subproject commit faecc2c304ad2c0ebd78d21170a02c172fd356bf