#------------------------------------------------------------------------------- # Create a partial analysis actor based on the Massaro-Cohen model of # coarticulation. Massaro-Cohen uses a dominance function to represent the # dominance of a given phoneme over a particular speech parameter. These # dominance functions, in conjunction with the target value for a given phoneme # over a particular speech parameter, provide a smooth curve for the given # speech parameter. # # Owner: John Briggs # # Copyright (c) 2002-2011 OC3 Entertainment, Inc. #------------------------------------------------------------------------------- from FxStudio import * from FxGestureShared import * import copy import math # A modified version of the Anim class in FxGestureShared class MCAnim(Anim): def buildAnim(self): count = 0 for curve in self.curves: issueCommand('curve -group "%s" -anim "%s" -add -name "%s" -owner "user";'%(self.group, self.name, curve.name)) issueCommand('select -type "animgroup" -names "%s";'%(self.group)) issueCommand('select -type "anim" -names "%s";'%(self.name)) issueCommand('select -type "curve" -names "%s";'%(curve.name)) issueCommand('batch') for key in curve.keys: issueCommand('key -insert -curveIndex "%d" -index -time "%s" -value "%s" -slopeIn "%s" -slopeOut "%s";'%(count, key.time, key.value, key.slopein, key.slopeout)); count += 1 issueCommand('execBatch -changedanim') for event in self.events: if self.groupChildEvents == "false": issueCommand('event -group "%s" -anim "%s" -add -eventgroup "%s" -eventanim "%s" -persist "%s" -inheritmag "%s" -inheritdur "%s" -probability "%f" -minstart "%f" -maxstart "%f" -minduration "%f" -maxduration "%f" -minmagnitude "%f" -maxmagnitude "%f" -minblendin "%f" -maxblendin "%f" -minblendout "%f" -maxblendout "%f";'%(self.group, self.name, event.group, event.name, event.persist, event.inheritmag, event.inheritdur, event.probability, event.minstart, event.maxstart, event.minduration, event.maxduration, event.minmagnitude, event.maxmagnitude, event.minblendin, event.maxblendin, event.minblendout, event.maxblendout)) if self.groupChildEvents != "false": issueCommand('event -group "%s" -anim "%s" -add -eventgroup "%s" -eventanim "%s" -persist "%s" -inheritmag "%s" -inheritdur "%s" -weight "%f" -probability "%f" -minstart "%f" -maxstart "%f" -minduration "%f" -maxduration "%f" -minmagnitude "%f" -maxmagnitude "%f" -minblendin "%f" -maxblendin "%f" -minblendout "%f" -maxblendout "%f";'%(self.group, self.name, event.group, event.name, event.persist, event.inheritmag, event.inheritdur, event.weight, event.probability, event.minstart, event.maxstart, event.minduration, event.maxduration, event.minmagnitude, event.maxmagnitude, event.minblendin, event.maxblendin, event.minblendout, event.maxblendout)) class MCEvent(Event): def __init__(self, animName, animGroup, durationScale = 1, magnitudeScale = 1): Event.__init__(self, animName, animGroup, durationScale, magnitudeScale) self.inheritdur = "false" #----------------------------------------------------------------------------- # Massaro-Cohen specific structures #----------------------------------------------------------------------------- class MCData: def __init__(self, magnitude, rate, rate_str, target, offset = None): self.magnitude = magnitude self.rate_in = rate self.rate_out = rate self.duration_scale = 1.0 self.target = target if offset is None: offset = 0.5 self.offset = offset try: self.duration_scale = { 'jaw_vclo' : 0.35, 'jaw_clos' : 0.47, 'jaw_medi' : 0.60, 'jaw_dist' : 0.75, 'jaw_vdis' : 0.90, 'lip_vclo' : 0.30, 'lip_clos' : 0.45, 'lip_medi' : 0.65, 'lip_dist' : 0.80, 'lip_vdis' : 1.00, 'tng_vclo' : 0.25, 'tng_clos' : 0.35, 'tng_medi' : 0.50, 'tng_dist' : 0.75, 'tng_vdis' : 0.80 }[rate_str] except KeyError: self.duration_scale = 1.0 def __str__(self): return '[mag: %f rate_in: %f rate_out %f target %f]' % (self.magnitude, self.rate_in, self.rate_out, self.target) def __repr__(self): return '%s[mag: %f rate_in: %f rate_out %f target %f]' % (self.__class__.__name__, self.magnitude, self.rate_in, self.rate_out, self.target) def calc_dominance_value(self, time): if time < 0: rate = self.rate_in elif time >= 0: rate = self.rate_out return self.magnitude * math.pow(math.e, -rate * math.fabs(time)) def calc_scaled_dominance_value(self, time): return self.calc_dominance_value(time) * self.target def calc_slope_in(self, time): if time <= 0: rate = self.rate_in flip = -1 elif time > 0: rate = self.rate_out flip = 1 return flip * -self.magnitude * rate * math.pow(math.e, -rate * math.fabs(time)) def calc_slope_out(self, time): if time < 0: rate = self.rate_in flip = -1 elif time >= 0: rate = self.rate_out flip = 1 return flip * -self.magnitude * rate * math.pow(math.e, -rate * math.fabs(time)) #----------------------------------------------------------------------------- # Utility functions #----------------------------------------------------------------------------- # frange, from the Python Cookbook def frange(start, end=None, inc=1.0): "A range-like function that accepts float increments..." if end == None: end = start + 0.0 # Ensure a float value for 'end' start = 0.0 assert inc # sanity check L = [] while 1: next = start + len(L) * inc if inc > 0 and next >= end: break elif inc < 0 and next <= end: break L.append(next) return L #------------------------------------------------------------------------------ # Constants #------------------------------------------------------------------------------ # Dominance array. # least dominant <--------------------> most dominant d = (0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1) # Rate array. # fastest <-------------------------------> slowest r = [50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150] global_mod = 0.30 jaw_vclo = 140 * global_mod jaw_clos = 120 * global_mod jaw_medi = 110 * global_mod jaw_dist = 95 * global_mod jaw_vdis = 85 * global_mod lip_vclo = 125 * global_mod lip_clos = 110 * global_mod lip_medi = 95 * global_mod lip_dist = 80 * global_mod lip_vdis = 65 * global_mod tng_vclo = 110 * global_mod tng_clos = 100 * global_mod tng_medi = 80 * global_mod tng_dist = 65 * global_mod tng_vdis = 50 * global_mod # Target array. # min <-----------------------------------------> max t = (0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1) # Target names jaw_open = '_jaw_open' lip_round_compression = '_lip_round_compression' lip_round_protrusion = '_lip_round_protrusion' lip_press_together = '_lip_press_together' lower_lip_f_tuck = '_lower_lip_f_tuck' lip_stretch = '_lip_stretch' tongue_to_back = '_tongue_to_back' tongue_to_roof = '_tongue_to_roof' tongue_to_teeth = '_tongue_to_teeth' # Modifiers scaled = '_scaled' sum = '_sum' spawned = '_spawned' targetList = (jaw_open, lip_round_compression, lip_round_protrusion, lip_press_together, lower_lip_f_tuck, lip_stretch, tongue_to_back, tongue_to_roof, tongue_to_teeth) finalTargetList = (('open', jaw_open + sum), ('W', lip_round_compression + sum), ('ShCh', lip_round_protrusion + sum), ('PBM', lip_press_together + sum), ('FV', lower_lip_f_tuck + sum), ('wide', lip_stretch + sum), ('tBack', tongue_to_back + sum), ('tRoof', tongue_to_roof + sum), ('tTeeth', tongue_to_teeth + sum)) nodesToCreate = ( (jaw_open, jaw_open + scaled, jaw_open + sum), (lip_round_compression, lip_round_compression + scaled, lip_round_compression + sum), (lip_round_protrusion, lip_round_protrusion + scaled, lip_round_protrusion + sum), (lip_press_together, lip_press_together + scaled, lip_press_together + sum), (lower_lip_f_tuck, lower_lip_f_tuck + scaled, lower_lip_f_tuck + sum), (lip_stretch, lip_stretch + scaled, lip_stretch + sum), (tongue_to_back, tongue_to_back + scaled, tongue_to_back + sum), (tongue_to_roof, tongue_to_roof + scaled, tongue_to_roof + sum), (tongue_to_teeth, tongue_to_teeth + scaled, tongue_to_teeth + sum) ) # Anim group names phonemeEventGroup = '_PhonemeEventGroup' spawnedPhonemeEventGroup = '_DominanceFunctions' # Data blocks should be grouped by phoneme. PhonemeDict = dict() # We'll create an animation for each phoneme which contains the dominance # curves for each target. # SIL - silence. SIL_Data = dict() SIL_Data[jaw_open] = MCData(d[10], jaw_vdis, 'jaw_vdis', t[0]) SIL_Data[lip_round_compression] = MCData(d[10], lip_vdis, 'lip_vdis', t[0]) SIL_Data[lip_round_protrusion] = MCData(d[10], lip_vdis, 'lip_vdis', t[0]) SIL_Data[lip_press_together] = MCData(d[10], lip_vdis, 'lip_vdis', t[0]) SIL_Data[lower_lip_f_tuck] = MCData(d[10], lip_vdis, 'lip_vdis', t[0]) SIL_Data[lip_stretch] = MCData(d[10], lip_vdis, 'lip_vdis', t[0]) SIL_Data[tongue_to_back] = MCData(d[9], tng_vdis, 'tng_vdis', t[0]) SIL_Data[tongue_to_roof] = MCData(d[9], tng_vdis, 'tng_vdis', t[0]) SIL_Data[tongue_to_teeth] = MCData(d[9], tng_vdis, 'tng_vdis', t[0]) PhonemeDict['SIL'] = SIL_Data # P - bilabial voiceless plosive /p/rint, s/p/in P_Data = dict() P_Data[jaw_open] = MCData(d[10], jaw_medi, 'jaw_medi', t[0], 0.1) P_Data[lip_round_compression] = MCData(d[3], lip_clos, 'lip_clos', t[0]) P_Data[lip_round_protrusion] = MCData(d[3], lip_clos, 'lip_clos', t[0]) P_Data[lip_press_together] = MCData(d[8], lip_medi, 'lip_medi', t[8], 0.1) P_Data[lower_lip_f_tuck] = MCData(d[3], lip_clos, 'lip_clos', t[0]) P_Data[lip_stretch] = MCData(d[5], lip_clos, 'lip_clos', t[0]) P_Data[tongue_to_back] = MCData(d[3], tng_vclo, 'tng_vclo', t[0]) P_Data[tongue_to_roof] = MCData(d[3], tng_vclo, 'tng_vclo', t[0]) P_Data[tongue_to_teeth] = MCData(d[3], tng_vclo, 'tng_vclo', t[0]) PhonemeDict['P'] = P_Data # B - bilabial voiced plosive /b/oot, a/b/out PhonemeDict['B'] = PhonemeDict['P'] # T - alveolar voiceless plosive /t/ry, /t/oday T_Data = dict() T_Data[jaw_open] = MCData(d[4], jaw_medi, 'jaw_medi', t[4]) T_Data[lip_round_compression] = MCData(d[1], lip_medi, 'lip_medi', t[0]) T_Data[lip_round_protrusion] = MCData(d[1], lip_medi, 'lip_medi', t[0]) T_Data[lip_press_together] = MCData(d[8], lip_medi, 'lip_medi', t[0]) T_Data[lower_lip_f_tuck] = MCData(d[8], lip_medi, 'lip_medi', t[0]) T_Data[lip_stretch] = MCData(d[1], lip_medi, 'lip_medi', t[0]) T_Data[tongue_to_back] = MCData(d[5], tng_medi, 'tng_medi', t[0]) T_Data[tongue_to_roof] = MCData(d[10], tng_dist, 'tng_dist', t[8], 0.1) T_Data[tongue_to_teeth] = MCData(d[5], tng_medi, 'tng_medi', t[0]) PhonemeDict['T'] = T_Data # D - alveolar voiced plosive /d/og, bombe/d/ PhonemeDict['D'] = PhonemeDict['T'] # K - velar voiced plosive /c/at, s/k/in K_Data = dict() K_Data[jaw_open] = MCData(d[3], jaw_medi, 'jaw_medi', t[3]) K_Data[lip_round_compression] = MCData(d[1], lip_clos, 'lip_clos', t[0]) K_Data[lip_round_protrusion] = MCData(d[1], lip_clos, 'lip_clos', t[0]) K_Data[lip_press_together] = MCData(d[7], lip_clos, 'lip_clos', t[0]) K_Data[lower_lip_f_tuck] = MCData(d[8], lip_clos, 'lip_clos', t[0]) K_Data[lip_stretch] = MCData(d[1], lip_clos, 'lip_clos', t[0]) K_Data[tongue_to_back] = MCData(d[9], tng_medi, 'tng_medi', t[8], 0.1) K_Data[tongue_to_roof] = MCData(d[6], tng_vclo, 'tng_vclo', t[0]) K_Data[tongue_to_teeth] = MCData(d[6], tng_vclo, 'tng_vclo', t[0]) PhonemeDict['K'] = K_Data # G - velar voiceless plosive /g/um, ba/g/ PhonemeDict['G'] = PhonemeDict['K'] # M - bilabial nasal /m/ore, botto/m/ PhonemeDict['M'] = PhonemeDict['B'] # N - alveolar nasal /n/i/n/e, pla/n/ N_Data = dict() N_Data[jaw_open] = MCData(d[5], jaw_clos, 'jaw_clos', t[4]) N_Data[lip_round_compression] = MCData(d[1], lip_clos, 'lip_clos', t[0]) N_Data[lip_round_protrusion] = MCData(d[1], lip_clos, 'lip_clos', t[0]) N_Data[lip_press_together] = MCData(d[5], lip_clos, 'lip_clos', t[0]) N_Data[lower_lip_f_tuck] = MCData(d[5], lip_clos, 'lip_clos', t[0]) N_Data[lip_stretch] = MCData(d[1], lip_clos, 'lip_clos', t[0]) N_Data[tongue_to_back] = MCData(d[7], tng_medi, 'tng_medi', t[0]) N_Data[tongue_to_roof] = MCData(d[8], tng_medi, 'tng_medi', t[8], 0.2) N_Data[tongue_to_teeth] = MCData(d[2], tng_medi, 'tng_medi', t[0]) PhonemeDict['N'] = N_Data # NG - velar nasal si/ng/, ba/n/k PhonemeDict['NG'] = PhonemeDict['N'] # RA - alveolar trill es: pe/rr/o RA_Data = dict() RA_Data[jaw_open] = MCData(d[7], jaw_medi, 'jaw_medi', t[4]) RA_Data[lip_round_compression] = MCData(d[2], lip_clos, 'lip_clos', t[0]) RA_Data[lip_round_protrusion] = MCData(d[2], lip_clos, 'lip_clos', t[0]) RA_Data[lip_press_together] = MCData(d[7], lip_clos, 'lip_clos', t[0]) RA_Data[lower_lip_f_tuck] = MCData(d[5], lip_clos, 'lip_clos', t[0]) RA_Data[lip_stretch] = MCData(d[2], lip_clos, 'lip_clos', t[0]) RA_Data[tongue_to_back] = MCData(d[7], tng_medi, 'tng_medi', t[0]) RA_Data[tongue_to_roof] = MCData(d[8], tng_medi, 'tng_medi', t[5]) RA_Data[tongue_to_teeth] = MCData(d[6], tng_medi, 'tng_medi', t[0]) PhonemeDict['RA'] = RA_Data # RU - uvular trill fr: /r/ue, de: /R/echt RU_Data = dict() RU_Data[jaw_open] = MCData(d[3], jaw_clos, 'jaw_clos', t[2]) RU_Data[lip_round_compression] = MCData(d[4], lip_clos, 'lip_clos', t[0]) RU_Data[lip_round_protrusion] = MCData(d[2], lip_clos, 'lip_clos', t[0]) RU_Data[lip_press_together] = MCData(d[3], lip_clos, 'lip_clos', t[0]) RU_Data[lower_lip_f_tuck] = MCData(d[5], lip_clos, 'lip_clos', t[0]) RU_Data[lip_stretch] = MCData(d[2], lip_clos, 'lip_clos', t[0]) RU_Data[tongue_to_back] = MCData(d[7], tng_medi, 'tng_medi', t[8]) RU_Data[tongue_to_roof] = MCData(d[5], tng_medi, 'tng_medi', t[0]) RU_Data[tongue_to_teeth] = MCData(d[7], tng_medi, 'tng_medi', t[0]) PhonemeDict['RU'] = RU_Data # FLAP - alveolar flap wa/t/er PhonemeDict['FLAP'] = PhonemeDict['T'] # PH - bilabial voiceless fric. japanese & korean PH_Data = dict() PH_Data[jaw_open] = MCData(d[10], jaw_medi, 'jaw_medi', t[0], 0.1) PH_Data[lip_round_compression] = MCData(d[5], lip_clos, 'lip_clos', t[0]) PH_Data[lip_round_protrusion] = MCData(d[8], lip_clos, 'lip_clos', t[0]) PH_Data[lip_press_together] = MCData(d[7], lip_clos, 'lip_clos', t[0]) PH_Data[lower_lip_f_tuck] = MCData(d[8], lip_medi, 'lip_medi', t[7], 0.1) PH_Data[lip_stretch] = MCData(d[4], lip_clos, 'lip_clos', t[0]) PH_Data[tongue_to_back] = MCData(d[2], tng_medi, 'tng_medi', t[0]) PH_Data[tongue_to_roof] = MCData(d[2], tng_medi, 'tng_medi', t[0]) PH_Data[tongue_to_teeth] = MCData(d[2], tng_medi, 'tng_medi', t[0]) PhonemeDict['PH'] = PH_Data # F - labiodental voiceless fric. /f/arm, ta/ff/y PhonemeDict['F'] = PhonemeDict['PH'] # V - labiodental voiced fric. /v/isit, ra/v/e PhonemeDict['V'] = PhonemeDict['F'] # TH - dental voiceless fric. /th/ing, ba/th/ TH_Data = dict() TH_Data[jaw_open] = MCData(d[6], jaw_medi, 'jaw_medi', t[5]) TH_Data[lip_round_compression] = MCData(d[3], lip_clos, 'lip_clos', t[0]) TH_Data[lip_round_protrusion] = MCData(d[2], lip_clos, 'lip_clos', t[0]) TH_Data[lip_press_together] = MCData(d[7], lip_clos, 'lip_clos', t[0]) TH_Data[lower_lip_f_tuck] = MCData(d[6], lip_clos, 'lip_clos', t[0]) TH_Data[lip_stretch] = MCData(d[2], lip_clos, 'lip_clos', t[0]) TH_Data[tongue_to_back] = MCData(d[8], tng_medi, 'tng_medi', t[0]) TH_Data[tongue_to_roof] = MCData(d[8], tng_medi, 'tng_medi', t[0]) TH_Data[tongue_to_teeth] = MCData(d[8], tng_vdis, 'tng_vdis', t[9], 0.1) PhonemeDict['TH'] = TH_Data # DH - dental voiced fric. /th/is, /th/e PhonemeDict['DH'] = PhonemeDict['TH'] # S - alveolar voiceless fric. /s/it, pa/ss/ S_Data = dict() S_Data[jaw_open] = MCData(d[7], jaw_medi, 'jaw_medi', t[2]) S_Data[lip_round_compression] = MCData(d[6], lip_clos, 'lip_clos', t[0]) S_Data[lip_round_protrusion] = MCData(d[4], lip_clos, 'lip_clos', t[0]) S_Data[lip_press_together] = MCData(d[7], lip_clos, 'lip_clos', t[0]) S_Data[lower_lip_f_tuck] = MCData(d[8], lip_clos, 'lip_clos', t[0]) S_Data[lip_stretch] = MCData(d[2], lip_medi, 'lip_medi', t[5]) S_Data[tongue_to_back] = MCData(d[5], tng_medi, 'tng_medi', t[0]) S_Data[tongue_to_roof] = MCData(d[7], tng_medi, 'tng_medi', t[4], 0.25) S_Data[tongue_to_teeth] = MCData(d[4], tng_medi, 'tng_medi', t[0]) PhonemeDict['S'] = S_Data # Z - alveolar voiced fric. /z/oo, ro/s/es PhonemeDict['Z'] = PhonemeDict['S'] # SH - postalveolar voiceless fric. /sh/oe, pa/ssi/on, dona/ti/on SH_Data = dict() SH_Data[jaw_open] = MCData(d[7], jaw_medi, 'jaw_medi', t[0]) SH_Data[lip_round_compression] = MCData(d[5], lip_clos, 'lip_clos', t[0]) SH_Data[lip_round_protrusion] = MCData(d[9], lip_dist, 'lip_dist', t[8], 0.25) SH_Data[lip_press_together] = MCData(d[4], lip_medi, 'lip_medi', t[0]) SH_Data[lower_lip_f_tuck] = MCData(d[8], lip_clos, 'lip_clos', t[0]) SH_Data[lip_stretch] = MCData(d[8], lip_medi, 'lip_medi', t[0]) SH_Data[tongue_to_back] = MCData(d[6], tng_medi, 'tng_medi', t[0]) SH_Data[tongue_to_roof] = MCData(d[8], tng_medi, 'tng_medi', t[4], 0.25) SH_Data[tongue_to_teeth] = MCData(d[6], tng_medi, 'tng_medi', t[0]) PhonemeDict['SH'] = SH_Data # ZH - poatalveolar voiced fric. trea/s/ure, mira/ge/ PhonemeDict['ZH'] = PhonemeDict['SH'] # CX - palatal voiceless fric. de: i/ch/ PhonemeDict['CX'] = PhonemeDict['RU'] # X - velar voiceless fric. lo/ch/, /Ch/anuka PhonemeDict['X'] = PhonemeDict['RU'] # GH - velar voiced fric. not in en PhonemeDict['GH'] = PhonemeDict['RU'] # HH - glottal voiceless fric. /h/appy, a/h/ead HH_Data = dict() HH_Data[jaw_open] = MCData(d[5], jaw_clos, 'jaw_clos', t[3]) HH_Data[lip_round_compression] = MCData(d[2], lip_vclo, 'lip_vclo', t[0]) HH_Data[lip_round_protrusion] = MCData(d[2], lip_vclo, 'lip_vclo', t[0]) HH_Data[lip_press_together] = MCData(d[4], lip_vclo, 'lip_vclo', t[0]) HH_Data[lower_lip_f_tuck] = MCData(d[4], lip_vclo, 'lip_vclo', t[0]) HH_Data[lip_stretch] = MCData(d[2], lip_vclo, 'lip_vclo', t[0]) HH_Data[tongue_to_back] = MCData(d[1], tng_vclo, 'tng_vclo', t[0]) HH_Data[tongue_to_roof] = MCData(d[1], tng_vclo, 'tng_vclo', t[0]) HH_Data[tongue_to_teeth] = MCData(d[1], tng_vclo, 'tng_vclo', t[0]) PhonemeDict['HH'] = HH_Data # R - alveolar approximant /r/ed R_Data = dict() R_Data[jaw_open] = MCData(d[7], jaw_medi, 'jaw_medi', t[1]) R_Data[lip_round_compression] = MCData(d[2], lip_medi, 'lip_medi', t[7]) R_Data[lip_round_protrusion] = MCData(d[2], lip_clos, 'lip_clos', t[0]) R_Data[lip_press_together] = MCData(d[6], lip_clos, 'lip_clos', t[0]) R_Data[lower_lip_f_tuck] = MCData(d[5], lip_clos, 'lip_clos', t[0]) R_Data[lip_stretch] = MCData(d[3], lip_clos, 'lip_clos', t[0]) R_Data[tongue_to_back] = MCData(d[6], tng_medi, 'tng_medi', t[0]) R_Data[tongue_to_roof] = MCData(d[6], tng_medi, 'tng_medi', t[4]) R_Data[tongue_to_teeth] = MCData(d[6], tng_medi, 'tng_medi', t[0]) PhonemeDict['R'] = R_Data # Y - palatal approximant /y/ou, /y/esterday Y_Data = dict() Y_Data[jaw_open] = MCData(d[3], jaw_medi, 'jaw_medi', t[0]) Y_Data[lip_round_compression] = MCData(d[2], lip_medi, 'lip_medi', t[0]) Y_Data[lip_round_protrusion] = MCData(d[2], lip_medi, 'lip_medi', t[0]) Y_Data[lip_press_together] = MCData(d[4], lip_clos, 'lip_clos', t[0]) Y_Data[lower_lip_f_tuck] = MCData(d[5], lip_clos, 'lip_clos', t[0]) Y_Data[lip_stretch] = MCData(d[3], lip_clos, 'lip_clos', t[0]) Y_Data[tongue_to_back] = MCData(d[7], tng_medi, 'tng_medi', t[0]) Y_Data[tongue_to_roof] = MCData(d[8], tng_medi, 'tng_medi', t[4]) Y_Data[tongue_to_teeth] = MCData(d[7], tng_medi, 'tng_medi', t[0]) PhonemeDict['Y'] = Y_Data # L - alveolar lateral approx. /l/ip, p/l/ease L_Data = dict() L_Data[jaw_open] = MCData(d[4], jaw_medi, 'jaw_medi', t[4]) L_Data[lip_round_compression] = MCData(d[3], lip_clos, 'lip_clos', t[0]) L_Data[lip_round_protrusion] = MCData(d[3], lip_clos, 'lip_clos', t[0]) L_Data[lip_press_together] = MCData(d[6], lip_clos, 'lip_clos', t[0]) L_Data[lower_lip_f_tuck] = MCData(d[7], lip_clos, 'lip_clos', t[0]) L_Data[lip_stretch] = MCData(d[3], lip_clos, 'lip_clos', t[0]) L_Data[tongue_to_back] = MCData(d[4], tng_medi, 'tng_medi', t[0]) L_Data[tongue_to_roof] = MCData(d[8], tng_medi, 'tng_medi', t[8], 0.25) L_Data[tongue_to_teeth] = MCData(d[5], tng_medi, 'tng_medi', t[0]) PhonemeDict['L'] = L_Data # W - labial-velar approximant /w/ater, /w/alk W_Data = dict() W_Data[jaw_open] = MCData(d[4], jaw_medi, 'jaw_medi', t[0]) W_Data[lip_round_compression] = MCData(d[7], lip_dist, 'lip_dist', t[9]) W_Data[lip_round_protrusion] = MCData(d[3], lip_clos, 'lip_clos', t[0]) W_Data[lip_press_together] = MCData(d[3], lip_clos, 'lip_clos', t[0]) W_Data[lower_lip_f_tuck] = MCData(d[7], lip_clos, 'lip_clos', t[0]) W_Data[lip_stretch] = MCData(d[5], lip_clos, 'lip_clos', t[0]) W_Data[tongue_to_back] = MCData(d[6], tng_medi, 'tng_medi', t[0]) W_Data[tongue_to_roof] = MCData(d[6], tng_medi, 'tng_medi', t[0]) W_Data[tongue_to_teeth] = MCData(d[7], tng_medi, 'tng_medi', t[0]) PhonemeDict['W'] = W_Data # H - labial-palatal approximant fr: /hu/it PhonemeDict['H'] = PhonemeDict['HH'] # TS - alveolar voiceless affricate pi/zz/a, de: /z/ehn PhonemeDict['TS'] = PhonemeDict['N'] # CH - postalveolar voiceless affr. /ch/ip CH_Data = dict() CH_Data[jaw_open] = MCData(d[4], jaw_medi, 'jaw_medi', t[0]) CH_Data[lip_round_compression] = MCData(d[5], lip_clos, 'lip_clos', t[0]) CH_Data[lip_round_protrusion] = MCData(d[8], lip_vdis, 'lip_vdis', t[8]) CH_Data[lip_press_together] = MCData(d[6], lip_medi, 'lip_medi', t[0]) CH_Data[lower_lip_f_tuck] = MCData(d[4], lip_clos, 'lip_clos', t[0]) CH_Data[lip_stretch] = MCData(d[5], lip_clos, 'lip_clos', t[0]) CH_Data[tongue_to_back] = MCData(d[6], tng_medi, 'tng_medi', t[0]) CH_Data[tongue_to_roof] = MCData(d[7], tng_medi, 'tng_medi', t[6], 0.2) CH_Data[tongue_to_teeth] = MCData(d[6], tng_medi, 'tng_medi', t[0]) PhonemeDict['CH'] = CH_Data # JH - postalveolar voiced affric. /g/irrafe, /j/ump PhonemeDict['JH'] = PhonemeDict['CH'] # IY - close front unlip_round_compressioned b/ee/t, fr: f/i/n/i/ IY_Data = dict() IY_Data[jaw_open] = MCData(d[7], jaw_medi, 'jaw_medi', t[4]) IY_Data[lip_round_compression] = MCData(d[7], lip_medi, 'lip_medi', t[0]) IY_Data[lip_round_protrusion] = MCData(d[7], lip_medi, 'lip_medi', t[0]) IY_Data[lip_press_together] = MCData(d[7], lip_medi, 'lip_medi', t[0]) IY_Data[lower_lip_f_tuck] = MCData(d[7], lip_medi, 'lip_medi', t[0]) IY_Data[lip_stretch] = MCData(d[7], lip_vdis, 'lip_vdis', t[8]) IY_Data[tongue_to_back] = MCData(d[5], tng_medi, 'tng_medi', t[0]) IY_Data[tongue_to_roof] = MCData(d[5], tng_medi, 'tng_medi', t[2]) IY_Data[tongue_to_teeth] = MCData(d[5], tng_medi, 'tng_medi', t[0]) PhonemeDict['IY'] = IY_Data # E - close-mid front unlip_round_compressioned fr: beaut/é/ E_Data = dict() E_Data[jaw_open] = MCData(d[7], jaw_medi, 'jaw_medi', t[4]) E_Data[lip_round_compression] = MCData(d[6], lip_medi, 'lip_medi', t[0]) E_Data[lip_round_protrusion] = MCData(d[6], lip_medi, 'lip_medi', t[0]) E_Data[lip_press_together] = MCData(d[6], lip_clos, 'lip_clos', t[0]) E_Data[lower_lip_f_tuck] = MCData(d[8], lip_clos, 'lip_clos', t[0]) E_Data[lip_stretch] = MCData(d[8], lip_dist, 'lip_dist', t[3]) E_Data[tongue_to_back] = MCData(d[7], tng_medi, 'tng_medi', t[0]) E_Data[tongue_to_roof] = MCData(d[7], tng_medi, 'tng_medi', t[3]) E_Data[tongue_to_teeth] = MCData(d[7], tng_medi, 'tng_medi', t[0]) PhonemeDict['E'] = E_Data # EN - close-mid front unlip_round_compressioned+n fr: /ain/si PhonemeDict['EN'] = PhonemeDict['E'] # EH - jaw_open-mid front unlip_round_compressioned b/e/d, fr: b/e/te EH_Data = dict() EH_Data[jaw_open] = MCData(d[7], jaw_dist, 'jaw_dist', t[5]) EH_Data[lip_round_compression] = MCData(d[6], lip_medi, 'lip_medi', t[0]) EH_Data[lip_round_protrusion] = MCData(d[6], lip_medi, 'lip_medi', t[0]) EH_Data[lip_press_together] = MCData(d[6], lip_medi, 'lip_medi', t[0]) EH_Data[lower_lip_f_tuck] = MCData(d[8], lip_medi, 'lip_medi', t[0]) EH_Data[lip_stretch] = MCData(d[8], lip_dist, 'lip_dist', t[6]) EH_Data[tongue_to_back] = MCData(d[7], tng_medi, 'tng_medi', t[4]) EH_Data[tongue_to_roof] = MCData(d[7], tng_medi, 'tng_medi', t[0]) EH_Data[tongue_to_teeth] = MCData(d[7], tng_medi, 'tng_medi', t[0]) PhonemeDict['EH'] = EH_Data # A - jaw_open front unlip_round_compressioned fr: r/a/t A_Data = dict() A_Data[jaw_open] = MCData(d[7], jaw_medi, 'jaw_medi', t[5]) A_Data[lip_round_compression] = MCData(d[6], lip_medi, 'lip_medi', t[0]) A_Data[lip_round_protrusion] = MCData(d[6], lip_medi, 'lip_medi', t[0]) A_Data[lip_press_together] = MCData(d[6], lip_medi, 'lip_medi', t[0]) A_Data[lower_lip_f_tuck] = MCData(d[6], lip_medi, 'lip_medi', t[0]) A_Data[lip_stretch] = MCData(d[6], lip_medi, 'lip_medi', t[0]) A_Data[tongue_to_back] = MCData(d[7], tng_medi, 'tng_medi', t[0]) A_Data[tongue_to_roof] = MCData(d[7], tng_medi, 'tng_medi', t[0]) A_Data[tongue_to_teeth] = MCData(d[7], tng_medi, 'tng_medi', t[0]) PhonemeDict['A'] = A_Data # AA - jaw_open back unlip_round_compressioned sp/a/, h/o/t PhonemeDict['AA'] = PhonemeDict['A'] # AAN - jaw_open back unlip_round_compressioned+n fr: qu/and/, fr: /un/ PhonemeDict['AAN'] = PhonemeDict['AA'] # AO - jaw_open-mid back lip_round_compressioned fr: s/o/rt AO_Data = dict() AO_Data[jaw_open] = MCData(d[8], jaw_dist, 'jaw_dist', t[4]) AO_Data[lip_round_compression] = MCData(d[7], lip_dist, 'lip_dist', t[5]) AO_Data[lip_round_protrusion] = MCData(d[6], lip_medi, 'lip_medi', t[0]) AO_Data[lip_press_together] = MCData(d[6], lip_medi, 'lip_medi', t[0]) AO_Data[lower_lip_f_tuck] = MCData(d[6], lip_medi, 'lip_medi', t[0]) AO_Data[lip_stretch] = MCData(d[6], lip_medi, 'lip_medi', t[0]) AO_Data[tongue_to_back] = MCData(d[7], tng_medi, 'tng_medi', t[0]) AO_Data[tongue_to_roof] = MCData(d[7], tng_medi, 'tng_medi', t[3 ]) AO_Data[tongue_to_teeth] = MCData(d[7], tng_medi, 'tng_medi', t[0]) PhonemeDict['AO'] = AO_Data # AON - jaw_open-mid back lip_round_compressioned+n fr: s/on/ PhonemeDict['AON'] = PhonemeDict['AO'] # O - close-mid back lip_round_compressioned fr: rés/eau/ PhonemeDict['O'] = PhonemeDict['AO'] # ON - close-mid back lip_round_compressioned+n fr: m/an/teau PhonemeDict['ON'] = PhonemeDict['O'] # UW - close back lip_round_compressioned b/oo/t PhonemeDict['UW'] = PhonemeDict['AO'] # UY - close front lip_round_compressioned fr: ch/u/te UY_Data = dict() UY_Data[jaw_open] = MCData(d[8], jaw_dist, 'jaw_dist', t[0]) UY_Data[lip_round_compression] = MCData(d[8], lip_vdis, 'lip_vdis', t[0]) UY_Data[lip_round_protrusion] = MCData(d[8], lip_dist, 'lip_dist', t[9]) UY_Data[lip_press_together] = MCData(d[7], lip_dist, 'lip_dist', t[0]) UY_Data[lower_lip_f_tuck] = MCData(d[7], lip_medi, 'lip_medi', t[0]) UY_Data[lip_stretch] = MCData(d[7], lip_vdis, 'lip_vdis', t[0]) UY_Data[tongue_to_back] = MCData(d[6], tng_medi, 'tng_medi', t[0]) UY_Data[tongue_to_roof] = MCData(d[6], tng_medi, 'tng_medi', t[0]) UY_Data[tongue_to_teeth] = MCData(d[6], tng_medi, 'tng_medi', t[0]) PhonemeDict['UY'] = UY_Data # EU - close-mid front lip_round_compressioned fr: p/eu/ EU_Data = dict() EU_Data[jaw_open] = MCData(d[8], jaw_medi, 'jaw_medi', t[4]) EU_Data[lip_round_compression] = MCData(d[7], lip_medi, 'lip_medi', t[0]) EU_Data[lip_round_protrusion] = MCData(d[8], lip_vdis, 'lip_vdis', t[6]) EU_Data[lip_press_together] = MCData(d[7], lip_medi, 'lip_medi', t[0]) EU_Data[lower_lip_f_tuck] = MCData(d[6], lip_medi, 'lip_medi', t[0]) EU_Data[lip_stretch] = MCData(d[6], lip_medi, 'lip_medi', t[0]) EU_Data[tongue_to_back] = MCData(d[6], tng_medi, 'tng_medi', t[0]) EU_Data[tongue_to_roof] = MCData(d[6], tng_medi, 'tng_medi', t[0]) EU_Data[tongue_to_teeth] = MCData(d[6], tng_medi, 'tng_medi', t[0]) PhonemeDict['EU'] = EU_Data # OE - jaw_open-mid front lip_round_compressioned de: H/ö/lle PhonemeDict['OE'] = PhonemeDict['EU'] # OEN - jaw_open-mid front lip_round_compressioned+n fr: j/eu/ne PhonemeDict['OEN'] = PhonemeDict['OE'] # AH - jaw_open-mid back unlip_round_compressioned n/u/t, r/u/n PhonemeDict['AH'] = PhonemeDict['EH'] # IH - near-close near-front unrnd. b/i/t PhonemeDict['IH'] = PhonemeDict['EH'] # UU - near-close near-front lip_round_compression. de: h/ü/bsch PhonemeDict['UU'] = PhonemeDict['EU'] # UH - near-close near-back lip_round_compression. h/oo/k PhonemeDict['UH'] = PhonemeDict['EU'] # AX - mid central /a/bout, syn/o/nym, /uh/ PhonemeDict['AX'] = PhonemeDict['EH'] # UX - near-jaw_open central de: de/r/ PhonemeDict['UX'] = PhonemeDict['EH'] # AE - near-jaw_open front unlip_round_compressioned f/a/t PhonemeDict['AE'] = PhonemeDict['EH'] # ER - jaw_open-mid central unlip_round_compressioned p/er/fect ER_Data = dict() ER_Data[jaw_open] = MCData(d[6], jaw_dist, 'jaw_dist', t[4]) ER_Data[lip_round_compression] = MCData(d[6], lip_medi, 'lip_medi', t[0]) ER_Data[lip_round_protrusion] = MCData(d[6], lip_dist, 'lip_dist', t[5]) ER_Data[lip_press_together] = MCData(d[5], lip_medi, 'lip_medi', t[0]) ER_Data[lower_lip_f_tuck] = MCData(d[5], lip_medi, 'lip_medi', t[0]) ER_Data[lip_stretch] = MCData(d[5], lip_medi, 'lip_medi', t[0]) ER_Data[tongue_to_back] = MCData(d[4], tng_medi, 'tng_medi', t[0]) ER_Data[tongue_to_roof] = MCData(d[4], tng_medi, 'tng_medi', t[5]) ER_Data[tongue_to_teeth] = MCData(d[4], tng_medi, 'tng_medi', t[0]) PhonemeDict['ER'] = ER_Data # AXR - mid central rhotacized butt/er/ PhonemeDict['AXR'] = PhonemeDict['ER'] # EXR - jaw_open-mid central rhotacized f/ur/ PhonemeDict['EXR'] = PhonemeDict['ER'] # EY - dipthong, split PhonemeDict['EY'] = PhonemeDict['EH'] # AW - dipthong, split PhonemeDict['AW'] = PhonemeDict['EH'] # AY - dipthong, split PhonemeDict['AY'] = PhonemeDict['EH'] # OY - dipthong, split PhonemeDict['OY'] = PhonemeDict['EU'] # OW - dipthong, split PhonemeDict['OW'] = PhonemeDict['EU'] #------------------------------------------------------------------------------ # Routines #------------------------------------------------------------------------------ timeIntervals = (-8.0, -6.0, -4.0, -2.0, -1.0, -0.5, -0.45, -0.40, -0.35, -0.30, -0.25, -0.20, -0.15, -0.1, -0.05, -0.04, -0.03, -0.02, -0.01, 0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.1, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.5, 1.0, 2.0, 4.0, 6.0, 8.0) def GeneratePrototypeDominanceCurve(curveName): mcData = MCData(1.0, 20, 'n/a', 1.0) dominanceCurve = Curve(curveName) for time in timeIntervals: dominanceCurve.keys.append(Key(time, mcData.calc_dominance_value(time), mcData.calc_slope_in(time), mcData.calc_slope_out(time))) return dominanceCurve def GenerateDominanceCurves(mcData, anim, curveName): dominanceCurve = Curve(curveName) # calculate the dominance curves for time in timeIntervals: dominanceCurve.keys.append(Key(time, mcData.calc_dominance_value(time), mcData.calc_slope_in(time), mcData.calc_slope_out(time))) anim.curves.append(dominanceCurve) scaledDominanceCurve = Curve(curveName + scaled) # calculate the scaled dominance curve. for key in dominanceCurve.keys: scaledDominanceCurve.keys.append(Key(key.time, key.value * mcData.target, key.slopein * mcData.target, key.slopeout * mcData.target)) anim.curves.append(scaledDominanceCurve) def CreateMCAnimations(): # Create the dominance functions group. issueCommand('animGroup -create -group "%s";' % (phonemeEventGroup)) issueCommand('animGroup -create -group "%s";' % (spawnedPhonemeEventGroup)) # Create the dominance curves animations. for target in targetList: targetDominanceAnimation = MCAnim(target, spawnedPhonemeEventGroup) targetDominanceAnimation.curves.append(GeneratePrototypeDominanceCurve(target)) targetDominanceAnimation.buildAnim() targetDominanceScaledAnimation = MCAnim(target + scaled, spawnedPhonemeEventGroup) targetDominanceScaledAnimation.curves.append(GeneratePrototypeDominanceCurve(target + scaled)) targetDominanceScaledAnimation.buildAnim() # For each phoneme in the data dictionary, add an animation with events that # reference each of the 18 dominance curves. total = len(PhonemeDict) curr = 0 for phoneme in sorted(PhonemeDict): # Create the phoneme's animation print 'Processing phoneme %d of %d' % (curr, total) phonemeAnim = MCAnim(phoneme, phonemeEventGroup) # For each target, add the dominance animation and the scaled dominance animation phonemeData = PhonemeDict[phoneme] for target in sorted(phonemeData): targetMCData = phonemeData[target] dominanceEvent = MCEvent(target, spawnedPhonemeEventGroup, targetMCData.duration_scale, targetMCData.magnitude) dominanceEvent.set_start(targetMCData.offset) scaledDominanceEvent = MCEvent(target + scaled, spawnedPhonemeEventGroup, targetMCData.duration_scale, targetMCData.magnitude * targetMCData.target) scaledDominanceEvent.set_start(targetMCData.offset) phonemeAnim.events.append(dominanceEvent) phonemeAnim.events.append(scaledDominanceEvent) # Finish the work for the phoneme by building the animation phonemeAnim.buildAnim() curr += 1 issueCommand('flushUndo') def CreateMCFaceGraph(): # Create the face graph structure. issueCommand('batch;') issueCommand('graph -addnode -nodetype "FxCombinerNode" -name "_constant_feeder" -min 0 -max 10') for nodeTuple in nodesToCreate: # Add the nodes issueCommand('graph -addnode -nodetype "FxCombinerNode" -name "%s" -min 0 -max 10' % (nodeTuple[0])) issueCommand('graph -addnode -nodetype "FxCombinerNode" -name "%s" -min 0 -max 10' % (nodeTuple[1])) issueCommand('graph -addnode -nodetype "FxCombinerNode" -name "%s" -min 0 -max 10 -inputop "mul"' % (nodeTuple[2])) # Create the links issueCommand('graph -link -from "_constant_feeder" -to "%s" -linkfn "constant" -linkfnparams "c=0.001"' % (nodeTuple[0])) issueCommand('graph -link -from "%s" -to "%s" -linkfn "linear";' % (nodeTuple[1], nodeTuple[2])) issueCommand('graph -link -from "%s" -to "%s" -linkfn "inverse";' % (nodeTuple[0], nodeTuple[2])) #issueCommand('graph -addnode -nodetype "FxCombinerNode" -name "_jaw_corrector" -min -0 -max 1"') #issueCommand('graph -link -from "%s" -to "%s" -linkfn "linear";' % (lip_press_together + sum, '_jaw_corrector')) #issueCommand('graph -link -from "%s" -to "%s" -linkfn "linear";' % (lower_lip_f_tuck + sum, '_jaw_corrector')) #issueCommand('graph -link -from "%s" -to "%s" -linkfn "corrective";' % ('_jaw_corrector', jaw_open + sum)) for nodeTuple in finalTargetList: issueCommand('graph -addnode -nodetype "FxCombinerNode" -name "%s" -min 0 -max 1' % (nodeTuple[0])) issueCommand('graph -link -from "%s" -to "%s" -linkfn "linear";' % (nodeTuple[1], nodeTuple[0])) issueCommand('execBatch -editednodes;') def DoFullModel(): phonemeWordList = FxPhonemes.PhonemeWordList() phonemeList = phonemeWordList.phonemes phonemeString = 'Phones: ' for phone in phonemeList: phonemeString += ' %s %f %f' % (FxPhonemes.PHONEME_REGISTRY.entries[phone.phonemeId].facefxCoding, phone.startTime, phone.endTime) print phonemeString targetString = 'Targets: ' curveDict = dict() for target in targetList: targetString += ' %s,' % (target) curveDict[target] = Curve(target + sum) print targetString # loop through each target for time in frange(0, 28.148, 0.05): for target in targetList: Dsp_sum = 0.0 DspxTsp_sum = 0.0 for phone in phonemeList: mcData = PhonemeDict[FxPhonemes.PHONEME_REGISTRY.entries[phone.phonemeId].facefxCoding][target] tcsp = phone.startTime + (phone.endTime - phone.startTime) * 0.5 #tcsp = phone.startTime tau = tcsp - time DspxTsp_sum += mcData.calc_scaled_dominance_value(tau) Dsp_sum += mcData.calc_dominance_value(tau) Fpt = 0.0 if Dsp_sum != 0.0: Fpt = DspxTsp_sum / Dsp_sum curveDict[target].keys.append(Key(time, Fpt, 0, 0)) animToAdd = MCAnim('allaround16_2', 'Comparison') for curveName in sorted(curveDict): animToAdd.curves.append(curveDict[curveName]) animToAdd.buildAnim() #------------------------------------------------------------------------------ # Main program begins here #------------------------------------------------------------------------------ CreateMCAnimations() CreateMCFaceGraph() #DoFullModel()