FilterParams.cpp (28325B)
1 /* 2 ZynAddSubFX - a software synthesizer 3 4 FilterParams.cpp - Parameters for filter 5 Copyright (C) 2002-2005 Nasca Octavian Paul 6 Copyright (C) 2017 Mark McCurry 7 Author: Nasca Octavian Paul 8 Mark McCurry 9 10 This program is free software; you can redistribute it and/or 11 modify it under the terms of the GNU General Public License 12 as published by the Free Software Foundation; either version 2 13 of the License, or (at your option) any later version. 14 */ 15 16 #include "FilterParams.h" 17 #include "../Misc/Util.h" 18 #include "../Misc/Time.h" 19 #include "../DSP/AnalogFilter.h" 20 #include "../DSP/SVFilter.h" 21 #include <cmath> 22 #include <cstdio> 23 #include <cstdlib> 24 25 #include <rtosc/rtosc.h> 26 #include <rtosc/ports.h> 27 #include <rtosc/port-sugar.h> 28 using namespace rtosc; 29 30 namespace zyn { 31 32 // g++ 4.8 needs this variable saved separately, otherwise it segfaults 33 constexpr int sizeof_pvowels = sizeof(FilterParams::Pvowels); 34 35 #define rObject FilterParams::Pvowels_t::formants_t 36 37 static const rtosc::Ports subsubports = { 38 rParamZyn(loc, rProp(internal), "location of the filter"), 39 rParamZyn(freq, rShort("f.freq"), rDefault(128), 40 rDefaultDepends(loc), 41 rPresets(34, 99, 108, 61, 71, 99, 70, 80, 20, 100), 42 "Formant frequency"), 43 rParamZyn(amp, rShort("f.str"), rDefault(127), 44 rDefaultDepends(loc), 45 rPresets(127, 122, 112, 127, 121, 117, 127, 122, 127, 121), 46 "Strength of formant"), 47 rParamZyn(q, rShort("f.q"), rDefault(64), 48 "The formant's quality factor, also known as " 49 "resonance bandwidth or Q for short"), 50 }; 51 #undef rObject 52 53 static const rtosc::Ports subports = { 54 {"Pformants#" STRINGIFY(FF_MAX_FORMANTS) "/", NULL, &subsubports, 55 [](const char *msg, RtData &d) { 56 const char *mm = msg; 57 while(*mm && !isdigit(*mm)) ++mm; 58 unsigned idx = atoi(mm); 59 60 SNIP; 61 FilterParams::Pvowels_t *obj = (FilterParams::Pvowels_t *) d.obj; 62 d.obj = (void*) &obj->formants[idx]; 63 subsubports.dispatch(msg, d); 64 }}, 65 }; 66 67 68 #define rObject FilterParams 69 #undef rChangeCb 70 #define rChangeCb do { obj->changed = true; if ( obj->time) { \ 71 obj->last_update_timestamp = obj->time->time(); } } while(false) 72 const rtosc::Ports FilterParams::ports = { 73 rSelf(FilterParams), 74 rPasteRt, 75 rArrayPasteRt, 76 rOption(loc, rProp(internal), 77 rOptions(ad_global_filter, ad_voice_filter, sub_filter, in_effect, 78 dynfilter_0, dynfilter_1, dynfilter_2, 79 dynfilter_3, dynfilter_4), 80 "location of the filter"), 81 rOption(Pcategory, rShort("class"), 82 rOptions(analog, formant, st.var., moog, comb), 83 rDefault(analog), rDefaultDepends(loc), 84 rPreset(dynfilter_1, 2), rPreset(dynfilter_3, formant), rPreset(dynfilter_4, formant), 85 "Class of filter"), 86 rOption(Ptype, rShort("type"), 87 rOptions(LP1, HP1, LP2, HP2, BP, notch, peak, l.shelf, h.shelf), 88 rDefault(LP2), rDefaultDepends(loc), 89 rPreset(dynfilter_0, LP2), 90 rPreset(dynfilter_1, LP1), 91 rPreset(dynfilter_2, BP), 92 rPreset(dynfilter_3, LP1), 93 rPreset(dynfilter_4, LP1), 94 "Filter Type"), 95 rParamI(Pstages, rShort("stages"), 96 rLinear(0,5), rDefault(0), rDefaultDepends(loc), 97 rPreset(dynfilter_0, 1), rPreset(dynfilter_2, 2), 98 rPreset(dynfilter_3, 1), rPreset(dynfilter_4, 1), 99 "Filter Stages"), 100 rParamF(baseq, rShort("q"), rUnit(none), rLog(0.1, 1000), 101 rDefaultDepends(loc), 102 rPreset(ad_global_filter, 0x1.1592acp+0), 103 rPreset(ad_voice_filter, 0x1.e2f3ap+1), 104 rPreset(sub_filter, 0x1.1592acp+0), 105 rPreset(in_effect, 0x1.384298p+2), 106 rPreset(dynfilter_0, 0x1.384298p+2), 107 rPreset(dynfilter_1, 0x1.384298p+2), 108 rPreset(dynfilter_2, 0x1.384298p+2), 109 rPreset(dynfilter_3, 0x1.d04b16p+2), 110 rPreset(dynfilter_4, 0x1.d04b16p+2), 111 "Quality Factor (resonance/bandwidth)"), 112 rParamF(basefreq, rShort("cutoff"), 113 rUnit(Hz), rLog(31.25, 32000), 114 rDefaultDepends(loc), 115 rPreset(ad_global_filter, 30313.21f), 116 rPreset(ad_voice_filter, 30313.21f), 117 rPreset(sub_filter, 30313.21f), 118 rPreset(in_effect, 0x1.f3fffcp+9), 119 rPreset(dynfilter_0, 0x1.65673ep+8), 120 rPreset(dynfilter_1, 0x1.818d7ap+10), 121 rPreset(dynfilter_2, 0x1.f3fffcp+9), 122 rPreset(dynfilter_3, 0x1.d48ab6p+8), 123 rPreset(dynfilter_4, 0x1.f3fffcp+9), 124 "Base cutoff frequency"), 125 rParamF(freqtracking, rShort("f.track"), rUnit(%), 126 rLinear(-100, 100), rDefault(0.0f), 127 "Frequency Tracking amount"), 128 rParamF(gain, rShort("gain"), rUnit(dB), 129 rLinear(-30, 30), rDefault(0.0f), 130 "Output Gain"), 131 rParamI(Pnumformants, rShort("formants"), 132 rLinear(1,12), rDefault(3), rDefaultDepends(loc), 133 rPreset(dynfilter_4, 2), 134 "Number of formants to be used"), 135 rParamZyn(Pformantslowness, rShort("slew"), 136 rDefault(64), "Rate that formants change"), 137 rParamZyn(Pvowelclearness, rShort("clarity"), rDefault(64), 138 rDefaultDepends(loc), rPreset(dynfilter_4, 0), 139 "How much each vowel is smudged with the next in sequence. A high clarity will avoid smudging."), 140 rParamZyn(Pcenterfreq, rShort("cutoff"), rDefault(64), 141 "Center Freq (formant)"), 142 rParamZyn(Poctavesfreq, rShort("octaves"), rDefault(64), 143 "Number of octaves for formant"), 144 145 rParamI(Psequencesize, rShort("seq.size"), 146 rLinear(0, FF_MAX_SEQUENCE), 147 rDefault(3), rDefaultDepends(loc), 148 rPreset(dynfilter_3, 2), rPreset(dynfilter_4, 2), 149 "Length of vowel sequence"), 150 rParamZyn(Psequencestretch, rShort("seq.str"), 151 rDefault(40), "How modulators stretch the sequence"), 152 rToggle(Psequencereversed, rShort("reverse"), 153 rDefault(false), "If the modulator input is inverted"), 154 155 {"vowel_seq#" STRINGIFY(FF_MAX_SEQUENCE) "::i", rShort("vowel") rProp(parameter) 156 rDefault([0 1 2 3 4 5 0 1]) 157 rDoc("Vowel number of this sequence position"), NULL, 158 [](const char *msg, RtData &d){ 159 FilterParams *obj = (FilterParams *) d.obj; 160 const char *mm = msg; 161 while(*mm && !isdigit(*mm)) ++mm; 162 unsigned idx = atoi(mm); 163 if(rtosc_narguments(msg)) { 164 obj->Psequence[idx].nvowel = rtosc_argument(msg, 0).i; 165 d.broadcast(d.loc, "i", obj->Psequence[idx].nvowel); 166 } else 167 d.reply(d.loc, "i", obj->Psequence[idx].nvowel); 168 }}, 169 {"type-svf::i:c:S", rProp(parameter) rProp(enumerated) rShort("type") 170 rOptions(low, high, band, notch) 171 rDoc("Filter Type"), 0, rOptionCb(Ptype)}, 172 {"type-moog::i:c:S", rProp(parameter) rProp(enumerated) rShort("type") 173 rOptions(HP, BP, LP) 174 rDoc("Filter Type"), 0, rOptionCb(Ptype)}, 175 {"type-comb::i:c:S", rProp(parameter) rProp(enumerated) rShort("type") 176 rOptions(BWD, FWD, both, BWDN, FWDN, bothN) 177 rDoc("Comb Filter Type"), 0, rOptionCb(Ptype)}, 178 //UI reader 179 {"Pvowels:", rDoc("Get Formant Vowels"), NULL, 180 [](const char *, RtData &d) { 181 FilterParams *obj = (FilterParams *) d.obj; 182 d.reply(d.loc, "b", sizeof_pvowels, obj->Pvowels); 183 }}, 184 185 rEnabledCondition(is_formant_filter, obj->Pcategory == 1), 186 {"Pvowels#" STRINGIFY(FF_MAX_VOWELS) "/", 187 rEnabledByCondition(is_formant_filter), 188 &subports, 189 [](const char *msg, RtData &d) { 190 const char *mm = msg; 191 while(*mm && !isdigit(*mm)) ++mm; 192 unsigned idx = atoi(mm); 193 194 SNIP; 195 FilterParams *obj = (FilterParams *) d.obj; 196 d.obj = (void*)&obj->Pvowels[idx]; 197 subports.dispatch(msg, d); 198 199 if(rtosc_narguments(msg)) 200 rChangeCb; 201 }}, 202 {"centerfreq:", rDoc("Get the center frequency of the formant's graph"), 203 NULL, [](const char *, RtData &d) { 204 FilterParams *obj = (FilterParams *) d.obj; 205 d.reply(d.loc, "f", obj->getcenterfreq()); 206 }}, 207 {"octavesfreq:", 208 rDoc("Get the number of octave that the formant functions applies to"), 209 NULL, [](const char *, RtData &d) { 210 FilterParams *obj = (FilterParams *) d.obj; 211 d.reply(d.loc, "f", obj->getoctavesfreq()); 212 }}, 213 {"q_value:", 214 rDoc("Q value for UI Response Graphs"), 215 NULL, [](const char *, RtData &d) { 216 FilterParams *obj = (FilterParams *) d.obj; 217 d.reply(d.loc, "f", obj->getq()); 218 }}, 219 {"response:", 220 rDoc("Get a frequency response"), 221 NULL, [](const char *, RtData &d) { 222 FilterParams *obj = (FilterParams *) d.obj; 223 if(obj->Pcategory == 0) { 224 int order = 0; 225 float gain = dB2rap(obj->getgain()); 226 if(obj->Ptype != 6 && obj->Ptype != 7 && obj->Ptype != 8) 227 gain = 1.0; 228 auto cf = AnalogFilter::computeCoeff(obj->Ptype, 229 Filter::getrealfreq(obj->getfreq()), 230 obj->getq(), obj->Pstages, 231 gain, 48000, order); 232 if(order == 2) { 233 d.reply(d.loc, "fffffff", 234 (float)obj->Pstages, 235 cf.c[0], cf.c[1], cf.c[2], 236 0.0, cf.d[1], cf.d[2]); 237 } else if(order == 1) { 238 d.reply(d.loc, "fffff", 239 (float)obj->Pstages, 240 cf.c[0], cf.c[1], 241 0.0, cf.d[1]); 242 } 243 } else if(obj->Pcategory == 2) { 244 float gain = dB2rap(obj->getgain()); 245 auto cf = SVFilter::computeResponse(obj->Ptype, 246 Filter::getrealfreq(obj->getfreq()), 247 obj->getq(), obj->Pstages, 248 gain, 48000); 249 d.reply(d.loc, "fffffff", 250 (float)obj->Pstages, 251 cf.b[0], cf.b[1], cf.b[2], 252 0.0, -cf.a[1], -cf.a[2]); 253 } else if(obj->Pcategory == 3) { 254 int order = 0; 255 float gain = dB2rap(obj->getgain()); 256 if(obj->Ptype != 6 && obj->Ptype != 7 && obj->Ptype != 8) 257 gain = 1.0; 258 int tmp = 4-obj->Ptype; 259 if(tmp < 0 || tmp > 8) 260 return; 261 auto cf = AnalogFilter::computeCoeff(4-obj->Ptype, 262 Filter::getrealfreq(obj->getfreq()), 263 obj->getq(), obj->Pstages, 264 gain, 48000, order); 265 d.reply(d.loc, "fffffff", 266 (float)obj->Pstages, 267 cf.c[0], cf.c[1], cf.c[2], 268 0.0, cf.d[1], cf.d[2]); 269 } 270 }}, 271 // "", NULL, [](){}},"/freq" 272 //{"Pvowels#" FF_MAX_VOWELS "/formants#" FF_MAX_FORMANTS "/amp", 273 // "", NULL, [](){}}, 274 //{"Pvowels#" FF_MAX_VOWELS "/formants#" FF_MAX_FORMANTS "/q", 275 // "", NULL, [](){}}, 276 // 277 //struct Pvowels_t { 278 // struct formants_t { 279 // unsigned char freq, amp, q; //frequency,amplitude,Q 280 // } formants[FF_MAX_FORMANTS]; 281 //} Pvowels[FF_MAX_VOWELS]; 282 {"vowels:", 283 rDoc("Get info for formant graph"), 284 NULL, [](const char *, RtData &d) { 285 FilterParams *obj = (FilterParams *) d.obj; 286 287 rtosc_arg_t args[2+3*FF_MAX_FORMANTS*FF_MAX_VOWELS]; 288 char type[2+3*FF_MAX_FORMANTS*FF_MAX_VOWELS + 1] = {}; 289 290 type[0] = 'i'; 291 type[1] = 'i'; 292 293 args[0].i = FF_MAX_VOWELS; 294 args[1].i = FF_MAX_FORMANTS; 295 296 297 for(int i=0; i<FF_MAX_VOWELS; ++i) { 298 auto &val = obj->Pvowels[i]; 299 for(int j=0; j<FF_MAX_FORMANTS; ++j) { 300 auto &f = val.formants[j]; 301 //each formant is 3 arguments 302 //each vowel is FF_MAX_FORMANTS * length of formants long 303 auto *a = args + i*FF_MAX_FORMANTS*3 + j*3 + 2; 304 auto *t = type + i*FF_MAX_FORMANTS*3 + j*3 + 2; 305 a[0].f = obj->getformantfreq(f.freq); 306 a[1].f = obj->getformantamp(f.amp); 307 a[2].f = obj->getformantq(f.q); 308 //printf("<%d,%d,%d,%d,%d,%f,%f,%f>\n", i, j, f.freq, f.amp, f.q, a[0].f, a[1].f, a[2].f); 309 t[0] = t[1] = t[2] = 'f'; 310 } 311 } 312 d.replyArray(d.loc, type, args); 313 }}, 314 315 //Old 0..127 parameter mappings 316 {"Pfreq::i", rLinear(0, 127) rShort("cutoff") rProp(deprecated) rDoc("Center Freq"), 0, 317 [](const char *msg, RtData &d) { 318 FilterParams *obj = (FilterParams*)d.obj; 319 if(rtosc_narguments(msg)) { 320 int Pfreq = rtosc_argument(msg, 0).i; 321 obj->basefreq = basefreqFromOldPreq(Pfreq); 322 rChangeCb; 323 d.broadcast(d.loc, "i", Pfreq); 324 } else { 325 float tmp = obj->basefreq; 326 tmp = log2f(tmp) - 9.96578428f; 327 tmp = (tmp / 5.0 + 1.0) * 64.0f; 328 int Pfreq = roundf(tmp); 329 d.reply(d.loc, "i", Pfreq); 330 } 331 }}, 332 {"Pfreqtrack::i", rLinear(0, 127) rShort("f.track") rProp(deprecated) rDoc("Frequency Tracking amount"), 0, 333 [](const char *msg, RtData &d) { 334 FilterParams *obj = (FilterParams*)d.obj; 335 if(rtosc_narguments(msg)) { 336 int Pfreqtracking = rtosc_argument(msg, 0).i; 337 obj->freqtracking = 100.0f * (Pfreqtracking - 64.0f) / (64.0f); 338 rChangeCb; 339 d.broadcast(d.loc, "i", Pfreqtracking); 340 } else { 341 int Pfreqtracking = static_cast<int>(roundf(((obj->freqtracking/100.0f) * 64.0f + 64.0f))); 342 d.reply(d.loc, "i", Pfreqtracking); 343 } 344 }}, 345 {"Pgain::i", rLinear(0, 127) rShort("gain") rProp(deprecated) rDoc("Output Gain"), 0, 346 [](const char *msg, RtData &d) { 347 FilterParams *obj = (FilterParams*)d.obj; 348 if(rtosc_narguments(msg)) { 349 int Pgain = rtosc_argument(msg, 0).i; 350 obj->gain = gainFromOldPgain(Pgain); //-30..30dB 351 rChangeCb; 352 d.broadcast(d.loc, "i", Pgain); 353 } else { 354 int Pgain = roundf((obj->gain/30.0f + 1.0f) * 64.0f); 355 d.reply(d.loc, "i", Pgain); 356 } 357 }}, 358 {"Pq::i", rLinear(0,127) rShort("q") rProp(deprecated) 359 rDoc("Quality Factor (resonance/bandwidth)"), 0, 360 [](const char *msg, RtData &d) { 361 FilterParams *obj = (FilterParams*)d.obj; 362 if(rtosc_narguments(msg)) { 363 int Pq = rtosc_argument(msg, 0).i; 364 obj->baseq = baseqFromOldPq(Pq); 365 rChangeCb; 366 d.broadcast(d.loc, "i", Pq); 367 } else { 368 int Pq = roundf(127.0f * sqrtf(logf(0.9f + obj->baseq)/logf(1000.0f))); 369 d.reply(d.loc, "i", Pq); 370 } 371 }}, 372 }; 373 #undef rChangeCb 374 #define rChangeCb 375 376 377 378 void FilterParams::setup() 379 { 380 setpresettype("Pfilter"); 381 382 changed = false; 383 defaults(); 384 } 385 386 FilterParams::FilterParams(const AbsTime *time_) 387 :FilterParams(in_effect, time_) 388 { 389 } 390 391 FilterParams::FilterParams(unsigned char Ptype_, 392 unsigned char Pfreq_, 393 unsigned char Pq_, 394 consumer_location_t loc, 395 const AbsTime *time_): 396 loc(loc), time(time_), last_update_timestamp(0), 397 Dtype(Ptype_), Dfreq(Pfreq_), Dq(Pq_) 398 { 399 setup(); 400 } 401 402 FilterParams::FilterParams(consumer_location_t loc, 403 const AbsTime *time_): 404 loc(loc), time(time_), last_update_timestamp(0) 405 { 406 auto init = 407 [&](unsigned char Ptype_, unsigned char Pfreq_, unsigned char Pq_) 408 { 409 Dtype = Ptype_; 410 Dfreq = Pfreq_; 411 Dq = Pq_; 412 }; 413 414 switch(loc) 415 { 416 case ad_global_filter: init(2, 127, 40); break; 417 case ad_voice_filter: init(2, 127, 60); break; 418 case sub_filter: init(2, 127, 40); break; 419 case in_effect: init(0, 64, 64); break; 420 default: throw std::logic_error("Invalid filter consumer location"); 421 } 422 423 setup(); 424 } 425 426 FilterParams::~FilterParams() 427 {} 428 429 430 void FilterParams::defaults() 431 { 432 Ptype = Dtype; 433 434 Pstages = 0; 435 basefreq = (Dfreq / 64.0f - 1.0f) * 5.0f; 436 basefreq = powf(2.0f, basefreq + 9.96578428f); 437 baseq = expf(powf((float) Dq / 127.0f, 2) * logf(1000.0f)) - 0.9f; 438 439 gain = 0.0f; 440 freqtracking = 0.0f; 441 442 Pcategory = 0; 443 444 Pnumformants = 3; 445 Pformantslowness = 64; 446 for(int j = 0; j < FF_MAX_VOWELS; ++j) 447 defaults(j); 448 449 450 Psequencesize = 3; 451 for(int i = 0; i < FF_MAX_SEQUENCE; ++i) 452 Psequence[i].nvowel = i % FF_MAX_VOWELS; 453 454 Psequencestretch = 40; 455 Psequencereversed = 0; 456 Pcenterfreq = 64; //1 kHz 457 Poctavesfreq = 64; 458 Pvowelclearness = 64; 459 } 460 461 void FilterParams::defaults(int n) 462 { 463 int j = n; 464 465 updateLoc(loc, n); 466 for(int i = 0; i < FF_MAX_FORMANTS; ++i) { 467 Pvowels[j].formants[i].freq = (int)(RND * 127.0f); //some random freqs 468 Pvowels[j].formants[i].q = 64; 469 Pvowels[j].formants[i].amp = 127; 470 } 471 } 472 473 void FilterParams::updateLoc(int newloc) 474 { 475 loc = newloc; 476 for(int j = 0; j < FF_MAX_VOWELS; ++j) 477 updateLoc(newloc, j); 478 } 479 480 void FilterParams::updateLoc(int newloc, int n) 481 { 482 int j = n; 483 for(int i = 0; i < FF_MAX_FORMANTS; ++i) 484 { 485 if (newloc == dynfilter_3 && i < 2 && j < 3) 486 { 487 Pvowels[j].formants[i].loc = j * 3 + i; /* 0 .. 5 */ 488 } else if (newloc == dynfilter_4 && i < 2 && j < 2) { 489 Pvowels[j].formants[i].loc = j * 3 + i; /* 6 .. 9 */ 490 } else { 491 Pvowels[j].formants[i].loc = -1; 492 } 493 } 494 } 495 496 497 /* 498 * Get the parameters from other FilterParams 499 */ 500 // WARNING! Function unused since 2004, see declaration in header 501 void FilterParams::getfromFilterParams(const FilterParams *pars) 502 { 503 defaults(); 504 505 if(pars == NULL) 506 return; 507 508 Ptype = pars->Ptype; 509 510 Pstages = pars->Pstages; 511 freqtracking = pars->freqtracking; 512 gain = pars->gain; 513 Pcategory = pars->Pcategory; 514 515 Pnumformants = pars->Pnumformants; 516 Pformantslowness = pars->Pformantslowness; 517 for(int j = 0; j < FF_MAX_VOWELS; ++j) 518 for(int i = 0; i < FF_MAX_FORMANTS; ++i) { 519 Pvowels[j].formants[i].freq = pars->Pvowels[j].formants[i].freq; 520 Pvowels[j].formants[i].q = pars->Pvowels[j].formants[i].q; 521 Pvowels[j].formants[i].amp = pars->Pvowels[j].formants[i].amp; 522 } 523 524 Psequencesize = pars->Psequencesize; 525 for(int i = 0; i < FF_MAX_SEQUENCE; ++i) 526 Psequence[i].nvowel = pars->Psequence[i].nvowel; 527 528 Psequencestretch = pars->Psequencestretch; 529 Psequencereversed = pars->Psequencereversed; 530 Pcenterfreq = pars->Pcenterfreq; 531 Poctavesfreq = pars->Poctavesfreq; 532 Pvowelclearness = pars->Pvowelclearness; 533 } 534 535 536 /* 537 * Parameter control 538 */ 539 float FilterParams::getfreq() const 540 { 541 return log2(basefreq) - log2f(1000.0f); 542 } 543 544 float FilterParams::getq() const 545 { 546 return baseq; 547 } 548 float FilterParams::getfreqtracking(float notefreq) const 549 { 550 return log2f(notefreq / 440.0f) * (freqtracking / 100.0f); 551 } 552 553 float FilterParams::getgain() const 554 { 555 return gain; 556 } 557 558 /* 559 * wrappers old <-> new parameters 560 */ 561 float FilterParams::baseqFromOldPq(int Pq) 562 { 563 return expf(powf((float) Pq / 127.0f, 2) * logf(1000.0f)) - 0.9f; 564 } 565 566 float FilterParams::gainFromOldPgain(int Pgain) 567 { 568 return (Pgain / 64.0f - 1.0f) * 30.0f; //-30..30dB 569 } 570 571 float FilterParams::basefreqFromOldPreq(int Pfreq) 572 { 573 float tmp = (Pfreq / 64.0f - 1.0f) * 5.0f; 574 return powf(2.0f, tmp + 9.96578428f); 575 } 576 577 /* 578 * Get the center frequency of the formant's graph 579 */ 580 float FilterParams::getcenterfreq() const 581 { 582 return 10000.0f * powf(10, -(1.0f - Pcenterfreq / 127.0f) * 2.0f); 583 } 584 585 /* 586 * Get the number of octave that the formant functions applies to 587 */ 588 float FilterParams::getoctavesfreq() const 589 { 590 return 0.25f + 10.0f * Poctavesfreq / 127.0f; 591 } 592 593 /* 594 * Get the frequency from x, where x is [0..1] 595 */ 596 float FilterParams::getfreqx(float x) const 597 { 598 if(x > 1.0f) 599 x = 1.0f; 600 float octf = powf(2.0f, getoctavesfreq()); 601 return getcenterfreq() / sqrt(octf) * powf(octf, x); 602 } 603 604 /* 605 * Get the x coordinate from frequency (used by the UI) 606 */ 607 float FilterParams::getfreqpos(float freq) const 608 { 609 return (logf(freq) - logf(getfreqx(0.0f))) / logf(2.0f) / getoctavesfreq(); 610 } 611 612 /* 613 * Transforms a parameter to the real value 614 */ 615 float FilterParams::getformantfreq(unsigned char freq) const 616 { 617 return getfreqx(freq / 127.0f); 618 } 619 620 float FilterParams::getformantamp(unsigned char amp) const 621 { 622 return powf(0.1f, (1.0f - amp / 127.0f) * 4.0f); 623 } 624 625 float FilterParams::getformantq(unsigned char q) const 626 { 627 //temp 628 return powf(25.0f, (q - 32.0f) / 64.0f); 629 } 630 631 632 633 void FilterParams::add2XMLsection(XMLwrapper& xml, int n) 634 { 635 int nvowel = n; 636 for(int nformant = 0; nformant < FF_MAX_FORMANTS; ++nformant) { 637 xml.beginbranch("FORMANT", nformant); 638 xml.addpar("freq", Pvowels[nvowel].formants[nformant].freq); 639 xml.addpar("amp", Pvowels[nvowel].formants[nformant].amp); 640 xml.addpar("q", Pvowels[nvowel].formants[nformant].q); 641 xml.endbranch(); 642 } 643 } 644 645 void FilterParams::add2XML(XMLwrapper& xml) 646 { 647 //filter parameters 648 xml.addpar("category", Pcategory); 649 xml.addpar("type", Ptype); 650 xml.addparreal("basefreq", basefreq); 651 xml.addparreal("baseq", baseq); 652 xml.addpar("stages", Pstages); 653 xml.addparreal("freq_tracking", freqtracking); 654 xml.addparreal("gain", gain); 655 656 //formant filter parameters 657 if((Pcategory == 1) || (!xml.minimal)) { 658 xml.beginbranch("FORMANT_FILTER"); 659 xml.addpar("num_formants", Pnumformants); 660 xml.addpar("formant_slowness", Pformantslowness); 661 xml.addpar("vowel_clearness", Pvowelclearness); 662 xml.addpar("center_freq", Pcenterfreq); 663 xml.addpar("octaves_freq", Poctavesfreq); 664 for(int nvowel = 0; nvowel < FF_MAX_VOWELS; ++nvowel) { 665 xml.beginbranch("VOWEL", nvowel); 666 add2XMLsection(xml, nvowel); 667 xml.endbranch(); 668 } 669 xml.addpar("sequence_size", Psequencesize); 670 xml.addpar("sequence_stretch", Psequencestretch); 671 xml.addparbool("sequence_reversed", Psequencereversed); 672 for(int nseq = 0; nseq < FF_MAX_SEQUENCE; ++nseq) { 673 xml.beginbranch("SEQUENCE_POS", nseq); 674 xml.addpar("vowel_id", Psequence[nseq].nvowel); 675 xml.endbranch(); 676 } 677 xml.endbranch(); 678 } 679 } 680 681 682 void FilterParams::getfromXMLsection(XMLwrapper& xml, int n) 683 { 684 int nvowel = n; 685 for(int nformant = 0; nformant < FF_MAX_FORMANTS; ++nformant) { 686 if(xml.enterbranch("FORMANT", nformant) == 0) 687 continue; 688 Pvowels[nvowel].formants[nformant].freq = xml.getpar127( 689 "freq", 690 Pvowels[nvowel 691 ].formants[nformant].freq); 692 Pvowels[nvowel].formants[nformant].amp = xml.getpar127( 693 "amp", 694 Pvowels[nvowel 695 ].formants[nformant].amp); 696 Pvowels[nvowel].formants[nformant].q = 697 xml.getpar127("q", Pvowels[nvowel].formants[nformant].q); 698 xml.exitbranch(); 699 } 700 } 701 702 void FilterParams::getfromXML(XMLwrapper& xml) 703 { 704 const bool upgrade_3_0_2 = (xml.fileversion() < version_type(3,0,2)) && (xml.getparreal("basefreq", -1) < 0); 705 706 //filter parameters 707 Pcategory = xml.getpar127("category", Pcategory); 708 Ptype = xml.getpar127("type", Ptype); 709 Pstages = xml.getpar127("stages", Pstages); 710 if(upgrade_3_0_2) { 711 int Pfreq = xml.getpar127("freq", 0); 712 basefreq = (Pfreq / 64.0f - 1.0f) * 5.0f; 713 basefreq = powf(2.0f, basefreq + 9.96578428f); 714 int Pq = xml.getpar127("q", 0); 715 baseq = expf(powf((float) Pq / 127.0f, 2) * logf(1000.0f)) - 0.9f; 716 int Pgain = xml.getpar127("gain", 0); 717 gain = (Pgain / 64.0f - 1.0f) * 30.0f; //-30..30dB 718 int Pfreqtracking = xml.getpar127("freq_track", 0); 719 freqtracking = 100 * (Pfreqtracking - 64.0f) / (64.0f); 720 } else { 721 basefreq = xml.getparreal("basefreq", 1000); 722 baseq = xml.getparreal("baseq", 10); 723 gain = xml.getparreal("gain", 0); 724 freqtracking = xml.getparreal("freq_tracking", 0); 725 } 726 float basefreq_min = std::atof(ports["basefreq"]->meta()["min"]); 727 basefreq = std::max(basefreq, basefreq_min); 728 729 //formant filter parameters 730 if(xml.enterbranch("FORMANT_FILTER")) { 731 Pnumformants = xml.getpar127("num_formants", Pnumformants); 732 Pformantslowness = xml.getpar127("formant_slowness", Pformantslowness); 733 Pvowelclearness = xml.getpar127("vowel_clearness", Pvowelclearness); 734 Pcenterfreq = xml.getpar127("center_freq", Pcenterfreq); 735 Poctavesfreq = xml.getpar127("octaves_freq", Poctavesfreq); 736 737 for(int nvowel = 0; nvowel < FF_MAX_VOWELS; ++nvowel) { 738 if(xml.enterbranch("VOWEL", nvowel) == 0) 739 continue; 740 getfromXMLsection(xml, nvowel); 741 xml.exitbranch(); 742 } 743 Psequencesize = xml.getpar127("sequence_size", Psequencesize); 744 Psequencestretch = xml.getpar127("sequence_stretch", Psequencestretch); 745 Psequencereversed = xml.getparbool("sequence_reversed", 746 Psequencereversed); 747 for(int nseq = 0; nseq < FF_MAX_SEQUENCE; ++nseq) { 748 if(xml.enterbranch("SEQUENCE_POS", nseq) == 0) 749 continue; 750 Psequence[nseq].nvowel = xml.getpar("vowel_id", 751 Psequence[nseq].nvowel, 752 0, 753 FF_MAX_VOWELS - 1); 754 xml.exitbranch(); 755 } 756 xml.exitbranch(); 757 } 758 } 759 760 #define COPY(y) this->y = x.y 761 void FilterParams::paste(FilterParams &x) 762 { 763 COPY(Pcategory); 764 COPY(Ptype); 765 COPY(basefreq); 766 COPY(Pstages); 767 COPY(freqtracking); 768 COPY(gain); 769 770 COPY(Pnumformants); 771 COPY(Pformantslowness); 772 COPY(Pvowelclearness); 773 COPY(Pcenterfreq); 774 COPY(Poctavesfreq); 775 776 for(int i=0; i<FF_MAX_VOWELS; ++i) { 777 for(int j=0; j<FF_MAX_FORMANTS; ++j) { 778 auto &a = this->Pvowels[i].formants[j]; 779 auto &b = x.Pvowels[i].formants[j]; 780 a.freq = b.freq; 781 a.amp = b.amp; 782 a.q = b.q; 783 } 784 } 785 786 787 COPY(Psequencesize); 788 COPY(Psequencestretch); 789 COPY(Psequencereversed); 790 for(int i=0; i<FF_MAX_SEQUENCE; ++i) 791 this->Psequence[i] = x.Psequence[i]; 792 793 COPY(changed); 794 795 if ( time ) { 796 last_update_timestamp = time->time(); 797 } 798 } 799 #undef COPY 800 801 void FilterParams::pasteArray(FilterParams &x, int nvowel) 802 { 803 for(int nformant = 0; nformant < FF_MAX_FORMANTS; ++nformant) { 804 auto &self = Pvowels[nvowel].formants[nformant]; 805 auto &update = x.Pvowels[nvowel].formants[nformant]; 806 self.freq = update.freq; 807 self.amp = update.amp; 808 self.q = update.q; 809 } 810 811 if ( time ) { 812 last_update_timestamp = time->time(); 813 } 814 } 815 816 }