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