zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

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 }