zynaddsubfx

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

Phaser.cpp (16073B)


      1 /*
      2   ZynAddSubFX - a software synthesizer
      3 
      4   Phaser.cpp - Phasing and Approximate digital model of an analog JFET phaser.
      5                Analog modeling implemented by Ryan Billing aka Transmogrifox.
      6                DSP analog modeling theory & practice largely influenced by
      7                various CCRMA publications, particularly works by Julius O. Smith.
      8   Copyright (C) 2002-2005 Nasca Octavian Paul
      9   Copyright (C) 2009-2010 Ryan Billing
     10   Copyright (C) 2010-2010 Mark McCurry
     11 
     12   This program is free software; you can redistribute it and/or
     13   modify it under the terms of the GNU General Public License
     14   as published by the Free Software Foundation; either version 2
     15   of the License, or (at your option) any later version.
     16 */
     17 
     18 #include <cmath>
     19 #include <algorithm>
     20 #include <rtosc/ports.h>
     21 #include <rtosc/port-sugar.h>
     22 #include "../Misc/Allocator.h"
     23 #include "Phaser.h"
     24 using namespace std;
     25 
     26 namespace zyn {
     27 
     28 #define rObject Phaser
     29 #define rBegin [](const char *msg, rtosc::RtData &d) {
     30 #define rEnd }
     31 
     32 #define ucharParamCb(pname) rBegin \
     33         rObject &p = *(rObject*)d.obj; \
     34         if(rtosc_narguments(msg)) \
     35             p.set##pname(rtosc_argument(msg, 0).i); \
     36         else \
     37             d.reply(d.loc, "i", p.P##pname); \
     38         rEnd
     39 #define rParamPhaser(name, ...) \
     40   {STRINGIFY(P##name) "::i",  rProp(parameter) rMap(min, 0) rMap(max, 127) \
     41    rDefaultDepends(preset) DOC(__VA_ARGS__), NULL, ucharParamCb(name)}
     42 
     43 rtosc::Ports Phaser::ports = {
     44     {"preset::i", rProp(parameter)
     45                   rOptions(Phaser 1, Phaser 2, Phaser 3, Phaser 4,
     46                            Phaser 5, Phaser 6,
     47                            APhaser 1, APhaser 2, APhaser 3, APhaser 4,
     48                            APhaser 5, APhaser 6)
     49                   rProp(alias)
     50                   rDefault(0)
     51                   rDoc("Instrument Presets"), 0,
     52                   rBegin;
     53                   rObject *o = (rObject*)d.obj;
     54                   if(rtosc_narguments(msg))
     55                       o->setpreset(rtosc_argument(msg, 0).i);
     56                   else
     57                       d.reply(d.loc, "i", o->Ppreset);
     58                   rEnd},
     59     rEffParVol(rDefaultDepends(preset),
     60             rDefault(64), rPreset(3, 39), rPreset(10, 25)),
     61     rEffParPan(),
     62     rEffPar(lfo.Pfreq,       2, rShort("freq"),
     63             rPresets(36, 35, 31, 22, 20, 53, 14, 14, 9, 14, 127, 1),
     64             "LFO frequency"),
     65     rEffPar(lfo.Prandomness, 3, rShort("rnd."),
     66             rPreset(5, 100), rPreset(7, 5), rPresetsAt(9, 10, 10, 10),
     67             rDefault(0), "LFO randomness"),
     68     rEffParOpt(lfo.PLFOtype,    4, rShort("type"),
     69             rPreset(4, tri), rPresetsAt(6, tri, tri), rPreset(11, tri),
     70             rDefault(sine),
     71             rOptions(sine, tri), "lfo shape"),
     72     rEffPar(lfo.Pstereo,     5, rShort("stereo"),
     73             rPresetsAt(1, 88, 66, 66, 110, 58), rDefault(64),
     74             "Left/right channel phase shift"),
     75     rEffPar(Pdepth,          6, rShort("depth"), rLinear(0, 127),
     76             rPresets(110, 40, 68, 67, 67, 37, 64, 70, 60, 45, 25, 70),
     77             "LFP depth"),
     78     rEffPar(Pfb,             7, rShort("fb"),
     79             rPresets(64, 64, 107, 10, 78, 78, 40, 40, 40, 80, 16, 40),
     80             "Feedback"),
     81     rEffPar(Pstages,         8, rLinear(1,12), rShort("stages"),
     82             rPresets(1, 3, 2, 5, 10, 3, 4, 6, 8, 7, 8, 12),
     83             ""),
     84     rParamPhaser(lrcross,       rShort("cross"),
     85             rPresetsAt(6, 10, 10, 10, 10, 100, 10) rDefault(0),
     86             "Channel routing"),
     87     rParamPhaser(offset,        rShort("off"),
     88             rPresetsAt(6, 10, 10, 10, 10, 100, 10) rDefault(0),
     89             "Offset"),
     90     rEffParTF(Poutsub,      10, rShort("sub"),
     91             rPreset(3, true), rPreset(9, true), rDefault(false),
     92             "Invert output"),
     93     rParamPhaser(phase,         rShort("phase"),
     94             rPresets(20, 20, 20, 20, 20, 20, 110, 110, 40, 110, 25, 110), ""),
     95     rParamPhaser(width,         rShort("width"),
     96             rPresets(20, 20, 20, 20, 20, 20, 110, 110, 40, 110, 25, 110), ""),
     97     rEffParTF(Phyper,       12, rShort("hyp."),
     98             rPresetsAt(6, true, true, false, true, false, true),
     99             rDefault(false), "Square the LFO"),
    100     rEffPar(Pdistortion,    13, rShort("distort"),
    101             rPresetsAt(6, 20, 20, 20, 20, 20, 20), rDefault(0),
    102             "Distortion"),
    103     rEffParTF(Panalog,      14, rShort("analog"),
    104             rPresetsAt(6, true, true, true, true, true, true), rDefault(false),
    105             "Use analog phaser"),
    106 };
    107 #undef rBegin
    108 #undef rEnd
    109 #undef rObject
    110 
    111 #define PHASER_LFO_SHAPE 2
    112 #define ONE_  0.99999f        // To prevent LFO ever reaching 1.0f for filter stability purposes
    113 #define ZERO_ 0.00001f        // Same idea as above.
    114 
    115 Phaser::Phaser(EffectParams pars)
    116     :Effect(pars), lfo(pars.srate, pars.bufsize), old(NULL), xn1(NULL),
    117       yn1(NULL), diff(0.0f), oldgain(0.0f), fb(0.0f)
    118 {
    119     analog_setup();
    120     setpreset(Ppreset);
    121     cleanup();
    122 }
    123 
    124 void Phaser::analog_setup()
    125 {
    126     //model mismatch between JFET devices
    127     offset[0]  = -0.2509303f;
    128     offset[1]  = 0.9408924f;
    129     offset[2]  = 0.998f;
    130     offset[3]  = -0.3486182f;
    131     offset[4]  = -0.2762545f;
    132     offset[5]  = -0.5215785f;
    133     offset[6]  = 0.2509303f;
    134     offset[7]  = -0.9408924f;
    135     offset[8]  = -0.998f;
    136     offset[9]  = 0.3486182f;
    137     offset[10] = 0.2762545f;
    138     offset[11] = 0.5215785f;
    139 
    140     barber = 0;  //Deactivate barber pole phasing by default
    141 
    142     mis       = 1.0f;
    143     Rmin      = 625.0f; // 2N5457 typical on resistance at Vgs = 0
    144     Rmax      = 22000.0f; // Resistor parallel to FET
    145     Rmx       = Rmin / Rmax;
    146     Rconst    = 1.0f + Rmx; // Handle parallel resistor relationship
    147     C         = 0.00000005f; // 50 nF
    148     CFs       = 2.0f * samplerate_f * C;
    149     invperiod = 1.0f / buffersize_f;
    150 }
    151 
    152 Phaser::~Phaser()
    153 {
    154     memory.devalloc(old.l);
    155     memory.devalloc(old.r);
    156     memory.devalloc(xn1.l);
    157     memory.devalloc(xn1.r);
    158     memory.devalloc(yn1.l);
    159     memory.devalloc(yn1.r);
    160 }
    161 
    162 /*
    163  * Effect output
    164  */
    165 void Phaser::out(const Stereo<float *> &input)
    166 {
    167     if(Panalog)
    168         AnalogPhase(input);
    169     else
    170         normalPhase(input);
    171 }
    172 
    173 void Phaser::AnalogPhase(const Stereo<float *> &input)
    174 {
    175     Stereo<float> gain(0.0f), lfoVal(0.0f), mod(0.0f), g(0.0f), b(0.0f), hpf(
    176         0.0f);
    177 
    178     lfo.effectlfoout(&lfoVal.l, &lfoVal.r);
    179     mod.l = lfoVal.l * width + (depth - 0.5f);
    180     mod.r = lfoVal.r * width + (depth - 0.5f);
    181 
    182     mod.l = limit(mod.l, ZERO_, ONE_);
    183     mod.r = limit(mod.r, ZERO_, ONE_);
    184 
    185     if(Phyper) {
    186         //Triangle wave squared is approximately sin on bottom, tri on top
    187         //Result is exponential sweep more akin to filter in synth with
    188         //exponential generator circuitry.
    189         mod.l *= mod.l;
    190         mod.r *= mod.r;
    191     }
    192 
    193     //g.l,g.r is Vp - Vgs. Typical FET drain-source resistance follows constant/[1-sqrt(Vp - Vgs)]
    194     mod.l = sqrtf(1.0f - mod.l);
    195     mod.r = sqrtf(1.0f - mod.r);
    196 
    197     diff.r = (mod.r - oldgain.r) * invperiod;
    198     diff.l = (mod.l - oldgain.l) * invperiod;
    199 
    200     g = oldgain;
    201     oldgain = mod;
    202 
    203     for(int i = 0; i < buffersize; ++i) {
    204         g.l += diff.l; // Linear interpolation between LFO samples
    205         g.r += diff.r;
    206 
    207         Stereo<float> xn(input.l[i] * pangainL, input.r[i] * pangainR);
    208 
    209         if(barber) {
    210             g.l += 0.25;
    211             g.l -= floorf(g.l);
    212             g.r += 0.25;
    213             g.r -= floorf(g.r);
    214         }
    215 
    216         xn.l = applyPhase(xn.l, g.l, fb.l, hpf.l, yn1.l, xn1.l);
    217         xn.r = applyPhase(xn.r, g.r, fb.r, hpf.r, yn1.r, xn1.r);
    218 
    219 
    220         fb.l = xn.l * feedback;
    221         fb.r = xn.r * feedback;
    222         efxoutl[i] = xn.l;
    223         efxoutr[i] = xn.r;
    224     }
    225 
    226     if(Poutsub) {
    227         invSignal(efxoutl, buffersize);
    228         invSignal(efxoutr, buffersize);
    229     }
    230 }
    231 
    232 float Phaser::applyPhase(float x, float g, float fb,
    233                          float &hpf, float *yn1, float *xn1)
    234 {
    235     for(int j = 0; j < Pstages; ++j) { //Phasing routine
    236         mis = 1.0f + offsetpct * offset[j];
    237 
    238         //This is symmetrical.
    239         //FET is not, so this deviates slightly, however sym dist. is
    240         //better sounding than a real FET.
    241         float d = (1.0f + 2.0f * (0.25f + g) * hpf * hpf * distortion) * mis;
    242         Rconst = 1.0f + mis * Rmx;
    243 
    244         // This is 1/R. R is being modulated to control filter fc.
    245         float b    = (Rconst - g) / (d * Rmin);
    246         float gain = (CFs - b) / (CFs + b);
    247         yn1[j] = gain * (x + yn1[j]) - xn1[j];
    248 
    249         //high pass filter:
    250         //Distortion depends on the high-pass part of the AP stage.
    251         hpf = yn1[j] + (1.0f - gain) * xn1[j];
    252 
    253         xn1[j] = x;
    254         x      = yn1[j];
    255         if(j == 1)
    256             x += fb;  //Insert feedback after first phase stage
    257     }
    258     return x;
    259 }
    260 void Phaser::normalPhase(const Stereo<float *> &input)
    261 {
    262     Stereo<float> gain(0.0f), lfoVal(0.0f);
    263 
    264     lfo.effectlfoout(&lfoVal.l, &lfoVal.r);
    265     gain.l =
    266         (expf(lfoVal.l
    267               * PHASER_LFO_SHAPE) - 1) / (expf(PHASER_LFO_SHAPE) - 1.0f);
    268     gain.r =
    269         (expf(lfoVal.r
    270               * PHASER_LFO_SHAPE) - 1) / (expf(PHASER_LFO_SHAPE) - 1.0f);
    271 
    272     gain.l = 1.0f - phase * (1.0f - depth) - (1.0f - phase) * gain.l * depth;
    273     gain.r = 1.0f - phase * (1.0f - depth) - (1.0f - phase) * gain.r * depth;
    274 
    275     gain.l = limit(gain.l, ZERO_, ONE_);
    276     gain.r = limit(gain.r, ZERO_, ONE_);
    277 
    278     for(int i = 0; i < buffersize; ++i) {
    279         float x  = (float) i / buffersize_f;
    280         float x1 = 1.0f - x;
    281         //TODO think about making panning an external feature
    282         Stereo<float> xn(input.l[i] * pangainL + fb.l,
    283                          input.r[i] * pangainR + fb.r);
    284 
    285         Stereo<float> g(gain.l * x + oldgain.l * x1,
    286                         gain.r * x + oldgain.r * x1);
    287 
    288         xn.l = applyPhase(xn.l, g.l, old.l);
    289         xn.r = applyPhase(xn.r, g.r, old.r);
    290 
    291         //Left/Right crossing
    292         crossover(xn.l, xn.r, lrcross);
    293 
    294         fb.l = xn.l * feedback;
    295         fb.r = xn.r * feedback;
    296         efxoutl[i] = xn.l;
    297         efxoutr[i] = xn.r;
    298     }
    299 
    300     oldgain = gain;
    301 
    302     if(Poutsub) {
    303         invSignal(efxoutl, buffersize);
    304         invSignal(efxoutr, buffersize);
    305     }
    306 }
    307 
    308 float Phaser::applyPhase(float x, float g, float *old)
    309 {
    310     for(int j = 0; j < Pstages * 2; ++j) { //Phasing routine
    311         float tmp = old[j];
    312         old[j] = g * tmp + x;
    313         x      = tmp - g * old[j];
    314     }
    315     return x;
    316 }
    317 
    318 /*
    319  * Cleanup the effect
    320  */
    321 void Phaser::cleanup()
    322 {
    323     fb = oldgain = Stereo<float>(0.0f);
    324     for(int i = 0; i < Pstages * 2; ++i) {
    325         old.l[i] = 0.0f;
    326         old.r[i] = 0.0f;
    327     }
    328     for(int i = 0; i < Pstages; ++i) {
    329         xn1.l[i] = 0.0f;
    330         yn1.l[i] = 0.0f;
    331         xn1.r[i] = 0.0f;
    332         yn1.r[i] = 0.0f;
    333     }
    334 }
    335 
    336 /*
    337  * Parameter control
    338  */
    339 void Phaser::setwidth(unsigned char Pwidth)
    340 {
    341     this->Pwidth = Pwidth;
    342     width = ((float)Pwidth / 127.0f);
    343 }
    344 
    345 void Phaser::setfb(unsigned char Pfb)
    346 {
    347     this->Pfb = Pfb;
    348     feedback  = (float) (Pfb - 64) / 64.2f;
    349 }
    350 
    351 void Phaser::setvolume(unsigned char Pvolume)
    352 {
    353     this->Pvolume = Pvolume;
    354     outvolume     = Pvolume / 127.0f;
    355     if(insertion == 0)
    356         volume = 1.0f;
    357     else
    358         volume = outvolume;
    359 }
    360 
    361 void Phaser::setdistortion(unsigned char Pdistortion)
    362 {
    363     this->Pdistortion = Pdistortion;
    364     distortion = (float)Pdistortion / 127.0f;
    365 }
    366 
    367 void Phaser::setoffset(unsigned char Poffset)
    368 {
    369     this->Poffset = Poffset;
    370     offsetpct     = (float)Poffset / 127.0f;
    371 }
    372 
    373 void Phaser::setstages(unsigned char Pstages_)
    374 {
    375     memory.devalloc(old.l);
    376     memory.devalloc(old.r);
    377     memory.devalloc(xn1.l);
    378     memory.devalloc(xn1.r);
    379     memory.devalloc(yn1.l);
    380     memory.devalloc(yn1.r);
    381 
    382     Pstages = limit<int>(Pstages_, 1, MAX_PHASER_STAGES);
    383 
    384     old = Stereo<float *>(memory.valloc<float>(Pstages * 2),
    385                           memory.valloc<float>(Pstages * 2));
    386 
    387     xn1 = Stereo<float *>(memory.valloc<float>(Pstages),
    388                           memory.valloc<float>(Pstages));
    389 
    390     yn1 = Stereo<float *>(memory.valloc<float>(Pstages),
    391                           memory.valloc<float>(Pstages));
    392 
    393     cleanup();
    394 }
    395 
    396 void Phaser::setphase(unsigned char Pphase)
    397 {
    398     this->Pphase = Pphase;
    399     phase = (Pphase / 127.0f);
    400 }
    401 
    402 void Phaser::setdepth(unsigned char Pdepth)
    403 {
    404     this->Pdepth = Pdepth;
    405     depth = (float)(Pdepth) / 127.0f;
    406 }
    407 
    408 unsigned char Phaser::getpresetpar(unsigned char npreset, unsigned int npar)
    409 {
    410 #define	PRESET_SIZE 15
    411 #define	NUM_PRESETS 12
    412     static const unsigned char presets[NUM_PRESETS][PRESET_SIZE] = {
    413         //Phaser
    414         //0   1    2    3  4   5     6   7   8    9 10   11 12  13 14
    415         {64, 64, 36,  0,   0, 64,  110, 64,  1,  0,   0, 20,
    416          0, 0,
    417          0 },
    418         {64, 64, 35,  0,   0, 88,  40,  64,  3,  0,   0, 20, 0,  0,
    419          0 },
    420         {64, 64, 31,  0,   0, 66,  68,  107, 2,  0,   0, 20, 0,  0,
    421          0 },
    422         {39, 64, 22,  0,   0, 66,  67,  10,  5,  0,   1, 20, 0,  0,
    423          0 },
    424         {64, 64, 20,  0,   1, 110, 67,  78,  10, 0,   0, 20, 0,  0,
    425          0 },
    426         {64, 64, 53,  100, 0, 58,  37,  78,  3,  0,   0, 20, 0,  0,
    427          0 },
    428         //APhaser
    429         //0   1    2   3   4   5     6   7   8    9 10   11 12  13 14
    430         {64, 64, 14,  0,   1, 64,  64,  40,  4,  10,  0, 110,1,  20,
    431          1 },
    432         {64, 64, 14,  5,   1, 64,  70,  40,  6,  10,  0, 110,1,  20,
    433          1 },
    434         {64, 64, 9,   0,   0, 64,  60,  40,  8,  10,  0, 40, 0,  20,
    435          1 },
    436         {64, 64, 14,  10,  0, 64,  45,  80,  7,  10,  1, 110,1,  20,
    437          1 },
    438         {25, 64, 127, 10,  0, 64,  25,  16,  8,  100, 0, 25, 0,  20,
    439          1 },
    440         {64, 64, 1,   10,  1, 64,  70,  40,  12, 10,  0, 110,1,  20,
    441          1 }
    442     };
    443     if(npreset < NUM_PRESETS && npar < PRESET_SIZE)
    444         return presets[npreset][npar];
    445     return 0;
    446 }
    447 
    448 void Phaser::setpreset(unsigned char npreset)
    449 {
    450     if(npreset >= NUM_PRESETS)
    451         npreset = NUM_PRESETS - 1;
    452     for(int n = 0; n != 128; n++)
    453         changepar(n, getpresetpar(npreset, n));
    454     Ppreset = npreset;
    455 }
    456 
    457 void Phaser::changepar(int npar, unsigned char value)
    458 {
    459     switch(npar) {
    460         case 0:
    461             setvolume(value);
    462             break;
    463         case 1:
    464             setpanning(value);
    465             break;
    466         case 2:
    467             lfo.Pfreq = value;
    468             lfo.updateparams();
    469             break;
    470         case 3:
    471             lfo.Prandomness = value;
    472             lfo.updateparams();
    473             break;
    474         case 4:
    475             lfo.PLFOtype = value;
    476             lfo.updateparams();
    477             barber = (2 == value);
    478             break;
    479         case 5:
    480             lfo.Pstereo = value;
    481             lfo.updateparams();
    482             break;
    483         case 6:
    484             setdepth(value);
    485             break;
    486         case 7:
    487             setfb(value);
    488             break;
    489         case 8:
    490             setstages(value);
    491             break;
    492         case 9:
    493             setlrcross(value);
    494             setoffset(value);
    495             break;
    496         case 10:
    497             Poutsub = min((int)value, 1);
    498             break;
    499         case 11:
    500             setphase(value);
    501             setwidth(value);
    502             break;
    503         case 12:
    504             Phyper = min((int)value, 1);
    505             break;
    506         case 13:
    507             setdistortion(value);
    508             break;
    509         case 14:
    510             Panalog = (value!=0);
    511             break;
    512     }
    513 }
    514 
    515 unsigned char Phaser::getpar(int npar) const
    516 {
    517     switch(npar) {
    518         case 0:  return Pvolume;
    519         case 1:  return Ppanning;
    520         case 2:  return lfo.Pfreq;
    521         case 3:  return lfo.Prandomness;
    522         case 4:  return lfo.PLFOtype;
    523         case 5:  return lfo.Pstereo;
    524         case 6:  return Pdepth;
    525         case 7:  return Pfb;
    526         case 8:  return Pstages;
    527         case 9:  return Plrcross;
    528             return Poffset;      //same
    529         case 10: return Poutsub;
    530         case 11: return Pphase;
    531             return Pwidth;      //same
    532         case 12: return Phyper;
    533         case 13: return Pdistortion;
    534         case 14: return Panalog;
    535         default: return 0;
    536     }
    537 }
    538 
    539 }