Christopher Brown
Christopher Brown

Reputation: 547

Praat: Get formant intensity

I have a praat script that extracts formant information from a folder of wavefiles:

clearinfo

min_f0 = 75
max_f0 = 350

directory$ = "./soundfiles/"
outputDir$ = "./test/"
strings = 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$'
    soundname$ = selected$ ("Sound", 1)
    outputFileName$ = outputDir$ + soundname$ + ".f0123"
    appendInfoLine: outputFileName$
    select Sound 'soundname$'

    formant = To Formant (burg): 0, 4, 5000, 0.025, 50
    formantStep = Get time step

    selectObject: formant
    table = Down to Table: "no", "yes", 6, "yes", 3, "yes", 3, "yes"
    numberOfRows = Get number of rows

    select Sound 'soundname$'
    pitch = To Pitch: 0, min_f0, max_f0

    selectObject: table
    Append column: "Pitch"

    for step to numberOfRows
        selectObject: table
        t = Get value: step, "time(s)"

        selectObject: pitch
        pitchValue = Get value at time: t, "Hertz", "Nearest"

        selectObject: table
        Set numeric value: step, "Pitch", pitchValue
    endfor

    #export to csv
    selectObject: table
    Save as comma-separated file: outputFileName$
    removeObject(table)

    select all
    minus Strings list
    Remove
endfor

select all
Remove
exit

And it generates the following output:

time(s),intensity,nformants,F1(Hz),B1(Hz),F2(Hz),B2(Hz),F3(Hz),B3(Hz),F4(Hz),B4(Hz),Pitch
0.025370,0.000007,3,213.115,14.053,2385.911,791.475,3622.099,677.605,--undefined--,--undefined--,--undefined--
0.031620,0.000007,3,208.843,15.034,2487.710,687.736,3818.027,645.184,--undefined--,--undefined--,197.5315925472943
...

This works great for what I need, but is there a way to get the intensity of each formant as well? Right now I only have the one intensity estimate.

Upvotes: 2

Views: 1935

Answers (2)

jja
jja

Reputation: 2098

I'm not sure if this is what you need, but based on the comment from @nikolay-shmyrev, this is how you'd insert the measurement of formant intensity from Spectrogram objects into your script.

I seem to be inoculated against the pain of scripting using Praat...

I simplified the script below so that it works only on the currently selected Sound object (for testing), and simply kept the generated Table (so you can check it out), but it should point you in the right direction.

form Script...
  positive Minimum_F0 75
  positive Maximum_F0 350
  positive Formants 4
endform

sound = selected("Sound")
pitch = To Pitch: 0, minimum_F0, maximum_F0

# You need this for the intensity
selectObject: sound
spectrogram = To Spectrogram: 0.005, 5000, 0.002, 20, "Gaussian"

selectObject: sound
formant = To Formant (burg): 0, formants, 5000, 0.025, 50

table = Down to Table: "no", "yes", 6, "yes", 3, "yes", 3, "yes"
Append column: "Pitch"

# Insert columns for each formant intensity
# (labeled here as "I#", where # is the formant index)
for f to formants
  index = Get column index: "F" + string$(f) + "(Hz)"
  Insert column: index + 1, "I" + string$(f)
endfor

for row to Object_'table'.nrow
  selectObject: table
  time = Object_'table'[row, "time(s)"]

  # Get the intensity of each formant
  for f to formants
    frequency = Object_'table'[row, "F" + string$(f) + "(Hz)"]

    selectObject: spectrogram
    if frequency != undefined
      intensity = Get power at: time, frequency
    else
      intensity = undefined
    endif

    selectObject: table
    Set string value: row, "I" + string$(f), fixed$(intensity, 3)
  endfor

  selectObject: pitch
  pitchValue = Get value at time: time, "Hertz", "Nearest"

  selectObject: table
  Set string value: row, "Pitch", fixed$(pitchValue, 3)
endfor

removeObject: spectrogram, formant, pitch

Upvotes: 0

Wouter van Nifterick
Wouter van Nifterick

Reputation: 24096

It's an old question, but I'll still respond.

I've ran into this too in 2002, when I was creating an editor for a hardware format synthesizer (FS1R). I used praat to do the wav->format tracks calculation, and the synthesizer expects formant frequencies and intensities as an input.

I've implemented several algorithms for it, but the one that had the most realistic results evaluated the intensity for each formant at each frame in the spectogram.

Here's the code that I've used for that. Keep in mind that it was my goal to get a list of 512 frames with up to 8 freq/intensity pairs, and a fundamental pitch.

# Add to dynamic menu... Sound 1 "" 0 "" 0 "Sine-wave speech" Resample... 1 yourdisk:Praat:scripts:SWS

form Add Sounds
    word wavePath e:\samples\wav\root\
    word waveFile DOUG.wav
    word OutPath e:\samples\wav\root\
    integer minFP 75
    integer maxFP 500
    integer maxFF 5000
    integer Amp_low_pass_freq 50
    integer Formant_low_pass_freq 20
endform


echo Wave to FSeq - FORMANT EXTRACTION
echo -------------------------------------------------------

# LOAD WAVEFILE 
echo loading 'wavePath$''waveFile$'
  Read from file... 'wavePath$''waveFile$'

if numberOfSelected ("Sound") <> 1
    pause Select one Sound then Continue
endif

snd$ = selected$("Sound", 1)
snd = selected("Sound", 1)

sampleRate = Get sample rate
numSamples = Get number of samples
dur = Get duration
zzz = 512/509*512
timeStep = dur/zzz

echo   samplerate        : 'sampleRate' herz
echo   number of samples : 'numSamples'
echo   duration          : 'dur' seconds
echo   timestep          : 'timeStep' seconds
echo 

# GET FUNDAMENTAL PITCH
  echo getting fundamental pitch
#  this was the old method, used until FSeqEdit 1.21:
#  To Pitch... 'timeStep' 'minFP' 'maxFP'
#  Interpolate

# this algorithm seems to work better
  To Pitch (ac)... 'timeStep' 'minFP' 15 no 1e-06 0.1 0.01 1 1 'maxFP'
  Kill octave jumps
  Interpolate
  select Pitch 'snd$'
    Write to short text file... 'outPath$'pitch.txt
  select Pitch 'snd$'
  Remove

# GET VOICED/UNVOICED INFORMATION
  echo getting voiced/unvoiced information
  select Pitch 'snd$'
    To PointProcess
  select PointProcess 'snd$'
    To TextGrid (vuv)... 0.02 'timeStep'    
  select TextGrid 'snd$'
    Write to short text file... 'outPath$'vuv.txt



#create wide-band spectrogram for finding formant amplitudes
# to spectorgam   analwidth maxfreq  timestep freqstep windowshape
echo to spectogram
select 'snd'
To Spectrogram... 0.003 'maxFF' 0.001 40 Gaussian

select 'snd'
echo finding formants
To Formant (burg)... 'timeStep' 8  'maxFF' 0.025 50
Rename... untrack
Track... 6 'maxFP' 'maxFP'*3 'maxFP'*5 'maxFP'*7 'maxFP'*9 1 0.1 1
Rename... 'snd$'
select Formant untrack
Remove

select 'snd'

#start of main formant loop
#===========================
#for each chosen formant turn formant tracks into 
#a Matrix then a Sound object for optional low-pass filtering
#NB this Sound object is the formant TRACK
#then back into a Matrix object for sound synthesis

for i from 1 to 6
  # make a matrix from Fi
  select Formant 'snd$'
  echo extracting formant 'i'   
  To Matrix... 'i'
  Rename... f'i'
    #low-pass filter the  formant track and tidy-up the names
    #filtering needs a Sound object, so cast as Sound, filter and then back to Matrix
    if Formant_low_pass_freq <> 0
      To Sound (slice)... 1
      Filter (pass Hann band)... 0 'formant_low_pass_freq' 'formant_low_pass_freq'
      Down to Matrix
      select Matrix f'i'
      Remove
      select Matrix f'i'_band
      Rename... f'i'
      select Sound f'i'
      plus Sound f'i'_band
      Remove
    endif

    #set up amplitude contour array (sample only at 1kHz) for i'th formant
    #make it a Sound object so that it can be smoothed by filtering

    Create Sound... amp'i' 0 'dur' 1000 sqrt(Spectrogram_'snd$'(x,Matrix_f'i'(x)))

    #smooth out pitch amplitude modulation by low-pass filtering
    if Amp_low_pass_freq <> 0
      Filter (pass Hann band)... 0 'amp_low_pass_freq' 'amp_low_pass_freq'
      select Sound amp'i'
      Remove
      select Sound amp'i'_band
      Rename... amp'i'
    endif

    Extract part... 0 'dur' Rectangular 1 yes
    To Intensity... 'minFP' 0

    Write to short text file... 'outPath$'amp'i'.txt    

    select Matrix f'i'
    Remove

endfor
#===========================
#end of the main formant loop

select Formant 'snd$'
Write to short text file... 'outPath$'formant.txt

#tidy-up
  select Spectrogram 'snd$'
  plus Formant 'snd$'
  plus Pitch 'snd$'
  plus PointProcess 'snd$'
  plus TextGrid 'snd$'
  Remove

echo  
echo -------------------------------------------------------
echo done.

Upvotes: 0

Related Questions