groovebox: looks surprisingly well

This commit is contained in:
🪞👃🪞 2025-05-14 22:17:42 +03:00
parent c66a006120
commit 03024f8a14
11 changed files with 130 additions and 91 deletions

View file

@ -7,20 +7,18 @@ impl Sampler {
/// Create [Voice]s from [Sample]s in response to MIDI input.
pub fn process_midi_in (&mut self, scope: &ProcessScope) {
let Sampler { midi_in, mapped, voices, .. } = self;
if let Some(ref midi_in) = midi_in {
for RawMidi { time, bytes } in midi_in.port().iter(scope) {
if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() {
match message {
MidiMessage::NoteOn { ref key, ref vel } => {
if let Some(ref sample) = mapped[key.as_int() as usize] {
voices.write().unwrap().push(Sample::play(sample, time as usize, vel));
}
},
MidiMessage::Controller { controller: _, value: _ } => {
// TODO
for RawMidi { time, bytes } in midi_in.port().iter(scope) {
if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() {
match message {
MidiMessage::NoteOn { ref key, ref vel } => {
if let Some(ref sample) = mapped[key.as_int() as usize] {
voices.write().unwrap().push(Sample::play(sample, time as usize, vel));
}
_ => {}
},
MidiMessage::Controller { controller: _, value: _ } => {
// TODO
}
_ => {}
}
}
}

View file

@ -22,7 +22,7 @@ pub struct Sampler {
/// Sample currently being edited.
pub editing: Option<Arc<RwLock<Sample>>>,
/// MIDI input port. Triggers sample playback.
pub midi_in: Option<JackMidiIn>,
pub midi_in: JackMidiIn,
/// Collection of currently playing instances of samples.
pub voices: Arc<RwLock<Vec<Voice>>>,
/// Audio output ports. Voices get played here.
@ -47,15 +47,28 @@ pub struct Sampler {
pub cursor: (AtomicUsize, AtomicUsize),
}
impl Default for Sampler {
fn default () -> Self {
Self {
midi_in: None,
audio_ins: vec![],
impl Sampler {
pub fn new (
jack: &Jack,
name: impl AsRef<str>,
midi_from: &[PortConnect],
audio_from: &[&[PortConnect];2],
audio_to: &[&[PortConnect];2],
) -> Usually<Self> {
let name = name.as_ref();
Ok(Self {
name: name.into(),
midi_in: JackMidiIn::new(jack, format!("M/{name}"), midi_from)?,
audio_ins: vec![
JackAudioIn::new(jack, &format!("L/{name}"), audio_from[0])?,
JackAudioIn::new(jack, &format!("R/{name}"), audio_from[1])?,
],
audio_outs: vec![
JackAudioOut::new(jack, &format!("{name}/L"), audio_to[0])?,
JackAudioOut::new(jack, &format!("{name}/R"), audio_to[1])?,
],
input_meters: vec![0.0;2],
output_meters: vec![0.0;2],
audio_outs: vec![],
name: "tek_sampler".into(),
mapped: [const { None };128],
unmapped: vec![],
voices: Arc::new(RwLock::new(vec![])),
@ -71,31 +84,6 @@ impl Default for Sampler {
color: Default::default(),
mixing_mode: Default::default(),
metering_mode: Default::default(),
}
}
}
impl Sampler {
pub fn new (
jack: &Jack,
name: impl AsRef<str>,
midi_from: &[PortConnect],
audio_from: &[&[PortConnect];2],
audio_to: &[&[PortConnect];2],
) -> Usually<Self> {
let name = name.as_ref();
Ok(Self {
name: name.into(),
midi_in: Some(JackMidiIn::new(jack, format!("M/{name}"), midi_from)?),
audio_ins: vec![
JackAudioIn::new(jack, &format!("L/{name}"), audio_from[0])?,
JackAudioIn::new(jack, &format!("R/{name}"), audio_from[1])?,
],
audio_outs: vec![
JackAudioOut::new(jack, &format!("{name}/L"), audio_to[0])?,
JackAudioOut::new(jack, &format!("{name}/R"), audio_to[1])?,
],
..Default::default()
})
}
/// Value of cursor