|
import soundfile as sf |
|
import numpy as np |
|
from scipy import signal |
|
from pydub import AudioSegment |
|
import subprocess |
|
import os |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def reaper_soundfile(sound_path, orig_filetype): |
|
|
|
aud_data = AudioSegment.from_file(sound_path, orig_filetype) |
|
curdir = subprocess.run(["pwd"], capture_output=True, text=True) |
|
curdir = curdir.stdout.splitlines()[0] |
|
fname = sound_path.split('/')[-1].replace(orig_filetype,'') |
|
tmp_path = f'{curdir}/files_tmp/{fname}tmp.wav' |
|
if not os.path.exists(f'{curdir}/files_tmp'): |
|
os.mkdir(f'{curdir}/files_tmp') |
|
aud_data.export(tmp_path, format="wav") |
|
wav_path = tmp_path |
|
|
|
return wav_path |
|
|
|
|
|
|
|
|
|
def get_reaper(wav_path, reaper_path, maxf0='700', minf0='50'): |
|
|
|
f0_data = subprocess.run([reaper_path, "-i", wav_path, '-f', '/dev/stdout', '-x', maxf0, '-m', minf0, '-a'],capture_output=True).stdout |
|
f0_data = f0_data.decode() |
|
f0_data = f0_data.split('EST_Header_End\n')[1].splitlines() |
|
f0_data = [l.split(' ') for l in f0_data] |
|
f0_data = [l for l in f0_data if len(l) == 3] |
|
f0_data = [ [float(t), float(f), float(v)] for t,v,f in f0_data] |
|
|
|
return f0_data |
|
|
|
|
|
|
|
|
|
|
|
def save_pitch(f0_data, save_path,hed=False): |
|
with open(save_path,'w') as handle: |
|
if hed: |
|
handle.write('TIME\tF0\tVOICED\n') |
|
handle.write(''.join([f'{t}\t{f}\t{v}\n' for t,f,v in f0_data])) |
|
|
|
|
|
|
|
def estimate_pitch(sound_path,reaper_path = "REAPER/build/reaper"): |
|
|
|
orig_ftype = sound_path.split('.')[-1] |
|
if orig_ftype == 'wav': |
|
wav_path = sound_path |
|
else: |
|
tmp_path = reaper_soundfile(sound_path, orig_ftype) |
|
wav_path = tmp_path |
|
|
|
|
|
|
|
first_pass = get_reaper(wav_path,reaper_path) |
|
first_pass = [f for t,f,v in first_pass if float(v) ==1] |
|
|
|
q1 = np.quantile(first_pass,0.25) |
|
q3 = np.quantile(first_pass,0.75) |
|
|
|
pfloor = 0.75 * q1 |
|
pceil = 1.5 * q3 |
|
|
|
second_pass = get_reaper(wav_path,reaper_path, maxf0 = str(round(pceil)), minf0 = str(round(pfloor))) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return second_pass |
|
|
|
|