Extract fundamental frequency (F0 or pitch) using Python


  • tested: Python3.6 on Linux and Mac
  • 2017-09-24 jk

  • Logic:

    • 1) Generate Praat script temporarily within Python script
    • 2) Run the Praat script through Python

Settings


In [1]:
import os
import numpy as np
from subprocess import Popen, PIPE
from sys import platform
import pdb

Main functions


In [2]:
tmp_script = 'tmp.praat'
def gen_script():
    # This generates temporary praat script file
    global tmp_script
    with open(tmp_script, 'w') as f:
        f.write('''
form extract_pitch
text FILENAME
positive TIMEAT 0.0
positive TIMESTEP 0.0
real FLOOR 75.0
real CEILING 600.0
endform
Read from file... 'FILENAME$'
To Pitch... 'TIMESTEP' 'FLOOR' 'CEILING'
Get value at time... 'TIMEAT' Hertz Linear
exit
''')
    return tmp_script
        
def run_praat_cmd(*args):
    # Check operating system
    if platform == 'darwin':  # macOS
        o = Popen(['praat'] + [str(i) for i in args],
                  shell=False, stdout=PIPE, stderr=PIPE)
    else:  # Linux
        o = Popen(['praat', '--run'] + [str(i) for i in args],
                  shell=False, stdout=PIPE, stderr=PIPE)
    stdout, stderr = o.communicate()
    if os.path.exists(tmp_script): 
        os.remove(tmp_script)
    if o.returncode:
        raise Exception(stderr.decode('utf-8'))
    else:
        return stdout
        
def get_pitch(FNAME, TIMEAT, TIMESTEP=0.0, FLOOR=75.0, CEILING=600.0):
    fmt_out = {}
    def _float(s):
        # Retrieved from https://github.com/mwv/praat_formants_python
        try:
            return float(s)
        except ValueError:
            return np.nan
    key = (FNAME, TIMEAT, TIMESTEP, FLOOR, CEILING)
    out = run_praat_cmd(gen_script(), FNAME, TIMEAT, TIMESTEP, FLOOR, CEILING)
    outstr = str(out, 'utf-8').split()
    if len(outstr) < 2:
        print('--undefined--')
        val = 0.0 # pad nan as 0
    else:
        val = float('{:.3f}'.format(float(outstr[0])))
    return val

Run


In [3]:
time = 0.5 # sec
get_pitch('da_ta.wav', time) # output: F0


Out[3]:
118.177