2016-10-13 3 views
2

J'ai un script praat qui extrait des informations formants d'un dossier de fichiers Wave:Praat: Obtenez l'intensité formants

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 

Et il génère la sortie suivante:

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 
... 

Cela fonctionne très bien pour ce que je besoin, mais y a-t-il un moyen d'obtenir l'intensité de chaque formant? À l'heure actuelle, je n'ai qu'une seule estimation de l'intensité.

+0

Vous devez obtenir la valeur du spectrogramme au point temps-fréquence correspondant. Le langage de script Praat est si douloureux, donc pas de véritable exemple;) –

+0

Par Intensité de chaque formant, vous voulez dire l'intensité à ce moment particulier, ou cette fréquence particulière ,? et avez-vous trouvé une solution jusqu'à présent? –

+0

zeeshan, je peux obtenir l'information formant en fréquence pour un ensemble donné de bacs de temps. Ce que je veux c'est, pour chaque bin, l'intensité à cette fréquence et à cette unité de temps. Je n'ai pas encore trouvé de solution. Merci. –

Répondre

0

C'est une vieille question, mais je vais quand même répondre.

Je l'ai déjà rencontré en 2002, lorsque je créais un éditeur pour un synthétiseur au format matériel (FS1R). J'ai utilisé praat pour faire le calcul des pistes wav-> format, et le synthétiseur attend les fréquences des formants et les intensités comme une entrée. J'ai implémenté plusieurs algorithmes pour celui-ci, mais celui qui a eu les résultats les plus réalistes a évalué l'intensité de chaque formant à chaque image du spectogramme.

Voici le code que j'ai utilisé pour cela. Gardez à l'esprit que mon objectif était d'obtenir une liste de 512 trames avec jusqu'à 8 paires freq/intensité, et une hauteur fondamentale.

# 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. 
0

Je ne sais pas si c'est ce dont vous avez besoin, mais d'après le commentaire de @ nikolay-shmyrev, c'est comment vous insérez la mesure de l'intensité des formants d'objets spectrogramme dans votre script.

me semble être inoculé contre la douleur de script en utilisant ... Praat

I simplifié le script ci-dessous afin qu'il ne fonctionne que sur l'objet de son sélectionné (pour les tests), et simplement gardé le tableau généré (donc vous pouvez le vérifier), mais il devrait vous diriger dans la bonne 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