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 */
|