Difference between revisions of "Meas formants"

From Phonlab
Jump to navigationJump to search
m
m
Line 1: Line 1:
<nowiki>meas_formants</nowiki> is a sample script for doing formant analysis on an audio file, reading an associated Praat TextGrid, and extracting formant measurements from vowel tokens. You can copy the script and customize it to your own project.
+
<code>meas_formants</code> is a sample script for doing formant analysis on an audio file, reading an associated Praat TextGrid, and extracting formant measurements from vowel tokens. You can copy the script and customize it to your own project.
   
 
<nowiki>
 
<nowiki>

Revision as of 10:10, 11 February 2014

meas_formants is a sample script for doing formant analysis on an audio file, reading an associated Praat TextGrid, and extracting formant measurements from vowel tokens. You can copy the script and customize it to your own project.

#!/usr/bin/env python

# Measure formants. Read input textgrids, call ifcformant on associated audio file,
# and output measurements to .meas files.

Usage = 'meas_formants speaker file1.TextGrid [file2.TextGrid] ... [fileN.TextGrid]'

import audiolabel
import os, sys, subprocess
import re
import numpy as np

# Do minimal checking to ensure the script was called with appropriate
# arguments.
try:
    if not (sys.argv[1] == 'male' or
            sys.argv[1] == 'female' or
            sys.argv[1] == 'child'): raise
    sys.argv[2] != None
except:
    raise Exception('Usage: ' + Usage)

# Regular expression used to identify vowels.
vre = re.compile(
         "^(?P<vowel>AA|AE|AH|AO|AW|AXR|AX|AY|EH|ER|EY|IH|IX|IY|OW|OY|UH|UW|UX)(?P<stress>\d)?$"
      )

# Mapping of column headings to column formats
fldmap = (
  "t1", "0.4f",
  "t2", "0.4f",
  "lintime", "0.4f",
  "ifctime", "0.4f",
  "idx", "d",
  "vowel", "s",
  "stress", "s",
  "rms", "s",
  "f1", "s",
  "f2", "s",
  "f3", "s",
  "f4", "s",
  "f0", "s",
  "word", "s",
  "context", "s",
)

# The output header line.
head = '\t'.join(fldmap[0:len(fldmap):2]) + '\n'

# Format string used for output.
fmt  = '\t'.join( \
           [ \
               '{' + '{0}:{1}'.format(col,fmt) + '}' \
               for col, fmt in zip( \
                       fldmap[0:len(fldmap):2], \
                       fldmap[1:len(fldmap):2] \
                   ) \
           ] \
       ) + '\n'

# Name to use for ifcformant output file.
tempifc = '__temp.ifc'

speaker = sys.argv[1]

ifc_args = ['ifcformant',
           '--speaker=' + speaker,
           '-e', 'gain -n -3 sinc -t 10 60 contrast',
           '--print-header',
           '--output=' + tempifc]

# Loop over all the input files specified on the command line.
for tg in sys.argv[2:]:
    fname = os.path.splitext(tg)[0]  # get filename without extension
    with open(fname + '.meas', 'w') as out:

        # Praat LabelManager.
        pm = audiolabel.LabelManager(fromFile=tg, fromType='praat')

        # Create ifcformant results and read into ifc LabelManager.
        proc = subprocess.Popen(ifc_args + [fname + '.wav'], stderr=subprocess.PIPE)
        proc.wait()
        if proc.returncode != 0:
            for line in proc.stderr:
                sys.stderr.write(line + '\n')
            raise Exception("ifcformant exited with status: {0}".format(proc.returncode))
        ifc = audiolabel.LabelManager(fromFile=tempifc, fromType='table', t1Col='sec')

        out.write(head)

        # Loop over all the vowel labels in the tier named 'phone'.
        for v, m in pm.tier('phone').search(vre, returnMatch=True):
            if v.duration() > 1 and v.t1() != 0:
                continue

            # Safer to use center of a label as reference point than an edge.
            word = pm.tier('word').labelAt(v.center())
            context = pm.tier('context').labelAt(v.center())

            # Take measurements at start and end of vowel and at five
            # equally-spaced intervals in between them.
            for idx, t in enumerate(np.linspace(v.t1(), v.t2(), num=7)):
                meas = ifc.labelsAt(t)
                out.write(fmt.format(t1=v.t1(), t2=v.t2(), lintime=t, ifctime=meas.f1.t1(),
                                 idx=idx, vowel=m.group('vowel'), stress=m.group('stress'),
                                 rms=meas.rms.text, f1=meas.f1.text,
                                 f2=meas.f2.text, f3=meas.f3.text, f4=meas.f4.text,
                                 f0=meas.f0.text, word=word.text,
                                 context=context.text)
                )
    os.unlink(tempifc)