1 /*
2 ZynAddSubFX - a software synthesizer
3
4 FormantFilter.cpp - formant filters
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 modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License (version 2 or later) for more details.
17
18 You should have received a copy of the GNU General Public License (version 2)
19 along with this program; if not, write to the Free Software Foundation,
20 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
22 */
23
24 #include <cmath>
25 #include <cstdio>
26 #include "../Misc/Util.h"
27 #include "FormantFilter.h"
28 #include "AnalogFilter.h"
29 #include "../Params/FilterParams.h"
30
FormantFilter(FilterParams * pars,unsigned int srate,int bufsize)31 FormantFilter::FormantFilter(FilterParams *pars, unsigned int srate, int bufsize)
32 : Filter(srate, bufsize)
33 {
34 numformants = pars->Pnumformants;
35 for(int i = 0; i < numformants; ++i)
36 formant[i] = new AnalogFilter(4 /*BPF*/, 1000.0f, 10.0f, pars->Pstages, srate, bufsize);
37 cleanup();
38
39 for(int j = 0; j < FF_MAX_VOWELS; ++j)
40 for(int i = 0; i < numformants; ++i) {
41 formantpar[j][i].freq = pars->getformantfreq(
42 pars->Pvowels[j].formants[i].freq);
43 formantpar[j][i].amp = pars->getformantamp(
44 pars->Pvowels[j].formants[i].amp);
45 formantpar[j][i].q = pars->getformantq(
46 pars->Pvowels[j].formants[i].q);
47 }
48
49 for(int i = 0; i < FF_MAX_FORMANTS; ++i)
50 oldformantamp[i] = 1.0f;
51 for(int i = 0; i < numformants; ++i) {
52 currentformants[i].freq = 1000.0f;
53 currentformants[i].amp = 1.0f;
54 currentformants[i].q = 2.0f;
55 }
56
57 formantslowness = powf(1.0f - (pars->Pformantslowness / 128.0f), 3.0f);
58
59 sequencesize = pars->Psequencesize;
60 if(sequencesize == 0)
61 sequencesize = 1;
62 for(int k = 0; k < sequencesize; ++k)
63 sequence[k].nvowel = pars->Psequence[k].nvowel;
64
65 vowelclearness = powf(10.0f, (pars->Pvowelclearness - 32.0f) / 48.0f);
66
67 sequencestretch = powf(0.1f, (pars->Psequencestretch - 32.0f) / 48.0f);
68 if(pars->Psequencereversed)
69 sequencestretch *= -1.0f;
70
71 outgain = dB2rap(pars->getgain());
72
73 oldinput = -1.0f;
74 Qfactor = 1.0f;
75 oldQfactor = Qfactor;
76 firsttime = 1;
77 }
78
~FormantFilter()79 FormantFilter::~FormantFilter()
80 {
81 for(int i = 0; i < numformants; ++i)
82 delete (formant[i]);
83 }
84
cleanup()85 void FormantFilter::cleanup()
86 {
87 for(int i = 0; i < numformants; ++i)
88 formant[i]->cleanup();
89 }
90
setpos(float input)91 void FormantFilter::setpos(float input)
92 {
93 int p1, p2;
94
95 if(firsttime != 0)
96 slowinput = input;
97 else
98 slowinput = slowinput
99 * (1.0f - formantslowness) + input * formantslowness;
100
101 if((fabsf(oldinput - input) < 0.001f) && (fabsf(slowinput - input) < 0.001f)
102 && (fabsf(Qfactor - oldQfactor) < 0.001f)) {
103 // oldinput=input; daca setez asta, o sa faca probleme la schimbari foarte lente
104 firsttime = 0;
105 return;
106 }
107 else
108 oldinput = input;
109
110 float pos = fmodf(input * sequencestretch, 1.0f);
111 if(pos < 0.0f)
112 pos += 1.0f;
113
114 F2I(pos * sequencesize, p2);
115 p1 = p2 - 1;
116 if(p1 < 0)
117 p1 += sequencesize;
118
119 pos = fmodf(pos * sequencesize, 1.0f);
120 if(pos < 0.0f)
121 pos = 0.0f;
122 else
123 if(pos > 1.0f)
124 pos = 1.0f;
125 pos =
126 (atanf((pos * 2.0f
127 - 1.0f)
128 * vowelclearness) / atanf(vowelclearness) + 1.0f) * 0.5f;
129
130 p1 = sequence[p1].nvowel;
131 p2 = sequence[p2].nvowel;
132
133 if(firsttime != 0) {
134 for(int i = 0; i < numformants; ++i) {
135 currentformants[i].freq =
136 formantpar[p1][i].freq
137 * (1.0f - pos) + formantpar[p2][i].freq * pos;
138 currentformants[i].amp =
139 formantpar[p1][i].amp
140 * (1.0f - pos) + formantpar[p2][i].amp * pos;
141 currentformants[i].q =
142 formantpar[p1][i].q * (1.0f - pos) + formantpar[p2][i].q * pos;
143 formant[i]->setfreq_and_q(currentformants[i].freq,
144 currentformants[i].q * Qfactor);
145 oldformantamp[i] = currentformants[i].amp;
146 }
147 firsttime = 0;
148 }
149 else
150 for(int i = 0; i < numformants; ++i) {
151 currentformants[i].freq =
152 currentformants[i].freq * (1.0f - formantslowness)
153 + (formantpar[p1][i].freq
154 * (1.0f - pos) + formantpar[p2][i].freq * pos)
155 * formantslowness;
156
157 currentformants[i].amp =
158 currentformants[i].amp * (1.0f - formantslowness)
159 + (formantpar[p1][i].amp * (1.0f - pos)
160 + formantpar[p2][i].amp * pos) * formantslowness;
161
162 currentformants[i].q = currentformants[i].q
163 * (1.0f - formantslowness)
164 + (formantpar[p1][i].q * (1.0f - pos)
165 + formantpar[p2][i].q
166 * pos) * formantslowness;
167
168
169 formant[i]->setfreq_and_q(currentformants[i].freq,
170 currentformants[i].q * Qfactor);
171 }
172
173 oldQfactor = Qfactor;
174 }
175
setfreq(float frequency)176 void FormantFilter::setfreq(float frequency)
177 {
178 setpos(frequency);
179 }
180
setq(float q_)181 void FormantFilter::setq(float q_)
182 {
183 Qfactor = q_;
184 for(int i = 0; i < numformants; ++i)
185 formant[i]->setq(Qfactor * currentformants[i].q);
186 }
187
setgain(float)188 void FormantFilter::setgain(float /*dBgain*/)
189 {}
190
log_2(float x)191 inline float log_2(float x)
192 {
193 return logf(x) / logf(2.0f);
194 }
195
setfreq_and_q(float frequency,float q_)196 void FormantFilter::setfreq_and_q(float frequency, float q_)
197 {
198 //Convert form real freq[Hz]
199 const float freq = log_2(frequency) - 9.96578428f; //log2(1000)=9.95748f.
200
201 Qfactor = q_;
202 setpos(freq);
203 }
204
205
filterout(float * smp)206 void FormantFilter::filterout(float *smp)
207 {
208 float inbuffer[buffersize];
209
210 memcpy(inbuffer, smp, bufferbytes);
211 memset(smp, 0, bufferbytes);
212
213 for(int j = 0; j < numformants; ++j) {
214 float tmpbuf[buffersize];
215 for(int i = 0; i < buffersize; ++i)
216 tmpbuf[i] = inbuffer[i] * outgain;
217 formant[j]->filterout(tmpbuf);
218
219 if(ABOVE_AMPLITUDE_THRESHOLD(oldformantamp[j], currentformants[j].amp))
220 for(int i = 0; i < buffersize; ++i)
221 smp[i] += tmpbuf[i]
222 * INTERPOLATE_AMPLITUDE(oldformantamp[j],
223 currentformants[j].amp,
224 i,
225 buffersize);
226 else
227 for(int i = 0; i < buffersize; ++i)
228 smp[i] += tmpbuf[i] * currentformants[j].amp;
229 oldformantamp[j] = currentformants[j].amp;
230 }
231 }
232