Using de Jong's SyllableNucleiv3.praat script in Python

76 views
Skip to first unread message

Magdalena Kachlicka

unread,
Mar 29, 2023, 6:00:10 AM3/29/23
to Parselmouth
Dear Parselmouth community! 

I have a question. I'm trying to incorporate de Jong's script into some analyses and I can't seem to find a way to redirect the output of the function (by default it saves it as SyllableNuclei.txt) into the data frame directly (instead of reading it from the txt file).

I'm running the function like this:
run_file('functions/SyllableNucleiv3.praat', '/audio/*.wav', 'None', -25, 2, 0.4, True, 'English', 1, 'Table', 'OverWriteData', True)

It seems that the function cannot take any additional argument that would allow me to specify where the output goes and in what form.

Is there a way one can save the results from that script directly onto the data frame? Any ideas and suggestions would be super appreciated, thanks!


yannick...@gmail.com

unread,
Mar 29, 2023, 12:49:09 PM3/29/23
to Parselmouth
Hi Magdalena!

Which version of the script are you using? This one, from the "Praat Vocal Toolkit": https://www.praatvocaltoolkit.com/syllable-nuclei-v3.html ?

When I run that script, with the parameters you list, `run_file` already returns one or more Praat objects:
>>> parselmouth.praat.run_file('../plugin_VocalToolkit/SyllableNucleiv3.praat', '/home/yannick/TEST/*.wav', 'None', -25, 2, 0.4, True, 'English', 1, 'Table', 'OverWriteData', True)
[<parselmouth.Sound object at 0x7f9a356d7770>, <parselmouth.TextGrid object at 0x7f9a345ddff0>, <parselmouth.Data object at 0x7f9a345de030>]
>>> table = parselmouth.praat.run_file('../plugin_VocalToolkit/SyllableNucleiv3.praat', '/home/yannick/TEST/*.wav', 'None', -25, 2, 0.4, True, 'English', 1, 'Table', 'OverWriteData', True)[-1]
>>> table.full_name
'Table "the_north_wind_and_the_sun"'
>>> print(table)
Object type: Table
Object name: the_north_wind_and_the_sun
Date: Wed Mar 29 18:19:25 2023

Number of rows: 4
Number of columns: 37


So, whereas this last object returned is a `parselmouth.Data` object, it contains a Praat Table inside. See https://parselmouth.readthedocs.io/en/stable/examples/pitch_manipulation.html for more explanation.

And what you can for example do is "List" to get out a TSV-formatted string:
>>> parselmouth.praat.call(table, "List", False)
'type\tts\tdur\tdurz\tF0\tF0z\tF1\tF1z\tF2\tF2z\tF3\tF3z\tdF0\tdF0z\tdF1\tdF1z\tdF2\tdF2z\tdF3\tdF3z\tdqF0\tdqF0z\tdqF1\tdqF1z\tdqF2\tdqF2z\tdqF3\tdqF3z\tsdF0\tsdF0z\tsdF1\tsdF1z\tsdF2\tsdF2z\tsdF3\tsdF3z\tscore\n?\t0.138\t0.152\t-0.487\t18.851\t1.226\t4.078\t-0.455\t8.580\t-0.977\t15.052\t0.024\t-8.932\t-1.226\t0.996\t-0.245\t1.435\t0.625\t1.573\t1.346\t7.497\t1.420\t3.115\t0.244\t4.270\t0.378\t6.675\t1.273\t2.853\t1.413\t1.108\t-0.105\t1.245\t-0.053\t2.029\t1.247\t2.320\n?\t0.466\t0.160\t-0.209\t13.722\t0.309\t4.032\t-0.503\t8.922\t-0.673\t14.192\t-1.072\t-3.802\t-0.309\t0.813\t-0.555\t1.422\t0.591\t0.941\t-0.839\t3.305\t-0.161\t1.919\t-0.688\t5.170\t1.208\t2.157\t-0.930\t1.292\t-0.056\t0.805\t-0.601\t1.779\t1.289\t0.810\t-0.923\t2.052\n?\t0.698\t0.144\t-0.765\t9.566\t-0.434\t3.996\t-0.541\t10.986\t1.164\t16.078\t1.330\t0.353\t0.434\t0.743\t-0.675\t1.301\t0.264\t0.988\t-0.675\t1.298\t-0.918\t1.691\t-0.866\t3.290\t-0.526\t2.732\t-0.649\t0.417\t-0.880\t0.721\t-0.738\t1.232\t-0.084\t0.945\t-0.682\t2.704\nfp\t1.042\t0.208\t1.461\t5.833\t-1.101\t5.937\t1.499\t10.224\t0.486\t14.813\t-0.282\t4.086\t1.101\t2.007\t1.475\t0.652\t-1.480\t1.232\t0.168\t2.831\t-0.340\t4.483\t1.310\t2.712\t-1.060\t4.693\t0.307\t0.845\t-0.477\t2.055\t1.443\t0.807\t-1.152\t1.529\t0.358\t3.725\n'

One more trick necessary to get Pandas to read this, it seems, but StringIO does the job:
>>> pd.read_table(io.StringIO(parselmouth.praat.call(table, "List", False)))
  type     ts    dur   durz      F0    F0z     F1    F1z      F2    F2z      F3    F3z    dF0   dF0z  ...  dqF1z   dqF2  dqF2z   dqF3  dqF3z   sdF0  sdF0z   sdF1  sdF1z   sdF2  sdF2z   sdF3  sdF3z  score
0    ?  0.138  0.152 -0.487  18.851  1.226  4.078 -0.455   8.580 -0.977  15.052  0.024 -8.932 -1.226  ...  0.244  4.270  0.378  6.675  1.273  2.853  1.413  1.108 -0.105  1.245 -0.053  2.029  1.247  2.320
1    ?  0.466  0.160 -0.209  13.722  0.309  4.032 -0.503   8.922 -0.673  14.192 -1.072 -3.802 -0.309  ... -0.688  5.170  1.208  2.157 -0.930  1.292 -0.056  0.805 -0.601  1.779  1.289  0.810 -0.923  2.052
2    ?  0.698  0.144 -0.765   9.566 -0.434  3.996 -0.541  10.986  1.164  16.078  1.330  0.353  0.434  ... -0.866  3.290 -0.526  2.732 -0.649  0.417 -0.880  0.721 -0.738  1.232 -0.084  0.945 -0.682  2.704
3   fp  1.042  0.208  1.461   5.833 -1.101  5.937  1.499  10.224  0.486  14.813 -0.282  4.086  1.101  ...  1.310  2.712 -1.060  4.693  0.307  0.845 -0.477  2.055  1.443  0.807 -1.152  1.529  0.358  3.725

[4 rows x 37 columns]

(or with `pd.read_csv(..., sep='\t')`)


Do note that it still seems that the Praat script is saving a few temporary files to disk, etc, but that's inherent to the Praat script. The alternative would be to adapt the script, or to reproduce it in Python, accessing Praat functionality through `parselmouth.praat.call`.

Next, I'm not entirely sure why, but I seem to be getting an entirely different table out, when I put "False" for the "Keep objects" parameter, so you might want to double check:
>>> table = parselmouth.praat.run_file('../plugin_VocalToolkit/SyllableNucleiv3.praat', '/home/yannick/TEST/*.wav', 'None', -25, 2, 0.4, True, 'English', 1, 'Table', 'OverWriteData', False)[-1]
>>> pd.read_table(io.StringIO(parselmouth.praat.call(table, "List", False)))
                         name   nsyll   npause   dur(s)   phonationtime(s)   speechrate(nsyll/dur)   articulation_rate(nsyll/phonationtime)   ASD(speakingtime/nsyll)   nrFP   tFP(s)
0  the_north_wind_and_the_sun       4        0     1.28               1.28                    3.12                                     3.12                     0.321      1    0.208


And finally, within the context of a larger Python program, it might also be nice to know you can just pass a Sound of your choice, rather than specifying the path:
>>> sound = parselmouth.Sound("the_north_wind_and_the_sun.wav")
>>> table = parselmouth.praat.run_file(sound, '../plugin_VocalToolkit/SyllableNucleiv3.praat', '', 'None', -25, 2, 0.4, True, 'English', 1, 'Table', 'OverWriteData', False)[-1]
>>> pd.read_table(io.StringIO(parselmouth.praat.call(table, "List", False)))
       name   nsyll   npause   dur(s)   phonationtime(s)   speechrate(nsyll/dur)   articulation_rate(nsyll/phonationtime)   ASD(speakingtime/nsyll)   nrFP   tFP(s)
0  untitled       4        0     1.28               1.28                    3.12                                     3.12                     0.321      1    0.208

Or even multiple Sound objects (obviously, in this case it's twice the same, but just showcasing you can pass a list):
>>> table = parselmouth.praat.run_file([sound, sound], '../plugin_VocalToolkit/SyllableNucleiv3.praat', '', 'None', -25, 2, 0.4, True, 'English', 1, 'Table', 'OverWriteData', False)[-1]
>>> pd.read_table(io.StringIO(parselmouth.praat.call(table, "List", False)))
       name   nsyll   npause   dur(s)   phonationtime(s)   speechrate(nsyll/dur)   articulation_rate(nsyll/phonationtime)   ASD(speakingtime/nsyll)   nrFP   tFP(s)
0  untitled       4        0     1.28               1.28                    3.12                                     3.12                     0.321      1    0.208
1  untitled       4        0     1.28               1.28                    3.12                                     3.12                     0.321      1    0.208



Also, it's an older version, but in the Journal of Phonetics publication of Parselmouth (https://www.sciencedirect.com/science/article/pii/S0095447017301389), we adapted and added the then-current syllable nuclei Praat script as an example included in the supplementary material: https://ai.vub.ac.be/~yajadoul/jadoul_introducing-parselmouth_a-python-interface-to-praat_supplementary-material.zip

Probably you don't need it, but it also shows how you can adapt the Praat scripts at the start and end (without touching the core part) if something's lacking in the interaction with Parselmouth/Python.

I hope this already helps, but if I missed something, don't hesitate to get back with more questions/issues!

Kind regards
Yannick
Reply all
Reply to author
Forward
0 new messages