Пример #1
0
static void IntervalTier_insertEmptyIntervalsFromOtherTier (IntervalTier to, IntervalTier from) {
	for (long iint = 1; iint <= from -> intervals.size; iint ++) {
		TextInterval tifrom = from -> intervals.at [iint];
		if (TextInterval_labelLength (tifrom) == 0) {   // found empty interval
			double t_left = tifrom -> xmin, t_right = tifrom -> xmax;
			long intervalIndex_to = IntervalTier_timeToLowIndex (to, t_left);
			if (intervalIndex_to > 0) {   // insert to the right of intervalIndex_to
				TextInterval tito = to -> intervals.at [intervalIndex_to];
				if (! almost_equal (tito -> xmin, t_left)) {   // not on the start boundary of the interval, it cannot be at xmax
					autoTextInterval newInterval = TextInterval_create (t_left, tito -> xmax, U"");
					tito -> xmax = t_left;
					to -> intervals. addItem_move (newInterval.move());
				}
			}
			intervalIndex_to = IntervalTier_timeToHighIndex (to, t_right);
			TextInterval tito = to -> intervals.at [intervalIndex_to];
			if (intervalIndex_to > 0) {
				if (! almost_equal (t_right, tito -> xmax)) {   // insert to the left of intervalIndex_to
					autoTextInterval newInterval = TextInterval_create (tito -> xmin, t_right, U"");
					tito -> xmin = t_right;
					to -> intervals. addItem_move (newInterval.move());
				}
			}
		}
	}
}
Пример #2
0
static void IntervalTier_add (IntervalTier me, double xmin, double xmax, const char32 *label) {
	long i = IntervalTier_timeToIndex (me, xmin); // xmin is in interval i
	if (i < 1) {
		Melder_throw (U"Index too low.");
	}

	autoTextInterval newti = TextInterval_create (xmin, xmax, label);
	TextInterval interval = (TextInterval) my intervals -> item[i];
	double xmaxi = interval -> xmax;
	if (xmax > xmaxi) {
		Melder_throw (U"Don't know what to do");    // Don't know what to do
	}
	if (xmin == interval -> xmin) {
		if (xmax == interval -> xmax) { // interval already present
			TextInterval_setText (interval, label);
			return;
		}
		// split interval
		interval -> xmin = xmax;
		Collection_addItem (my intervals, newti.transfer());
		return;
	}
	interval -> xmax = xmin;
	Collection_addItem (my intervals, newti.transfer());
	// extra interval when xmax's are not the same
	if (xmax < xmaxi) {
		autoTextInterval newti2 = TextInterval_create (xmax, xmaxi, interval -> text);
		Collection_addItem (my intervals, newti2.transfer());
	}
}
Пример #3
0
static void IntervalTier_insertIntervalDestructively (IntervalTier me, double tmin, double tmax) {
	Melder_assert (tmin < tmax);
	Melder_assert (tmin >= my xmin);
	Melder_assert (tmax <= my xmax);
	/*
	 * Make sure that the tier has boundaries at the edges of the interval.
	 */
	long firstIntervalNumber = IntervalTier_hasTime (me, tmin);
	if (! firstIntervalNumber) {
		long intervalNumber = IntervalTier_timeToIndex (me, tmin);
		if (intervalNumber == 0)
			Melder_throw (U"Cannot add a boundary at ", Melder_fixed (tmin, 6), U" seconds, because this is outside the time domain of the intervals.");
		TextInterval interval = my intervals.at [intervalNumber];
		/*
		 * Move the text to the left of the boundary.
		 */
		autoTextInterval newInterval = TextInterval_create (tmin, interval -> xmax, U"");
		interval -> xmax = tmin;
		my intervals. addItem_move (newInterval.move());
		firstIntervalNumber = IntervalTier_hasTime (me, interval -> xmin);
	}
	Melder_assert (firstIntervalNumber >= 1 && firstIntervalNumber <= my intervals.size);
	long lastIntervalNumber = IntervalTier_hasTime (me, tmax);
	if (! lastIntervalNumber) {
		long intervalNumber = IntervalTier_timeToIndex (me, tmax);
		if (intervalNumber == 0)
			Melder_throw (U"Cannot add a boundary at ", Melder_fixed (tmin, 6), U" seconds, because this is outside the time domain of the intervals.");
		TextInterval interval = my intervals.at [intervalNumber];
		/*
		 * Move the text to the right of the boundary.
		 */
		autoTextInterval newInterval = TextInterval_create (interval -> xmin, tmax, U"");
		interval -> xmin = tmax;
		my intervals. addItem_move (newInterval.move());
		lastIntervalNumber = IntervalTier_hasTime (me, interval -> xmax);
	}
	Melder_assert (lastIntervalNumber >= 1 && lastIntervalNumber <= my intervals.size);
	/*
	 * Empty the interval in the word tier.
	 */
	trace (U"Empty interval %ld down to ", lastIntervalNumber, U".", firstIntervalNumber);
	for (long iinterval = lastIntervalNumber; iinterval >= firstIntervalNumber; iinterval --) {
		TextInterval interval = my intervals.at [iinterval];
		if (interval -> xmin > tmin && interval -> xmin < tmax) {
			Melder_assert (iinterval > 1);
			TextInterval previous = my intervals.at [iinterval - 1];
			previous -> xmax = tmax;   // collapse left and right intervals into left interval
			TextInterval_setText (previous, U"");
			my intervals. removeItem (iinterval);   // remove right interval
		}
		if (interval -> xmax == tmax) {
			TextInterval_setText (interval, U"");
		}
	}
}
// Precondition: if (preserveTimes) { my xmax <= thy xmin }
// Postcondition: my xmin preserved
void IntervalTiers_append_inline (IntervalTier me, IntervalTier thee, bool preserveTimes) {
	try {
        double xmax_previous = my xmax, time_shift = my xmax - thy xmin;
		if (preserveTimes && my xmax < thy xmin) {
			autoTextInterval connection = TextInterval_create (my xmax, thy xmin, L"");
            xmax_previous = thy xmin;
			Collection_addItem (my intervals, connection.transfer());
		}
		for (long iint = 1; iint <= thy intervals -> size; iint++) {
			autoTextInterval ti = (TextInterval) Data_copy ((Data) thy intervals -> item[iint]);
			if (preserveTimes) {
				Collection_addItem (my intervals, ti.transfer());
			} else {
				/* the interval could be so short that if we test ti -> xmin < ti->xmax it might be true
				 * but after assigning ti->xmin = xmax_previous and ti->xmax += time_shift the test
				 * ti -> xmin < ti->xmax might be false!
				 * We want to make sure xmin and xmax are not register variables and therefore force double64 
				 * by using volatile variables.
		 		 */
				volatile double xmin = xmax_previous;
				volatile double xmax = ti -> xmax + time_shift;
				if (xmin < xmax) {
					ti -> xmin = xmin; ti -> xmax = xmax;
					Collection_addItem (my intervals, ti.transfer());
					xmax_previous = xmax;
				}
				// else don't include interval
            }
		}
		my xmax = preserveTimes ? thy xmax : xmax_previous;
	} catch (MelderError) {
		Melder_throw ("IntervalTiers not appended.");
	}
}
Пример #5
0
void IntervalTier_setEarlierStartTime (IntervalTier me, double xmin, const char32 *mark) {
	try {
		if (xmin >= my xmin) return; // nothing to be done
		TextInterval ti = (TextInterval) my intervals -> item[1];
		Melder_assert (xmin < ti -> xmin);
		if (mark != NULL) {
			autoTextInterval interval = TextInterval_create (xmin, ti -> xmin, mark);
			Collection_addItem (my intervals, interval.transfer());
		} else {
			// extend first interval
			ti -> xmin = xmin;
		}
		my xmin = xmin;
	} catch (MelderError) {
		Melder_throw (U"Earlier start time of IntervalTier not set.");
	}
}
Пример #6
0
void IntervalTier_setLaterEndTime (IntervalTier me, double xmax, const char32 *mark) {
	try {
		if (xmax <= my xmax) return; // nothing to be done
		TextInterval ti = (TextInterval) my intervals -> item[my intervals -> size];
		Melder_assert (xmax > ti -> xmax);
		if (mark != NULL) {
			autoTextInterval interval = TextInterval_create (ti -> xmax, xmax, mark);
			Collection_addItem (my intervals, interval.transfer());
		} else {
			// extend last interval
			ti -> xmax = xmax;
		}
		my xmax = xmax;
	} catch (MelderError) {
		Melder_throw (U"Larger end time of IntervalTier not set.");
	}
}
Пример #7
0
static void IntervalTier_addBoundaryUnsorted (IntervalTier me, long iinterval, double time, const char32 *leftLabel) {
	if (time <= my xmin || time >= my xmax) {
		Melder_throw (U"Time is outside interval.");
	}

	// Find interval to split
	if (iinterval <= 0) {
		iinterval = IntervalTier_timeToLowIndex (me, time);
	}

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

	autoTextInterval ti_new = TextInterval_create (time, my xmax, U"");
	Sorted_addItem_unsorted (my intervals, ti_new.transfer());
}
Пример #8
0
static void IntervalTier_addBoundaryUnsorted (IntervalTier me, long iinterval, double time, const char32 *newLabel, bool isNewleftLabel) {
	if (time <= my xmin || time >= my xmax) {
		Melder_throw (U"Time is outside interval domains.");
	}

	// Find interval to split
	if (iinterval <= 0) {
		iinterval = IntervalTier_timeToLowIndex (me, time);
	}

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

	autoTextInterval ti_new = TextInterval_create (time, my xmax, (! isNewleftLabel ? newLabel : U"" ));
	my intervals. addItem_unsorted_move (ti_new.move());
}
Пример #9
0
void TextGrid_extendTime (TextGrid me, double extra_time, int position) {
	autoTextGrid thee = 0;
	try {
		double xmax = my xmax, xmin = my xmin;
		int at_end = position == 0;

		if (extra_time == 0) {
			return;
		}
		extra_time = fabs (extra_time); // Just in case...
		thee.reset (Data_copy (me));

		if (at_end) {
			xmax += extra_time;
		} else {
			xmin -= extra_time;
		}

		for (long i = 1; i <= my tiers -> size; i++) {
			Function anyTier = (Function) my tiers -> item [i];
			double tmin = anyTier -> xmin, tmax = anyTier -> xmax;

			if (at_end) {
				anyTier -> xmax = xmax;
				tmin = tmax;
				tmax = xmax;
			} else {
				anyTier -> xmin = xmin;
				tmax = tmin;
				tmin = xmin;
			}
			if (anyTier -> classInfo == classIntervalTier) {
				IntervalTier tier = (IntervalTier) anyTier;
				autoTextInterval interval = TextInterval_create (tmin, tmax, U"");
				Collection_addItem (tier -> intervals, interval.transfer());
			}
		}
		my xmin = xmin;
		my xmax = xmax;
	} catch (MelderError) {
		Melder_throw (me, U": time not extended.");
	}
}
Пример #10
0
// Precondition: if (preserveTimes) { my xmax <= thy xmin }
// Postcondition: my xmin preserved
void IntervalTiers_append_inline (IntervalTier me, IntervalTier thee, bool preserveTimes) {
	try {
        double xmax_previous = my xmax, time_shift = my xmax - thy xmin;
		if (preserveTimes && my xmax < thy xmin) {
			autoTextInterval connection = TextInterval_create (my xmax, thy xmin, L"");
            xmax_previous = thy xmin;
			Collection_addItem (my intervals, connection.transfer());
		}
		for (long iint = 1; iint <= thy intervals -> size; iint++) {
			autoTextInterval ti = (TextInterval) Data_copy ((Data) thy intervals -> item[iint]);
			if (not preserveTimes) {
				ti -> xmin = xmax_previous;
				xmax_previous = ti -> xmax += time_shift;
            }
			Collection_addItem (my intervals, ti.transfer());
		}
		my xmax = preserveTimes ? thy xmax : xmax_previous;
	} catch (MelderError) {
		Melder_throw ("IntervalTiers not appended.");
	}
}
void IntervalTier_splitInterval (IntervalTier me, double time, const char32 *leftLabel, long interval, double precision) {
    try {
		Melder_assert (interval > 0);
        TextInterval ti = nullptr;
		long index = 0; 
        for (long i = interval; i <= my intervals.size; i ++) {
            ti = my intervals.at [i];
            if (time < ti -> xmax + precision && time > ti -> xmin - precision) {
                index = i; break;
            }
        }
        // if index == 0 then search left intervals??
        if (index == 0 || TIMES_ARE_CLOSE(time, ti -> xmin) || TIMES_ARE_CLOSE(time, ti -> xmax)) {
            return;
        }
        autoTextInterval newInterval = TextInterval_create (ti -> xmin, time, leftLabel);
        // Make start of current and begin of new interval equal
        ti -> xmin = time;
        my intervals. addItem_move (newInterval.move());
    } catch (MelderError) {
        Melder_throw (U"Boundary not inserted.");
    }

}
Пример #12
0
void TextGrid_anySound_alignInterval (TextGrid me, Function anySound, long tierNumber, long intervalNumber, const char32 *languageName, bool includeWords, bool includePhonemes) {
	try {
		IntervalTier headTier = TextGrid_checkSpecifiedTierIsIntervalTier (me, tierNumber);
		if (intervalNumber < 1 || intervalNumber > headTier -> intervals.size)
			Melder_throw (U"Interval ", intervalNumber, U" does not exist.");
		TextInterval interval = headTier -> intervals.at [intervalNumber];
		if (! includeWords && ! includePhonemes)
			Melder_throw (U"Nothing to be done, because you asked neither for word alignment nor for phoneme alignment.");
		if (str32str (headTier -> name, U"/") )
			Melder_throw (U"The current tier already has a slash (\"/\") in its name. Cannot create a word or phoneme tier from it.");
		autoSound part =
			anySound -> classInfo == classLongSound ? 
				LongSound_extractPart (static_cast <LongSound> (anySound), interval -> xmin, interval -> xmax, true) :
				Sound_extractPart (static_cast <Sound> (anySound), interval -> xmin, interval -> xmax, kSound_windowShape_RECTANGULAR, 1.0, true);
		autoSpeechSynthesizer synthesizer = SpeechSynthesizer_create (languageName, U"default");
		double silenceThreshold = -35, minSilenceDuration = 0.1, minSoundingDuration = 0.1;
		autoTextGrid analysis;
		if (! Melder_equ (interval -> text, U"")) {
			try {
				analysis = SpeechSynthesizer_and_Sound_and_TextInterval_align
					(synthesizer.get(), part.get(), interval, silenceThreshold, minSilenceDuration, minSoundingDuration);
			} catch (MelderError) {
				Melder_clearError ();   // ignore all error messages from DTW and the like
			}
		}
		if (analysis) {
			/*
			 * Clean up the analysis.
			 */
			Melder_assert (analysis -> xmin == interval -> xmin);
			Melder_assert (analysis -> xmax == interval -> xmax);
			Melder_assert (analysis -> tiers->size == 4);
			Thing_cast (IntervalTier, analysisWordTier, analysis -> tiers->at [3]);
			if (! IntervalTier_check (analysisWordTier))
				Melder_throw (U"Analysis word tier out of order.");
			IntervalTier_removeEmptyIntervals (analysisWordTier, nullptr);
			Melder_assert (analysisWordTier -> xmax == analysis -> xmax);
			Melder_assert (analysisWordTier -> intervals.size >= 1);
			TextInterval firstInterval = analysisWordTier -> intervals.at [1];
			TextInterval lastInterval = analysisWordTier -> intervals.at [analysisWordTier -> intervals.size];
			firstInterval -> xmin = analysis -> xmin;
			lastInterval  -> xmax = analysis -> xmax;
			if (lastInterval -> xmax != analysis -> xmax)
				Melder_fatal (U"analysis ends at ", analysis -> xmax, U", but last interval at ", lastInterval -> xmax, U" seconds");
			if (! IntervalTier_check (analysisWordTier))
				Melder_throw (U"Analysis word tier out of order (2).");
			Thing_cast (IntervalTier, analysisPhonemeTier, analysis -> tiers->at [4]);
			if (! IntervalTier_check (analysisPhonemeTier))
				Melder_throw (U"Analysis phoneme tier out of order.");
			IntervalTier_removeEmptyIntervals (analysisPhonemeTier, analysisWordTier);
			Melder_assert (analysisPhonemeTier -> xmax == analysis -> xmax);
			Melder_assert (analysisPhonemeTier -> intervals.size >= 1);
			firstInterval = analysisPhonemeTier -> intervals.at [1];
			lastInterval  = analysisPhonemeTier -> intervals.at [analysisPhonemeTier -> intervals.size];
			firstInterval -> xmin = analysis -> xmin;
			lastInterval  -> xmax = analysis -> xmax;
			Melder_assert (lastInterval -> xmax == analysis -> xmax);
			if (! IntervalTier_check (analysisPhonemeTier))
				Melder_throw (U"Analysis phoneme tier out of order (2).");
		}
		long wordTierNumber = 0, phonemeTierNumber = 0;
		IntervalTier wordTier = nullptr, phonemeTier = nullptr;
		/*
		 * Include a word tier.
		 */
		if (includeWords) {
			/*
			 * Make sure that the word tier exists.
			 */
			autoMelderString newWordTierName;
			MelderString_copy (& newWordTierName, headTier -> name, U"/word");
			for (long itier = 1; itier <= my tiers->size; itier ++) {
				IntervalTier tier = static_cast <IntervalTier> (my tiers->at [itier]);
				if (Melder_equ (newWordTierName.string, tier -> name)) {
					if (tier -> classInfo != classIntervalTier)
						Melder_throw (U"A tier with the prospective word tier name (", tier -> name, U") already exists, but it is not an interval tier."
							U"\nPlease change its name or remove it.");
					wordTierNumber = itier;
					break;
				}
			}
			if (! wordTierNumber) {
				autoIntervalTier newWordTier = IntervalTier_create (my xmin, my xmax);
				Thing_setName (newWordTier.get(), newWordTierName.string);
				my tiers -> addItemAtPosition_move (newWordTier.move(), wordTierNumber = tierNumber + 1);
			}
			Melder_assert (wordTierNumber >= 1 && wordTierNumber <= my tiers->size);
			wordTier = static_cast <IntervalTier> (my tiers->at [wordTierNumber]);
			/*
			 * Make sure that the word tier has boundaries at the edges of the interval.
			 */
			IntervalTier_insertIntervalDestructively (wordTier, interval -> xmin, interval -> xmax);
			/*
			 * Copy the contents of the word analysis into the interval in the word tier.
			 */
			long wordIntervalNumber = IntervalTier_hasTime (wordTier, interval -> xmin);
			Melder_assert (wordIntervalNumber != 0);
			if (analysis) {
				Thing_cast (IntervalTier, analysisWordTier, analysis -> tiers->at [3]);
				if (! IntervalTier_check (analysisWordTier))
					Melder_throw (U"Analysis word tier out of order (3).");
				if (! IntervalTier_check (wordTier))
					Melder_throw (U"Word tier out of order (3).");
				for (long ianalysisInterval = 1; ianalysisInterval <= analysisWordTier -> intervals.size; ianalysisInterval ++) {
					TextInterval analysisInterval = analysisWordTier -> intervals.at [ianalysisInterval];
					TextInterval wordInterval = nullptr;
					double tmin = analysisInterval -> xmin, tmax = analysisInterval -> xmax;
					if (tmax == analysis -> xmax) {
						wordInterval = wordTier -> intervals.at [wordIntervalNumber];
						TextInterval_setText (wordInterval, analysisInterval -> text);
					} else {
						wordInterval = wordTier -> intervals.at [wordIntervalNumber];
						autoTextInterval newInterval = TextInterval_create (tmin, tmax, analysisInterval -> text);
						wordInterval -> xmin = tmax;
						wordTier -> intervals. addItem_move (newInterval.move());
						wordIntervalNumber ++;
					}
				}
				if (! IntervalTier_check (analysisWordTier))
					Melder_throw (U"Analysis word tier out of order (4).");
				if (! IntervalTier_check (wordTier))
					Melder_throw (U"Word tier out of order (4).");
			}
		}
		/*
		 * Include a phoneme tier.
		 */
		if (includePhonemes) {
			/*
			 * Make sure that the phoneme tier exists.
			 */
			autoMelderString newPhonemeTierName;
			MelderString_copy (& newPhonemeTierName, headTier -> name, U"/phon");
			for (long itier = 1; itier <= my tiers->size; itier ++) {
				IntervalTier tier = (IntervalTier) my tiers->at [itier];
				if (Melder_equ (newPhonemeTierName.string, tier -> name)) {
					if (tier -> classInfo != classIntervalTier)
						Melder_throw (U"A tier with the prospective phoneme tier name (", tier -> name, U") already exists, but it is not an interval tier."
							U"\nPlease change its name or remove it.");
					phonemeTierNumber = itier;
					break;
				}
			}
			if (! phonemeTierNumber) {
				autoIntervalTier newPhonemeTier = IntervalTier_create (my xmin, my xmax);
				Thing_setName (newPhonemeTier.get(), newPhonemeTierName.string);
				my tiers -> addItemAtPosition_move (newPhonemeTier.move(),
					phonemeTierNumber = wordTierNumber ? wordTierNumber + 1 : tierNumber + 1);
			}
			Melder_assert (phonemeTierNumber >= 1 && phonemeTierNumber <= my tiers->size);
			phonemeTier = static_cast <IntervalTier> (my tiers->at [phonemeTierNumber]);
			/*
			 * Make sure that the phoneme tier has boundaries at the edges of the interval.
			 */
			IntervalTier_insertIntervalDestructively (phonemeTier, interval -> xmin, interval -> xmax);
			/*
			 * Copy the contents of the phoneme analysis into the interval in the phoneme tier.
			 */
			long phonemeIntervalNumber = IntervalTier_hasTime (phonemeTier, interval -> xmin);
			Melder_assert (phonemeIntervalNumber != 0);
			if (analysis.get()) {
				Thing_cast (IntervalTier, analysisPhonemeTier, analysis -> tiers->at [4]);
				for (long ianalysisInterval = 1; ianalysisInterval <= analysisPhonemeTier -> intervals.size; ianalysisInterval ++) {
					TextInterval analysisInterval = analysisPhonemeTier -> intervals.at [ianalysisInterval];
					TextInterval phonemeInterval = nullptr;
					double tmin = analysisInterval -> xmin, tmax = analysisInterval -> xmax;
					if (tmax == analysis -> xmax) {
						phonemeInterval = phonemeTier -> intervals.at [phonemeIntervalNumber];
						TextInterval_setText (phonemeInterval, analysisInterval -> text);
					} else {
						phonemeInterval = phonemeTier -> intervals.at [phonemeIntervalNumber];
						autoTextInterval newInterval = TextInterval_create (tmin, tmax, analysisInterval -> text);
						phonemeInterval -> xmin = tmax;
						phonemeTier -> intervals. addItem_move (newInterval.move());
						phonemeIntervalNumber ++;
					}
				}
			}
			if (includeWords) {
				/*
				 * Synchronize the boundaries between the word tier and the phoneme tier.
				 */
				//for (long iinterval = 1; iinterval <=
			}
		}
	} catch (MelderError) {
		Melder_throw (me, U" & ", anySound, U": interval not aligned.");
	}
}