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
mod filters;
use filters::{Mode, TPTOnePoleStereo};
const SAMPLE_RATE: f32 = 44_100.0;
pub struct Settings {
pub delay_time: f32,
pub output_level: f32,
pub feedback: f32,
pub ping_pong: bool,
pub width: f32,
pub phase_reverse: bool,
pub lowpass_filter: f64,
pub highpass_filter: f64,
pub dry_wet_mix: f32,
}
impl Default for Settings {
fn default() -> Self {
Self {
delay_time: 250.,
output_level: 1.0,
feedback: 0.8,
ping_pong: true,
width: 1.0,
phase_reverse: true,
lowpass_filter: 5000.0,
highpass_filter: 500.0,
dry_wet_mix: 0.5,
}
}
}
struct State {
delay_buffer: Vec<(f32, f32)>,
delay_buffer_index: usize,
lowpass_filter: TPTOnePoleStereo,
highpass_filter: TPTOnePoleStereo,
}
pub struct Delay {
pub settings: Settings,
state: State,
}
impl Delay {
pub fn new(settings: Settings) -> Self {
let delay_buffer_size = (settings.delay_time / 1000.0) * SAMPLE_RATE;
let state = State {
delay_buffer: vec![(0.0, 0.0); delay_buffer_size as usize],
delay_buffer_index: 0,
lowpass_filter: TPTOnePoleStereo::new(
Mode::LOWPASS,
SAMPLE_RATE as f64,
settings.lowpass_filter,
),
highpass_filter: TPTOnePoleStereo::new(
Mode::HIGHPASS,
SAMPLE_RATE as f64,
settings.highpass_filter,
),
};
Self { settings, state }
}
pub fn process(&mut self, input: &[f32], output: &mut [f32]) {
let mut input_index = 0;
let mut output_index = 0;
let input_stereo: Vec<(f32, f32)> = input.chunks(2).map(|c| (c[0], c[1])).collect();
while input_index < input_stereo.len() && output_index < output.len() {
let input_sample = input_stereo[input_index];
let delay_sample = self.state.delay_buffer[self.state.delay_buffer_index];
let delay_sample = (
delay_sample.0 * self.settings.feedback,
delay_sample.1 * self.settings.feedback,
);
let delay_sample = match self.settings.phase_reverse {
true => (-delay_sample.0, -delay_sample.1),
false => delay_sample,
};
let delay_sample = self.state.lowpass_filter.process(delay_sample);
let delay_sample = self.state.highpass_filter.process(delay_sample);
if self.settings.ping_pong {
let width = self.settings.width / 2.0 + 0.5;
let pp_input = ((input_sample.0) * (1.0 - width), (input_sample.1) * width);
let pp_delay = (
delay_sample.0 * (1.0 - width) + delay_sample.1 * width,
delay_sample.1 * (1.0 - width) + delay_sample.0 * width,
);
self.state.delay_buffer[self.state.delay_buffer_index] =
(pp_input.0 + pp_delay.0, pp_input.1 + pp_delay.1);
} else {
self.state.delay_buffer[self.state.delay_buffer_index] = (
input_sample.0 + delay_sample.0,
input_sample.1 + delay_sample.1,
);
}
let delay_sample = (
(1.0 - self.settings.dry_wet_mix) * input_sample.0
+ self.settings.dry_wet_mix * delay_sample.0,
(1.0 - self.settings.dry_wet_mix) * input_sample.1
+ self.settings.dry_wet_mix * delay_sample.1,
);
let delay_sample = (
delay_sample.0 * self.settings.output_level,
delay_sample.1 * self.settings.output_level,
);
output[output_index * 2] = delay_sample.0;
output[output_index * 2 + 1] = delay_sample.1;
input_index += 1;
output_index += 1;
self.state.delay_buffer_index =
(self.state.delay_buffer_index + 1) % self.state.delay_buffer.len();
}
}
}