1 /* Pitch_extensions.cpp 2 * 3 * Copyright (C) 1993-2019 David Weenink, 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. See the GNU 13 * 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 /* 20 djmw 1997 21 djmw 20030217 Latest modification 22 djmw 20061201 Interface change: removed minimumPitch parameter from PitchTier_modifyRange. 23 djmw 20061207 Removed PitchTier_modifyRange. 24 */ 25 26 #include "Pitch_extensions.h" 27 28 void Pitch_Frame_addPitch (Pitch_Frame me, double f, double strength, integer maxnCandidates) { 29 integer pos = 0; 30 double weakest = 1e308; 31 if (my nCandidates < maxnCandidates) { 32 my candidates. resize (++ my nCandidates); 33 pos = my nCandidates; 34 } else { 35 // Find weakest candidate so far (skip the unvoiced one) 36 for (integer i = 1; i <= maxnCandidates; i ++) 37 if (my candidates [i]. strength < weakest && my candidates [i]. frequency > 0.0) 38 weakest = my candidates [pos = i]. strength; 39 if (strength < weakest) 40 pos = 0; 41 } 42 if (pos > 0) { 43 my candidates [pos]. frequency = f; 44 my candidates [pos]. strength = strength; 45 } 46 } 47 48 void Pitch_Frame_getPitch (Pitch_Frame me, double *out_f, double *out_strength) { 49 integer pos = 1; 50 double strength = -1.0; 51 for (integer i = 1; i <= my nCandidates; i ++) 52 if (my candidates [i]. strength > strength && my candidates [i]. frequency > 0.0) 53 strength = my candidates [pos = i]. strength; 54 if (out_f) 55 *out_f = my candidates [pos]. frequency; 56 if (out_strength) 57 *out_strength = strength; 58 } 59 60 void Pitch_Frame_resizeStrengths (Pitch_Frame me, double maxStrength, double unvoicedCriterium) { 61 integer pos = 1; 62 double strongest = my candidates [1]. strength; 63 for (integer i = 2; i <= my nCandidates; i ++) 64 if (my candidates [i]. strength > strongest) 65 strongest = my candidates [pos = i]. strength; 66 if (strongest != 0) 67 for (integer i = 1; i <= my nCandidates; i ++) 68 my candidates [i]. strength *= maxStrength / strongest; 69 70 if (maxStrength < unvoicedCriterium) 71 for (integer i = 1; i <= my nCandidates; i ++) 72 if (my candidates [i]. frequency == 0) { 73 pos = i; 74 break; 75 } 76 if (pos != 1) { 77 std::swap (my candidates [1]. frequency, my candidates [pos]. frequency); 78 std::swap (my candidates [1]. strength, my candidates [pos]. strength); 79 } 80 } 81 82 autoPitch Pitch_scaleTime (Pitch me, double scaleFactor) { 83 try { 84 double dx = my dx, x1 = my x1, xmax = my xmax; 85 if (scaleFactor != 1.0) { 86 dx = my dx * scaleFactor; 87 x1 = my xmin + 0.5 * dx; 88 xmax = my xmin + my nx * dx; 89 } 90 autoPitch thee = Pitch_create (my xmin, xmax, my nx, dx, x1, my ceiling, 2); 91 for (integer i = 1; i <= my nx; i ++) { 92 double f = my frames [i]. candidates [1]. frequency; 93 thy frames [i]. candidates [1]. strength = my frames [i]. candidates [1]. strength; 94 f /= scaleFactor; 95 if (f < my ceiling) 96 thy frames [i]. candidates [1]. frequency = f; 97 } 98 return thee; 99 } catch (MelderError) { 100 Melder_throw (me, U": not scaled."); 101 } 102 } 103 104 static double HertzToSpecial (double value, kPitch_unit pitchUnit) { 105 return ( pitchUnit == kPitch_unit::HERTZ ? value : 106 ( pitchUnit == kPitch_unit::HERTZ_LOGARITHMIC ? ( value <= 0.0 ? undefined : log10 (value)) : 107 ( pitchUnit == kPitch_unit::MEL ? NUMhertzToMel (value) : 108 ( pitchUnit == kPitch_unit::LOG_HERTZ ? ( value <= 0.0 ? undefined : log10 (value) ) : 109 ( pitchUnit == kPitch_unit::SEMITONES_1 ? ( value <= 0.0 ? undefined : 12.0 * log (value / 1.0) / NUMln2 ) : 110 ( pitchUnit == kPitch_unit::SEMITONES_100 ? ( value <= 0.0 ? undefined : 12.0 * log (value / 100.0) / NUMln2 ) : 111 ( pitchUnit == kPitch_unit::SEMITONES_200 ? (value <= 0.0 ? undefined : 12.0 * log (value / 200.0) / NUMln2 ) : 112 ( pitchUnit == kPitch_unit::SEMITONES_440 ? ( value <= 0.0 ? undefined : 12.0 * log (value / 440.0) / NUMln2 ) : 113 ( pitchUnit == kPitch_unit::ERB ? NUMhertzToErb (value) : undefined ) ) ) ) ) ) ) ) ); 114 } 115 116 static double SpecialToHertz (double value, kPitch_unit pitchUnit) { 117 return ( pitchUnit == kPitch_unit::HERTZ ? value : 118 ( pitchUnit == kPitch_unit::HERTZ_LOGARITHMIC ? pow (10.0, value) : 119 ( pitchUnit == kPitch_unit::MEL ? NUMmelToHertz (value) : 120 ( pitchUnit == kPitch_unit::LOG_HERTZ ? pow (10.0, value) : 121 ( pitchUnit == kPitch_unit::SEMITONES_1 ? 1.0 * exp (value * (NUMln2 / 12.0)) : 122 ( pitchUnit == kPitch_unit::SEMITONES_100 ? 100.0 * exp (value * (NUMln2 / 12.0)) : 123 ( pitchUnit == kPitch_unit::SEMITONES_200 ? 200.0 * exp (value * (NUMln2 / 12.0)) : 124 ( pitchUnit == kPitch_unit::SEMITONES_440 ? 440.0 * exp (value * (NUMln2 / 12.0)) : 125 ( pitchUnit == kPitch_unit::ERB ? NUMerbToHertz (value) : undefined ) ) ) ) ) ) ) ) ); 126 } 127 128 autoPitchTier PitchTier_normalizePitchRange (PitchTier me, double pitchMin_ref_Hz, double pitchMax_ref_Hz, double pitchMin_Hz, double pitchMax_Hz, kPitch_unit pitchUnit); 129 autoPitchTier PitchTier_normalizePitchRange (PitchTier me, double pitchMin_ref_Hz, double pitchMax_ref_Hz, double pitchMin_Hz, double pitchMax_Hz, kPitch_unit pitchUnit) { 130 try { 131 const double fminr = HertzToSpecial (pitchMin_ref_Hz, pitchUnit); 132 const double fmaxr = HertzToSpecial (pitchMax_ref_Hz, pitchUnit); 133 const double fmin = HertzToSpecial (pitchMin_Hz, pitchUnit); 134 const double fmax = HertzToSpecial (pitchMax_Hz, pitchUnit); 135 136 Melder_require (! (isundef (fminr) || isundef (fmaxr) || isundef (fmin) || isundef (fmax)), 137 U"The conversion of a pitch value is not defined."); 138 const double ranger = fmaxr - fminr, range = fmax - fmin; 139 Melder_require (ranger >= 0.01 && range >= 0.01, 140 U"Pitch range too small."); 141 142 const double fmidr = fminr + ranger / 2.0; 143 const double factor = ranger / range; 144 autoPitchTier thee = Data_copy (me); 145 for (integer i = 1; i <= my points.size; i ++) { 146 const RealPoint point = thy points.at [i]; 147 double f = HertzToSpecial (point -> value, pitchUnit); 148 f = factor * (f - fmidr); 149 f = SpecialToHertz (f, pitchUnit); 150 point -> value = f; 151 } 152 return thee; 153 } catch (MelderError) { 154 Melder_throw (me, U": no PitchTier created."); 155 } 156 } 157 158 autoPitch PitchTier_to_Pitch (PitchTier me, double dt, double pitchFloor, double pitchCeiling) { 159 try { 160 Melder_require (my points.size > 0, 161 U"The PitchTier is empty."); 162 Melder_require (dt > 0.0, 163 U"The time step should be a positive number."); 164 Melder_require (pitchFloor < pitchCeiling, 165 U"The pitch floor should be lower than the pitch ceiling."); 166 167 const double tmin = my xmin, tmax = my xmax, t1 = my xmin + dt / 2.0; 168 integer nt = Melder_ifloor ((tmax - tmin - t1) / dt); 169 if (t1 + nt * dt < tmax) 170 nt ++; 171 Melder_require (nt > 0, 172 U"Duration is too short."); 173 174 autoPitch thee = Pitch_create (tmin, tmax, nt, dt, t1, pitchCeiling, 1); 175 for (integer i = 1; i <= nt; i ++) { 176 const Pitch_Frame frame = & thy frames [i]; 177 const Pitch_Candidate candidate = & frame -> candidates [1]; 178 const double t = t1 + (i - 1) * dt; 179 double f = RealTier_getValueAtTime (me, t); 180 if (f < pitchFloor || f > pitchCeiling) 181 f = 0.0; 182 candidate -> frequency = f; 183 } 184 return thee; 185 } catch (MelderError) { 186 Melder_throw (me, U": no Pitch created."); 187 } 188 } 189 190 /* End of file Pitch_extensions.cpp */ 191