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 }