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

Rafael Laboissière (@rafael) gitlab at salsa.debian.org
Sun Dec 3 19:45:27 GMT 2023



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


Commits:
f4394a63 by Rafael Laboissière at 2023-12-02T09:01:34-03:00
New upstream version 6.4.01+dfsg
- - - - -
b355ec86 by Rafael Laboissière at 2023-12-02T09:02:56-03:00
Update upstream source from tag 'upstream/6.4.01+dfsg'

Update to upstream version '6.4.01+dfsg'
with Debian dir 60d562c97e5ff5cfe79b2d5b70c69f46038e78dd
- - - - -
9bed39b0 by Rafael Laboissière at 2023-12-03T10:13:28-03:00
d/changelog: Add entry for release 6.4.01+dfsg-1

Gbp-Dch: Ignore

- - - - -


12 changed files:

- debian/changelog
- fon/manual_functions.cpp
- fon/manual_scripting.cpp
- fon/manual_whatsnew.cpp
- fon/praat_Sound.cpp
- foned/SoundAnalysisArea.cpp
- foned/SoundAnalysisArea_enums.h
- sys/EditorM.h
- sys/Ui.cpp
- sys/Ui.h
- sys/praatM.h
- sys/praat_version.h


Changes:

=====================================
debian/changelog
=====================================
@@ -1,3 +1,9 @@
+praat (6.4.01+dfsg-1) unstable; urgency=medium
+
+  * New upstream version 6.4.01+dfsg
+
+ -- Rafael Laboissière <rafael at debian.org>  Sat, 02 Dec 2023 09:18:27 -0300
+
 praat (6.4+dfsg-1) unstable; urgency=medium
 
   * New upstream version 6.4+dfsg


=====================================
fon/manual_functions.cpp
=====================================
@@ -271,10 +271,21 @@ A growing list of functions that you can use in @formulas and @scripting...
 , @`runSubprocess$` (%`executableFilePath$`, `...`) – run an external program with the given arguments, and return its output
 , @`runSystem` (`...`) – run a system command line with the given arguments concatenated
 , @`runSystem$` (`...`) – run a system command line with the given arguments concatenated, and return its output
+, @`selected` ( ) – the ID of the topmost selected object
+, @`selected` (%`i`) – the ID of the %%i%th selected object (as counted from the top, or from the bottom if negative)
+, @`selected` (%`type$`) – the ID of the topmost selected object of type %`type$`
+, @`selected` (%`type$`, %`i`) – the ID of the %%i%th selected object of type %`type$` (as counted from the top,
+  or from the bottom if negative)
+, @`selected$` ( ) – the full name (type + name) of the topmost selected object
+, @`selected$` (%`i`) – the full name (type + name) of the %%i%th selected object (as counted from the top,
+  or from the bottom if negative)
+, @`selected$` (%`type$`) – the name of the topmost selected object of type %`type$`
+, @`selected$` (%`type$`, %`i`) – the name of the %%i%th selected object of type %`type$` (as counted from the top,
+  or from the bottom if negative)
 , @`selected#` ( ) – the IDs of all selected objects
-, @`selected#` (%`type`) – the IDs of all selected objects of type %`type`
+, @`selected#` (%`type$`) – the IDs of all selected objects of type %`type$`
 , @`selected$#` ( ) – the names of all selected objects
-, @`selected$#` (%`type`) – the names of all selected objects of type %`type`
+, @`selected$#` (%`type$`) – the names of all selected objects of type %`type$`
 , @`selectObject` (`...`) – select objects in the list by ID and/or name
 , @`semitonesToHertz` (%`x`) – from logarithmic scale %re 100 Hz to acoustic frequency
 , @`sigmoid` (%`x`) – 1 / (1 + %e^^-%`x`^)
@@ -3670,6 +3681,56 @@ and return the output of that command line.
 
 For details and examples, see @@Scripting 6.5. Calling system commands at .
 
+################################################################################
+"`selected`"
+© Paul Boersma 2023
+
+A function that can be used in @Formulas.
+
+Syntax and semantics
+====================
+#`selected` ( )
+: return the ID of the topmost selected object.
+
+#`selected` (%`i`)
+: return the ID of the %%i%th selected object (as counted from the top, or from the bottom if %`i` is negative).
+
+#`selected` (%`type$`)
+: return the ID of the topmost selected object of type %`type$`.
+
+#`selected` (%`type$`, %`i`)
+: return the ID of the %%i%th selected object of type %`type$` (as counted from the top, or from the bottom if %`i` is negative).
+
+Usage
+=====
+For examples, see @@Scripting 4.3. Querying objects at .
+
+################################################################################
+"`selected$`"
+© Paul Boersma 2023
+
+A function that can be used in @Formulas.
+
+Syntax and semantics
+====================
+#`selected$` ( )
+: return the full name (type + name) of the topmost selected object.
+
+#`selected$` (%`i`)
+: return the full name (type + name) of the %%i%th selected object (as counted from the top, or from the bottom if %`i` is negative).
+
+#`selected$` (%`type$`)
+: return the name of the topmost selected object of type %`type$`.
+
+#`selected$` (%`type$`, %`i`)
+: return the name of the %%i%th selected object of type %`type$` (as counted from the top, or from the bottom if %`i` is negative).
+
+Usage
+=====
+This function is useful if you want to write or draw the name of the object.
+For selecting an object, using @`selected` is safer,
+as explained in @@Scripting 4.3. Querying objects at .
+
 ################################################################################
 "`selected#`"
 © Paul Boersma 2023
@@ -3681,8 +3742,8 @@ Syntax and semantics
 #`selected#` ( )
 : return a list of the IDs of all currently selected objects.
 
-#`selected#` (%`type`)
-: return a list of the IDs of all currently selected objects of type %`type`.
+#`selected#` (%`type$`)
+: return a list of the IDs of all currently selected objects of type %`type$`.
 
 Example
 =======
@@ -3741,8 +3802,8 @@ Syntax and semantics
 #`selected$#` ( )
 : return a list of the names of all currently selected objects.
 
-#`selected$#` (%`type`)
-: return a list of the names of all currently selected objects of type %`type`.
+#`selected$#` (%`type$`)
+: return a list of the names of all currently selected objects of type %`type$`.
 
 Pitfall
 =======


=====================================
fon/manual_scripting.cpp
=====================================
@@ -671,28 +671,28 @@ MAN_BEGIN (U"Scripting 3.2. Numeric variables", U"ppgb", 20230201)
 INTRO (U"In any general procedural programming language you can work with %variables, "
 	"which are places in your computer's memory where you can store a number or anything else.")
 NORMAL (U"For instance, you could put the number 3.1 into the variable $%b in the following way:")
-CODE (U"%b = 3.1")
-NORMAL (U"This statement is called as %assignment, i.e., you %assign the %value 3.1 to the %variable $%b. "
-	"We read this statement aloud as “$%b becomes 3.1” (or “$%b gets 3.1”, but not “$%b is 3.1”). "
-	"What this means is that after this statement, the memory location $%b %contains the numeric value (number) 3.1.")
-NORMAL (U"You can regard a variable as a box: you put the value 3.1 into the box named $%b. "
-	"Or you can regard a variable as a house: the house is called $%b and now the family “3.1” is living there. "
+CODE (U"b = 3.1")
+NORMAL (U"This statement is called as %assignment, i.e., you %assign the %value 3.1 to the %variable %`b`. "
+	"We read this statement aloud as “%`b` becomes 3.1” (or “%`b` gets 3.1”, but not “%`b` is 3.1”). "
+	"What this means is that after this statement, the memory location %`b` %contains the numeric value (number) 3.1.")
+NORMAL (U"You can regard a variable as a box: you put the value 3.1 into the box named %`b`. "
+	"Or you can regard a variable as a house: the house is called %`b` and now the family “3.1” is living there. "
 	"Or you can regard it as any other storage location.")
 NORMAL (U"To see what value a variable contains (what’s in the box, or who lives in the house), "
-	"you can use the $#writeInfoLine function:")
-CODE (U"%b = 3.1")
-CODE (U"writeInfoLine: “The value is ”, %b, “.”")
+	"you can use the #`writeInfoLine` function:")
+CODE (U"b = 3.1")
+CODE (U"writeInfoLine: “The value is ”, b, “.”")
 NORMAL (U"This will put the text “`The value is 3.1.`” into the Info window, as you are invited to verify.")
 NORMAL (U"A variable is called a variable because it is %variable, i.e. its value can change. Try the script")
-CODE (U"%b = 3.1")
-CODE (U"%b = 5.8")
-CODE (U"writeInfoLine: “The value is ”, %b, “.”")
-NORMAL (U"You will see that `b` ends up having the value 5.8. The first line puts the value 3.1 there, but the second line "
+CODE (U"b = 3.1")
+CODE (U"b = 5.8")
+CODE (U"writeInfoLine: “The value is ”, b, “.”")
+NORMAL (U"You will see that %`b` ends up having the value 5.8. The first line puts the value 3.1 there, but the second line "
 	"replaces it with 5.8. It’s like taking the 3.1 out of the box and putting the 5.8 in its stead. "
 	"Or the family 3.1 moves from the house, and the family called 5.8 moves in.")
 NORMAL (U"In an assignment, the part to the right of the “becomes” sign (the “=” sign) doesn’t have to be a number; "
 	"it can be any %formula that %evaluates to a number. For instance, the script")
-CODE (U"%b = 3.1 * 2")
+CODE (U"b = 3.1 * 2")
 CODE (U"writeInfoLine: “The value is ”, b, “.”")
 NORMAL (U"puts the text “`The value is 6.2.`” into the Info window. This works because Praat handles the first line "
 	"in the following way:")
@@ -701,22 +701,22 @@ LIST_ITEM (U"2. the value 6.2 is subsequently stored in the variable `b`.")
 NORMAL (U"After line 1 has been executed, the variable %`b` just contains the value 6.2, nothing more; "
 	"the variable %`b` doesn’t remember that that value has been computed by multiplying 3.1 with 2.")
 NORMAL (U"Formulas can contain more things than numbers: they can also contain other variables:")
-CODE (U"%b = 3.1")
-CODE (U"%c = %b * 2")
-CODE (U"writeInfoLine: “The value of b is ”, %b, “, and the value of c is ”, %c, “.”")
+CODE (U"b = 3.1")
+CODE (U"c = b * 2")
+CODE (U"writeInfoLine: “The value of b is ”, b, “, and the value of c is ”, c, “.”")
 NORMAL (U"In the first line, %`b` gets the value 3.1. In the second line, the formula `b * 2` first has to be evaluated. "
 	"Praat looks up the value of %`b` (which is 3.1), so that it knows that the formula actually means `3.1 * 2`. "
 	"Praat evaluates this formula and stores the result (namely the value 6.2) "
 	"into the variable %`c`, which will then contain nothing else than the value 6.2. "
 	"The Info window thus reports “`The value of b is 3.1, and the value of c is 6.2.`”.")
 NORMAL (U"After these explanations, consider the following script:")
-CODE (U"%b = 3.1")
-CODE (U"%c = %b * 2")
-CODE (U"%b = 5.8")
-CODE (U"writeInfoLine: “The value of c is ”, %c, “.”")
+CODE (U"b = 3.1")
+CODE (U"c = b * 2")
+CODE (U"b = 5.8")
+CODE (U"writeInfoLine: “The value of c is ”, c, “.”")
 NORMAL (U"Can you figure out what the Info will report? If you think it will report "
 	"“`The value of c is 6.2.`”, then you are correct: after the first line, %`b` contains the value 3.1; "
-	"after the second line, the value of $%c is therefore 6.2, and nothing more; "
+	"after the second line, the value of %`c` is therefore 6.2, and nothing more; "
 	"after line 3, the value of %`b` has changed to 5.8, but the value of %`c` hasn’t changed and is still 6.2.")
 NORMAL (U"If you thought that %`c` would end up having the value 11.6, then you’re thinking in terms "
 	"of a non-procedural language such as Prolog; you may have thought that the thing assigned to %`c` in the second line "
@@ -746,10 +746,10 @@ NORMAL (U"This is the mean power of the whole Sound.")
 NORMAL (U"In a script, you want to use the value of this power in the script itself, not in the Info window, "
 	"perhaps because you want to do computations with it or because you want to report the value with a nice text around it. "
 	"This is how you do the latter:")
-CODE (U"%power = Get power: 0.0, 0.0")
-CODE (U"writeInfoLine: “The power of this sound is ”, %power, “ Pascal-squared.”")
+CODE (U"power = Get power: 0.0, 0.0")
+CODE (U"writeInfoLine: “The power of this sound is ”, power, “ Pascal-squared.”")
 NORMAL (U"The first line of this script executes the menu command ##Get power...#, "
-	"but puts the value 0.1350605005239421 into the variable $%power instead of into the Info window "
+	"but puts the value 0.1350605005239421 into the variable %`power` instead of into the Info window "
 	"(the variable can have any name you like, as long as it starts with a lower-case letter "
 	"and consists of letters and digits; see @@Scripting 5.1. Variables@).")
 NORMAL (U"The second line then reports the value in the Info window, this time with a nice text around it:")
@@ -827,8 +827,8 @@ SCRIPT (6, 3, U""
 )
 NORMAL (U"A numeric query stores in a numeric variable only the first number that it can find in the text that would appear in the Info window. "
 	"For instance, the script")
-CODE (U"%power = Get power: 0.0, 0.0")
-CODE (U"writeInfoLine: %power")
+CODE (U"power = Get power: 0.0, 0.0")
+CODE (U"writeInfoLine: power")
 NORMAL (U"could give you the following result:")
 SCRIPT (6, 3, U""
 	Manual_DRAW_WINDOW (3, "Praat Info", "File   Edit   Search   Convert   Font   Help")
@@ -995,38 +995,38 @@ MAN_END
 
 MAN_BEGIN (U"Scripting 4.1. Selecting objects", U"ppgb", 20180428)
 NORMAL (U"To simulate the mouse-clicked and dragged selection in the list of objects, "
-	"you have the functions #`selectObject`, #`plusObject` and #`minusObject`.")
+	"you have the functions @`selectObject`, @`plusObject` and @`minusObject`.")
 NORMAL (U"Suppose you start Praat and use ##Create Sound as tone...# to create a Sound called %tone. "
 	"In the object list it looks like “1. Sound tone”. "
 	"Suppose you then do ##To Spectrum...# from the ##Analyse Spectrum# menu. "
 	"A second object, called “2. Spectrum tone” appears in the list and is selected. "
 	"To select and play the Sound, you can do either")
-CODE (U"selectObject: 1")
+CODE (U"\\#`{selectObject}: 1")
 CODE (U"Play")
 NORMAL (U"or")
-CODE (U"selectObject: “Sound tone”")
+CODE (U"\\#`{selectObject}: “Sound tone”")
 CODE (U"Play")
 NORMAL (U"So you can select an object either by its unique ID (identifier: the unique number by which it appears in the list) "
 	"or by name.")
-NORMAL (U"The function #selectObject works by first deselecting all objects, and then selecting the one you mention. "
-	"If you don’t want to deselect the existing selection, you can use #plusObject or #minusObject. "
+NORMAL (U"The function @`selectObject` works by first deselecting all objects, and then selecting the one you mention. "
+	"If you don’t want to deselect the existing selection, you can use @`plusObject` or @`minusObject`. "
 	"When the Sound is selected, you can select the Spectrum as well by doing")
-CODE (U"plusObject: 2")
+CODE (U"\\#`{plusObject}: 2")
 NORMAL (U"or")
-CODE (U"plusObject: “Spectrum tone”")
+CODE (U"\\#`{plusObject}: “Spectrum tone”")
 NORMAL (U"If you then want to deselect the Sound, and keep the Spectrum selected, you can do")
 CODE (U"\\#`{minusObject}: 1")
 NORMAL (U"or")
-CODE (U"minusObject: “Sound tone”")
+CODE (U"\\#`{minusObject}: “Sound tone”")
 NORMAL (U"All these functions can take more than one argument. To select the Sound and the Spectrum together, you can do")
 CODE (U"\\#`{selectObject}: 1, 2")
 NORMAL (U"or")
-CODE (U"selectObject: “Sound tone”, “Spectrum tone”")
+CODE (U"\\#`{selectObject}: “Sound tone”, “Spectrum tone”")
 NORMAL (U"or even")
-CODE (U"selectObject: 1, “Spectrum tone”")
+CODE (U"\\#`{selectObject}: 1, “Spectrum tone”")
 NORMAL (U"or, using a numeric vector:")
 CODE (U"myObjects# = { 1, 2 }")
-CODE (U"selectObject: myObjects#")
+CODE (U"\\#`{selectObject}: myObjects#")
 ENTRY (U"How to refer to objects created in your script")
 NORMAL (U"In a script, you typically don't know whether the IDs of the objects are 1 and 2, or much higher numbers. "
 	"Fortunately, commands that create a new object give you the ID of the object that is created, "
@@ -1038,7 +1038,7 @@ CODE (U"Play   ; the Sound is selected, so it plays")
 CODE (U"To Spectrum: “yes”")
 CODE (U"Draw: 0, 5000, 20, 80, “yes”   ; the Spectrum is selected, so it is drawn")
 CODE (U"# Remove the created Spectrum and Sound:")
-CODE (U"plusObject: sound   ; the Spectrum was already selected")
+CODE (U"\\#`{plusObject}: sound   ; the Spectrum was already selected")
 CODE (U"Remove")
 NORMAL (U"You could also select the objects by name:")
 CODE (U"Create Sound as pure tone: “sine377”,")
@@ -1047,97 +1047,141 @@ CODE (U"Play   ; the Sound is selected, so it plays")
 CODE (U"To Spectrum: “yes”")
 CODE (U"Draw: 0, 5000, 20, 80, “yes”   ; the Spectrum is selected, so it is drawn")
 CODE (U"# Remove the created Spectrum and Sound:")
-CODE (U"plusObject: “Sound sine377”   ; the Spectrum was already selected")
+CODE (U"\\#`{plusObject}: “Sound sine377”   ; the Spectrum was already selected")
 CODE (U"Remove")
 NORMAL (U"This works even if there are multiple objects called “Sound sine377”, "
-	"because if there are more objects with the same name, #selectObject and #plusObject select the most recently created one, "
+	"because if there are more objects with the same name, @`selectObject` and @`plusObject` select the most recently created one, "
 	"i.e., the one nearest to the bottom of the list of objects.")
 MAN_END
 
-MAN_BEGIN (U"Scripting 4.2. Removing objects", U"ppgb", 20140111)
-NORMAL (U"In @@Scripting 4.1. Selecting objects|\\SS4.1@ we saw that objects could be removed by selecting them first and then calling the #Remove command. "
-	"A faster way is the #removeObject function, which can also remove unselected objects:")
-CODE (U"sound = Create Sound as pure tone: “sine377”,")
-CODE (U"... 1, 0, 1, 44100, 377, 0.2, 0.01, 0.01   ; remember the ID of the Sound")
-CODE (U"Play   ; the Sound is selected, so it plays")
-CODE (U"spectrum = To Spectrum: “yes”   ; remember the ID of the Spectrum")
-CODE (U"Draw: 0, 5000, 20, 80, “yes”   ; the Spectrum is selected, so it is drawn")
-CODE (U"# Remove the created Spectrum and Sound:")
-CODE (U"\\#{removeObject}: sound, spectrum   ; remove one selected and one unselected object")
-NORMAL (U"The #removeObject function keeps the objects selected that were selected before "
-	"(except of course the ones it throws away). "
-	"This allows you to easily throw away objects as soon as you no longer need them:")
-CODE (U"sound = Create Sound as pure tone: “sine377”,")
-CODE (U"... 1, 0, 1, 44100, 377, 0.2, 0.01, 0.01   ; remember the ID of the Sound")
-CODE (U"Play   ; the Sound is selected, so it plays")
-CODE (U"spectrum = To Spectrum: “yes”")
-CODE (U"\\#{removeObject}: sound   ; we no longer need the Sound, so we remove it")
-CODE (U"Draw: 0, 5000, 20, 80, “yes”   ; the Spectrum is still selected, so it is drawn")
-CODE (U"\\#{removeObject}: spectrum   ; remove the last object created by the script")
-ENTRY (U"Selecting and removing all objects from the list (don't)")
-NORMAL (U"A very strange command, which you should not normally use, is `select all`:")
-	CODE1 (U"\\#{select all}")
-	CODE1 (U"Remove")
-NORMAL (U"This selects all objects in the list and then removes them. "
-	"Please try not to use this, because it will remove even the objects that your script did not create! "
-	"After all, you don’t want the users of your script to lose the objects they created! "
-	"So please try to remove in your script only the objects that your script created, "
-	"even if the script is for your own use (because if it is a nice script, others will want to use it).")
-MAN_END
 
-MAN_BEGIN (U"Scripting 4.3. Querying objects", U"ppgb", 20180427)
-NORMAL (U"You can get the name of a selected object into a string variable. "
-	"For instance, the following reads the name of the second selected Sound "
-	"(as counted from the top of the list of objects) into the variable %`name$`:")
-CODE (U"name$ = selected$ (“Sound”, 2)")
-NORMAL (U"If the Sound was called “Sound hallo”, the variable %`name$` will contain the string “hallo”. "
-	"To get the name of the topmost selected Sound object, you can leave out the number:")
-CODE (U"name$ = selected$ (“Sound”)")
-NORMAL (U"To get the full name (type + name) of the third selected object, you do:")
-CODE (U"fullName$ = selected$ (3)")
-NORMAL (U"To get the full name of the topmost selected object, you do:")
-CODE (U"fullName$ = selected$ ()")
-NORMAL (U"To get the type and name out of the full name, you do:")
-CODE (U"type$ = extractWord$ (fullName$, “”)")
-CODE (U"name$ = extractLine$ (fullName$, “ ”)")
-NORMAL (U"Negative numbers count from the bottom. Thus, to get the name of the bottom-most selected Sound "
-	"object, you say")
-CODE (U"name$ = selected$ (“Sound”, -1)")
-NORMAL (U"You would use `selected$` () for drawing the object name in a picture:")
-CODE (U"Draw: 0, 0, 0, 0, \"yes\"")
-CODE (U"name$ = selected$ (“Sound”)")
-CODE (U"Text top: “no”, “This is sound ” + name$")
-NORMAL (U"For identifying previously selected objects, this method is not very suitable, since "
-	"there may be multiple objects with the same name:")
-CODE (U"# The following two lines are OK:")
-CODE (U"soundName$ = selected$ (“Sound”, -1)")
-CODE (U"pitchName$ = selected$ (“Pitch”)")
-CODE (U"# But the following line is questionable, since it doesn't")
-CODE (U"# necessarily select the previously selected Pitch again:")
-CODE (U"selectObject: “Pitch ” + pitchName$")
-NORMAL (U"Instead of this error-prone approach, you should get the object’s unique ID. "
-	"The correct version of our example becomes:")
-CODE (U"sound = selected (“Sound”, -1)")
-CODE (U"pitch = selected (“Pitch”)")
-CODE (U"# Correct:")
-CODE (U"selectObject: pitch")
-NORMAL (U"To get the number of selected Sound objects into a variable, use")
-CODE (U"numberOfSelectedSounds = numberOfSelected (“Sound”)")
-NORMAL (U"To get the number of selected objects into a variable, use")
-CODE (U"numberOfSelectedObjects = numberOfSelected ()")
-ENTRY (U"Example: doing something to every selected Sound")
-CODE (U"sounds# = selected# (“Sound”)")
-CODE (U"# Median pitches of all selected sounds:")
-CODE (U"for i to size (sounds#)")
-	CODE1 (U"selectObject: sounds# [i]")
-	CODE1 (U"To Pitch: 0.0, 75, 600")
-	CODE1 (U"f0 = Get quantile: 0, 0, 0.50, “Hertz”")
-	CODE1 (U"appendInfoLine: f0")
-	CODE1 (U"Remove")
-CODE (U"endfor")
-CODE (U"# Restore selection:")
-CODE (U"selectObject (sounds#)")
-MAN_END
+MAN_PAGES_BEGIN
+R"~~~(
+################################################################################
+"Scripting 4.2. Removing objects"
+© Paul Boersma 1999,2004,2006–2008,2011,2013,2014
+
+In @@Scripting 4.1. Selecting objects|\SS4.1@ we saw that objects could be removed by
+selecting them first and then calling the #Remove command.
+A faster way is the #removeObject function, which can also remove unselected objects:
+{;
+	sound = Create Sound as pure tone: “sine377”,
+	... 1, 0, 1, 44100, 377, 0.2, 0.01, 0.01   ; remember the ID of the Sound
+	Play   ; the Sound is selected, so it plays
+	spectrum = To Spectrum: “yes”   ; remember the ID of the Spectrum
+	Draw: 0, 5000, 20, 80, “yes”   ; the Spectrum is selected, so it is drawn
+	# Remove the created Spectrum and Sound:
+	\#`{removeObject}: sound, spectrum   ; remove one selected and one unselected object
+}
+The #removeObject function keeps the objects selected that were selected before
+(except of course the ones it throws away).
+This allows you to easily throw away objects as soon as you no longer need them:
+{;
+	sound = Create Sound as pure tone: “sine377”,
+	... 1, 0, 1, 44100, 377, 0.2, 0.01, 0.01   ; remember the ID of the Sound
+	Play   ; the Sound is selected, so it plays
+	spectrum = To Spectrum: “yes”
+	\#`{removeObject}: sound   ; we no longer need the Sound, so we remove it
+	Draw: 0, 5000, 20, 80, “yes”   ; the Spectrum is still selected, so it is drawn
+	\#`{removeObject}: spectrum   ; remove the last object created by the script
+}
+Selecting and removing all objects from the list (don’t)
+========================================================
+A very strange command, which you should not normally use, is `select all`:
+{;
+	\#{select all}
+	Remove
+}
+This selects all objects in the list and then removes them.
+Please try not to use this, because it will remove even the objects that your script did not create!
+After all, you don’t want the users of your script to lose the objects they created!
+So please try to remove in your script only the objects that your script created,
+even if the script is for your own use (because if it is a nice script, others will want to use it).
+
+################################################################################
+"Scripting 4.3. Querying objects"
+© Paul Boersma 1999,2004,2006–2008,2011,2013,2014,2018,2023
+
+You can get the name of a selected object into a string variable.
+For instance, the following reads the name of the second selected Sound
+(as counted from the top of the list of objects) into the variable %`name$`:
+{;
+	name$ = \#`{selected$} (“Sound”, 2)
+}
+If the Sound was called “Sound hallo”, the variable %`name$` will contain the string “hallo”.
+To get the name of the topmost selected Sound object, you can leave out the number:
+{;
+	name$ = selected$ (“Sound”)
+}
+To get the full name (type + name) of the third selected object, you do:
+{;
+	fullName$ = selected$ (3)
+}
+To get the full name of the topmost selected object, you do:
+{;
+	fullName$ = selected$ ()
+}
+To get the type and name out of the full name, you do:
+{;
+	type$ = \`{extractWord$} (fullName$, “”)
+	name$ = \`{extractLine$} (fullName$, “ ”)
+}
+Negative numbers count from the bottom. Thus, to get the name of the bottom-most selected Sound
+object, you say
+{;
+	name$ = selected$ (“Sound”, -1)
+}
+You would use `selected$` () for drawing the object name in a picture:
+{;
+	Draw: 0, 0, 0, 0, “yes”
+	name$ = selected$ (“Sound”)
+	Text top: “no”, “This is sound ” + name$
+}
+For identifying previously selected objects, this method is not very suitable, since
+there may be multiple objects with the same name:
+{;
+	# The following two lines are OK:
+	soundName$ = selected$ (“Sound”, -1)
+	pitchName$ = selected$ (“Pitch”)
+	# But the following line is questionable, since it doesn’t
+	# necessarily select the previously selected Pitch again:
+	selectObject: “Pitch ” + pitchName$
+}
+Instead of this error-prone approach, you should get the object’s unique ID.
+The correct version of our example becomes:
+{;
+	sound = selected (“Sound”, -1)
+	pitch = selected (“Pitch”)
+	# Correct:
+	selectObject: pitch
+}
+To get the number of selected Sound objects into a variable, use
+{;
+	numberOfSelectedSounds = numberOfSelected (“Sound”)
+}
+To get the number of selected objects into a variable, use
+{;
+	numberOfSelectedObjects = numberOfSelected ()
+}
+Example: doing something to every selected Sound
+================================================
+{;
+	sounds# = \#`{selected#} (“Sound”)
+	# Median pitches of all selected sounds:
+	for i to size (sounds#)
+		selectObject: sounds# [i]
+		To Pitch (filtered ac): 0.0, 50, 800, 15, “no”, 0.03, 0.09, 0.50, 0.055, 0.35, 0.14
+		f0 = Get quantile: 0, 0, 0.50, “Hertz”
+		appendInfoLine: f0
+		Remove
+	endfor
+	# Restore selection:
+	selectObject (sounds#)
+}
+
+################################################################################
+)~~~"
+MAN_PAGES_END
 
 MAN_BEGIN (U"Scripting 5. Language elements reference", U"ppgb", 20170718)
 NORMAL (U"In a Praat script, you can use variables, expressions, and functions, of numeric as well as string type, "


=====================================
fon/manual_whatsnew.cpp
=====================================
@@ -29,6 +29,19 @@ R"~~~(
 
 Latest changes in Praat.
 
+##6.4.01# (30 November 2023)
+• Removed some visible percent signs before variable names from the scripting tutorial.
+• SoundEditor/TextGridEditor logging: when logging 'f0',
+  Praat now correctly reports values in Hz (rather than logarithms)
+  if Unit is set to “Hertz (logarithmic)”.
+  This bug had existed since Praat version 4.3.16 (June 2005).
+• SoundEditor/TextGridEditor scripting compatibility: made old versions of “Pitch settings...”
+  and “Advanced pitch settings...” available to scripts again, made the old denominations
+  “autocorrelation” and “cross-correlation” (as pitch analysis methods) available to scripts again,
+  and made obsolete versions of pitch analysis settings (such as “Pitch silence threshold”)
+  available again, now under the COMPATIBILITY section of the output of “Editor info”.
+  This will allow older editor scripts to continue to run without change.
+
 ##6.4# (15 November 2023)
 • New pitch analysis methods: @@Sound: To Pitch (filtered ac)...@ and
   @@Sound: To Pitch (filtered cc)... at .


=====================================
fon/praat_Sound.cpp
=====================================
@@ -1607,12 +1607,12 @@ DO
 }
 
 FORM (CONVERT_EACH_TO_ONE__Sound_to_Pitch_ac, U"Sound: To Pitch (ac)", U"Sound: To Pitch (ac)...") {
-	LABEL (U"Finding the candidates")
+	LABEL (U"Finding the candidates...")
 	REAL (timeStep, U"Time step (s)", U"0.0 (= auto)")
 	POSITIVE (pitchFloor, U"Pitch floor (Hz)", U"75.0")
 	NATURAL (maximumNumberOfCandidates, U"Max. number of candidates", U"15")
 	BOOLEAN (veryAccurate, U"Very accurate", false)
-	LABEL (U"Finding a path")
+	LABEL (U"Finding a path...")
 	REAL (silenceThreshold, U"Silence threshold", U"0.03")
 	REAL (voicingThreshold, U"Voicing threshold", U"0.45")
 	REAL (octaveCost, U"Octave cost", U"0.01")
@@ -1632,12 +1632,12 @@ DO
 	CONVERT_EACH_TO_ONE_END (my name.get())
 }
 FORM (CONVERT_EACH_TO_ONE__Sound_to_Pitch_cc, U"Sound: To Pitch (cc)", U"Sound: To Pitch (cc)...") {
-	LABEL (U"Finding the candidates")
+	LABEL (U"Finding the candidates...")
 	REAL (timeStep, U"Time step (s)", U"0.0 (= auto)")
 	POSITIVE (pitchFloor, U"Pitch floor (Hz)", U"75.0")
 	NATURAL (maximumNumberOfCandidates, U"Max. number of candidates", U"15")
 	BOOLEAN (veryAccurate, U"Very accurate", false)
-	LABEL (U"Finding a path")
+	LABEL (U"Finding a path...")
 	REAL (silenceThreshold, U"Silence threshold", U"0.03")
 	REAL (voicingThreshold, U"Voicing threshold", U"0.45")
 	REAL (octaveCost, U"Octave cost", U"0.01")
@@ -1658,13 +1658,13 @@ DO
 }
 
 FORM (CONVERT_EACH_TO_ONE__Sound_to_Pitch_rawAc, U"Sound: To Pitch (raw ac)", U"Sound: To Pitch (raw ac)...") {
-	LABEL (U"Finding the candidates")
+	LABEL (U"Finding the candidates...")
 	REAL (timeStep, U"Time step (s)", U"0.0 (= auto)")
 	POSITIVE (pitchFloor, U"Pitch floor (Hz)", U"75.0")
 	POSITIVE (pitchCeiling, U"Pitch ceiling (Hz)", U"600.0")
 	NATURAL (maximumNumberOfCandidates, U"Max. number of candidates", U"15")
 	BOOLEAN (veryAccurate, U"Very accurate", false)
-	LABEL (U"Finding a path")
+	LABEL (U"Finding a path...")
 	REAL (silenceThreshold, U"Silence threshold", U"0.03")
 	REAL (voicingThreshold, U"Voicing threshold", U"0.45")
 	REAL (octaveCost, U"Octave cost", U"0.01")
@@ -1684,13 +1684,13 @@ DO
 }
 
 FORM (CONVERT_EACH_TO_ONE__Sound_to_Pitch_rawCc, U"Sound: To Pitch (raw cc)", U"Sound: To Pitch (raw cc)...") {
-	LABEL (U"Finding the candidates")
+	LABEL (U"Finding the candidates...")
 	REAL (timeStep, U"Time step (s)", U"0.0 (= auto)")
 	POSITIVE (pitchFloor, U"Pitch floor (Hz)", U"75.0")
 	POSITIVE (pitchCeiling, U"Pitch ceiling (Hz)", U"600.0")
 	NATURAL (maximumNumberOfCandidates, U"Max. number of candidates", U"15")
 	BOOLEAN (veryAccurate, U"Very accurate", false)
-	LABEL (U"Finding a path")
+	LABEL (U"Finding a path...")
 	REAL (silenceThreshold, U"Silence threshold", U"0.03")
 	REAL (voicingThreshold, U"Voicing threshold", U"0.45")
 	REAL (octaveCost, U"Octave cost", U"0.01")
@@ -1710,15 +1710,15 @@ DO
 }
 
 FORM (CONVERT_EACH_TO_ONE__Sound_to_Pitch_filteredAc, U"Sound: To Pitch (filtered ac)", U"Sound: To Pitch (filtered ac)...") {
-	LABEL (U"Finding the candidates")
+	LABEL (U"Finding the candidates...")
 	REAL (timeStep, U"Time step (s)", U"0.0 (= auto)")
 	POSITIVE (pitchFloor, U"Pitch floor (Hz)", U"50.0")
 	POSITIVE (pitchCeiling, U"Pitch ceiling (Hz)", U"800.0")
 	NATURAL (maximumNumberOfCandidates, U"Max. number of candidates", U"15")
 	BOOLEAN (veryAccurate, U"Very accurate", false)
-	LABEL (U"Preprocessing")
+	LABEL (U"Preprocessing...")
 	POSITIVE (attenuationAtCeiling, U"Attenuation at ceiling", U"0.03")
-	LABEL (U"Finding a path")
+	LABEL (U"Finding a path...")
 	REAL (silenceThreshold, U"Silence threshold", U"0.09")
 	REAL (voicingThreshold, U"Voicing threshold", U"0.50")
 	REAL (octaveCost, U"Octave cost", U"0.055")
@@ -1738,15 +1738,15 @@ DO
 }
 
 FORM (CONVERT_EACH_TO_ONE__Sound_to_Pitch_filteredCc, U"Sound: To Pitch (filtered cc)", U"Sound: To Pitch (filtered cc)...") {
-	LABEL (U"Finding the candidates")
+	LABEL (U"Finding the candidates...")
 	REAL (timeStep, U"Time step (s)", U"0.0 (= auto)")
 	POSITIVE (pitchFloor, U"Pitch floor (Hz)", U"50.0")
 	POSITIVE (pitchCeiling, U"Pitch ceiling (Hz)", U"800.0")
 	NATURAL (maximumNumberOfCandidates, U"Max. number of candidates", U"15")
 	BOOLEAN (veryAccurate, U"Very accurate", false)
-	LABEL (U"Preprocessing")
+	LABEL (U"Preprocessing...")
 	POSITIVE (attenuationAtCeiling, U"Attenuation at ceiling", U"0.03")
-	LABEL (U"Finding a path")
+	LABEL (U"Finding a path...")
 	REAL (silenceThreshold, U"Silence threshold", U"0.09")
 	REAL (voicingThreshold, U"Voicing threshold", U"0.50")
 	REAL (octaveCost, U"Octave cost", U"0.055")


=====================================
foned/SoundAnalysisArea.cpp
=====================================
@@ -482,6 +482,17 @@ void structSoundAnalysisArea :: v1_info () {
 	MelderInfo_writeLine (U"Log 2 format: ", our instancePref_log2_format());
 	MelderInfo_writeLine (U"Log 3 script: ", our instancePref_logScript3());
 	MelderInfo_writeLine (U"Log 4 script: ", our instancePref_logScript4());
+	/*
+		COMPATIBILITY < 6400
+	*/
+	MelderInfo_writeLine (U"\nCOMPATIBILITY (obsolete settings for the benefit of old scripts):");
+	MelderInfo_writeLine (U"Pitch max. number of candidates: ", our instancePref_pitch_rawAcCc_maximumNumberOfCandidates());
+	MelderInfo_writeLine (U"Pitch very accurate: ", our instancePref_pitch_rawAcCc_veryAccurate());
+	MelderInfo_writeLine (U"Pitch silence threshold: ", our instancePref_pitch_rawAcCc_silenceThreshold(), U" of global peak");
+	MelderInfo_writeLine (U"Pitch voicing threshold: ", our instancePref_pitch_rawAcCc_voicingThreshold(), U" (periodic power / total power)");
+	MelderInfo_writeLine (U"Pitch octave cost: ", our instancePref_pitch_rawAcCc_octaveCost(), U" per octave");
+	MelderInfo_writeLine (U"Pitch octave jump cost: ", our instancePref_pitch_rawAcCc_octaveJumpCost(), U" per octave");
+	MelderInfo_writeLine (U"Pitch voiced/unvoiced cost: ", our instancePref_pitch_rawAcCc_voicedUnvoicedCost());
 }
 
 
@@ -691,6 +702,7 @@ static void do_log (SoundAnalysisArea me, int which) {
 				value = Pitch_getValueAtTime (my d_pitch.get(), tmin, my instancePref_pitch_unit(), 1);
 			else
 				value = Pitch_getMean (my d_pitch.get(), tmin, tmax, my instancePref_pitch_unit());
+			value = Function_convertToNonlogarithmic (my d_pitch.get(), value, Pitch_LEVEL_FREQUENCY, (int) my instancePref_pitch_unit());
 		} else if (varName [0] == U'f' && varName [1] >= U'1' && varName [1] <= U'5' && varName [2] == U'\0') {
 			SoundAnalysisArea_haveVisibleFormants (me);
 			if (part == SoundAnalysisArea_PART_CURSOR)
@@ -962,6 +974,33 @@ static void menu_cb_showPitch (SoundAnalysisArea me, EDITOR_ARGS) {
 	VOID_EDITOR_END
 }
 
+static void menu_cb_pitchSettings_BEFORE_6400 (SoundAnalysisArea me, EDITOR_ARGS) {
+	EDITOR_FORM (U"Pitch settings", U"Intro 4.2. Configuring the pitch contour")
+		LABEL   (U"YOU SHOULD NEVER SEE THIS OBSOLETE SETTINGS WINDOW;")
+		LABEL   (U"IT IS HERE ONLY FOR COMPATIBILITY WITH OLD SCRIPTS.")
+		POSITIVE (pitchFloor,   U"left Pitch range (Hz)",  my default_pitch_floor())
+		POSITIVE (pitchCeiling, U"right Pitch range (Hz)", my default_pitch_ceiling())
+		OPTIONMENU_ENUM (kPitch_unit, unit, U"Unit", my default_pitch_unit ())
+		CHOICE_ENUM (kSoundAnalysisArea_pitch_analysisMethod, analysisMethod, U"Analysis method", my default_pitch_method())
+		OPTIONMENU_ENUM (kSoundAnalysisArea_pitch_drawingMethod, drawingMethod, U"Drawing method", my default_pitch_drawingMethod())
+	EDITOR_OK
+	EDITOR_DO
+		Melder_require (pitchCeiling > pitchFloor,
+			U"The pitch ceiling has to be greater than the pitch floor, so they cannot be ",
+			pitchCeiling, U" and ", pitchFloor, U" ", kPitch_unit_getText (unit), U", respectively."
+		);
+		my setInstancePref_pitch_floor (pitchFloor);
+		my setInstancePref_pitch_ceiling (pitchCeiling);
+		my setInstancePref_pitch_unit (unit);
+		my setInstancePref_pitch_method (analysisMethod);
+		my setInstancePref_pitch_drawingMethod (drawingMethod);
+		my d_pitch. reset();
+		my d_intensity. reset();
+		my d_pulses. reset();
+		FunctionEditor_redraw (my functionEditor());
+	EDITOR_END
+}
+
 static void menu_cb_pitchSettings (SoundAnalysisArea me, EDITOR_ARGS) {
 	EDITOR_FORM (U"Pitch settings", U"Intro 4.2. Configuring the pitch contour")
 		POSITIVE (pitchFloor,   U"left Pitch range (Hz)",  my default_pitch_floor())
@@ -1015,7 +1054,7 @@ static void menu_cb_pitchSettings (SoundAnalysisArea me, EDITOR_ARGS) {
 		} else {
 			SET_STRING (note2, U"(your “time step strategy” has its standard value: automatic)")
 		}
-	EDITOR_DO
+	EDITOR_DO_ALTERNATIVE (menu_cb_pitchSettings_BEFORE_6400)
 		Melder_require (pitchCeiling > pitchFloor,
 			U"The pitch ceiling has to be greater than the pitch floor, so they cannot be ",
 			pitchCeiling, U" and ", pitchFloor, U" ", kPitch_unit_getText (unit), U", respectively."
@@ -1034,14 +1073,56 @@ static void menu_cb_pitchSettings (SoundAnalysisArea me, EDITOR_ARGS) {
 	EDITOR_END
 }
 
+static void menu_cb_advancedPitchSettings (SoundAnalysisArea me, EDITOR_ARGS) {   // COMPATIBILITY < 6400
+	EDITOR_FORM (U"Advanced pitch settings", U"Advanced pitch settings...")
+		LABEL   (U"YOU SHOULD NEVER SEE THIS OBSOLETE SETTINGS WINDOW;")
+		LABEL   (U"IT IS HERE ONLY FOR COMPATIBILITY WITH OLD SCRIPTS.")
+		REAL    (viewFrom,                  U"left View range (units)",   my default_pitch_viewFrom                  ())
+		REAL    (viewTo,                    U"right View range (units)",  my default_pitch_viewTo                    ())
+		BOOLEAN (veryAccurate,              U"Very accurate",             false)
+		NATURAL (maximumNumberOfCandidates, U"Max. number of candidates", my default_pitch_rawAcCc_maximumNumberOfCandidates ())
+		REAL    (silenceThreshold,          U"Silence threshold",         my default_pitch_rawAcCc_silenceThreshold          ())
+		REAL    (voicingThreshold,          U"Voicing threshold",         my default_pitch_rawAcCc_voicingThreshold          ())
+		REAL    (octaveCost,                U"Octave cost",               my default_pitch_rawAcCc_octaveCost                ())
+		REAL    (octaveJumpCost,            U"Octave-jump cost",          my default_pitch_rawAcCc_octaveJumpCost            ())
+		REAL    (voicedUnvoicedCost,        U"Voiced / unvoiced cost",    my default_pitch_rawAcCc_voicedUnvoicedCost        ())
+	EDITOR_OK
+		SET_REAL    (viewFrom,                  my instancePref_pitch_viewFrom())
+		SET_REAL    (viewTo,                    my instancePref_pitch_viewTo())
+		SET_BOOLEAN (veryAccurate,              my instancePref_pitch_rawAcCc_veryAccurate())
+		SET_INTEGER (maximumNumberOfCandidates, my instancePref_pitch_rawAcCc_maximumNumberOfCandidates())
+		SET_REAL    (silenceThreshold,          my instancePref_pitch_rawAcCc_silenceThreshold())
+		SET_REAL    (voicingThreshold,          my instancePref_pitch_rawAcCc_voicingThreshold())
+		SET_REAL    (octaveCost,                my instancePref_pitch_rawAcCc_octaveCost())
+		SET_REAL    (octaveJumpCost,            my instancePref_pitch_rawAcCc_octaveJumpCost())
+		SET_REAL    (voicedUnvoicedCost,        my instancePref_pitch_rawAcCc_voicedUnvoicedCost())
+	EDITOR_DO
+		if (maximumNumberOfCandidates < 2)
+			Melder_throw (U"Your maximum number of candidates should be greater than 1.");
+		my setInstancePref_pitch_viewFrom (viewFrom);
+		my setInstancePref_pitch_viewTo (viewTo);
+		my setInstancePref_pitch_rawAcCc_veryAccurate (veryAccurate);
+		my setInstancePref_pitch_rawAcCc_maximumNumberOfCandidates (maximumNumberOfCandidates);
+		my setInstancePref_pitch_rawAcCc_silenceThreshold (silenceThreshold);
+		my setInstancePref_pitch_rawAcCc_voicingThreshold (voicingThreshold);
+		my setInstancePref_pitch_rawAcCc_octaveCost (octaveCost);
+		my setInstancePref_pitch_rawAcCc_octaveJumpCost (octaveJumpCost);
+		my setInstancePref_pitch_rawAcCc_voicedUnvoicedCost (voicedUnvoicedCost);
+		my d_pitch.     reset();
+		my d_intensity. reset();
+		my d_pulses.    reset();
+		FunctionEditor_redraw (my functionEditor());
+	EDITOR_END
+}
+
 static void menu_cb_advancedPitchSettings_rawAcCc (SoundAnalysisArea me, EDITOR_ARGS) {
 	EDITOR_FORM (U"Advanced pitch settings (raw AC and CC)", U"Advanced pitch settings (raw AC and CC)...")
 		LABEL   (U"Settings for the RAW autocorrelation and cross-correlation methods only.")
 		LABEL   (U"")
-		LABEL (U"Finding the candidates")
+		LABEL (U"Finding the candidates...")
 		NATURAL (maximumNumberOfCandidates, U"Max. number of candidates", my default_pitch_rawAcCc_maximumNumberOfCandidates ())
 		BOOLEAN (veryAccurate,              U"Very accurate", false)
-		LABEL (U"Finding a path")
+		LABEL (U"Finding a path...")
 		REAL    (silenceThreshold,          U"Silence threshold",         my default_pitch_rawAcCc_silenceThreshold          ())
 		REAL    (voicingThreshold,          U"Voicing threshold",         my default_pitch_rawAcCc_voicingThreshold          ())
 		REAL    (octaveCost,                U"Octave cost",               my default_pitch_rawAcCc_octaveCost                ())
@@ -1076,12 +1157,12 @@ static void menu_cb_advancedPitchSettings_filteredAcCc (SoundAnalysisArea me, ED
 	EDITOR_FORM (U"Advanced pitch settings (filtered AC and CC)", U"Advanced pitch settings (filtered AC and CC)...")
 		LABEL    (U"Settings for the FILTERED autocorrelation and cross-correlation methods only.")
 		LABEL    (U"")
-		LABEL (U"Finding the candidates")
+		LABEL (U"Finding the candidates...")
 		NATURAL  (maximumNumberOfCandidates, U"Max. number of candidates", my default_pitch_filteredAcCc_maximumNumberOfCandidates ())
 		BOOLEAN  (veryAccurate,              U"Very accurate", false)
-		LABEL (U"Preprocessing")
+		LABEL (U"Preprocessing...")
 		POSITIVE (attenuationAtCeiling,      U"Attenuation at ceiling",    my default_pitch_filteredAcCc_attenuationAtCeiling      ())
-		LABEL (U"Finding a path")
+		LABEL (U"Finding a path...")
 		REAL     (silenceThreshold,          U"Silence threshold",         my default_pitch_filteredAcCc_silenceThreshold          ())
 		REAL     (voicingThreshold,          U"Voicing threshold",         my default_pitch_filteredAcCc_voicingThreshold          ())
 		REAL     (octaveCost,                U"Octave cost",               my default_pitch_filteredAcCc_octaveCost                ())
@@ -1827,6 +1908,8 @@ void structSoundAnalysisArea :: v_createMenus () {
 		);
 		FunctionAreaMenu_addCommand (menu, U"Pitch settings...", 0,
 				menu_cb_pitchSettings, this);
+		FunctionAreaMenu_addCommand (menu, U"Advanced pitch settings...", GuiMenu_HIDDEN,
+				menu_cb_advancedPitchSettings, this);
 		FunctionAreaMenu_addCommand (menu, U"Advanced pitch settings (filtered AC and CC)...", 0,
 				menu_cb_advancedPitchSettings_filteredAcCc, this);
 		FunctionAreaMenu_addCommand (menu, U"Advanced pitch settings (raw AC and CC)...", 0,


=====================================
foned/SoundAnalysisArea_enums.h
=====================================
@@ -32,7 +32,9 @@ enums_end (kSoundAnalysisArea_pitch_drawingMethod, 3, AUTOMATIC)
 enums_begin (kSoundAnalysisArea_pitch_analysisMethod, 1)
 	enums_add (kSoundAnalysisArea_pitch_analysisMethod, 1, FILTERED_AUTOCORRELATION, U"filtered autocorrelation")
 	enums_add (kSoundAnalysisArea_pitch_analysisMethod, 2, RAW_CROSS_CORRELATION, U"raw cross-correlation")
+	enums_alt (kSoundAnalysisArea_pitch_analysisMethod,    RAW_CROSS_CORRELATION, U"cross-correlation")   // COMPATIBILITY < 6400
 	enums_add (kSoundAnalysisArea_pitch_analysisMethod, 3, RAW_AUTOCORRELATION, U"raw autocorrelation")
+	enums_alt (kSoundAnalysisArea_pitch_analysisMethod,    RAW_AUTOCORRELATION, U"autocorrelation")   // COMPATIBILITY < 6400
 	enums_add (kSoundAnalysisArea_pitch_analysisMethod, 4, FILTERED_CROSS_CORRELATION, U"filtered cross-correlation")
 enums_end (kSoundAnalysisArea_pitch_analysisMethod, 4, FILTERED_AUTOCORRELATION)
 


=====================================
sys/EditorM.h
=====================================
@@ -46,6 +46,37 @@ _form_inited_: \
 		UiForm_parseStringE (cmd, _narg_, _args_, _sendingString_, optionalInterpreter); \
 	} else {
 
+#define EDITOR_DO_ALTERNATIVE(alternative)  \
+		UiForm_do (cmd -> d_uiform.get(), false); \
+	} else if (! _sendingForm_) { \
+		try { \
+			UiForm_parseStringE (cmd, _narg_, _args_, _sendingString_, optionalInterpreter); \
+		} catch (MelderError) { \
+			if (Melder_hasCrash ()) \
+				throw; \
+			autostring32 _parkedError = Melder_dup_f (Melder_getError ()); \
+			Melder_clearError (); \
+			try { \
+				static autoEditorCommand _alternativeCmd; \
+				if (! _alternativeCmd) \
+					_alternativeCmd = Thing_new (EditorCommand); \
+				_alternativeCmd -> d_editor = cmd -> d_editor; \
+				_alternativeCmd -> sender = cmd -> sender; \
+				_alternativeCmd -> menu = cmd -> menu; \
+				_alternativeCmd -> itemTitle = Melder_dup (cmd -> itemTitle.get()); \
+				_alternativeCmd -> itemWidget = nullptr; \
+				_alternativeCmd -> commandCallback = cmd -> commandCallback; \
+				_alternativeCmd -> script = Melder_dup (cmd -> script.get()); \
+				_alternativeCmd -> d_uiform = autoUiForm (); \
+				alternative (me, _alternativeCmd.get(), _sendingForm_, _narg_, _args_, _sendingString_, optionalInterpreter); \
+			} catch (MelderError) { \
+				Melder_clearError (); \
+				Melder_appendError (_parkedError.get()); \
+				throw; \
+			} \
+		} \
+	} else {
+
 #define EDITOR_END  \
 	}
 
@@ -301,8 +332,10 @@ _form_inited_: \
 		[[maybe_unused]] enum EnumeratedType _compilerTypeCheckDummy = defaultValue; \
 		_compilerTypeCheckDummy = enumeratedVariable; \
 	} \
-	UiForm_addChoice (cmd -> d_uiform.get(), (int *) & enumeratedVariable, nullptr, nullptr, labelText, \
-			(int) defaultValue - (int) EnumeratedType::MIN + 1, (int) EnumeratedType::MIN); \
+	UiForm_addChoiceEnum (cmd -> d_uiform.get(), (int *) & enumeratedVariable, nullptr, nullptr, labelText, \
+		(int) defaultValue - (int) EnumeratedType::MIN + 1, (int) EnumeratedType::MIN, \
+		(enum_generic_getValue) EnumeratedType##_getValue \
+	); \
 	for (int _ienum = (int) EnumeratedType::MIN; _ienum <= (int) EnumeratedType::MAX; _ienum ++) \
 		UiForm_addOption (cmd -> d_uiform.get(), EnumeratedType##_getText ((enum EnumeratedType) _ienum)); \
 
@@ -319,8 +352,10 @@ _form_inited_: \
 		[[maybe_unused]] enum EnumeratedType _compilerTypeCheckDummy = defaultValue; \
 		_compilerTypeCheckDummy = enumeratedVariable; \
 	} \
-	UiForm_addOptionMenu (cmd -> d_uiform.get(), (int *) & enumeratedVariable, nullptr, nullptr, labelText, \
-			(int) defaultValue - (int) EnumeratedType::MIN + 1, (int) EnumeratedType::MIN); \
+	UiForm_addOptionMenuEnum (cmd -> d_uiform.get(), (int *) & enumeratedVariable, nullptr, nullptr, labelText, \
+		(int) defaultValue - (int) EnumeratedType::MIN + 1, (int) EnumeratedType::MIN, \
+		(enum_generic_getValue) EnumeratedType##_getValue \
+	); \
 	for (int _ienum = (int) EnumeratedType::MIN; _ienum <= (int) EnumeratedType::MAX; _ienum ++) \
 		UiForm_addOption (cmd -> d_uiform.get(), EnumeratedType##_getText ((enum EnumeratedType) _ienum)); \
 


=====================================
sys/Ui.cpp
=====================================
@@ -934,7 +934,9 @@ static UiField UiForm_addField (UiForm me, _kUiField_type type, conststring32 la
 	return my field [my numberOfFields].get();
 }
 
-UiField UiForm_addReal (UiForm me, double *variable, conststring32 variableName, conststring32 labelText, conststring32 defaultValue) {
+UiField UiForm_addReal (UiForm me, double *variable, conststring32 variableName,
+	conststring32 labelText, conststring32 defaultValue)
+{
 	UiField thee = UiForm_addField (me, _kUiField_type::REAL_, labelText);
 	my referenceToLatestUsedChoiceOrOptionMenu = nullptr;
 	thy stringDefaultValue = Melder_dup (defaultValue);
@@ -943,7 +945,9 @@ UiField UiForm_addReal (UiForm me, double *variable, conststring32 variableName,
 	return thee;
 }
 
-UiField UiForm_addRealOrUndefined (UiForm me, double *variable, conststring32 variableName, conststring32 labelText, conststring32 defaultValue) {
+UiField UiForm_addRealOrUndefined (UiForm me, double *variable, conststring32 variableName,
+	conststring32 labelText, conststring32 defaultValue)
+{
 	UiField thee = UiForm_addField (me, _kUiField_type::REAL_OR_UNDEFINED_, labelText);
 	my referenceToLatestUsedChoiceOrOptionMenu = nullptr;
 	thy stringDefaultValue = Melder_dup (defaultValue);
@@ -952,7 +956,9 @@ UiField UiForm_addRealOrUndefined (UiForm me, double *variable, conststring32 va
 	return thee;
 }
 
-UiField UiForm_addPositive (UiForm me, double *variable, conststring32 variableName, conststring32 labelText, conststring32 defaultValue) {
+UiField UiForm_addPositive (UiForm me, double *variable, conststring32 variableName,
+	conststring32 labelText, conststring32 defaultValue)
+{
 	UiField thee = UiForm_addField (me, _kUiField_type::POSITIVE_, labelText);
 	my referenceToLatestUsedChoiceOrOptionMenu = nullptr;
 	thy stringDefaultValue = Melder_dup (defaultValue);
@@ -961,7 +967,9 @@ UiField UiForm_addPositive (UiForm me, double *variable, conststring32 variableN
 	return thee;
 }
 
-UiField UiForm_addInteger (UiForm me, integer *variable, conststring32 variableName, conststring32 labelText, conststring32 defaultValue) {
+UiField UiForm_addInteger (UiForm me, integer *variable, conststring32 variableName,
+	conststring32 labelText, conststring32 defaultValue)
+{
 	UiField thee = UiForm_addField (me, _kUiField_type::INTEGER_, labelText);
 	my referenceToLatestUsedChoiceOrOptionMenu = nullptr;
 	thy stringDefaultValue = Melder_dup (defaultValue);
@@ -970,7 +978,9 @@ UiField UiForm_addInteger (UiForm me, integer *variable, conststring32 variableN
 	return thee;
 }
 
-UiField UiForm_addNatural (UiForm me, integer *variable, conststring32 variableName, conststring32 labelText, conststring32 defaultValue) {
+UiField UiForm_addNatural (UiForm me, integer *variable, conststring32 variableName,
+	conststring32 labelText, conststring32 defaultValue)
+{
 	UiField thee = UiForm_addField (me, _kUiField_type::NATURAL_, labelText);
 	my referenceToLatestUsedChoiceOrOptionMenu = nullptr;
 	thy stringDefaultValue = Melder_dup (defaultValue);
@@ -979,7 +989,9 @@ UiField UiForm_addNatural (UiForm me, integer *variable, conststring32 variableN
 	return thee;
 }
 
-UiField UiForm_addWord (UiForm me, conststring32 *variable, conststring32 variableName, conststring32 labelText, conststring32 defaultValue) {
+UiField UiForm_addWord (UiForm me, conststring32 *variable, conststring32 variableName,
+	conststring32 labelText, conststring32 defaultValue)
+{
 	UiField thee = UiForm_addField (me, _kUiField_type::WORD_, labelText);
 	my referenceToLatestUsedChoiceOrOptionMenu = nullptr;
 	thy stringDefaultValue = Melder_dup (defaultValue);
@@ -988,7 +1000,9 @@ UiField UiForm_addWord (UiForm me, conststring32 *variable, conststring32 variab
 	return thee;
 }
 
-UiField UiForm_addSentence (UiForm me, conststring32 *variable, conststring32 variableName, conststring32 labelText, conststring32 defaultValue) {
+UiField UiForm_addSentence (UiForm me, conststring32 *variable, conststring32 variableName,
+	conststring32 labelText, conststring32 defaultValue)
+{
 	UiField thee = UiForm_addField (me, _kUiField_type::SENTENCE_, labelText);
 	my referenceToLatestUsedChoiceOrOptionMenu = nullptr;
 	thy stringDefaultValue = Melder_dup (defaultValue);
@@ -1005,7 +1019,9 @@ UiField UiForm_addLabel (UiForm me, conststring32 *variable, conststring32 label
 	return thee;
 }
 
-UiField UiForm_addBoolean (UiForm me, bool *variable, conststring32 variableName, conststring32 labelText, bool defaultValue) {
+UiField UiForm_addBoolean (UiForm me, bool *variable, conststring32 variableName,
+	conststring32 labelText, bool defaultValue)
+{
 	UiField thee = UiForm_addField (me, _kUiField_type::BOOLEAN_, labelText);
 	my referenceToLatestUsedChoiceOrOptionMenu = nullptr;
 	thy integerDefaultValue = defaultValue;
@@ -1151,7 +1167,22 @@ UiField UiForm_addStringArray (UiForm me, constSTRVEC *variable, conststring32 v
 	return thee;
 }
 
-UiField UiForm_addChoice (UiForm me, int *intVariable, conststring32 *stringVariable, conststring32 variableName, conststring32 labelText, int defaultValue, int base) {
+UiField UiForm_addChoice (UiForm me, int *intVariable, conststring32 *stringVariable, conststring32 variableName,
+	conststring32 labelText, int defaultValue, int base)
+{
+	UiField thee = UiForm_addField (me, _kUiField_type::CHOICE_, labelText);
+	my referenceToLatestUsedChoiceOrOptionMenu = thee;
+	thy integerDefaultValue = defaultValue;
+	thy intVariable = intVariable;
+	thy stringVariable = stringVariable;
+	thy variableName = variableName;
+	thy subtract = ( base == 1 ? 0 : 1 );
+	return thee;
+}
+
+UiField UiForm_addChoiceEnum (UiForm me, int *intVariable, conststring32 *stringVariable, conststring32 variableName,
+	conststring32 labelText, int defaultValue, int base, enum_generic_getValue getValueFunction)
+{
 	UiField thee = UiForm_addField (me, _kUiField_type::CHOICE_, labelText);
 	my referenceToLatestUsedChoiceOrOptionMenu = thee;
 	thy integerDefaultValue = defaultValue;
@@ -1159,10 +1190,13 @@ UiField UiForm_addChoice (UiForm me, int *intVariable, conststring32 *stringVari
 	thy stringVariable = stringVariable;
 	thy variableName = variableName;
 	thy subtract = ( base == 1 ? 0 : 1 );
+	thy getValueFunction = getValueFunction;
 	return thee;
 }
 
-UiField UiForm_addOptionMenu (UiForm me, int *intVariable, conststring32 *stringVariable, conststring32 variableName, conststring32 labelText, int defaultValue, int base) {
+UiField UiForm_addOptionMenu (UiForm me, int *intVariable, conststring32 *stringVariable, conststring32 variableName,
+	conststring32 labelText, int defaultValue, int base)
+{
 	UiField thee = UiForm_addField (me, _kUiField_type::OPTIONMENU_, labelText);
 	my referenceToLatestUsedChoiceOrOptionMenu = thee;
 	thy integerDefaultValue = defaultValue;
@@ -1173,7 +1207,23 @@ UiField UiForm_addOptionMenu (UiForm me, int *intVariable, conststring32 *string
 	return thee;
 }
 
-UiField UiForm_addList (UiForm me, integer *integerVariable, conststring32 *stringVariable, conststring32 variableName, conststring32 labelText, constSTRVEC strings, integer defaultValue) {
+UiField UiForm_addOptionMenuEnum (UiForm me, int *intVariable, conststring32 *stringVariable, conststring32 variableName,
+	conststring32 labelText, int defaultValue, int base, enum_generic_getValue getValueFunction)
+{
+	UiField thee = UiForm_addField (me, _kUiField_type::OPTIONMENU_, labelText);
+	my referenceToLatestUsedChoiceOrOptionMenu = thee;
+	thy integerDefaultValue = defaultValue;
+	thy intVariable = intVariable;
+	thy stringVariable = stringVariable;
+	thy variableName = variableName;
+	thy subtract = ( base == 1 ? 0 : 1 );
+	thy getValueFunction = getValueFunction;
+	return thee;
+}
+
+UiField UiForm_addList (UiForm me, integer *integerVariable, conststring32 *stringVariable, conststring32 variableName,
+	conststring32 labelText, constSTRVEC strings, integer defaultValue)
+{
 	UiField thee = UiForm_addField (me, _kUiField_type::LIST_, labelText);
 	my referenceToLatestUsedChoiceOrOptionMenu = nullptr;
 	thy strings = strings;
@@ -1184,7 +1234,9 @@ UiField UiForm_addList (UiForm me, integer *integerVariable, conststring32 *stri
 	return thee;
 }
 
-UiField UiForm_addColour (UiForm me, MelderColour *colourVariable, conststring32 variableName, conststring32 labelText, conststring32 defaultValue) {
+UiField UiForm_addColour (UiForm me, MelderColour *colourVariable, conststring32 variableName,
+	conststring32 labelText, conststring32 defaultValue)
+{
 	UiField thee = UiForm_addField (me, _kUiField_type::COLOUR_, labelText);
 	my referenceToLatestUsedChoiceOrOptionMenu = nullptr;
 	thy stringDefaultValue = Melder_dup (defaultValue);
@@ -1193,7 +1245,9 @@ UiField UiForm_addColour (UiForm me, MelderColour *colourVariable, conststring32
 	return thee;
 }
 
-UiField UiForm_addChannel (UiForm me, integer *variable, conststring32 variableName, conststring32 labelText, conststring32 defaultValue) {
+UiField UiForm_addChannel (UiForm me, integer *variable, conststring32 variableName,
+	conststring32 labelText, conststring32 defaultValue)
+{
 	UiField thee = UiForm_addField (me, _kUiField_type::CHANNEL_, labelText);
 	my referenceToLatestUsedChoiceOrOptionMenu = nullptr;
 	thy stringDefaultValue = Melder_dup (defaultValue);
@@ -2034,21 +2088,25 @@ static void UiField_argToValue (UiField me, Stackel arg, Interpreter /* interpre
 		{
 			if (arg -> which != Stackel_STRING)
 				Melder_throw (U"Option argument “", my name.get(), U"” should be a string, not ", arg -> whichText(), U".");
-			my integerValue = 0;
-			for (int i = 1; i <= my options.size; i ++) {
-				UiOption b = my options.at [i];
-				if (str32equ (arg -> getString(), b -> name.get()))
-					my integerValue = i;
-			}
-			if (my integerValue == 0) {
-				/*
-					Retry with different case.
-				*/
+			if (my getValueFunction) {
+				my integerValue = my getValueFunction (arg -> getString()) + my subtract;
+			} else {
+				my integerValue = 0;
 				for (int i = 1; i <= my options.size; i ++) {
 					UiOption b = my options.at [i];
-					if (Melder_equ_firstCharacterCaseInsensitive (arg -> getString(), b -> name.get()))
+					if (str32equ (arg -> getString(), b -> name.get()))
 						my integerValue = i;
 				}
+				if (my integerValue == 0) {
+					/*
+						Retry with different case.
+					*/
+					for (int i = 1; i <= my options.size; i ++) {
+						UiOption b = my options.at [i];
+						if (Melder_equ_firstCharacterCaseInsensitive (arg -> getString(), b -> name.get()))
+							my integerValue = i;
+					}
+				}
 			}
 			if (my integerValue == 0) {
 				if (my intVariable)
@@ -2229,21 +2287,25 @@ static void UiField_stringToValue (UiField me, conststring32 string, Interpreter
 		case _kUiField_type::CHOICE_:
 		case _kUiField_type::OPTIONMENU_:
 		{
-			my integerValue = 0;
-			for (int i = 1; i <= my options.size; i ++) {
-				UiOption b = my options.at [i];
-				if (str32equ (string, b -> name.get()))
-					my integerValue = i;
-			}
-			if (my integerValue == 0) {
-				/*
-					Retry with different case.
-				*/
+			if (my getValueFunction) {
+				my integerValue = my getValueFunction (string) + my subtract;
+			} else {
+				my integerValue = 0;
 				for (int i = 1; i <= my options.size; i ++) {
 					UiOption b = my options.at [i];
-					if (Melder_equ_firstCharacterCaseInsensitive (string, b -> name.get()))
+					if (str32equ (string, b -> name.get()))
 						my integerValue = i;
 				}
+				if (my integerValue == 0) {
+					/*
+						Retry with different case.
+					*/
+					for (int i = 1; i <= my options.size; i ++) {
+						UiOption b = my options.at [i];
+						if (Melder_equ_firstCharacterCaseInsensitive (string, b -> name.get()))
+							my integerValue = i;
+					}
+				}
 			}
 			if (my integerValue == 0)
 				Melder_throw (U"Field “", my name.get(), U"” must not have the value “", string, U"”.");


=====================================
sys/Ui.h
=====================================
@@ -134,6 +134,7 @@ Thing_define (UiField, Thing) {
 	GuiRadioButton radioButton;   // for CHOICE_
 	GuiList list;
 	GuiOptionMenu optionMenu;
+	enum_generic_getValue getValueFunction;
 	GuiButton pushButton;   // like "Browse..." for INFILE_, OUTFILE_, FOLDER_ (2021-03-30)
 	int y;
 
@@ -244,8 +245,12 @@ UiField UiForm_addStringArray (UiForm me, constSTRVEC *variable, conststring32 v
 		conststring32 labelText, constSTRVEC defaultValue, integer numberOfLines = 7);
 UiField UiForm_addChoice (UiForm me, int *intVariable, conststring32 *stringVariable, conststring32 variableName,
 		conststring32 labelText, int defaultValue, int base);
+UiField UiForm_addChoiceEnum (UiForm me, int *intVariable, conststring32 *stringVariable, conststring32 variableName,
+		conststring32 labelText, int defaultValue, int base, enum_generic_getValue getValueFunction);
 UiField UiForm_addOptionMenu (UiForm me, int *intVariable, conststring32 *stringVariable, conststring32 variableName,
 		conststring32 labelText, int defaultValue, int base);
+UiField UiForm_addOptionMenuEnum (UiForm me, int *intVariable, conststring32 *stringVariable, conststring32 variableName,
+		conststring32 labelText, int defaultValue, int base, enum_generic_getValue getValueFunction);
 UiOption UiForm_addOption (UiForm me, conststring32 optionText);
 UiField UiForm_addList (UiForm me, integer *integerVariable, conststring32 *stringVariable, conststring32 variableName,
 		conststring32 labelText, constSTRVEC strings, integer defaultValue);


=====================================
sys/praatM.h
=====================================
@@ -225,8 +225,10 @@
 			[[maybe_unused]] enum EnumeratedType _compilerTypeCheckDummy = defaultValue; \
 			_compilerTypeCheckDummy = enumeratedVariable; \
 		} \
-		UiForm_addChoice (_dia_.get(), (int *) & enumeratedVariable, nullptr, U"" #enumeratedVariable, \
-				labelText, (int) defaultValue - (int) EnumeratedType::MIN + 1, (int) EnumeratedType::MIN); \
+		UiForm_addChoiceEnum (_dia_.get(), (int *) & enumeratedVariable, nullptr, U"" #enumeratedVariable, \
+			labelText, (int) defaultValue - (int) EnumeratedType::MIN + 1, (int) EnumeratedType::MIN, \
+			(enum_generic_getValue) EnumeratedType##_getValue \
+		); \
 		for (int ienum = (int) EnumeratedType::MIN; ienum <= (int) EnumeratedType::MAX; ienum ++) \
 			UiForm_addOption (_dia_.get(), EnumeratedType##_getText ((enum EnumeratedType) ienum));
 
@@ -236,8 +238,10 @@
 			[[maybe_unused]] enum EnumeratedType _compilerTypeCheckDummy = defaultValue; \
 			_compilerTypeCheckDummy = enumeratedVariable; \
 		} \
-		UiForm_addOptionMenu (_dia_.get(), (int *) & enumeratedVariable, nullptr, U"" #enumeratedVariable, \
-				labelText, (int) defaultValue - (int) EnumeratedType::MIN + 1, (int) EnumeratedType::MIN); \
+		UiForm_addOptionMenuEnum (_dia_.get(), (int *) & enumeratedVariable, nullptr, U"" #enumeratedVariable, \
+			labelText, (int) defaultValue - (int) EnumeratedType::MIN + 1, (int) EnumeratedType::MIN, \
+			(enum_generic_getValue) EnumeratedType##_getValue \
+		); \
 		for (int ienum = (int) EnumeratedType::MIN; ienum <= (int) EnumeratedType::MAX; ienum ++) \
 			UiForm_addOption (_dia_.get(), EnumeratedType##_getText ((enum EnumeratedType) ienum));
 
@@ -247,8 +251,10 @@
 			[[maybe_unused]] enum EnumeratedType _compilerTypeCheckDummy = defaultValue; \
 			_compilerTypeCheckDummy = enumeratedVariable; \
 		} \
-		UiForm_addOptionMenu (_dia_.get(), nullptr, & enumeratedVariableAsString, U"" #enumeratedVariableAsString, \
-				labelText, (int) defaultValue - (int) EnumeratedType::MIN + 1, (int) EnumeratedType::MIN); \
+		UiForm_addOptionMenuEnum (_dia_.get(), nullptr, & enumeratedVariableAsString, U"" #enumeratedVariableAsString, \
+			labelText, (int) defaultValue - (int) EnumeratedType::MIN + 1, (int) EnumeratedType::MIN, \
+			(enum_generic_getValue) EnumeratedType##_getValue \
+		); \
 		for (int ienum = (int) EnumeratedType::MIN; ienum <= (int) EnumeratedType::MAX; ienum ++) \
 			UiForm_addOption (_dia_.get(), EnumeratedType##_getText ((enum EnumeratedType) ienum));
 


=====================================
sys/praat_version.h
=====================================
@@ -1,5 +1,5 @@
-#define PRAAT_VERSION_STR 6.4
+#define PRAAT_VERSION_STR 6.4.01
 #define PRAAT_VERSION_NUM 6400
 #define PRAAT_YEAR 2023
 #define PRAAT_MONTH November
-#define PRAAT_DAY 15
+#define PRAAT_DAY 30



View it on GitLab: https://salsa.debian.org/med-team/praat/-/compare/2d7c80e0bcdc814e79a914d7c9ca8f5eed0d7142...9bed39b049e013710a25609db5073d17bc0c74d7

-- 
View it on GitLab: https://salsa.debian.org/med-team/praat/-/compare/2d7c80e0bcdc814e79a914d7c9ca8f5eed0d7142...9bed39b049e013710a25609db5073d17bc0c74d7
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/20231203/3438096a/attachment-0001.htm>


More information about the debian-med-commit mailing list