File: Intensity_extensions.cpp

package info (click to toggle)
praat 6.4.27%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 206,060 kB
  • sloc: cpp: 1,409,811; ansic: 286,305; makefile: 946; python: 340; sh: 35
file content (157 lines) | stat: -rw-r--r-- 5,676 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* Intensity_extensions.cpp
 *
 * Copyright (C) 2007-2019 David Weenink, 2015,2017 Paul Boersma
 *
 * This code is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This code is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this work. If not, see <http://www.gnu.org/licenses/>.
 */

/*
 djmw 20061204 Initial version
 djmw 20070129 Extra argument for Vector_get<Maximum/Minimum>AndX
 djmw 20071201 Melder_warning<n>
 djmw 20090818 Intensity_to_TextGrid_detectSilences: mark last interval also if sounding
*/

#include "Intensity_extensions.h"
#include "TextGrid_extensions.h"

static void IntervalTier_addBoundaryUnsorted (IntervalTier me, integer iinterval, double time, conststring32 leftLabel) {
	Melder_require (time > my xmin && time < my xmax,
		U"Time is outside interval.");
	/*
		Find interval to split.
	*/
	if (iinterval <= 0)
		iinterval = IntervalTier_timeToLowIndex (me, time);

	/*
		Modify end time of left label.
	*/
	const TextInterval ti = my intervals.at [iinterval];
	ti -> xmax = time;
	TextInterval_setText (ti, leftLabel);

	autoTextInterval ti_new = TextInterval_create (time, my xmax, U"");
	my intervals. addItem_unsorted_move (ti_new.move());
}

autoTextGrid Intensity_to_TextGrid_detectSilences (Intensity me,
	double silenceThreshold_dB, double minSilenceDuration, double minSoundingDuration,
	conststring32 silenceLabel, conststring32 soundingLabel)
{
	try {
		const double duration = my xmax - my xmin;

		Melder_require (silenceThreshold_dB < 0.0,
			U"The silence threshold w.r.t. the maximum intensity should be a negative number.");

		autoTextGrid thee = TextGrid_create (my xmin, my xmax, U"silences", U"");
		const IntervalTier it = (IntervalTier) thy tiers->at [1];
		TextInterval_setText (it -> intervals.at [1], soundingLabel);
		if (minSilenceDuration > duration)
			return thee;

		double intensity_max_db, intensity_min_db, xOfMaximum, xOfMinimum;
		Vector_getMaximumAndX (me, 0.0, 0.0, 1, kVector_peakInterpolation :: PARABOLIC, & intensity_max_db, & xOfMaximum);
		Vector_getMinimumAndX (me, 0.0, 0.0, 1, kVector_peakInterpolation :: PARABOLIC, & intensity_min_db, & xOfMinimum);
		const double intensity_dbRange = intensity_max_db - intensity_min_db;

		if (intensity_dbRange < 10.0)
			Melder_warning (U"The loudest and softest part in your sound differ by only ", intensity_dbRange, U" dB.");

		const double intensityThreshold = intensity_max_db - fabs (silenceThreshold_dB);

		if (minSilenceDuration > duration || intensityThreshold < intensity_min_db)
			return thee;

		bool inSilenceInterval = my z [1] [1] < intensityThreshold;
		integer iinterval = 1;
		conststring32 label;
		for (integer i = 2; i <= my nx; i ++) {
			bool addBoundary = false;
			if (my z [1] [i] < intensityThreshold) {
				if (! inSilenceInterval) {   // start of silence
					addBoundary = true;
					inSilenceInterval = true;
					label = soundingLabel;
				}
			} else {
				if (inSilenceInterval) {   // end of silence
					addBoundary = true;
					inSilenceInterval = false;
					label = silenceLabel;
				}
			}

			if (addBoundary) {
				const double time = my x1 + (i - 1) * my dx;
				IntervalTier_addBoundaryUnsorted (it, iinterval, time, label);
				iinterval ++;
			}
		}
		/*
			(re)label last interval.
		*/
		label = inSilenceInterval ? silenceLabel : soundingLabel;
		TextInterval_setText (it -> intervals.at [iinterval], label);
		it -> intervals. sort ();

		/*
			First remove short non-silence intervals in-between silence intervals and
			then remove the remaining short silence intervals.
			This works much better than first removing short silence intervals and
			then short non-silence intervals.
		*/
		if (minSoundingDuration > 0.0) {
			IntervalTier_cutIntervals_minimumDuration (it, soundingLabel, minSoundingDuration);
			IntervalTier_combineIntervalsOnLabelMatch (it, silenceLabel);
		}
		if (minSilenceDuration > 0.0) {
			IntervalTier_cutIntervals_minimumDuration (it, silenceLabel, minSilenceDuration);
			IntervalTier_combineIntervalsOnLabelMatch (it, soundingLabel);
		}

		return thee;
	} catch (MelderError) {
		Melder_throw (me, U": TextGrid not created.");
	}
}

autoIntensity IntensityTier_to_Intensity (IntensityTier me, double dt) {
	try {
		const integer nt = Melder_ifloor ((my xmax - my xmin) / dt);
		const double t1 = 0.5 * dt;
		autoIntensity thee = Intensity_create (my xmin, my xmax, nt, dt, t1);
		for (integer i = 1; i <= nt; i ++) {
			const double time = t1 + (i - 1) * dt;
			thy z [1] [i] = RealTier_getValueAtTime (me, time);
		}
		return thee;
	} catch (MelderError) {
		Melder_throw (me, U": Intensity not created.");
	}
}

autoTextGrid IntensityTier_to_TextGrid_detectSilences (IntensityTier me, double dt, double silenceThreshold_dB, double minSilenceDuration,
	double minSoundingDuration, conststring32 silenceLabel, conststring32 soundingLabel) {
	try {
		autoIntensity intensity = IntensityTier_to_Intensity (me, dt);
		autoTextGrid thee = Intensity_to_TextGrid_detectSilences (intensity.get(), silenceThreshold_dB, minSilenceDuration, minSoundingDuration, silenceLabel, soundingLabel);
		return thee;
	} catch (MelderError) {
		Melder_throw (me, U": TextGrid not created.");
	}
}

/* End of file Intensity_extensions.cpp */