|
| 1 | +use std::sync::{Arc, mpsc::Receiver}; |
| 2 | + |
| 3 | +use cpal::{FromSample, Sample}; |
| 4 | +use plinth_core::{buffers::buffer::Buffer, signals::{signal::{Signal, SignalMut}, signal_base::SignalBase}}; |
| 5 | + |
| 6 | +use super::parameters::StandaloneParameterEventMap; |
| 7 | +use super::plugin::StandalonePlugin; |
| 8 | +use crate::{Event, Processor}; |
| 9 | + |
| 10 | +pub struct AudioState<P: StandalonePlugin> { |
| 11 | + pub processor: P::Processor, |
| 12 | + pub buffer: Buffer, |
| 13 | + pub channels: usize, |
| 14 | + pub midi_receiver: Receiver<Event>, |
| 15 | + pub parameter_event_map: Arc<StandaloneParameterEventMap>, |
| 16 | + pending_events: Vec<Event>, |
| 17 | +} |
| 18 | + |
| 19 | +impl<P: StandalonePlugin> AudioState<P> { |
| 20 | + pub fn new( |
| 21 | + processor: P::Processor, |
| 22 | + channels: usize, |
| 23 | + midi_receiver: Receiver<Event>, |
| 24 | + parameter_event_map: Arc<StandaloneParameterEventMap>, |
| 25 | + ) -> Self { |
| 26 | + Self { |
| 27 | + processor, |
| 28 | + buffer: Buffer::new(channels, P::MAX_BLOCK_SIZE), |
| 29 | + channels, |
| 30 | + midi_receiver, |
| 31 | + parameter_event_map, |
| 32 | + pending_events: Vec::with_capacity(P::EVENT_QUEUE_LEN), |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | + pub fn process<T>(&mut self, data: &mut [T], channels: usize) |
| 37 | + where |
| 38 | + T: Sample + FromSample<f32>, |
| 39 | + f32: FromSample<T>, |
| 40 | + { |
| 41 | + let frame_count = data.len() / channels; |
| 42 | + |
| 43 | + // Drain MIDI events |
| 44 | + self.pending_events.clear(); |
| 45 | + while let Ok(event) = self.midi_receiver.try_recv() { |
| 46 | + self.pending_events.push(event); |
| 47 | + } |
| 48 | + for event in self.parameter_event_map.iter_events() { |
| 49 | + self.pending_events.push(event); |
| 50 | + } |
| 51 | + |
| 52 | + // Process audio, ensuring we don't call process with more than P::MAX_BLOCK_SIZE frames |
| 53 | + let mut frame_offset = 0; |
| 54 | + while frame_offset < frame_count { |
| 55 | + let chunk_size = (frame_count - frame_offset).min(P::MAX_BLOCK_SIZE); |
| 56 | + |
| 57 | + if self.buffer.len() != chunk_size { |
| 58 | + self.buffer.resize(chunk_size); |
| 59 | + } |
| 60 | + |
| 61 | + // Deinterleave chunk from CPAL buffer |
| 62 | + for frame in 0..chunk_size { |
| 63 | + for ch in 0..self.channels { |
| 64 | + self.buffer.channel_mut(ch)[frame] = |
| 65 | + f32::from_sample(data[(frame_offset + frame) * self.channels + ch]); |
| 66 | + } |
| 67 | + } |
| 68 | + |
| 69 | + // Process and drain all events on first run, assuming they have no time tags |
| 70 | + let aux: Option<&Buffer> = None; |
| 71 | + self.processor |
| 72 | + .process(&mut self.buffer, aux, None, self.pending_events.drain(..)); |
| 73 | + |
| 74 | + // Reinterleave chunk back into CPAL buffer |
| 75 | + for frame in 0..chunk_size { |
| 76 | + for ch in 0..self.channels { |
| 77 | + data[(frame_offset + frame) * self.channels + ch] = |
| 78 | + T::from_sample(self.buffer.channel(ch)[frame]); |
| 79 | + } |
| 80 | + } |
| 81 | + |
| 82 | + frame_offset += chunk_size; |
| 83 | + } |
| 84 | + } |
| 85 | +} |
0 commit comments