[med-svn] [Git][med-team/praat][master] 3 commits: New upstream version 6.4.12+dfsg

Rafael Laboissière (@rafael) gitlab at salsa.debian.org
Sun May 5 11:37:26 BST 2024



Rafael Laboissière pushed to branch master at Debian Med / praat


Commits:
f9c970b5 by Rafael Laboissière at 2024-05-03T08:11:31-03:00
New upstream version 6.4.12+dfsg
- - - - -
5d62010c by Rafael Laboissière at 2024-05-03T08:13:53-03:00
Update upstream source from tag 'upstream/6.4.12+dfsg'

Update to upstream version '6.4.12+dfsg'
with Debian dir b02dc4ee2730373922be7ef66a47a17787f47366
- - - - -
5fcb70a3 by Rafael Laboissière at 2024-05-04T15:18:21-03:00
d/changelog: Add entry for release 6.4.12+dfsg-1

Gbp-Dch: Ignore

- - - - -


24 changed files:

- debian/changelog
- dwtools/CCA.cpp
- dwtools/Confusion.cpp
- dwtools/DTW.cpp
- dwtools/DTW_and_TextGrid.cpp
- dwtools/Sound_and_TextGrid_extensions.cpp
- dwtools/Sound_extensions.cpp
- dwtools/SpeechSynthesizer.cpp
- dwtools/SpeechSynthesizer_and_TextGrid.cpp
- dwtools/TextGrid_extensions.cpp
- dwtools/TextGrid_extensions.h
- dwtools/VowelEditor.cpp
- dwtools/espeakdata_FileInMemory.cpp
- dwtools/praat_David_init.cpp
- external/espeak/common.cpp
- external/espeak/synthesize.h
- external/espeak/wavegen.cpp
- fon/TextGrid.cpp
- fon/TextGrid.h
- fon/TextGrid_Sound.cpp
- sys/Gui_messages.cpp
- sys/HyperPage.cpp
- sys/ManPage.cpp
- sys/ManPages_toHtml.cpp


Changes:

=====================================
debian/changelog
=====================================
@@ -1,3 +1,9 @@
+praat (6.4.12+dfsg-1) unstable; urgency=medium
+
+  * New upstream version 6.4.12+dfsg
+
+ -- Rafael Laboissière <rafael at debian.org>  Sat, 04 May 2024 15:18:08 -0300
+
 praat (6.4.11+dfsg-1) unstable; urgency=medium
 
   * New upstream version 6.4.11+dfsg


=====================================
dwtools/CCA.cpp
=====================================
@@ -221,7 +221,6 @@ autoTableOfReal CCA_TableOfReal_predict (CCA me, TableOfReal thee, integer from)
 		
 		Melder_require (ny == nev,
 			U"There are not enough correlations present for prediction.");
-		
 
 		if (from == 0)
 			from = 1;


=====================================
dwtools/Confusion.cpp
=====================================
@@ -341,7 +341,7 @@ autoConfusion Confusion_condense (Confusion me, conststring32 search, conststrin
 		integer nmatches, nstringmatches;
 		Melder_require (my rowLabels && my columnLabels,
 			U"Both row and column labels should be present.");
-		
+
 		autoSTRVEC rowLabels = string32vector_searchAndReplace (my rowLabels.get(),
 				search, replace, maximumNumberOfReplaces, & nmatches, & nstringmatches, use_regexp);
 


=====================================
dwtools/DTW.cpp
=====================================
@@ -134,12 +134,16 @@ double DTW_getYTimeFromXTime (DTW me, double tx) {
 	/*
 		If `eps` were zero, then the condition would rely on floating-point equality,
 		which is a bad idea (e.g. the result would be platform-dependent).
-		(fix ppgb 20241020, after this crashed on Windows only)
+		(fix ppgb 20240420, after this crashed on Windows only)
+		(rewind 20240501, because of retries in SpeechSynthesizer & Sound & TextGrid alignment)
 	*/
-	const double eps = 1e-6 * (my xmax - my xmin);
+	const double eps = 0.0 * (my xmax - my xmin);
 	if (tx > my xmin + eps && tx < my xmax - eps) {
 		DTW_Path_Query thee = & my pathQuery;
 		time = RealTier_getValueAtTime (thy yfromx.get(), tx);
+	} else {
+		//TRACE
+		trace (U"Time set to ", tx, U" instead of between ", my xmin, U" and ", my xmax, U".");
 	}
 	return time;
 }
@@ -149,9 +153,10 @@ double DTW_getXTimeFromYTime (DTW me, double ty) {
 	/*
 		If `eps` were zero, then the condition would rely on floating-point equality,
 		which is a bad idea (e.g. the result would be platform-dependent).
-		(fix ppgb 20241020, after this crashed on Windows only)
+		(fix ppgb 20240420, after this crashed on Windows only)
+		(rewind 20240501, because of retries in SpeechSynthesizer & Sound & TextGrid alignment)
 	*/
-	const double eps = 1e-6 * (my ymax - my ymin);
+	const double eps = 0.0 * (my ymax - my ymin);
 	if (ty > my ymin + eps && ty < my ymax - eps) {
 		DTW_Path_Query thee = & my pathQuery;
 		time = RealTier_getValueAtTime (thy xfromy.get(), ty);


=====================================
dwtools/DTW_and_TextGrid.cpp
=====================================
@@ -83,7 +83,9 @@ autoIntervalTier DTW_IntervalTier_to_IntervalTier (DTW me, IntervalTier thee, do
 			}
 			textinterval = his intervals.at [his intervals.size];
 			textinterval -> xmax = his xmax;
-			Melder_assert (textinterval -> xmin < textinterval -> xmax);
+			//Melder_assert (textinterval -> xmin < textinterval -> xmax);
+			Melder_require (textinterval -> xmin < textinterval -> xmax,
+				U"Interval runs from ", textinterval -> xmin, U" to ", textinterval -> xmax, U" seconds.");
 			return him;
 		} else if (fabs (my xmin - thy xmin) <= precision && fabs (my xmax - thy xmax) <= precision) { // map from X to Y
 			autoIntervalTier him = Data_copy (thee);
@@ -104,7 +106,7 @@ autoIntervalTier DTW_IntervalTier_to_IntervalTier (DTW me, IntervalTier thee, do
 			textinterval = his intervals.at [his intervals.size];
 			textinterval -> xmax = his xmax;
 			trace (U"interval ", his intervals.size, U": from ", textinterval -> xmin, U" to ", textinterval -> xmax, U", label <<", textinterval -> text.get(), U">>");
-			Melder_assert (textinterval -> xmin < textinterval -> xmax);
+			//Melder_assert (textinterval -> xmin < textinterval -> xmax);
 			Melder_require (textinterval -> xmin < textinterval -> xmax,
 				U"Interval runs from ", textinterval -> xmin, U" to ", textinterval -> xmax, U" seconds.");
 			return him;
@@ -112,7 +114,7 @@ autoIntervalTier DTW_IntervalTier_to_IntervalTier (DTW me, IntervalTier thee, do
 			Melder_throw (U"The domain of the IntervalTier and one of the domains of the DTW should be equal.");
 		}
 	} catch (MelderError) {
-		Melder_throw (U"IntervalTier not created from DTW & IntervalTier.");
+		Melder_throw (U"DTW & IntervalTier: new IntervalTier not created.");
 	}
 }
 
@@ -148,7 +150,7 @@ autoTextGrid DTW_TextGrid_to_TextGrid (DTW me, TextGrid thee, double precision)
 		}
 		return him;
 	} catch (MelderError) {
-		Melder_throw (U"TextGrid not created from DTW & TextGrid.");
+		Melder_throw (U"DTW & TextGrid: new TextGrid not created.");
 	}
 }
 


=====================================
dwtools/Sound_and_TextGrid_extensions.cpp
=====================================
@@ -1,6 +1,6 @@
 /* Sound_and_TextGrid_extensions.cpp
  *
- * Copyright (C) 1993-2022 David Weenink
+ * Copyright (C) 1993-2022 David Weenink, 2024 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
  */
 
 #include "Intensity_extensions.h"
+#include "Sound_extensions.h"
 #include "Sound_and_TextGrid_extensions.h"
 #include "Sound_and_Spectrum.h"
 #include "Sound_to_Intensity.h"
@@ -69,16 +70,16 @@ autoTextGrid Sound_to_TextGrid_highMidLowIntervals (Sound me, double min, double
 }
 
 autoSound Sound_IntervalTier_cutPartsMatchingLabel (Sound me, IntervalTier thee, conststring32 match) {
-    try {
+	try {
 		/*
 			Count samples of the trimmed sound
 		*/
-        integer ixmin, ixmax, numberOfSamples = 0, previous_ixmax = 0;
+		integer ixmin, ixmax, numberOfSamples = 0, previous_ixmax = 0;
 		double xmin = my xmin; // start time of output sound is start time of input sound
-        for (integer iint = 1; iint <= thy intervals.size; iint ++) {
-            TextInterval interval = thy intervals.at [iint];
-            if (! Melder_equ (interval -> text.get(), match)) {
-                numberOfSamples += Sampled_getWindowSamples (me, interval -> xmin, interval -> xmax, & ixmin, & ixmax);
+		for (integer iint = 1; iint <= thy intervals.size; iint ++) {
+			TextInterval interval = thy intervals.at [iint];
+			if (! Melder_equ (interval -> text.get(), match)) {
+				numberOfSamples += Sampled_getWindowSamples (me, interval -> xmin, interval -> xmax, & ixmin, & ixmax);
 				/*
 					If two contiguous intervals have to be copied then the last sample of previous interval
 					and first sample of current interval might sometimes be equal
@@ -89,31 +90,31 @@ autoSound Sound_IntervalTier_cutPartsMatchingLabel (Sound me, IntervalTier thee,
 			} else { // matches label
 				if (iint == 1) // Start time of output sound is end time of first interval
 					xmin = interval -> xmax;
-            }
-        }
-        /*
+			}
+		}
+		/*
 			Now copy the parts. The output sound starts at xmin
 		*/
-        autoSound him = Sound_create (my ny, xmin, xmin + numberOfSamples * my dx, numberOfSamples, my dx, xmin + 0.5 * my dx);
-        numberOfSamples = 0;
+		autoSound him = Sound_create (my ny, xmin, xmin + numberOfSamples * my dx, numberOfSamples, my dx, xmin + 0.5 * my dx);
+		numberOfSamples = 0;
 		previous_ixmax = 0;
-        for (integer iint = 1; iint <= thy intervals.size; iint ++) {
-            const TextInterval interval = thy intervals.at [iint];
-            if (! Melder_equ (interval -> text.get(), match)) {
-                Sampled_getWindowSamples (me, interval -> xmin, interval -> xmax, & ixmin, & ixmax);
+		for (integer iint = 1; iint <= thy intervals.size; iint ++) {
+			const TextInterval interval = thy intervals.at [iint];
+			if (! Melder_equ (interval -> text.get(), match)) {
+				Sampled_getWindowSamples (me, interval -> xmin, interval -> xmax, & ixmin, & ixmax);
 				if (ixmin == previous_ixmax)
 					ixmin ++;
 				previous_ixmax = ixmax;
 				integer numberOfSamplesToCopy = ixmax - ixmin + 1;
 				his z.part (1, my ny, numberOfSamples + 1, numberOfSamples + numberOfSamplesToCopy)  <<=  my z.part (1, my ny, ixmin, ixmax);
-                numberOfSamples += numberOfSamplesToCopy;
-            }
-        }
-        Melder_assert (numberOfSamples == his nx);
-        return him;
-    } catch (MelderError) {
-        Melder_throw (me, U": intervals not trimmed.");
-    }
+				numberOfSamples += numberOfSamplesToCopy;
+			}
+		}
+		Melder_assert (numberOfSamples == his nx);
+		return him;
+	} catch (MelderError) {
+		Melder_throw (me, U": intervals not trimmed.");
+	}
 }
 
 autoTextGrid Sound_to_TextGrid_detectSilences (Sound me, double minPitch, double timeStep,


=====================================
dwtools/Sound_extensions.cpp
=====================================
@@ -1,6 +1,6 @@
 /* Sound_extensions.cpp
  *
- * Copyright (C) 1993-2023 David Weenink, 2017 Paul Boersma
+ * Copyright (C) 1993-2023 David Weenink, 2017,2024 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -1146,19 +1146,18 @@ Sound Sound_createShepardTone (double minimumTime, double maximumTime, double sa
 	Sound me; integer i, j, nComponents = 1 + log2 (maximumFrequency / 2 / baseFrequency);
 	double lmin = pow (10, - amplitudeRange / 10);
 	double twoPi = NUM2pi, f = baseFrequency * (1 + frequencyShiftFraction);
-	if (nComponents < 2) Melder_warning (U"Sound_createShepardTone: only 1 component.");
+	if (nComponents < 2)
+		Melder_warning (U"Sound_createShepardTone: only 1 component.");
 	Melder_casual (U"Sound_createShepardTone: ", nComponents, U" components.");
-	if (! (me = Sound_create2 (minimumTime, maximumTime, samplingFrequency))) return nullptr;
+	if (! (me = Sound_create2 (minimumTime, maximumTime, samplingFrequency)))
+		return nullptr;
 
-	for (j=1; j <= nComponents; j ++)
-	{
+	for (j=1; j <= nComponents; j ++) {
 		double fj = f * pow (2, j-1), wj = twoPi * fj;
 		double amplitude = lmin + (1 - lmin) *
 			(1 - cos (twoPi * log (fj + 1) / log (maximumFrequency + 1))) / 2;
 		for (i=1; i <= my nx; i ++)
-		{
 			my z [1] [i] += amplitude * sin (wj * (i - 0.5) * my dx);
-		}
 	}
 	Vector_scale (me, 0.99996948);
 	return me;
@@ -1735,52 +1734,58 @@ void Sound_getStartAndEndTimesOfSounding (Sound me, double minPitch, double time
 	}
 }
 
-autoSound Sound_trimSilences (Sound me, double trimDuration, bool onlyAtStartAndEnd, double minPitch, double timeStep, double silenceThreshold, double minSilenceDuration, double minSoundingDuration, autoTextGrid *p_tg, conststring32 trimLabel) {
-    try {
+autoSound Sound_trimSilences (Sound me, double trimDuration, bool onlyAtStartAndEnd,
+	double minPitch, double timeStep, double silenceThreshold,
+	double minSilenceDuration, double minSoundingDuration,
+	autoTextGrid *out_tg, conststring32 trimLabel
+) {
+	try {
 		Melder_require (my ny == 1,
 			U"The sound should be a mono sound.");
-		
-        const conststring32 silentLabel = U"silent", soundingLabel = U"sounding";
-        const conststring32 copyLabel = U"";
-        autoTextGrid tg = Sound_to_TextGrid_detectSilences (me, minPitch, timeStep, silenceThreshold, minSilenceDuration, minSoundingDuration, silentLabel, soundingLabel);
-        autoIntervalTier itg = Data_copy ((IntervalTier) tg -> tiers->at [1]);
-        IntervalTier tier = (IntervalTier) tg -> tiers->at [1];
-        for (integer iint = 1; iint <= tier -> intervals.size; iint ++) {
-            const TextInterval ti = tier -> intervals.at [iint];
-            const TextInterval ati = itg -> intervals.at [iint];
-            const double duration = ti -> xmax - ti -> xmin;
-            if (duration > trimDuration && Melder_equ (ti -> text.get(), silentLabel)) {   // silent
+
+		const conststring32 silentLabel = U"silent", soundingLabel = U"sounding";
+		const conststring32 copyLabel = U"";
+		autoTextGrid tg = Sound_to_TextGrid_detectSilences (me, minPitch, timeStep, silenceThreshold, minSilenceDuration, minSoundingDuration, silentLabel, soundingLabel);
+		autoIntervalTier itg = Data_copy ((IntervalTier) tg -> tiers->at [1]);
+		IntervalTier tier = (IntervalTier) tg -> tiers->at [1];
+		for (integer iint = 1; iint <= tier -> intervals.size; iint ++) {
+			const TextInterval ti = tier -> intervals.at [iint];
+			const TextInterval ati = itg -> intervals.at [iint];
+			const double duration = ti -> xmax - ti -> xmin;
+			if (duration > trimDuration && Melder_equ (ti -> text.get(), silentLabel)) {   // silent
 				conststring32 label = trimLabel;
-                if (iint == 1) { // first is special
-                    const double trim_t = ti -> xmax - trimDuration;
-                    IntervalTier_moveBoundary (itg.get(), iint, false, trim_t);
-                } else if (iint == tier -> intervals.size) {   // last is special
-                    const double trim_t = ti -> xmin + trimDuration;
-                    IntervalTier_moveBoundary (itg.get(), iint, true, trim_t);
-                } else {
+				if (tier -> intervals.size == 1) {   // current interval is both the first and the last: very special
+					// all of the sound is silent: do nothing
+				} else if (iint == 1) {   // first is special
+					const double trim_t = ti -> xmax - trimDuration;
+					IntervalTier_moveRightBoundary (itg.get(), iint, trim_t);
+				} else if (iint == tier -> intervals.size) {   // last is special
+					const double trim_t = ti -> xmin + trimDuration;
+					IntervalTier_moveLeftBoundary (itg.get(), iint, trim_t);
+				} else {
 					if (onlyAtStartAndEnd) {
 						label = ati -> text.get();
 					} else {
-                    	double trim_t = ti -> xmin + 0.5 * trimDuration;
-						IntervalTier_moveBoundary (itg.get(), iint, true, trim_t);
-                    	trim_t = ti -> xmax - 0.5 * trimDuration;
-                    	IntervalTier_moveBoundary (itg.get(), iint, false, trim_t);
+						double trim_t = ti -> xmin + 0.5 * trimDuration;
+						IntervalTier_moveLeftBoundary (itg.get(), iint, trim_t);
+						trim_t = ti -> xmax - 0.5 * trimDuration;
+						IntervalTier_moveRightBoundary (itg.get(), iint, trim_t);
 					}
-                }
-                TextInterval_setText (ati, label);
-            } else {   // sounding
-                TextInterval_setText (ati, copyLabel);
-            }
-        }
-        autoSound thee = Sound_IntervalTier_cutPartsMatchingLabel (me, itg.get(), trimLabel);
-        if (p_tg) {
+				}
+				TextInterval_setText (ati, label);
+			} else {   // sounding
+				TextInterval_setText (ati, copyLabel);
+			}
+		}
+		autoSound thee = Sound_IntervalTier_cutPartsMatchingLabel (me, itg.get(), trimLabel);
+		if (out_tg) {
 			TextGrid_addTier_copy (tg.get(), itg.get());
-            *p_tg = tg.move();
-        }
-        return thee;
-    } catch (MelderError) {
-        Melder_throw (me, U": silences not trimmed.");
-    }
+			*out_tg = tg.move();
+		}
+		return thee;
+	} catch (MelderError) {
+		Melder_throw (me, U": silences not trimmed.");
+	}
 }
 
 autoSound Sound_trimSilencesAtStartAndEnd (Sound me, double trimDuration, double minPitch, double timeStep,
@@ -1789,7 +1794,7 @@ autoSound Sound_trimSilencesAtStartAndEnd (Sound me, double trimDuration, double
 	try {
 		autoTextGrid tg;
 		autoSound thee = Sound_trimSilences (me, trimDuration, true, minPitch, timeStep, silenceThreshold, 
-			minSilenceDuration, minSoundingDuration, & tg, U"trimmed");
+				minSilenceDuration, minSoundingDuration, & tg, U"trimmed");
 		const IntervalTier trim = (IntervalTier) tg -> tiers->at [2];
 		const TextInterval ti1 = trim -> intervals.at [1];
 		if (startTimeOfSounding) {
@@ -1805,7 +1810,7 @@ autoSound Sound_trimSilencesAtStartAndEnd (Sound me, double trimDuration, double
 		}
 		return thee;
 	} catch (MelderError) {
-		Melder_throw (me, U": silences not trimmed.");
+		Melder_throw (me, U": silences at start and end not trimmed.");
 	}
 }
 


=====================================
dwtools/SpeechSynthesizer.cpp
=====================================
@@ -1,6 +1,6 @@
 /* SpeechSynthesizer.cpp
  *
- * Copyright (C) 2011-2023 David Weenink
+ * Copyright (C) 2011-2023 David Weenink, 2012,2013,2015-2024 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by


=====================================
dwtools/SpeechSynthesizer_and_TextGrid.cpp
=====================================
@@ -101,15 +101,15 @@ static double TextGrid_getEndTimeOfLastOccurrence (TextGrid thee, integer tierNu
 #endif
 
 static void IntervalTier_getLabelInfo (IntervalTier me, conststring32 label, double *labelDurations, integer *numberOfOccurences) {
-    *labelDurations = 0.0;
-    *numberOfOccurences = 0;
-    for (integer i = 1; i <= my intervals.size; i ++) {
+	*labelDurations = 0.0;
+	*numberOfOccurences = 0;
+	for (integer i = 1; i <= my intervals.size; i ++) {
 		const TextInterval ti = my intervals.at [i];
-        if (Melder_equ (ti -> text.get(), label)) {
-            *labelDurations += ti -> xmax - ti -> xmin;
-            (*numberOfOccurences) ++;
-        }
-    }
+		if (Melder_equ (ti -> text.get(), label)) {
+			*labelDurations += ti -> xmax - ti -> xmin;
+			(*numberOfOccurences) ++;
+		}
+	}
 }
 
 #define TIMES_ARE_CLOSE(x,y) (fabs((x)-(y)) < precision)
@@ -469,7 +469,11 @@ autoTextGrid TextGrid_IntervalTier_patch (TextGrid me, IntervalTier thee, consts
 }
 
 // We assume that the Sound and the SpeechSynthesizer have the same samplingFrequency
-autoTextGrid SpeechSynthesizer_Sound_TextInterval_align (SpeechSynthesizer me, Sound thee, TextInterval him, double silenceThreshold, double minSilenceDuration, double minSoundingDuration) {
+autoTextGrid SpeechSynthesizer_Sound_TextInterval_align (
+	const SpeechSynthesizer me, const Sound thee, const TextInterval him,
+	const double silenceThreshold,
+	const double minSilenceDuration, const double minSoundingDuration
+) {
 	try {
 		Melder_require (thy xmin == his xmin && thy xmax == his xmax,
 			U"Domains of Sound and TextGrid should be equal.");
@@ -477,7 +481,8 @@ autoTextGrid SpeechSynthesizer_Sound_TextInterval_align (SpeechSynthesizer me, S
 			U"The sampling frequencies of the SpeechSynthesizer and the Sound should be equal.");
 
 //TRACE
-trace(1);
+trace(U"original sound: ", thy xmin, U" .. ", thy xmax);
+trace(U"interval: ", his xmin, U" .. ", his xmax, U" ", his text.get());
 		autoSTRVEC tokens = splitByWhitespace_STRVEC (his text.get());
 		const integer numberOfTokens = tokens.size;
 		Melder_require (numberOfTokens > 0,
@@ -490,15 +495,24 @@ trace(1);
 trace(2);
 		const double minPitch = 200.0, timeStep = 0.005, precision = thy dx;
 		double startTimeOfSounding, endTimeOfSounding;
-		autoSound soundTrimmed = Sound_trimSilencesAtStartAndEnd (thee, 0.0, minPitch, timeStep, silenceThreshold, minSilenceDuration, minSoundingDuration, & startTimeOfSounding, & endTimeOfSounding);
+		autoSound soundTrimmed;
+		{// scope
+			autoMelderWarningOff nowarn;
+			soundTrimmed = Sound_trimSilencesAtStartAndEnd (thee, 0.0, minPitch, timeStep,
+					silenceThreshold, minSilenceDuration, minSoundingDuration, & startTimeOfSounding, & endTimeOfSounding);
+		}
+trace (U"- silence-trimmed: ", soundTrimmed -> xmin, U" .. ", soundTrimmed -> xmax);
 		const double duration_soundTrimmed = soundTrimmed -> xmax - soundTrimmed -> xmin;
+		Melder_require (duration_soundTrimmed > 0.0,
+			soundTrimmed.get(), U" is silent, so we cannot align it with text.");
 		const bool hasSilence_sound = fabs (startTimeOfSounding - thy xmin) > precision || fabs (endTimeOfSounding - thy xmax) > precision;
 trace(3);
 
-		if (my d_estimateSpeechRate) {
+		if (my d_estimateSpeechRate && duration_soundTrimmed != 0.0) {
 			/*
 				Estimate speaking rate with the number of words per minute from the text
 			*/
+			Melder_assert (duration_soundTrimmed != 0.0);
 			const double wordsPerMinute_rawTokens = 60.0 * numberOfTokens / duration_soundTrimmed;
 			/*
 				Compensation for long words: 5 characters / word
@@ -519,10 +533,17 @@ trace(4);
 		const double silenceThreshold_synth = -40.0, minSilenceDuration_synth = 0.05; 
 		const double minSoundingDuration_synth = 0.05;
 		double startTimeOfSounding_synth, endTimeOfSounding_synth;
-		autoSound synthTrimmed = Sound_trimSilencesAtStartAndEnd (synth.get(), 0.0, minPitch, timeStep, silenceThreshold_synth,
-			minSilenceDuration_synth, minSoundingDuration_synth, & startTimeOfSounding_synth, & endTimeOfSounding_synth);
+		autoSound synthTrimmed;
+		{// scope
+			autoMelderWarningOff nowarn;
+			synthTrimmed = Sound_trimSilencesAtStartAndEnd (synth.get(), 0.0, minPitch, timeStep, silenceThreshold_synth,
+					minSilenceDuration_synth, minSoundingDuration_synth, & startTimeOfSounding_synth, & endTimeOfSounding_synth);
+		}
 		const double synthTrimmed_duration = synthTrimmed -> xmax - synthTrimmed -> xmin;
-		const bool hasSilence_synth = fabs (startTimeOfSounding_synth - synth -> xmin) > precision || 
+trace (U"synthesized sound: ", synth -> xmin, U" .. ", synth -> xmax);
+trace (U"- silence-trimmed: ", synthTrimmed -> xmin, U" .. ", synthTrimmed -> xmax);
+trace (U"-        sounding: ", startTimeOfSounding_synth, U" .. ", endTimeOfSounding_synth);
+		const bool hasSilence_synth = fabs (startTimeOfSounding_synth - synth -> xmin) > precision ||
 								fabs (endTimeOfSounding_synth - synth -> xmax) > precision;
 trace(5);
 
@@ -531,12 +552,14 @@ trace(5);
 		/*
 			Compare the durations of the two sounds to get an indication of the slope constraint needed for the DTW
 		*/
+		Melder_assert (synthTrimmed_duration != 0.0);
 		double slope = duration_soundTrimmed / synthTrimmed_duration;
+		Melder_assert (slope != 0.0);
 		slope = ( slope > 1.0 ? slope : 1.0 / slope );
-		const int constraint = ( slope < 1.5 ? 4 : slope < 2.0 ? 3 : slope < 3.0 ? 2 : 1 ); // TODO enums
+		const int constraint = ( slope < 1.5 ? 4 : slope < 2.0 ? 3 : slope < 3.0 ? 2 : 1 );   // TODO enums
 
 trace(6);
-		trace (hasSilence_sound, hasSilence_synth);
+trace (hasSilence_sound, hasSilence_synth);
 		const double analysisWidth = 0.02, dt = 0.005, band = 0.0;
 		autoDTW dtw = Sounds_to_DTW ((hasSilence_sound ? soundTrimmed.get() : thee),
 				(hasSilence_synth ? synthTrimmed.get() : synth.get()), analysisWidth, dt, band, constraint);
@@ -545,15 +568,19 @@ trace(7);
 		autoTextGrid result = DTW_TextGrid_to_TextGrid (dtw.get(), (hasSilence_synth ? textgrid_synth_sounding.get() : textgrid_synth.get()), precision);
 trace(8);
 		if (hasSilence_sound) {
-			if (startTimeOfSounding > thy xmin)
+			if (startTimeOfSounding > thy xmin) {
+				trace (U"Have to set earlier start time ", thy xmin);
 				TextGrid_setEarlierStartTime (result.get(), thy xmin, U"", U"");
-			if (endTimeOfSounding < thy xmax || result -> xmax < thy xmax)
-					TextGrid_setLaterEndTime (result.get(), thy xmax, U"", U"");
+			}
+			if (endTimeOfSounding < thy xmax || result -> xmax < thy xmax) {
+				trace (U"Have to set later end time ", thy xmax);
+				TextGrid_setLaterEndTime (result.get(), thy xmax, U"", U"");
+			}
 		}
 trace(9);
 		return result;
 	} catch (MelderError) {
-		Melder_throw (U"Sound and TextInterval not aligned.");
+		Melder_throw (U"SpeechSynthesizer & Sound & TextInterval: not aligned.");
 	}
 }
 /*
@@ -589,7 +616,11 @@ static autoTextGrid SpeechSynthesizer_Sound_TextInterval_align2 (SpeechSynthesiz
 		*/
 		const double minPitch = 200, timeStep = 0.005, precision = thy dx;
 		autoTextGrid thee_trimmer;
-		autoSound thee_trimmed = Sound_trimSilences (thee, trimDuration, false, minPitch, timeStep, silenceThreshold,  minSilenceDuration, minSoundingDuration, &thee_trimmer, trimLabel);
+		autoSound thee_trimmed;
+		{// scope
+			autoMelderWarningOff nowarn;
+			thee_trimmed = Sound_trimSilences (thee, trimDuration, false, minPitch, timeStep, silenceThreshold,  minSilenceDuration, minSoundingDuration, & thee_trimmer, trimLabel);
+		}
 		/*
 			2. Synthesize the sound from the TextInterval
 		*/


=====================================
dwtools/TextGrid_extensions.cpp
=====================================
@@ -1,6 +1,6 @@
 /* TextGrid_extensions.cpp
  *
- * Copyright (C) 1993-2019, 2023 David Weenink, Paul Boersma 2019
+ * Copyright (C) 1993-2019,2023 David Weenink, 2015-2022,2024 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -385,30 +385,6 @@ void IntervalTier_setEarlierStartTime (IntervalTier me, double xmin, conststring
 	}
 }
 
-void IntervalTier_moveBoundary (IntervalTier me, integer iint, bool atStart, double newTime) {
-    try {
-		Melder_require (iint >= 1 && iint <= my intervals.size,
-            U"The interval number is out of the valid range.");
-		Melder_require (! ((iint == 1 && atStart) or (iint == my intervals.size && ! atStart)),
-			U"Cannot change the domain.");
-        TextInterval interval = my intervals.at [iint];
-        if (atStart) {
-            const TextInterval pinterval = my intervals.at [iint-1];
-			Melder_require (newTime > pinterval -> xmin,
-				U"Cannot move past the start of previous interval.");
-            pinterval -> xmax = interval -> xmin = newTime;
-        } else {
-            const TextInterval ninterval = my intervals.at [iint+1];
-			Melder_require (newTime < ninterval -> xmax,
-				U"Cannot move past the end of next interval.");
-            ninterval -> xmin = interval -> xmax = newTime;
-        }
-    } catch (MelderError) {
-        Melder_throw (me, U": boundary not moved.");
-    }
-}
-
-
 void TextTier_setLaterEndTime (TextTier me, double xmax, conststring32 mark) {
 	try {
 		if (xmax <= my xmax)
@@ -565,7 +541,7 @@ static void IntervalTier_cutInterval (IntervalTier me, integer index, int extend
 }
 
 void IntervalTier_removeBoundariesBetweenIdenticallyLabeledIntervals (IntervalTier me, conststring32 label) {
-    try {
+	try {
 		for (integer iinterval = my intervals.size; iinterval > 1; iinterval --) {
 			const TextInterval thisInterval = my intervals.at [iinterval];
 			if (Melder_equ (thisInterval -> text.get(), label)) {


=====================================
dwtools/TextGrid_extensions.h
=====================================
@@ -102,8 +102,6 @@ void IntervalTier_setLaterEndTime (IntervalTier me, double xmax, conststring32 m
 
 void IntervalTier_setEarlierStartTime (IntervalTier me, double xmin, conststring32 mark);
 
-void IntervalTier_moveBoundary (IntervalTier me, integer interval, bool atStart, double newTime);
-
 void TextTier_setLaterEndTime (TextTier me, double xmax, conststring32 mark);
 
 void TextTier_setEarlierStartTime (TextTier me, double xmin, conststring32 mark);


=====================================
dwtools/VowelEditor.cpp
=====================================
@@ -772,9 +772,9 @@ static void menu_cb_settings (VowelEditor me, EDITOR_ARGS) {
 		}
 		const integer numberOfPairs = extraFrequencyBandwidthPairs.size / 2;
 		Melder_require (numberOfFormants <= numberOfPairs + 2,
-			U"The “Number of formants for synthesis” should not exceed 2 plus the number of extra frequency–bandwidth pairs (i.e. 2+",
-			numberOfPairs, U"). Either lower the number of formants for synthesis or specify more "
-			"frequency–bandwidth pairs.");
+			U"The “Number of formants for synthesis” should not exceed 2 plus the number of extra frequency–bandwidth pairs "
+			U"(i.e. 2+", numberOfPairs,
+			U"). Either lower the number of formants for synthesis, or specify more frequency–bandwidth pairs.");
 		/*
 			Formants and bandwidths are valid. It is safe to copy them.
 		*/


=====================================
dwtools/espeakdata_FileInMemory.cpp
=====================================
@@ -216,13 +216,12 @@ void espeakdata_getIndices (conststring32 language_string, conststring32 voice_s
 		if (languageIndex == 0) {
 			if (Melder_equ (language_string, U"Default") || Melder_equ (language_string, U"English")) {
 				languageIndex = Strings_findString (espeakdata_languages_names.get(), U"English (Great Britain)");
-				Melder_casual (U"Language \"", language_string, U"\" is deprecated. Please use \"",
-					espeakdata_languages_names -> strings [languageIndex].get(), U"\".");
+				Melder_warning (U"Language \"", language_string, U"\" is deprecated. Please use \"",
+						espeakdata_languages_names -> strings [languageIndex].get(), U"\".");
 			} else {
 				languageIndex = Table_searchColumn (espeakdata_languages_propertiesTable.get(), 1, language_string);
-				if (languageIndex == 0) {
+				if (languageIndex == 0)
 					Melder_throw (U"Language \"", language_string, U"\" is not a valid option.");
-				}
 			}
 		}
 		*p_languageIndex = languageIndex;
@@ -246,7 +245,7 @@ void espeakdata_getIndices (conststring32 language_string, conststring32 voice_s
 		if (voiceIndex != *p_voiceIndex) {
 			*p_voiceIndex = voiceIndex;
 			Melder_casual (U"Voice \"", voice_string, U"\" is deprecated. Please use \"",
-				espeakdata_voices_names -> strings [*p_voiceIndex].get(), U"\".");
+					espeakdata_voices_names -> strings [*p_voiceIndex].get(), U"\".");
 		} else {
 			// unknown voice, handled by interface
 		}


=====================================
dwtools/praat_David_init.cpp
=====================================
@@ -5743,7 +5743,7 @@ DO
 }
 
 FORM (CONVERT_EACH_TO_ONE__Sound_trimSilences, U"Sound: Trim silences", U"Sound: Trim silences...") {
-    REAL (trimDuration, U"Trim duration (s)", U"0.08")
+	REAL (trimDuration, U"Trim duration (s)", U"0.08")
 	BOOLEAN (onlyAtStartAndEnd, U"Only at start and end", true);
 	LABEL (U"Parameters for the intensity analysis")
 	POSITIVE (pitchFloor, U"Pitch floor (Hz)", U"100")
@@ -5756,7 +5756,7 @@ FORM (CONVERT_EACH_TO_ONE__Sound_trimSilences, U"Sound: Trim silences", U"Sound:
 	WORD (trim_string, U"Trim label", U"trimmed")
 	OK
 DO
-	trimDuration = ( trimDuration < 0.0 ? 0.0 : trimDuration );
+	Melder_clipLeft (0.0, & trimDuration);
 	CONVERT_EACH_TO_ONE (Sound)
 		autoTextGrid tg;
 		autoSound result = Sound_trimSilences (me, trimDuration, onlyAtStartAndEnd, pitchFloor, timeStep,


=====================================
external/espeak/common.cpp
=====================================
@@ -332,14 +332,18 @@ static uint32_t espeak_rand_state = 0;
 
 long espeak_rand(long min, long max) {
 	// Ref: https://github.com/bminor/glibc/blob/glibc-2.36/stdlib/random_r.c#L364
+#if 1
 	espeak_rand_state = (((uint64_t)espeak_rand_state * 1103515245) + 12345) % 0x7fffffff;
+#endif
 	long res = (long)espeak_rand_state;
 	return (res % (max-min+1))-min;
 }
 
 void espeak_srand(long seed) {
+#if 1
 	espeak_rand_state = (uint32_t)(seed);
 	(void)espeak_rand(0, 1); // Dummy flush a generator
+#endif
 }
 
 #pragma GCC visibility push(default)


=====================================
external/espeak/synthesize.h
=====================================
@@ -412,7 +412,7 @@ extern const unsigned char env_fall[128];
 #define WCMD_SONIC_SPEED 15
 #define WCMD_PHONEME_ALIGNMENT 16
 
-#define N_WCMDQ   170
+#define N_WCMDQ   170   // normally 170
 #define MIN_WCMDQ  25   // need this many free entries before adding new phoneme
 
 extern intptr_t wcmdq[N_WCMDQ][4];


=====================================
external/espeak/wavegen.cpp
=====================================
@@ -37,6 +37,8 @@
 #include "synthesize.h"               // for WGEN_DATA, RESONATOR, frame_t
 #include "mbrola.h"                  // for MbrolaFill, MbrolaReset, mbrola...
 
+#include "melder.h"   // for tracing
+
 #if USE_KLATT
 #include "klatt.h"
 #endif
@@ -269,6 +271,8 @@ void WcmdqInc(void)
 {
 	wcmdq_tail++;
 	if (wcmdq_tail >= N_WCMDQ) wcmdq_tail = 0;
+	//TRACE
+	trace (U"Tail now ", wcmdq_tail);
 }
 
 static void WcmdqIncHead(void)
@@ -276,6 +280,8 @@ static void WcmdqIncHead(void)
 	MAKE_MEM_UNDEFINED(&wcmdq[wcmdq_head], sizeof(wcmdq[wcmdq_head]));
 	wcmdq_head++;
 	if (wcmdq_head >= N_WCMDQ) wcmdq_head = 0;
+	//TRACE
+	trace (U"Head now ", wcmdq_head);
 }
 
 #define PEAKSHAPEW 256


=====================================
fon/TextGrid.cpp
=====================================
@@ -1189,6 +1189,49 @@ void TextGrid_removeBoundaryAtTime (TextGrid me, integer tierNumber, double t) {
 	}
 }
 
+void IntervalTier_moveLeftBoundary (const IntervalTier me, const integer intervalNumber, const double newTime) {
+	try {
+		Melder_require (intervalNumber >= 1 && intervalNumber <= my intervals.size,
+			U"The interval number (", intervalNumber, U" is out of the valid range (1 ..", my intervals.size, U").");
+		TextInterval currentInterval = my intervals.at [intervalNumber];
+		Melder_require (newTime < currentInterval -> xmax,
+			U"Cannot move boundary forward from ", currentInterval -> xmin, U" to ", newTime, U" seconds, ",
+			U"because that would be past the end of the current interval (", currentInterval -> xmax, U" seconds).");
+		Melder_require (intervalNumber > 1,
+			U"Trying to change the end of the previous interval (", intervalNumber - 1, U"), but there is no previous interval.");
+		Melder_assert (my intervals.size >= 2);   // otherwise we would have thrown
+		const TextInterval previousInterval = my intervals.at [intervalNumber - 1];
+		Melder_require (newTime > previousInterval -> xmin,
+			U"Cannot move boundary back from ", currentInterval -> xmin, U" to ", newTime, U" seconds, ",
+			U"because that would be past the start of the previous interval (", previousInterval -> xmin, U" seconds).");
+		previousInterval -> xmax = currentInterval -> xmin = newTime;
+	} catch (MelderError) {
+		Melder_throw (me, U": left boundary not moved.");
+	}
+}
+
+void IntervalTier_moveRightBoundary (const IntervalTier me, const integer intervalNumber, const double newTime) {
+	try {
+		Melder_require (intervalNumber >= 1 && intervalNumber <= my intervals.size,
+			U"The interval number (", intervalNumber, U" is out of the valid range (1 ..", my intervals.size, U").");
+		TextInterval currentInterval = my intervals.at [intervalNumber];
+		Melder_require (newTime > currentInterval -> xmin,
+			U"Cannot move boundary back from ", currentInterval -> xmax, U" to ", newTime, U" seconds, ",
+			U"because that would be past the start of the current interval (", currentInterval -> xmin, U" seconds).");
+		Melder_require (intervalNumber < my intervals.size,
+			U"Trying to change the start of the next interval (", intervalNumber + 1, U"), but there is no next interval.");
+		Melder_assert (my intervals.size >= 2);   // otherwise we would have thrown
+		const TextInterval nextInterval = my intervals.at [intervalNumber + 1];
+		Melder_require (newTime < nextInterval -> xmax,
+			U"Cannot move boundary forward from ", currentInterval -> xmax, U" to ", newTime, U" seconds, ",
+			U"because that would be past the end of the next interval (", nextInterval -> xmax, U" seconds)."
+		);
+		nextInterval -> xmin = currentInterval -> xmax = newTime;
+	} catch (MelderError) {
+		Melder_throw (me, U": right boundary not moved.");
+	}
+}
+
 void TextGrid_setIntervalText (TextGrid me, integer tierNumber, integer intervalNumber, conststring32 text) {
 	try {
 		IntervalTier intervalTier = TextGrid_checkSpecifiedTierIsIntervalTier (me, tierNumber);


=====================================
fon/TextGrid.h
=====================================
@@ -58,6 +58,8 @@ autoPointProcess IntervalTier_getCentrePoints (IntervalTier me, conststring32 te
 autoPointProcess IntervalTier_PointProcess_startToCentre (IntervalTier tier, PointProcess point, double phase);
 autoPointProcess IntervalTier_PointProcess_endToCentre (IntervalTier tier, PointProcess point, double phase);
 void IntervalTier_removeLeftBoundary (IntervalTier me, integer intervalNumber);
+void IntervalTier_moveLeftBoundary (IntervalTier me, integer interval, double newTime);
+void IntervalTier_moveRightBoundary (IntervalTier me, integer interval, double newTime);
 
 void TextTier_removePoint (TextTier me, integer pointNumber);
 


=====================================
fon/TextGrid_Sound.cpp
=====================================
@@ -30,7 +30,8 @@ static bool IntervalTier_check (IntervalTier me) {
 			return false;
 		}
 	}
-	if (my intervals.size < 2) return true;
+	if (my intervals.size < 2)
+		return true;
 	for (integer iinterval = 1; iinterval < my intervals.size; iinterval ++) {
 		TextInterval thisInterval = my intervals.at [iinterval];
 		TextInterval nextInterval = my intervals.at [iinterval + 1];
@@ -149,6 +150,7 @@ void TextGrid_anySound_alignInterval (
 	const bool includeWords, const bool includePhonemes
 ) {
 	try {
+		//TRACE
 		IntervalTier headTier = TextGrid_checkSpecifiedTierIsIntervalTier (me, tierNumber);
 		if (intervalNumber < 1 || intervalNumber > headTier -> intervals.size)
 			Melder_throw (U"Interval ", intervalNumber, U" does not exist.");
@@ -157,6 +159,8 @@ void TextGrid_anySound_alignInterval (
 			Melder_throw (U"Nothing to be done, because you asked neither for word alignment nor for phoneme alignment.");
 		if (str32str (headTier -> name.get(), U"/"))
 			Melder_throw (U"The current tier already has a slash (\"/\") in its name. Cannot create a word or phoneme tier from it.");
+		trace (U"tier ", tierNumber, U" interval ", intervalNumber,
+				U" (", interval -> xmin, U" .. ", interval -> xmax, U" “", interval -> text.get(), U"”)");
 		autoSound part =
 			anySound -> classInfo == classLongSound ? 
 				LongSound_extractPart (static_cast <LongSound> (anySound), interval -> xmin, interval -> xmax, true) :
@@ -169,16 +173,31 @@ void TextGrid_anySound_alignInterval (
 		);
 		double silenceThreshold = -30.0, minSilenceDuration = 0.1, minSoundingDuration = 0.1;
 		autoTextGrid analysis;
+int tries = 0;
+constexpr int maxTries = 5;
+again:
 		if (! Melder_equ (interval -> text.get(), U""))
-			analysis = SpeechSynthesizer_Sound_TextInterval_align
-					(synthesizer.get(), part.get(), interval, silenceThreshold, minSilenceDuration, minSoundingDuration);
+			try {
+				analysis = SpeechSynthesizer_Sound_TextInterval_align
+						(synthesizer.get(), part.get(), interval, silenceThreshold, minSilenceDuration, minSoundingDuration);
+			} catch (MelderError) {
+				if (++ tries < maxTries) {
+					Melder_casual (U"TRY ", tries, U" FAILED (SpeechSynthesizer & Sound & TextInterval: align):");
+					Melder_casual (U"    Tier ", tierNumber);
+					Melder_casual (U"    Interval ", intervalNumber, U": ", interval -> xmin, U" .. ", interval -> xmax, U" “", interval -> text.get(), U"”");
+					Melder_casual (U"REASON OF THIS TEMPORARY FAILURE (now comes a suppressed Praat error message):\n", Melder_getError (), U"(GOING TO RETRY...)");
+					Melder_clearError ();
+					goto again;
+				} else
+					Melder_throw (U"All ", maxTries, U" tries failed.");
+			}
 		if (analysis) {
 			/*
 				Clean up the analysis.
 			*/
 			Melder_assert (fabs (analysis -> xmin - interval -> xmin) < 1e-12);
 			if (analysis -> xmax != interval -> xmax) {
-				//Melder_fatal (U"Analysis ends at ", analysis -> xmax, U" but interval at ", interval -> xmax, U"seconds.");
+				Melder_casual (U"Analysis ends at ", analysis -> xmax, U" but interval at ", interval -> xmax, U" seconds.");
 				analysis -> xmax = interval -> xmax;
 				analysis -> intervalTier_cast (1) -> xmax = interval -> xmax;
 				analysis -> intervalTier_cast (2) -> xmax = interval -> xmax;
@@ -191,8 +210,19 @@ void TextGrid_anySound_alignInterval (
 			}
 			Melder_assert (analysis -> tiers->size == 4);
 			IntervalTier analysisWordTier = analysis -> intervalTier_cast (3);
-			if (! IntervalTier_check (analysisWordTier))
-				Melder_throw (U"Analysis word tier out of order.");
+			tries += 1;
+			if (! IntervalTier_check (analysisWordTier)) {
+				if (tries < maxTries) {
+					Melder_casual (U"TRY ", tries, U" FAILED (SpeechSynthesizer & Sound & TextInterval: align):");
+					Melder_casual (U"    Tier ", tierNumber);
+					Melder_casual (U"    Interval ", intervalNumber, U": ", interval -> xmin, U" .. ", interval -> xmax, U" “", interval -> text.get(), U"”");
+					Melder_casual (U"REASON OF THIS TEMPORARY FAILURE:\n");
+					Melder_casual (U"Analysis word tier out of order.\n(GOING TO RETRY...)");
+					goto again;
+				} else
+					Melder_throw (U"All ", maxTries, U" tries failed.");
+			} else if (tries > 1)
+				Melder_casual (U"(TRY ", tries, U" SUCCEEDED)");
 			IntervalTier_removeEmptyIntervals (analysisWordTier, nullptr);
 			Melder_assert (analysisWordTier -> xmax == analysis -> xmax);
 			Melder_assert (analysisWordTier -> intervals.size >= 1);


=====================================
sys/Gui_messages.cpp
=====================================
@@ -300,11 +300,7 @@ static void * gui_monitor (double progress, conststring32 message) {
 		}
 		/*
 			Display the alert dialog and synchronously wait for the user to click OK.
-			But: it is not impossible that the program crashes during `runModal`,
-			especially if `runModal` is called at expose time.
-			Write the message to stdout just in case.
 		*/
-		Melder_casual (message32);
 		[alert runModal];
 		[alert release];
 	}
@@ -315,6 +311,7 @@ static char * theMessageFund = nullptr;
 
 static void gui_fatal (conststring32 message) {
 	free (theMessageFund);
+	Melder_casual (U"PRAAT CRASH MESSAGE:\n", message, U"\n(END OF PRAAT CRASH MESSAGE)");
 	#if gtk
 		GuiObject dialog = gtk_message_dialog_new (GTK_WINDOW (Melder_topShell -> d_gtkWindow), GTK_DIALOG_DESTROY_WITH_PARENT,
 			GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE, "%s", Melder_peek32to8 (message));
@@ -333,6 +330,12 @@ static void gui_error (conststring32 message) {
 	const bool memoryIsLow = str32str (message, U"Out of memory");
 	if (memoryIsLow)
 		free (theMessageFund);
+	/*
+		It is not impossible that the program crashes during `gtk_dialog_run` or `MessageBox` or `runModal`,
+		especially if these are called at expose time.
+		Write the message to stdout just in case.
+	*/
+	Melder_casual (U"PRAAT ERROR MESSAGE:\n", message, U"(END OF PRAAT ERROR MESSAGE)");
 	#if gtk
 		trace (U"create dialog");
 		GuiObject dialog = gtk_message_dialog_new (GTK_WINDOW (Melder_topShell -> d_gtkWindow), GTK_DIALOG_DESTROY_WITH_PARENT,
@@ -364,6 +367,7 @@ static void gui_error (conststring32 message) {
 }
 
 static void gui_warning (conststring32 message) {
+	Melder_casual (U"PRAAT WARNING MESSAGE:\n", message, U"\n(END OF PRAAT WARNING MESSAGE)");
 	#if gtk
 		GuiObject dialog = gtk_message_dialog_new (GTK_WINDOW (Melder_topShell -> d_gtkWindow), GTK_DIALOG_DESTROY_WITH_PARENT,
 			GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", Melder_peek32to8 (message));


=====================================
sys/HyperPage.cpp
=====================================
@@ -462,7 +462,7 @@ void HyperPage_script (HyperPage me, double width_inches, double height_inches,
 
 				{// scope
 					autoMelderProgressOff progress;
-					autoMelderWarningOff warning;
+					autoMelderWarningOff nowarn;
 					autoMelderSaveCurrentFolder saveFolder;
 					if (! MelderFolder_isNull (& my rootDirectory))
 						Melder_setCurrentFolder (& my rootDirectory);
@@ -560,7 +560,7 @@ void HyperPage_script (HyperPage me, double width_inches, double height_inches,
 
 			{// scope
 				autoMelderProgressOff progress;
-				autoMelderWarningOff warning;
+				autoMelderWarningOff nowarn;
 				autoMelderSaveCurrentFolder saveFolder;
 				if (! MelderFolder_isNull (& my rootDirectory))
 					Melder_setCurrentFolder (& my rootDirectory);


=====================================
sys/ManPage.cpp
=====================================
@@ -140,7 +140,7 @@ void ManPage_runAllChunksToCache (ManPage me, Interpreter optionalInterpreterRef
 			MelderInfo_close ();
 		} else {
 			autoMelderProgressOff progress;
-			autoMelderWarningOff warning;
+			autoMelderWarningOff nowarn;
 			autoMelderSaveCurrentFolder saveFolder;
 			if (! MelderFolder_isNull (rootDirectory))
 				Melder_setCurrentFolder (rootDirectory);


=====================================
sys/ManPages_toHtml.cpp
=====================================
@@ -228,7 +228,7 @@ static void writeParagraphsAsHtml (ManPages me, Interpreter optionalInterpreterR
 				);
 				{// scope
 					autoMelderProgressOff progress;
-					autoMelderWarningOff warning;
+					autoMelderWarningOff nowarn;
 					autoMelderSaveCurrentFolder saveFolder;
 					if (! MelderFolder_isNull (& my rootDirectory))
 						Melder_setCurrentFolder (& my rootDirectory);



View it on GitLab: https://salsa.debian.org/med-team/praat/-/compare/8006c3ff72623ec4444d98d6b646562a04553d47...5fcb70a345dedb1c174bd109e101f8758f8c1dac

-- 
View it on GitLab: https://salsa.debian.org/med-team/praat/-/compare/8006c3ff72623ec4444d98d6b646562a04553d47...5fcb70a345dedb1c174bd109e101f8758f8c1dac
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20240505/3f4d3adb/attachment-0001.htm>


More information about the debian-med-commit mailing list