/* 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 version 2 of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License (version 2 or later) for more details. You should have received a copy of the GNU General Public License (version 2) along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "Resonance.h" Resonance::Resonance():Presets() { setpresettype("Presonance"); defaults(); } Resonance::~Resonance() {} void Resonance::defaults() { 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) { if(Penabled == 0) return; //if the resonance is disabled float sum = 0.0f, l1 = logf(getfreqx(0.0f) * ctlcenter), l2 = logf(2.0f) * getoctavesfreq() * ctlbw; for(int i = 0; i < N_RES_POINTS; ++i) if(sum < Prespoints[i]) sum = Prespoints[i]; if(sum < 1.0f) sum = 1.0f; for(int i = 1; i < n; ++i) { float x = (logf(freq * i) - l1) / l2; //compute where the n-th hamonics fits to the graph if(x < 0.0f) x = 0.0f; x *= N_RES_POINTS; float dx = x - floor(x); x = floor(x); int kx1 = (int)x; if(kx1 >= N_RES_POINTS) kx1 = N_RES_POINTS - 1; int kx2 = kx1 + 1; if(kx2 >= N_RES_POINTS) kx2 = N_RES_POINTS - 1; float y = (Prespoints[kx1] * (1.0f - dx) + Prespoints[kx2] * dx) / 127.0f - sum / 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" */ float Resonance::getfreqresponse(float freq) { float l1 = logf(getfreqx(0.0f) * ctlcenter), l2 = logf(2.0f) * getoctavesfreq() * ctlbw, sum = 0.0f; for(int i = 0; i < N_RES_POINTS; ++i) if(sum < Prespoints[i]) sum = Prespoints[i]; if(sum < 1.0f) sum = 1.0f; float x = (logf(freq) - l1) / l2; //compute where the n-th hamonics fits to the graph if(x < 0.0f) x = 0.0f; x *= N_RES_POINTS; float dx = x - floor(x); x = floor(x); int kx1 = (int)x; if(kx1 >= N_RES_POINTS) kx1 = N_RES_POINTS - 1; int kx2 = kx1 + 1; if(kx2 >= N_RES_POINTS) kx2 = N_RES_POINTS - 1; float result = (Prespoints[kx1] * (1.0f - dx) + Prespoints[kx2] * dx) / 127.0f - sum / 127.0f; result = powf(10.0f, result * PmaxdB / 20.0f); return result; } /* * Smooth the resonance function */ void Resonance::smooth() { 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(); } /* * 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) { if(x > 1.0f) x = 1.0f; float octf = powf(2.0f, getoctavesfreq()); return getcenterfreq() / sqrt(octf) * powf(octf, x); } /* * Get the x coordinate from frequency (used by the UI) */ float Resonance::getfreqpos(float freq) { return (logf(freq) - logf(getfreqx(0.0f))) / logf(2.0f) / getoctavesfreq(); } /* * Get the center frequency of the resonance graph */ float Resonance::getcenterfreq() { 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() { 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; } 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(); } }