1 /* Pitch_Intensity.cpp
2  *
3  * Copyright (C) 1992-2007,2011,2014-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 "Pitch_Intensity.h"
20 
Pitch_getExtrema(Pitch me,double * minimum,double * maximum)21 static void Pitch_getExtrema (Pitch me, double *minimum, double *maximum) {
22 	MelderExtremaWithInit extrema;
23 	for (integer i = 1; i <= my nx; i ++) {
24 		const double frequency = my frames [i]. candidates [1]. frequency;
25 		if (frequency == 0.0)
26 			continue;   // voiceless
27 		extrema.update (frequency);
28 	}
29 	if (extrema.isValid()) {
30 		*minimum = extrema.min;
31 		*maximum = extrema.max;
32 	} else {
33 		*minimum = *maximum = 0.0;
34 	}
35 }
36 
Pitch_Intensity_draw(Pitch pitchObject,Intensity intensityObject,Graphics g,double f1,double f2,double s1,double s2,bool garnish,int connect)37 void Pitch_Intensity_draw (Pitch pitchObject, Intensity intensityObject, Graphics g,
38 	double f1, double f2, double s1, double s2, bool garnish, int connect)
39 {
40 	if (f1 == f2)
41 		Pitch_getExtrema (pitchObject, & f1, & f2);   // autowindow
42 	if (f1 == 0.0)   // all voiceless?
43 		return;
44 	if (f1 == f2) {
45 		f1 -= 1.0;
46 		f2 += 1.0;
47 	}
48 	if (s1 == s2)
49 		Matrix_getWindowExtrema (intensityObject, 0, 0, 1, 1, & s1, & s2);   // autowindow
50 	if (s1 == s2) {
51 		s1 -= 1.0;
52 		s2 += 1.0;
53 	}
54 	Graphics_setWindow (g, f1, f2, s1, s2);
55 	Graphics_setInner (g);
56 	double previousPitchValue = undefined;
57 	double previousIntensityValue = undefined;
58 	integer previousPitchFrameNumber = 0;
59 	for (integer ipitchFrame = 1; ipitchFrame <= pitchObject -> nx; ipitchFrame ++) {
60 		/*
61 			Get pitch value.
62 		*/
63 		const bool pitchMeasurementWillBeValid = Pitch_isVoiced_i (pitchObject, ipitchFrame);
64 		if (! pitchMeasurementWillBeValid)
65 			continue;   // voiceless -> don't draw
66 		const Pitch_Frame pitchFrame = & pitchObject -> frames [ipitchFrame];
67 		constexpr integer winningPitchCandidateNumber = 1;
68 		const double pitchValue = pitchFrame -> candidates [winningPitchCandidateNumber]. frequency;
69 		/*
70 			Get the corresponding intensity value.
71 			"Corresponding" means: measure the intensity at the same time as the pitch.
72 		*/
73 		const double time = Sampled_indexToX (pitchObject, ipitchFrame);
74 		constexpr integer onlyIntensityChannel = 1;
75 		constexpr integer defaultUnit = 0;
76 		const double intensityValue = Sampled_getValueAtX (intensityObject, time, onlyIntensityChannel, defaultUnit, true);
77 		const bool intensityMeasurementIsValid = isdefined (intensityValue);
78 		if (! intensityMeasurementIsValid)
79 			continue;   // no intensity measured, e.g. at the edges of the time domain -> don't draw
80 		/*
81 			Draw.
82 		*/
83 		constexpr integer shouldSpeckle_mask = 1;
84 		constexpr integer shouldCurve_mask = 2;
85 		if (connect & shouldSpeckle_mask)
86 			Graphics_speckle (g, pitchValue, intensityValue);
87 		if ((connect & shouldCurve_mask) && isdefined (previousPitchValue)) {
88 			/*
89 				We draw a solid line if the previous point represented the previous frame,
90 				but a dotted line if, instead, the previous frame was voiceless.
91 			*/
92 			if (previousPitchFrameNumber >= 1 && previousPitchFrameNumber < ipitchFrame - 1)
93 				Graphics_setLineType (g, Graphics_DOTTED);
94 			Graphics_line (g, previousPitchValue, previousIntensityValue, pitchValue, intensityValue);
95 			Graphics_setLineType (g, Graphics_DRAWN);
96 		}
97 		/*
98 			Cycle.
99 		*/
100 		previousPitchValue = pitchValue;
101 		previousIntensityValue = intensityValue;
102 		previousPitchFrameNumber = ipitchFrame;
103 	}
104 	Graphics_unsetInner (g);
105 	if (garnish) {
106 		Graphics_drawInnerBox (g);
107 		Graphics_textBottom (g, true, U"Fundamental frequency (Hz)");
108 		Graphics_marksBottom (g, 2, true, true, false);
109 		Graphics_textLeft (g, true, U"Intensity (dB)");
110 		Graphics_marksLeft (g, 2, true, true, false);
111 	}
112 }
113 
Pitch_Intensity_getMean(Pitch thee,Intensity me)114 double Pitch_Intensity_getMean (Pitch thee, Intensity me) {
115 	integer numberOfValidLocalMeasurements = 0;
116 	longdouble sumOfLocalValues = 0.0;
117 	for (integer iframe = 1; iframe <= my nx; iframe ++) {
118 		const double time = Sampled_indexToX (me, iframe);
119 		const bool localMeasurentIsValid = Pitch_isVoiced_t (thee, time);
120 		if (localMeasurentIsValid) {
121 			double localValue = my z [1] [iframe];
122 			sumOfLocalValues += localValue;
123 			numberOfValidLocalMeasurements += 1;
124 		}
125 	}
126 	return numberOfValidLocalMeasurements > 0 ? double (sumOfLocalValues) / numberOfValidLocalMeasurements : undefined;
127 }
128 
Pitch_Intensity_getMeanAbsoluteSlope(Pitch thee,Intensity me)129 double Pitch_Intensity_getMeanAbsoluteSlope (Pitch thee, Intensity me) {
130 	integer numberOfValidLocalMeasurements = 0;
131 	longdouble sumOfLocalAbsoluteSlopes = 0.0;
132 	for (integer iframe = 1; iframe < my nx; iframe ++) {
133 		const double t1 = Sampled_indexToX (me, iframe);
134 		const double t2 = t1 + my dx;
135 		const bool localMeasurentIsValid = ( Pitch_isVoiced_t (thee, t1) && Pitch_isVoiced_t (thee, t2) );
136 		if (localMeasurentIsValid) {
137 			double absoluteLocalSlope = fabs (my z [1] [iframe + 1] -  my z [1] [iframe]);
138 			sumOfLocalAbsoluteSlopes += absoluteLocalSlope;
139 			numberOfValidLocalMeasurements += 1;
140 		}
141 	}
142 	sumOfLocalAbsoluteSlopes /= my dx;   // convert to dB per second
143 	return numberOfValidLocalMeasurements > 0 ? double (sumOfLocalAbsoluteSlopes) / numberOfValidLocalMeasurements : undefined;
144 }
145 
146 /* End of file Pitch_Intensity.cpp */
147