Add python3 to github action test deps
[zynaddsubfx-code.git] / src / Params / FilterParams.cpp
blobcac633c8681200634018bb573644b837561745cc
1 /*
2 ZynAddSubFX - a software synthesizer
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
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.
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>
25 #include <rtosc/rtosc.h>
26 #include <rtosc/ports.h>
27 #include <rtosc/port-sugar.h>
28 using namespace rtosc;
30 namespace zyn {
32 // g++ 4.8 needs this variable saved separately, otherwise it segfaults
33 constexpr int sizeof_pvowels = sizeof(FilterParams::Pvowels);
35 #define rObject FilterParams::Pvowels_t::formants_t
37 static const rtosc::Ports subsubports = {
38 rParamZyn(freq, rShort("f.freq"), "Formant frequency"),
39 rParamZyn(amp, rShort("f.str"), rDefault(127), "Strength of formant"),
40 rParamZyn(q, rShort("f.q"), rDefault(64),
41 "The formant's quality factor, also known as "
42 "resonance bandwidth or Q for short"),
44 #undef rObject
46 static const rtosc::Ports subports = {
47 {"Pformants#" STRINGIFY(FF_MAX_FORMANTS) "/", NULL, &subsubports,
48 [](const char *msg, RtData &d) {
49 const char *mm = msg;
50 while(*mm && !isdigit(*mm)) ++mm;
51 unsigned idx = atoi(mm);
53 SNIP;
54 FilterParams::Pvowels_t *obj = (FilterParams::Pvowels_t *) d.obj;
55 d.obj = (void*) &obj->formants[idx];
56 subsubports.dispatch(msg, d);
57 }},
60 #define rObject FilterParams
61 #undef rChangeCb
62 #define rChangeCb do { obj->changed = true; if ( obj->time) { \
63 obj->last_update_timestamp = obj->time->time(); } } while(false)
64 const rtosc::Ports FilterParams::ports = {
65 rSelf(FilterParams),
66 rPaste,
67 rArrayPaste,
68 rOption(loc, rProp(internal),
69 rOptions(ad_global_filter, ad_voice_filter, sub_filter, in_effect),
70 "location of the filter"),
71 rOption(Pcategory, rShort("class"),
72 rOptions(analog, formant, st.var.), rDefault(analog),
73 "Class of filter"),
74 rOption(Ptype, rShort("type"),
75 rOptions(LP1, HP1, LP2, HP2, BP, notch, peak, l.shelf, h.shelf),
76 rDefault(LP2), "Filter Type"),
77 rParamI(Pstages, rShort("stages"),
78 rLinear(0,5), rDefault(0), "Filter Stages"),
79 rParamF(baseq, rShort("q"), rUnit(none), rLog(0.1, 1000),
80 rDefaultDepends(loc),
81 rPreset(ad_global_filter, 0x1.1592acp+0),
82 rPreset(ad_voice_filter, 0x1.e2f3ap+1),
83 rPreset(sub_filter, 0x1.1592acp+0),
84 rPreset(in_effect, 0x1.384298p+2),
85 "Quality Factor (resonance/bandwidth)"),
86 rParamF(basefreq, rShort("cutoff"),
87 rUnit(Hz), rLog(31.25, 32000),
88 rDefaultDepends(loc),
89 rPreset(ad_global_filter, 32000),
90 rPreset(ad_voice_filter, 32000),
91 rPreset(sub_filter, 32000),
92 rPreset(in_effect, 0x1.f3fffcp+9),
93 "Base cutoff frequency"),
94 rParamF(freqtracking, rShort("f.track"), rUnit(%),
95 rLinear(-100, 100), rDefault(0.0f),
96 "Frequency Tracking amount"),
97 rParamF(gain, rShort("gain"), rUnit(dB),
98 rLinear(-30, 30), rDefault(0.0f),
99 "Output Gain"),
100 rParamI(Pnumformants, rShort("formants"),
101 rLinear(1,12), rDefault(3),
102 "Number of formants to be used"),
103 rParamZyn(Pformantslowness, rShort("slew"),
104 rDefault(64), "Rate that formants change"),
105 rParamZyn(Pvowelclearness, rShort("clarity"), rDefault(64),
106 "How much each vowel is smudged with the next in sequence. A high clarity will avoid smudging."),
107 rParamZyn(Pcenterfreq, rShort("cutoff"), rDefault(64),
108 "Center Freq (formant)"),
109 rParamZyn(Poctavesfreq, rShort("octaves"), rDefault(64),
110 "Number of octaves for formant"),
112 rParamI(Psequencesize, rShort("seq.size"),
113 rLinear(0, FF_MAX_SEQUENCE), rDefault(3), "Length of vowel sequence"),
114 rParamZyn(Psequencestretch, rShort("seq.str"),
115 rDefault(40), "How modulators stretch the sequence"),
116 rToggle(Psequencereversed, rShort("reverse"),
117 rDefault(false), "If the modulator input is inverted"),
119 {"vowel_seq#" STRINGIFY(FF_MAX_SEQUENCE) "::i", rShort("vowel") rDoc("Vowel number of this sequence position"), NULL,
120 [](const char *msg, RtData &d){
121 FilterParams *obj = (FilterParams *) d.obj;
122 const char *mm = msg;
123 while(*mm && !isdigit(*mm)) ++mm;
124 unsigned idx = atoi(mm);
125 if(rtosc_narguments(msg)) {
126 obj->Psequence[idx].nvowel = rtosc_argument(msg, 0).i;
127 d.broadcast(d.loc, "i", obj->Psequence[idx].nvowel);
128 } else
129 d.reply(d.loc, "i", obj->Psequence[idx].nvowel);
131 {"type-svf::i", rProp(parameter) rShort("type")
132 rOptions(low, high, band, notch)
133 rDoc("Filter Type"), 0, rOptionCb(Ptype)},
135 //UI reader
136 {"Pvowels:", rDoc("Get Formant Vowels"), NULL,
137 [](const char *, RtData &d) {
138 FilterParams *obj = (FilterParams *) d.obj;
139 d.reply(d.loc, "b", sizeof_pvowels, obj->Pvowels);
142 rEnabledCondition(is_formant_filter, obj->Pcategory == 1),
143 {"Pvowels#" STRINGIFY(FF_MAX_VOWELS) "/",
144 rEnabledByCondition(is_formant_filter),
145 &subports,
146 [](const char *msg, RtData &d) {
147 const char *mm = msg;
148 while(*mm && !isdigit(*mm)) ++mm;
149 unsigned idx = atoi(mm);
151 SNIP;
152 FilterParams *obj = (FilterParams *) d.obj;
153 d.obj = (void*)&obj->Pvowels[idx];
154 subports.dispatch(msg, d);
156 if(rtosc_narguments(msg))
157 rChangeCb;
159 {"centerfreq:", rDoc("Get the center frequency of the formant's graph"),
160 NULL, [](const char *, RtData &d) {
161 FilterParams *obj = (FilterParams *) d.obj;
162 d.reply(d.loc, "f", obj->getcenterfreq());
164 {"octavesfreq:",
165 rDoc("Get the number of octave that the formant functions applies to"),
166 NULL, [](const char *, RtData &d) {
167 FilterParams *obj = (FilterParams *) d.obj;
168 d.reply(d.loc, "f", obj->getoctavesfreq());
170 {"q_value:",
171 rDoc("Q value for UI Response Graphs"),
172 NULL, [](const char *, RtData &d) {
173 FilterParams *obj = (FilterParams *) d.obj;
174 d.reply(d.loc, "f", obj->getq());
176 {"response:",
177 rDoc("Get a frequency response"),
178 NULL, [](const char *, RtData &d) {
179 FilterParams *obj = (FilterParams *) d.obj;
180 if(obj->Pcategory == 0) {
181 int order = 0;
182 float gain = dB2rap(obj->getgain());
183 if(obj->Ptype != 6 && obj->Ptype != 7 && obj->Ptype != 8)
184 gain = 1.0;
185 auto cf = AnalogFilter::computeCoeff(obj->Ptype,
186 Filter::getrealfreq(obj->getfreq()),
187 obj->getq(), obj->Pstages,
188 gain, 48000, order);
189 if(order == 2) {
190 d.reply(d.loc, "fffffff",
191 (float)obj->Pstages,
192 cf.c[0], cf.c[1], cf.c[2],
193 0.0, cf.d[1], cf.d[2]);
194 } else if(order == 1) {
195 d.reply(d.loc, "fffff",
196 (float)obj->Pstages,
197 cf.c[0], cf.c[1],
198 0.0, cf.d[1]);
200 } else if(obj->Pcategory == 2) {
201 float gain = dB2rap(obj->getgain());
202 auto cf = SVFilter::computeResponse(obj->Ptype,
203 Filter::getrealfreq(obj->getfreq()),
204 obj->getq(), obj->Pstages,
205 gain, 48000);
206 d.reply(d.loc, "fffffff",
207 (float)obj->Pstages,
208 cf.b[0], cf.b[1], cf.b[2],
209 0.0, -cf.a[1], -cf.a[2]);
212 // "", NULL, [](){}},"/freq"
213 //{"Pvowels#" FF_MAX_VOWELS "/formants#" FF_MAX_FORMANTS "/amp",
214 // "", NULL, [](){}},
215 //{"Pvowels#" FF_MAX_VOWELS "/formants#" FF_MAX_FORMANTS "/q",
216 // "", NULL, [](){}},
218 //struct Pvowels_t {
219 // struct formants_t {
220 // unsigned char freq, amp, q; //frequency,amplitude,Q
221 // } formants[FF_MAX_FORMANTS];
222 //} Pvowels[FF_MAX_VOWELS];
223 {"vowels:",
224 rDoc("Get info for formant graph"),
225 NULL, [](const char *, RtData &d) {
226 FilterParams *obj = (FilterParams *) d.obj;
228 rtosc_arg_t args[2+3*FF_MAX_FORMANTS*FF_MAX_VOWELS];
229 char type[2+3*FF_MAX_FORMANTS*FF_MAX_VOWELS + 1] = {};
231 type[0] = 'i';
232 type[1] = 'i';
234 args[0].i = FF_MAX_VOWELS;
235 args[1].i = FF_MAX_FORMANTS;
238 for(int i=0; i<FF_MAX_VOWELS; ++i) {
239 auto &val = obj->Pvowels[i];
240 for(int j=0; j<FF_MAX_FORMANTS; ++j) {
241 auto &f = val.formants[j];
242 //each formant is 3 arguments
243 //each vowel is FF_MAX_FORMANTS * length of formants long
244 auto *a = args + i*FF_MAX_FORMANTS*3 + j*3 + 2;
245 auto *t = type + i*FF_MAX_FORMANTS*3 + j*3 + 2;
246 a[0].f = obj->getformantfreq(f.freq);
247 a[1].f = obj->getformantamp(f.amp);
248 a[2].f = obj->getformantq(f.q);
249 //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);
250 t[0] = t[1] = t[2] = 'f';
253 d.replyArray(d.loc, type, args);
256 //Old 0..127 parameter mappings
257 {"Pfreq::i", rLinear(0, 127) rShort("cutoff") rProp(deprecated) rDoc("Center Freq"), 0,
258 [](const char *msg, RtData &d) {
259 FilterParams *obj = (FilterParams*)d.obj;
260 if(rtosc_narguments(msg)) {
261 int Pfreq = rtosc_argument(msg, 0).i;
262 obj->basefreq = (Pfreq / 64.0f - 1.0f) * 5.0f;
263 obj->basefreq = powf(2.0f, obj->basefreq + 9.96578428f);
264 rChangeCb;
265 d.broadcast(d.loc, "i", Pfreq);
266 } else {
267 float tmp = obj->basefreq;
268 tmp = log2f(tmp) - 9.96578428f;
269 tmp = (tmp / 5.0 + 1.0) * 64.0f;
270 int Pfreq = roundf(tmp);
271 d.reply(d.loc, "i", Pfreq);
274 {"Pfreqtrack::i", rLinear(0, 127) rShort("f.track") rProp(deprecated) rDoc("Frequency Tracking amount"), 0,
275 [](const char *msg, RtData &d) {
276 FilterParams *obj = (FilterParams*)d.obj;
277 if(rtosc_narguments(msg)) {
278 int Pfreqtracking = rtosc_argument(msg, 0).i;
279 obj->freqtracking = 100 * (Pfreqtracking - 64.0f) / (64.0f);
280 rChangeCb;
281 d.broadcast(d.loc, "i", Pfreqtracking);
282 } else {
283 int Pfreqtracking = obj->freqtracking/100.0*64.0 + 64.0;
284 d.reply(d.loc, "i", Pfreqtracking);
287 {"Pgain::i", rLinear(0, 127) rShort("gain") rProp(deprecated) rDoc("Output Gain"), 0,
288 [](const char *msg, RtData &d) {
289 FilterParams *obj = (FilterParams*)d.obj;
290 if(rtosc_narguments(msg)) {
291 int Pgain = rtosc_argument(msg, 0).i;
292 obj->gain = (Pgain / 64.0f - 1.0f) * 30.0f; //-30..30dB
293 rChangeCb;
294 d.broadcast(d.loc, "i", Pgain);
295 } else {
296 int Pgain = roundf((obj->gain/30.0f + 1.0f) * 64.0f);
297 d.reply(d.loc, "i", Pgain);
300 {"Pq::i", rLinear(0,127) rShort("q") rProp(deprecated)
301 rDoc("Quality Factor (resonance/bandwidth)"), 0,
302 [](const char *msg, RtData &d) {
303 FilterParams *obj = (FilterParams*)d.obj;
304 if(rtosc_narguments(msg)) {
305 int Pq = rtosc_argument(msg, 0).i;
306 obj->baseq = expf(powf((float) Pq / 127.0f, 2) * logf(1000.0f)) - 0.9f;
307 rChangeCb;
308 d.broadcast(d.loc, "i", Pq);
309 } else {
310 int Pq = roundf(127.0f * sqrtf(logf(0.9f + obj->baseq)/logf(1000.0f)));
311 d.reply(d.loc, "i", Pq);
315 #undef rChangeCb
316 #define rChangeCb
320 void FilterParams::setup()
322 setpresettype("Pfilter");
324 changed = false;
325 defaults();
328 FilterParams::FilterParams(const AbsTime *time_)
329 :FilterParams(in_effect, time_)
333 FilterParams::FilterParams(unsigned char Ptype_,
334 unsigned char Pfreq_,
335 unsigned char Pq_,
336 consumer_location_t loc,
337 const AbsTime *time_):
338 loc(loc), time(time_), last_update_timestamp(0),
339 Dtype(Ptype_), Dfreq(Pfreq_), Dq(Pq_)
341 setup();
344 FilterParams::FilterParams(consumer_location_t loc,
345 const AbsTime *time_):
346 loc(loc), time(time_), last_update_timestamp(0)
348 auto init =
349 [&](unsigned char Ptype_, unsigned char Pfreq_, unsigned char Pq_)
351 Dtype = Ptype_;
352 Dfreq = Pfreq_;
353 Dq = Pq_;
356 switch(loc)
358 case ad_global_filter: init(2, 127, 40); break;
359 case ad_voice_filter: init(2, 127, 60); break;
360 case sub_filter: init(2, 127, 40); break;
361 case in_effect: init(0, 64, 64); break;
362 default: throw std::logic_error("Invalid filter consumer location");
365 setup();
368 FilterParams::~FilterParams()
372 void FilterParams::defaults()
374 Ptype = Dtype;
375 Pfreq = Dfreq;
376 Pq = Dq;
378 Pstages = 0;
379 basefreq = (Pfreq / 64.0f - 1.0f) * 5.0f;
380 basefreq = powf(2.0f, basefreq + 9.96578428f);
381 baseq = expf(powf((float) Pq / 127.0f, 2) * logf(1000.0f)) - 0.9f;
383 gain = 0.0f;
384 freqtracking = 0.0f;
386 Pcategory = 0;
388 Pnumformants = 3;
389 Pformantslowness = 64;
390 for(int j = 0; j < FF_MAX_VOWELS; ++j)
391 defaults(j);
394 Psequencesize = 3;
395 for(int i = 0; i < FF_MAX_SEQUENCE; ++i)
396 Psequence[i].nvowel = i % FF_MAX_VOWELS;
398 Psequencestretch = 40;
399 Psequencereversed = 0;
400 Pcenterfreq = 64; //1 kHz
401 Poctavesfreq = 64;
402 Pvowelclearness = 64;
405 void FilterParams::defaults(int n)
407 int j = n;
409 for(int i = 0; i < FF_MAX_FORMANTS; ++i) {
410 Pvowels[j].formants[i].freq = (int)(RND * 127.0f); //some random freqs
411 Pvowels[j].formants[i].q = 64;
412 Pvowels[j].formants[i].amp = 127;
418 * Get the parameters from other FilterParams
420 // WARNING! Function unused since 2004, see declaration in header
421 void FilterParams::getfromFilterParams(const FilterParams *pars)
423 defaults();
425 if(pars == NULL)
426 return;
428 Ptype = pars->Ptype;
429 Pfreq = pars->Pfreq;
430 Pq = pars->Pq;
432 Pstages = pars->Pstages;
433 freqtracking = pars->freqtracking;
434 gain = pars->gain;
435 Pcategory = pars->Pcategory;
437 Pnumformants = pars->Pnumformants;
438 Pformantslowness = pars->Pformantslowness;
439 for(int j = 0; j < FF_MAX_VOWELS; ++j)
440 for(int i = 0; i < FF_MAX_FORMANTS; ++i) {
441 Pvowels[j].formants[i].freq = pars->Pvowels[j].formants[i].freq;
442 Pvowels[j].formants[i].q = pars->Pvowels[j].formants[i].q;
443 Pvowels[j].formants[i].amp = pars->Pvowels[j].formants[i].amp;
446 Psequencesize = pars->Psequencesize;
447 for(int i = 0; i < FF_MAX_SEQUENCE; ++i)
448 Psequence[i].nvowel = pars->Psequence[i].nvowel;
450 Psequencestretch = pars->Psequencestretch;
451 Psequencereversed = pars->Psequencereversed;
452 Pcenterfreq = pars->Pcenterfreq;
453 Poctavesfreq = pars->Poctavesfreq;
454 Pvowelclearness = pars->Pvowelclearness;
459 * Parameter control
461 float FilterParams::getfreq() const
463 return log2(basefreq) - log2f(1000.0f);
466 float FilterParams::getq() const
468 return baseq;
470 float FilterParams::getfreqtracking(float notefreq) const
472 return log2f(notefreq / 440.0f) * (freqtracking / 100.0f);
475 float FilterParams::getgain() const
477 return gain;
481 * Get the center frequency of the formant's graph
483 float FilterParams::getcenterfreq() const
485 return 10000.0f * powf(10, -(1.0f - Pcenterfreq / 127.0f) * 2.0f);
489 * Get the number of octave that the formant functions applies to
491 float FilterParams::getoctavesfreq() const
493 return 0.25f + 10.0f * Poctavesfreq / 127.0f;
497 * Get the frequency from x, where x is [0..1]
499 float FilterParams::getfreqx(float x) const
501 if(x > 1.0f)
502 x = 1.0f;
503 float octf = powf(2.0f, getoctavesfreq());
504 return getcenterfreq() / sqrt(octf) * powf(octf, x);
508 * Get the x coordinate from frequency (used by the UI)
510 float FilterParams::getfreqpos(float freq) const
512 return (logf(freq) - logf(getfreqx(0.0f))) / logf(2.0f) / getoctavesfreq();
516 * Transforms a parameter to the real value
518 float FilterParams::getformantfreq(unsigned char freq) const
520 return getfreqx(freq / 127.0f);
523 float FilterParams::getformantamp(unsigned char amp) const
525 return powf(0.1f, (1.0f - amp / 127.0f) * 4.0f);
528 float FilterParams::getformantq(unsigned char q) const
530 //temp
531 return powf(25.0f, (q - 32.0f) / 64.0f);
536 void FilterParams::add2XMLsection(XMLwrapper& xml, int n)
538 int nvowel = n;
539 for(int nformant = 0; nformant < FF_MAX_FORMANTS; ++nformant) {
540 xml.beginbranch("FORMANT", nformant);
541 xml.addpar("freq", Pvowels[nvowel].formants[nformant].freq);
542 xml.addpar("amp", Pvowels[nvowel].formants[nformant].amp);
543 xml.addpar("q", Pvowels[nvowel].formants[nformant].q);
544 xml.endbranch();
548 void FilterParams::add2XML(XMLwrapper& xml)
550 //filter parameters
551 xml.addpar("category", Pcategory);
552 xml.addpar("type", Ptype);
553 xml.addparreal("basefreq", basefreq);
554 xml.addparreal("baseq", baseq);
555 xml.addpar("stages", Pstages);
556 xml.addparreal("freq_tracking", freqtracking);
557 xml.addparreal("gain", gain);
559 //formant filter parameters
560 if((Pcategory == 1) || (!xml.minimal)) {
561 xml.beginbranch("FORMANT_FILTER");
562 xml.addpar("num_formants", Pnumformants);
563 xml.addpar("formant_slowness", Pformantslowness);
564 xml.addpar("vowel_clearness", Pvowelclearness);
565 xml.addpar("center_freq", Pcenterfreq);
566 xml.addpar("octaves_freq", Poctavesfreq);
567 for(int nvowel = 0; nvowel < FF_MAX_VOWELS; ++nvowel) {
568 xml.beginbranch("VOWEL", nvowel);
569 add2XMLsection(xml, nvowel);
570 xml.endbranch();
572 xml.addpar("sequence_size", Psequencesize);
573 xml.addpar("sequence_stretch", Psequencestretch);
574 xml.addparbool("sequence_reversed", Psequencereversed);
575 for(int nseq = 0; nseq < FF_MAX_SEQUENCE; ++nseq) {
576 xml.beginbranch("SEQUENCE_POS", nseq);
577 xml.addpar("vowel_id", Psequence[nseq].nvowel);
578 xml.endbranch();
580 xml.endbranch();
585 void FilterParams::getfromXMLsection(XMLwrapper& xml, int n)
587 int nvowel = n;
588 for(int nformant = 0; nformant < FF_MAX_FORMANTS; ++nformant) {
589 if(xml.enterbranch("FORMANT", nformant) == 0)
590 continue;
591 Pvowels[nvowel].formants[nformant].freq = xml.getpar127(
592 "freq",
593 Pvowels[nvowel
594 ].formants[nformant].freq);
595 Pvowels[nvowel].formants[nformant].amp = xml.getpar127(
596 "amp",
597 Pvowels[nvowel
598 ].formants[nformant].amp);
599 Pvowels[nvowel].formants[nformant].q =
600 xml.getpar127("q", Pvowels[nvowel].formants[nformant].q);
601 xml.exitbranch();
605 void FilterParams::getfromXML(XMLwrapper& xml)
607 const bool upgrade_3_0_2 = (xml.fileversion() < version_type(3,0,2)) && (xml.getparreal("basefreq", -1) < 0);
609 //filter parameters
610 Pcategory = xml.getpar127("category", Pcategory);
611 Ptype = xml.getpar127("type", Ptype);
612 Pstages = xml.getpar127("stages", Pstages);
613 if(upgrade_3_0_2) {
614 int Pfreq = xml.getpar127("freq", 0);
615 basefreq = (Pfreq / 64.0f - 1.0f) * 5.0f;
616 basefreq = powf(2.0f, basefreq + 9.96578428f);
617 int Pq = xml.getpar127("q", 0);
618 baseq = expf(powf((float) Pq / 127.0f, 2) * logf(1000.0f)) - 0.9f;
619 int Pgain = xml.getpar127("gain", 0);
620 gain = (Pgain / 64.0f - 1.0f) * 30.0f; //-30..30dB
621 int Pfreqtracking = xml.getpar127("freq_track", 0);
622 freqtracking = 100 * (Pfreqtracking - 64.0f) / (64.0f);
623 } else {
624 basefreq = xml.getparreal("basefreq", 1000);
625 baseq = xml.getparreal("baseq", 10);
626 gain = xml.getparreal("gain", 0);
627 freqtracking = xml.getparreal("freq_tracking", 0);
630 //formant filter parameters
631 if(xml.enterbranch("FORMANT_FILTER")) {
632 Pnumformants = xml.getpar127("num_formants", Pnumformants);
633 Pformantslowness = xml.getpar127("formant_slowness", Pformantslowness);
634 Pvowelclearness = xml.getpar127("vowel_clearness", Pvowelclearness);
635 Pcenterfreq = xml.getpar127("center_freq", Pcenterfreq);
636 Poctavesfreq = xml.getpar127("octaves_freq", Poctavesfreq);
638 for(int nvowel = 0; nvowel < FF_MAX_VOWELS; ++nvowel) {
639 if(xml.enterbranch("VOWEL", nvowel) == 0)
640 continue;
641 getfromXMLsection(xml, nvowel);
642 xml.exitbranch();
644 Psequencesize = xml.getpar127("sequence_size", Psequencesize);
645 Psequencestretch = xml.getpar127("sequence_stretch", Psequencestretch);
646 Psequencereversed = xml.getparbool("sequence_reversed",
647 Psequencereversed);
648 for(int nseq = 0; nseq < FF_MAX_SEQUENCE; ++nseq) {
649 if(xml.enterbranch("SEQUENCE_POS", nseq) == 0)
650 continue;
651 Psequence[nseq].nvowel = xml.getpar("vowel_id",
652 Psequence[nseq].nvowel,
654 FF_MAX_VOWELS - 1);
655 xml.exitbranch();
657 xml.exitbranch();
661 #define COPY(y) this->y = x.y
662 void FilterParams::paste(FilterParams &x)
664 COPY(Pcategory);
665 COPY(Ptype);
666 COPY(basefreq);
667 COPY(Pq);
668 COPY(Pstages);
669 COPY(freqtracking);
670 COPY(gain);
672 COPY(Pnumformants);
673 COPY(Pformantslowness);
674 COPY(Pvowelclearness);
675 COPY(Pcenterfreq);
676 COPY(Poctavesfreq);
678 for(int i=0; i<FF_MAX_VOWELS; ++i) {
679 for(int j=0; j<FF_MAX_FORMANTS; ++j) {
680 auto &a = this->Pvowels[i].formants[j];
681 auto &b = x.Pvowels[i].formants[j];
682 a.freq = b.freq;
683 a.amp = b.amp;
684 a.q = b.q;
689 COPY(Psequencesize);
690 COPY(Psequencestretch);
691 COPY(Psequencereversed);
692 for(int i=0; i<FF_MAX_SEQUENCE; ++i)
693 this->Psequence[i] = x.Psequence[i];
695 COPY(changed);
697 if ( time ) {
698 last_update_timestamp = time->time();
701 #undef COPY
703 void FilterParams::pasteArray(FilterParams &x, int nvowel)
705 for(int nformant = 0; nformant < FF_MAX_FORMANTS; ++nformant) {
706 auto &self = Pvowels[nvowel].formants[nformant];
707 auto &update = x.Pvowels[nvowel].formants[nformant];
708 self.freq = update.freq;
709 self.amp = update.amp;
710 self.q = update.q;
713 if ( time ) {
714 last_update_timestamp = time->time();