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