Skip to content

Instantly share code, notes, and snippets.

@Taekyoon
Created July 21, 2020 08:01
Show Gist options
  • Save Taekyoon/aa8dfe57e592842859da098a975a3204 to your computer and use it in GitHub Desktop.
Save Taekyoon/aa8dfe57e592842859da098a975a3204 to your computer and use it in GitHub Desktop.
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