Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/parselmouth fix #85

Open
wants to merge 15 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ docs/_build
*.swp
*.orig
env
dist/*
dist/*
.ipynb_checkpoints/*
34 changes: 18 additions & 16 deletions fave/align/aligner.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from . import transcriptprocessor
from fave import cmudictionary
from fave import praat

import parselmouth

class Aligner():
"""
Expand Down Expand Up @@ -129,21 +129,23 @@ def get_duration(self, FADIR='', PRAATPATH=''):
f.close()
duration = round((nx / sr), 3)
except wave.Error: # wave.py does not seem to support 32-bit .wav files???
self.logger.debug('Script path is %s',os.path.join(
FADIR, "praatScripts", "get_duration.praat"))
if PRAATPATH:
dur_command = "%s %s %s" % (PRAATPATH, os.path.join(
FADIR, "praatScripts", "get_duration.praat"), self.audio)
else:
dur_command = "praat %s %s" % (os.path.join(
FADIR, "praatScripts", "get_duration.praat"), self.audio)
duration = round(
float(
subprocess.Popen(
dur_command,
shell=True,
stdout=subprocess.PIPE).communicate()[0].strip()),
3)
sound = parselmouth.Sound(self.audio)
duration = round(sound.duration, 3)
# self.logger.debug('Script path is %s',os.path.join(
# FADIR, "praatScripts", "get_duration.praat"))
# if PRAATPATH:
# dur_command = "%s %s %s" % (PRAATPATH, os.path.join(
# FADIR, "praatScripts", "get_duration.praat"), self.audio)
# else:
# dur_command = "praat %s %s" % (os.path.join(
# FADIR, "praatScripts", "get_duration.praat"), self.audio)
# duration = round(
# float(
# subprocess.Popen(
# dur_command,
# shell=True,
# stdout=subprocess.PIPE).communicate()[0].strip()),
# 3)

return duration

Expand Down
217 changes: 49 additions & 168 deletions fave/extractFormants.py

Large diffs are not rendered by default.

81 changes: 54 additions & 27 deletions fave/praat.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,57 @@
#
# !!! This is NOT the original praat.py file !!! ##
#
# Last modified by Ingrid Rosenfelder: February 2, 2012 ##
# - comments (all comments beginning with a double pound sign ("##")) ##
# - docstrings for all classes and functions ##
# - read() methods for TextGrid can read both long and short file formats ##
# - formant frames no longer need to have a minimum of x formants (formerly three) ##
# (smoothing routine in extractFormants.py demands equal spacing between frames) ##
# - added Intensity class ##
# - round all times to three digits (i.e. ms) ##
# - improved reading of long TextGrid format ##
#

import parselmouth

class Formant:

"""represents a formant contour as a series of frames"""

def __init__(self, name=None):
def __init__(self, name=None, formant = None, maxFormant = None):
if formant and maxFormant:
if isinstance(formant, parselmouth.Formant):
self.__times = list(formant.ts()) # list of measurement times (frames)
self.__intensities = []
# list of intensities (maximum intensity in each frame)
self.__formants = [[formant.get_value_at_time(formant_number = N, time = T)
for N in (1,2,3) ]
for T in formant.ts()]
# list of formants frequencies (F1-F3, for each frame)
self.__bandwidths = [[formant.get_bandwidth_at_time(formant_number = N, time = T)
for N in (1,2,3)]
for T in formant.ts()]
# list of bandwidths (for each formant F1-F3, for each frame)
# !!! CHANGED: all above lists no longer include frames with only
# a minimum of 2 formant measurements
# !!!
self.__xmin = formant.xmin # start time (in seconds)
self.__xmax = formant.xmax # end time (in seconds)
self.__nx = formant.nx # number of frames
self.__dx = formant.dx # time step = frame duration (in seconds)
self.__x1 = formant.x1 # start time of first frame (in seconds)
self.__maxFormants = maxFormant # maximum number of formants in a frame
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should turn this into a subclass of parselmouth.Formant instead of interfacing like this.

See https://stackoverflow.com/questions/15526858/how-to-extend-a-class-in-python for an example of how to do this.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be rolled out into a separate module, like the praat.Formant and esps.Formant modules are. I'd have to really think about how to make it a real subclass of parselmouth.Formant, since the formant class is written in C++.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm realizing that subclassing isn't going to work well given how the formant class comes to us---we don't create it, rather, it's returned from a function call. I started building a bridge in the most recent commits. See af8f871

else:
self.blanks()
else:
self.blanks()

def blanks(self):
"""empty entries"""
self.__times = [] # list of measurement times (frames)
self.__intensities = []
# list of intensities (maximum intensity in each frame)
self.__formants = []
# list of formants frequencies (F1-F3, for each frame)
self.__bandwidths = []
# list of bandwidths (for each formant F1-F3, for each frame)
# !!! CHANGED: all above lists no longer include frames with only
# a minimum of 2 formant measurements
# !!!
# !!! CHANGED: all above lists no longer include frames with only
# a minimum of 2 formant measurements
# !!!
self.__xmin = None # start time (in seconds)
self.__xmax = None # end time (in seconds)
self.__nx = None # number of frames
self.__dx = None # time step = frame duration (in seconds)
self.__x1 = None # start time of first frame (in seconds)
self.__maxFormants = None # maximum number of formants in a frame


def n(self):
"""returns the number of frames"""
return self.__nx
Expand Down Expand Up @@ -294,15 +311,25 @@ class Intensity:

chrisbrickhouse marked this conversation as resolved.
Show resolved Hide resolved
"""represents an intensity contour"""

def __init__(self):
self.__xmin = None
self.__xmax = None
self.__n = None
self.__nx = None
self.__dx = None
self.__x1 = None
self.__times = []
self.__intensities = []
def __init__(self, intensity = None):
if intensity and isinstance(intensity, parselmouth.Intensity):
self.__xmin = intensity.xmin
self.__xmax = intensity.xmax
self.__n = intensity.nx
self.__nx = intensity.nx
self.__dx = intensity.dx
self.__x1 = intensity.x1
self.__times = list(intensity.ts())
self.__intensities = [intensity.get_value(time = T) for T in intensity.ts()]
else:
self.__xmin = None
self.__xmax = None
self.__n = None
self.__nx = None
self.__dx = None
self.__x1 = None
self.__times = []
self.__intensities = []

def __str__(self):
return '<Intensity object with %i frames>' % self.__n
Expand Down
29 changes: 0 additions & 29 deletions fave/praatScripts/extractFormants.praat

This file was deleted.

12 changes: 0 additions & 12 deletions fave/praatScripts/extractSegment.praat

This file was deleted.

23 changes: 0 additions & 23 deletions fave/praatScripts/getIntensity.praat

This file was deleted.

16 changes: 0 additions & 16 deletions fave/praatScripts/get_duration.praat

This file was deleted.

Loading