use crate::core::*; pub struct Sampler { pub name: String, pub cursor: (usize, usize), pub samples: BTreeMap>, pub voices: Vec, pub ports: JackPorts, } render!(Sampler = crate::view::sampler::render); handle!(Sampler = crate::control::sampler::handle); //jack!(Sampler { //process = Sampler::process, //audio = { //ins = |s|Ok(s.jack.audio_ins.values().collect()), //outs = |s|Ok(s.jack.audio_outs.values().collect()), //} //midi = { //ins = |s|Ok(s.jack.midi_ins.values().collect()), //outs = |s|Ok(s.jack.midi_outs.values().collect()), //} //}); process!(Sampler = Sampler::process); //ports!(Sampler { //audio: { //ins: |s|Ok(s.ports.audio_ins.values().collect()), //outs: |s|Ok(s.ports.audio_outs.values().collect()), //} //midi: { //ins: |s|Ok(s.ports.midi_ins.values().collect()), //outs: |s|Ok(s.ports.midi_outs.values().collect()), //} //}); impl Sampler { pub fn new ( name: &str, samples: Option>>, ) -> Usually { Jack::new(name)? .midi_in("midi") .audio_in("recL") .audio_in("recR") .audio_out("outL") .audio_out("outR") .run(|ports|Box::new(Self { name: name.into(), cursor: (0, 0), samples: samples.unwrap_or(BTreeMap::new()), voices: vec![], ports })) } pub fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control { // Output buffer: this will be copied to the audio outs. let channel_count = self.ports.audio_outs.len(); let mut mixed = vec![vec![0.0;scope.n_frames() as usize];channel_count]; // Process MIDI input to add new voices. for RawMidi { time, bytes } in self.ports.midi_ins.get("midi").unwrap().iter(scope) { if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() { if let MidiMessage::NoteOn { ref key, .. } = message { if let Some(sample) = self.samples.get(key) { self.voices.push(sample.play(time as usize)); } } } } // Emit next chunk of each currently playing voice, // dropping voices that have reached their ends. let mut voices = vec![]; std::mem::swap(&mut voices, &mut self.voices); loop { if voices.len() < 1 { break } let mut voice = voices.swap_remove(0); if let Some(chunk) = voice.chunk(scope.n_frames() as usize) { for (i, channel) in chunk.iter().enumerate() { let buffer = &mut mixed[i % channel_count]; for (i, sample) in channel.iter().enumerate() { buffer[i] += sample; } } self.voices.push(voice); } } // Write output buffer to output ports. for (i, port) in self.ports.audio_outs.values_mut().enumerate() { let buffer = &mixed[i]; for (i, value) in port.as_mut_slice(scope).iter_mut().enumerate() { *value = *buffer.get(i).unwrap_or(&0.0); } } Control::Continue } fn load_sample (&mut self, _path: &str) {} } #[macro_export] macro_rules! sample { ($note:expr, $name:expr, $src:expr) => { { let mut channels: Vec> = vec![]; for channel in wavers::Wav::from_path($src)?.channels() { channels.push(channel); } let mut end = 0; let mut data: Vec> = vec![]; for samples in channels.iter() { let channel = Vec::from(samples.as_ref()); end = end.max(channel.len()); data.push(channel); } (u7::from_int_lossy($note).into(), Sample::new($name, 0, end, data).into()) } }; } pub struct Sample { pub name: String, pub start: usize, pub end: usize, pub channels: Vec>, } impl Sample { pub fn new (name: &str, start: usize, end: usize, channels: Vec>) -> Arc { Arc::new(Self { name: name.to_string(), start, end, channels }) } pub fn play (self: &Arc, after: usize) -> Voice { Voice { sample: self.clone(), after, position: self.start } } } pub struct Voice { pub sample: Arc, pub after: usize, pub position: usize, } impl Voice { pub fn chunk (&mut self, mut frames: usize) -> Option>> { // Create output buffer for each channel let mut chunk = vec![vec![];self.sample.channels.len()]; // If it's not time to play yet, count down if self.after >= frames { self.after = self.after - frames; return Some(chunk) } // If the voice will start playing within the current buffer, // subtract the remaining number of wait frames. if self.after > 0 && self.after < frames { chunk = vec![vec![0.0;self.after];self.sample.channels.len()]; frames = frames - self.after; self.after = 0; } if self.position < self.sample.end { let start = self.position.min(self.sample.end); let end = (self.position + frames).min(self.sample.end); for (i, channel) in self.sample.channels.iter().enumerate() { chunk[i].extend_from_slice(&channel[start..end]); }; self.position = self.position + frames; Some(chunk) } else { None } } }