|
- /*
- ZynAddSubFX - a software synthesizer
-
- Resonance.cpp - Resonance
- Copyright (C) 2002-2005 Nasca Octavian Paul
- Author: Nasca Octavian Paul
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- */
-
- #include <cmath>
- #include <cstdlib>
- #include "Resonance.h"
- #include "../Misc/Util.h"
-
- #include <rtosc/ports.h>
- #include <rtosc/port-sugar.h>
- using namespace rtosc;
-
- namespace zyncarla {
-
- #define rObject Resonance
- #define rBegin [](const char *msg, RtData &d) { rObject &o = *(rObject*)d.obj
- #define rEnd }
-
- const rtosc::Ports Resonance::ports = {
- rSelf(Resonance),
- rPaste,
- rToggle(Penabled, rShort("enable"), rDefault(false),
- "resonance enable"),
- rToggle(Pprotectthefundamental, rShort("p.fund."), rDefault(false),
- "Disable resonance filter on first harmonic"),
- rParams(Prespoints, N_RES_POINTS, rDefaultMissing,
- "Resonance data points"),
- rParamZyn(PmaxdB, rShort("max"), rDefault(20),
- "how many dB the signal may be amplified"),
- rParamZyn(Pcenterfreq, rShort("c.freq"), rDefault(64), "Center frequency"),
- rParamZyn(Poctavesfreq, rShort("oct"), rDefault(64),
- "The number of octaves..."),
- rActioni(randomize, rMap(min,0), rMap(max, 2), "Randomize frequency response"),
- rActioni(interpolatepeaks, rMap(min,0), rMap(max, 2), "Generate response from peak values"),
- rAction(smooth, "Smooth out frequency response"),
- rAction(zero, "Reset frequency response"),
- //UI Value listeners
- {"centerfreq:", rDoc("Get center frequency") rMap(unit, Hz), NULL,
- [](const char *, RtData &d)
- {d.reply(d.loc, "f", ((rObject*)d.obj)->getcenterfreq());}},
- {"octavesfreq:", rDoc("Get center freq of graph"), NULL,
- [](const char *, RtData &d)
- {d.reply(d.loc, "f", ((rObject*)d.obj)->getoctavesfreq());}},
- {"respoints", 0, 0,
- rBegin;
- if(rtosc_narguments(msg)) {
- int i=0;
- auto itr = rtosc_itr_begin(msg);
- while(!rtosc_itr_end(itr) && i < N_RES_POINTS) {
- auto ival = rtosc_itr_next(&itr);
- if(ival.type == 'f')
- o.Prespoints[i++] = ival.val.f*127;
- }
- } else {
- rtosc_arg_t args[N_RES_POINTS];
- char types[N_RES_POINTS+1] = {0};
- for(int i=0; i<N_RES_POINTS; ++i) {
- args[i].f = o.Prespoints[i]/127.0;
- types[i] = 'f';
- }
- d.replyArray(d.loc, types, args);
- }
- rEnd},
- };
- #undef rBegin
- #undef rEnd
-
- Resonance::Resonance():Presets()
- {
- setpresettype("Presonance");
- defaults();
- }
-
- Resonance::~Resonance(void)
- {}
-
-
- void Resonance::defaults(void)
- {
- Penabled = 0;
- PmaxdB = 20;
- Pcenterfreq = 64; //1 kHz
- Poctavesfreq = 64;
- Pprotectthefundamental = 0;
- ctlcenter = 1.0f;
- ctlbw = 1.0f;
- for(int i = 0; i < N_RES_POINTS; ++i)
- Prespoints[i] = 64;
- }
-
- /*
- * Set a point of resonance function with a value
- */
- void Resonance::setpoint(int n, unsigned char p)
- {
- if((n < 0) || (n >= N_RES_POINTS))
- return;
- Prespoints[n] = p;
- }
-
- /*
- * Apply the resonance to FFT data
- */
- void Resonance::applyres(int n, fft_t *fftdata, float freq) const
- {
- if(Penabled == 0)
- return; //if the resonance is disabled
-
- const float l1 = logf(getfreqx(0.0f) * ctlcenter),
- l2 = logf(2.0f) * getoctavesfreq() * ctlbw;
-
- //Provide an upper bound for resonance
- const float upper =
- limit<float>(array_max(Prespoints, N_RES_POINTS), 1.0f, (float)INFINITY);
-
- for(int i = 1; i < n; ++i) {
- //compute where the n-th hamonics fits to the graph
- const float x = limit((logf(freq*i) - l1) / l2, 0.0f, (float)INFINITY) * N_RES_POINTS;
- const float dx = x - floor(x);
- const int kx1 = limit<int>(floor(x), 0, N_RES_POINTS - 1);
- const int kx2 = limit<int>(kx1 + 1, 0, N_RES_POINTS - 1);
- float y =
- ((Prespoints[kx1] * (1.0f - dx) + Prespoints[kx2] * dx)
- - upper) / 127.0f;
-
- y = powf(10.0f, y * PmaxdB / 20.0f);
-
- if((Pprotectthefundamental != 0) && (i == 1))
- y = 1.0f;
-
- fftdata[i] *= y;
- }
- }
-
- /*
- * Gets the response at the frequency "freq"
- */
- //Requires
- // - resonance data
- // - max resonance
- // - mapping from resonance data to frequency
- float Resonance::getfreqresponse(float freq) const
- {
- const float l1 = logf(getfreqx(0.0f) * ctlcenter),
- l2 = logf(2.0f) * getoctavesfreq() * ctlbw;
-
- //Provide an upper bound for resonance
- const float upper =
- limit<float>(array_max(Prespoints, N_RES_POINTS), 1.0f, INFINITY);
-
- //compute where the n-th hamonics fits to the graph
- const float x = limit((logf(freq) - l1) / l2, 0.0f, (float)INFINITY) * N_RES_POINTS;
- const float dx = x - floor(x);
- const int kx1 = limit<int>(floor(x), 0, N_RES_POINTS - 1);
- const int kx2 = limit<int>(kx1 + 1, 0, N_RES_POINTS - 1);
- //Interpolate
- const float result =
- ((Prespoints[kx1] * (1.0f - dx) + Prespoints[kx2] * dx) - upper) / 127.0f;
- return powf(10.0f, result * PmaxdB / 20.0f);
- }
-
-
- /*
- * Smooth the resonance function
- */
- void Resonance::smooth(void)
- {
- float old = Prespoints[0];
- for(int i = 0; i < N_RES_POINTS; ++i) {
- old = old * 0.4f + Prespoints[i] * 0.6f;
- Prespoints[i] = (int) old;
- }
- old = Prespoints[N_RES_POINTS - 1];
- for(int i = N_RES_POINTS - 1; i > 0; i--) {
- old = old * 0.4f + Prespoints[i] * 0.6f;
- Prespoints[i] = (int) old + 1;
- if(Prespoints[i] > 127)
- Prespoints[i] = 127;
- }
- }
-
- /*
- * Randomize the resonance function
- */
- void Resonance::randomize(int type)
- {
- int r = (int)(RND * 127.0f);
- for(int i = 0; i < N_RES_POINTS; ++i) {
- Prespoints[i] = r;
- if((RND < 0.1f) && (type == 0))
- r = (int)(RND * 127.0f);
- if((RND < 0.3f) && (type == 1))
- r = (int)(RND * 127.0f);
- if(type == 2)
- r = (int)(RND * 127.0f);
- }
- smooth();
- }
-
- void Resonance::zero(void)
- {
- for(int i=0; i<N_RES_POINTS; ++i)
- setpoint(i,64);
- }
-
- /*
- * Interpolate the peaks
- */
- void Resonance::interpolatepeaks(int type)
- {
- int x1 = 0, y1 = Prespoints[0];
- for(int i = 1; i < N_RES_POINTS; ++i)
- if((Prespoints[i] != 64) || (i + 1 == N_RES_POINTS)) {
- int y2 = Prespoints[i];
- for(int k = 0; k < i - x1; ++k) {
- float x = (float) k / (i - x1);
- if(type == 0)
- x = (1 - cosf(x * PI)) * 0.5f;
- Prespoints[x1 + k] = (int)(y1 * (1.0f - x) + y2 * x);
- }
- x1 = i;
- y1 = y2;
- }
- }
-
- /*
- * Get the frequency from x, where x is [0..1]; x is the x coordinate
- */
- float Resonance::getfreqx(float x) const
- {
- const float octf = powf(2.0f, getoctavesfreq());
- return getcenterfreq() / sqrt(octf) * powf(octf, limit(x, 0.0f, 1.0f));
- }
-
- /*
- * Get the x coordinate from frequency (used by the UI)
- */
- float Resonance::getfreqpos(float freq) const
- {
- return (logf(freq) - logf(getfreqx(0.0f))) / logf(2.0f) / getoctavesfreq();
- }
-
- /*
- * Get the center frequency of the resonance graph
- */
- float Resonance::getcenterfreq() const
- {
- return 10000.0f * powf(10, -(1.0f - Pcenterfreq / 127.0f) * 2.0f);
- }
-
- /*
- * Get the number of octave that the resonance functions applies to
- */
- float Resonance::getoctavesfreq() const
- {
- return 0.25f + 10.0f * Poctavesfreq / 127.0f;
- }
-
- void Resonance::sendcontroller(MidiControllers ctl, float par)
- {
- if(ctl == C_resonance_center)
- ctlcenter = par;
- else
- ctlbw = par;
- }
-
- #define COPY(y) this->y = r.y
- void Resonance::paste(Resonance &r)
- {
- COPY(Penabled);
- for(int i=0; i<N_RES_POINTS; ++i)
- this->Prespoints[i] = r.Prespoints[i];
- COPY(PmaxdB);
- COPY(Pcenterfreq);
- COPY(Poctavesfreq);
- COPY(Pprotectthefundamental);
-
- COPY(ctlcenter);
- COPY(ctlbw);
- }
- #undef COPY
-
- void Resonance::add2XML(XMLwrapper& xml)
- {
- xml.addparbool("enabled", Penabled);
-
- if((Penabled == 0) && (xml.minimal))
- return;
-
- xml.addpar("max_db", PmaxdB);
- xml.addpar("center_freq", Pcenterfreq);
- xml.addpar("octaves_freq", Poctavesfreq);
- xml.addparbool("protect_fundamental_frequency", Pprotectthefundamental);
- xml.addpar("resonance_points", N_RES_POINTS);
- for(int i = 0; i < N_RES_POINTS; ++i) {
- xml.beginbranch("RESPOINT", i);
- xml.addpar("val", Prespoints[i]);
- xml.endbranch();
- }
- }
-
-
- void Resonance::getfromXML(XMLwrapper& xml)
- {
- Penabled = xml.getparbool("enabled", Penabled);
-
- PmaxdB = xml.getpar127("max_db", PmaxdB);
- Pcenterfreq = xml.getpar127("center_freq", Pcenterfreq);
- Poctavesfreq = xml.getpar127("octaves_freq", Poctavesfreq);
- Pprotectthefundamental = xml.getparbool("protect_fundamental_frequency",
- Pprotectthefundamental);
- for(int i = 0; i < N_RES_POINTS; ++i) {
- if(xml.enterbranch("RESPOINT", i) == 0)
- continue;
- Prespoints[i] = xml.getpar127("val", Prespoints[i]);
- xml.exitbranch();
- }
- }
-
- }
|