SPPAS integration of the automatic Formants estimator on intervals.
Estimate the formants of the center of segments, i.e. phonemes.

SPPAS integration of the automatic Formants estimator on intervals.
Estimate the formants of the center of segments, i.e. phonemes.
Create a new sppasRMS instance.
def __init__(self, log=None):
"""Create a new sppasRMS instance.
:param log: (sppasLog) Human-readable logs.
"""
super(sppasFormants, self).__init__('formants.json', log)
self.__estimator = FormantsEstimator()
Fix all options.
def fix_options(self, options):
"""Fix all options.
:param options: (sppasOption)
"""
for opt in options:
key = opt.get_key()
if 'threshold' == key:
self.set_threshold(opt.get_value())
elif 'win_length' == key:
self.set_win_length(opt.get_value())
elif 'order' == key:
self.set_lpc_order(opt.get_value())
elif 'floor_freq' == key:
self.set_floor_frequency(opt.get_value())
elif 'praat_max_freq' == key:
self.set_praat_max_freq(opt.get_value())
elif 'output_type' == key:
self.set_output_type(opt.get_value())
elif key in self.__estimator.get_available_method_names():
self.__estimator.enable_method(key, opt.get_value())
elif 'pattern' in key:
self._options[key] = opt.get_value()
else:
raise AnnotationOptionError(key)
def get_threshold(self) -> float:
return self._options['threshold']
def get_win_length(self) -> float:
return self._options['win_length']
def get_lpc_order(self) -> int:
return self._options['lpc_order']
def get_floor_freq(self) -> float:
return self._options['floor_freq']
def get_praat_max_freq(self) -> float:
return self._options['praat_max_freq']
Return the list of active method names.
def get_enabled_method_names(self) -> tuple:
"""Return the list of active method names.
:return: (tuple) Names of the currently selected methods
"""
return self.__estimator.get_enabled_method_names()
Set the RMS threshold value: 0 for automatic.
def set_threshold(self, value: int):
"""Set the RMS threshold value: 0 for automatic.
:param value: (int) RMS value used as volume threshold
:raises: TypeError: Given value is not an integer.
:raises: ValueError: Given value must be between a positive integer.
"""
self.__estimator.set_rms_threshold(value)
self._options['threshold'] = value
Set a new length of window for the estimation of formant values.
def set_win_length(self, value: float):
"""Set a new length of window for the estimation of formant values.
:param value: (float) Hamming window duration in seconds.
:raises: TypeError: Given value is not a number.
:raises: ValueError: Given value must range 0.01 - 0.1.
"""
self.__estimator.set_win_dur(value)
self._options['win_length'] = value
Set the LPC order.
def set_lpc_order(self, value: int) -> None:
"""Set the LPC order.
:param value: (int) Order value, between 6 and samplerate/100
:raises: TypeError: Given value is not an integer.
"""
self.__estimator.set_order(value)
self._options['lpc_order'] = value
Set the minimum frequency to consider for formants.
def set_floor_frequency(self, value: float) -> None:
"""Set the minimum frequency to consider for formants.
:param value: (float)
:raises: TypeError: Given value is not a number.
:raises: ValueError: Given value must be between 50 and 500.
"""
self.__estimator.set_floor_frequency(value)
self._options['floor_freq'] = value
Set the highest frequency the Praat-based methods are analyzing.
def set_praat_max_freq(self, value: float) -> None:
"""Set the highest frequency the Praat-based methods are analyzing.
:param value: (float) Frequency in Hz, ranging 1000 - 10000
:raises: TypeError: Given value is not a number.
:raises: ValueError: Given value is out of range.
"""
self.__estimator.set_max_freq(value)
self._options['praat_max_freq'] = float(value)
Set the type of output, among center, mean or all.
def set_output_type(self, value: str) -> None:
"""Set the type of output, among center, mean or all.
:param value: (str) One of the expected output type
:raises: ValueError: if out_type is invalid.
"""
self.__estimator.set_output_type(value)
Return the audio filename and the tier with time-aligned phonemes.
NoTierInputError
def get_inputs(self, input_files: list) -> tuple:
"""Return the audio filename and the tier with time-aligned phonemes.
:param input_files: (list)
:raise: NoTierInputError
:return: (str, sppasTier)
"""
ext = self.get_input_extensions()
audio_ext = ext[0]
annot_ext = ext[1]
tier = None
audio_filename = None
for filename in input_files:
fn, fe = os.path.splitext(filename)
if audio_filename is None and fe in audio_ext:
audio_speech = audioopy.aio.open(filename)
n = audio_speech.get_nchannels()
audio_speech.close()
if n != 1:
logging.error('An audio file with only one channel was expected.')
raise NoChannelInputError()
audio_filename = filename
elif tier is None and fe in annot_ext:
parser = sppasTrsRW(filename)
trs_input = parser.read()
tier = sppasFindTier.aligned_phones(trs_input)
if tier is None:
logging.error('A tier with time-aligned phonemes was not found in the given files: {:s}.'.format(str(input_files)))
raise NoTierInputError
if tier.is_interval() is False:
logging.error('The tier should be of type: Interval.')
raise AnnDataTypeError(tier.get_name(), 'IntervalTier')
if tier.is_empty() is True:
raise EmptyInputError(tier.get_name())
extm = os.path.splitext(audio_filename)[1].lower()[1:]
media = sppasMedia(os.path.abspath(audio_filename), mime_type='audio/' + extm)
tier.set_media(media)
return (audio_filename, tier)
Run the automatic annotation process on an input.
Input file is a tuple with 2 files: the audio file and the annotation file
def run(self, input_files, output=None):
"""Run the automatic annotation process on an input.
Input file is a tuple with 2 files:
the audio file and the annotation file
:param input_files: (list of str) (audio, time-aligned phonemes)
:param output: (str) the output name
:return: (sppasTranscription)
"""
audio_filename, tier = self.get_inputs(input_files)
tiers = self.__estimator.estimate(audio_filename, tier)
trs_output = sppasTranscription(self.name)
trs_output.set_meta('annotation_result_of', input_files[0])
for formant_tier in tiers:
trs_output.append(formant_tier)
if output is not None:
if len(trs_output) > 0:
output_file = self.fix_out_file_ext(output)
parser = sppasTrsRW(output_file)
parser.write(trs_output)
return [output_file]
else:
raise EmptyOutputError
return trs_output
Pattern this annotation uses in an output filename.
def get_output_pattern(self):
"""Pattern this annotation uses in an output filename."""
return self._options.get('outputpattern', '-formants')
Pattern this annotation expects for its input filename.
def get_input_patterns(self):
"""Pattern this annotation expects for its input filename."""
return [self._options.get('inputpattern1', ''), self._options.get('inputpattern2', '-palign')]
Extensions that the annotation expects for its input filename.
@staticmethod
def get_input_extensions():
"""Extensions that the annotation expects for its input filename."""
return [sppasFiles.get_informat_extensions('AUDIO'), sppasFiles.get_informat_extensions('ANNOT_ANNOT')]