use crate::*; use KeyCode::Char; use std::fs::File; use symphonia::{ core::{ formats::Packet, codecs::{Decoder, CODEC_TYPE_NULL}, errors::Error, io::MediaSourceStream, probe::Hint, audio::SampleBuffer, }, default::get_codecs, }; pub mod sample; pub(crate) use self::sample::*; pub use self::sample::Sample; pub mod voice; pub(crate) use self::voice::*; pub use self::voice::Voice; pub mod sampler_tui; pub(crate) use self::sampler_tui::*; pub use self::sampler_tui::SamplerTui; pub mod sample_import; pub(crate) use self::sample_import::*; pub mod sample_viewer; pub(crate) use self::sample_viewer::*; pub use self::sample_viewer::SampleViewer; /// The sampler plugin plays sounds. #[derive(Debug)] pub struct Sampler { pub jack: Arc>, pub name: String, pub mapped: [Option>>;128], pub recording: Option<(usize, Arc>)>, pub unmapped: Vec>>, pub voices: Arc>>, pub midi_in: Port, pub audio_ins: Vec>, pub input_meter: Vec, pub audio_outs: Vec>, pub buffer: Vec>, pub output_gain: f32 } impl Sampler { pub fn new ( jack: &Arc>, name: impl AsRef, midi_from: &[impl AsRef], audio_from: &[&[impl AsRef];2], audio_to: &[&[impl AsRef];2], ) -> Usually { let name = name.as_ref(); Ok(Self { midi_in: jack.midi_in(&format!("M/{name}"), midi_from)?, audio_ins: vec![ jack.audio_in(&format!("L/{name}"), audio_from[0])?, jack.audio_in(&format!("R/{name}"), audio_from[1])? ], input_meter: vec![0.0;2], audio_outs: vec![ jack.audio_out(&format!("{name}/L"), audio_to[0])?, jack.audio_out(&format!("{name}/R"), audio_to[1])?, ], jack: jack.clone(), name: name.into(), mapped: [const { None };128], unmapped: vec![], voices: Arc::new(RwLock::new(vec![])), buffer: vec![vec![0.0;16384];2], output_gain: 1., recording: None, }) } pub fn cancel_recording (&mut self) { self.recording = None; } pub fn begin_recording (&mut self, index: usize) { self.recording = Some(( index, Arc::new(RwLock::new(Sample::new("(new)", 0, 0, vec![vec![];self.audio_ins.len()]))) )); } pub fn finish_recording (&mut self) -> Option>> { let recording = self.recording.take(); if let Some((index, sample)) = recording { let old = self.mapped[index].clone(); self.mapped[index] = Some(sample); old } else { None } } } pub enum SamplerCommand { RecordBegin(u7), RecordCancel, RecordFinish, SetSample(u7, Option>>), SetStart(u7, usize), SetGain(f32), NoteOn(u7, u7), NoteOff(u7), } command!(|self: SamplerCommand, state: Sampler|match self { Self::SetSample(index, sample) => { let i = index.as_int() as usize; let old = state.mapped[i].clone(); state.mapped[i] = sample; Some(Self::SetSample(index, old)) }, Self::RecordBegin(index) => { state.begin_recording(index.as_int() as usize); None }, Self::RecordCancel => { state.cancel_recording(); None }, Self::RecordFinish => { state.finish_recording(); None }, _ => todo!() }); audio!(|self: SamplerTui, client, scope|{ SamplerAudio(&mut self.state).process(client, scope) }); pub struct SamplerAudio<'a>(pub &'a mut Sampler); audio!(|self: SamplerAudio<'a>, _client, scope|{ self.0.process_midi_in(scope); self.0.clear_output_buffer(); self.0.process_audio_out(scope); self.0.write_output_buffer(scope); self.0.process_audio_in(scope); Control::Continue }); impl Sampler { pub fn process_audio_in (&mut self, scope: &ProcessScope) { let Sampler { audio_ins, input_meter, recording, .. } = self; if audio_ins.len() != input_meter.len() { *input_meter = vec![0.0;audio_ins.len()]; } if let Some((_, sample)) = recording { let mut sample = sample.write().unwrap(); if sample.channels.len() != audio_ins.len() { panic!("channel count mismatch"); } let iterator = audio_ins.iter().zip(input_meter).zip(sample.channels.iter_mut()); let mut length = 0; for ((input, meter), channel) in iterator { let slice = input.as_slice(scope); length = length.max(slice.len()); let total: f32 = slice.iter().map(|x|x.abs()).sum(); let count = slice.len() as f32; *meter = 10. * (total / count).log10(); channel.extend_from_slice(slice); } sample.end += length; } else { for (input, meter) in audio_ins.iter().zip(input_meter) { let slice = input.as_slice(scope); let total: f32 = slice.iter().map(|x|x.abs()).sum(); let count = slice.len() as f32; *meter = 10. * (total / count).log10(); } } } /// 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; for RawMidi { time, bytes } in midi_in.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)); } }, _ => {} } } } } /// Zero the output buffer. pub fn clear_output_buffer (&mut self) { for buffer in self.buffer.iter_mut() { buffer.fill(0.0); } } /// Mix all currently playing samples into the output. pub fn process_audio_out (&mut self, scope: &ProcessScope) { let Sampler { ref mut buffer, voices, output_gain, .. } = self; let channel_count = buffer.len(); voices.write().unwrap().retain_mut(|voice|{ for index in 0..scope.n_frames() as usize { if let Some(frame) = voice.next() { for (channel, sample) in frame.iter().enumerate() { // Averaging mixer: //self.buffer[channel % channel_count][index] = ( //(self.buffer[channel % channel_count][index] + sample * self.output_gain) / 2.0 //); buffer[channel % channel_count][index] += sample * *output_gain; } } else { return false } } true }); } /// Write output buffer to output ports. pub fn write_output_buffer (&mut self, scope: &ProcessScope) { let Sampler { ref mut audio_outs, buffer, .. } = self; for (i, port) in audio_outs.iter_mut().enumerate() { let buffer = &buffer[i]; for (i, value) in port.as_mut_slice(scope).iter_mut().enumerate() { *value = *buffer.get(i).unwrap_or(&0.0); } } } }