Automate Lip-sync in Blender using Python!

Опубликовано: 20 Июль 2026
на канале: MiniMart3D
58
6

Learn how to use Python and cmusphinx/pocketsphinx to create a speech to animation system in Blender!

Feel free to ask me any questions about the project! I'd be happy to help with any issues!


YouTube wouldn't let me include the code while there was a angled bracket. If you copy the code below make sure you replace the unicode bracket I used with an actual bracket for this line - (if seg.end_frame>frame_end:).

Also make sure to update the directories to reflect your install locations.

MAIN PYTHON CODE BEGINS BELOW

import pyaudio
from pocketsphinx import Decoder, Config
import os


Model = r"C:/Users/USER/Documents/cmusphinx/cmusphinx-en-us-5.2"

#Lookup table for phonemes to visemes
phoneme_to_viseme = {
"AA" : "AEI" , "AE" : "AEI" , "AO" : "AEI", "AW" : "AEI", "AY" : "AEI", "EH" : "AEI", "ER" : "AEI", "EY" : "AEI", "IH" : "AEI", "IY" : "AEI",
"AH" : "UHHAH" , "HH" : "UHHAH",
"B" : "BMP" , "M" : "BMP", "P" : "BMP", "SIL" : "BMP",
"CH" : "CHJSH", "JH" : "CHJSH", "SH" : "CHJSH",
"D" : "DGKN", "G" : "DGKN", "K" : "DGKN", "N" : "DGKN", "NG" : "DGKN", "S" : "DGKN", "T" : "DGKN", "Y" : "DGKN", "Z" : "DGKN", "ZH" : "DGKN",
"F" : "FV", "V" : "FV",
"L" : "L",
"OW" : "O", "OY" : "O",
"R" : "R",
"TH" : "TH",
"UH" : "UHHAH",
"UW" : "OOUUW", "W" : "OOUUW"
}

#Set up the model
config = Config()

config.set_string("-lm", None)
config.set_string("-dict", None)
config.set_string("-jsgf", None)
config.set_string("-fsg", None)
config.set_string("-keyphrase", None)
config.set_string("-kws", None)
config.set_string("-lmctl", None)

config.set_string("-hmm", os.path.join(Model, "cmusphinx-en-us-5.2"))
config.set_string("-allphone", "en-us-phone.lm.dmp")


#Adjust cmusphinx
config.set_float("-lw", 2.0)
config.set_float("-beam", 1e-20)
config.set_float("-pbeam", 1e-20)

#Set Decoder to config specs
decoder = Decoder(config)

#Open incoming mic, start the stream for decoding
audiostream = pyaudio.PyAudio()
stream = audiostream.open(format = pyaudio.paInt16, channels = 1, rate = 16000, input=True, output = True, frames_per_buffer = 1024)
stream.start_stream()
decoder.start_utt()

print("debug_begin")


frame_end = 0

#Main loop
while True:
buf = stream.read(1024, exception_on_overflow=False)
if buf:
decoder.process_raw(buf, False, False)

#Detect phoneme segment
segments = decoder.seg()
if segments is not None:
for seg in segments:
#Stop from repeating segment output
if seg.end_frame> frame_end:
#Lookup corresponding viseme
phoneme = seg.word
viseme = phoneme_to_viseme.get(phoneme, "BMP")
print(viseme)

#Write current viseme to text
with open("current_viseme.txt", "w") as f:
f.write(viseme)

frame_end = seg.end_frame

else:
break
decoder.end_utt()

END OF MAIN PYTHON SCRIPT

BLENDER PYTHON SCRIPT BEGINS BELOW

import bpy
import os

obj = bpy.data.objects["Mouth"]
keys = obj.data.shape_keys.key_blocks


def update_viseme(scene):
try:
with open(r"C:\Users\USER\Documents\current_viseme.txt") as f:
viseme = f.read().strip()
print(viseme)
for key in keys:
key.value = 0.0
key.keyframe_insert(data_path='value', frame=bpy.context.scene.frame_current)
if viseme in keys:
keys[viseme].value = 1.0
keys[viseme].keyframe_insert(data_path='value', frame=bpy.context.scene.frame_current)
else:
print("viseme missing", viseme)

except:
pass



bpy.app.handlers.frame_change_pre.clear()
bpy.app.handlers.frame_change_pre.append(update_viseme)