DynamicFilter.cpp (12495B)
1 /* 2 ZynAddSubFX - a software synthesizer 3 4 DynamicFilter.cpp - "WahWah" effect and others 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 <cassert> 15 #include <cmath> 16 #include <iostream> 17 #include "DynamicFilter.h" 18 #include "../DSP/Filter.h" 19 #include "../Misc/Allocator.h" 20 #include <rtosc/ports.h> 21 #include <rtosc/port-sugar.h> 22 23 namespace zyn { 24 25 #define rObject DynamicFilter 26 #define rBegin [](const char *msg, rtosc::RtData &d) { 27 #define rEnd } 28 29 rtosc::Ports DynamicFilter::ports = { 30 {"preset::i", rOptions(WahWah, AutoWah, Sweep, VocalMorph1, VocalMorph2) 31 rDefault(0) 32 rDoc("Instrument Presets"), 0, 33 rBegin; 34 rObject *o = (rObject*)d.obj; 35 if(rtosc_narguments(msg)) 36 o->setpreset(rtosc_argument(msg, 0).i); 37 else 38 d.reply(d.loc, "i", o->Ppreset); 39 rEnd}, 40 rPresetForVolume, 41 rEffParVol(rDefaultDepends(presetOfVolume), 42 rDefault(55), rPreset(2, 50), rPreset(4, 63), 43 rPresetsAt(16, 110, 110, 100, 110, 127)), 44 rEffParPan(), 45 rEffPar(Pfreq, 2, rShort("freq"), rPresets(80, 70, 30, 80, 50), 46 "Effect Frequency"), 47 rEffPar(Pfreqrnd, 3, rShort("rand"), rDefault(0), 48 "Frequency Randomness"), 49 rEffParOpt(PLFOtype, 4, rShort("shape"), rOptions(sin, tri), 50 rDefault(sin), "LFO Shape"), 51 rEffPar(PStereo, 5, rShort("stereo"), rPresets(64, 80, 50, 64, 96), 52 "Stereo Mode"), 53 rEffPar(Pdepth, 6, rShort("depth"), rPresets(0, 70, 80, 0, 64), 54 "LFO Depth"), 55 rEffPar(Pampsns, 7, rShort("sense"), 56 rPreset(0, 90) rPreset(3, 64) rDefault(0), 57 "how the filter varies according to the input amplitude"), 58 rEffPar(Pampsnsinv, 8, rShort("sns.inv"), rDefault(0), "Sense Inversion"), 59 rEffPar(Pampsmooth, 9, rShort("smooth"), rDefault(60), 60 "how smooth the input amplitude changes the filter"), 61 }; 62 #undef rBegin 63 #undef rEnd 64 #undef rObject 65 66 DynamicFilter::DynamicFilter(EffectParams pars) 67 :Effect(pars), 68 lfo(pars.srate, pars.bufsize), 69 Pvolume(110), 70 Pdepth(0), 71 Pampsns(90), 72 Pampsnsinv(0), 73 Pampsmooth(60), 74 filterl(NULL), 75 filterr(NULL) 76 { 77 filterpars = pars.filterpars; 78 setpreset(Ppreset, pars.filterprotect); 79 cleanup(); 80 } 81 82 DynamicFilter::~DynamicFilter() 83 { 84 memory.dealloc(filterl); 85 memory.dealloc(filterr); 86 } 87 88 89 // Apply the effect 90 void DynamicFilter::out(const Stereo<float *> &smp) 91 { 92 if(filterpars->changed) { 93 filterpars->changed = false; 94 cleanup(); 95 } 96 97 float lfol, lfor; 98 lfo.effectlfoout(&lfol, &lfor); 99 lfol *= depth * 5.0f; 100 lfor *= depth * 5.0f; 101 const float freq = filterpars->getfreq(); 102 const float q = filterpars->getq(); 103 104 for(int i = 0; i < buffersize; ++i) { 105 efxoutl[i] = smp.l[i]; 106 efxoutr[i] = smp.r[i]; 107 108 const float x = (fabsf(smp.l[i]) + fabsf(smp.r[i])) * 0.5f; 109 ms1 = ms1 * (1.0f - ampsmooth) + x * ampsmooth + 1e-10; 110 } 111 112 const float ampsmooth2 = powf(ampsmooth, 0.2f) * 0.3f; 113 ms2 = ms2 * (1.0f - ampsmooth2) + ms1 * ampsmooth2; 114 ms3 = ms3 * (1.0f - ampsmooth2) + ms2 * ampsmooth2; 115 ms4 = ms4 * (1.0f - ampsmooth2) + ms3 * ampsmooth2; 116 const float rms = (sqrtf(ms4)) * ampsns; 117 118 const float frl = Filter::getrealfreq(freq + lfol + rms); 119 const float frr = Filter::getrealfreq(freq + lfor + rms); 120 121 filterl->setfreq_and_q(frl, q); 122 filterr->setfreq_and_q(frr, q); 123 124 filterl->filterout(efxoutl); 125 filterr->filterout(efxoutr); 126 127 //panning 128 for(int i = 0; i < buffersize; ++i) { 129 efxoutl[i] *= pangainL; 130 efxoutr[i] *= pangainR; 131 } 132 } 133 134 // Cleanup the effect 135 void DynamicFilter::cleanup(void) 136 { 137 reinitfilter(); 138 ms1 = ms2 = ms3 = ms4 = 0.0f; 139 } 140 141 142 //Parameter control 143 void DynamicFilter::setdepth(unsigned char _Pdepth) 144 { 145 Pdepth = _Pdepth; 146 depth = powf(Pdepth / 127.0f, 2.0f); 147 } 148 149 150 void DynamicFilter::setvolume(unsigned char _Pvolume) 151 { 152 Pvolume = _Pvolume; 153 outvolume = Pvolume / 127.0f; 154 if(!insertion) 155 volume = 1.0f; 156 else 157 volume = outvolume; 158 } 159 160 void DynamicFilter::setampsns(unsigned char _Pampsns) 161 { 162 Pampsns = _Pampsns; 163 ampsns = powf(Pampsns / 127.0f, 2.5f) * 10.0f; 164 if(Pampsnsinv) 165 ampsns = -ampsns; 166 ampsmooth = expf(-Pampsmooth / 127.0f * 10.0f) * 0.99f; 167 } 168 169 void DynamicFilter::reinitfilter(void) 170 { 171 memory.dealloc(filterl); 172 memory.dealloc(filterr); 173 174 try { 175 filterl = Filter::generate(memory, filterpars, samplerate, buffersize); 176 } catch(std::bad_alloc& ba) { 177 std::cerr << "failed to generate left filter for dynamic filter: " << ba.what() << std::endl; 178 } 179 180 try { 181 filterr = Filter::generate(memory, filterpars, samplerate, buffersize); 182 } catch(std::bad_alloc& ba) { 183 std::cerr << "failed to generate right filter for dynamic filter: " << ba.what() << std::endl; 184 } 185 } 186 187 void DynamicFilter::setfilterpreset(unsigned char npreset) 188 { 189 filterpars->defaults(); 190 filterpars->updateLoc(dynfilter_0 + npreset); 191 192 switch(npreset) { 193 case 0: 194 filterpars->Pcategory = 0; 195 filterpars->Ptype = 2; 196 filterpars->basefreq = FilterParams::basefreqFromOldPreq(45); 197 filterpars->baseq = FilterParams::baseqFromOldPq(64); 198 filterpars->Pstages = 1; 199 filterpars->gain = FilterParams::gainFromOldPgain(64); 200 break; 201 case 1: 202 filterpars->Pcategory = 2; 203 filterpars->Ptype = 0; 204 filterpars->basefreq = FilterParams::basefreqFromOldPreq(72); 205 filterpars->baseq = FilterParams::baseqFromOldPq(64); 206 filterpars->Pstages = 0; 207 filterpars->gain = FilterParams::gainFromOldPgain(64); 208 break; 209 case 2: 210 filterpars->Pcategory = 0; 211 filterpars->Ptype = 4; 212 filterpars->basefreq = FilterParams::basefreqFromOldPreq(64); 213 filterpars->baseq = FilterParams::baseqFromOldPq(64); 214 filterpars->Pstages = 2; 215 filterpars->gain = FilterParams::gainFromOldPgain(64); 216 break; 217 case 3: 218 filterpars->Pcategory = 1; 219 filterpars->Ptype = 0; 220 filterpars->basefreq = FilterParams::basefreqFromOldPreq(50); 221 filterpars->baseq = 222 #ifdef __clang__ 223 // rounding issues with clang, so we cannot use the function 224 0x1.d04b16p+2; 225 #else 226 FilterParams::baseqFromOldPq(70); 227 #endif 228 filterpars->Pstages = 1; 229 filterpars->gain = FilterParams::gainFromOldPgain(64); 230 231 filterpars->Psequencesize = 2; 232 // "I" 233 filterpars->Pvowels[0].formants[0].freq = 34; 234 filterpars->Pvowels[0].formants[0].amp = 127; 235 filterpars->Pvowels[0].formants[0].q = 64; 236 filterpars->Pvowels[0].formants[1].freq = 99; 237 filterpars->Pvowels[0].formants[1].amp = 122; 238 filterpars->Pvowels[0].formants[1].q = 64; 239 filterpars->Pvowels[0].formants[2].freq = 108; 240 filterpars->Pvowels[0].formants[2].amp = 112; 241 filterpars->Pvowels[0].formants[2].q = 64; 242 // "A" 243 filterpars->Pvowels[1].formants[0].freq = 61; 244 filterpars->Pvowels[1].formants[0].amp = 127; 245 filterpars->Pvowels[1].formants[0].q = 64; 246 filterpars->Pvowels[1].formants[1].freq = 71; 247 filterpars->Pvowels[1].formants[1].amp = 121; 248 filterpars->Pvowels[1].formants[1].q = 64; 249 filterpars->Pvowels[1].formants[2].freq = 99; 250 filterpars->Pvowels[1].formants[2].amp = 117; 251 filterpars->Pvowels[1].formants[2].q = 64; 252 break; 253 case 4: 254 filterpars->Pcategory = 1; 255 filterpars->Ptype = 0; 256 filterpars->basefreq = FilterParams::basefreqFromOldPreq(64); 257 filterpars->baseq = 258 #ifdef __clang__ 259 // rounding issues with clang, so we cannot use the function 260 0x1.d04b16p+2; 261 #else 262 FilterParams::baseqFromOldPq(70); 263 #endif 264 filterpars->Pstages = 1; 265 filterpars->gain = FilterParams::gainFromOldPgain(64); 266 267 filterpars->Psequencesize = 2; 268 filterpars->Pnumformants = 2; 269 filterpars->Pvowelclearness = 0; 270 271 filterpars->Pvowels[0].formants[0].freq = 70; 272 filterpars->Pvowels[0].formants[0].amp = 127; 273 filterpars->Pvowels[0].formants[0].q = 64; 274 filterpars->Pvowels[0].formants[1].freq = 80; 275 filterpars->Pvowels[0].formants[1].amp = 122; 276 filterpars->Pvowels[0].formants[1].q = 64; 277 278 filterpars->Pvowels[1].formants[0].freq = 20; 279 filterpars->Pvowels[1].formants[0].amp = 127; 280 filterpars->Pvowels[1].formants[0].q = 64; 281 filterpars->Pvowels[1].formants[1].freq = 100; 282 filterpars->Pvowels[1].formants[1].amp = 121; 283 filterpars->Pvowels[1].formants[1].q = 64; 284 break; 285 } 286 287 // for (int i=0;i<5;i++){ 288 // printf("freq=%d amp=%d q=%d\n",filterpars->Pvowels[0].formants[i].freq,filterpars->Pvowels[0].formants[i].amp,filterpars->Pvowels[0].formants[i].q); 289 // }; 290 reinitfilter(); 291 } 292 293 unsigned char DynamicFilter::getpresetpar(unsigned char npreset, unsigned int npar) 294 { 295 #define PRESET_SIZE 10 296 #define NUM_PRESETS 5 297 static const unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { 298 //WahWah 299 {110, 64, 80, 0, 0, 64, 0, 90, 0, 60}, 300 //AutoWah 301 {110, 64, 70, 0, 0, 80, 70, 0, 0, 60}, 302 //Sweep 303 {100, 64, 30, 0, 0, 50, 80, 0, 0, 60}, 304 //VocalMorph1 305 {110, 64, 80, 0, 0, 64, 0, 64, 0, 60}, 306 //VocalMorph2 307 {127, 64, 50, 0, 0, 96, 64, 0, 0, 60} 308 }; 309 if(npreset < NUM_PRESETS && npar < PRESET_SIZE) { 310 if(npar == 0 && insertion == 0) { 311 /* lower the volume if this is system effect */ 312 return presets[npreset][npar] / 2; 313 } 314 return presets[npreset][npar]; 315 } 316 return 0; 317 } 318 319 void DynamicFilter::setpreset(unsigned char npreset, bool protect) 320 { 321 if(npreset >= NUM_PRESETS) 322 npreset = NUM_PRESETS - 1; 323 for(int n = 0; n != 128; n++) 324 changepar(n, getpresetpar(npreset, n)); 325 Ppreset = npreset; 326 if(!protect) 327 setfilterpreset(npreset); 328 } 329 330 void DynamicFilter::changepar(int npar, unsigned char value) 331 { 332 switch(npar) { 333 case 0: 334 setvolume(value); 335 break; 336 case 1: 337 setpanning(value); 338 break; 339 case 2: 340 lfo.Pfreq = value; 341 lfo.updateparams(); 342 break; 343 case 3: 344 lfo.Prandomness = value; 345 lfo.updateparams(); 346 break; 347 case 4: 348 lfo.PLFOtype = value; 349 lfo.updateparams(); 350 break; 351 case 5: 352 lfo.Pstereo = value; 353 lfo.updateparams(); 354 break; 355 case 6: 356 setdepth(value); 357 break; 358 case 7: 359 setampsns(value); 360 break; 361 case 8: 362 Pampsnsinv = value; 363 setampsns(Pampsns); 364 break; 365 case 9: 366 Pampsmooth = value; 367 setampsns(Pampsns); 368 break; 369 } 370 } 371 372 unsigned char DynamicFilter::getpar(int npar) const 373 { 374 switch(npar) { 375 case 0: return Pvolume; 376 case 1: return Ppanning; 377 case 2: return lfo.Pfreq; 378 case 3: return lfo.Prandomness; 379 case 4: return lfo.PLFOtype; 380 case 5: return lfo.Pstereo; 381 case 6: return Pdepth; 382 case 7: return Pampsns; 383 case 8: return Pampsnsinv; 384 case 9: return Pampsmooth; 385 default: return 0; 386 } 387 } 388 389 }