################################################################################### # modifyFormants-preVocalic.praat (Written by Kyuchul Yoon, kyoon@kyungnam.ac.kr) # ================================================================================ # Given, for example, a syllable, this script resynthesizes it, but with formant # frequency values modified by the user. # Resynthesis based on the source-filter theory of speech production. # Source signal extracted by inverse-filtering the LPC(burg) and the target sound. # Filter signal extracted by Formant (burg) algorithm implemented in Praat. # ================================================================================ # In order for the formant values to be modified, the user needs to specify the # onset time/location and the offset time/location of the formant transition. # The user also needs to specify the "new" onset formant frequencies. She doesn't # need to specify the offset frequency of formant transition because it won't be # changed. Think of this as changing the 'locus' frequencies. # This file was originally written for Professor Hahn at Konkuk Univ. # This script is for the formant transition at the ONSET of a vowel followed by a # consonant. ################################################################################### form Specify the parameters word inputSound_(with_dot_wav) resynCenter-ga.wav natural resampleFreq_(in_Hz) 11000 real preVocalicOnset_(in_sec) 0.13 real preVocalicOffset_(in_sec) 0.21 real newF1_(in_Hz_0_for_no_change) 800 real newF2_(in_Hz_0_for_no_change) 2500 real newF3_(in_Hz_0_for_no_change) 3500 comment Resynthesize sound file will have a "resynPreVocalic-" prefix word logFile log-preVocalic.txt endform # Following the Praat manual, LPC prediction order is set to 10 (five formants) lpcPredictionOrder = 10 outputSound$ = "resynPreVocalic-" + inputSound$ fileappend 'logFile$' Filename'tab$'preVocalicOnset'tab$'preVocalicOffset'tab$'location ...'tab$'oldF1'tab$'oldF2'tab$'oldF3'tab$'newF1'tab$'newF2'tab$'newF3'newline$' Read from file... 'inputSound$' # Extract the source Resample... resampleFreq 50 Rename... soundObj To LPC (burg)... lpcPredictionOrder 0.025 0.005 50 Rename... lpcObj plus Sound soundObj Filter (inverse) Rename... sourceObj # Extract the filter (formant tier object) select Sound soundObj To Formant (burg)... 0 5 5500 0.025 50 Down to FormantTier Rename... formantTierObj Copy... copyFormantTierObj # Now, query the formantTier object for the number of indices in between the transition # onset and offset select FormantTier formantTierObj onsetIndex = Get nearest index from time... preVocalicOnset offsetIndex = Get nearest index from time... preVocalicOffset numOfIndices = offsetIndex-onsetIndex # Store the transition formant/bandwidth values into array variables f1, f2, f3/b1, b2, b3 for i from 0 to numOfIndices select FormantTier formantTierObj realIndex = onsetIndex+i timeOfIndex = Get time from index... realIndex f1'i' = Get value at time... 1 timeOfIndex f2'i' = Get value at time... 2 timeOfIndex f3'i' = Get value at time... 3 timeOfIndex b1'i' = Get bandwidth at time... 1 timeOfIndex b2'i' = Get bandwidth at time... 2 timeOfIndex b3'i' = Get bandwidth at time... 3 timeOfIndex # Since the LPC prediction order is 10, we also need information about F4, F5/B4, B5 f4'i' = Get value at time... 4 timeOfIndex f5'i' = Get value at time... 5 timeOfIndex b4'i' = Get bandwidth at time... 4 timeOfIndex b5'i' = Get bandwidth at time... 5 timeOfIndex endfor # Get the transition offset (steady-state vowel onset) formant values. # This is necessary to get the increments for the successive frames in the transition. offsetF1 = f1'numOfIndices' offsetF2 = f2'numOfIndices' offsetF3 = f3'numOfIndices' incrementF1 = (offsetF1-newF1)/numOfIndices incrementF2 = (offsetF2-newF2)/numOfIndices incrementF3 = (offsetF3-newF3)/numOfIndices # Finally, prepare the formant/bandwidth series, i.e. F1 B1 F2 B2 F3 B3 F4 B4 F5 B5 # to be added to the FormantTier object for i from 0 to numOfIndices select FormantTier formantTierObj realIndex = onsetIndex+i timeOfIndex = Get time from index... realIndex # Now, calculate the actual F1/F2/F3 values. The rest, i.e. B1/B2/B3/F4/B4/F5/B5 # stays the same. actualF1 = newF1 + incrementF1 * i actualF2 = newF2 + incrementF2 * i actualF3 = newF3 + incrementF3 * i # Get the formant/bandwidth series for the current index frame f1dummy = f1'i' f2dummy = f2'i' f3dummy = f3'i' f4dummy = f4'i' f5dummy = f5'i' b1dummy = b1'i' b2dummy = b2'i' b3dummy = b3'i' b4dummy = b4'i' b5dummy = b5'i' f1b1$ = "'actualF1'" + " " + "'b1dummy'" f2b2$ = "'actualF2'" + " " + "'b2dummy'" f3b3$ = "'actualF3'" + " " + "'b3dummy'" f4b4$ = "'f4dummy'" + " " + "'b4dummy'" f5b5$ = "'f5dummy'" + " " + "'b5dummy'" formantBandwidthSeries$ = f1b1$ + " " + f2b2$ formantBandwidthSeries$ = formantBandwidthSeries$ + " " + f3b3$ formantBandwidthSeries$ = formantBandwidthSeries$ + " " + f4b4$ formantBandwidthSeries$ = formantBandwidthSeries$ + " " + f5b5$ # Store the whole information into the log file fileappend 'logFile$' 'inputSound$''tab$''preVocalicOnset''tab$''preVocalicOffset' ...'tab$''timeOfIndex''tab$''f1dummy:0''tab$''f2dummy:0''tab$''f3dummy:0''tab$' ...'actualF1:0''tab$''actualF2:0''tab$''actualF3:0''newline$' # Remove the index frame Remove point... realIndex Add point... timeOfIndex 'formantBandwidthSeries$' endfor # Now, resynthesize the source and the modified formant tier object select Sound sourceObj plus FormantTier formantTierObj Filter Rename... resynthesizedObj Write to WAV file... 'outputSound$' # Clean up select Sound soundObj plus LPC lpcObj plus Sound sourceObj plus Formant soundObj plus FormantTier formantTierObj plus FormantTier copyFormantTierObj Remove ################# END OF SCRIPT ###################