Skip to content

viseme_generator

Generate Visemes from text.

This module converts text to phonemes and then phonemes to visemes.

VisemeGenerator

Contains the functionality to convert text to visemes

Or to convert between viseme types

Source code in backend/app/utils/tts/backends/viseme_generator.py
class VisemeGenerator:
    """Contains the functionality to convert text to visemes

    Or to convert between viseme types
    """

    def __init__(self, convertion_table="./resources/.phoneme-viseme_map.csv", log=False) -> None:

        self.log = log
        self.path = Path(__file__).parent
        conversion_table_path = os.path.join(self.path, convertion_table)

        self.backend = EspeakBackend('en-us', preserve_punctuation=True, with_stress=False)

        self.joint_df = pd.read_csv(conversion_table_path, header=0)
        self.joint_df.set_index("IPA")

    def get_viseme(self, ipa, type='IPA'):
        """Converts individual phoneme to a viseme"""
        try:
            viseme_dict = self.joint_df[self.joint_df[type]==ipa]
            if len(viseme_dict) < 1:
                viseme_dict = self.joint_df[self.joint_df['Alternative IPA'] == ipa]
                if len(viseme_dict) < 1:
                    if self.log:
                        print(f"Viseme for: {ipa} NOT FOUND")
            viseme = viseme_dict["SimpleViseme"].values[0]
        except Exception as exc:
            print(exc)
            viseme = "IDLE"
        return viseme

    def process_phoneme_string(self, phonemes_string):
        """Converts phoneme string to list

        Handles a bug with a special character as well
        """
        phoneme_list = []
        for phoneme in phonemes_string:
            if phoneme != "ː":
                phoneme_list.append(phoneme)
            else:
                phoneme_list[-1] = phoneme_list[-1] + "ː"
                                    # note this is a special character, not a colon
        if self.log:
            print(phoneme_list)
        return phoneme_list

    def convert_aws_visemes(self, visemes):
        new_visemes = []
        for vis in visemes:
            new_visemes.append(self.get_viseme(vis, type="Viseme"))
        return new_visemes

    def get_visemes(self, sentence, return_phonemes = False):
        """Process a sentence or list of sentences into visemes"""
        if isinstance(sentence, str):
            sentence = [sentence]
        if self.log:
            print(f"String to process: {sentence}")
        phonemized = self.backend.phonemize(sentence, strip=False)[0]
        if self.log:
            print(f"Phonemes: {phonemized}")
        phoneme_list = self.process_phoneme_string(phonemized) + [' ']
        visemes_list = []
        for phoneme in phoneme_list:
            vis = self.get_viseme(phoneme)
            if vis == "IDLE":# Append Idles twice to give better pauses
                visemes_list.append(vis)
            visemes_list.append(vis)

        if return_phonemes:
            return visemes_list, phoneme_list
        return visemes_list

get_viseme(ipa, type='IPA')

Converts individual phoneme to a viseme

Source code in backend/app/utils/tts/backends/viseme_generator.py
def get_viseme(self, ipa, type='IPA'):
    """Converts individual phoneme to a viseme"""
    try:
        viseme_dict = self.joint_df[self.joint_df[type]==ipa]
        if len(viseme_dict) < 1:
            viseme_dict = self.joint_df[self.joint_df['Alternative IPA'] == ipa]
            if len(viseme_dict) < 1:
                if self.log:
                    print(f"Viseme for: {ipa} NOT FOUND")
        viseme = viseme_dict["SimpleViseme"].values[0]
    except Exception as exc:
        print(exc)
        viseme = "IDLE"
    return viseme

get_visemes(sentence, return_phonemes=False)

Process a sentence or list of sentences into visemes

Source code in backend/app/utils/tts/backends/viseme_generator.py
def get_visemes(self, sentence, return_phonemes = False):
    """Process a sentence or list of sentences into visemes"""
    if isinstance(sentence, str):
        sentence = [sentence]
    if self.log:
        print(f"String to process: {sentence}")
    phonemized = self.backend.phonemize(sentence, strip=False)[0]
    if self.log:
        print(f"Phonemes: {phonemized}")
    phoneme_list = self.process_phoneme_string(phonemized) + [' ']
    visemes_list = []
    for phoneme in phoneme_list:
        vis = self.get_viseme(phoneme)
        if vis == "IDLE":# Append Idles twice to give better pauses
            visemes_list.append(vis)
        visemes_list.append(vis)

    if return_phonemes:
        return visemes_list, phoneme_list
    return visemes_list

process_phoneme_string(phonemes_string)

Converts phoneme string to list

Handles a bug with a special character as well

Source code in backend/app/utils/tts/backends/viseme_generator.py
def process_phoneme_string(self, phonemes_string):
    """Converts phoneme string to list

    Handles a bug with a special character as well
    """
    phoneme_list = []
    for phoneme in phonemes_string:
        if phoneme != "ː":
            phoneme_list.append(phoneme)
        else:
            phoneme_list[-1] = phoneme_list[-1] + "ː"
                                # note this is a special character, not a colon
    if self.log:
        print(phoneme_list)
    return phoneme_list

main()

Integration testing for viseme generator

Source code in backend/app/utils/tts/backends/viseme_generator.py
def main():
    """Integration testing for viseme generator"""
    text = ["Hello, world! Welcome to the arena?"]
    gen = VisemeGenerator()
    visemes,phonemes = gen.get_visemes(text, True)

    print(len(visemes), len(phonemes))
    min_phone_vis = min(len(visemes),len(phonemes))
    for i in range(min_phone_vis):
        print(i, phonemes[i], visemes[i])