1 /* PitchTier_to_PointProcess.cpp
2  *
3  * Copyright (C) 1992-2005,2011,2012,2015-2017,2019 Paul Boersma
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 "PitchTier_to_PointProcess.h"
20 #include "Pitch_to_PitchTier.h"
21 
22 autoPointProcess PitchTier_to_PointProcess (PitchTier me) {
23 	try {
24 		autoPointProcess thee = PointProcess_create (my xmin, my xmax, 1000);
25 		double area = 0.5;   // imagine an event half a period before the beginning
26 		integer size = my points.size;
27 		if (size == 0)
28 			return thee;
29 		for (integer interval = 0; interval <= size; interval ++) {
30 			double t1 = ( interval == 0 ? my xmin : my points.at [interval] -> number );
31 			Melder_assert (isdefined (t1));
32 			double t2 = ( interval == size ? my xmax : my points.at [interval + 1] -> number );
33 			Melder_assert (isdefined (t2));
34 			double f1 = my points.at [interval == 0 ? 1 : interval] -> value;
35 			Melder_assert (isdefined (f1));
36 			double f2 = my points.at [interval == size ? size : interval + 1] -> value;
37 			Melder_assert (isdefined (f2));
38 			area += (t2 - t1) * 0.5 * (f1 + f2);
39 			while (area >= 1.0) {
40 				const double slope = (f2 - f1) / (t2 - t1);
41 				area -= 1.0;
42 				double discriminant = f2 * f2 - 2.0 * area * slope;
43 				if (discriminant < 0.0)
44 					discriminant = 0.0;   // catch rounding errors
45 				PointProcess_addPoint (thee.get(), t2 - 2.0 * area / (f2 + sqrt (discriminant)));
46 			}
47 		}
48 		return thee;
49 	} catch (MelderError) {
50 		Melder_throw (me, U": not converted to PointProcess.");
51 	}
52 }
53 
54 autoPointProcess PitchTier_Pitch_to_PointProcess (PitchTier me, Pitch vuv) {
55 	try {
56 		autoPointProcess fullPoint = PitchTier_to_PointProcess (me);
57 		autoPointProcess thee = PointProcess_create (my xmin, my xmax, fullPoint -> nt);
58 		/*
59 		 * Copy only voiced parts to result.
60 		 */
61 		for (integer i = 1; i <= fullPoint -> nt; i ++) {
62 			double t = fullPoint -> t [i];
63 			if (Pitch_isVoiced_t (vuv, t))
64 				PointProcess_addPoint (thee.get(), t);
65 		}
66 		return thee;
67 	} catch (MelderError) {
68 		Melder_throw (me, U" & ", vuv, U": not converted to PointProcess.");
69 	}
70 }
71 
72 static bool PointProcess_isVoiced_t (PointProcess me, double t, double maxT) {
73 	integer imid = PointProcess_getNearestIndex (me, t);
74 	if (imid == 0)
SpillPlacement()75 		return false;
~SpillPlacement()76 	double tmid = my t [imid];
77 	bool leftVoiced = ( imid > 1 && tmid - my t [imid - 1] <= maxT );
78 	bool rightVoiced = ( imid < my nt && my t [imid + 1] - tmid <= maxT );
79 	if (leftVoiced && t <= tmid || rightVoiced && t >= tmid)
80 		return true;
81 	if (leftVoiced && t < 1.5 * tmid - 0.5 * my t [imid - 1])
82 		return true;
83 	if (rightVoiced && t > 1.5 * tmid - 0.5 * my t [imid + 1])
84 		return true;
85 	return false;
86 }
87 
88 autoPointProcess PitchTier_Point_to_PointProcess (PitchTier me, PointProcess vuv, double maxT) {
89 	try {
90 		autoPointProcess fullPoint = PitchTier_to_PointProcess (me);
91 		autoPointProcess thee = PointProcess_create (my xmin, my xmax, fullPoint -> nt);
92 		/*
93 		 * Copy only voiced parts to result.
94 		 */
95 		for (integer i = 1; i <= fullPoint -> nt; i ++) {
96 			double t = fullPoint -> t [i];
97 			if (PointProcess_isVoiced_t (vuv, t, maxT))
98 				PointProcess_addPoint (thee.get(), t);
99 		}
100 		return thee;
101 	} catch (MelderError) {
102 		Melder_throw (me, U" & ", vuv, U": not converted to PointProcess.");
103 	}
104 }
105 
106 autoPitchTier PointProcess_to_PitchTier (PointProcess me, double maximumInterval) {
107 	try {
108 		autoPitchTier thee = PitchTier_create (my xmin, my xmax);
109 		for (integer i = 1; i < my nt; i ++) {
110 			double interval = my t [i + 1] - my t [i];
111 			if (interval <= maximumInterval)
112 				RealTier_addPoint (thee.get(), my t [i] + 0.5 * interval, 1.0 / interval);
113 		}
114 		return thee;
115 	} catch (MelderError) {
116 		Melder_throw (me, U": not converted to PitchTier.");
117 	}
118 }
119 
120 autoPitchTier Pitch_PointProcess_to_PitchTier (Pitch me, PointProcess pp) {
121 	try {
122 		autoPitchTier temp = Pitch_to_PitchTier (me);
123 		autoPitchTier thee = PitchTier_PointProcess_to_PitchTier (temp.get(), pp);
124 		return thee;
125 	} catch (MelderError) {
126 		Melder_throw (me, U" & ", pp, U": not converted to PitchTier.");
127 	}
128 }
129 
130 autoPitchTier PitchTier_PointProcess_to_PitchTier (PitchTier me, PointProcess pp) {
131 	try {
132 		if (my points.size == 0) Melder_throw (U"No pitch points.");
133 		autoPitchTier thee = PitchTier_create (pp -> xmin, pp -> xmax);
134 		for (integer i = 1; i <= pp -> nt; i ++) {
135 			double time = pp -> t [i];
136 			double value = RealTier_getValueAtTime (me, time);
137 			RealTier_addPoint (thee.get(), time, value);
138 		}
139 		return thee;
140 	} catch (MelderError) {
141 		Melder_throw (me, U" & ", pp, U": not converted to PitchTier.");
getRecentPositive()142 	}
143 }
144 
145 autoTableOfReal PitchTier_downto_TableOfReal (PitchTier me, int useSemitones) {
146 	try {
147 		autoTableOfReal thee = RealTier_downto_TableOfReal (me, U"Time", U"F0");
148 		if (useSemitones)
149 			for (integer i = 1; i <= thy numberOfRows; i ++)
150 				thy data [i] [2] = NUMhertzToSemitones (thy data [i] [2]);
151 		return thee;
152 	} catch (MelderError) {
153 		Melder_throw (me, U": not converted to TableOfReal.");
154 	}
155 }
156 
157 /* End of file PitchTier_to_PointProcess.cpp */
158