Skip to content

Commit

Permalink
Update.
Browse files Browse the repository at this point in the history
  • Loading branch information
SamiPerttu committed Jun 22, 2024
1 parent 7d61b4d commit 577560c
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 91 deletions.
2 changes: 1 addition & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Changes

### Version 0.18 (Next Version)
### Version 0.18

- This release involves a major rewrite and many changes.
- 64-bit sample support is gone. All samples are now `f32`.
Expand Down
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ funutd = { version = "0.16.0", default-features = false }
thingbuf = { version = "0.1.6", default-features = false, features = ["alloc"] }
once_cell = { version = "1.19.0", default-features = false, features = ["race", "alloc"] }
symphonia = { version = "0.5.4", optional = true, features = ["all"] }
no_denormals = "0.1.2"

[dev-dependencies]
anyhow = "1.0.86"
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ Add `fundsp` to your `Cargo.toml` as a dependency.
fundsp = "0.18.0"
```

The `files` feature is enabled by default. It adds support for
loading of audio files into `Wave` objects
via the [Symphonia](https://crates.io/crates/symphonia) crate.

### no_std Support

FunDSP supports `no_std` environments. To enable `no_std`, disable
Expand Down
152 changes: 64 additions & 88 deletions src/feedback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,6 @@ use alloc::boxed::Box;
use alloc::vec;
use alloc::vec::Vec;

#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))]
#[inline(always)]
pub fn flush_denormals<T, F: FnOnce() -> T>(f: F) -> T {
f()
}

#[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))]
#[inline(always)]
pub fn flush_denormals<T, F: FnOnce() -> T>(f: F) -> T {
no_denormals::no_denormals(f)
}

/// Diffusive Hadamard feedback matrix. The number of channels must be a power of two.
#[derive(Default, Clone)]
pub struct FrameHadamard<N: Size<f32>> {
Expand Down Expand Up @@ -137,25 +125,21 @@ where

#[inline]
fn tick(&mut self, input: &Frame<f32, Self::Inputs>) -> Frame<f32, Self::Outputs> {
flush_denormals(|| {
let output = self.x.tick(&(input + self.value.clone()));
self.value = self.feedback.frame(&output);
output
})
let output = self.x.tick(&(input + self.value.clone()));
self.value = self.feedback.frame(&output);
output
}

fn process(&mut self, size: usize, input: &BufferRef, output: &mut BufferMut) {
flush_denormals(|| {
for i in 0..size {
let input_frame =
Frame::generate(|channel| input.at_f32(channel, i) + self.value[channel]);
let output_frame = self.x.tick(&input_frame);
self.value = self.feedback.frame(&output_frame);
for channel in 0..self.outputs() {
output.set_f32(channel, i, output_frame[channel]);
}
for i in 0..size {
let input_frame =
Frame::generate(|channel| input.at_f32(channel, i) + self.value[channel]);
let output_frame = self.x.tick(&input_frame);
self.value = self.feedback.frame(&output_frame);
for channel in 0..self.outputs() {
output.set_f32(channel, i, output_frame[channel]);
}
})
}
}

fn route(&mut self, input: &SignalFrame, _frequency: f64) -> SignalFrame {
Expand Down Expand Up @@ -251,25 +235,21 @@ where

#[inline]
fn tick(&mut self, input: &Frame<f32, Self::Inputs>) -> Frame<f32, Self::Outputs> {
flush_denormals(|| {
let output = self.x.tick(&(input + self.value.clone()));
self.value = self.feedback.frame(&self.y.tick(&output));
output
})
let output = self.x.tick(&(input + self.value.clone()));
self.value = self.feedback.frame(&self.y.tick(&output));
output
}

fn process(&mut self, size: usize, input: &BufferRef, output: &mut BufferMut) {
flush_denormals(|| {
for i in 0..size {
let input_frame =
Frame::generate(|channel| input.at_f32(channel, i) + self.value[channel]);
let output_frame = self.x.tick(&input_frame);
self.value = self.feedback.frame(&self.y.tick(&output_frame));
for channel in 0..self.outputs() {
output.set_f32(channel, i, output_frame[channel]);
}
for i in 0..size {
let input_frame =
Frame::generate(|channel| input.at_f32(channel, i) + self.value[channel]);
let output_frame = self.x.tick(&input_frame);
self.value = self.feedback.frame(&self.y.tick(&output_frame));
for channel in 0..self.outputs() {
output.set_f32(channel, i, output_frame[channel]);
}
})
}
}

fn route(&mut self, input: &SignalFrame, _frequency: f64) -> SignalFrame {
Expand Down Expand Up @@ -369,60 +349,56 @@ impl AudioUnit for FeedbackUnit {
}

fn tick(&mut self, input: &[f32], output: &mut [f32]) {
flush_denormals(|| {
let read_i = self.read_index(self.samples);
for (channel, (tick, i)) in self.tick_buffer.iter_mut().zip(input.iter()).enumerate() {
*tick = *i + self.feedback[channel][read_i];
}
self.x.tick(&self.tick_buffer, output);
for (channel, i) in output.iter().enumerate() {
self.feedback[channel][self.index] = *i;
}
self.index = (self.index + 1) & self.mask;
});
let read_i = self.read_index(self.samples);
for (channel, (tick, i)) in self.tick_buffer.iter_mut().zip(input.iter()).enumerate() {
*tick = *i + self.feedback[channel][read_i];
}
self.x.tick(&self.tick_buffer, output);
for (channel, i) in output.iter().enumerate() {
self.feedback[channel][self.index] = *i;
}
self.index = (self.index + 1) & self.mask;
}

fn process(&mut self, size: usize, input: &BufferRef, output: &mut BufferMut) {
flush_denormals(|| {
if size <= self.samples {
// We have enough feedback samples to process the whole block at once.
for channel in 0..self.channels {
let mut read_i = self.read_index(self.samples);
for (b, i) in self.buffer.channel_mut_f32(channel)[0..size]
.iter_mut()
.zip(input.channel_f32(channel)[0..size].iter())
{
*b = *i + self.feedback[channel][read_i];
read_i = (read_i + 1) & self.mask;
}
}
self.x.process(size, &self.buffer.buffer_ref(), output);
for channel in 0..self.channels {
let mut write_i = self.index;
for i in output.channel_f32(channel)[0..size].iter() {
self.feedback[channel][write_i] = *i;
write_i = (write_i + 1) & self.mask;
}
}
} else {
// The feedback delay is small so we proceed sample by sample.
if size <= self.samples {
// We have enough feedback samples to process the whole block at once.
for channel in 0..self.channels {
let mut read_i = self.read_index(self.samples);
let mut write_i = self.index;
for i in 0..size {
for (channel, tick) in self.tick_buffer.iter_mut().enumerate() {
*tick = input.at_f32(channel, i) + self.feedback[channel][read_i];
}
self.x.tick(&self.tick_buffer, &mut self.tick_buffer2);
for (channel, tick) in self.tick_buffer2.iter().enumerate() {
output.set_f32(channel, i, *tick);
self.feedback[channel][write_i] = *tick;
}
for (b, i) in self.buffer.channel_mut_f32(channel)[0..size]
.iter_mut()
.zip(input.channel_f32(channel)[0..size].iter())
{
*b = *i + self.feedback[channel][read_i];
read_i = (read_i + 1) & self.mask;
}
}
self.x.process(size, &self.buffer.buffer_ref(), output);
for channel in 0..self.channels {
let mut write_i = self.index;
for i in output.channel_f32(channel)[0..size].iter() {
self.feedback[channel][write_i] = *i;
write_i = (write_i + 1) & self.mask;
}
}
self.index = (self.index + size) & self.mask;
});
} else {
// The feedback delay is small so we proceed sample by sample.
let mut read_i = self.read_index(self.samples);
let mut write_i = self.index;
for i in 0..size {
for (channel, tick) in self.tick_buffer.iter_mut().enumerate() {
*tick = input.at_f32(channel, i) + self.feedback[channel][read_i];
}
self.x.tick(&self.tick_buffer, &mut self.tick_buffer2);
for (channel, tick) in self.tick_buffer2.iter().enumerate() {
output.set_f32(channel, i, *tick);
self.feedback[channel][write_i] = *tick;
}
read_i = (read_i + 1) & self.mask;
write_i = (write_i + 1) & self.mask;
}
}
self.index = (self.index + size) & self.mask;
}

fn inputs(&self) -> usize {
Expand Down
2 changes: 1 addition & 1 deletion src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl Wave {
for i in 0..self.length() {
for channel in 0..self.channels() {
let sample = round(clamp11(self.at(channel, i)) * 32767.49);
write16(&mut writer, (sample as i64) as u16)?;
write16(&mut writer, (sample as i16) as u16)?;
}
}
std::io::Result::Ok(())
Expand Down

0 comments on commit 577560c

Please sign in to comment.