zynaddsubfx

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

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 }