audio_processor_time/mono_delay/
mod.rs

1// Augmented Audio: Audio libraries and applications
2// Copyright (c) 2022 Pedro Tacla Yamada
3//
4// The MIT License (MIT)
5//
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to deal
8// in the Software without restriction, including without limitation the rights
9// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10// copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12//
13// The above copyright notice and this permission notice shall be included in
14// all copies or substantial portions of the Software.
15//
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22// THE SOFTWARE.
23
24use std::sync::atomic::{AtomicUsize, Ordering};
25use std::time::Duration;
26
27use audio_garbage_collector::Shared;
28use audio_processor_traits::parameters::{
29    make_handle_ref, AudioProcessorHandleProvider, AudioProcessorHandleRef,
30};
31use audio_processor_traits::simple_processor::MonoAudioProcessor;
32use audio_processor_traits::{AtomicF32, AudioContext, Float};
33use augmented_atomics::AtomicValue;
34use generic_handle::GenericHandle;
35
36mod generic_handle;
37
38pub struct MonoDelayProcessorHandle {
39    feedback: AtomicF32,
40    delay_time_secs: AtomicF32,
41    current_write_position: AtomicUsize,
42    current_read_position: AtomicUsize,
43    sample_rate: AtomicF32,
44    buffer_size: AtomicUsize,
45}
46
47impl Default for MonoDelayProcessorHandle {
48    fn default() -> Self {
49        Self {
50            feedback: AtomicF32::from(0.3),
51            delay_time_secs: AtomicF32::from(0.2),
52            current_write_position: AtomicUsize::new(0),
53            sample_rate: AtomicF32::new(44100.0),
54            buffer_size: AtomicUsize::new(1),
55            current_read_position: AtomicUsize::new(0),
56        }
57    }
58}
59
60impl MonoDelayProcessorHandle {
61    pub fn set_feedback(&self, value: f32) {
62        self.feedback.set(value);
63    }
64
65    pub fn set_delay_time_secs(&self, value: f32) {
66        self.delay_time_secs.set(value);
67
68        // Cast to i64 to prevent negative overflow
69        let write_position = self.current_write_position.get() as i64;
70        let sample_rate = self.sample_rate.get();
71        let buffer_size = self.buffer_size.get() as i64;
72        let offset = (sample_rate * value) as i64;
73        let cursor = write_position - offset + buffer_size;
74        self.current_read_position
75            .store((cursor % buffer_size) as usize, Ordering::Relaxed);
76    }
77}
78
79pub struct MonoDelayProcessor<Sample> {
80    delay_buffer: Vec<Sample>,
81    handle: Shared<MonoDelayProcessorHandle>,
82    max_delay_time: Duration,
83}
84
85impl<Sample> AudioProcessorHandleProvider for MonoDelayProcessor<Sample> {
86    fn generic_handle(&self) -> AudioProcessorHandleRef {
87        make_handle_ref(GenericHandle(self.handle.clone()))
88    }
89}
90
91impl<Sample: Float + From<f32>> Default for MonoDelayProcessor<Sample> {
92    fn default() -> Self {
93        Self::default_with_handle(audio_garbage_collector::handle())
94    }
95}
96
97impl<Sample: Float + From<f32>> MonoDelayProcessor<Sample> {
98    pub fn default_with_handle(handle: &audio_garbage_collector::Handle) -> Self {
99        let max_delay_time = Duration::from_secs(5);
100        let processor_handle = Shared::new(handle, MonoDelayProcessorHandle::default());
101
102        Self::new(max_delay_time, processor_handle)
103    }
104
105    pub fn new(max_delay_time: Duration, handle: Shared<MonoDelayProcessorHandle>) -> Self {
106        Self {
107            handle,
108            max_delay_time,
109            delay_buffer: Self::make_vec(max_delay_time.as_secs() as usize),
110        }
111    }
112
113    pub fn handle(&self) -> &Shared<MonoDelayProcessorHandle> {
114        &self.handle
115    }
116
117    fn make_vec(max_delay_time: usize) -> Vec<Sample> {
118        let mut v = Vec::with_capacity(max_delay_time);
119        v.resize(max_delay_time, 0.0.into());
120        v
121    }
122
123    pub fn read(&self) -> Sample {
124        let delay_samples = self.delay_samples();
125        let offset = delay_samples - delay_samples.floor();
126        let offset: Sample = offset.into();
127        let buffer_size = self.handle.buffer_size.get();
128
129        let mut current_read_position = self.handle().current_read_position.get();
130        let delay_output = interpolate(
131            self.delay_buffer[current_read_position],
132            self.delay_buffer[(current_read_position + 1) % buffer_size],
133            offset,
134        );
135
136        current_read_position += 1;
137        if current_read_position >= buffer_size {
138            current_read_position = 0;
139        }
140        self.handle
141            .current_read_position
142            .store(current_read_position, Ordering::Relaxed);
143
144        delay_output
145    }
146
147    pub fn write(&mut self, sample: Sample) {
148        let mut current_write_position = self.handle().current_write_position.get();
149        self.delay_buffer[current_write_position] = sample;
150
151        current_write_position += 1;
152        if current_write_position >= self.handle.buffer_size.get() {
153            current_write_position = 0;
154        }
155        self.handle
156            .current_write_position
157            .store(current_write_position, Ordering::Relaxed);
158    }
159
160    fn delay_samples(&self) -> f32 {
161        self.handle.delay_time_secs.get() * self.handle.sample_rate.get()
162    }
163}
164
165fn interpolate<S>(s1: S, s2: S, offset: S) -> S
166where
167    S: Float + From<f32>,
168{
169    let one: S = 1.0_f32.into();
170    let offset: S = offset;
171    let rhs = offset * s2;
172    let lhs = (one - offset) * s1;
173    // assert!(rhs < S::epsilon());
174    // assert!(lhs - s1 < S::epsilon());
175    lhs + rhs
176}
177
178impl<Sample: Float + From<f32>> MonoAudioProcessor for MonoDelayProcessor<Sample> {
179    type SampleType = Sample;
180
181    fn m_prepare(&mut self, context: &mut AudioContext) {
182        let settings = context.settings;
183        let buffer_size = (self.max_delay_time.as_secs_f32() * settings.sample_rate()) as usize;
184
185        self.handle
186            .buffer_size
187            .store(buffer_size, Ordering::Relaxed);
188        self.delay_buffer.resize(buffer_size, 0.0.into());
189        self.handle
190            .sample_rate
191            .store(settings.sample_rate(), Ordering::Relaxed);
192
193        self.handle.current_write_position.store(
194            (self.handle.delay_time_secs.get() * settings.sample_rate()) as usize,
195            Ordering::Relaxed,
196        );
197        self.handle
198            .current_read_position
199            .store(0, Ordering::Relaxed);
200    }
201
202    fn m_process(
203        &mut self,
204        _context: &mut AudioContext,
205        sample: Self::SampleType,
206    ) -> Self::SampleType {
207        let delay_output = self.read();
208
209        let write_sample = sample + delay_output * self.handle.feedback.get().into();
210        self.write(write_sample);
211
212        delay_output
213    }
214}