Files
2025-09-29 00:52:08 +02:00

70 lines
3.5 KiB
Python
Executable File

# This script will create an analysis actor that outputs curves
# for speech targets with a "Cartoon Coarticulation" model.
# There is no blending between targets, just an immediate ramp
# to the phoneme's mapped value. To use the script, set up your
# mapping from the Mapping tab how you want it, then run this
# script. Save the resulting actor in the "Analysis Actors"
# folder so you can use it as an analysis actor. If you do use
# the resulting analysis actor, make sure the actor you are using
# it on has a blank mapping, otherwise curves will be overdriven
# or overwritten with the default coarticulation results.
from FxStudio import *
import copy
phonemeMap = FxPhonemes.PhonemeMap()
class MappingPhoneme:
def __init__(self, name, visemeTable):
self.visemeTable = copy.deepcopy(visemeTable)
self.name = name
class MappingTable:
def __init__(self):
self.phonemes = []
phonemeMap = FxPhonemes.PhonemeMap()
visemeTable = {}
for entry in phonemeMap.entries:
visemeTable[entry.targetName] = 0
for entry in FxPhonemes.PHONEME_REGISTRY.entries:
self.phonemes.append(MappingPhoneme(entry.facefxCoding, visemeTable))
def addEntry(self, phonemeId, weight, target):
self.phonemes[phonemeId].visemeTable[target] = weight
# Create combiner nodes for all targets in mapping
visemeTable = {}
for entry in phonemeMap.entries:
visemeTable[entry.targetName] = 0
for key in visemeTable.keys():
# Below we assume that no targets are driven below -1000 or above 1000
FxStudio.issueCommand('graph -addnode -nodetype "FxCombinerNode" -name "%s" -max "1000" -min "-1000";'%(key))
# The amount to shoft phonemes by.
timeshift = -.05
issueCommand('animGroup -create -group "_PhonemeEventGroup";');
issueCommand('animGroup -create -group "_NoScalePhonemeEventGroup";');
issueCommand('animGroup -create -group "_ShiftedPhonemeEventGroup";');
for entry in FxPhonemes.PHONEME_REGISTRY.entries:
issueCommand('anim -add -group "_PhonemeEventGroup" -name "%s";'%(entry.facefxCoding))
issueCommand('anim -add -group "_NoScalePhonemeEventGroup" -name "%s";'%(entry.facefxCoding))
issueCommand('anim -add -group "_ShiftedPhonemeEventGroup" -name "%s";'%(entry.facefxCoding))
# Remove Duration Scale
issueCommand('event -group "_PhonemeEventGroup" -anim "%s" -add -eventgroup "_NoScalePhonemeEventGroup" -eventanim "%s" -inheritdur "false";' % (entry.facefxCoding, entry.facefxCoding));
# Shift by timeshift. Use a very small duration so the phoneme transitions are instantaneous.
issueCommand('event -group "_NoScalePhonemeEventGroup" -anim "%s" -add -eventgroup "_ShiftedPhonemeEventGroup" -persist "true" -eventanim "%s" -duration ".001" -start %f' % (entry.facefxCoding, entry.facefxCoding, timeshift));
mapping = MappingTable()
for entry in phonemeMap.entries:
mapping.addEntry(entry.phonemeId, entry.mappingAmount, entry.targetName)
for phoneme in mapping.phonemes:
for key in phoneme.visemeTable.keys():
selectAnimation("_ShiftedPhonemeEventGroup", phoneme.name);
issueCommand('curve -group "_ShiftedPhonemeEventGroup" -anim "%s" -add -name "%s" -owner "user";'%(phoneme.name, key))
issueCommand('select -type "curve" -names "%s";'%(key))
issueCommand('key -insert -default -time "0" -value "%f";'%(phoneme.visemeTable[key]))
issueCommand('key -insert -default -time "1" -value "%f";'%(phoneme.visemeTable[key]))