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