LMMS
Loading...
Searching...
No Matches
Delay.h
Go to the documentation of this file.
1/*
2 * Delay.h - Delay effect objects to use as building blocks in DSP
3 *
4 * Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
5 * Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
6 *
7 * This file is part of LMMS - https://lmms.io
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public
20 * License along with this program (see COPYING); if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301 USA.
23 *
24 */
25
26#ifndef LMMS_DELAY_H
27#define LMMS_DELAY_H
28
29#include <cmath>
30
31#include "LmmsTypes.h"
32
33namespace lmms
34{
35
36// brief usage
37
38// Classes:
39
40// CombFeedback: a feedback comb filter - basically a simple delay line, makes a comb shape in the freq response
41// CombFeedfwd: a feed-forward comb filter - an "inverted" comb filter, can be combined with CombFeedback to create a net allpass if negative gain is used
42// CombFeedbackDualtap: same as CombFeedback but takes two delay values
43// AllpassDelay: an allpass delay - combines feedback and feed-forward - has flat frequency response
44
45// all classes are templated with channel count, any arbitrary channel count can be used for each fx
46
47// Methods (for all classes):
48
49// setDelay sets delay amount in frames. It's up to you to make this samplerate-agnostic.
50// Fractions are allowed - linear interpolation is used to deal with them
51// CombFeedbackDualTap is a special case: it requires 2 delay times
52
53// setMaxDelay (re)sets the maximum allowed delay, in frames
54// NOTE: for performance reasons, there's no bounds checking at setDelay, so make sure you set maxDelay >= delay!
55
56// clearHistory clears the delay buffer
57
58// setGain sets the feedback/feed-forward gain, in linear amplitude, negative values are allowed
59// 1.0 is full feedback/feed-forward, -1.0 is full negative feedback/feed-forward
60
61// update runs the fx for one frame - takes as arguments input and number of channel to run, returns output
62
63template<ch_cnt_t CHANNELS>
65{
66public:
67 using frame = std::array<double, CHANNELS>;
68
69 CombFeedback( int maxDelay ) :
70 m_size( maxDelay ),
71 m_position( 0 ),
72 m_feedBack( 0.0 ),
73 m_delay( 0 ),
74 m_fraction( 0.0 )
75 {
76 m_buffer = new frame[maxDelay];
77 memset( m_buffer, 0, sizeof( frame ) * maxDelay );
78 }
79 virtual ~CombFeedback()
80 {
81 delete[] m_buffer;
82 }
83
84 inline void setMaxDelay( int maxDelay )
85 {
86 if( maxDelay > m_size )
87 {
88 delete[] m_buffer;
89 m_buffer = new frame[maxDelay];
90 memset( m_buffer, 0, sizeof( frame ) * maxDelay );
91 }
92 m_size = maxDelay;
94 }
95
96 inline void clearHistory()
97 {
98 memset( m_buffer, 0, sizeof( frame ) * m_size );
99 }
100
101 inline void setDelay( double delay )
102 {
103 m_delay = static_cast<int>( ceil( delay ) );
104 m_fraction = 1.0 - ( delay - floor( delay ) );
105 }
106
107 inline void setGain( double gain )
108 {
109 m_gain = gain;
110 }
111
112 inline double update( double in, ch_cnt_t ch )
113 {
114 int readPos = m_position - m_delay;
115 if( readPos < 0 ) { readPos += m_size; }
116
117 const double y = std::lerp(m_buffer[readPos][ch], m_buffer[(readPos + 1) % m_size][ch], m_fraction);
118
119 ++m_position %= m_size;
120
121 m_buffer[m_position][ch] = in + m_gain * y;
122 return y;
123 }
124
125private:
129 double m_gain;
132};
133
134
135template<ch_cnt_t CHANNELS>
137{
138 using frame = std::array<double, CHANNELS>;
139
140 CombFeedfwd( int maxDelay ) :
141 m_size( maxDelay ),
142 m_position( 0 ),
143 m_feedBack( 0.0 ),
144 m_delay( 0 ),
145 m_fraction( 0.0 )
146 {
147 m_buffer = new frame[maxDelay];
148 memset( m_buffer, 0, sizeof( frame ) * maxDelay );
149 }
150 virtual ~CombFeedfwd()
151 {
152 delete[] m_buffer;
153 }
154
155 inline void setMaxDelay( int maxDelay )
156 {
157 if( maxDelay > m_size )
158 {
159 delete[] m_buffer;
160 m_buffer = new frame[maxDelay];
161 memset( m_buffer, 0, sizeof( frame ) * maxDelay );
162 }
163 m_size = maxDelay;
165 }
166
167 inline void clearHistory()
168 {
169 memset( m_buffer, 0, sizeof( frame ) * m_size );
170 }
171
172 inline void setDelay( double delay )
173 {
174 m_delay = static_cast<int>( ceil( delay ) );
175 m_fraction = 1.0 - ( delay - floor( delay ) );
176 }
177
178 inline void setGain( double gain )
179 {
180 m_gain = gain;
181 }
182
183 inline double update( double in, ch_cnt_t ch )
184 {
185 int readPos = m_position - m_delay;
186 if( readPos < 0 ) { readPos += m_size; }
187
188 const double y = std::lerp(m_buffer[readPos][ch], m_buffer[(readPos + 1) % m_size][ch], m_fraction) + in * m_gain;
189
190 ++m_position %= m_size;
191
192 m_buffer[m_position][ch] = in;
193 return y;
194 }
195
196private:
200 double m_gain;
203};
204
205
206template<ch_cnt_t CHANNELS>
208{
209 using frame = std::array<double, CHANNELS>;
210
211 CombFeedbackDualtap( int maxDelay ) :
212 m_size( maxDelay ),
213 m_position( 0 ),
214 m_feedBack( 0.0 ),
215 m_delay( 0 ),
216 m_fraction( 0.0 )
217 {
218 m_buffer = new frame[maxDelay];
219 memset( m_buffer, 0, sizeof( frame ) * maxDelay );
220 }
222 {
223 delete[] m_buffer;
224 }
225
226 inline void setMaxDelay( int maxDelay )
227 {
228 if( maxDelay > m_size )
229 {
230 delete[] m_buffer;
231 m_buffer = new frame[maxDelay];
232 memset( m_buffer, 0, sizeof( frame ) * maxDelay );
233 }
234 m_size = maxDelay;
236 }
237
238 inline void clearHistory()
239 {
240 memset( m_buffer, 0, sizeof( frame ) * m_size );
241 }
242
243 inline void setDelays( double delay1, double delay2 )
244 {
245 m_delay1 = static_cast<int>( ceil( delay1 ) );
246 m_fraction1 = 1.0 - ( delay1 - floor( delay1 ) );
247
248 m_delay2 = static_cast<int>( ceil( delay2 ) );
249 m_fraction2 = 1.0 - ( delay2 - floor( delay2 ) );
250 }
251
252 inline void setGain( double gain )
253 {
254 m_gain = gain;
255 }
256
257 inline double update( double in, ch_cnt_t ch )
258 {
259 int readPos1 = m_position - m_delay1;
260 if( readPos1 < 0 ) { readPos1 += m_size; }
261
262 int readPos2 = m_position - m_delay2;
263 if( readPos2 < 0 ) { readPos2 += m_size; }
264
265 const double y = std::lerp(m_buffer[readPos1][ch], m_buffer[(readPos1 + 1) % m_size][ch], m_fraction1)
266 + std::lerp(m_buffer[readPos2][ch], m_buffer[(readPos2 + 1) % m_size][ch], m_fraction2);
267
268 ++m_position %= m_size;
269
270 m_buffer[m_position][ch] = in + m_gain * y;
271 return y;
272 }
273
274private:
278 double m_gain;
283};
284
285
286template<ch_cnt_t CHANNELS>
288{
289public:
290 using frame = std::array<double, CHANNELS>;
291
292 AllpassDelay( int maxDelay ) :
293 m_size( maxDelay ),
294 m_position( 0 ),
295 m_feedBack( 0.0 ),
296 m_delay( 0 ),
297 m_fraction( 0.0 )
298 {
299 m_buffer = new frame[maxDelay];
300 memset( m_buffer, 0, sizeof( frame ) * maxDelay );
301 }
303 {
304 delete[] m_buffer;
305 }
306
307 inline void setMaxDelay( int maxDelay )
308 {
309 if( maxDelay > m_size )
310 {
311 delete[] m_buffer;
312 m_buffer = new frame[maxDelay];
313 memset( m_buffer, 0, sizeof( frame ) * maxDelay );
314 }
315 m_size = maxDelay;
317 }
318
319 inline void clearHistory()
320 {
321 memset( m_buffer, 0, sizeof( frame ) * m_size );
322 }
323
324 inline void setDelay( double delay )
325 {
326 m_delay = static_cast<int>( ceil( delay ) );
327 m_fraction = 1.0 - ( delay - floor( delay ) );
328 }
329
330 inline void setGain( double gain )
331 {
332 m_gain = gain;
333 }
334
335 inline double update( double in, ch_cnt_t ch )
336 {
337 int readPos = m_position - m_delay;
338 if( readPos < 0 ) { readPos += m_size; }
339
340 const double y = std::lerp(m_buffer[readPos][ch], m_buffer[(readPos + 1) % m_size][ch], m_fraction) + in * -m_gain;
341 const double x = in + m_gain * y;
342
343 ++m_position %= m_size;
344
345 m_buffer[m_position][ch] = x;
346 return y;
347 }
348
349private:
353 double m_gain;
355 double m_fraction;
356};
357
358// convenience typedefs for stereo effects
363
364} // namespace lmms
365
366#endif // LMMS_DELAY_H
Definition Delay.h:288
void clearHistory()
Definition Delay.h:319
double update(double in, ch_cnt_t ch)
Definition Delay.h:335
AllpassDelay(int maxDelay)
Definition Delay.h:292
int m_size
Definition Delay.h:351
int m_position
Definition Delay.h:352
double m_gain
Definition Delay.h:353
virtual ~AllpassDelay()
Definition Delay.h:302
int m_delay
Definition Delay.h:354
frame * m_buffer
Definition Delay.h:350
std::array< double, CHANNELS > frame
Definition Delay.h:290
void setMaxDelay(int maxDelay)
Definition Delay.h:307
void setDelay(double delay)
Definition Delay.h:324
double m_fraction
Definition Delay.h:355
void setGain(double gain)
Definition Delay.h:330
Definition Delay.h:208
int m_delay2
Definition Delay.h:280
double m_fraction1
Definition Delay.h:281
std::array< double, CHANNELS > frame
Definition Delay.h:209
int m_position
Definition Delay.h:277
int m_delay1
Definition Delay.h:279
void setMaxDelay(int maxDelay)
Definition Delay.h:226
double m_gain
Definition Delay.h:278
double m_fraction2
Definition Delay.h:282
double update(double in, ch_cnt_t ch)
Definition Delay.h:257
void setDelays(double delay1, double delay2)
Definition Delay.h:243
void clearHistory()
Definition Delay.h:238
int m_size
Definition Delay.h:276
void setGain(double gain)
Definition Delay.h:252
frame * m_buffer
Definition Delay.h:275
CombFeedbackDualtap(int maxDelay)
Definition Delay.h:211
virtual ~CombFeedbackDualtap()
Definition Delay.h:221
Definition Delay.h:65
frame * m_buffer
Definition Delay.h:126
void setMaxDelay(int maxDelay)
Definition Delay.h:84
double update(double in, ch_cnt_t ch)
Definition Delay.h:112
virtual ~CombFeedback()
Definition Delay.h:79
double m_gain
Definition Delay.h:129
void setGain(double gain)
Definition Delay.h:107
CombFeedback(int maxDelay)
Definition Delay.h:69
void setDelay(double delay)
Definition Delay.h:101
int m_delay
Definition Delay.h:130
void clearHistory()
Definition Delay.h:96
std::array< double, CHANNELS > frame
Definition Delay.h:67
int m_size
Definition Delay.h:127
int m_position
Definition Delay.h:128
double m_fraction
Definition Delay.h:131
Definition Delay.h:137
frame * m_buffer
Definition Delay.h:197
virtual ~CombFeedfwd()
Definition Delay.h:150
double update(double in, ch_cnt_t ch)
Definition Delay.h:183
void setGain(double gain)
Definition Delay.h:178
void setMaxDelay(int maxDelay)
Definition Delay.h:155
int m_position
Definition Delay.h:199
void clearHistory()
Definition Delay.h:167
std::array< double, CHANNELS > frame
Definition Delay.h:138
int m_delay
Definition Delay.h:201
int m_size
Definition Delay.h:198
double m_gain
Definition Delay.h:200
double m_fraction
Definition Delay.h:202
CombFeedfwd(int maxDelay)
Definition Delay.h:140
void setDelay(double delay)
Definition Delay.h:172
int y
Definition inflate.c:1588
unsigned x[BMAX+1]
Definition inflate.c:1586
float in
Definition lilv_test.c:1460
Definition AudioAlsa.cpp:35
CombFeedbackDualtap< 2 > StereoCombFeedbackDualtap
Definition Delay.h:361
std::uint16_t ch_cnt_t
Definition LmmsTypes.h:44
CombFeedback< 2 > StereoCombFeedback
Definition Delay.h:359
AllpassDelay< 2 > StereoAllpassDelay
Definition Delay.h:362
CombFeedfwd< 2 > StereoCombFeedfwd
Definition Delay.h:360