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

View file

@ -1,5 +1,6 @@
(@up sampler select :sample-up)
(@down sampler select :sample-down)
(@left sampler select :sample-left)
(@right sampler select :sample-right)
(@r sampler record/toggle :sample)
(@up sampler select :sample-above)
(@down sampler select :sample-below)
(@left sampler select :sample-to-left)
(@right sampler select :sample-to-right)
(@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));
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> {
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> {
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 {

View file

@ -129,8 +129,9 @@ impl Configuration {
}
print!("{path:?}...");
let keys = read_and_leak(path)?.into();
println!("ok");
let cond = cond.unwrap();
print!("{exp:?}...");
println!("ok");
map.add_layer_if(
Box::new(move |state|{
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::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::midi::{u7, LiveEvent, MidiMessage};
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 {
#[cfg(feature = "sequencer")] Sequencer(MidiPlayer),
#[cfg(feature = "sampler")] Sampler(Sampler),
#[cfg(feature = "plugin")] Plugin(Plugin),
#[cfg(feature = "lv2")] Lv2, // TODO
#[cfg(feature = "lv2")] Lv2(Lv2), // TODO
#[cfg(feature = "vst2")] Vst2, // TODO
#[cfg(feature = "vst3")] Vst3, // TODO
#[cfg(feature = "clap")] Clap, // TODO

View file

@ -43,13 +43,50 @@ impl Sampler {
//fn selected_pitch () -> u7 {
//(self.note_pos() as u8).into() // TODO
//}
//fn selected_sample () -> u7 { // TODO
//(self.note_pos() as u8).into()
//}
fn sample_selected (&self) -> usize {
(self.get_note_pos() as u8).into()
}
fn sample_selected_pitch (&self) -> u7 {
(self.get_note_pos() as u8).into()
}
}
#[tengri_proc::command(Sampler)]
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> {
//Self::Select(state.set_note_pos(i))
//}
@ -60,28 +97,6 @@ impl SamplerCommand {
//self.mapped[i] = sample;
//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> {
//todo!()
//}

View file

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

View file

@ -16,7 +16,7 @@ impl Sampler {
voices.write().unwrap().push(Sample::play(sample, time as usize, vel));
}
},
MidiMessage::Controller { controller, value } => {
MidiMessage::Controller { controller: _, value: _ } => {
// 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::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::*;
/// 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> {
/// Returns current value
fn get (&self) -> T;

2
deps/tengri vendored

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