1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
//! Adapters and utilities for working with audio buffers.
use std::marker::PhantomData;
mod blocks;
mod samples;
pub use blocks::{Block, BlockChannelsIter, BlocksIter};
pub use samples::{ChannelSamples, ChannelSamplesIter, SamplesIter};
/// The audio buffers used during processing. This contains the output audio output buffers with the
/// inputs already copied to the outputs. You can either use the iterator adapters to conveniently
/// and efficiently iterate over the samples, or you can do your own thing using the raw audio
/// buffers.
///
/// TODO: This lifetime makes zero sense because you're going to need unsafe lifetime casts to use
/// this either way. Maybe just get rid of it in favor for raw pointers.
#[derive(Default)]
pub struct Buffer<'a> {
/// The number of samples contained within `output_slices`. This needs to be stored separately
/// to be able to handle 0 channel IO for MIDI-only plugins.
num_samples: usize,
/// Contains slices for the plugin's outputs. You can't directly create a nested slice from a
/// pointer to pointers, so this needs to be preallocated in the setup call and kept around
/// between process calls. And because storing a reference to this means a) that you need a lot
/// of lifetime annotations everywhere and b) that at some point you need unsound lifetime casts
/// because this `Buffers` either cannot have the same lifetime as the separately stored output
/// buffers, and it also cannot be stored in a field next to it because that would mean
/// containing mutable references to data stored in a mutex.
output_slices: Vec<&'a mut [f32]>,
}
impl<'a> Buffer<'a> {
/// Returns the number of samples per channel in this buffer.
#[inline]
pub fn samples(&self) -> usize {
self.num_samples
}
/// Returns the number of channels in this buffer.
#[inline]
pub fn channels(&self) -> usize {
self.output_slices.len()
}
/// Returns true if this buffer does not contain any samples.
#[inline]
pub fn is_empty(&self) -> bool {
self.num_samples == 0
}
/// Obtain the raw audio buffers.
#[inline]
pub fn as_slice(&mut self) -> &mut [&'a mut [f32]] {
&mut self.output_slices
}
/// The same as [`as_slice()`][Self::as_slice()], but for a non-mutable reference. This is
/// usually not needed.
#[inline]
pub fn as_slice_immutable(&self) -> &[&'a mut [f32]] {
&self.output_slices
}
/// Iterate over the samples, returning a channel iterator for each sample.
#[inline]
pub fn iter_samples<'slice>(&'slice mut self) -> SamplesIter<'slice, 'a> {
SamplesIter {
buffers: self.output_slices.as_mut_slice(),
current_sample: 0,
samples_end: self.samples(),
_marker: PhantomData,
}
}
/// Iterate over the buffer in blocks with the specified maximum size. The ideal maximum block
/// size depends on the plugin in question, but 64 or 128 samples works for most plugins. Since
/// the buffer's total size may not be cleanly divisible by the maximum size, the returned
/// buffers may have any size in `[1, max_block_size]`. This is useful when using algorithms
/// that work on entire blocks of audio, like those that would otherwise need to perform
/// expensive per-sample branching or that can use per-sample SIMD as opposed to per-channel
/// SIMD.
///
/// The parameter smoothers can also produce smoothed values for an entire block using
/// [`Smoother::next_block()`][crate::prelude::Smoother::next_block()].
///
/// You can use this to obtain block-slices from a buffer so you can pass them to a library:
///
/// ```ignore
/// for block in buffer.iter_blocks(128) {
/// let mut block_channels = block.into_iter();
/// let stereo_slice = &[
/// block_channels.next().unwrap(),
/// block_channels.next().unwrap(),
/// ];
///
/// // Do something cool with `stereo_slice`
/// }
/// ````
#[inline]
pub fn iter_blocks<'slice>(&'slice mut self, max_block_size: usize) -> BlocksIter<'slice, 'a> {
BlocksIter {
buffers: self.output_slices.as_mut_slice(),
max_block_size,
current_block_start: 0,
_marker: PhantomData,
}
}
/// Set the slices in the raw output slice vector. This vector needs to be resized to match the
/// number of output channels during the plugin's initialization. Then during audio processing,
/// these slices should be updated to point to the plugin's audio buffers. The `num_samples`
/// argument should match the length of the inner slices.
///
/// # Safety
///
/// The stored slices must point to live data when this object is passed to the plugins' process
/// function. The rest of this object also assumes all channel lengths are equal. Panics will
/// likely occur if this is not the case.
pub unsafe fn set_slices(
&mut self,
num_samples: usize,
update: impl FnOnce(&mut Vec<&'a mut [f32]>),
) {
self.num_samples = num_samples;
update(&mut self.output_slices);
#[cfg(debug_assertions)]
for slice in &self.output_slices {
nih_debug_assert_eq!(slice.len(), num_samples);
}
}
}
#[cfg(any(miri, test))]
mod miri {
use super::*;
#[test]
fn repeated_access() {
let mut real_buffers = vec![vec![0.0; 512]; 2];
let mut buffer = Buffer::default();
unsafe {
buffer.set_slices(512, |output_slices| {
let (first_channel, other_channels) = real_buffers.split_at_mut(1);
*output_slices = vec![&mut first_channel[0], &mut other_channels[0]];
})
};
for samples in buffer.iter_samples() {
for sample in samples {
*sample += 0.001;
}
}
for mut samples in buffer.iter_samples() {
for _ in 0..2 {
for sample in samples.iter_mut() {
*sample += 0.001;
}
}
}
assert_eq!(real_buffers[0][0], 0.003);
}
#[test]
fn repeated_slices() {
let mut real_buffers = vec![vec![0.0; 512]; 2];
let mut buffer = Buffer::default();
unsafe {
buffer.set_slices(512, |output_slices| {
let (first_channel, other_channels) = real_buffers.split_at_mut(1);
*output_slices = vec![&mut first_channel[0], &mut other_channels[0]];
})
};
// These iterators should not alias
let mut blocks = buffer.iter_blocks(16);
let (_block1_offset, block1) = blocks.next().unwrap();
let (_block2_offset, block2) = blocks.next().unwrap();
for channel in block1 {
for sample in channel.iter_mut() {
*sample += 0.001;
}
}
for channel in block2 {
for sample in channel.iter_mut() {
*sample += 0.001;
}
}
for i in 0..32 {
assert_eq!(real_buffers[0][i], 0.001);
}
for i in 32..48 {
assert_eq!(real_buffers[0][i], 0.0);
}
}
}