-
Notifications
You must be signed in to change notification settings - Fork 35
/
praat_features.py
129 lines (117 loc) · 6.36 KB
/
praat_features.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
'''
AAA lllllll lllllll iiii
A:::A l:::::l l:::::l i::::i
A:::::A l:::::l l:::::l iiii
A:::::::A l:::::l l:::::l
A:::::::::A l::::l l::::l iiiiiii eeeeeeeeeeee
A:::::A:::::A l::::l l::::l i:::::i ee::::::::::::ee
A:::::A A:::::A l::::l l::::l i::::i e::::::eeeee:::::ee
A:::::A A:::::A l::::l l::::l i::::i e::::::e e:::::e
A:::::A A:::::A l::::l l::::l i::::i e:::::::eeeee::::::e
A:::::AAAAAAAAA:::::A l::::l l::::l i::::i e:::::::::::::::::e
A:::::::::::::::::::::A l::::l l::::l i::::i e::::::eeeeeeeeeee
A:::::AAAAAAAAAAAAA:::::A l::::l l::::l i::::i e:::::::e
A:::::A A:::::A l::::::ll::::::li::::::ie::::::::e
A:::::A A:::::A l::::::ll::::::li::::::i e::::::::eeeeeeee
A:::::A A:::::A l::::::ll::::::li::::::i ee:::::::::::::e
AAAAAAA AAAAAAAlllllllllllllllliiiiiiii eeeeeeeeeeeeee
| ___| | | / _ \ | ___ \_ _| _
| |_ ___ __ _| |_ _ _ _ __ ___ ___ / /_\ \| |_/ / | | (_)
| _/ _ \/ _` | __| | | | '__/ _ \/ __| | _ || __/ | |
| || __/ (_| | |_| |_| | | | __/\__ \ | | | || | _| |_ _
\_| \___|\__,_|\__|\__,_|_| \___||___/ \_| |_/\_| \___/ (_)
___ _ _
/ _ \ | (_)
/ /_\ \_ _ __| |_ ___
| _ | | | |/ _` | |/ _ \
| | | | |_| | (_| | | (_) |
\_| |_/\__,_|\__,_|_|\___/
This will featurize folders of audio files if the default_audio_features = ['praat_features']
Inspired by https://github.com/drfeinberg/genderless -
Praat features that are not affected by changing genders.
'''
import glob, os, json
import parselmouth
from parselmouth.praat import call
def praat_featurize(voiceID):
voiceID = voiceID
sound = parselmouth.Sound(voiceID) # read the sound
broad_pitch = call(sound, "To Pitch", 0.0, 50, 600) #create a praat pitch object
minF0 = call(broad_pitch, "Get minimum", 0, 0, "hertz", "Parabolic") # get min pitch
maxF0 = call(broad_pitch, "Get maximum", 0, 0, "hertz", "Parabolic") # get max pitch
floor = minF0 * 0.9
ceiling = maxF0 * 1.1
pitch = call(sound, "To Pitch", 0.0, floor, ceiling) # create a praat pitch object
duration = call(sound, "Get total duration") # duration
meanF0 = call(pitch, "Get mean", 0, 0, "hertz") # get mean pitch
stdevF0 = call(pitch, "Get standard deviation", 0 ,0, "hertz") # get standard deviation
harmonicity = call(sound, "To Harmonicity (cc)", 0.01, minF0, 0.1, 1.0)
hnr = call(harmonicity, "Get mean", 0, 0)
pointProcess = call(sound, "To PointProcess (periodic, cc)", minF0, maxF0)
localJitter = call(pointProcess, "Get jitter (local)", 0, 0, 0.0001, 0.02, 1.3)
localabsoluteJitter = call(pointProcess, "Get jitter (local, absolute)", 0, 0, 0.0001, 0.02, 1.3)
rapJitter = call(pointProcess, "Get jitter (rap)", 0, 0, 0.0001, 0.02, 1.3)
ppq5Jitter = call(pointProcess, "Get jitter (ppq5)", 0, 0, 0.0001, 0.02, 1.3)
ddpJitter = call(pointProcess, "Get jitter (ddp)", 0, 0, 0.0001, 0.02, 1.3)
localShimmer = call([sound, pointProcess], "Get shimmer (local)", 0, 0, 0.0001, 0.02, 1.3, 1.6)
localdbShimmer = call([sound, pointProcess], "Get shimmer (local_dB)",
0, 0, 0.0001, 0.02, 1.3, 1.6)
apq3Shimmer = call([sound, pointProcess], "Get shimmer (apq3)", 0, 0, 0.0001, 0.02, 1.3, 1.6)
aqpq5Shimmer = call([sound, pointProcess], "Get shimmer (apq5)", 0, 0, 0.0001, 0.02, 1.3, 1.6)
apq11Shimmer = call([sound, pointProcess], "Get shimmer (apq11)", 0, 0, 0.0001, 0.02, 1.3, 1.6)
ddaShimmer = call([sound, pointProcess], "Get shimmer (dda)", 0, 0, 0.0001, 0.02, 1.3, 1.6)
if meanF0 > 170 and meanF0 < 300:
max_formant = 5500
elif meanF0 <=170:
max_formant = 5000
elif meanF0 >= 300:
max_formant = 8000
formants = call(sound, "To Formant (burg)", 0.0025, 5, max_formant, 0.025, 50)
numPoints = call(pointProcess, "Get number of points")
f1_list = []
f2_list = []
f3_list = []
f4_list = []
# Measure formants only at glottal pulses
for point in range(0, numPoints):
point += 1
t = call(pointProcess, "Get time from index", point)
f1 = call(formants, "Get value at time", 1, t, 'Hertz', 'Linear')
f2 = call(formants, "Get value at time", 2, t, 'Hertz', 'Linear')
f3 = call(formants, "Get value at time", 3, t, 'Hertz', 'Linear')
f4 = call(formants, "Get value at time", 4, t, 'Hertz', 'Linear')
f1_list.append(f1)
f2_list.append(f2)
f3_list.append(f3)
f4_list.append(f4)
f1_list.append(f1)
f2_list.append(f2)
f3_list.append(f3)
f4_list.append(f4)
f1_list = [f1 for f1 in f1_list if str(f1) != 'nan']
f2_list = [f2 for f2 in f2_list if str(f2) != 'nan']
f3_list = [f3 for f3 in f3_list if str(f3) != 'nan']
f4_list = [f4 for f4 in f4_list if str(f4) != 'nan']
# calculate mean formants across pulses
if len(f1_list) > 0:
f1_mean = sum(f1_list) / len(f1_list)
else:
f1_mean = 0
if len(f2_list) > 0:
f2_mean = sum(f2_list) / len(f2_list)
else:
f2_mean = 0
if len(f3_list) > 0:
f3_mean = sum(f3_list) / len(f3_list)
else:
f3_mean = 0
if len(f4_list) > 0:
f4_mean = sum(f4_list) / len(f4_list)
else:
f4_mean = 0
measurements = [duration, meanF0, stdevF0, hnr, localJitter, localabsoluteJitter, rapJitter, ppq5Jitter, ddpJitter,
localShimmer, localdbShimmer, apq3Shimmer, aqpq5Shimmer, apq11Shimmer, ddaShimmer,
f1_mean, f2_mean, f3_mean, f4_mean]
labels=['duration', 'meanF0', 'stdevF0', 'hnr', 'localJitter', 'localabsoluteJitter', 'rapJitter', 'ppq5Jitter', 'ddpJitter',
'localShimmer', 'localdbShimmer', 'apq3Shimmer', 'aqpq5Shimmer', 'apq11Shimmer', 'ddaShimmer', 'f1_mean', 'f2_mean', 'f3_mean', 'f4_mean']
return measurements, labels