From a4f126bcbb5c6b93c4cd65662035655913e1e830 Mon Sep 17 00:00:00 2001 From: Sami Perttu Date: Mon, 18 Nov 2024 20:18:47 +0200 Subject: [PATCH] Update. --- CHANGES.md | 1 + examples/keys.rs | 4 ++-- src/wave.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 215f28f..f2e8436 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ - `BiquadBank` parameters for channel `i` are now set with the syntax `Setting::biquad(...).index(i)`. - New `Wave` methods `mix` and `mix_channel`. - New builder notation for setting envelope sampling interval, for example, `lfo(|t| exp(-t)).interval(0.01)`. +- New `Wave` methods `append`, `amplify` and `retain`. ### Version 0.20 diff --git a/examples/keys.rs b/examples/keys.rs index 84359e4..84667c1 100644 --- a/examples/keys.rs +++ b/examples/keys.rs @@ -514,12 +514,12 @@ impl eframe::App for State { (pass() | lfo(move |t| (max(800.0, 20000.0 * exp(-t * 6.0)), 3.0))) >> !dlowpass(Tanh(1.02)) >> mul((1.0, 0.666, 1.0)) - >> dlowpass(Tanh(1.0)), + >> dlowpass(Tanh(1.02)), )), Filter::FeedbackBiquad => Net::wrap(Box::new( (mul(2.0) | lfo(move |t| (xerp11(200.0, 10000.0, sin_hz(0.2, t)), 5.0))) - >> fresonator(Softsign(1.01)), + >> fresonator(Softsign(1.10)), )), }; let mut note = Box::new(waveform >> filter >> dcblock()); diff --git a/src/wave.rs b/src/wave.rs index 3d43c18..cc3a056 100644 --- a/src/wave.rs +++ b/src/wave.rs @@ -14,10 +14,12 @@ extern crate alloc; use alloc::sync::Arc; use alloc::vec::Vec; -/// Multichannel wave in 32-bit float precision. Requires memory allocation via `Vec`. +/// Multichannel wave in 32-bit float precision. +/// Requires memory allocation via `Vec`. +/// Each channel is stored in its own vector of samples. #[derive(Clone)] pub struct Wave { - /// Vector of channels. Each channel is stored in its own vector. + /// Vector of channels. vec: Vec>, /// Sample rate of the wave. sample_rate: f64, @@ -149,6 +151,8 @@ impl Wave { /// Insert a channel to the wave at channel `channel` from a vector of `samples`. /// The length of the wave and the number of samples must match. + /// If there are no channels yet, then the length of the wave + /// will become the length of the slice. pub fn insert_channel(&mut self, channel: usize, samples: &[f32]) { assert!(self.channels() == 0 || self.len() == samples.len()); assert!(channel <= self.channels()); @@ -177,6 +181,19 @@ impl Wave { self.vec.remove(channel) } + /// Append the contents of the `source` wave to the end of this wave. + /// The number of channels in `source` and this wave must match. + /// Any sample rate differences are ignored. + /// The `source` wave is left unchanged. + pub fn append(&mut self, source: &Wave) { + assert!(self.channels() == source.channels()); + let offset = self.length(); + self.resize(self.length() + source.length()); + for i in 0..self.channels() { + self.mix_channel(i, offset as isize, source.channel(i)); + } + } + /// Sample accessor. #[inline] pub fn at(&self, channel: usize, index: usize) -> f32 { @@ -284,6 +301,22 @@ impl Wave { self.len = length; } + /// Retain in this wave only samples in `start .. start + length` and discard the rest. + /// Only the part of the span overlapping the wave is considered. + /// That is, the offset may be negative and the end of the span may lie beyond the end of the wave. + pub fn retain(&mut self, start: isize, length: usize) { + let i0 = max(start, 0) as usize; + let i1 = min(self.length(), max(0, start + length as isize) as usize); + if i0 > 0 { + for channel in 0..self.channels() { + for i in i0..i1 { + self.set(channel, i - i0, self.at(channel, i)); + } + } + } + self.resize(i1 - i0); + } + /// Peak amplitude of the wave. An empty wave has zero amplitude. /// /// ### Example @@ -303,6 +336,15 @@ impl Wave { peak } + /// Multiply all samples with `amplitude`. + pub fn amplify(&mut self, amplitude: f32) { + for channel in 0..self.channels() { + for i in 0..self.length() { + self.set(channel, i, self.at(channel, i) * amplitude); + } + } + } + /// Scales the wave to the range -1..1. Does nothing if the wave is empty. /// /// ### Example