static void IntervalTier_removeEmptyIntervals (IntervalTier me, IntervalTier boss) { IntervalTier_removeBoundariesBetweenIdenticallyLabeledIntervals (me, U""); if (my intervals.size < 2) return; TextInterval firstInterval = my intervals.at [1]; if (Melder_equ (firstInterval -> text, U"")) { IntervalTier_removeLeftBoundary (me, 2); } if (my intervals.size < 2) return; TextInterval lastInterval = my intervals.at [my intervals.size]; if (Melder_equ (lastInterval -> text, U"")) { IntervalTier_removeLeftBoundary (me, my intervals.size); } if (my intervals.size < 3) return; for (long iinterval = my intervals.size - 1; iinterval >= 2; iinterval --) { TextInterval interval = my intervals.at [iinterval]; if (Melder_equ (interval -> text, U"")) { /* * Distribute the empty interval between its neigbours. */ double newBoundaryTime = boss ? IntervalTier_boundaryTimeClosestTo (boss, interval -> xmin, interval -> xmax) : 0.5 * (interval -> xmin + interval -> xmax); TextInterval previous = my intervals.at [iinterval - 1]; TextInterval next = my intervals.at [iinterval + 1]; previous -> xmax = newBoundaryTime; next -> xmin = newBoundaryTime; my intervals. removeItem (iinterval); } } }
void EditDistanceTable_drawEditOperations (EditDistanceTable me, Graphics graphics) { const char32 *oinsertion = U"i", *insertion = U"*", *odeletion = U"d", *deletion = U"*", *osubstitution = U"s", *oequal = U""; Graphics_setWindow (graphics, 0.5, my warpingPath -> pathLength - 0.5, 0, 1); // pathLength-1 symbols double lineSpacing = getLineSpacing (graphics); double ytarget = 1 - lineSpacing, ysource = ytarget - 2 * lineSpacing, yoper = ysource - lineSpacing; Graphics_setTextAlignment (graphics, Graphics_CENTRE, Graphics_BOTTOM); for (long i = 2; i <= my warpingPath -> pathLength; i++) { structPairOfInteger p = my warpingPath -> path[i], p1 = my warpingPath -> path[i - 1]; double x = i - 1; if (p.x == p1.x) { // insertion Graphics_text (graphics, x, ytarget, my rowLabels[p.y]); Graphics_text (graphics, x, ysource, deletion); Graphics_text (graphics, x, yoper, oinsertion); } else if (p.y == p1.y) { // deletion Graphics_text (graphics, x, ytarget, insertion); Graphics_text (graphics, x, ysource, my columnLabels[p.x]); Graphics_text (graphics, x, yoper, odeletion); } else { // substitution ? Graphics_text (graphics, x, ytarget, my rowLabels[p.y]); Graphics_text (graphics, x, ysource, my columnLabels[p.x]); Graphics_text (graphics, x, yoper, (Melder_equ (my rowLabels[p.y], my columnLabels[p.x]) ? oequal : osubstitution)); } Graphics_line (graphics, x, ysource + lineSpacing, x, ytarget - 0.1 * lineSpacing); } }
void IntervalTier_removeBoundariesBetweenIdenticallyLabeledIntervals (IntervalTier me, const char32 *label) { try { for (long iint = my intervals -> size; iint > 1; iint--) { TextInterval ti = (TextInterval) my intervals -> item[iint]; if (Melder_equ (ti -> text, label)) { TextInterval tim1 = (TextInterval) my intervals -> item[iint - 1]; if (Melder_equ (tim1 -> text, label)) { Melder_free (tim1 -> text); IntervalTier_removeLeftBoundary (me, iint); } } } } catch (MelderError) { Melder_throw (me, U": boundaries not removed."); } }
long Regression_getFactorIndexFromFactorName_e (Regression me, const char32 *factorName) { for (long iparm = 1; iparm <= my parameters -> size; iparm ++) { RegressionParameter parm = static_cast<RegressionParameter> (my parameters -> item [iparm]); if (Melder_equ (factorName, parm -> label)) return iparm; } Melder_throw (Thing_messageName (me), U" has no parameter named \"", factorName, U"\"."); }
autoTextGrid TextGrid_and_IntervalTier_cutPartsMatchingLabel (TextGrid me, IntervalTier thee, const char32 *label, double precision) { try { if (my xmin != thy xmin || my xmax != thy xmax) { Melder_throw (U"Domains must be equal."); } double cutDurations = 0; for (long i = 1; i <= thy intervals.size; i ++) { TextInterval cut = thy intervals.at [i]; if (Melder_equ (cut -> text, label)) { cutDurations += cut -> xmax - cut -> xmin; } } if (cutDurations <= precision) { // Nothing to patch return Data_copy (me); } autoTextGrid him = TextGrid_createWithoutTiers (0, thy xmax - thy xmin - cutDurations); for (long itier = 1; itier <= my tiers->size; itier ++) { Function anyTier = my tiers->at [itier]; if (anyTier -> classInfo == classIntervalTier) { autoIntervalTier newTier = IntervalTier_and_IntervalTier_cutPartsMatchingLabel ((IntervalTier) anyTier, thee, label, precision); his tiers -> addItem_move (newTier.move()); } else { autoTextTier newTier = TextTier_and_IntervalTier_cutPartsMatchingLabel ((TextTier) anyTier, thee, label, precision); his tiers -> addItem_move (newTier.move()); } } return him; } catch (MelderError) { Melder_throw (me, U": no parts cut."); } }
autoConfusion Confusion_groupStimuli (Confusion me, const char32 *labels, const char32 *newLabel, long newpos) { try { long ncondense = Melder_countTokens (labels); autoNUMvector<long> irow (1, my numberOfRows); for (long i = 1; i <= my numberOfRows; i++) { irow[i] = i; } for (char32 *token = Melder_firstToken (labels); token != nullptr; token = Melder_nextToken ()) { for (long i = 1; i <= my numberOfRows; i++) { if (Melder_equ (token, my rowLabels[i])) { irow[i] = 0; break; } } } long nfound = 0; for (long i = 1; i <= my numberOfRows; i++) { if (irow[i] == 0) { nfound ++; } } if (nfound == 0) { Melder_throw (U"Invalid stimulus labels."); } if (nfound != ncondense) { Melder_warning (U"One or more of the given stimulus labels are suspect."); } long newnstim = my numberOfRows - nfound + 1; if (newpos < 1) { newpos = 1; } if (newpos > newnstim) { newpos = newnstim; } autoConfusion thee = Confusion_create (newnstim, my numberOfColumns); NUMstrings_copyElements (my columnLabels, thy columnLabels, 1, my numberOfColumns); TableOfReal_setRowLabel (thee.get(), newpos, newLabel); long inewrow = 1; for (long i = 1; i <= my numberOfRows; i++) { long rowpos = newpos; if (irow[i] > 0) { if (inewrow == newpos) { inewrow++; } rowpos = inewrow; inewrow++; TableOfReal_setRowLabel (thee.get(), rowpos, my rowLabels[i]); } for (long j = 1; j <= my numberOfColumns; j++) { thy data[rowpos][j] += my data[i][j]; } } return thee; } catch (MelderError) { Melder_throw (me, U": stimuli not grouped."); } }
static autoTextTier TextTier_and_IntervalTier_cutPartsMatchingLabel (TextTier me, IntervalTier thee, const char32 *label, double precision) { try { if (my xmin != thy xmin || my xmax != thy xmax) { Melder_throw (U"Domains must be equal."); } long myIndex = 1; double timeCut = 0.0; autoTextTier him = TextTier_create (0.0, my xmax - my xmin); for (long j = 1; j <= thy intervals.size; j ++) { TextInterval cut = thy intervals.at [j]; if (Melder_equ (cut -> text, label)) { timeCut += cut -> xmax - cut -> xmin; } else { while (myIndex <= my points.size) { TextPoint tp = my points.at [myIndex]; if (tp -> number < cut -> xmin - precision) { // point is left of cut myIndex++; } else if (tp -> number < cut -> xmax + precision) { // point is in (no)cut double time = tp -> number - my xmin - timeCut; TextTier_addPoint (him.peek(), time, tp -> mark); myIndex++; } else { break; } } } } his xmax -= timeCut; return him; } catch (MelderError) { Melder_throw (me, U": parts not cut."); } }
autoStringsIndex Stringses_to_StringsIndex (Strings me, Strings classes) { try { autoStringsIndex tmp = Strings_to_StringsIndex (classes); long numberOfClasses = tmp -> classes->size; autoStringsIndex him = StringsIndex_create (my numberOfStrings); for (long i = 1; i <= numberOfClasses; i ++) { SimpleString t = (SimpleString) tmp -> classes->at [i]; // FIXME cast autoSimpleString t2 = Data_copy (t); his classes -> addItem_move (t2.move()); } for (long j = 1; j <= my numberOfStrings; j ++) { long index = 0; char32 *stringsj = my strings [j]; for (long i = 1; i <= numberOfClasses; i ++) { SimpleString ss = (SimpleString) his classes->at [i]; // FIXME cast if (Melder_equ (stringsj, ss -> string)) { index = i; break; } } his classIndex [j] = index; } return him; } catch (MelderError) { Melder_throw (me, U": no StringsIndex created."); } }
autoConfusion Confusion_groupResponses (Confusion me, const char32 *labels, const char32 *newLabel, long newpos) { try { long ncondense = Melder_countTokens (labels); autoNUMvector<long> icol (1, my numberOfColumns); for (long i = 1; i <= my numberOfColumns; i++) { icol[i] = i; } for (char32 *token = Melder_firstToken (labels); token != 0; token = Melder_nextToken ()) { for (long i = 1; i <= my numberOfColumns; i++) { if (Melder_equ (token, my columnLabels[i])) { icol[i] = 0; break; } } } long nfound = 0; for (long i = 1; i <= my numberOfColumns; i++) { if (icol[i] == 0) { nfound ++; } } if (nfound == 0) { Melder_throw (U"Invalid response labels."); } if (nfound != ncondense) { Melder_warning (U"One or more of the given response labels are suspect."); } long newnresp = my numberOfColumns - nfound + 1; if (newpos < 1) { newpos = 1; } if (newpos > newnresp) { newpos = newnresp; } autoConfusion thee = Confusion_create (my numberOfRows, newnresp); NUMstrings_copyElements (my rowLabels, thy rowLabels, 1, my numberOfRows); TableOfReal_setColumnLabel (thee.get(), newpos, newLabel); long inewcol = 1; for (long i = 1; i <= my numberOfColumns; i++) { long colpos = newpos; if (icol[i] > 0) { if (inewcol == newpos) { inewcol++; } colpos = inewcol; inewcol++; TableOfReal_setColumnLabel (thee.get(), colpos, my columnLabels[i]); } for (long j = 1; j <= my numberOfRows; j++) { thy data[j][colpos] += my data[j][i]; } } return thee; } catch (MelderError) { Melder_throw (me, U": responses not grouped."); } }
long Strings_findString (Strings me, const char32 *string) { for (long i = 1; i <= my numberOfStrings; i++) { if (Melder_equ (my strings[i], string)) { return i; } } return 0; }
long ERPTier_getChannelNumber (ERPTier me, const char32 *channelName) { for (long ichan = 1; ichan <= my numberOfChannels; ichan ++) { if (Melder_equ (my channelNames [ichan], channelName)) { return ichan; } } return 0; }
static void IntervalTier_getLabelInfo (IntervalTier me, const char32 *label, double *labelDurations, long *numberOfOccurences) { *labelDurations = 0; *numberOfOccurences = 0; for (long i = 1; i <= my intervals.size; i ++) { TextInterval ti = my intervals.at [i]; if (Melder_equ (ti -> text, label)) { *labelDurations += ti -> xmax - ti -> xmin; (*numberOfOccurences)++; } } }
long FileInMemorySet_getIndexFromId (FileInMemorySet me, const char32 *id) { long index = 0; for (long i = 1; i <= my size; i ++) { FileInMemory fim = my at [i]; if (Melder_equ (id, fim -> d_id)) { index = i; break; } } return index; }
static void IntervalTier_mergeSpecialIntervals (IntervalTier me) { long intervalIndex = my intervals.size; TextInterval right = my intervals.at [intervalIndex]; long labelLength_right = TextInterval_labelLength (right); bool isEmptyInterval_right = labelLength_right == 0 || (labelLength_right == 1 && Melder_equ (right -> text, U"\001")); while (intervalIndex > 1) { TextInterval left = my intervals.at [intervalIndex - 1]; long labelLength_left = TextInterval_labelLength (left); bool isEmptyInterval_left = labelLength_left == 0 || (labelLength_left == 1 && Melder_equ (left -> text, U"\001")); if (isEmptyInterval_right && isEmptyInterval_left) { // remove right interval and empty left interval left -> xmax = right -> xmax; TextInterval_setText (left, U""); my intervals. removeItem (intervalIndex); } right = left; isEmptyInterval_right = isEmptyInterval_left; intervalIndex --; } }
static autoIntervalTier IntervalTiers_patch (IntervalTier me, IntervalTier thee, const char32 *patchLabel, double precision) { try { autoIntervalTier him = IntervalTier_create (thy xmin, thy xmax); long myInterval = 1, hisInterval = 1; double xmax = thy xmin; for (long i = 1; i <= thy intervals.size; i ++) { TextInterval myti, ti = thy intervals.at [i]; if (Melder_equ (ti -> text, patchLabel)) { bool splitInterval = false; double endtime, split = 0; if (i > 0) { while (myInterval <= my intervals.size) { myti = my intervals.at [myInterval]; endtime = xmax + myti -> xmax - myti -> xmin; if (endtime <= ti -> xmin + precision) { xmax = endtime; IntervalTier_splitInterval (him.peek(), xmax, myti -> text, hisInterval, precision); hisInterval++; } else { if (xmax < ti -> xmin - precision) { // split interval ??? splitInterval = true; xmax = ti -> xmin; split = endtime - xmax; IntervalTier_splitInterval (him.peek(), xmax, myti -> text, hisInterval, precision); hisInterval ++; myInterval++; } break; } myInterval++; } } xmax += ti -> xmax - ti -> xmin; IntervalTier_splitInterval (him.peek(), xmax, U"", hisInterval, precision); hisInterval++; if (splitInterval) { xmax += split; IntervalTier_splitInterval (him.peek(), xmax, myti -> text, hisInterval, precision); hisInterval ++; } } else if (i == thy intervals.size) { // copy remaining if last interval doesn't match while (myInterval <= my intervals.size) { myti = my intervals.at [myInterval]; xmax += myti -> xmax - myti -> xmin; IntervalTier_splitInterval (him.peek(), xmax, myti -> text, hisInterval, precision); hisInterval++; myInterval++; } } } return him; } catch (MelderError) { Melder_throw (me, U": not patched."); } }
void Strings_replace (Strings me, long position, const char32 *text) { if (position < 1 || position > my numberOfStrings) { Melder_throw (U"You supplied a position of ", position, U", but for this string it has to be in the range [1, ", my numberOfStrings, U"]."); } if (Melder_equ (my strings [position], text)) return; // nothing to change /* * Create without change. */ autostring32 newString = Melder_dup (text); /* * Change without error. */ Melder_free (my strings [position]); my strings [position] = newString.transfer(); }
static void do_replace (TextEditor me) { if (! theReplaceString) return; // e.g. when the user does "Replace again" before having done any "Replace" autostring32 selection = GuiText_getSelection (my textWidget); if (! Melder_equ (selection.peek(), theFindString)) { do_find (me); return; } long left, right; autostring32 text = GuiText_getStringAndSelectionPosition (my textWidget, & left, & right); GuiText_replace (my textWidget, left, right, theReplaceString); GuiText_setSelection (my textWidget, left, left + str32len (theReplaceString)); GuiText_scrollToSelection (my textWidget); #ifdef _WIN32 GuiThing_show (my d_windowForm); #endif }
static double TextGrid_getEndTimeOfLastOccurence (TextGrid thee, long tierNumber, const char32 *label) { TextGrid_checkSpecifiedTierNumberWithinRange (thee, tierNumber); IntervalTier intervalTier = (IntervalTier) thy tiers->at [tierNumber]; if (intervalTier -> classInfo != classIntervalTier) { Melder_throw (U"Tier ", tierNumber, U" is not an interval tier."); } double end = NUMundefined; for (long iint = intervalTier -> intervals.size; iint > 0; iint --) { TextInterval ti = intervalTier -> intervals.at [iint]; if (Melder_equ (ti -> text, label)) { end = ti -> xmax; break; } } return end; }
autoVocalTract VocalTract_createFromPhone (const char32 *phone) { try { int i = 0; for (;; i ++) { if (! theVocalTract::data [i]. phone) Melder_throw (U"Unknown phone ", phone); if (Melder_equ (theVocalTract::data [i]. phone, phone)) break; } autoVocalTract me = VocalTract_create (theVocalTract::data [i]. numberOfSections, 0.005); for (int isection = 1; isection <= my nx; isection ++) my z [1] [isection] = theVocalTract::data [i]. area [isection - 1] * 0.0001; return me; } catch (MelderError) { Melder_throw (U"VocalTract not created from phone."); } }
static long *EEG_channelNames_to_channelNumbers (EEG me, char32 **channelNames, long numberOfChannelNames) { try { autoNUMvector<long> channelNumbers (1, numberOfChannelNames); for (long i = 1; i <= numberOfChannelNames; i++) { for (long j = 1; j <= my numberOfChannels; j++) { if (Melder_equ (channelNames[i], my channelNames[j])) { channelNumbers[i] = j; } } if (channelNumbers[i] == 0) { Melder_throw (U"Channel name \"", channelNames[i], U"\" not found."); } } return channelNumbers.transfer(); } catch (MelderError) { Melder_throw (me, U": channelNames not found."); } }
void SpeechSynthesizer_changeLanguageNameToCurrent (SpeechSynthesizer me) { try { struct espeakLanguagestruct { const char32 *oldName, *currentName; } names[] = { { U"Akan-test", nullptr}, { U"Bulgarian-test", U"Bulgarian"}, { U"Dari-test", nullptr}, { U"Divehi-test", nullptr}, { U"Dutch-test", U"Dutch"}, { U"French (Belgium)", U"French-Belgium"}, { U"Georgian-test", U"Georgian"}, { U"Haitian", nullptr}, { U"Icelandic-test", U"Icelandic"}, { U"Indonesian-test", U"Indonesian"}, { U"Irish-test", U"Irish-gaeilge"}, { U"Kazakh", nullptr}, { U"Kinyarwanda-test", nullptr}, { U"Korean", U"Korean-test"}, { U"Lancashire", nullptr}, { U"Macedonian-test", U"Macedonian"}, { U"Maltese-test", nullptr}, { U"Nahuatl - classical", U"Nahuatl-classical"}, { U"Nepali-test", U"Nepali"}, { U"Northern-sotho", nullptr}, { U"Punjabi-test", U"Punjabi"}, { U"Russian_test", U"Russian"}, // yes, underscore { U"Setswana-test", nullptr}, { U"Sinhala", U"Sinhala-test"}, { U"Spanish-latin-american", U"Spanish-latin-am"}, { U"Tatar-test", nullptr}, { U"Telugu", U"Telugu-test"}, { U"Welsh-test", U"Welsh"}, { U"Wolof-test", nullptr}, {nullptr,nullptr}}; long index = 0; while (const char32 *oldName = names [index]. oldName) { if (Melder_equ (oldName, my d_voiceLanguageName)) { if (names [index]. currentName) { autostring32 newLabel = Melder_dup (names [index]. currentName); Melder_free (my d_voiceLanguageName); my d_voiceLanguageName = newLabel.transfer(); break; } else { Melder_throw (U"Language ", oldName, U" is not available any longer."); } } ++ index; } } catch (MelderError) { Melder_throw (U"Cannot change language name."); } }
static autoTextTier TextTier_and_IntervalTier_patch (TextTier me, IntervalTier thee, const char32 *patchLabel, double precision) { try { long myIndex = 1; autoTextTier him = TextTier_create (thy xmin, thy xmax); double xShift = thy xmin - my xmin; for (long i = 1; i <= thy intervals.size; i ++) { TextInterval ti = thy intervals.at [i]; if (Melder_equ (ti -> text, patchLabel)) { if (i > 1) { while (myIndex <= my points.size) { TextPoint tp = my points.at [myIndex]; double time = tp -> number + xShift; if (time < ti -> xmin + precision) { autoTextPoint newPoint = TextPoint_create (time, tp -> mark); his points. addItem_move (newPoint.move()); } else { break; } myIndex++; } } xShift += ti -> xmax - ti -> xmin; } else if (i == thy intervals.size) { while (myIndex <= my points.size) { TextPoint tp = my points.at [myIndex]; double time = tp -> number + xShift; if (time < ti -> xmin + precision) { autoTextPoint newPoint = TextPoint_create (time, tp -> mark); his points. addItem_move (newPoint.move()); } myIndex++; } } } return him; } catch (MelderError) { Melder_throw (me, U": cannot patch TextTier."); } }
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."); } }
bool structEditCostsTable :: v_matchTargetWithSourceSymbol (const char32 *targetSymbol, const char32 *sourceSymbol) { return Melder_equ (targetSymbol, sourceSymbol); }
bool structEditCostsTable :: v_matchSourceSymbol (const char32 *sourceSymbol, const char32 *symbol) { return Melder_equ (sourceSymbol, symbol); }
// Cut parts from me marked by labels in thee autoIntervalTier IntervalTier_and_IntervalTier_cutPartsMatchingLabel (IntervalTier me, IntervalTier thee, const char32 *label, double precision) { try { if (my xmin != thy xmin || my xmax != thy xmax) { Melder_throw (U"Domains must be equal."); } autoNUMvector<double> durations (1, my intervals.size); for (long i = 1; i <= my intervals.size; i ++) { TextInterval ti = my intervals.at [i]; durations[i] = ti -> xmax - ti -> xmin; } long myInterval = 1; for (long j = 1; j <= thy intervals.size; j ++) { TextInterval cut = thy intervals.at [j]; if (Melder_equ (cut -> text, label)) { // trim while (myInterval <= my intervals.size) { TextInterval ti = my intervals.at [myInterval]; if (ti -> xmin > cut -> xmin - precision && ti -> xmax < cut -> xmax + precision) { // 1. interval completely within cut durations[myInterval] = 0; myInterval++; } else if (ti -> xmin < cut -> xmin + precision && cut -> xmin < ti -> xmax + precision) { // 2. cut start is within interval if (cut -> xmax > ti -> xmax - precision) { // interval end is in cut, interval start before durations[myInterval] -= ti -> xmax - cut -> xmin; myInterval++; } else { // 3. cut completely within interval durations[myInterval] -= cut -> xmax - cut -> xmin; break; } } else if (cut -> xmax > ti -> xmin - precision && cut -> xmin < ti -> xmax + precision) { // +1+2 : cut end is within interval, cut start before durations[myInterval] -= cut -> xmax - ti -> xmin; break; } else if (ti -> xmax < cut -> xmin + precision) { myInterval++; } } } } double totalDuration = 0; for (long i = 1; i <= my intervals.size; i ++) { if (durations[i] < precision) { durations[i] = 0; } totalDuration += durations[i]; } autoIntervalTier him = IntervalTier_create (0, totalDuration); double time = 0; long hisInterval = 1; for (long i = 1; i <= my intervals.size; i ++) { if (durations[i] <= 0) continue; TextInterval ti = my intervals.at [i]; time += durations[i]; if (fabs (time - totalDuration) > precision) { IntervalTier_splitInterval (him.peek(), time, ti -> text, hisInterval, precision); hisInterval++; } else { // last interval TextInterval histi = his intervals.at [hisInterval]; TextInterval_setText (histi, ti -> text); } } return him; } catch (MelderError) { Melder_throw (me, U": parts not cut."); } }
// Patch thy intervals that match patchLabel into my intervals // The resulting IntervalTier has thy xmin as starting time and thy xmax as end time autoIntervalTier IntervalTiers_patch_noBoundaries (IntervalTier me, IntervalTier thee, const char32 *patchLabel, double precision) { try { autoNUMvector<double> durations (0L, my intervals.size + 1); for (long i = 1; i <= my intervals.size; i ++) { TextInterval myti = my intervals.at [i]; durations [i] = myti -> xmax - myti -> xmin; } long myInterval = 1; double xShift = thy xmin - my xmin; for (long j = 1; j <= thy intervals.size; j ++) { TextInterval patch = thy intervals.at [j]; if (Melder_equ (patch -> text, patchLabel)) { if (j == 1) { xShift += durations[0] = patch -> xmax - patch -> xmin; } else if (j == thy intervals.size) { durations [my intervals.size + 1] = patch -> xmax - patch -> xmin; } else { while (myInterval <= my intervals.size) { TextInterval ti = my intervals.at [myInterval]; double tixmin = ti -> xmin + xShift; double tixmax = ti -> xmax + xShift; if ((patch -> xmin > tixmin - precision) && (patch -> xmin < tixmax + precision)) { durations[myInterval] += patch -> xmax - patch -> xmin; break; } myInterval++; } } } else { while (myInterval <= my intervals.size) { TextInterval ti = my intervals.at [myInterval]; double tixmax = ti -> xmax + xShift; if (tixmax < patch -> xmin + precision) { myInterval++; } else { break; } } } } autoIntervalTier him = IntervalTier_create (thy xmin, thy xmax); // first interval double time = thy xmin + durations[0]; long hisInterval = 1; if (durations [0] > 0) { IntervalTier_splitInterval (him.peek(), time , U"", hisInterval, precision); hisInterval++; } for (long i = 1; i <= my intervals.size; i ++) { TextInterval ti = my intervals.at [i]; time += durations [i]; IntervalTier_splitInterval (him.peek(), time, ti -> text, hisInterval, precision); hisInterval++; } if (durations [my intervals.size + 1] > 0) { time += durations [my intervals.size + 1]; IntervalTier_splitInterval (him.peek(), time , U"", hisInterval, precision); } return him; } catch (MelderError) { Melder_throw (me, U": not patched."); } }
autoTable IntervalTiers_to_Table_textAlignmentment (IntervalTier target, IntervalTier source, EditCostsTable costs) { try { long numberOfTargetIntervals = target -> intervals.size; long numberOfSourceIntervals = source -> intervals.size; autoNUMvector<long> targetOrigin (1, numberOfTargetIntervals); autoNUMvector<long> sourceOrigin (1, numberOfSourceIntervals); autoStrings targets = IntervalTier_to_Strings_withOriginData (target, targetOrigin.peek()); autoStrings sources = IntervalTier_to_Strings_withOriginData (source, sourceOrigin.peek()); autoEditDistanceTable edit = EditDistanceTable_create (targets.peek(), sources.peek()); if (costs != 0) { EditDistanceTable_setEditCosts (edit.peek(), costs); EditDistanceTable_findPath (edit.peek(), nullptr); } long pathLength = edit -> warpingPath -> pathLength; autoTable thee = Table_createWithColumnNames (pathLength - 1, U"targetInterval targetText targetStart targetEnd sourceInterval sourceText sourceStart sourceEnd operation"); for (long i = 2; i <= pathLength; i++) { structPairOfInteger p = edit -> warpingPath -> path[i]; structPairOfInteger p1 = edit -> warpingPath -> path[i - 1]; double targetStart = NUMundefined, targetEnd = NUMundefined; double sourceStart = NUMundefined, sourceEnd = NUMundefined; const char32 * targetText = U"", *sourceText = U""; long targetInterval = p.y > 1 ? targetOrigin[p.y - 1] : 0; long sourceInterval = p.x > 1 ? sourceOrigin[p.x - 1] : 0; if (targetInterval > 0) { TextInterval ti = target -> intervals.at [targetInterval]; targetStart = ti -> xmin; targetEnd = ti -> xmax; targetText = ti -> text; } if (sourceInterval > 0) { TextInterval ti = source -> intervals.at [sourceInterval]; sourceStart = ti -> xmin; sourceEnd = ti -> xmax; sourceText = ti -> text; } long irow = i - 1; if (p.y == p1.y) { // deletion Table_setNumericValue (thee.peek(), irow, 1, 0); Table_setStringValue (thee.peek(), irow, 2, U""); Table_setNumericValue (thee.peek(), irow, 3, NUMundefined); Table_setNumericValue (thee.peek(), irow, 4, NUMundefined); Table_setNumericValue (thee.peek(), irow, 5, sourceInterval); Table_setStringValue (thee.peek(), irow, 6, sourceText); Table_setNumericValue (thee.peek(), irow, 7, sourceStart); Table_setNumericValue (thee.peek(), irow, 8, sourceEnd); Table_setStringValue (thee.peek(), irow, 9, U"d"); } else if (p.x == p1.x) { // insertion Table_setNumericValue (thee.peek(), irow, 1, targetInterval); Table_setStringValue (thee.peek(), irow, 2, targetText); Table_setNumericValue (thee.peek(), irow, 3, targetStart); Table_setNumericValue (thee.peek(), irow, 4, targetEnd); Table_setNumericValue (thee.peek(), irow, 5, 0); Table_setStringValue (thee.peek(), irow, 6, U""); Table_setNumericValue (thee.peek(), irow, 7, NUMundefined); Table_setNumericValue (thee.peek(), irow, 8, NUMundefined); Table_setStringValue (thee.peek(), irow, 9, U"i"); } else { // substitution ? Table_setNumericValue (thee.peek(), irow, 1, targetInterval); Table_setStringValue (thee.peek(), irow, 2, targetText); Table_setNumericValue (thee.peek(), irow, 3, targetStart); Table_setNumericValue (thee.peek(), irow, 4, targetEnd); Table_setNumericValue (thee.peek(), irow, 5, sourceInterval); Table_setStringValue (thee.peek(), irow, 6, sourceText); Table_setNumericValue (thee.peek(), irow, 7, sourceStart); Table_setNumericValue (thee.peek(), irow, 8, sourceEnd); Table_setStringValue (thee.peek(), irow, 9, Melder_equ (targetText, sourceText) ? U" " : U"s"); } } return thee; } catch (MelderError) { Melder_throw (target, U" and ", source, U" not aligned."); } }