Source code for annotations.Align.aligners.basealigner

"""
:filename: sppas.src.annotations.Align.tracksio.py
:author:   Brigitte Bigi
:contact:  develop@sppas.org
:summary:  Base class for any automatic forced alignment system.

.. _This file is part of SPPAS: http://www.sppas.org/
..
    -------------------------------------------------------------------------

     ___   __    __    __    ___
    /     |  \  |  \  |  \  /              the automatic
    \__   |__/  |__/  |___| \__             annotation and
       \  |     |     |   |    \             analysis
    ___/  |     |     |   | ___/              of speech

    Copyright (C) 2011-2021  Brigitte Bigi
    Laboratoire Parole et Langage, Aix-en-Provence, France

    Use of this software is governed by the GNU Public License, version 3.

    SPPAS is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    SPPAS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with SPPAS. If not, see <http://www.gnu.org/licenses/>.

    This banner notice must not be removed.

    -------------------------------------------------------------------------

"""

import os
import shutil
import random
from datetime import date

from sppas.src.config import sppasUnicode

from ..models.acm.tiedlist import sppasTiedList

# ---------------------------------------------------------------------------


[docs]class BaseAligner(object): """Base class for any automatic alignment system. Base class for a system to perform phonetic speech segmentation. """
[docs] def __init__(self, model_dir=None): """Create a BaseAligner instance. :param model_dir: (str) the acoustic model directory name """ if model_dir is not None: if os.path.exists(model_dir) is False: raise IOError("{:s} is not a valid acoustic model directory." "".format(model_dir)) # members self._model = model_dir self._name = "" self._extensions = list() # alignment options self._outext = "" # output file name extension self._phones = "" # string of the phonemes to time-align self._tokens = "" # string of the tokens to time-align
# ------------------------------------------------------------------------ # members # ------------------------------------------------------------------------
[docs] def extensions(self): """Return the list of supported file name extensions.""" return self._extensions
# -----------------------------------------------------------------------
[docs] def name(self): """Return the identifier name of the aligner.""" return self._name
# -----------------------------------------------------------------------
[docs] def outext(self): """Return the extension of output files.""" return self._outext
# ----------------------------------------------------------------------- # alignment options # -----------------------------------------------------------------------
[docs] def add_tiedlist(self, entries): """Add missing triphones/biphones in the tiedlist of the model. Backup the initial file if entries were added. :param entries: (list) List of missing entries into the tiedlist. :returns: list of entries really added """ tied_file = os.path.join(self._model, "tiedlist") if os.path.exists(tied_file) is False: return [] tie = sppasTiedList() tie.read(tied_file) add_entries = tie.add_to_tie(entries) if len(add_entries) > 0: today = str(date.today()) rand_val = str(int(random.random()*10000)) backup_tied_file = os.path.join( self._model, "tiedlist." + today + "." + rand_val) shutil.copy(tied_file, backup_tied_file) tie.save(tied_file) return add_entries
# ------------------------------------------------------------------------
[docs] def set_phones(self, phones): """Fix the pronunciations of each token. :param phones: (str) Phonetization """ phones = sppasUnicode(phones).unicode() self._phones = phones
# ------------------------------------------------------------------------
[docs] def set_tokens(self, tokens): """Fix the tokens. :param tokens: (str) Tokenization """ tokens = sppasUnicode(tokens).unicode() self._tokens = tokens
# -----------------------------------------------------------------------
[docs] def check_data(self): """Check the given data to be aligned (phones and tokens). :returns: A warning message, or an empty string if check is OK. """ if len(self._phones) == 0: raise IOError("No data to time-align.") phones = sppasUnicode(self._phones).to_strip().split() tokens = sppasUnicode(self._tokens).to_strip().split() if len(tokens) != len(phones): message = "Tokens alignment disabled: " \ "not the same number of tokens in tokenization ({:d}) " \ "and phonetization ({:d}).".format(len(self._tokens), len(self._phones)) # assign a "w_" to each phone self._tokens = " ".join(["w_" + str(i) for i in range(len(phones))]) return message return ""
# -----------------------------------------------------------------------
[docs] def run_alignment(self, input_wav, output_align): """Perform forced-alignment. It is expected that the alignment is performed on a file with a size less or equal to a sentence (sentence/IPUs/segment/utterance). The audio file must be of type PCM-WAV 16000 Hz, 16 bits, like in the model. :param input_wav: (str) the audio input file name :param output_align: (str) the output file name :returns: (str) A message of the aligner """ raise NotImplementedError