Ejemplo n.º 1
0
static autoTextGrid Table_to_TextGrid (Table me, const char32 *text, double xmin, double xmax) {
	//Table_createWithColumnNames (0, L"time type type-t t-pos length a-pos sample id uniq");
	try {
		long length, textLength = str32len (text);
		long numberOfRows = my rows.size;
		long timeColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"time");
		long typeColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"type");
		long tposColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"t-pos");
		long   idColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"id");
		autoTextGrid thee = TextGrid_create (xmin, xmax, U"sentence clause word phoneme", U"");

		TextGrid_setIntervalText (thee.get(), 1, 1, text);

		long p1c = 1, p1w = 1;
		double time_phon_p = xmin;
		bool wordEnd = false;
		autoMelderString mark;

		IntervalTier clauses = (IntervalTier) thy tiers->at [2];
		IntervalTier words = (IntervalTier) thy tiers->at [3];
		IntervalTier phonemes = (IntervalTier) thy tiers->at [4];

		for (long i = 1; i <= numberOfRows; i++) {
			double time = Table_getNumericValue_Assert (me, i, timeColumnIndex);
			int type = Table_getNumericValue_Assert (me, i, typeColumnIndex);
			long pos = Table_getNumericValue_Assert (me, i, tposColumnIndex);
			if (type == espeakEVENT_SENTENCE) {
				// Only insert a new boundary, no text
				// text will be inserted at end sentence event
				if (time > xmin && time < xmax) {
					IntervalTier_addBoundaryUnsorted (clauses, clauses -> intervals.size, time, U"", true);
				}
				p1c = pos;
			} else if (type == espeakEVENT_END) {
				// End of clause: insert new boundary, and fill left interval with text
				length = pos - p1c + 1;
				MelderString_ncopy (&mark, text + p1c - 1, length);
				MelderString_trimWhiteSpaceAtEnd (& mark);
				if (time > xmin && time < xmax) {
					IntervalTier_addBoundaryUnsorted (clauses, clauses -> intervals.size, time, mark.string, true);
				} else {
					TextGrid_setIntervalText (thee.get(), 2, clauses -> intervals.size, mark.string);
				}
				p1c = pos;

				// End of clause always signals "end of a word"

				if (pos <= textLength) {
					length = pos - p1w + 1;
					MelderString_ncopy (&mark, text + p1w - 1, length);
					MelderString_trimWhiteSpaceAtEnd (& mark);
					if (time > xmin && time < xmax) {
						IntervalTier_addBoundaryUnsorted (words, words -> intervals.size, time, mark.string, true);
					} else {
						TextGrid_setIntervalText (thee.get(), 3, words -> intervals.size, mark.string);
					}
					// now the next word event should not trigger setting the left interval text
					wordEnd = false;
				}
			} else if (type == espeakEVENT_WORD) {
				if (pos < p1w) {
					continue;
				}
				if (time > xmin && time < xmax) {
					length = pos - p1w;
					if (pos == textLength) {
						length++;
					}
					MelderString_ncopy (&mark, text + p1w - 1, length);
					MelderString_trimWhiteSpaceAtEnd (& mark);
					IntervalTier_addBoundaryUnsorted (words, words -> intervals.size, time, ( wordEnd ? mark.string : U"" ), true);
				}
				wordEnd = true;
				p1w = pos;
			} else if (type == espeakEVENT_PHONEME) {
				const char32 *id = Table_getStringValue_Assert (me, i, idColumnIndex);
				if (time > time_phon_p) {
					// Insert new boudary and label interval with the id
					// TODO: Translate the id to the correct notation
					TextInterval ti = phonemes -> intervals.at [phonemes -> intervals.size];
					if (time > ti -> xmin && time < ti -> xmax) {
						IntervalTier_addBoundaryUnsorted (phonemes, phonemes -> intervals.size, time, id, false);
					}
				} else {
					// Just in case the phoneme starts at xmin we only need to set interval text
					TextGrid_setIntervalText (thee.get(), 4, phonemes -> intervals.size, id);
				}
				time_phon_p = time;
			}
		}
		clauses -> intervals. sort ();
		words -> intervals. sort ();
		phonemes -> intervals. sort ();
		
		IntervalTier_mergeSpecialIntervals (phonemes); // Merge neighbouring empty U"" and U"\001" intervals
		
		IntervalTier_removeVeryShortIntervals (words);
		IntervalTier_removeVeryShortIntervals (clauses);
		
		/* Use empty intervals in phoneme tier for more precision in the word tier */
		
		IntervalTier_insertEmptyIntervalsFromOtherTier (words, phonemes);
		IntervalTier_mergeSpecialIntervals (words); // Merge neighbouring empty U"" and U"\001" intervals

		return thee;
	} catch (MelderError) {
		Melder_throw (U"TextGrid not created from Table with events.");
	}
}
Ejemplo n.º 2
0
TextGrid Intensity_to_TextGrid_detectSilences (Intensity me, double silenceThreshold_dB,
		double minSilenceDuration, double minSoundingDuration, const char32 *silenceLabel, const char32 *soundingLabel) {
	try {
		double duration = my xmax - my xmin, time;

		if (silenceThreshold_dB >= 0) {
			Melder_throw (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"");
		IntervalTier it = (IntervalTier) thy tiers -> item[1];
		TextInterval_setText ( (TextInterval) it -> intervals -> item[1], soundingLabel);
		if (minSilenceDuration > duration) {
			return thee.transfer();
		}

		double intensity_max_db, intensity_min_db, xOfMaximum, xOfMinimum;
		Vector_getMaximumAndX (me, 0, 0, 1, NUM_PEAK_INTERPOLATE_PARABOLIC, &intensity_max_db, &xOfMaximum);
		Vector_getMinimumAndX (me, 0, 0, 1, NUM_PEAK_INTERPOLATE_PARABOLIC, &intensity_min_db, &xOfMinimum);
		double intensity_dbRange = intensity_max_db - intensity_min_db;

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

		double intensityThreshold = intensity_max_db - fabs (silenceThreshold_dB);

		if (minSilenceDuration > duration || intensityThreshold < intensity_min_db) {
			return thee.transfer();
		}

		int inSilenceInterval = my z[1][1] < intensityThreshold;
		long iinterval = 1;
		const char32 *label;
		for (long i = 2; i <= my nx; i++) {
			int addBoundary = 0;
			if (my z[1][i] < intensityThreshold) {
				if (!inSilenceInterval) { // Start of silence
					addBoundary = 1;
					inSilenceInterval = 1;
					label = soundingLabel;
				}
			} else {
				if (inSilenceInterval) { // End of silence
					addBoundary = 1;
					inSilenceInterval = 0;
					label = silenceLabel;
				}
			}

			if (addBoundary) {
				time = my x1 + (i - 1) * my dx;
				IntervalTier_addBoundaryUnsorted (it, iinterval, time, label);
				iinterval++;
			}
		}

		// (re)label last interval */

		label = inSilenceInterval ? silenceLabel : soundingLabel;
		TextInterval_setText ( (TextInterval) it -> intervals -> item[iinterval], label);
		Sorted_sort (it -> intervals);

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

		IntervalTier_cutIntervals_minimumDuration (it, soundingLabel, minSoundingDuration);
		IntervalTier_cutIntervalsOnLabelMatch (it, silenceLabel);
		IntervalTier_cutIntervals_minimumDuration (it, silenceLabel, minSilenceDuration);
		IntervalTier_cutIntervalsOnLabelMatch (it, soundingLabel);

		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, U": TextGrid not created.");
	}
}
Ejemplo n.º 3
0
static autoTextGrid Table_to_TextGrid (Table me, const char32 *text, double xmin, double xmax) {
	//Table_createWithColumnNames (0, L"time type type-t t-pos length a-pos sample id uniq");
	try {
		long length, textLength = str32len (text);
		long numberOfRows = my rows -> size;
		long timeColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"time");
		long typeColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"type");
		long tposColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"t-pos");
		long   idColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"id");
		autoTextGrid thee = TextGrid_create (xmin, xmax, U"sentence clause word phoneme", U"");

		TextGrid_setIntervalText (thee.peek(), 1, 1, text);

		long p1c = 1, p1w = 1;
		double t1p = xmin;
		bool wordEnd = false;
		autoMelderString mark;

		IntervalTier itc = (IntervalTier) thy tiers -> item[2];
		IntervalTier itw = (IntervalTier) thy tiers -> item[3];
		IntervalTier itp = (IntervalTier) thy tiers -> item[4];

		for (long i = 1; i <= numberOfRows; i++) {
			double time = Table_getNumericValue_Assert (me, i, timeColumnIndex);
			int type = Table_getNumericValue_Assert (me, i, typeColumnIndex);
			long pos = Table_getNumericValue_Assert (me, i, tposColumnIndex);
			if (type == espeakEVENT_SENTENCE) {
				// Only insert a new boundary, no text
				// text will be inserted at end sentence event
				if (time > xmin and time < xmax) {
					IntervalTier_addBoundaryUnsorted (itc, itc -> intervals -> size, time, U"", true);
				}
				p1c = pos;
			} else if (type == espeakEVENT_END) {
				// End of clause: insert new boundary, and fill left interval with text
				length = pos - p1c + 1;
				MelderString_ncopy (&mark, text + p1c - 1, length);
				MelderString_trimWhiteSpaceAtEnd (&mark);
				if (time > xmin and time < xmax) {
					IntervalTier_addBoundaryUnsorted (itc, itc -> intervals -> size, time, mark.string, true);
				} else {
					TextGrid_setIntervalText (thee.peek(), 2, itc -> intervals -> size, mark.string);
				}
				p1c = pos;

				// End of clause always signals "end of a word"

				if (pos <= textLength) {
					length = pos - p1w + 1;
					MelderString_ncopy (&mark, text + p1w - 1, length);
					MelderString_trimWhiteSpaceAtEnd (&mark);
					if (time > xmin and time < xmax) {
						IntervalTier_addBoundaryUnsorted (itw, itw -> intervals -> size, time, mark.string, true);
					} else {
						TextGrid_setIntervalText (thee.peek(), 3, itw -> intervals -> size, mark.string);
					}
					// now the next word event should not trigger setting the left interval text
					wordEnd = false;
				}
			} else if (type == espeakEVENT_WORD) {
				if (pos < p1w) {
					continue;
				}
				if (time > xmin and time < xmax) {
					length = pos - p1w;
					if (pos == textLength) length++;
					MelderString_ncopy (&mark, text + p1w - 1, length);
					MelderString_trimWhiteSpaceAtEnd (&mark);
					IntervalTier_addBoundaryUnsorted (itw, itw -> intervals -> size, time, (wordEnd ? mark.string : U""), true);
				}
				wordEnd = true;
				p1w = pos;
			} else if (type == espeakEVENT_PHONEME) {
				const char32 *id = Table_getStringValue_Assert (me, i, idColumnIndex);
				if (time > t1p) {
					// Insert new boudary and label interval with the id
					// TODO: Translate the id to the correct notation
					TextInterval ti = (TextInterval) itp -> intervals -> item[itp -> intervals -> size];
					if (time > ti -> xmin and time < ti -> xmax) {
						IntervalTier_addBoundaryUnsorted (itp, itp -> intervals -> size, time, id, false);
					}
				} else {
					// Just in case the phoneme starts at xmin we only need to set interval text
					TextGrid_setIntervalText (thee.peek(), 4, itp -> intervals -> size, id);
				}
				t1p = time;
			}
		}
		Sorted_sort (itc -> intervals);
		Sorted_sort (itw -> intervals);
		Sorted_sort (itp -> intervals);
		return thee;
	} catch (MelderError) {
		Melder_throw (U"TextGrid not created from Table with events.");
	}
}