Source code for polyglotdb.acoustics.formants.base
from conch import analyze_segments
from polyglotdb.acoustics.formants.helper import (
generate_base_formants_function,
generate_formants_point_function,
)
from polyglotdb.acoustics.segments import generate_utterance_segments, generate_vowel_segments
from polyglotdb.acoustics.utils import PADDING
from polyglotdb.exceptions import SpeakerAttributeError
[docs]
def analyze_formant_points(
corpus_context,
call_back=None,
stop_check=None,
vowel_label="vowel",
duration_threshold=None,
multiprocessing=True,
):
"""First pass of the algorithm; generates prototypes.
Parameters
----------
corpus_context : :class:`polyglot.corpus.context.CorpusContext`
The CorpusContext object of the corpus.
call_back : callable
Information about callback.
stop_check : string
Information about stop check.
vowel_label : str
The subset of phones to analyze.
duration_threshold : float, optional
Segments with length shorter than this value (in milliseconds) will not be analyzed.
Returns
-------
dict
Track data
"""
# ------------- Step 1: Prototypes -------------
if not corpus_context.hierarchy.has_type_subset("phone", vowel_label):
raise Exception('Phones do not have a "{}" subset.'.format(vowel_label))
# Gets segment mapping of phones that are vowels
segment_mapping = generate_vowel_segments(
corpus_context,
duration_threshold=duration_threshold,
padding=0.25,
vowel_label=vowel_label,
)
if call_back is not None:
call_back("Analyzing files...")
formant_function = generate_formants_point_function(corpus_context) # Make formant function
output = analyze_segments(
segment_mapping,
formant_function,
stop_check=stop_check,
multiprocessing=multiprocessing,
) # Analyze the phone
return output
[docs]
def analyze_formant_tracks(
corpus_context,
vowel_label=None,
source="praat",
call_back=None,
stop_check=None,
multiprocessing=True,
):
"""
Analyze formants of an entire utterance, and save the resulting formant tracks into the database.
Parameters
----------
corpus_context : CorpusContext
corpus context to use
vowel_label : str, optional
Optional subset of phones to compute tracks over. If None, then tracks over utterances are computed.
call_back : callable
call back function, optional
stop_check : callable
stop check function, optional
"""
if vowel_label is None:
segment_mapping = generate_utterance_segments(corpus_context, padding=PADDING)
else:
if not corpus_context.hierarchy.has_type_subset("phone", vowel_label):
raise Exception('Phones do not have a "{}" subset.'.format(vowel_label))
segment_mapping = generate_vowel_segments(
corpus_context, padding=0, vowel_label=vowel_label
)
if "formants" not in corpus_context.hierarchy.acoustics:
corpus_context.hierarchy.add_acoustic_properties(
corpus_context, "formants", [("F1", float), ("F2", float), ("F3", float)]
)
corpus_context.encode_hierarchy()
segment_mapping = segment_mapping.grouped_mapping("speaker")
if call_back is not None:
call_back("Analyzing files...")
for i, ((speaker,), v) in enumerate(segment_mapping.items()):
gender = None
try:
q = corpus_context.query_speakers().filter(corpus_context.speaker.name == speaker)
q = q.columns(corpus_context.speaker.gender.column_name("Gender"))
gender = q.all()[0]["Gender"]
except SpeakerAttributeError:
pass
if gender is not None:
formant_function = generate_base_formants_function(
corpus_context, gender=gender, source=source
)
else:
formant_function = generate_base_formants_function(corpus_context, source=source)
output = analyze_segments(
v, formant_function, stop_check=stop_check, multiprocessing=multiprocessing
)
corpus_context.save_acoustic_tracks("formants", output, speaker)