Spaces:
Runtime error
Runtime error
| ########################################################################### | |
| # The library was developed based upon the idea introduced # | |
| # by Nivja DeJong and Ton Wempe [1], Paul Boersma and David Weenink [2], # | |
| # Carlo Gussenhoven [3], # | |
| # S.M Witt and S.J. Young [4] # | |
| # Peaks in intensity (dB) that are preceded and followed by dips in # | |
| # intensity are considered as potential syllable cores. # | |
| # # | |
| # Praat Script voice analysis # | |
| # Copyright (C) 2017 Shahab Sabahi # | |
| # # | |
| # This program is a Mysolutions software intellectual property: # | |
| # you can redistribute it and/or modify it under the terms # | |
| # of the Mysolutions Permision. # | |
| # # | |
| # 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. # | |
| # # | |
| # # | |
| ########################################################################### | |
| # | |
| # modified 2018 July by Shahab Sabahi, | |
| # bug fixed concerning summing total pause, May 28th 2017 | |
| ########################################################################### | |
| clearinfo | |
| # select all | |
| # Remove | |
| form Counting Syllables in Sound Utterances | |
| real Silence_threshold_(dB) -20 | |
| real Minimum_dip_between_peaks_(dB) 2 | |
| real Minimum_pause_duration_(s) 0.27 | |
| boolean Keep_Soundfiles_and_Textgrids 1 | |
| sentence soundin | |
| sentence directory | |
| positive Minimum_pitch_(Hz) 80 | |
| positive Maximum_pitch_(Hz) 400 | |
| positive Time_step_(s) 0.01 | |
| endform | |
| # shorten variables | |
| silencedb = 'silence_threshold' | |
| mindip = 'minimum_dip_between_peaks' | |
| showtext = 'keep_Soundfiles_and_Textgrids' | |
| minpause = 'minimum_pause_duration' | |
| # read files | |
| Read from file... 'soundin$' | |
| # 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 | |
| Save as text file: "'directory$'/'soundname$'.TextGrid" | |
| # use object ID | |
| Read from file... 'soundin$' | |
| soundname$ = selected$("Sound") | |
| soundid = selected("Sound") | |
| fileName$ = "f0points'soundname$'.txt" | |
| # Calculate F0 values | |
| To Pitch... time_step minimum_pitch maximum_pitch | |
| numberOfFrames = Get number of frames | |
| # Loop through all frames in the Pitch object: | |
| select Pitch 'soundname$' | |
| unit$ = "Hertz" | |
| min_Hz = Get minimum... 0 0 Hertz Parabolic | |
| min$ = "'min_Hz'" | |
| max_Hz = Get maximum... 0 0 Hertz Parabolic | |
| max$ = "'max_Hz'" | |
| mean_Hz = Get mean... 0 0 Hertz | |
| mean$ = "'mean_Hz'" | |
| stdev_Hz = Get standard deviation... 0 0 Hertz | |
| stdev$ = "'stdev_Hz'" | |
| median_Hz = Get quantile... 0 0 0.50 Hertz | |
| median$ = "'median_Hz'" | |
| quantile25_Hz = Get quantile... 0 0 0.25 Hertz | |
| quantile25$ = "'quantile25_Hz'" | |
| quantile75_Hz = Get quantile... 0 0 0.75 Hertz | |
| quantile75$ = "'quantile75_Hz'" | |
| # Collect and save the pitch values from the individual frames to the text file: | |
| quantile250 = 'quantile25$' | |
| quantile750 = 'quantile75$' | |
| meanall = 'mean$' | |
| sd='stdev$' | |
| medi='median$' | |
| mini='min$' | |
| maxi='max$' | |
| # clean up before next sound file is opened | |
| select 'intid' | |
| plus 'matid' | |
| plus 'sndintid' | |
| plus 'ppid' | |
| plus 'pitchid' | |
| plus 'silencetierid' | |
| plus 'silencetableid' | |
| Read from file... 'soundin$' | |
| soundname$ = selected$ ("Sound") | |
| To Formant (burg)... 0 5 5500 0.025 50 | |
| Read from file... 'directory$'/'soundname$'.TextGrid | |
| int=Get number of intervals... 2 | |
| appendInfoLine:"int = ", 'int' | |
| if int<2 | |
| warning$="A noisy background or unnatural-sounding speech detected. No result try again" | |
| appendInfoLine: warning$ | |
| # exitScript() | |
| endif | |
| # We then calculate F1, F2 and F3 | |
| fff= 0 | |
| eee= 0 | |
| inside= 0 | |
| outside= 0 | |
| for k from 2 to 'int' | |
| select TextGrid 'soundname$' | |
| label$ = Get label of interval... 2 'k' | |
| if label$ <> "" | |
| # calculates the onset and offset | |
| vowel_onset = Get starting point... 2 'k' | |
| vowel_offset = Get end point... 2 'k' | |
| select Formant 'soundname$' | |
| f_one = Get mean... 1 vowel_onset vowel_offset Hertz | |
| f_two = Get mean... 2 vowel_onset vowel_offset Hertz | |
| f_three = Get mean... 3 vowel_onset vowel_offset Hertz | |
| appendInfoLine: "f_one = ", 'f_one' | |
| appendInfoLine: "f_two = ", 'f_two' | |
| appendInfoLine: "f_three = ", 'f_three' | |
| ff = 'f_two'/'f_one' | |
| lnf1 = 'f_one' | |
| lnf2f1 = ('f_two'/'f_one') | |
| uplim =(-0.012*'lnf1')+13.17 | |
| lowlim =(-0.0148*'lnf1')+8.18 | |
| f1uplim =(lnf2f1-13.17)/-0.012 | |
| f1lowlim =(lnf2f1-8.18)/-0.0148 | |
| if lnf1>='f1lowlim' and lnf1<='f1uplim' | |
| inside = 'inside'+1 | |
| else | |
| outside = 'outside'+1 | |
| endif | |
| fff = 'fff'+'f1uplim' | |
| eee = 'eee'+'f1lowlim' | |
| ffff = 'fff'/'int' | |
| eeee = 'eee'/'int' | |
| pron =('inside'*100)/('inside'+'outside') | |
| prom =('outside'*100)/('inside'+'outside') | |
| prob1 = invBinomialP ('pron'/100, 'inside', 'inside'+'outside') | |
| prob = 'prob1:2' | |
| endif | |
| endfor | |
| lnf0 = (ln(f_one)-5.65)/0.31 | |
| f00 = exp (lnf0) | |
| Remove | |
| if showtext < 1 | |
| select 'soundid' | |
| plus 'textgridid' | |
| Remove | |
| endif | |
| # summarize results in Info window | |
| speakingrate = 'voicedcount'/'originaldur' | |
| speakingraterp = ('voicedcount'/'originaldur')*100/3.93 | |
| articulationrate = 'voicedcount'/'speakingtot' | |
| articulationraterp = ('voicedcount'/'speakingtot')*100/4.64 | |
| npause = 'npauses'-1 | |
| asd = 'speakingtot'/'voicedcount' | |
| avenumberofwords = ('voicedcount'/1.74)/'speakingtot' | |
| avenumberofwordsrp = (('voicedcount'/1.74)/'speakingtot')*100/2.66 | |
| nuofwrdsinchunk = (('voicedcount'/1.74)/'speakingtot')* 'speakingtot'/'npauses' | |
| nuofwrdsinchunkrp = ((('voicedcount'/1.74)/'speakingtot')* 'speakingtot'/'npauses')*100/9 | |
| avepauseduratin = ('originaldur'-'speakingtot')/('npauses'-1) | |
| avepauseduratinrp = (('originaldur'-'speakingtot')/('npauses'-1))*100/0.75 | |
| balance = ('voicedcount'/'originaldur')/('voicedcount'/'speakingtot') | |
| balancerp = (('voicedcount'/'originaldur')/('voicedcount'/'speakingtot'))*100/0.85 | |
| nuofwrds= ('voicedcount'/1.74) | |
| f1norm = -0.0118*'pron'*'pron'+0.5072*'pron'+394.34 | |
| inpro = ('nuofwrds'*60/'originaldur') | |
| polish = 'originaldur'/2 | |
| # Read the saved pitch points as a Matrix object: | |
| if meanall<150 | |
| q25='quantile250'/100 | |
| q75='quantile750'/140 | |
| mr= 'meanall'/119 | |
| else | |
| q25='quantile250'/183 | |
| q75='quantile750'/237 | |
| mr= 'meanall'/210 | |
| endif | |
| # Convert the original minimum and maximum parameters in order to define the x scale of the | |
| if q25<=1 and q75<=1 and mr>=0.95 and mr<=1.05 | |
| ins=10 | |
| elsif q25<=1 and q75<=1 and mr>=0.9 and mr<=1.1 | |
| ins=9 | |
| elsif q25<=1 and q75<=1 and mr>=0.85 and mr<=1.15 | |
| ins=8 | |
| elsif mr>=0.9 and mr<=1.1 | |
| ins=7 | |
| elsif mr>=0.8 and mr<=1.2 | |
| ins=6 | |
| elsif mr<=0.8 | |
| ins=4 | |
| else | |
| ins=5 | |
| endif | |
| #SCORING | |
| if f00<90 or f00>255 | |
| z=1.16 | |
| elsif f00<97 or f00>245 | |
| z=2 | |
| elsif f00<115 or f00>245 | |
| z=3 | |
| elsif f00<=245 or f00>=115 | |
| z=4 | |
| else | |
| z=1 | |
| endif | |
| if nuofwrdsinchunk>=6.24 and avepauseduratin<=1.0 | |
| l=4 | |
| elsif nuofwrdsinchunk>=6.24 and avepauseduratin>1.0 | |
| l=3.6 | |
| elsif nuofwrdsinchunk>=4.4 and nuofwrdsinchunk<=6.24 and avepauseduratin<=1.15 | |
| l=3.3 | |
| elsif nuofwrdsinchunk>=4.4 and nuofwrdsinchunk<=6.24 and avepauseduratin>1.15 | |
| l=3 | |
| elsif nuofwrdsinchunk<4.4 and avepauseduratin<=1.15 | |
| l=2 | |
| elsif nuofwrdsinchunk<=4.4 and avepauseduratin>1.15 | |
| l=1.16 | |
| else | |
| l=1 | |
| endif | |
| if balance>=0.69 and avenumberofwords>=2.60 | |
| o=4 | |
| elsif balance>=0.60 and avenumberofwords>=2.43 | |
| o=3.5 | |
| elsif balance>=0.5 and avenumberofwords>=2.25 | |
| o=3 | |
| elsif balance>=0.5 and avenumberofwords>=2.07 | |
| o=2 | |
| elsif balance>=0.5 and avenumberofwords>=1.95 | |
| o=1.16 | |
| else | |
| o=1 | |
| endif | |
| if speakingrate<=4.26 and speakingrate>=3.16 | |
| q=4 | |
| elsif speakingrate<=3.16 and speakingrate>=2.54 | |
| q=3.5 | |
| elsif speakingrate<=2.54 and speakingrate>=1.91 | |
| q=3 | |
| elsif speakingrate<=1.91 and speakingrate>=1.28 | |
| q=2 | |
| elsif speakingrate<=1.28 and speakingrate>=1.0 | |
| q=1.16 | |
| else | |
| q=1 | |
| endif | |
| if balance>=0.69 and articulationrate>=4.54 | |
| w=4 | |
| elsif balance>=0.60 and articulationrate>=4.22 | |
| w=3.5 | |
| elsif balance>=0.50 and articulationrate>=3.91 | |
| w=3 | |
| elsif balance>=0.5 and articulationrate>=3.59 | |
| w=2 | |
| elsif balance>=0.5 and articulationrate>=3.10 | |
| w=1.16 | |
| else | |
| w=1 | |
| endif | |
| if inpro>=119 and ('f1norm'*1.1)>=f1lowlim | |
| r = 4 | |
| elsif inpro>=119 and ('f1norm'*1.1)<f1lowlim | |
| r = 3.8 | |
| elsif inpro<119 and inpro>=100 and ('f1norm'*1.1)>=f1lowlim | |
| r = 3.6 | |
| elsif inpro<119 and inpro>=100 and ('f1norm'*1.1)<f1lowlim | |
| r = 3.4 | |
| elsif inpro<100 and inpro>=80 and ('f1norm'*1.1)>=f1lowlim | |
| r= 3.2 | |
| elsif inpro<100 and inpro>=80 and ('f1norm'*1.1)<f1lowlim | |
| r = 2.8 | |
| elsif inpro<80 and inpro>=70 and ('f1norm'*1.1)>=f1lowlim | |
| r = 2.4 | |
| elsif inpro<70 and inpro>=60 and ('f1norm'*1.1)>=f1lowlim | |
| r = 2 | |
| elsif inpro<70 and inpro>=60 and ('f1norm'*1.1)<f1lowlim | |
| r = 1.1 | |
| else | |
| r = 0.3 | |
| endif | |
| if articulationrate>=4.80 and balance>=0.8 | |
| qr = 4 | |
| elsif articulationrate>=4.80 and balance<0.8 | |
| qr = 3.8 | |
| elsif articulationrate<4.80 and articulationrate>=4.65 and balance>=0.8 | |
| qr = 3.6 | |
| elsif articulationrate<4.80 and articulationrate>=4.65 and balance<0.8 | |
| qr = 3.4 | |
| elsif articulationrate<4.65 and articulationrate>=4.55 and balance>=0.8 | |
| qr= 3.2 | |
| elsif articulationrate<4.65 and articulationrate>=4.55 and balance<0.8 | |
| qr = 2.8 | |
| elsif articulationrate<4.55 and articulationrate>=4.40 and balance>=0.8 | |
| qr = 2.4 | |
| elsif articulationrate<4.40 and articulationrate>=4.30 and balance>=0.8 | |
| qr = 2 | |
| elsif articulationrate<4.40 and articulationrate>=4.30 and balance<0.8 | |
| qr = 1.5 | |
| else | |
| qr = 1 | |
| endif | |
| # summarize SCORE in Info window | |
| totalscore =(l*2+z*4+o*3+qr*3+w*4+r*4)/20 | |
| totalscale= 'totalscore'*25 | |
| if totalscore>=3.6 | |
| a=4 | |
| elsif totalscore>=0.6 and totalscore<2 | |
| a=1 | |
| elsif totalscore>=2 and totalscore<3 | |
| a=2 | |
| elsif totalscore>=3 and totalscore<3.6 | |
| a=3 | |
| else | |
| a=0.5 | |
| endif | |
| if totalscale>=90 | |
| s=4 | |
| elsif totalscale>=15 and totalscale<50 | |
| s=1 | |
| elsif totalscale>=50 and totalscale<75 | |
| s=2 | |
| elsif totalscale>=75 and totalscale<90 | |
| s=3 | |
| else | |
| s=0.5 | |
| endif | |
| #vvv=a+('totalscale'/100) | |
| vvv=totalscore+('totalscale'/100) | |
| if vvv>=4 | |
| u=4*(1-(randomInteger(1,16)/100)) | |
| else | |
| u=vvv-(randomInteger(1,16)/100) | |
| endif | |
| if totalscore>=4 | |
| xx=30 | |
| elsif totalscore>=3.80 and totalscore<4 | |
| xx=29 | |
| elsif totalscore>=3.60 and totalscore<3.80 | |
| xx=28 | |
| elsif totalscore>=3.5 and totalscore<3.6 | |
| xx=27 | |
| elsif totalscore>=3.3 and totalscore<3.5 | |
| xx=26 | |
| elsif totalscore>=3.15 and totalscore<3.3 | |
| xx=25 | |
| elsif totalscore>=3.08 and totalscore<3.15 | |
| xx=24 | |
| elsif totalscore>=3 and totalscore<3.08 | |
| xx=23 | |
| elsif totalscore>=2.83 and totalscore<3 | |
| xx=22 | |
| elsif totalscore>=2.60 and totalscore<2.83 | |
| xx=21 | |
| elsif totalscore>=2.5 and totalscore<2.60 | |
| xx=20 | |
| elsif totalscore>=2.30 and totalscore<2.50 | |
| xx=19 | |
| elsif totalscore>=2.23 and totalscore<2.30 | |
| xx=18 | |
| elsif totalscore>=2.15 and totalscore<2.23 | |
| xx=17 | |
| elsif totalscore>=2 and totalscore<2.15 | |
| xx=16 | |
| elsif totalscore>=1.93 and totalscore<2 | |
| xx=15 | |
| elsif totalscore>=1.83 and totalscore<1.93 | |
| xx=14 | |
| elsif totalscore>=1.74 and totalscore<1.83 | |
| xx=13 | |
| elsif totalscore>=1.66 and totalscore<1.74 | |
| xx=12 | |
| elsif totalscore>=1.50 and totalscore<1.66 | |
| xx=11 | |
| elsif totalscore>=1.33 and totalscore<1.50 | |
| xx=10 | |
| else | |
| xx=9 | |
| endif | |
| overscore = xx*4/30 | |
| ov = overscore | |
| if xx>=25 | |
| xxban$="C" | |
| elsif xx>=20 and xx<25 | |
| xxban$="B2" | |
| elsif xx>=16 and xx<20 | |
| xxban$="B1" | |
| elsif xx>=10 and xx<16 | |
| xxban$="A2" | |
| else | |
| xxban$="A1" | |
| endif | |
| qaz = 0.18 | |
| rr = (r*4+qr*2+z*1)/7 | |
| lu = (l*1+w*2+inpro*4/125)/4 | |
| td = (w*1+o*2+inpro*1/125)/3.25 | |
| facts=(ln(7/4)*4/7+ln(7/2)*2/7+ln(7)*1/7+ln(4)*1/4+ln(2)*1/2+ln(4)*1/4+ln(3.25)*1/3.25+ln(3.25/2)*2/3.25+ln(3.25/0.25)*0.25/3.25+ln(14.25/7)*7/14.25+ln(14.25/4)*4/14.25+ln(14.25/3.35)*3.25/14.25) | |
| totsco = (r*ln(7/4)*4/7+qr*ln(7/2)*2/7+z*ln(7)*1/7+l*ln(4)*1/4+w*ln(2)*1/2+ln(4)*1/4*inpro*4/125+w*ln(3.25)*1/3.25+o*ln(3.25/2)*2/3.25+ln(3.25/0.25)*0.25/3.25*inpro*4/125)/facts | |
| if totalscore>=4 | |
| totsco=3.9 | |
| else | |
| totsco=totalscore | |
| endif | |
| rrr = rr*qaz | |
| lulu = lu*qaz | |
| tdtd = td*qaz | |
| totscoo = totsco*qaz | |
| whx=rrr*cos(1.309) | |
| why=rrr*sin(1.309) | |
| who=4*qaz | |
| probpron=(r/4) | |
| lstd=(10*l)/4 | |
| ostd=(10*o)/4 | |
| wstd=(10*w)/4 | |
| rstd=(10*r)/4 | |
| zstd=(10*z)/4 | |
| qstd=(10*qr)/4 | |
| Erase all | |
| appendInfoLine: "1. voicedcount = ", 'voicedcount:0' | |
| appendInfoLine: "2. npause = ", 'npause:0' | |
| appendInfoLine: "3. speakingrate = ", 'speakingrate:2' | |
| appendInfoLine: "4. articulationrate = ", 'articulationrate:2' | |
| appendInfoLine: "5. speakingtot = ", 'speakingtot:2' | |
| appendInfoLine: "6. originaldur = ", 'originaldur:2' | |
| appendInfoLine: "7. balance = ", 'balance:1' | |
| appendInfoLine: "8. meanall = ", 'meanall:2' | |
| appendInfoLine: "9. sd = ", 'sd:2' | |
| appendInfoLine: "10. medi = ", 'medi:1' | |
| appendInfoLine: "11. mini = ", 'mini:0' | |
| appendInfoLine: "12. maxi = ", 'maxi:0' | |
| appendInfoLine: "13. quantile250 = ", 'quantile250:0' | |
| appendInfoLine: "14. quantile750 = ", 'quantile750:0' | |
| appendInfoLine: "15. probpron = ", 'probpron:2' |