zynaddsubfx

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

Resonance.cpp (9444B)


      1 /*
      2   ZynAddSubFX - a software synthesizer
      3 
      4   Resonance.cpp - Resonance
      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 <cstdlib>
     16 #include "Resonance.h"
     17 #include "../Misc/Util.h"
     18 
     19 #include <rtosc/ports.h>
     20 #include <rtosc/port-sugar.h>
     21 using namespace rtosc;
     22 
     23 namespace zyn {
     24 
     25 #define rObject Resonance
     26 #define rBegin [](const char *msg, RtData &d) { rObject &o = *(rObject*)d.obj
     27 #define rEnd }
     28 
     29 const rtosc::Ports Resonance::ports = {
     30     rSelf(Resonance),
     31     rPasteRt,
     32     rToggle(Penabled,      rShort("enable"), rDefault(false),
     33             "resonance enable"),
     34     rToggle(Pprotectthefundamental, rShort("p.fund."), rDefault(false),
     35             "Disable resonance filter on first harmonic"),
     36     rParams(Prespoints, N_RES_POINTS, rDefault([64 ...]),
     37             "Resonance data points"),
     38     rParamZyn(PmaxdB,      rShort("max"), rDefault(20),
     39               "how many dB the signal may be amplified"),
     40     rParamZyn(Pcenterfreq, rShort("c.freq"), rDefault(64), "Center frequency"),
     41     rParamZyn(Poctavesfreq, rShort("oct"), rDefault(64),
     42               "The number of octaves..."),
     43     rActioni(randomize, rMap(min,0), rMap(max, 2), "Randomize frequency response"),
     44     rActioni(interpolatepeaks, rMap(min,0), rMap(max, 2), "Generate response from peak values"),
     45     rAction(smooth, "Smooth out frequency response"),
     46     rAction(zero,   "Reset frequency response"),
     47     //UI Value listeners
     48     {"centerfreq:", rDoc("Get center frequency") rMap(unit, Hz),  NULL,
     49         [](const char *, RtData &d)
     50         {d.reply(d.loc, "f", ((rObject*)d.obj)->getcenterfreq());}},
     51     {"octavesfreq:", rDoc("Get center freq of graph"), NULL,
     52             [](const char *, RtData &d)
     53         {d.reply(d.loc, "f", ((rObject*)d.obj)->getoctavesfreq());}},
     54     {"respoints", 0, 0,
     55         rBegin;
     56         if(rtosc_narguments(msg)) {
     57             int i=0;
     58             auto itr = rtosc_itr_begin(msg);
     59             while(!rtosc_itr_end(itr) && i < N_RES_POINTS) {
     60                 auto ival = rtosc_itr_next(&itr);
     61                 if(ival.type == 'f')
     62                     o.Prespoints[i++] = ival.val.f*127;
     63             }
     64         } else {
     65             rtosc_arg_t args[N_RES_POINTS];
     66             char        types[N_RES_POINTS+1] = {};
     67             for(int i=0; i<N_RES_POINTS; ++i) {
     68                 args[i].f = o.Prespoints[i]/127.0;
     69                 types[i]  = 'f';
     70             }
     71             d.replyArray(d.loc, types, args);
     72         }
     73         rEnd},
     74 };
     75 #undef rBegin
     76 #undef rEnd
     77 
     78 Resonance::Resonance():Presets()
     79 {
     80     setpresettype("Presonance");
     81     defaults();
     82 }
     83 
     84 Resonance::~Resonance(void)
     85 {}
     86 
     87 
     88 void Resonance::defaults(void)
     89 {
     90     Penabled     = 0;
     91     PmaxdB       = 20;
     92     Pcenterfreq  = 64; //1 kHz
     93     Poctavesfreq = 64;
     94     Pprotectthefundamental = 0;
     95     ctlcenter = 1.0f;
     96     ctlbw     = 1.0f;
     97     for(int i = 0; i < N_RES_POINTS; ++i)
     98         Prespoints[i] = 64;
     99 }
    100 
    101 /*
    102  * Set a point of resonance function with a value
    103  */
    104 void Resonance::setpoint(int n, unsigned char p)
    105 {
    106     if((n < 0) || (n >= N_RES_POINTS))
    107         return;
    108     Prespoints[n] = p;
    109 }
    110 
    111 /*
    112  * Apply the resonance to FFT data
    113  */
    114 void Resonance::applyres(int n, fft_t *fftdata, float freq) const
    115 {
    116     if(Penabled == 0)
    117         return;             //if the resonance is disabled
    118 
    119     const float l1  = logf(getfreqx(0.0f) * ctlcenter),
    120                 l2  = logf(2.0f) * getoctavesfreq() * ctlbw;
    121 
    122     //Provide an upper bound for resonance
    123     const float upper =
    124         limit<float>(array_max(Prespoints, N_RES_POINTS), 1.0f, (float)INFINITY);
    125 
    126     for(int i = 1; i < n; ++i) {
    127         //compute where the n-th hamonics fits to the graph
    128         const float x  = limit((logf(freq*i) - l1) / l2, 0.0f, (float)INFINITY) * N_RES_POINTS;
    129         const float dx = x - floor(x);
    130         const int kx1  = limit<int>(floor(x), 0, N_RES_POINTS - 1);
    131         const int kx2  = limit<int>(kx1 + 1,  0, N_RES_POINTS - 1);
    132         float y =
    133             ((Prespoints[kx1] * (1.0f - dx) + Prespoints[kx2] * dx)
    134              - upper) / 127.0f;
    135 
    136         y = powf(10.0f, y * PmaxdB / 20.0f);
    137 
    138         if((Pprotectthefundamental != 0) && (i == 1))
    139             y = 1.0f;
    140 
    141         fftdata[i] *= y;
    142     }
    143 }
    144 
    145 /*
    146  * Gets the response at the frequency "freq"
    147  */
    148 //Requires
    149 // - resonance data
    150 // - max resonance
    151 // - mapping from resonance data to frequency
    152 float Resonance::getfreqresponse(float freq) const
    153 {
    154     const float l1 = logf(getfreqx(0.0f) * ctlcenter),
    155                 l2 = logf(2.0f) * getoctavesfreq() * ctlbw;
    156 
    157     //Provide an upper bound for resonance
    158     const float upper =
    159         limit<float>(array_max(Prespoints, N_RES_POINTS), 1.0f, INFINITY);
    160 
    161     //compute where the n-th hamonics fits to the graph
    162     const float x   = limit((logf(freq) - l1) / l2, 0.0f, (float)INFINITY) * N_RES_POINTS;
    163     const float dx  = x - floor(x);
    164     const int   kx1 = limit<int>(floor(x), 0, N_RES_POINTS - 1);
    165     const int   kx2 = limit<int>(kx1 + 1,  0, N_RES_POINTS - 1);
    166     //Interpolate
    167     const float result =
    168         ((Prespoints[kx1] * (1.0f - dx) + Prespoints[kx2] * dx) - upper) / 127.0f;
    169     return powf(10.0f, result * PmaxdB / 20.0f);
    170 }
    171 
    172 
    173 /*
    174  * Smooth the resonance function
    175  */
    176 void Resonance::smooth(void)
    177 {
    178     float old = Prespoints[0];
    179     for(int i = 0; i < N_RES_POINTS; ++i) {
    180         old = old * 0.4f + Prespoints[i] * 0.6f;
    181         Prespoints[i] = (int) old;
    182     }
    183     old = Prespoints[N_RES_POINTS - 1];
    184     for(int i = N_RES_POINTS - 1; i > 0; i--) {
    185         old = old * 0.4f + Prespoints[i] * 0.6f;
    186         Prespoints[i] = (int) old + 1;
    187         if(Prespoints[i] > 127)
    188             Prespoints[i] = 127;
    189     }
    190 }
    191 
    192 /*
    193  * Randomize the resonance function
    194  */
    195 void Resonance::randomize(int type)
    196 {
    197     int r = (int)(RND * 127.0f);
    198     for(int i = 0; i < N_RES_POINTS; ++i) {
    199         Prespoints[i] = r;
    200         if((RND < 0.1f) && (type == 0))
    201             r = (int)(RND * 127.0f);
    202         if((RND < 0.3f) && (type == 1))
    203             r = (int)(RND * 127.0f);
    204         if(type == 2)
    205             r = (int)(RND * 127.0f);
    206     }
    207     smooth();
    208 }
    209 
    210 void Resonance::zero(void)
    211 {
    212     for(int i=0; i<N_RES_POINTS; ++i)
    213         setpoint(i,64);
    214 }
    215 
    216 /*
    217  * Interpolate the peaks
    218  */
    219 void Resonance::interpolatepeaks(int type)
    220 {
    221     int x1 = 0, y1 = Prespoints[0];
    222     for(int i = 1; i < N_RES_POINTS; ++i)
    223         if((Prespoints[i] != 64) || (i + 1 == N_RES_POINTS)) {
    224             int y2 = Prespoints[i];
    225             for(int k = 0; k < i - x1; ++k) {
    226                 float x = (float) k / (i - x1);
    227                 if(type == 0)
    228                     x = (1 - cosf(x * PI)) * 0.5f;
    229                 Prespoints[x1 + k] = (int)(y1 * (1.0f - x) + y2 * x);
    230             }
    231             x1 = i;
    232             y1 = y2;
    233         }
    234 }
    235 
    236 /*
    237  * Get the frequency from x, where x is [0..1]; x is the x coordinate
    238  */
    239 float Resonance::getfreqx(float x) const
    240 {
    241     const float octf = powf(2.0f, getoctavesfreq());
    242     return getcenterfreq() / sqrt(octf) * powf(octf, limit(x, 0.0f, 1.0f));
    243 }
    244 
    245 /*
    246  * Get the x coordinate from frequency (used by the UI)
    247  */
    248 float Resonance::getfreqpos(float freq) const
    249 {
    250     return (logf(freq) - logf(getfreqx(0.0f))) / logf(2.0f) / getoctavesfreq();
    251 }
    252 
    253 /*
    254  * Get the center frequency of the resonance graph
    255  */
    256 float Resonance::getcenterfreq() const
    257 {
    258     return 10000.0f * powf(10, -(1.0f - Pcenterfreq / 127.0f) * 2.0f);
    259 }
    260 
    261 /*
    262  * Get the number of octave that the resonance functions applies to
    263  */
    264 float Resonance::getoctavesfreq() const
    265 {
    266     return 0.25f + 10.0f * Poctavesfreq / 127.0f;
    267 }
    268 
    269 void Resonance::sendcontroller(MidiControllers ctl, float par)
    270 {
    271     if(ctl == C_resonance_center)
    272         ctlcenter = par;
    273     else
    274         ctlbw = par;
    275 }
    276 
    277 #define COPY(y) this->y = r.y
    278 void Resonance::paste(Resonance &r)
    279 {
    280     COPY(Penabled);
    281     for(int i=0; i<N_RES_POINTS; ++i)
    282         this->Prespoints[i] = r.Prespoints[i];
    283     COPY(PmaxdB);
    284     COPY(Pcenterfreq);
    285     COPY(Poctavesfreq);
    286     COPY(Pprotectthefundamental);
    287 
    288     COPY(ctlcenter);
    289     COPY(ctlbw);
    290 }
    291 #undef COPY
    292 
    293 void Resonance::add2XML(XMLwrapper& xml)
    294 {
    295     xml.addparbool("enabled", Penabled);
    296 
    297     if((Penabled == 0) && (xml.minimal))
    298         return;
    299 
    300     xml.addpar("max_db", PmaxdB);
    301     xml.addpar("center_freq", Pcenterfreq);
    302     xml.addpar("octaves_freq", Poctavesfreq);
    303     xml.addparbool("protect_fundamental_frequency", Pprotectthefundamental);
    304     xml.addpar("resonance_points", N_RES_POINTS);
    305     for(int i = 0; i < N_RES_POINTS; ++i) {
    306         xml.beginbranch("RESPOINT", i);
    307         xml.addpar("val", Prespoints[i]);
    308         xml.endbranch();
    309     }
    310 }
    311 
    312 
    313 void Resonance::getfromXML(XMLwrapper& xml)
    314 {
    315     Penabled = xml.getparbool("enabled", Penabled);
    316 
    317     PmaxdB       = xml.getpar127("max_db", PmaxdB);
    318     Pcenterfreq  = xml.getpar127("center_freq", Pcenterfreq);
    319     Poctavesfreq = xml.getpar127("octaves_freq", Poctavesfreq);
    320     Pprotectthefundamental = xml.getparbool("protect_fundamental_frequency",
    321                                              Pprotectthefundamental);
    322     for(int i = 0; i < N_RES_POINTS; ++i) {
    323         if(xml.enterbranch("RESPOINT", i) == 0)
    324             continue;
    325         Prespoints[i] = xml.getpar127("val", Prespoints[i]);
    326         xml.exitbranch();
    327     }
    328 }
    329 
    330 }