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); } }
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."); } }