+ DSP primitives: fix a rather stupid bug in clamping functions
[calf.git] / src / calf / delay.h
blob4fd37a56f1014012de3de659ee8eddda6a86c7c1
1 /* Calf DSP Library
2 * Reusable audio effect classes.
4 * Copyright (C) 2001-2007 Krzysztof Foltman
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
21 #ifndef __CALF_DELAY_H
22 #define __CALF_DELAY_H
24 #include "primitives.h"
25 #include "buffer.h"
26 #include "onepole.h"
28 namespace dsp {
30 /**
31 * Delay primitive. Can be used for most delay stuff, including
32 * variable (modulated) delays like chorus/flanger. Note that
33 * for modulated delay effects use of GetInterp is preferred,
34 * because it handles fractional positions and uses linear
35 * interpolation, which sounds better most of the time.
37 * @param N maximum length
38 * @param C number of channels read/written for each sample (1 mono, 2 stereo etc)
40 template<int N, class T>
41 struct simple_delay {
42 auto_buffer<N, T> data;
43 int pos;
45 simple_delay() {
46 reset();
48 void reset() {
49 pos = 0;
50 for (int i=0; i<N; i++)
51 zero(data[i]);
53 /** Write one C-channel sample from idata[0], idata[1] etc into buffer */
54 inline void put(T idata) {
55 data[pos] = idata;
56 pos = wrap_around<N>(pos+1);
59 /**
60 * Read one C-channel sample into odata[0], odata[1] etc into buffer.
61 * Don't use for modulated delays (chorus/flanger etc) unless you
62 * want them to crackle and generally sound ugly
63 * @param odata pointer to write into
64 * @param delay delay relative to current writing pos
66 template<class U>
67 inline void get(U &odata, int delay) {
68 assert(delay >= 0 && delay < N);
69 int ppos = wrap_around<N>(pos + N - delay);
70 odata = data[ppos];
73 /**
74 * Read and write during the same function call
76 inline T process(T idata, int delay)
78 assert(delay >= 0 && delay < N);
79 int ppos = wrap_around<N>(pos + N - delay);
80 T odata = data[ppos];
81 data[pos] = idata;
82 pos = wrap_around<N>(pos+1);
83 return odata;
86 /** Read one C-channel sample at fractional position.
87 * This version can be used for modulated delays, because
88 * it uses linear interpolation.
89 * @param odata value to write into
90 * @param delay delay relative to current writing pos
91 * @param udelay fractional delay (0..1)
93 template<class U>
94 inline void get_interp(U &odata, int delay, float udelay) {
95 // assert(delay >= 0 && delay < N-1);
96 int ppos = wrap_around<N>(pos + N - delay);
97 int pppos = wrap_around<N>(ppos + N - 1);
98 odata = lerp(data[ppos], data[pppos], udelay);
101 /** Read one C-channel sample at fractional position.
102 * This version can be used for modulated delays, because
103 * it uses linear interpolation.
104 * @param odata value to write into
105 * @param delay delay relative to current writing pos
106 * @param udelay fractional delay (0..1)
108 inline T get_interp_1616(unsigned int delay) {
109 float udelay = (float)((delay & 0xFFFF) * (1.0 / 65536.0));
110 delay = delay >> 16;
111 // assert(delay >= 0 && delay < N-1);
112 int ppos = wrap_around<N>(pos + N - delay);
113 int pppos = wrap_around<N>(ppos + N - 1);
114 return lerp(data[ppos], data[pppos], udelay);
118 * Comb filter. Feedback delay line with given delay and feedback values
119 * @param in input signal
120 * @param delay delay length (must be <N and integer)
121 * @param fb feedback (must be <1 or it will be unstable)
123 inline T process_comb(T in, unsigned int delay, float fb)
125 T old, cur;
126 get(old, delay);
127 cur = in + fb*old;
128 sanitize(cur);
129 put(cur);
130 return old;
134 * Comb filter with linear interpolation. Feedback delay line with given delay and feedback values
135 * Note that linear interpolation introduces some weird effects in frequency response.
136 * @param in input signal
137 * @param delay fractional delay length (must be < 65536 * N)
138 * @param fb feedback (must be <1 or it will be unstable)
140 inline T process_comb_lerp16(T in, unsigned int delay, float udelay, float fb)
142 T old, cur;
143 get_interp(old, delay>>16, dsp::fract16(delay));
144 cur = in + fb*old;
145 sanitize(cur);
146 put(cur);
147 return old;
151 * Comb allpass filter. The comb filter with additional direct path, which is supposed to cancel the coloration.
152 * @param in input signal
153 * @param delay delay length (must be <N and integer)
154 * @param fb feedback (must be <1 or it will be unstable)
156 inline T process_allpass_comb(T in, unsigned int delay, float fb)
158 T old, cur;
159 get(old, delay);
160 cur = in + fb*old;
161 sanitize(cur);
162 put(cur);
163 return old - fb * cur;
167 * Comb allpass filter. The comb filter with additional direct path, which is supposed to cancel the coloration.
168 * @param in input signal
169 * @param delay fractional delay length (must be < 65536 * N)
170 * @param fb feedback (must be <1 or it will be unstable)
172 inline T process_allpass_comb_lerp16(T in, unsigned int delay, float fb)
174 T old, cur;
175 get_interp(old, delay>>16, dsp::fract16(delay));
176 cur = in + fb*old;
177 sanitize(cur);
178 put(cur);
179 return old - fb * cur;
185 #endif