059c3748a4edcabaf50006a5bb94b927afd41e48
[vlc.git] / modules / audio_filter / spatializer / revmodel.cpp
1 // Reverb model implementation
2 // 
3 // 
4 // Google Summer of Code 2007
5 // 
6 // Authors: Biodun Osunkunle <biodun@videolan.org> 
7 // 
8 // Mentor : Jean-Baptiste Kempf <jb@videolan.org>
9 //
10 // Original written by Jezar at Dreampoint, June 2000
11
12 // This code is public domain
13
14 #include "revmodel.hpp"
15 #include <stdlib.h>
16
17 revmodel::revmodel()
18 {
19         // Tie the components to their buffers
20         combL[0].setbuffer(bufcombL1,combtuningL1);
21         combR[0].setbuffer(bufcombR1,combtuningR1);
22         combL[1].setbuffer(bufcombL2,combtuningL2);
23         combR[1].setbuffer(bufcombR2,combtuningR2);
24         combL[2].setbuffer(bufcombL3,combtuningL3);
25         combR[2].setbuffer(bufcombR3,combtuningR3);
26         combL[3].setbuffer(bufcombL4,combtuningL4);
27         combR[3].setbuffer(bufcombR4,combtuningR4);
28         combL[4].setbuffer(bufcombL5,combtuningL5);
29         combR[4].setbuffer(bufcombR5,combtuningR5);
30         combL[5].setbuffer(bufcombL6,combtuningL6);
31         combR[5].setbuffer(bufcombR6,combtuningR6);
32         combL[6].setbuffer(bufcombL7,combtuningL7);
33         combR[6].setbuffer(bufcombR7,combtuningR7);
34         combL[7].setbuffer(bufcombL8,combtuningL8);
35         combR[7].setbuffer(bufcombR8,combtuningR8);
36         allpassL[0].setbuffer(bufallpassL1,allpasstuningL1);
37         allpassR[0].setbuffer(bufallpassR1,allpasstuningR1);
38         allpassL[1].setbuffer(bufallpassL2,allpasstuningL2);
39         allpassR[1].setbuffer(bufallpassR2,allpasstuningR2);
40         allpassL[2].setbuffer(bufallpassL3,allpasstuningL3);
41         allpassR[2].setbuffer(bufallpassR3,allpasstuningR3);
42         allpassL[3].setbuffer(bufallpassL4,allpasstuningL4);
43         allpassR[3].setbuffer(bufallpassR4,allpasstuningR4);
44
45         // Set default values
46         allpassL[0].setfeedback(0.5f);
47         allpassR[0].setfeedback(0.5f);
48         allpassL[1].setfeedback(0.5f);
49         allpassR[1].setfeedback(0.5f);
50         allpassL[2].setfeedback(0.5f);
51         allpassR[2].setfeedback(0.5f);
52         allpassL[3].setfeedback(0.5f);
53         allpassR[3].setfeedback(0.5f);
54         setwet(initialwet);
55         setroomsize(initialroom);
56         setdry(initialdry);
57         setdamp(initialdamp);
58         setwidth(initialwidth);
59         setmode(initialmode);
60
61         // Buffer will be full of rubbish - so we MUST mute them
62         mute();
63 }
64
65 void revmodel::mute()
66 {
67         int i;
68         if (getmode() >= freezemode)
69                 return;
70
71         for (i = 0 ; i < numcombs ; i++)
72         {
73                 combL[i].mute();
74                 combR[i].mute();
75         }
76         for (i=0;i<numallpasses;i++)
77         {
78                 allpassL[i].mute();
79                 allpassR[i].mute();
80         }
81 }
82
83 void revmodel::processreplace(float *inputL, float *outputL, long numsamples, int skip)
84 {
85         float outL,outR,input;
86         float inputR;
87         int i;
88
89         outL = outR = 0;
90         if (skip > 1) 
91            inputR = inputL[1];
92         else 
93            inputR = inputL[0];         
94                 input = (inputL[0] + inputR) * gain;
95                 
96                 // Accumulate comb filters in parallel
97                 for(i=0; i<numcombs; i++)
98                 {
99                         outL += combL[i].process(input);
100                         outR += combR[i].process(input);
101                 }
102
103                 // Feed through allpasses in series
104                 for(i=0; i<numallpasses; i++)
105                 {
106                         outL = allpassL[i].process(outL);
107                         outR = allpassR[i].process(outR);
108                 }
109
110                 // Calculate output REPLACING anything already there
111                 outputL[0] = (outL*wet1 + outR*wet2 + inputR*dry);
112            if (skip > 1)
113                 outputL[1] = (outR*wet1 + outL*wet2 + inputR*dry);
114 }
115
116 void revmodel::processmix(float *inputL, float *outputL, long numsamples, int skip)
117 {
118         float outL,outR,input;
119         float inputR;
120         int i;
121
122         outL = outR = 0;
123         if (skip > 1) 
124            inputR = inputL[1];
125         else 
126            inputR = inputL[0];         
127                 input = (inputL[0] + inputR) * gain;
128                 
129                 // Accumulate comb filters in parallel
130                 for(i=0; i<numcombs; i++)
131                 {
132                         outL += combL[i].process(input);
133                         outR += combR[i].process(input);
134                 }
135
136                 // Feed through allpasses in series
137                 for(i=0; i<numallpasses; i++)
138                 {
139                         outL = allpassL[i].process(outL);
140                         outR = allpassR[i].process(outR);
141                 }
142
143                 // Calculate output REPLACING anything already there
144                 outputL[0] += (outL*wet1 + outR*wet2 + inputR*dry);
145            if (skip > 1)
146                 outputL[1] += (outR*wet1 + outL*wet2 + inputR*dry);
147 }
148
149 void revmodel::update()
150 {
151 // Recalculate internal values after parameter change
152
153         int i;
154
155         wet1 = wet*(width/2 + 0.5f);
156         wet2 = wet*((1-width)/2);
157
158         if (mode >= freezemode)
159         {
160                 roomsize1 = 1;
161                 damp1 = 0;
162                 gain = muted;
163         }
164         else
165         {
166                 roomsize1 = roomsize;
167                 damp1 = damp;
168                 gain = fixedgain;
169         }
170
171         for(i=0; i<numcombs; i++)
172         {
173                 combL[i].setfeedback(roomsize1);
174                 combR[i].setfeedback(roomsize1);
175         }
176
177         for(i=0; i<numcombs; i++)
178         {
179                 combL[i].setdamp(damp1);
180                 combR[i].setdamp(damp1);
181         }
182 }
183
184 // The following get/set functions are not inlined, because
185 // speed is never an issue when calling them, and also
186 // because as you develop the reverb model, you may
187 // wish to take dynamic action when they are called.
188
189 void revmodel::setroomsize(float value)
190 {
191         roomsize = (value*scaleroom) + offsetroom;
192         update();
193 }
194
195 float revmodel::getroomsize()
196 {
197         return (roomsize-offsetroom)/scaleroom;
198 }
199
200 void revmodel::setdamp(float value)
201 {
202         damp = value*scaledamp;
203         update();
204 }
205
206 float revmodel::getdamp()
207 {
208         return damp/scaledamp;
209 }
210
211 void revmodel::setwet(float value)
212 {
213         wet = value*scalewet;
214         update();
215 }
216
217 float revmodel::getwet()
218 {
219         return wet/scalewet;
220 }
221
222 void revmodel::setdry(float value)
223 {
224         dry = value*scaledry;
225 }
226
227 float revmodel::getdry()
228 {
229         return dry/scaledry;
230 }
231
232 void revmodel::setwidth(float value)
233 {
234         width = value;
235         update();
236 }
237
238 float revmodel::getwidth()
239 {
240         return width;
241 }
242
243 void revmodel::setmode(float value)
244 {
245         mode = value;
246         update();
247 }
248
249 float revmodel::getmode()
250 {
251         if (mode >= freezemode)
252                 return 1;
253         else
254                 return 0;
255 }
256
257 //ends