Chorus.cpp (12837B)
1 /* 2 ZynAddSubFX - a software synthesizer 3 4 Chorus.cpp - Chorus and Flange effects 5 Copyright (C) 2002-2005 Nasca Octavian Paul 6 Author: Nasca Octavian Paul 7 8 This program is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License 10 as published by the Free Software Foundation; either version 2 11 of the License, or (at your option) any later version. 12 */ 13 14 #include <cmath> 15 #include <rtosc/ports.h> 16 #include <rtosc/port-sugar.h> 17 #include "../Misc/Allocator.h" 18 #include "Chorus.h" 19 #include <iostream> 20 using namespace std; 21 22 namespace zyn { 23 24 constexpr float PHASE_120 = 0.33333333f; 25 constexpr float PHASE_180 = 0.5f; 26 constexpr float PHASE_240 = 0.66666666f; 27 28 #define rObject Chorus 29 #define rBegin [](const char *msg, rtosc::RtData &d) { 30 #define rEnd } 31 32 rtosc::Ports Chorus::ports = { 33 {"preset::i", rProp(parameter) 34 rOptions(Chorus1, Chorus2, Chorus3, Celeste1, Celeste2, 35 Flange1, Flange2, Flange3, Flange4, Flange5, 36 Triple, Dual) 37 rProp(alias) 38 rDefault(0) 39 rDoc("Instrument Presets"), 0, 40 rBegin; 41 rObject *o = (rObject*)d.obj; 42 if(rtosc_narguments(msg)) 43 o->setpreset(rtosc_argument(msg, 0).i); 44 else 45 d.reply(d.loc, "i", o->Ppreset); 46 47 rEnd}, 48 //Pvolume/Ppanning are common 49 rEffParVol(rDefaultDepends(preset), rDefault(64), rPreset(10, 127), rPreset(11, 127)), 50 rEffParPan(), 51 rEffPar(Pfreq, 2, rShort("freq"), 52 rPresets(50, 45, 29, 26, 29, 57, 33, 53, 40, 55, 68, 55), 53 "Effect Frequency"), 54 rEffPar(Pfreqrnd, 3, rShort("rand"), 55 rPreset(4, 117) rPreset(6, 34) rPreset(7, 34) rPreset(9, 105) 56 rPreset(10, 25) rPreset(11, 25) 57 rDefault(0), "Frequency Randomness"), 58 rEffParOpt(PLFOtype, 4, rShort("shape"), 59 rOptions(sine, tri), 60 rPresets(sine, sine, tri, sine, sine, sine, tri, tri, tri, sine, tri, tri), 61 "LFO Shape"), 62 rEffPar(PStereo, 5, rShort("stereo"), 63 rPresets(90, 98, 42, 42, 50, 60, 40, 94, 62, 24, 24, 24), "Stereo Mode"), 64 rEffPar(Pdepth, 6, rShort("depth"), 65 rPresets(40, 56, 97, 115, 115, 23, 35, 35, 12, 39, 35, 32), "LFO Depth"), 66 rEffPar(Pdelay, 7, rShort("delay"), 67 rPresets(85, 90, 95, 18, 9, 3, 3, 3, 19, 19, 55, 55), "Delay"), 68 rEffPar(Pfeedback,8, rShort("fb"), 69 rPresets(64, 64, 90, 90, 31, 62, 109, 54, 97, 17, 64, 80), "Feedback"), 70 rEffPar(Plrcross, 9, rShort("l/r"), rPresets(119, 19, 127, 127, 127), 71 rDefault(0), "Left/Right Crossover"), 72 rEffParOpt(Pflangemode, 10, rShort("mode"), rDefault(CHORUS), rOptions(CHORUS_MODES), 73 rPreset(10, TRIPLE), rPreset(11, DUAL), 74 "Chorus Mode"), 75 rEffParTF(Poutsub, 11, rShort("sub"), 76 rPreset(4, true), rPreset(7, true), rPreset(9, true), 77 rDefault(false), "Output Subtraction"), 78 }; 79 #undef rBegin 80 #undef rEnd 81 #undef rObject 82 83 Chorus::Chorus(EffectParams pars) 84 :Effect(pars), 85 lfo(pars.srate, pars.bufsize), 86 maxdelay((int)(MAX_CHORUS_DELAY / 1000.0f * samplerate_f)), 87 delaySample(memory.valloc<float>(maxdelay), memory.valloc<float>(maxdelay)) 88 { 89 dlk = 0; 90 drk = 0; 91 setpreset(Ppreset); 92 changepar(1, 64); 93 lfo.effectlfoout(&lfol, &lfor); 94 dlNew = getdelay(lfol); 95 drNew = getdelay(lfor); 96 cleanup(); 97 } 98 99 Chorus::~Chorus() 100 { 101 memory.devalloc(delaySample.l); 102 memory.devalloc(delaySample.r); 103 } 104 105 //get the delay value in samples; xlfo is the current lfo value 106 float Chorus::getdelay(float xlfo) 107 { 108 float result = 109 (Pflangemode==FLANGE) ? 0 : (delay + xlfo * depth) * samplerate_f; 110 111 //check if delay is too big (caused by bad setdelay() and setdepth() 112 if((result + 0.5f) >= maxdelay) { 113 cerr 114 << 115 "WARNING: Chorus.cpp::getdelay(..) too big delay (see setdelay and setdepth funcs.)" 116 << endl; 117 result = maxdelay - 1.0f; 118 } 119 return result; 120 } 121 122 // sample 123 124 inline float Chorus::getSample(float* delayline, float mdel, int dk) 125 { 126 float samplePos = dk - mdel + float(maxdelay * 2); //where should I get the sample from 127 return cinterpolate(delayline, maxdelay, samplePos); 128 129 } 130 131 //Apply the effect 132 void Chorus::out(const Stereo<float *> &input) 133 { 134 // store old delay value for linear interpolation 135 dlHist = dlNew; 136 drHist = drNew; 137 // calculate new lfo values 138 lfo.effectlfoout(&lfol, &lfor); 139 // calculate new delay values 140 dlNew = getdelay(lfol); 141 drNew = getdelay(lfor); 142 float fbComp = fb; 143 if (Pflangemode == DUAL) // ensemble mode 144 { 145 // same for second member for ensemble mode with 180° phase offset 146 dlHist2 = dlNew2; 147 drHist2 = drNew2; 148 lfo.effectlfoout(&lfol, &lfor, PHASE_180); 149 dlNew2 = getdelay(lfol); 150 drNew2 = getdelay(lfor); 151 fbComp /= 2.0f; 152 } 153 154 if (Pflangemode == TRIPLE) // ensemble mode 155 { 156 // same for second member for ensemble mode with 120° phase offset 157 dlHist2 = dlNew2; 158 drHist2 = drNew2; 159 lfo.effectlfoout(&lfol, &lfor, PHASE_120); 160 dlNew2 = getdelay(lfol); 161 drNew2 = getdelay(lfor); 162 163 // same for third member for ensemble mode with 240° phase offset 164 dlHist3 = dlNew3; 165 drHist3 = drNew3; 166 lfo.effectlfoout(&lfol, &lfor, PHASE_240); 167 dlNew3 = getdelay(lfol); 168 drNew3 = getdelay(lfor); 169 // reduce amplitude to match single phase modes 170 // 0.85 * fbComp / 3 171 fbComp /= 3.53f; 172 } 173 174 for(int i = 0; i < buffersize; ++i) { 175 float inL = input.l[i]; 176 float inR = input.r[i]; 177 //LRcross 178 Stereo<float> tmpc(inL, inR); 179 inL = tmpc.l * (1.0f - lrcross) + tmpc.r * lrcross; 180 inR = tmpc.r * (1.0f - lrcross) + tmpc.l * lrcross; 181 182 //Left channel 183 // reset output accumulator 184 output = 0.0f; 185 // increase delay line writing position and handle turnaround 186 if(++dlk >= maxdelay) 187 dlk = 0; 188 // linear interpolate from old to new value over length of the buffer 189 float dl = (dlHist * (buffersize - i) + dlNew * i) / buffersize_f; 190 // get sample with that delay from delay line and add to output accumulator 191 output += getSample(delaySample.l, dl, dlk); 192 switch (Pflangemode) { 193 case DUAL: 194 // calculate and apply delay for second ensemble member 195 dl = (dlHist2 * (buffersize - i) + dlNew2 * i) / buffersize_f; 196 output += getSample(delaySample.l, dl, dlk); 197 break; 198 case TRIPLE: 199 // calculate and apply delay for second ensemble member 200 dl = (dlHist2 * (buffersize - i) + dlNew2 * i) / buffersize_f; 201 output += getSample(delaySample.l, dl, dlk); 202 // same for third ensemble member 203 dl = (dlHist3 * (buffersize - i) + dlNew3 * i) / buffersize_f; 204 output += getSample(delaySample.l, dl, dlk); 205 break; 206 default: 207 // nothing to do for standard chorus 208 break; 209 } 210 // store current input + feedback to delay line at writing position 211 delaySample.l[dlk] = inL + output * fbComp; 212 // write output to output interface 213 efxoutl[i] = output; 214 215 //Right channel 216 output = 0.0f; 217 if(++drk >= maxdelay) 218 drk = 0; 219 float dr = (drHist * (buffersize - i) + drNew * i) / buffersize_f; 220 output += getSample(delaySample.r, dr, drk); 221 switch (Pflangemode) { 222 case DUAL: 223 // calculate and apply delay for second ensemble member 224 dr = (drHist2 * (buffersize - i) + drNew2 * i) / buffersize_f; 225 output += getSample(delaySample.r, dr, drk); 226 break; 227 case TRIPLE: 228 // calculate and apply delay for second ensemble member 229 dr = (drHist2 * (buffersize - i) + drNew2 * i) / buffersize_f; 230 output += getSample(delaySample.r, dr, drk); 231 // same for third ensemble member 232 dr = (drHist3 * (buffersize - i) + drNew3 * i) / buffersize_f; 233 output += getSample(delaySample.r, dr, drk); 234 // reduce amplitude to match single phase modes 235 output *= 0.85f; 236 break; 237 default: 238 // nothing to do for standard chorus 239 break; 240 } 241 242 delaySample.r[drk] = inR + output * fbComp; 243 efxoutr[i] = output; 244 } 245 246 if(Poutsub) 247 for(int i = 0; i < buffersize; ++i) { 248 efxoutl[i] *= -1.0f; 249 efxoutr[i] *= -1.0f; 250 } 251 252 for(int i = 0; i < buffersize; ++i) { 253 efxoutl[i] *= pangainL; 254 efxoutr[i] *= pangainR; 255 } 256 } 257 258 //Cleanup the effect 259 void Chorus::cleanup(void) 260 { 261 memset(delaySample.l, 0, maxdelay * sizeof(float)); 262 memset(delaySample.r, 0, maxdelay * sizeof(float)); 263 } 264 265 //Parameter control 266 void Chorus::setdepth(unsigned char _Pdepth) 267 { 268 Pdepth = _Pdepth; 269 depth = (powf(8.0f, (Pdepth / 127.0f) * 2.0f) - 1.0f) / 1000.0f; //seconds 270 } 271 272 void Chorus::setdelay(unsigned char _Pdelay) 273 { 274 Pdelay = _Pdelay; 275 delay = (powf(10.0f, (Pdelay / 127.0f) * 2.0f) - 1.0f) / 1000.0f; //seconds 276 } 277 278 void Chorus::setfb(unsigned char _Pfb) 279 { 280 Pfb = _Pfb; 281 fb = (Pfb - 64.0f) / 64.1f; 282 } 283 284 void Chorus::setvolume(unsigned char _Pvolume) 285 { 286 Pvolume = _Pvolume; 287 outvolume = Pvolume / 127.0f; 288 volume = (!insertion) ? 1.0f : outvolume; 289 } 290 291 unsigned char Chorus::getpresetpar(unsigned char npreset, unsigned int npar) 292 { 293 #define PRESET_SIZE 12 294 #define NUM_PRESETS 12 295 static const unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { 296 //Chorus1 297 {64, 64, 50, 0, 0, 90, 40, 85, 64, 119, 0, 0}, 298 //Chorus2 299 {64, 64, 45, 0, 0, 98, 56, 90, 64, 19, 0, 0}, 300 //Chorus3 301 {64, 64, 29, 0, 1, 42, 97, 95, 90, 127, 0, 0}, 302 //Celeste1 303 {64, 64, 26, 0, 0, 42, 115, 18, 90, 127, 0, 0}, 304 //Celeste2 305 {64, 64, 29, 117, 0, 50, 115, 9, 31, 127, 0, 1}, 306 //Flange1 307 {64, 64, 57, 0, 0, 60, 23, 3, 62, 0, 0, 0}, 308 //Flange2 309 {64, 64, 33, 34, 1, 40, 35, 3, 109, 0, 0, 0}, 310 //Flange3 311 {64, 64, 53, 34, 1, 94, 35, 3, 54, 0, 0, 1}, 312 //Flange4 313 {64, 64, 40, 0, 1, 62, 12, 19, 97, 0, 0, 0}, 314 //Flange5 315 {64, 64, 55, 105, 0, 24, 39, 19, 17, 0, 0, 1}, 316 //Ensemble 317 {127, 64, 68, 25, 1, 24, 35, 55, 64, 0, TRIPLE, 0}, 318 //Dual 319 {127, 64, 55, 25, 1, 24, 32, 55, 80, 0, DUAL, 0} 320 }; 321 if(npreset < NUM_PRESETS && npar < PRESET_SIZE) { 322 return presets[npreset][npar]; 323 } 324 return 0; 325 } 326 327 void Chorus::setpreset(unsigned char npreset) 328 { 329 if(npreset >= NUM_PRESETS) 330 npreset = NUM_PRESETS - 1; 331 for(int n = 0; n != 128; n++) 332 changepar(n, getpresetpar(npreset, n)); 333 Ppreset = npreset; 334 } 335 336 void Chorus::changepar(int npar, unsigned char value) 337 { 338 switch(npar) { 339 case 0: 340 setvolume(value); 341 break; 342 case 1: 343 setpanning(value); 344 break; 345 case 2: 346 lfo.Pfreq = value; 347 lfo.updateparams(); 348 break; 349 case 3: 350 lfo.Prandomness = value; 351 lfo.updateparams(); 352 break; 353 case 4: 354 lfo.PLFOtype = value; 355 lfo.updateparams(); 356 break; 357 case 5: 358 lfo.Pstereo = value; 359 lfo.updateparams(); 360 break; 361 case 6: 362 setdepth(value); 363 break; 364 case 7: 365 setdelay(value); 366 break; 367 case 8: 368 setfb(value); 369 break; 370 case 9: 371 setlrcross(value); 372 break; 373 case 10: 374 lfo.updateparams(); 375 Pflangemode = (value > 3) ? 3 : value; 376 break; 377 case 11: 378 Poutsub = (value > 1) ? 1 : value; 379 break; 380 } 381 } 382 383 unsigned char Chorus::getpar(int npar) const 384 { 385 switch(npar) { 386 case 0: return Pvolume; 387 case 1: return Ppanning; 388 case 2: return lfo.Pfreq; 389 case 3: return lfo.Prandomness; 390 case 4: return lfo.PLFOtype; 391 case 5: return lfo.Pstereo; 392 case 6: return Pdepth; 393 case 7: return Pdelay; 394 case 8: return Pfb; 395 case 9: return Plrcross; 396 case 10: return Pflangemode; 397 case 11: return Poutsub; 398 default: return 0; 399 } 400 } 401 402 }