Praat Script Syllable Nuclei v2
Note that the new (and slightly better) version of this script (v3), including options to measure filled pauses, can be found here:
###########################################################################
# #
# Praat Script Syllable Nuclei #
# Copyright (C) 2008 Nivja de Jong and Ton Wempe #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see http://www.gnu.org/licenses/ #
# #
###########################################################################
#
# modified 2010.09.17 by Hugo Quené, Ingrid Persoon, & Nivja de Jong
# Overview of changes:
# + change threshold-calculator: rather than using median, use the almost maximum
# minus 25dB. (25 dB is in line with the standard setting to detect silence
# in the "To TextGrid (silences)" function.
# Almost maximum (.99 quantile) is used rather than maximum to avoid using
# irrelevant non-speech sound-bursts.
# + add silence-information to calculate articulation rate and ASD (average syllable
# duration.
# NB: speech rate = number of syllables / total time
# articulation rate = number of syllables / phonation time
# + remove max number of syllable nuclei
# + refer to objects by unique identifier, not by name
# + keep track of all created intermediate objects, select these explicitly,
# then Remove
# + provide summary output in Info window
# + do not save TextGrid-file but leave it in Object-window for inspection
# (if requested in startup-form)
# + allow Sound to have starting time different from zero
# for Sound objects created with Extract (preserve times)
# + programming of checking loop for mindip adjusted
# in the orig version, precedingtime was not modified if the peak was rejected !!
# var precedingtime and precedingint renamed to currenttime and currentint
#
# + bug fixed concerning summing total pause, feb 28th 2011
###########################################################################
# counts syllables of all sound utterances in a directory
# NB unstressed syllables are sometimes overlooked
# NB filter sounds that are quite noisy beforehand
# NB use Silence threshold (dB) = -25 (or -20?)
# NB use Minimum dip between peaks (dB) = between 2-4 (you can first try;
# For clean and filtered: 4)
form Counting Syllables in Sound Utterances
real Silence_threshold_(dB) -25
real Minimum_dip_between_peaks_(dB) 2
real Minimum_pause_duration_(s) 0.3
boolean Keep_Soundfiles_and_Textgrids yes
sentence directory /directory
endform
# shorten variables
silencedb = 'silence_threshold'
mindip = 'minimum_dip_between_peaks'
showtext = 'keep_Soundfiles_and_Textgrids'
minpause = 'minimum_pause_duration'
# print a single header line with column names and units
printline soundname, nsyll, npause, dur (s), phonationtime (s), speechrate (nsyll/dur), articulation rate (nsyll / phonationtime), ASD (speakingtime/nsyll)
# read files
Create Strings as file list... list 'directory$'/*.wav
numberOfFiles = Get number of strings
for ifile to numberOfFiles
select Strings list
fileName$ = Get string... ifile
Read from file... 'directory$'/'fileName$'
# use object ID
soundname$ = selected$("Sound")
soundid = selected("Sound")
originaldur = Get total duration
# allow non-zero starting time
bt = Get starting time
# Use intensity to get threshold
To Intensity... 50 0 yes
intid = selected("Intensity")
start = Get time from frame number... 1
nframes = Get number of frames
end = Get time from frame number... 'nframes'
# estimate noise floor
minint = Get minimum... 0 0 Parabolic
# estimate noise max
maxint = Get maximum... 0 0 Parabolic
#get .99 quantile to get maximum (without influence of non-speech sound bursts)
max99int = Get quantile... 0 0 0.99
# estimate Intensity threshold
threshold = max99int + silencedb
threshold2 = maxint - max99int
threshold3 = silencedb - threshold2
if threshold < minint
threshold = minint
endif
# get pauses (silences) and speakingtime
To TextGrid (silences)... threshold3 minpause 0.1 silent sounding
textgridid = selected("TextGrid")
silencetierid = Extract tier... 1
silencetableid = Down to TableOfReal... sounding
nsounding = Get number of rows
npauses = 'nsounding'
speakingtot = 0
for ipause from 1 to npauses
beginsound = Get value... 'ipause' 1
endsound = Get value... 'ipause' 2
speakingdur = 'endsound' - 'beginsound'
speakingtot = 'speakingdur' + 'speakingtot'
endfor
select 'intid'
Down to Matrix
matid = selected("Matrix")
# Convert intensity to sound
To Sound (slice)... 1
sndintid = selected("Sound")
# use total duration, not end time, to find out duration of intdur
# in order to allow nonzero starting times.
intdur = Get total duration
intmax = Get maximum... 0 0 Parabolic
# estimate peak positions (all peaks)
To PointProcess (extrema)... Left yes no Sinc70
ppid = selected("PointProcess")
numpeaks = Get number of points
# fill array with time points
for i from 1 to numpeaks
t'i' = Get time from index... 'i'
endfor
# fill array with intensity values
select 'sndintid'
peakcount = 0
for i from 1 to numpeaks
value = Get value at time... t'i' Cubic
if value > threshold
peakcount += 1
int'peakcount' = value
timepeaks'peakcount' = t'i'
endif
endfor
# fill array with valid peaks: only intensity values if preceding
# dip in intensity is greater than mindip
select 'intid'
validpeakcount = 0
currenttime = timepeaks1
currentint = int1
for p to peakcount-1
following = p + 1
followingtime = timepeaks'following'
dip = Get minimum... 'currenttime' 'followingtime' None
diffint = abs(currentint - dip)
if diffint > mindip
validpeakcount += 1
validtime'validpeakcount' = timepeaks'p'
endif
currenttime = timepeaks'following'
currentint = Get value at time... timepeaks'following' Cubic
endfor
# Look for only voiced parts
select 'soundid'
To Pitch (ac)... 0.02 30 4 no 0.03 0.25 0.01 0.35 0.25 450
# keep track of id of Pitch
pitchid = selected("Pitch")
voicedcount = 0
for i from 1 to validpeakcount
querytime = validtime'i'
select 'textgridid'
whichinterval = Get interval at time... 1 'querytime'
whichlabel$ = Get label of interval... 1 'whichinterval'
select 'pitchid'
value = Get value at time... 'querytime' Hertz Linear
if value <> undefined
if whichlabel$ = "sounding"
voicedcount = voicedcount + 1
voicedpeak'voicedcount' = validtime'i'
endif
endif
endfor
# calculate time correction due to shift in time for Sound object versus
# intensity object
timecorrection = originaldur/intdur
# Insert voiced peaks in TextGrid
if showtext > 0
select 'textgridid'
Insert point tier... 1 syllables
for i from 1 to voicedcount
position = voicedpeak'i' * timecorrection
Insert point... 1 position 'i'
endfor
endif
# clean up before next sound file is opened
select 'intid'
plus 'matid'
plus 'sndintid'
plus 'ppid'
plus 'pitchid'
plus 'silencetierid'
plus 'silencetableid'
Remove
if showtext < 1
select 'soundid'
plus 'textgridid'
Remove
endif
# summarize results in Info window
speakingrate = 'voicedcount'/'originaldur'
articulationrate = 'voicedcount'/'speakingtot'
npause = 'npauses'-1
asd = 'speakingtot'/'voicedcount'
printline 'soundname$', 'voicedcount', 'npause', 'originaldur:2', 'speakingtot:2', 'speakingrate:2', 'articulationrate:2', 'asd:3'
endfor