implement controller traits
Some checks are pending
/ build (push) Waiting to run

This commit is contained in:
i do not exist 2026-08-11 17:41:51 +03:00
parent a4931d8e4f
commit def7a1b210
17 changed files with 2209 additions and 1790 deletions

View file

@ -8,12 +8,28 @@ pub(crate) use symphonia::{
},
};
pub trait HasSampler: AsRef<Sampler> + AsMut<Sampler> {
fn sampler (&self) -> &Sampler {
self.as_ref()
}
fn sampler_mut (&mut self) -> &mut Sampler {
self.as_mut()
}
}
impl<T: AsRef<Sampler> + AsMut<Sampler>> HasSampler for T {}
#[tek_proc::commands(SamplerCommand = "sampler")]
impl Sampler {
pub trait SamplerController: HasSampler
+ for<'a> Namespace<'a, usize>
{
#[command(RecordToggle = "rec-toggle")]
fn record_toggle (&mut self, slot: usize) -> Perhaps<SamplerCommand> {
let recording = self.recording.as_ref().map(|x|x.0);
fn record_toggle (&mut self, slot: usize) -> Perhaps<SamplerCommand>
where Self: Sized
{
let sampler = self.sampler_mut();
let recording = sampler.recording.as_ref().map(|x|x.0);
let _ = SamplerCommand::RecordFinish.act(self)?;
// autoslice: continue recording at next slot
if recording != Some(slot) {
@ -25,10 +41,11 @@ impl Sampler {
#[command(RecordBegin = "rec-begin")]
fn record_begin (&mut self, slot: usize) -> Perhaps<SamplerCommand> {
self.recording = Some((
let sampler = self.sampler_mut();
sampler.recording = Some((
slot,
Some(Arc::new(RwLock::new(Sample::new(
"Sample", 0, 0, vec![vec![];self.audio_ins.len()]
"Sample", 0, 0, vec![vec![]; sampler.audio_ins.len()]
))))
));
Ok(None)
@ -36,8 +53,9 @@ impl Sampler {
#[command(RecordFinish = "rec-finish")]
fn record_finish (&mut self) -> Perhaps<SamplerCommand> {
let _prev_sample = self.recording.as_mut().map(|(index, sample)|{
std::mem::swap(sample, &mut self.samples.0[*index]);
let sampler = self.sampler_mut();
let _prev_sample = sampler.recording.as_mut().map(|(index, sample)|{
std::mem::swap(sample, &mut sampler.samples.0[*index]);
sample
}); // TODO: undo
Ok(None)
@ -45,14 +63,15 @@ impl Sampler {
#[command(RecordCancel = "rec-cancel")]
fn record_cancel (&mut self) -> Perhaps<SamplerCommand> {
self.recording = None;
self.sampler_mut().recording = None;
Ok(None)
}
#[command(PlaySample = "sample-play")]
fn sample_play (&mut self, slot: usize) -> Perhaps<SamplerCommand> {
if let Some(ref sample) = self.samples.0[slot] {
self.voices.write().unwrap().push(Sample::play(sample, 0, &u7::from(128)));
let sampler = self.sampler_mut();
if let Some(ref sample) = sampler.samples.0[slot] {
sampler.voices.write().unwrap().push(Sample::play(sample, 0, &u7::from(128)));
}
Ok(None)
}
@ -730,3 +749,95 @@ impl SampleAdd {
fn read_sample_data (_: &str) -> Usually<(usize, Vec<Vec<f32>>)> {
todo!();
}
pub fn view_sample_info (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> + use<'_> {
when(sample.is_some(), draw(move|to: &mut Tui|{
let sample = sample.unwrap().read().unwrap();
let theme = sample.color;
east!(
field_h(theme, "Name", format!("{:<10}", sample.name.clone())),
field_h(theme, "Length", format!("{:<8}", sample.channels[0].len())),
field_h(theme, "Start", format!("{:<8}", sample.start)),
field_h(theme, "End", format!("{:<8}", sample.end)),
field_h(theme, "Trans", "0"),
field_h(theme, "Gain", format!("{}", sample.gain)),
).draw(to)
}))
}
pub fn view_sample_info_v (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> + use<'_> {
let a = draw(move|to: &mut Tui|{
let sample = sample.unwrap().read().unwrap();
let theme = sample.color;
south!(
field_h(theme, "Name ", format!("{:<10}", sample.name.clone())) .align_w().full_w(),
field_h(theme, "Length", format!("{:<8}", sample.channels[0].len())).align_w().full_w(),
field_h(theme, "Start ", format!("{:<8}", sample.start)) .align_w().full_w(),
field_h(theme, "End ", format!("{:<8}", sample.end)) .align_w().full_w(),
field_h(theme, "Trans ", "0") .align_w().full_w(),
field_h(theme, "Gain ", format!("{}", sample.gain)) .align_w().full_w(),
).exact_w(20).draw(to)
});
let b = draw(|to: &mut Tui|fg(Red, south!(
bold(true, "× No sample."),
"[r] record",
"[Shift-F9] import",
)).draw(to));
either(sample.is_some(), a, b)
}
pub fn view_sample_status (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> {
bold(true, fg(g(224), sample
.map(|sample|{
let sample = sample.read().unwrap();
format!("Sample {}-{}", sample.start, sample.end)
})
.unwrap_or_else(||"No sample".to_string())))
}
#[cfg(feature = "track")]
impl Track {
/// Create a new track connecting the [Sequencer] to a [Sampler].
pub fn new_with_sampler (
name: &impl AsRef<str>,
color: Option<ItemTheme>,
jack: &Jack<'static>,
clock: Option<&Clock>,
clip: Option<&Arc<RwLock<MidiClip>>>,
midi_from: &[Connect],
midi_to: &[Connect],
audio_from: &[&[Connect];2],
audio_to: &[&[Connect];2],
) -> Usually<Self> {
let mut track = Self::new(name, color, jack, clock, clip, midi_from, midi_to)?;
let client_name = jack.with_client(|c|c.name().to_string());
let port_name = track.sequencer.midi_outs[0].port_name();
let connect = [Connect::exact(format!("{client_name}:{}", port_name))];
track.devices.push(Device::Sampler(Sampler::new(
jack, &format!("{}/sampler", name.as_ref()), &connect, audio_from, audio_to
)?));
Ok(track)
}
pub fn sampler (&self, mut nth: usize) -> Option<&Sampler> {
for device in self.devices.iter() {
match device {
Device::Sampler(s) => if nth == 0 { return Some(s); } else { nth -= 1; },
_ => {}
}
}
None
}
pub fn sampler_mut (&mut self, mut nth: usize) -> Option<&mut Sampler> {
for device in self.devices.iter_mut() {
match device {
Device::Sampler(s) => if nth == 0 { return Some(s); } else { nth -= 1; },
_ => {}
}
}
None
}
}