zynaddsubfx

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

Alienwah.cpp (7713B)


      1 /*
      2   ZynAddSubFX - a software synthesizer
      3 
      4   Alienwah.cpp - "AlienWah" effect
      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/port-sugar.h>
     16 #include <rtosc/ports.h>
     17 #include "../Misc/Allocator.h"
     18 #include "Alienwah.h"
     19 
     20 namespace zyn {
     21 
     22 using std::complex;
     23 
     24 #define rObject Alienwah
     25 #define rBegin [](const char *msg, rtosc::RtData &d) {
     26 #define rEnd }
     27 
     28 rtosc::Ports Alienwah::ports = {
     29     {"preset::i", rProp(parameter)
     30                   rOptions(wah 1, wah 2, wah 3, wah 4)
     31                   rProp(alias)
     32                   rDefault(0)
     33                   rDoc("Instrument Presets"), 0,
     34                   rBegin;
     35                   rObject *o = (rObject*)d.obj;
     36                   if(rtosc_narguments(msg))
     37                       o->setpreset(rtosc_argument(msg, 0).i);
     38                   else
     39                       d.reply(d.loc, "i", o->Ppreset);
     40                   rEnd},
     41     rPresetForVolume,
     42     rEffParVol(rDefaultDepends(presetOfVolume),
     43                rDefault(63), rPresetsAt(3, 46),
     44                rPresetsAt(16, 127, 127, 127, 93)),
     45     rEffParPan(),
     46     rEffPar(Pfreq,     2, rShort("freq") rPresets(70, 73, 63, 25),
     47             "Effect Frequency"),
     48     rEffPar(Pfreqrnd,  3, rShort("rand"), rPreset(1, 106) rDefault(0),
     49             "Frequency Randomness"),
     50     rEffParOpt(PLFOtype,  4, rShort("shape"),
     51             rOptions(sine, triangle), rPresets(sine, sine, triangle, triangle),
     52             "LFO Shape"),
     53     rEffPar(PStereo,   5, rShort("stereo"), rPresets(62, 101, 100, 66),
     54             "Stereo Mode"),
     55     rEffPar(Pdepth,    6, rShort("depth"), rPresets(60, 60, 112, 101),
     56             "LFO Depth"),
     57     rEffPar(Pfeedback, 7, rShort("fb"), rPreset(3, 11), rDefault(105),
     58             "Feedback"),
     59     rEffPar(Pdelay,    8, rLinear(1,100), rPresets(25, 17, 31, 47),
     60             rShort("delay"), "Delay"),
     61     rEffPar(Plrcross,  9, rShort("l/r"), rDefault(0), "Left/Right Crossover"),
     62     rEffPar(Pphase,   10, rShort("phase"), rDefault(64), rPreset(2, 42),
     63             rPreset(3, 86), "Phase"),
     64 };
     65 #undef rBegin
     66 #undef rEnd
     67 #undef rObject
     68 
     69 Alienwah::Alienwah(EffectParams pars)
     70     :Effect(pars),
     71       lfo(pars.srate, pars.bufsize),
     72       oldl(NULL),
     73       oldr(NULL)
     74 {
     75     setpreset(Ppreset);
     76     cleanup();
     77     oldclfol = complex<float>(fb, 0.0f);
     78     oldclfor = complex<float>(fb, 0.0f);
     79 }
     80 
     81 Alienwah::~Alienwah()
     82 {
     83     memory.devalloc(oldl);
     84     memory.devalloc(oldr);
     85 }
     86 
     87 
     88 //Apply the effect
     89 void Alienwah::out(const Stereo<float *> &smp)
     90 {
     91     float lfol, lfor; //Left/Right LFOs
     92     complex<float> clfol, clfor;
     93     /**\todo Rework, as optimization can be used when the new complex type is
     94      * utilized.
     95      * Before all calculations needed to be done with individual float,
     96      * but now they can be done together*/
     97     lfo.effectlfoout(&lfol, &lfor);
     98     lfol *= depth * PI * 2.0f;
     99     lfor *= depth * PI * 2.0f;
    100     clfol = complex<float>(cosf(lfol + phase) * fb, sinf(lfol + phase) * fb); //rework
    101     clfor = complex<float>(cosf(lfor + phase) * fb, sinf(lfor + phase) * fb); //rework
    102 
    103     for(int i = 0; i < buffersize; ++i) {
    104         float x  = ((float) i) / buffersize_f;
    105         float x1 = 1.0f - x;
    106         //left
    107         complex<float> tmp = clfol * x + oldclfol * x1;
    108 
    109         complex<float> out = tmp * oldl[oldk];
    110         out += (1 - fabsf(fb)) * smp.l[i] * pangainL;
    111 
    112         oldl[oldk] = out;
    113         float l = out.real() * 10.0f * (fb + 0.1f);
    114 
    115         //right
    116         tmp = clfor * x + oldclfor * x1;
    117 
    118         out = tmp * oldr[oldk];
    119         out += (1 - fabsf(fb)) * smp.r[i] * pangainR;
    120 
    121         oldr[oldk] = out;
    122         float r = out.real() * 10.0f * (fb + 0.1f);
    123 
    124 
    125         if(++oldk >= Pdelay)
    126             oldk = 0;
    127         //LRcross
    128         efxoutl[i] = l * (1.0f - lrcross) + r * lrcross;
    129         efxoutr[i] = r * (1.0f - lrcross) + l * lrcross;
    130     }
    131 
    132     oldclfol = clfol;
    133     oldclfor = clfor;
    134 }
    135 
    136 //Cleanup the effect
    137 void Alienwah::cleanup(void)
    138 {
    139     for(int i = 0; i < Pdelay; ++i) {
    140         oldl[i] = complex<float>(0.0f, 0.0f);
    141         oldr[i] = complex<float>(0.0f, 0.0f);
    142     }
    143     oldk = 0;
    144 }
    145 
    146 
    147 //Parameter control
    148 void Alienwah::setdepth(unsigned char _Pdepth)
    149 {
    150     Pdepth = _Pdepth;
    151     depth  = Pdepth / 127.0f;
    152 }
    153 
    154 void Alienwah::setfb(unsigned char _Pfb)
    155 {
    156     Pfb = _Pfb;
    157     fb  = fabsf((Pfb - 64.0f) / 64.1f);
    158     fb  = sqrtf(fb);
    159     if(fb < 0.4f)
    160         fb = 0.4f;
    161     if(Pfb < 64)
    162         fb = -fb;
    163 }
    164 
    165 void Alienwah::setvolume(unsigned char _Pvolume)
    166 {
    167     Pvolume   = _Pvolume;
    168     outvolume = Pvolume / 127.0f;
    169     if(insertion == 0)
    170         volume = 1.0f;
    171     else
    172         volume = outvolume;
    173 }
    174 
    175 void Alienwah::setphase(unsigned char _Pphase)
    176 {
    177     Pphase = _Pphase;
    178     phase  = (Pphase - 64.0f) / 64.0f * PI;
    179 }
    180 
    181 void Alienwah::setdelay(unsigned char _Pdelay)
    182 {
    183     memory.devalloc(oldl);
    184     memory.devalloc(oldr);
    185     Pdelay = limit<int>(_Pdelay, 1, MAX_ALIENWAH_DELAY);
    186     oldl   = memory.valloc<complex<float>>(Pdelay);
    187     oldr   = memory.valloc<complex<float>>(Pdelay);
    188     cleanup();
    189 }
    190 
    191 unsigned char Alienwah::getpresetpar(unsigned char npreset, unsigned int npar)
    192 {
    193 #define	PRESET_SIZE 11
    194 #define	NUM_PRESETS 4
    195     static const unsigned char presets[NUM_PRESETS][PRESET_SIZE] = {
    196         //AlienWah1
    197         {127, 64, 70, 0,   0, 62,  60,  105, 25, 0, 64},
    198         //AlienWah2
    199         {127, 64, 73, 106, 0, 101, 60,  105, 17, 0, 64},
    200         //AlienWah3
    201         {127, 64, 63, 0,   1, 100, 112, 105, 31, 0, 42},
    202         //AlienWah4
    203         {93,  64, 25, 0,   1, 66,  101, 11,  47, 0, 86}
    204     };
    205     if(npreset < NUM_PRESETS && npar < PRESET_SIZE) {
    206         if (npar == 0 && insertion == 0) {
    207             /* lower the volume if this is system effect */
    208             return presets[npreset][npar] / 2;
    209         }
    210         return presets[npreset][npar];
    211     }
    212     return 0;
    213 }
    214 
    215 void Alienwah::setpreset(unsigned char npreset)
    216 {
    217     if(npreset >= NUM_PRESETS)
    218         npreset = NUM_PRESETS - 1;
    219     for(int n = 0; n != 128; n++)
    220         changepar(n, getpresetpar(npreset, n));
    221     Ppreset = npreset;
    222 }
    223 
    224 void Alienwah::changepar(int npar, unsigned char value)
    225 {
    226     switch(npar) {
    227         case 0:
    228             setvolume(value);
    229             break;
    230         case 1:
    231             setpanning(value);
    232             break;
    233         case 2:
    234             lfo.Pfreq = value;
    235             lfo.updateparams();
    236             break;
    237         case 3:
    238             lfo.Prandomness = value;
    239             lfo.updateparams();
    240             break;
    241         case 4:
    242             lfo.PLFOtype = value;
    243             lfo.updateparams();
    244             break;
    245         case 5:
    246             lfo.Pstereo = value;
    247             lfo.updateparams();
    248             break;
    249         case 6:
    250             setdepth(value);
    251             break;
    252         case 7:
    253             setfb(value);
    254             break;
    255         case 8:
    256             setdelay(value);
    257             break;
    258         case 9:
    259             setlrcross(value);
    260             break;
    261         case 10:
    262             setphase(value);
    263             break;
    264     }
    265 }
    266 
    267 unsigned char Alienwah::getpar(int npar) const
    268 {
    269     switch(npar) {
    270         case 0:  return Pvolume;
    271         case 1:  return Ppanning;
    272         case 2:  return lfo.Pfreq;
    273         case 3:  return lfo.Prandomness;
    274         case 4:  return lfo.PLFOtype;
    275         case 5:  return lfo.Pstereo;
    276         case 6:  return Pdepth;
    277         case 7:  return Pfb;
    278         case 8:  return Pdelay;
    279         case 9:  return Plrcross;
    280         case 10: return Pphase;
    281         default: return 0;
    282     }
    283 }
    284 
    285 }