CSL 5.2

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

Freeverb.cpp
Go to the documentation of this file.
1 //
2 // Reverb.h -- The CSL port of the public domain Freeverb reverberator
3 // Freeverb was written by Jezar at Dreampoint, June 2000 -- http://www.dreampoint.co.uk
4 // See the copyright notice and acknowledgment of authors in the file COPYRIGHT
5 //
6
7 #include "Freeverb.h"
8
9 //#undef GCC_AUTO_VECTORIZATION
10
11 using namespace csl;
12
13 // These values assume 44.1KHz sample rate
14 // they will probably be OK for 48KHz sample rate
15 // but would need scaling for 96KHz (or other) sample rates.
16 // The values were obtained by listening tests.
17
18 const int kNumCombs = 8;
19 const int kNumAllpasses = 4;
20 const float kMuted = 0.0f;
21 const float kFixedGain = 0.015f;
22 //const float kFixedGain = 1.0f;
23 const float kScaleWet = 3.0f;
24 const float kScaleDry = 2.0f;
25 const float kScaleDamp = 0.4f;
26 const float kScaleRoom = 0.28f;
27 const float kOffsetRoom = 0.7f;
28 const float kInitialRoom = 0.95;
29 const float kInitialDamp = 0.5f;
30 const float kInitialWet = 0.5;
31 const float kInitialDry = 0.5;
32 const float kInitialWidth = 1.0f;
33 const float kInitialMode = 0.0f;
34 const float kFreezeMode = 1.0f;
35 const int kStereoSpread = 23;
36
37 const int kCombBufferSizes[] = { 1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617 };
38 const int kAllpassBufferSizes[] = { 556, 441, 341, 225 };
39
40 // ~~~~~~ Comb implementation ~~~~~~~~~~ //
41
42 void Comb::setBuffer(float *buf, int size) {
43 mBufferPtr = buf;
44 mBufSize = size;
45 }
46
47 void Comb::mute() {
48 for (int i = 0; i < mBufSize; ++i)
49 mBufferPtr[i] = 0;
50 }
51
52 void Comb::setDamp(float val) {
53 mDamp1 = val;
54 mDamp2 = 1 - val;
55 }
56
57 // ~~~~~~ Allpass implementation ~~~~~~~~~~ //
58
59 void FAllpass::setBuffer(float *buf, int size) {
60 mBufferPtr = buf;
61 mBufSize = size;
62 }
63
64 void FAllpass::mute() {
65 for (int i = 0; i < mBufSize; i++)
66 mBufferPtr[i] = 0;
67 }
68
69 // ~~~~~~~ Freeverb implementation ~~~~~~ //
70
71 Freeverb::Freeverb(UnitGenerator &input) : Effect(input) {
72 constructReverbGraph();
73 }
74
75 Freeverb::~Freeverb() {
76 for (unsigned i = 0; i < mCombFilters.size(); i++)
77 delete mCombBuffers[i];
78
79 for (unsigned i = 0; i < mAllpassFilters.size(); i++)
80 delete mAllpassBuffers[i];
81
82 std::vector<Comb*>::iterator iComb = mCombFilters.begin();
83 for (; iComb != mCombFilters.end(); ++iComb)
84 delete *iComb;
85
86 std::vector<FAllpass*>::iterator iAllpass = mAllpassFilters.begin();
87 for (; iAllpass != mAllpassFilters.end(); ++iAllpass)
88 delete *iAllpass;
89 }
90
91 void Freeverb::constructReverbGraph() {
92 int i, j;
93 int bufferSize;
94 sample * bufferPtr;
95 Comb *combFilter;
96 FAllpass *allpassFilter;
97 mCombBuffers = new SampleBuffer[kNumCombs];
98 mAllpassBuffers = new SampleBuffer[kNumAllpasses];
99
100 // create buffers and combs
101 for (i = 0; i < kNumCombs; i++) {
102 bufferSize = kCombBufferSizes[i];
103 bufferPtr = new sample[bufferSize];
104 for (j = 0; j < bufferSize; j++)
105 bufferPtr[j] = 0.0f;
106 mCombBuffers[i] = bufferPtr;
107 combFilter = new Comb();
108 combFilter->setBuffer(bufferPtr, bufferSize);
109 mCombFilters.push_back(combFilter);
110 }
111 // create buffers and allpasses
112 for (i = 0; i < kNumAllpasses; i++) {
113 bufferSize = kAllpassBufferSizes[i];
114 bufferPtr = new sample[bufferSize];
115 for (j = 0; j < bufferSize; j++)
116 bufferPtr[j] = 0.0f;
117 mAllpassBuffers[i]= bufferPtr;
118 allpassFilter = new FAllpass();
119 allpassFilter->setBuffer(bufferPtr, bufferSize);
120 allpassFilter->setFeedback(0.5f);
121 mAllpassFilters.push_back(allpassFilter);
122 }
123 // Set default values
124 setWetLevel(kInitialWet);
125 setDryLevel(kInitialDry);
126 setRoomSize(kInitialRoom);
127 setDampening(kInitialDamp);
128 setWidth(kInitialWidth);
129 mGain = kFixedGain;
130 updateParameters();
131 }
132
133 void Freeverb::updateParameters() {
134 for (std::vector<Comb*>::iterator iComb = mCombFilters.begin();
135 iComb != mCombFilters.end(); ++iComb) {
136 (*iComb)->setFeedback(mRoomSize);
137 (*iComb)->setDamp(mDampening);
138 }
139 }
140
141 float Freeverb::roomSize() { return mRoomSize; }
142
143 void Freeverb::setRoomSize(float size) {
144 mRoomSize = size * kScaleRoom + kOffsetRoom;
145 updateParameters();
146 }
147
148 float Freeverb::dampening() { return (mDampening * 100.0f) / kScaleDamp; }
149
150 /// The "damp" parameter can be thought as setting the material of the room walls.
151
152 void Freeverb::setDampening(float damp) {
153 mDampening = (damp * 0.01f) * kScaleDamp;
154 updateParameters();
155 }
156
157 float Freeverb::wetLevel() { return mWetLevel; }
158
159 void Freeverb::setWetLevel(float level) {
160 mWetLevel = level;
161 updateParameters();
162 }
163
164 float Freeverb::dryLevel() { return mDryLevel; }
165
166 /// Amount of the original "dry" signal in the output.
167
168 void Freeverb::setDryLevel(float level) { mDryLevel = level; }
169
170 float Freeverb::width() { return (mWidth*100.0f); }
171
172 void Freeverb::setWidth(float twidth) {
173 mWidth = (twidth*0.01f);
174 updateParameters();
175 }
176
177 // Do the work
178
179 void Freeverb::nextBuffer(Buffer &outputBuffer, unsigned outBufNum) throw (CException) {
180 unsigned numFrames = outputBuffer.mNumFrames;
181 sample * fp = outputBuffer.buffer(outBufNum);
182 this->pullInput(outputBuffer);
183 sample * inputBuf = mInputPtr;
184 float out, input;
185 unsigned i;
186 #ifdef CSL_DEBUG
187 logMsg("Freeverb nextBuffer");
188 #endif
189 for (i = 0; i < numFrames; i++) {
190 out = 0;
191 input = inputBuf[i] * mGain;
192 // Accumulate comb filters in parallel
193 std::vector<Comb*>::iterator iComb = mCombFilters.begin();
194 for (; iComb != mCombFilters.end(); ++iComb)
195 out += (*iComb)->process(input);
196 // Feed through allpasses in series
197 std::vector<FAllpass*>::iterator iAllpass = mAllpassFilters.begin();
198 for (; iAllpass != mAllpassFilters.end(); ++iAllpass)
199 out = (*iAllpass)->process(out);
200 *fp++ = out * mWetLevel + inputBuf[i] * mDryLevel; // Calculate output REPLACING anything already there
201 }
202 }
203
204 //// Stereoverb ////////////////////////////////
205
206 // Constructor sets up splitter/joiner network
207
208 Stereoverb::Stereoverb(UnitGenerator &input) {
209 split = new Splitter(input);
210
211 leftRev = new Freeverb(* split); // 2 mono reverbs
212 leftRev->setWetLevel(kInitialWet);
213 leftRev->setDryLevel(kInitialWet);
214 leftRev->setRoomSize(kInitialRoom);
215
216 rightRev = new Freeverb(* split);
217 rightRev->setWetLevel(kInitialWet);
218 rightRev->setDryLevel(kInitialWet);
219 rightRev->setRoomSize(kInitialRoom);
220
221 join = new Joiner (* leftRev, * rightRev); // mono-to-stereo joiner
222 }
223
224 Stereoverb::~Stereoverb() {
225 delete split;
226 delete leftRev;
227 delete rightRev;
228 delete join;
229 }
230
231 bool Stereoverb::isActive() {
232 return(split->isActive());
233 }
234
235 void Stereoverb::setRoomSize(float size) {
236 leftRev->setRoomSize(size);
237 rightRev->setRoomSize(size);
238 }
239
240 void Stereoverb::setDampening(float damp) {
241 leftRev->setDampening(damp);
242 rightRev->setDampening(damp);
243 }
244
245 void Stereoverb::setWetLevel(float level) {
246 leftRev->setWetLevel(level);
247 rightRev->setWetLevel(level);
248 }
249
250 void Stereoverb::setDryLevel(float level) {
251 leftRev->setDryLevel(level);
252 rightRev->setDryLevel(level);
253 }
254
255 void Stereoverb::setWidth(float width) {
256 leftRev->setWidth(width);
257 rightRev->setWidth(width);
258 }
259
260 // next_buffer work-horse method
261
262 void Stereoverb::nextBuffer(Buffer &outputBuffer) throw (CException) {
263 join->nextBuffer(outputBuffer);
264 }