Created
July 21, 2020 08:01
-
-
Save Taekyoon/aa8dfe57e592842859da098a975a3204 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import parselmouth | |
import time | |
import concurrent.futures | |
NO_PITCH_VALUE = -999 | |
NO_INTENSITY_VALUE = -999 | |
MIN_PITCH = 75.0 | |
def extract_pitch(path, window_size=0.01): | |
""" | |
:param path: input audio file path, window_size of pitch data | |
:return: a list of tuples, specifying time and corresponding pitch data. | |
Ex: (0.024999999999999963, 292.1824184709096) | |
Pratt Pitch Setting: | |
Pitch range: 75.0 - 600.0 Hz | |
""" | |
snd = parselmouth.Sound(path) | |
pitch = snd.to_pitch(window_size) | |
pitch_values = pitch.selected_array['frequency'] | |
pitch_values[pitch_values == 0] = NO_PITCH_VALUE | |
result = [(i, j) for i, j in zip(pitch.xs(), pitch_values)] | |
return result | |
def extract_intensity(path): | |
""" | |
:param path: input audio file path | |
:return: a list of tuples, specifying time and corresponding intensity data. | |
Ex: (0.024999999999999963, 292.1824184709096) | |
Model Setting: | |
minimum_pitch = 75.0 to align with pitch data | |
""" | |
snd = parselmouth.Sound(path) | |
intensity = snd.to_intensity(minimum_pitch=MIN_PITCH) | |
intensity_values = intensity.values | |
intensity_values[intensity_values == 0] = NO_INTENSITY_VALUE | |
result = [(i, j[0]) for i, j in zip(intensity.xs(), intensity_values.T)] | |
return result | |
def extract_pitch_threading(audio_path, num_thread=4): | |
""" | |
:param audio_path: a list of path for each audio file | |
:param num_thread: default number of threads we are using | |
:return: result is a list of pitch data, one for each file | |
""" | |
result = [] | |
with concurrent.futures.ThreadPoolExecutor(max_workers=num_thread) as executor: | |
start = time.time() | |
pitch_lists = executor.map(extract_pitch, audio_path) | |
for pitch_list in pitch_lists: | |
result.append(pitch_list) | |
end = time.time() | |
print("Extracting Pitch Time Elapsed with Threading: " + str(end - start)) | |
return result | |
def extract_intensity_threading(audio_path_list, num_thread=4): | |
""" | |
:param audio_path_list: a list of path for each audio file | |
:param num_thread: default number of threads we are using | |
:return: result is a list of intensity data, one for each file | |
""" | |
result = [] | |
with concurrent.futures.ThreadPoolExecutor(max_workers=num_thread) as executor: | |
start = time.time() | |
intensity_lists = executor.map(extract_intensity, audio_path_list) | |
for intensity_list in intensity_lists: | |
result.append(intensity_list) | |
end = time.time() | |
print("Extracting Intensity Time Elapsed with Threading: " + str(end - start)) | |
return result | |
def pitch_spectrogram_align_xaxis(path, spectrogram_len, pitch_window=0.0125): | |
""" | |
:param path: path of .wav file | |
:param spectrogram_len: length of the spectrogram that we need to align with | |
:param pitch_window: window size of pitch data | |
:return: pitch data, after aligning with spectrogram | |
""" | |
pitch_list = extract_pitch(path, pitch_window) | |
print("Length of spectrogram: ", spectrogram_len) | |
print("Length of pitch_list before alignment: ", len(pitch_list)) | |
# Check number of missing frames in pitch_list | |
i = 0 | |
while(pitch_list[0][0] > (i+1) * pitch_window): | |
i += 1 | |
# Aligning by appending 0 to the front of pitch_list | |
for add in range(i): | |
pitch_list.insert(0, (pitch_list[0][0] - pitch_window * (add + 1), 0)) | |
# Validate that each frame correspondes to one pitch value | |
while(i < spectrogram_len and i < len(pitch_list)): | |
start = i*pitch_window | |
end = (i + 1)*pitch_window | |
if pitch_list[i][0] < start or pitch_list[i][0] > end: | |
print(False) | |
i += 1 | |
# Aligning by appending 0 to the back of pitch_list | |
last = pitch_list[-1][0] | |
j = 1 | |
while(i < spectrogram_len): | |
pitch_list.append((last + j * pitch_window, 0)) | |
i += 1 | |
j += 1 | |
# Now dimension of pitch_list should align with dimension of matrix columns | |
print("Length of pitch list after alignment: ", len(pitch_list)) | |
print("Pitch list: ", pitch_list) | |
return pitch_list |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment