1 /* FormantGrid.cpp
2 *
3 * Copyright (C) 2008,2009,2011,2012,2014-2020 Paul Boersma & David Weenink
4 *
5 * This code is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 *
10 * This code is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this work. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "FormantGrid.h"
20 #include "PitchTier_to_Sound.h"
21 #include "Formula.h"
22
23 #include "oo_DESTROY.h"
24 #include "FormantGrid_def.h"
25 #include "oo_COPY.h"
26 #include "FormantGrid_def.h"
27 #include "oo_EQUAL.h"
28 #include "FormantGrid_def.h"
29 #include "oo_CAN_WRITE_AS_ENCODING.h"
30 #include "FormantGrid_def.h"
31 #include "oo_WRITE_TEXT.h"
32 #include "FormantGrid_def.h"
33 #include "oo_READ_TEXT.h"
34 #include "FormantGrid_def.h"
35 #include "oo_WRITE_BINARY.h"
36 #include "FormantGrid_def.h"
37 #include "oo_READ_BINARY.h"
38 #include "FormantGrid_def.h"
39 #include "oo_DESCRIPTION.h"
40 #include "FormantGrid_def.h"
41
42 Thing_implement (FormantGrid, Function, 0);
43
v_getVector(integer irow,integer icol)44 double structFormantGrid :: v_getVector (integer irow, integer icol) {
45 RealTier tier = our formants.at [irow];
46 return RealTier_getValueAtIndex (tier, icol);
47 }
48
v_getFunction1(integer irow,double x)49 double structFormantGrid :: v_getFunction1 (integer irow, double x) {
50 RealTier tier = our formants.at [irow];
51 return RealTier_getValueAtTime (tier, x);
52 }
53
v_shiftX(double xfrom,double xto)54 void structFormantGrid :: v_shiftX (double xfrom, double xto) {
55 FormantGrid_Parent :: v_shiftX (xfrom, xto);
56 for (integer i = 1; i <= our formants.size; i ++) {
57 RealTier tier = our formants.at [i];
58 tier -> v_shiftX (xfrom, xto);
59 }
60 for (integer i = 1; i <= our bandwidths.size; i ++) {
61 RealTier tier = our bandwidths.at [i];
62 tier -> v_shiftX (xfrom, xto);
63 }
64 }
65
v_scaleX(double xminfrom,double xmaxfrom,double xminto,double xmaxto)66 void structFormantGrid :: v_scaleX (double xminfrom, double xmaxfrom, double xminto, double xmaxto) {
67 FormantGrid_Parent :: v_scaleX (xminfrom, xmaxfrom, xminto, xmaxto);
68 for (integer i = 1; i <= our formants.size; i ++) {
69 RealTier tier = our formants.at [i];
70 tier -> v_scaleX (xminfrom, xmaxfrom, xminto, xmaxto);
71 }
72 for (integer i = 1; i <= our bandwidths.size; i ++) {
73 RealTier tier = our bandwidths.at [i];
74 tier -> v_scaleX (xminfrom, xmaxfrom, xminto, xmaxto);
75 }
76 }
77
FormantGrid_init(FormantGrid me,double tmin,double tmax,integer numberOfFormants)78 void FormantGrid_init (FormantGrid me, double tmin, double tmax, integer numberOfFormants) {
79 for (integer iformant = 1; iformant <= numberOfFormants; iformant ++) {
80 autoRealTier formant = RealTier_create (tmin, tmax);
81 my formants. addItem_move (formant.move());
82 autoRealTier bandwidth = RealTier_create (tmin, tmax);
83 my bandwidths. addItem_move (bandwidth.move());
84 }
85 my xmin = tmin;
86 my xmax = tmax;
87 }
88
FormantGrid_createEmpty(double tmin,double tmax,integer numberOfFormants)89 autoFormantGrid FormantGrid_createEmpty (double tmin, double tmax, integer numberOfFormants) {
90 try {
91 autoFormantGrid me = Thing_new (FormantGrid);
92 FormantGrid_init (me.get(), tmin, tmax, numberOfFormants);
93 return me;
94 } catch (MelderError) {
95 Melder_throw (U"Empty FormantGrid not created.");
96 }
97 }
98
FormantGrid_create(double tmin,double tmax,integer numberOfFormants,double initialFirstFormant,double initialFormantSpacing,double initialFirstBandwidth,double initialBandwidthSpacing)99 autoFormantGrid FormantGrid_create (double tmin, double tmax, integer numberOfFormants,
100 double initialFirstFormant, double initialFormantSpacing,
101 double initialFirstBandwidth, double initialBandwidthSpacing)
102 {
103 try {
104 autoFormantGrid me = FormantGrid_createEmpty (tmin, tmax, numberOfFormants);
105 for (integer iformant = 1; iformant <= numberOfFormants; iformant ++) {
106 FormantGrid_addFormantPoint (me.get(), iformant, 0.5 * (tmin + tmax),
107 initialFirstFormant + (iformant - 1) * initialFormantSpacing);
108 FormantGrid_addBandwidthPoint (me.get(), iformant, 0.5 * (tmin + tmax),
109 initialFirstBandwidth + (iformant - 1) * initialBandwidthSpacing);
110 }
111 return me;
112 } catch (MelderError) {
113 Melder_throw (U"FormantGrid not created.");
114 }
115 }
116
FormantGrid_addFormantPoint(FormantGrid me,integer iformant,double t,double value)117 void FormantGrid_addFormantPoint (FormantGrid me, integer iformant, double t, double value) {
118 try {
119 if (iformant < 1 || iformant > my formants.size)
120 Melder_throw (U"No such formant number.");
121 RealTier formantTier = my formants.at [iformant];
122 RealTier_addPoint (formantTier, t, value);
123 } catch (MelderError) {
124 Melder_throw (me, U": formant point not added.");
125 }
126 }
127
FormantGrid_addBandwidthPoint(FormantGrid me,integer iformant,double t,double value)128 void FormantGrid_addBandwidthPoint (FormantGrid me, integer iformant, double t, double value) {
129 try {
130 if (iformant < 1 || iformant > my formants.size)
131 Melder_throw (U"No such formant number.");
132 RealTier bandwidthTier = my bandwidths.at [iformant];
133 RealTier_addPoint (bandwidthTier, t, value);
134 } catch (MelderError) {
135 Melder_throw (me, U": bandwidth point not added.");
136 }
137 }
138
FormantGrid_getFormantAtTime(FormantGrid me,integer iformant,double t)139 double FormantGrid_getFormantAtTime (FormantGrid me, integer iformant, double t) {
140 if (iformant < 1 || iformant > my formants.size) return undefined;
141 return RealTier_getValueAtTime (my formants.at [iformant], t);
142 }
143
FormantGrid_getBandwidthAtTime(FormantGrid me,integer iformant,double t)144 double FormantGrid_getBandwidthAtTime (FormantGrid me, integer iformant, double t) {
145 if (iformant < 1 || iformant > my bandwidths.size) return undefined;
146 return RealTier_getValueAtTime (my bandwidths.at [iformant], t);
147 }
148
FormantGrid_removeFormantPointsBetween(FormantGrid me,integer iformant,double tmin,double tmax)149 void FormantGrid_removeFormantPointsBetween (FormantGrid me, integer iformant, double tmin, double tmax) {
150 if (iformant < 1 || iformant > my formants.size) return;
151 AnyTier_removePointsBetween (my formants.at [iformant]->asAnyTier(), tmin, tmax);
152 }
153
FormantGrid_removeBandwidthPointsBetween(FormantGrid me,integer iformant,double tmin,double tmax)154 void FormantGrid_removeBandwidthPointsBetween (FormantGrid me, integer iformant, double tmin, double tmax) {
155 if (iformant < 1 || iformant > my bandwidths.size) return;
156 AnyTier_removePointsBetween (my bandwidths.at [iformant]->asAnyTier(), tmin, tmax);
157 }
158
Sound_FormantGrid_filter_inplace(Sound me,FormantGrid formantGrid)159 void Sound_FormantGrid_filter_inplace (Sound me, FormantGrid formantGrid) {
160 double dt = my dx;
161 if (formantGrid -> formants.size > 0 && formantGrid -> bandwidths.size > 0) {
162 for (integer iformant = 1; iformant <= formantGrid -> formants.size; iformant ++) {
163 RealTier formantTier = formantGrid -> formants.at [iformant];
164 RealTier bandwidthTier = formantGrid -> bandwidths.at [iformant];
165 for (integer isamp = 1; isamp <= my nx; isamp ++) {
166 double t = my x1 + (isamp - 1) * my dx;
167 /*
168 * Compute LP coefficients.
169 */
170 double formant, bandwidth;
171 formant = RealTier_getValueAtTime (formantTier, t);
172 bandwidth = RealTier_getValueAtTime (bandwidthTier, t);
173 if (isdefined (formant) && isdefined (bandwidth)) {
174 double cosomdt = cos (2 * NUMpi * formant * dt);
175 double r = exp (- NUMpi * bandwidth * dt);
176 /* Formants at 0 Hz or the Nyquist are single poles, others are double poles. */
177 if (fabs (cosomdt) > 0.999999) { /* Allow for round-off errors. */
178 /* single pole: D(z) = 1 - r z^-1 */
179 for (integer channel = 1; channel <= my ny; channel ++) {
180 if (isamp > 1) my z [channel] [isamp] += r * my z [channel] [isamp - 1];
181 }
182 } else {
183 /* double pole: D(z) = 1 + p z^-1 + q z^-2 */
184 double p = - 2 * r * cosomdt;
185 double q = r * r;
186 for (integer channel = 1; channel <= my ny; channel ++) {
187 if (isamp > 1) my z [channel] [isamp] -= p * my z [channel] [isamp - 1];
188 if (isamp > 2) my z [channel] [isamp] -= q * my z [channel] [isamp - 2];
189 }
190 }
191 }
192 }
193 }
194 }
195 }
196
Sound_FormantGrid_filter(Sound me,FormantGrid formantGrid)197 autoSound Sound_FormantGrid_filter (Sound me, FormantGrid formantGrid) {
198 try {
199 autoSound thee = Data_copy (me);
200 Sound_FormantGrid_filter_inplace (thee.get(), formantGrid);
201 Vector_scale (thee.get(), 0.99);
202 return thee;
203 } catch (MelderError) {
204 Melder_throw (me, U": not filtered with ", formantGrid, U".");
205 }
206 }
207
Sound_FormantGrid_filter_noscale(Sound me,FormantGrid formantGrid)208 autoSound Sound_FormantGrid_filter_noscale (Sound me, FormantGrid formantGrid) {
209 try {
210 autoSound thee = Data_copy (me);
211 Sound_FormantGrid_filter_inplace (thee.get(), formantGrid);
212 return thee;
213 } catch (MelderError) {
214 Melder_throw (me, U": not filtered with ", formantGrid, U".");
215 }
216 }
217
FormantGrid_to_Sound(FormantGrid me,double samplingFrequency,double tStart,double f0Start,double tMid,double f0Mid,double tEnd,double f0End,double adaptFactor,double maximumPeriod,double openPhase,double collisionPhase,double power1,double power2)218 autoSound FormantGrid_to_Sound (FormantGrid me, double samplingFrequency,
219 double tStart, double f0Start, double tMid, double f0Mid, double tEnd, double f0End,
220 double adaptFactor, double maximumPeriod, double openPhase, double collisionPhase, double power1, double power2)
221 {
222 try {
223 autoPitchTier pitch = PitchTier_create (my xmin, my xmax);
224 RealTier_addPoint (pitch.get(), my xmin + tStart * (my xmax - my xmin), f0Start);
225 RealTier_addPoint (pitch.get(), my xmin + tMid * (my xmax - my xmin), f0Mid);
226 RealTier_addPoint (pitch.get(), my xmax - (1.0 - tEnd) * (my xmax - my xmin), f0End);
227 autoSound thee = PitchTier_to_Sound_phonation (pitch.get(), samplingFrequency,
228 adaptFactor, maximumPeriod, openPhase, collisionPhase, power1, power2, false);
229 Sound_FormantGrid_filter_inplace (thee.get(), me);
230 return thee;
231 } catch (MelderError) {
232 Melder_throw (me, U": not converted to Sound.");
233 }
234 }
235
FormantGrid_playPart(FormantGrid me,double tmin,double tmax,double samplingFrequency,double tStart,double f0Start,double tMid,double f0Mid,double tEnd,double f0End,double adaptFactor,double maximumPeriod,double openPhase,double collisionPhase,double power1,double power2,Sound_PlayCallback playCallback,Thing playBoss)236 void FormantGrid_playPart (FormantGrid me, double tmin, double tmax, double samplingFrequency,
237 double tStart, double f0Start, double tMid, double f0Mid, double tEnd, double f0End,
238 double adaptFactor, double maximumPeriod, double openPhase, double collisionPhase, double power1, double power2,
239 Sound_PlayCallback playCallback, Thing playBoss)
240 {
241 try {
242 autoSound sound = FormantGrid_to_Sound (me, samplingFrequency,
243 tStart, f0Start, tMid, f0Mid, tEnd, f0End,
244 adaptFactor, maximumPeriod, openPhase, collisionPhase, power1, power2);
245 Vector_scale (sound.get(), 0.99);
246 Sound_playPart (sound.get(), tmin, tmax, playCallback, playBoss);
247 } catch (MelderError) {
248 Melder_throw (me, U": not played.");
249 }
250 }
251
FormantGrid_formula_bandwidths(FormantGrid me,conststring32 expression,Interpreter interpreter,FormantGrid thee)252 void FormantGrid_formula_bandwidths (FormantGrid me, conststring32 expression, Interpreter interpreter, FormantGrid thee) {
253 try {
254 Formula_compile (interpreter, me, expression, kFormula_EXPRESSION_TYPE_NUMERIC, true);
255 Formula_Result result;
256 if (! thee)
257 thee = me;
258 for (integer irow = 1; irow <= my formants.size; irow ++) {
259 const RealTier bandwidth = thy bandwidths.at [irow];
260 for (integer icol = 1; icol <= bandwidth -> points.size; icol ++) {
261 Formula_run (irow, icol, & result);
262 if (isundef (result. numericResult))
263 Melder_throw (U"Cannot put an undefined value into the tier.\nFormula not finished.");
264 bandwidth -> points.at [icol] -> value = result. numericResult;
265 }
266 }
267 } catch (MelderError) {
268 Melder_throw (me, U": bandwidth formula not completed.");
269 }
270 }
271
FormantGrid_formula_frequencies(FormantGrid me,conststring32 expression,Interpreter interpreter,FormantGrid thee)272 void FormantGrid_formula_frequencies (FormantGrid me, conststring32 expression, Interpreter interpreter, FormantGrid thee) {
273 try {
274 Formula_compile (interpreter, me, expression, kFormula_EXPRESSION_TYPE_NUMERIC, true);
275 Formula_Result result;
276 if (! thee)
277 thee = me;
278 for (integer irow = 1; irow <= my formants.size; irow ++) {
279 const RealTier formant = thy formants.at [irow];
280 for (integer icol = 1; icol <= formant -> points.size; icol ++) {
281 Formula_run (irow, icol, & result);
282 if (isundef (result. numericResult))
283 Melder_throw (U"Cannot put an undefined value into the tier.\nFormula not finished.");
284 formant -> points.at [icol] -> value = result. numericResult;
285 }
286 }
287 } catch (MelderError) {
288 Melder_throw (me, U": frequency formula not completed.");
289 }
290 }
291
Formant_downto_FormantGrid(Formant me)292 autoFormantGrid Formant_downto_FormantGrid (Formant me) {
293 try {
294 autoFormantGrid thee = FormantGrid_createEmpty (my xmin, my xmax, my maxnFormants);
295 for (integer iframe = 1; iframe <= my nx; iframe ++) {
296 const Formant_Frame frame = & my frames [iframe];
297 const double t = Sampled_indexToX (me, iframe);
298 for (integer iformant = 1; iformant <= frame -> numberOfFormants; iformant ++) {
299 Formant_Formant pair = & frame -> formant [iformant];
300 FormantGrid_addFormantPoint (thee.get(), iformant, t, pair -> frequency);
301 FormantGrid_addBandwidthPoint (thee.get(), iformant, t, pair -> bandwidth);
302 }
303 }
304 return thee;
305 } catch (MelderError) {
306 Melder_throw (me, U": not converted to FormantGrid.");
307 }
308 }
309
FormantGrid_to_Formant(FormantGrid me,double dt,double intensity)310 autoFormant FormantGrid_to_Formant (FormantGrid me, double dt, double intensity) {
311 try {
312 Melder_assert (dt > 0.0);
313 Melder_assert (intensity >= 0.0);
314 const integer nt = Melder_ifloor ((my xmax - my xmin) / dt) + 1;
315 const double t1 = 0.5 * (my xmin + my xmax - (nt - 1) * dt);
316 autoFormant thee = Formant_create (my xmin, my xmax, nt, dt, t1, my formants.size);
317 for (integer iframe = 1; iframe <= nt; iframe ++) {
318 const Formant_Frame frame = & thy frames [iframe];
319 frame -> intensity = intensity;
320 frame -> numberOfFormants = my formants.size;
321 frame -> formant = newvectorzero <structFormant_Formant> (my formants.size);
322 const double t = t1 + (iframe - 1) * dt;
323 for (integer iformant = 1; iformant <= my formants.size; iformant ++) {
324 const Formant_Formant formant = & frame -> formant [iformant];
325 formant -> frequency = RealTier_getValueAtTime (my formants.at [iformant], t);
326 formant -> bandwidth = RealTier_getValueAtTime (my bandwidths.at [iformant], t);
327 }
328 }
329 return thee;
330 } catch (MelderError) {
331 Melder_throw (me, U": not converted to Formant.");
332 }
333 }
334
Sound_Formant_filter(Sound me,Formant formant)335 autoSound Sound_Formant_filter (Sound me, Formant formant) {
336 try {
337 autoFormantGrid grid = Formant_downto_FormantGrid (formant);
338 autoSound thee = Sound_FormantGrid_filter (me, grid.get());
339 return thee;
340 } catch (MelderError) {
341 Melder_throw (me, U": not filtered with ", formant, U".");
342 }
343 }
344
Sound_Formant_filter_noscale(Sound me,Formant formant)345 autoSound Sound_Formant_filter_noscale (Sound me, Formant formant) {
346 try {
347 autoFormantGrid grid = Formant_downto_FormantGrid (formant);
348 autoSound thee = Sound_FormantGrid_filter_noscale (me, grid.get());
349 return thee;
350 } catch (MelderError) {
351 Melder_throw (me, U": not filtered with ", formant, U".");
352 }
353 }
354
355 /* End of file FormantGrid.cpp */
356