FormantPath Queries

41 views
Skip to first unread message

Ethelyn Huang

unread,
Jul 22, 2025, 4:12:03 PMJul 22
to Parselmouth
Hi Yannick,

Thanks for all your work! Parselmouth has been really useful for me in my workflow.

I'm currently trying to leverage Praat's ability to extract the FormantPath from a sound file, and then query the optimal ceiling from the Formant Path. I am aware Parselmouth does not have built-in support for FormantPaths, but it is able to make certain commands like 'Extract Formant' through the 'call' command, yet it doesn't seem to be able to make queries. Is there an existing workaround for this?


Anirudh Thommandram

unread,
Jul 22, 2025, 4:56:16 PMJul 22
to Parselmouth
Hi Ethelyn,
Not sure what you mean by not being able to make queries part. I think it ends up just being another "call" command. Like for example, if I wanted to get the mean intensity of a sound i would first call the To Intensity command (https://www.fon.hum.uva.nl/praat/manual/Sound__To_Intensity___.html) and then call the Get mean query (https://www.fon.hum.uva.nl/praat/manual/Intensity__Get_mean___.html):

# Intensity
intensity = call(sound, "To Intensity", 75, 0.0)  # create a praat Intensity object
meanIntensity = call(intensity, "Get mean", 0, 0)  # get mean intensity

In your case, I think this would just be the call to create the FormantPath object, and then the call to the query that does the Down To Table (optimal interval) probably - sorry I'm not actually sure of the specific praat commands relevant to your task. But I think you should be able to convert all the Praat steps into parselmouth.praat.call commands

Ani

Ethelyn Huang

unread,
Jul 22, 2025, 5:16:55 PMJul 22
to Parselmouth
Hi Ani,

I had the same thing in mind. However, my code snippet here throws the error "Command "Get optimal ceiling" not available for given objects". Maybe I'm structuring the query incorrectly? 

snd = parselmouth.Sound(audio_path)
formant_path = call(snd, "To FormantPath...", *fpathparams.values())
opt_ceiling = call(formant_path, "Get optimal ceiling", 0.0, 0.0, [3, 3, 3], 1.25)

Thanks!
Ethelyn

Anirudh Thommandram

unread,
Jul 22, 2025, 5:40:03 PMJul 22
to Parselmouth
Oh I see what you mean. Hmmm I'm not sure "Get optimal ceiling" is a valid Praat query - curious where you found this command. Looking at the Praat docs, my best guess to how you can get the optimal ceiling is maybe first call the "Down to Table (optimal interval)" command (which returns a Table object), and then read the first row's ceiling value. Something like:

optimal_table = call(formant_path, "Down to Table (optimal interval)")
optimal_ceiling = call(optimal_table, "Get value", 1, "Ceiling")

I'm kiiind of just thinking out loud here, haven't actually ran any of these lines so I could for sure be wrong haha

Ani

Ethelyn Huang

unread,
Jul 22, 2025, 6:16:15 PMJul 22
to Parselmouth
Hi Ani,

"Get optimal ceiling" is an option in the Praat GUI, and it does seem to give me a reasonable value. I have actually tried the table command you mentioned, and it still gives me a similar error "Command "Down to Table (optimal interval)" not available for given objects."

Thanks a lot for your input though, I appreciate it!
Screenshot 2025-07-22 at 5.12.52 PM.png

yannick...@gmail.com

unread,
Jul 22, 2025, 6:44:39 PMJul 22
to Parselmouth
Hi both!

Thanks for the kind words and question, Ethelyn!
And thanks for the help, Ani! Exactly the sort of kind community I hope Parselmouth will gather over time :-)

To answer the issue: I don't know for sure and I'll have a closer look tomorrow!
But two things to keep in mind, which might already help:
1) In case of things like this, do check with the actual version of Praat that's included with Parselmouth. For now, Parselmouth 0.4.5 is based on Praat 6.1.38 (see `parselmouth.PRAAT_VERSION`). I'm working on a newer version, but in the meanwhile you'll either have to use the old Praat functionality that's present in 6.1.38, or get the latest development version of Parselmouth (which hasn't been tested as thoroughly yet).
2) Make sure that the command you call are in the main "Object window". Currently, the exact commands from the "View & Edit" aren't available (since Parselmouth doesn't enable the whole interactive GUI part of Praat). However, for now, I've found basically all of these commands in the "View & Edit" window accessible in the main "Praat objects" window, so you might be able to find the corresponding command?

Do let me know if you find something more! If not, I'll have a look myself tomorrow.

Cheers
Yannick

Anirudh Thommandram

unread,
Jul 23, 2025, 8:55:33 AMJul 23
to Parselmouth
Ah, I think we're onto something. I installed both versions 6.1.16 and 6.3.09 and the commands available in the main Object window for a FormantPath object are indeed different! For what it's worth I did confirm that the "Get optimal ceiling" button is essentially doing the same thing as the down to table (optimal interval) and Get value combo - not that it helps our current situation right now haha
Maybe its possible to play around the 6.1.16 GUI to see if there is another path of commands to do this analysis...

Ani
praat_6309_downToTable.png
praat_6116.png
praat_6309_getOptimalCeiling.png
praat_6309.png

yannick...@gmail.com

unread,
Jul 23, 2025, 7:40:49 PMJul 23
to Parselmouth
Good catch, Ani!
It does seem like Praat indeed added a bunch of FormantPath functionality since then...

I did manage to do this, but since I haven't really worked with FormantPaths myself, I'm not 100% sure what the numbers mean and how exactly to go from this matrix to a single stress value per candidate:

```
>>> import parselmouth
>>> from parselmouth.praat import call
>>> parselmouth.__version__
'0.4.6'
>>> parselmouth.PRAAT_VERSION
'6.1.38'
>>> sound = parselmouth.Sound("the_north_wind_and_the_sun.wav")
>>> formant_path = call(sound, "To FormantPath (burg)", 0.005, 5, 5500, 0.025, 50, 0.05, 4)
>>> formant_path_stresses_matrix = call(formant_path, "To Matrix (stress)", 0.025, "3 3 3", 1.25)
>>> formant_path_stresses_matrix
<parselmouth.Matrix object at 0x7fc6a1b05770>
>>> formant_path_stresses_matrix_np = call(formant_path, "To Matrix (stress)", 0.025, "3 3 3", 1.25).values
>>> formant_path_stresses_matrix_np
array([[          nan, 1634.81242793,  447.10077754, ...,   86.44609807,
         372.37636892,           nan],
       [          nan, 1920.62221904,  604.63955535, ...,   87.05854912,
         305.2462656 ,           nan],
       [          nan,  468.83203277,  262.31071455, ...,   75.06313702,
         227.41453831,           nan],
       ...,
       [          nan, 2981.37522676, 1382.49097372, ...,   32.95922791,
          78.37265058,           nan],
       [          nan, 1997.98323388,  796.29181513, ...,   22.92870824,
          55.30490867,           nan],
       [          nan, 1034.23910621,  601.91152071, ..., 1309.39011679,
          48.83513104,           nan]])

```

Ethelyn Huang

unread,
Jul 24, 2025, 12:40:28 AMJul 24
to Parselmouth
Hi Ani and Yannick,

Thanks a lot for your input! The stress matrix looks promising, I'll look into it and see if I can find a workaround :)

Anirudh Thommandram

unread,
Jul 24, 2025, 9:11:28 AMJul 24
to Parselmouth
Also I was thinking, if there is no simple workaround, you could always go the route of running a sub process that executes a Praat script using a later version executable of Praat. Of course, this doesn't get you all the Pythonic conveniences of Parselmouth, but you could potentially do a combination of the two in your application either by writing/reading temp files or passing output back from the process through stdout.
Ani

yannick...@gmail.com

unread,
Jul 24, 2025, 1:38:12 PMJul 24
to Parselmouth
Let me have another look. It was getting too late to think straight, yesterday, but there might be a way to get this! ;-)

Apart from that, if you're happy running the development version (currently based on Praat 6.4.16), you can find the last builds here: https://github.com/YannickJadoul/Parselmouth/actions/workflows/wheels.yml?query=branch%3Amaster
In that case, you can just scroll down to the lastest build's artifacts (https://github.com/YannickJadoul/Parselmouth/actions/runs/15754914118#artifacts), download the zip with the wheels for your platform, find the wheel that's matching your Python version and run `pip install that_correct_python_version.whl`).

I'll update if I find anything more!

Cheers
Yannick

Ethelyn Huang

unread,
Jul 25, 2025, 12:28:54 PMJul 25
to Parselmouth
Hi Ani and Yannick,

I ended up going with Ani's suggestion of writing a Praat script to handle the querying. It turns out that the command exhibits some strange behaviour for my test files and gives me very low values for my optimal ceiling (down to around 1900 Hz, which is very strange given the typical value is 5000-5500 Hz). Regardless, thanks so much for your input and advice! I really appreciate it :)
Reply all
Reply to author
Forward
0 new messages