예제 #1
0
void structCategories :: v_readText (MelderReadText a_text, int /*formatVersion*/) {
	long l_size = texgeti4 (a_text);
	if (l_size == 0) {
		OrderedOfString_init (this, 1);
	} else if (l_size < 0) {
		Melder_throw (U"Size cannot be negative.");
	} else {
		OrderedOfString_init (this, l_size);
	}
	for (long i = 1; i <= l_size; i ++) {
		autoSimpleString itemi = Thing_new (SimpleString);
		itemi -> v_readText (a_text, 0);
		Ordered_addItemPos (this, itemi.transfer(), i);
	}
}
예제 #2
0
void TextGrid_anySound_alignInterval (TextGrid me, Function anySound, long tierNumber, long intervalNumber, const wchar_t *languageName, bool includeWords, bool includePhonemes) {
	try {
		IntervalTier headTier = TextGrid_checkSpecifiedTierIsIntervalTier (me, tierNumber);
		if (intervalNumber < 1 || intervalNumber > headTier -> numberOfIntervals ())
			Melder_throw ("Interval ", intervalNumber, " does not exist.");
		TextInterval interval = headTier -> interval (intervalNumber);
		if (! includeWords && ! includePhonemes)
			Melder_throw ("Nothing to be done, because you asked neither for word alignment nor for phoneme alignment.");
		if (wcsstr (headTier -> name, L"/") )
			Melder_throw ("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, L"default");
		double silenceThreshold = -35, minSilenceDuration = 0.1, minSoundingDuration = 0.1;
		autoTextGrid analysis = NULL;
		if (! Melder_wcsequ (interval -> text, L"")) {
			try {
				analysis.reset (SpeechSynthesizer_and_Sound_and_TextInterval_align
					(synthesizer.peek(), part.peek(), interval, silenceThreshold, minSilenceDuration, minSoundingDuration));
			} catch (MelderError) {
				Melder_clearError ();   // ignore all error messages from DTW and the like
			}
		}
		if (analysis.peek()) {
			/*
			 * Clean up the analysis.
			 */
			Melder_assert (analysis -> xmin == interval -> xmin);
			Melder_assert (analysis -> xmax == interval -> xmax);
			Melder_assert (analysis -> numberOfTiers () == 4);
			Thing_cast (IntervalTier, analysisWordTier, analysis -> tier (3));
			if (! IntervalTier_check (analysisWordTier))
				Melder_throw (L"Analysis word tier out of order.");
			IntervalTier_removeEmptyIntervals (analysisWordTier, NULL);
			Melder_assert (analysisWordTier -> xmax == analysis -> xmax);
			Melder_assert (analysisWordTier -> numberOfIntervals () >= 1);
			TextInterval firstInterval = analysisWordTier -> interval (1);
			TextInterval lastInterval = analysisWordTier -> interval (analysisWordTier -> numberOfIntervals ());
			firstInterval -> xmin = analysis -> xmin;
			lastInterval  -> xmax = analysis -> xmax;
			if (lastInterval -> xmax != analysis -> xmax)
				Melder_fatal ("analysis ends at %ls, but last interval at %ls seconds",
					Melder_double (analysis -> xmax), Melder_double (lastInterval -> xmax));
			if (! IntervalTier_check (analysisWordTier))
				Melder_throw (L"Analysis word tier out of order (2).");
			Thing_cast (IntervalTier, analysisPhonemeTier, analysis -> tier (4));
			if (! IntervalTier_check (analysisPhonemeTier))
				Melder_throw (L"Analysis phoneme tier out of order.");
			IntervalTier_removeEmptyIntervals (analysisPhonemeTier, analysisWordTier);
			Melder_assert (analysisPhonemeTier -> xmax == analysis -> xmax);
			Melder_assert (analysisPhonemeTier -> numberOfIntervals () >= 1);
			firstInterval = analysisPhonemeTier -> interval (1);
			lastInterval  = analysisPhonemeTier -> interval (analysisPhonemeTier -> numberOfIntervals ());
			firstInterval -> xmin = analysis -> xmin;
			lastInterval  -> xmax = analysis -> xmax;
			Melder_assert (lastInterval -> xmax == analysis -> xmax);
			if (! IntervalTier_check (analysisPhonemeTier))
				Melder_throw (L"Analysis phoneme tier out of order (2).");
		}
		long wordTierNumber = 0, phonemeTierNumber = 0;
		IntervalTier wordTier = NULL, phonemeTier = NULL;
		/*
		 * Include a word tier.
		 */
		if (includeWords) {
			/*
			 * Make sure that the word tier exists.
			 */
			autoMelderString newWordTierName;
			MelderString_copy (& newWordTierName, headTier -> name);
			MelderString_append (& newWordTierName, L"/word");
			for (long itier = 1; itier <= my numberOfTiers (); itier ++) {
				IntervalTier tier = static_cast <IntervalTier> (my tier (itier));
				if (Melder_wcsequ (newWordTierName.string, tier -> name)) {
					if (tier -> classInfo != classIntervalTier)
						Melder_throw ("A tier with the prospective word tier name (", tier -> name, ") already exists, but it is not an interval tier."
							"\nPlease change its name or remove it.");
					wordTierNumber = itier;
					break;
				}
			}
			if (! wordTierNumber) {
				autoIntervalTier newWordTier = IntervalTier_create (my xmin, my xmax);
				Thing_setName (newWordTier.peek(), newWordTierName.string);
				Ordered_addItemPos (my tiers, newWordTier.transfer(), wordTierNumber = tierNumber + 1);
			}
			Melder_assert (wordTierNumber >= 1 && wordTierNumber <= my tiers -> size);
			wordTier = static_cast <IntervalTier> (my tier (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.peek()) {
				Thing_cast (IntervalTier, analysisWordTier, analysis -> tier (3));
				if (! IntervalTier_check (analysisWordTier))
					Melder_throw (L"Analysis word tier out of order (3).");
				if (! IntervalTier_check (wordTier))
					Melder_throw (L"Word tier out of order (3).");
				for (long ianalysisInterval = 1; ianalysisInterval <= analysisWordTier -> numberOfIntervals (); ianalysisInterval ++) {
					TextInterval analysisInterval = analysisWordTier -> interval (ianalysisInterval);
					TextInterval wordInterval = NULL;
					double tmin = analysisInterval -> xmin, tmax = analysisInterval -> xmax;
					if (tmax == analysis -> xmax) {
						wordInterval = wordTier -> interval (wordIntervalNumber);
						TextInterval_setText (wordInterval, analysisInterval -> text);
					} else {
						wordInterval = wordTier -> interval (wordIntervalNumber);
						autoTextInterval newInterval = TextInterval_create (tmin, tmax, analysisInterval -> text);
						wordInterval -> xmin = tmax;
						Collection_addItem (wordTier -> intervals, newInterval.transfer());
						wordIntervalNumber ++;
					}
				}
				if (! IntervalTier_check (analysisWordTier))
					Melder_throw (L"Analysis word tier out of order (4).");
				if (! IntervalTier_check (wordTier))
					Melder_throw (L"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);
			MelderString_append (& newPhonemeTierName, L"/phon");
			for (long itier = 1; itier <= my numberOfTiers (); itier ++) {
				IntervalTier tier = static_cast <IntervalTier> (my tier (itier));
				if (Melder_wcsequ (newPhonemeTierName.string, tier -> name)) {
					if (tier -> classInfo != classIntervalTier)
						Melder_throw ("A tier with the prospective phoneme tier name (", tier -> name, ") already exists, but it is not an interval tier."
							"\nPlease change its name or remove it.");
					phonemeTierNumber = itier;
					break;
				}
			}
			if (! phonemeTierNumber) {
				autoIntervalTier newPhonemeTier = IntervalTier_create (my xmin, my xmax);
				Thing_setName (newPhonemeTier.peek(), newPhonemeTierName.string);
				Ordered_addItemPos (my tiers, newPhonemeTier.transfer(), phonemeTierNumber = wordTierNumber ? wordTierNumber + 1 : tierNumber + 1);
			}
			Melder_assert (phonemeTierNumber >= 1 && phonemeTierNumber <= my tiers -> size);
			phonemeTier = static_cast <IntervalTier> (my tiers -> item [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.peek()) {
				Thing_cast (IntervalTier, analysisPhonemeTier, analysis -> tiers -> item [4]);
				for (long ianalysisInterval = 1; ianalysisInterval <= analysisPhonemeTier -> numberOfIntervals (); ianalysisInterval ++) {
					TextInterval analysisInterval = analysisPhonemeTier -> interval (ianalysisInterval);
					TextInterval phonemeInterval = NULL;
					double tmin = analysisInterval -> xmin, tmax = analysisInterval -> xmax;
					if (tmax == analysis -> xmax) {
						phonemeInterval = phonemeTier -> interval (phonemeIntervalNumber);
						TextInterval_setText (phonemeInterval, analysisInterval -> text);
					} else {
						phonemeInterval = phonemeTier -> interval (phonemeIntervalNumber);
						autoTextInterval newInterval = TextInterval_create (tmin, tmax, analysisInterval -> text);
						phonemeInterval -> xmin = tmax;
						Collection_addItem (phonemeTier -> intervals, newInterval.transfer());
						phonemeIntervalNumber ++;
					}
				}
			}
			if (includeWords) {
				/*
				 * Synchronize the boundaries between the word tier and the phoneme tier.
				 */
				//for (long iinterval = 1; iinterval <=
			}
		}
	} catch (MelderError) {
		Melder_throw (me, " & ", anySound, ": interval not aligned.");
	}
}