mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-08 20:56:43 +01:00
606 lines
18 KiB
Rust
606 lines
18 KiB
Rust
//! Buffers to safely work with audio samples.
|
|
|
|
use num_traits::Float;
|
|
|
|
use std::slice;
|
|
|
|
/// `AudioBuffer` contains references to the audio buffers for all input and output channels.
|
|
///
|
|
/// To create an `AudioBuffer` in a host, use a [`HostBuffer`](../host/struct.HostBuffer.html).
|
|
pub struct AudioBuffer<'a, T: 'a + Float> {
|
|
inputs: &'a [*const T],
|
|
outputs: &'a mut [*mut T],
|
|
samples: usize,
|
|
}
|
|
|
|
impl<'a, T: 'a + Float> AudioBuffer<'a, T> {
|
|
/// Create an `AudioBuffer` from raw pointers.
|
|
/// Only really useful for interacting with the VST API.
|
|
#[inline]
|
|
pub unsafe fn from_raw(
|
|
input_count: usize,
|
|
output_count: usize,
|
|
inputs_raw: *const *const T,
|
|
outputs_raw: *mut *mut T,
|
|
samples: usize,
|
|
) -> Self {
|
|
Self {
|
|
inputs: slice::from_raw_parts(inputs_raw, input_count),
|
|
outputs: slice::from_raw_parts_mut(outputs_raw, output_count),
|
|
samples,
|
|
}
|
|
}
|
|
|
|
/// The number of input channels that this buffer was created for
|
|
#[inline]
|
|
pub fn input_count(&self) -> usize {
|
|
self.inputs.len()
|
|
}
|
|
|
|
/// The number of output channels that this buffer was created for
|
|
#[inline]
|
|
pub fn output_count(&self) -> usize {
|
|
self.outputs.len()
|
|
}
|
|
|
|
/// The number of samples in this buffer (same for all channels)
|
|
#[inline]
|
|
pub fn samples(&self) -> usize {
|
|
self.samples
|
|
}
|
|
|
|
/// The raw inputs to pass to processReplacing
|
|
#[inline]
|
|
pub(crate) fn raw_inputs(&self) -> &[*const T] {
|
|
self.inputs
|
|
}
|
|
|
|
/// The raw outputs to pass to processReplacing
|
|
#[inline]
|
|
pub(crate) fn raw_outputs(&mut self) -> &mut [*mut T] {
|
|
&mut self.outputs
|
|
}
|
|
|
|
/// Split this buffer into separate inputs and outputs.
|
|
#[inline]
|
|
pub fn split<'b>(&'b mut self) -> (Inputs<'b, T>, Outputs<'b, T>)
|
|
where
|
|
'a: 'b,
|
|
{
|
|
(
|
|
Inputs {
|
|
bufs: self.inputs,
|
|
samples: self.samples,
|
|
},
|
|
Outputs {
|
|
bufs: self.outputs,
|
|
samples: self.samples,
|
|
},
|
|
)
|
|
}
|
|
|
|
/// Create an iterator over pairs of input buffers and output buffers.
|
|
#[inline]
|
|
pub fn zip<'b>(&'b mut self) -> AudioBufferIterator<'a, 'b, T> {
|
|
AudioBufferIterator {
|
|
audio_buffer: self,
|
|
index: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Iterator over pairs of buffers of input channels and output channels.
|
|
pub struct AudioBufferIterator<'a, 'b, T>
|
|
where
|
|
T: 'a + Float,
|
|
'a: 'b,
|
|
{
|
|
audio_buffer: &'b mut AudioBuffer<'a, T>,
|
|
index: usize,
|
|
}
|
|
|
|
impl<'a, 'b, T> Iterator for AudioBufferIterator<'a, 'b, T>
|
|
where
|
|
T: 'b + Float,
|
|
{
|
|
type Item = (&'b [T], &'b mut [T]);
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if self.index < self.audio_buffer.inputs.len() && self.index < self.audio_buffer.outputs.len() {
|
|
let input =
|
|
unsafe { slice::from_raw_parts(self.audio_buffer.inputs[self.index], self.audio_buffer.samples) };
|
|
let output =
|
|
unsafe { slice::from_raw_parts_mut(self.audio_buffer.outputs[self.index], self.audio_buffer.samples) };
|
|
let val = (input, output);
|
|
self.index += 1;
|
|
Some(val)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
use std::ops::{Index, IndexMut};
|
|
|
|
/// Wrapper type to access the buffers for the input channels of an `AudioBuffer` in a safe way.
|
|
/// Behaves like a slice.
|
|
#[derive(Copy, Clone)]
|
|
pub struct Inputs<'a, T: 'a> {
|
|
bufs: &'a [*const T],
|
|
samples: usize,
|
|
}
|
|
|
|
impl<'a, T> Inputs<'a, T> {
|
|
/// Number of channels
|
|
pub fn len(&self) -> usize {
|
|
self.bufs.len()
|
|
}
|
|
|
|
/// Returns true if the buffer is empty
|
|
pub fn is_empty(&self) -> bool {
|
|
self.len() == 0
|
|
}
|
|
|
|
/// Access channel at the given index
|
|
pub fn get(&self, i: usize) -> &'a [T] {
|
|
unsafe { slice::from_raw_parts(self.bufs[i], self.samples) }
|
|
}
|
|
|
|
/// Split borrowing at the given index, like for slices
|
|
pub fn split_at(&self, i: usize) -> (Inputs<'a, T>, Inputs<'a, T>) {
|
|
let (l, r) = self.bufs.split_at(i);
|
|
(
|
|
Inputs {
|
|
bufs: l,
|
|
samples: self.samples,
|
|
},
|
|
Inputs {
|
|
bufs: r,
|
|
samples: self.samples,
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
impl<'a, T> Index<usize> for Inputs<'a, T> {
|
|
type Output = [T];
|
|
|
|
fn index(&self, i: usize) -> &Self::Output {
|
|
self.get(i)
|
|
}
|
|
}
|
|
|
|
/// Iterator over buffers for input channels of an `AudioBuffer`.
|
|
pub struct InputIterator<'a, T: 'a> {
|
|
data: Inputs<'a, T>,
|
|
i: usize,
|
|
}
|
|
|
|
impl<'a, T> Iterator for InputIterator<'a, T> {
|
|
type Item = &'a [T];
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if self.i < self.data.len() {
|
|
let val = self.data.get(self.i);
|
|
self.i += 1;
|
|
Some(val)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, T: Sized> IntoIterator for Inputs<'a, T> {
|
|
type Item = &'a [T];
|
|
type IntoIter = InputIterator<'a, T>;
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
InputIterator { data: self, i: 0 }
|
|
}
|
|
}
|
|
|
|
/// Wrapper type to access the buffers for the output channels of an `AudioBuffer` in a safe way.
|
|
/// Behaves like a slice.
|
|
pub struct Outputs<'a, T: 'a> {
|
|
bufs: &'a [*mut T],
|
|
samples: usize,
|
|
}
|
|
|
|
impl<'a, T> Outputs<'a, T> {
|
|
/// Number of channels
|
|
pub fn len(&self) -> usize {
|
|
self.bufs.len()
|
|
}
|
|
|
|
/// Returns true if the buffer is empty
|
|
pub fn is_empty(&self) -> bool {
|
|
self.len() == 0
|
|
}
|
|
|
|
/// Access channel at the given index
|
|
pub fn get(&self, i: usize) -> &'a [T] {
|
|
unsafe { slice::from_raw_parts(self.bufs[i], self.samples) }
|
|
}
|
|
|
|
/// Mutably access channel at the given index
|
|
pub fn get_mut(&mut self, i: usize) -> &'a mut [T] {
|
|
unsafe { slice::from_raw_parts_mut(self.bufs[i], self.samples) }
|
|
}
|
|
|
|
/// Split borrowing at the given index, like for slices
|
|
pub fn split_at_mut(self, i: usize) -> (Outputs<'a, T>, Outputs<'a, T>) {
|
|
let (l, r) = self.bufs.split_at(i);
|
|
(
|
|
Outputs {
|
|
bufs: l,
|
|
samples: self.samples,
|
|
},
|
|
Outputs {
|
|
bufs: r,
|
|
samples: self.samples,
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
impl<'a, T> Index<usize> for Outputs<'a, T> {
|
|
type Output = [T];
|
|
|
|
fn index(&self, i: usize) -> &Self::Output {
|
|
self.get(i)
|
|
}
|
|
}
|
|
|
|
impl<'a, T> IndexMut<usize> for Outputs<'a, T> {
|
|
fn index_mut(&mut self, i: usize) -> &mut Self::Output {
|
|
self.get_mut(i)
|
|
}
|
|
}
|
|
|
|
/// Iterator over buffers for output channels of an `AudioBuffer`.
|
|
pub struct OutputIterator<'a, 'b, T>
|
|
where
|
|
T: 'a,
|
|
'a: 'b,
|
|
{
|
|
data: &'b mut Outputs<'a, T>,
|
|
i: usize,
|
|
}
|
|
|
|
impl<'a, 'b, T> Iterator for OutputIterator<'a, 'b, T>
|
|
where
|
|
T: 'b,
|
|
{
|
|
type Item = &'b mut [T];
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if self.i < self.data.len() {
|
|
let val = self.data.get_mut(self.i);
|
|
self.i += 1;
|
|
Some(val)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, 'b, T: Sized> IntoIterator for &'b mut Outputs<'a, T> {
|
|
type Item = &'b mut [T];
|
|
type IntoIter = OutputIterator<'a, 'b, T>;
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
OutputIterator { data: self, i: 0 }
|
|
}
|
|
}
|
|
|
|
use crate::event::{Event, MidiEvent, SysExEvent};
|
|
|
|
/// This is used as a placeholder to pre-allocate space for a fixed number of
|
|
/// midi events in the re-useable `SendEventBuffer`, because `SysExEvent` is
|
|
/// larger than `MidiEvent`, so either one can be stored in a `SysExEvent`.
|
|
pub type PlaceholderEvent = api::SysExEvent;
|
|
|
|
/// This trait is used by `SendEventBuffer::send_events` to accept iterators over midi events
|
|
pub trait WriteIntoPlaceholder {
|
|
/// writes an event into the given placeholder memory location
|
|
fn write_into(&self, out: &mut PlaceholderEvent);
|
|
}
|
|
|
|
impl<'a, T: WriteIntoPlaceholder> WriteIntoPlaceholder for &'a T {
|
|
fn write_into(&self, out: &mut PlaceholderEvent) {
|
|
(*self).write_into(out);
|
|
}
|
|
}
|
|
|
|
impl WriteIntoPlaceholder for MidiEvent {
|
|
fn write_into(&self, out: &mut PlaceholderEvent) {
|
|
let out = unsafe { &mut *(out as *mut _ as *mut _) };
|
|
*out = api::MidiEvent {
|
|
event_type: api::EventType::Midi,
|
|
byte_size: mem::size_of::<api::MidiEvent>() as i32,
|
|
delta_frames: self.delta_frames,
|
|
flags: if self.live {
|
|
api::MidiEventFlags::REALTIME_EVENT.bits()
|
|
} else {
|
|
0
|
|
},
|
|
note_length: self.note_length.unwrap_or(0),
|
|
note_offset: self.note_offset.unwrap_or(0),
|
|
midi_data: self.data,
|
|
_midi_reserved: 0,
|
|
detune: self.detune,
|
|
note_off_velocity: self.note_off_velocity,
|
|
_reserved1: 0,
|
|
_reserved2: 0,
|
|
};
|
|
}
|
|
}
|
|
|
|
impl<'a> WriteIntoPlaceholder for SysExEvent<'a> {
|
|
fn write_into(&self, out: &mut PlaceholderEvent) {
|
|
*out = PlaceholderEvent {
|
|
event_type: api::EventType::SysEx,
|
|
byte_size: mem::size_of::<PlaceholderEvent>() as i32,
|
|
delta_frames: self.delta_frames,
|
|
_flags: 0,
|
|
data_size: self.payload.len() as i32,
|
|
_reserved1: 0,
|
|
system_data: self.payload.as_ptr() as *const u8 as *mut u8,
|
|
_reserved2: 0,
|
|
};
|
|
}
|
|
}
|
|
|
|
impl<'a> WriteIntoPlaceholder for Event<'a> {
|
|
fn write_into(&self, out: &mut PlaceholderEvent) {
|
|
match *self {
|
|
Event::Midi(ref ev) => {
|
|
ev.write_into(out);
|
|
}
|
|
Event::SysEx(ref ev) => {
|
|
ev.write_into(out);
|
|
}
|
|
Event::Deprecated(e) => {
|
|
let out = unsafe { &mut *(out as *mut _ as *mut _) };
|
|
*out = e;
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
use crate::{api, host::Host};
|
|
use std::mem;
|
|
|
|
/// This buffer is used for sending midi events through the VST interface.
|
|
/// The purpose of this is to convert outgoing midi events from `event::Event` to `api::Events`.
|
|
/// It only allocates memory in new() and reuses the memory between calls.
|
|
pub struct SendEventBuffer {
|
|
buf: Vec<u8>,
|
|
api_events: Vec<PlaceholderEvent>, // using SysExEvent to store both because it's larger than MidiEvent
|
|
}
|
|
|
|
impl Default for SendEventBuffer {
|
|
fn default() -> Self {
|
|
SendEventBuffer::new(1024)
|
|
}
|
|
}
|
|
|
|
impl SendEventBuffer {
|
|
/// Creates a buffer for sending up to the given number of midi events per frame
|
|
#[inline(always)]
|
|
pub fn new(capacity: usize) -> Self {
|
|
let header_size = mem::size_of::<api::Events>() - (mem::size_of::<*mut api::Event>() * 2);
|
|
let body_size = mem::size_of::<*mut api::Event>() * capacity;
|
|
let mut buf = vec![0u8; header_size + body_size];
|
|
let api_events = vec![unsafe { mem::zeroed::<PlaceholderEvent>() }; capacity];
|
|
{
|
|
let ptrs = {
|
|
let e = Self::buf_as_api_events(&mut buf);
|
|
e.num_events = capacity as i32;
|
|
e.events_raw_mut()
|
|
};
|
|
for (ptr, event) in ptrs.iter_mut().zip(&api_events) {
|
|
let (ptr, event): (&mut *const PlaceholderEvent, &PlaceholderEvent) = (ptr, event);
|
|
*ptr = event;
|
|
}
|
|
}
|
|
Self { buf, api_events }
|
|
}
|
|
|
|
/// Sends events to the host. See the `fwd_midi` example.
|
|
///
|
|
/// # Example
|
|
/// ```no_run
|
|
/// # use vst::plugin::{Info, Plugin, HostCallback};
|
|
/// # use vst::buffer::{AudioBuffer, SendEventBuffer};
|
|
/// # use vst::host::Host;
|
|
/// # use vst::event::*;
|
|
/// # struct ExamplePlugin { host: HostCallback, send_buffer: SendEventBuffer }
|
|
/// # impl Plugin for ExamplePlugin {
|
|
/// # fn new(host: HostCallback) -> Self { Self { host, send_buffer: Default::default() } }
|
|
/// #
|
|
/// # fn get_info(&self) -> Info { Default::default() }
|
|
/// #
|
|
/// fn process(&mut self, buffer: &mut AudioBuffer<f32>){
|
|
/// let events: Vec<MidiEvent> = vec![
|
|
/// // ...
|
|
/// ];
|
|
/// self.send_buffer.send_events(&events, &mut self.host);
|
|
/// }
|
|
/// # }
|
|
/// ```
|
|
#[inline(always)]
|
|
pub fn send_events<T: IntoIterator<Item = U>, U: WriteIntoPlaceholder>(&mut self, events: T, host: &mut dyn Host) {
|
|
self.store_events(events);
|
|
host.process_events(self.events());
|
|
}
|
|
|
|
/// Stores events in the buffer, replacing the buffer's current content.
|
|
/// Use this in [`process_events`](crate::Plugin::process_events) to store received input events, then read them in [`process`](crate::Plugin::process) using [`events`](SendEventBuffer::events).
|
|
#[inline(always)]
|
|
pub fn store_events<T: IntoIterator<Item = U>, U: WriteIntoPlaceholder>(&mut self, events: T) {
|
|
#[allow(clippy::suspicious_map)]
|
|
let count = events
|
|
.into_iter()
|
|
.zip(self.api_events.iter_mut())
|
|
.map(|(ev, out)| ev.write_into(out))
|
|
.count();
|
|
self.set_num_events(count);
|
|
}
|
|
|
|
/// Returns a reference to the stored events
|
|
#[inline(always)]
|
|
pub fn events(&self) -> &api::Events {
|
|
#[allow(clippy::cast_ptr_alignment)]
|
|
unsafe {
|
|
&*(self.buf.as_ptr() as *const api::Events)
|
|
}
|
|
}
|
|
|
|
/// Clears the buffer
|
|
#[inline(always)]
|
|
pub fn clear(&mut self) {
|
|
self.set_num_events(0);
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn buf_as_api_events(buf: &mut [u8]) -> &mut api::Events {
|
|
#[allow(clippy::cast_ptr_alignment)]
|
|
unsafe {
|
|
&mut *(buf.as_mut_ptr() as *mut api::Events)
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn set_num_events(&mut self, events_len: usize) {
|
|
use std::cmp::min;
|
|
let e = Self::buf_as_api_events(&mut self.buf);
|
|
e.num_events = min(self.api_events.len(), events_len) as i32;
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::buffer::AudioBuffer;
|
|
|
|
/// Size of buffers used in tests.
|
|
const SIZE: usize = 1024;
|
|
|
|
/// Test that creating and zipping buffers works.
|
|
///
|
|
/// This test creates a channel for 2 inputs and 2 outputs.
|
|
/// The input channels are simply values
|
|
/// from 0 to `SIZE-1` (e.g. [0, 1, 2, 3, 4, .. , SIZE - 1])
|
|
/// and the output channels are just 0.
|
|
/// This test assures that when the buffers are zipped together,
|
|
/// the input values do not change.
|
|
#[test]
|
|
fn buffer_zip() {
|
|
let in1: Vec<f32> = (0..SIZE).map(|x| x as f32).collect();
|
|
let in2 = in1.clone();
|
|
|
|
let mut out1 = vec![0.0; SIZE];
|
|
let mut out2 = out1.clone();
|
|
|
|
let inputs = vec![in1.as_ptr(), in2.as_ptr()];
|
|
let mut outputs = vec![out1.as_mut_ptr(), out2.as_mut_ptr()];
|
|
let mut buffer = unsafe { AudioBuffer::from_raw(2, 2, inputs.as_ptr(), outputs.as_mut_ptr(), SIZE) };
|
|
|
|
for (input, output) in buffer.zip() {
|
|
input.iter().zip(output.iter_mut()).fold(0, |acc, (input, output)| {
|
|
assert_eq!(*input, acc as f32);
|
|
assert_eq!(*output, 0.0);
|
|
acc + 1
|
|
});
|
|
}
|
|
}
|
|
|
|
// Test that the `zip()` method returns an iterator that gives `n` elements
|
|
// where n is the number of inputs when this is lower than the number of outputs.
|
|
#[test]
|
|
fn buffer_zip_fewer_inputs_than_outputs() {
|
|
let in1 = vec![1.0; SIZE];
|
|
let in2 = vec![2.0; SIZE];
|
|
|
|
let mut out1 = vec![3.0; SIZE];
|
|
let mut out2 = vec![4.0; SIZE];
|
|
let mut out3 = vec![5.0; SIZE];
|
|
|
|
let inputs = vec![in1.as_ptr(), in2.as_ptr()];
|
|
let mut outputs = vec![out1.as_mut_ptr(), out2.as_mut_ptr(), out3.as_mut_ptr()];
|
|
let mut buffer = unsafe { AudioBuffer::from_raw(2, 3, inputs.as_ptr(), outputs.as_mut_ptr(), SIZE) };
|
|
|
|
let mut iter = buffer.zip();
|
|
if let Some((observed_in1, observed_out1)) = iter.next() {
|
|
assert_eq!(1.0, observed_in1[0]);
|
|
assert_eq!(3.0, observed_out1[0]);
|
|
} else {
|
|
unreachable!();
|
|
}
|
|
|
|
if let Some((observed_in2, observed_out2)) = iter.next() {
|
|
assert_eq!(2.0, observed_in2[0]);
|
|
assert_eq!(4.0, observed_out2[0]);
|
|
} else {
|
|
unreachable!();
|
|
}
|
|
|
|
assert_eq!(None, iter.next());
|
|
}
|
|
|
|
// Test that the `zip()` method returns an iterator that gives `n` elements
|
|
// where n is the number of outputs when this is lower than the number of inputs.
|
|
#[test]
|
|
fn buffer_zip_more_inputs_than_outputs() {
|
|
let in1 = vec![1.0; SIZE];
|
|
let in2 = vec![2.0; SIZE];
|
|
let in3 = vec![3.0; SIZE];
|
|
|
|
let mut out1 = vec![4.0; SIZE];
|
|
let mut out2 = vec![5.0; SIZE];
|
|
|
|
let inputs = vec![in1.as_ptr(), in2.as_ptr(), in3.as_ptr()];
|
|
let mut outputs = vec![out1.as_mut_ptr(), out2.as_mut_ptr()];
|
|
let mut buffer = unsafe { AudioBuffer::from_raw(3, 2, inputs.as_ptr(), outputs.as_mut_ptr(), SIZE) };
|
|
|
|
let mut iter = buffer.zip();
|
|
|
|
if let Some((observed_in1, observed_out1)) = iter.next() {
|
|
assert_eq!(1.0, observed_in1[0]);
|
|
assert_eq!(4.0, observed_out1[0]);
|
|
} else {
|
|
unreachable!();
|
|
}
|
|
|
|
if let Some((observed_in2, observed_out2)) = iter.next() {
|
|
assert_eq!(2.0, observed_in2[0]);
|
|
assert_eq!(5.0, observed_out2[0]);
|
|
} else {
|
|
unreachable!();
|
|
}
|
|
|
|
assert_eq!(None, iter.next());
|
|
}
|
|
|
|
/// Test that creating buffers from raw pointers works.
|
|
#[test]
|
|
fn from_raw() {
|
|
let in1: Vec<f32> = (0..SIZE).map(|x| x as f32).collect();
|
|
let in2 = in1.clone();
|
|
|
|
let mut out1 = vec![0.0; SIZE];
|
|
let mut out2 = out1.clone();
|
|
|
|
let inputs = vec![in1.as_ptr(), in2.as_ptr()];
|
|
let mut outputs = vec![out1.as_mut_ptr(), out2.as_mut_ptr()];
|
|
let mut buffer = unsafe { AudioBuffer::from_raw(2, 2, inputs.as_ptr(), outputs.as_mut_ptr(), SIZE) };
|
|
|
|
for (input, output) in buffer.zip() {
|
|
input.iter().zip(output.iter_mut()).fold(0, |acc, (input, output)| {
|
|
assert_eq!(*input, acc as f32);
|
|
assert_eq!(*output, 0.0);
|
|
acc + 1
|
|
});
|
|
}
|
|
}
|
|
}
|