2 * Multitap chorus class.
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., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307, USA.
21 #ifndef __CALF_MULTICHORUS_H
22 #define __CALF_MULTICHORUS_H
28 typedef fixed_point
<unsigned int, 20> chorus_phase
;
30 template<class T
, uint32_t Voices
>
34 sine_table
<int, 4096, 65535> sine
;
39 /// LFO phase increment
41 /// LFO phase per-voice increment
43 /// Current number of voices
45 /// Current scale (output multiplier)
50 phase
= dphase
= vphase
= 0.0;
53 inline uint32_t get_voices() const
57 inline void set_voices(uint32_t value
)
60 // use sqrt, because some phases will cancel each other - so 1 / N is usually too low
61 scale
= sqrt(1.0 / voices
);
63 /// Get LFO value for given voice, returns a values in range of [-65536, 65535] (or close)
64 inline int get_value(uint32_t voice
) {
65 // find this voice's phase (= phase + voice * 360 degrees / number of voices)
66 chorus_phase voice_phase
= phase
+ vphase
* (int)voice
;
68 unsigned int ipart
= voice_phase
.ipart();
69 // interpolate (use 14 bits of precision - because the table itself uses 17 bits and the result of multiplication must fit in int32_t)
70 // note, the result is still -65535 .. 65535, it's just interpolated
71 // it is never reaching -65536 - but that's acceptable
72 return voice_phase
.lerp_by_fract_int
<int, 14, int>(sine
.data
[ipart
], sine
.data
[ipart
+1]);
77 inline T
get_scale() const {
86 * Multi-tap chorus without feedback.
87 * Perhaps MaxDelay should be a bit longer!
89 template<class T
, class MultiLfo
, class Postprocessor
, int MaxDelay
=4096>
90 class multichorus
: public chorus_base
93 simple_delay
<MaxDelay
,T
> delay
;
110 void set_rate(float rate
) {
111 chorus_base::set_rate(rate
);
114 virtual void setup(int sample_rate
) {
115 modulation_effect::setup(sample_rate
);
118 set_min_delay(get_min_delay());
119 set_mod_depth(get_mod_depth());
121 template<class OutIter
, class InIter
>
122 void process(OutIter buf_out
, InIter buf_in
, int nsamples
) {
123 int mds
= min_delay_samples
+ mod_depth_samples
* 1024 + 2*65536;
124 int mdepth
= mod_depth_samples
;
125 // 1 sample peak-to-peak = mod_depth_samples of 32 (this scaling stuff is tricky and may - but shouldn't - be wrong)
126 // with 192 kHz sample rate, 1 ms = 192 samples, and the maximum 20 ms = 3840 samples (so, 4096 will be used)
127 // 3840 samples of mod depth = mdepth of 122880 (which multiplied by 65536 doesn't fit in int32_t)
128 // so, it will be right-shifted by 2, which gives it a safe range of 30720
129 // NB: calculation of mod_depth_samples (and multiply-by-32) is in chorus_base::set_mod_depth
130 mdepth
= mdepth
>> 2;
131 T scale
= lfo
.get_scale();
132 for (int i
=0; i
<nsamples
; i
++) {
135 float in
= *buf_in
++;
138 unsigned int nvoices
= lfo
.get_voices();
140 // add up values from all voices, each voice tell its LFO phase and the buffer value is picked at that location
141 for (unsigned int v
= 0; v
< nvoices
; v
++)
143 int lfo_output
= lfo
.get_value(v
);
144 // 3 = log2(32 >> 2) + 1 because the LFO value is in range of [-65535, 65535] (17 bits)
145 int dv
= mds
+ (mdepth
* lfo_output
>> (3 + 1));
147 T fd
; // signal from delay's output
148 delay
.get_interp(fd
, ifv
, (dv
& 0xFFFF)*(1.0/65536.0));
151 // apply the post filter
152 out
= post
.process(out
);
153 T sdry
= in
* gs_dry
.get();
154 T swet
= out
* gs_wet
.get() * scale
;
155 *buf_out
++ = sdry
+ swet
;
160 float freq_gain(float freq
, float sr
)
162 typedef std::complex<double> cfloat
;
163 freq
*= 2.0 * M_PI
/ sr
;
164 cfloat z
= 1.0 / exp(cfloat(0.0, freq
)); // z^-1
166 int mds
= min_delay_samples
+ mod_depth_samples
* 1024 + 2*65536;
167 int mdepth
= mod_depth_samples
;
168 mdepth
= mdepth
>> 2;
169 T scale
= lfo
.get_scale();
170 unsigned int nvoices
= lfo
.get_voices();
171 for (unsigned int v
= 0; v
< nvoices
; v
++)
173 int lfo_output
= lfo
.get_value(v
);
174 // 3 = log2(32 >> 2) + 1 because the LFO value is in range of [-65535, 65535] (17 bits)
175 int dv
= mds
+ (mdepth
* lfo_output
>> (3 + 1));
177 cfloat zn
= std::pow(z
, fldp
); // z^-N
178 h
+= zn
+ (zn
* z
- zn
) * cfloat(dv
/ 65536.0 - fldp
);
180 // apply the post filter
182 // mix with dry signal
183 float v
= std::abs(cfloat(gs_dry
.get_last()) + cfloat(scale
* gs_wet
.get_last()) * h
);