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