diff --git a/io_import_lipSync_Importer.py b/io_import_lipSync_Importer.py index fe610c9c6e24042b7f7d46ace3e15fa8b4ac4c5a..89d70a96df3a08f4a00027966f0d1491888e4c7f 100644 --- a/io_import_lipSync_Importer.py +++ b/io_import_lipSync_Importer.py @@ -18,96 +18,105 @@ bl_info = { "name": "LipSync Importer & Blinker", - "author": "Yousef Harfoush - bat3a ;)", - "version": (0, 5, 1), + "author": "Yousef Harfoush - bat3a)", + "version": (0, 5, 2), "blender": (2, 70, 0), "location": "3D window > Tool Shelf", "description": "Plots Moho (Papagayo, Jlipsync, Yolo) file " - "to frames and adds automatic blinking", + "to frames and adds automatic blinking", "warning": "", - "wiki_url": "http://wiki.blender.org/index.php?title=Extensions:2.6/Py/" - "Scripts/Import-Export/Lipsync Importer", + "wiki_url": "https://wiki.blender.org/index.php?title=Extensions:2.6/Py/" + "Scripts/Import-Export/Lipsync Importer", "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/", "category": "Import-Export"} -import bpy, re +import bpy +import re from random import random -from bpy.props import * -from bpy.props import IntProperty, FloatProperty, StringProperty +from bpy.props import ( + EnumProperty, + IntProperty, + FloatProperty, + StringProperty, + PointerProperty, + ) global lastPhoneme -lastPhoneme="nothing" +lastPhoneme = "nothing" + # add blinking def blinker(): scn = bpy.context.scene - obj = bpy.context.object if scn.regMenuTypes.enumBlinkTypes == '0': modifier = 0 elif scn.regMenuTypes.enumBlinkTypes == '1': - modifier = scn.blinkMod + modifier = scn.regMenuTypes.blinkMod - #creating keys with blinkNm count - for y in range(scn.blinkNm): - frame = y * scn.blinkSp + int(random()*modifier) + # creating keys with blinkNm count + for y in range(scn.regMenuTypes.blinkNm): + frame = y * scn.regMenuTypes.blinkSp + int(random() * modifier) createShapekey('blink', frame) -# -----------code contributed by dalai felinto adds armature support modified by me------------------- + +# -- code contributed by dalai felinto adds armature support modified by me -- bone_keys = { -"AI": ('location', 0), -"E": ('location', 1), -"FV": ('location', 2), -"L": ('rotation_euler', 0), -"MBP": ('rotation_euler', 1), -"O": ('rotation_euler', 2), -"U": ('scale', 0), -"WQ": ('scale', 1), -"etc": ('scale', 2), -"rest": ('ik_stretch', -1) + "AI": ('location', 0), + "E": ('location', 1), + "FV": ('location', 2), + "L": ('rotation_euler', 0), + "MBP": ('rotation_euler', 1), + "O": ('rotation_euler', 2), + "U": ('scale', 0), + "WQ": ('scale', 1), + "etc": ('scale', 2), + "rest": ('ik_stretch', -1) } + def lipsyncerBone(): # reading imported file & creating keys - object = bpy.context.object scene = bpy.context.scene bone = bpy.context.active_pose_bone resetBoneScale(bone) - f=open(scene.fpath) # importing file - f.readline() # reading the 1st line that we don"t need + f = open(scene.regMenuTypes.fpath) # importing file + f.readline() # reading the 1st line that we don"t need for line in f: # removing new lines lsta = re.split("\n+", line) # building a list of frames & shapes indexes - lst = re.split(":? ", lsta[0])# making a list of a frame & number + lst = re.split(":? ", lsta[0]) # making a list of a frame & number frame = int(lst[0]) - for key,attribute in bone_keys.items(): + for key, attribute in bone_keys.items(): if lst[1] == key: createBoneKeys(key, bone, attribute, frame) + def resetBoneScale(bone): # set the attributes used by papagayo to 0.0 - for attribute,index in bone_keys.values(): + for attribute, index in bone_keys.values(): if index != -1: - #bone.location[0] = 0.0 + # bone.location[0] = 0.0 exec("bone.%s[%d] = %f" % (attribute, index, 0.0)) else: exec("bone.%s = %f" % (attribute, 0.0)) + def addBoneKey(bone, data_path, index=-1, value=None, frame=0, group=""): # set a value and keyframe for the bone # it assumes the 'bone' variable was defined before # and it's the current selected bone - frame=bpy.context.scene.frame_current - if value != None: + frame = bpy.context.scene.frame_current + if value is not None: if index != -1: # bone.location[0] = 0.0 exec("bone.%s[%d] = %f" % (data_path, index, value)) @@ -117,37 +126,38 @@ def addBoneKey(bone, data_path, index=-1, value=None, frame=0, group=""): # bone.keyframe_insert("location", 0, 10.0, "Lipsync") exec('bone.keyframe_insert("%s", %d, %f, "%s")' % (data_path, index, frame, group)) + # creating keys with offset and eases for a phonem @ the Skframe def createBoneKeys(phoneme, bone, attribute, frame): global lastPhoneme scene = bpy.context.scene - object = bpy.context.object - offst = scene.offset # offset value - skVlu = scene.skscale # shape key value + offst = scene.regMenuTypes.offset # offset value + skVlu = scene.regMenuTypes.skscale # shape key value - #in case of Papagayo format - if scene.regMenuTypes.enumFileTypes == '0' : - frmIn = scene.easeIn # ease in value - frmOut = scene.easeOut # ease out value - hldIn = scene.holdGap # holding time value + # in case of Papagayo format + if scene.regMenuTypes.enumFileTypes == '0': + frmIn = scene.regMenuTypes.easeIn # ease in value + frmOut = scene.regMenuTypes.easeOut # ease out value + hldIn = scene.regMenuTypes.holdGap # holding time value - #in case of Jlipsync format or Yolo - elif scene.regMenuTypes.enumFileTypes == '1' : + # in case of Jlipsync format or Yolo + elif scene.regMenuTypes.enumFileTypes == '1': frmIn = 1 frmOut = 1 hldIn = 0 # inserting the In key only when phonem change or when blinking - if lastPhoneme!=phoneme or eval(scene.regMenuTypes.enumModeTypes) == 1: - addBoneKey(bone, attribute[0], attribute[1], 0.0, offst+frame-frmIn, "Lipsync") + if lastPhoneme != phoneme or eval(scene.regMenuTypes.enumModeTypes) == 1: + addBoneKey(bone, attribute[0], attribute[1], 0.0, offst + frame - frmIn, "Lipsync") - addBoneKey(bone, attribute[0], attribute[1], skVlu, offst+frame, "Lipsync") - addBoneKey(bone, attribute[0], attribute[1], skVlu, offst+frame+hldIn, "Lipsync") - addBoneKey(bone, attribute[0], attribute[1], 0.0, offst+frame+hldIn+frmOut, "Lipsync") + addBoneKey(bone, attribute[0], attribute[1], skVlu, offst + frame, "Lipsync") + addBoneKey(bone, attribute[0], attribute[1], skVlu, offst + frame + hldIn, "Lipsync") + addBoneKey(bone, attribute[0], attribute[1], 0.0, offst + frame + hldIn + frmOut, "Lipsync") + + lastPhoneme = phoneme - lastPhoneme=phoneme # ------------------------------------------------------------------------------- @@ -157,8 +167,8 @@ def lipsyncer(): obj = bpy.context.object scn = bpy.context.scene - f=open(scn.fpath) # importing file - f.readline() # reading the 1st line that we don"t need + f = open(scn.regMenuTypes.fpath) # importing file + f.readline() # reading the 1st line that we don"t need for line in f: @@ -166,13 +176,14 @@ def lipsyncer(): lsta = re.split("\n+", line) # building a list of frames & shapes indexes - lst = re.split(":? ", lsta[0])# making a list of a frame & number + lst = re.split(":? ", lsta[0]) # making a list of a frame & number frame = int(lst[0]) for key in obj.data.shape_keys.key_blocks: if lst[1] == key.name: createShapekey(key.name, frame) + # creating keys with offset and eases for a phonem @ the frame def createShapekey(phoneme, frame): @@ -182,41 +193,43 @@ def createShapekey(phoneme, frame): obj = bpy.context.object objSK = obj.data.shape_keys - offst = scn.offset # offset value - skVlu = scn.skscale # shape key value + offst = scn.regMenuTypes.offset # offset value + skVlu = scn.regMenuTypes.skscale # shape key value - #in case of Papagayo format - if scn.regMenuTypes.enumFileTypes == '0' : - frmIn = scn.easeIn # ease in value - frmOut = scn.easeOut # ease out value - hldIn = scn.holdGap # holding time value + # in case of Papagayo format + if scn.regMenuTypes.enumFileTypes == '0': + frmIn = scn.regMenuTypes.easeIn # ease in value + frmOut = scn.regMenuTypes.easeOut # ease out value + hldIn = scn.regMenuTypes.holdGap # holding time value - #in case of Jlipsync format or Yolo - elif scn.regMenuTypes.enumFileTypes == '1' : + # in case of Jlipsync format or Yolo + elif scn.regMenuTypes.enumFileTypes == '1': frmIn = 1 frmOut = 1 hldIn = 0 # inserting the In key only when phonem change or when blinking - if lastPhoneme!=phoneme or eval(scn.regMenuTypes.enumModeTypes) == 1: - objSK.key_blocks[phoneme].value=0.0 - objSK.key_blocks[phoneme].keyframe_insert("value", - -1, offst+frame-frmIn, "Lipsync") - - objSK.key_blocks[phoneme].value=skVlu - objSK.key_blocks[phoneme].keyframe_insert("value", - -1, offst+frame, "Lipsync") - - objSK.key_blocks[phoneme].value=skVlu - objSK.key_blocks[phoneme].keyframe_insert("value", - -1, offst+frame+hldIn, "Lipsync") - - objSK.key_blocks[phoneme].value=0.0 - objSK.key_blocks[phoneme].keyframe_insert("value", - -1, offst+frame+hldIn+frmOut, "Lipsync") - + if lastPhoneme != phoneme or eval(scn.regMenuTypes.enumModeTypes) == 1: + objSK.key_blocks[phoneme].value = 0.0 + objSK.key_blocks[phoneme].keyframe_insert( + "value", -1, offst + frame - frmIn, "Lipsync" + ) + + objSK.key_blocks[phoneme].value = skVlu + objSK.key_blocks[phoneme].keyframe_insert( + "value", -1, offst + frame, "Lipsync" + ) + objSK.key_blocks[phoneme].value = skVlu + objSK.key_blocks[phoneme].keyframe_insert( + "value", -1, offst + frame + hldIn, "Lipsync" + ) + objSK.key_blocks[phoneme].value = 0.0 + objSK.key_blocks[phoneme].keyframe_insert( + "value", -1, offst + frame + hldIn + frmOut, "Lipsync" + ) lastPhoneme = phoneme + # lipsyncer operation start class btn_lipsyncer(bpy.types.Operator): bl_idname = 'lipsync.go' @@ -229,23 +242,32 @@ class btn_lipsyncer(bpy.types.Operator): obj = context.active_object # testing if object is valid - if obj!=None: - if obj.type=="MESH": - if obj.data.shape_keys!=None: - if scn.fpath!='': lipsyncer() - else: print ("select a Moho file") - else: print("No shape keys") - - elif obj.type=="ARMATURE": - if 1:#XXX add prop test - if scn.fpath!='': lipsyncerBone() - else: print ("select a Moho file") - else: print("Create Pose properties") - - else: print ("Object is not a mesh ot bone") - else: print ("Select object") + if obj is not None: + if obj.type == "MESH": + if obj.data.shape_keys is not None: + if scn.regMenuTypes.fpath != '': + lipsyncer() + else: + print("select a Moho file") + else: + print("No shape keys") + + elif obj.type == "ARMATURE": + if 1: # XXX add prop test + if scn.regMenuTypes.fpath != '': + lipsyncerBone() + else: + print("select a Moho file") + else: + print("Create Pose properties") + else: + print("Object is not a mesh ot bone") + else: + print("Select object") + return {'FINISHED'} + # blinker operation start class btn_blinker(bpy.types.Operator): bl_idname = 'blink.go' @@ -254,42 +276,94 @@ class btn_blinker(bpy.types.Operator): def execute(self, context): - scn = context.scene obj = context.object - # testing if object is valid - if obj!=None: - if obj.type=="MESH": - if obj.data.shape_keys!=None: + # testing if object is valid + if obj is not None: + if obj.type == "MESH": + if obj.data.shape_keys is not None: for key in obj.data.shape_keys.key_blocks: - if key.name=='blink': + if key.name == 'blink': blinker() - #return - else: print("No shape keys") - else: print ("Object is not a mesh ot bone") - else: print ("Select object") + # return + else: + print("No shape keys") + else: + print("Object is not a mesh ot bone") + else: + print("Select object") + return {'FINISHED'} -#defining custom enumeratos +# defining custom enumeratos class menuTypes(bpy.types.PropertyGroup): - enumFileTypes = EnumProperty(items =(('0', 'Papagayo', ''), - ('1', 'Jlipsync Or Yolo', '') - #,('2', 'Retarget', '') - ), - name = 'Choose FileType', - default = '0') - - enumBlinkTypes = EnumProperty(items =(('0', 'Specific', ''), - ('1', 'Random','')), - name = 'Choose BlinkType', - default = '0') + enumFileTypes = EnumProperty( + items=(('0', 'Papagayo', ''), + ('1', 'Jlipsync Or Yolo', '') + # ('2', 'Retarget', '') + ), + name='Choose FileType', + default='0' + ) + enumBlinkTypes = EnumProperty( + items=(('0', 'Specific', ''), + ('1', 'Random', '')), + name='Choose BlinkType', + default='0' + ) + enumModeTypes = EnumProperty( + items=(('0', 'Lipsyncer', ''), + ('1', 'Blinker', '')), + name='Choose Mode', + default='0' + ) + + fpath = StringProperty( + name="Import File ", + description="Select your voice file", + subtype="FILE_PATH" + ) + skscale = FloatProperty( + description="Smoothing shape key values", + min=0.1, max=1.0, + default=0.8 + ) + offset = IntProperty( + description="Offset your frames", + default=0 + ) + easeIn = IntProperty( + description="Smoothing In curve", + min=1, default=3 + ) + easeOut = IntProperty( + description="Smoothing Out curve", + min=1, + default=3 + ) + holdGap = IntProperty( + description="Holding for slow keys", + min=0, + default=0 + ) + blinkSp = IntProperty( + description="Space between blinks", + min=1, + default=100 + ) + blinkNm = IntProperty( + description="Number of blinks", + min=1, + default=10 + ) + blinkMod = IntProperty( + description="Randomzing keyframe placment", + min=1, + default=10 + ) - enumModeTypes = EnumProperty(items =(('0', 'Lipsyncer',''), - ('1', 'Blinker','')), - name = 'Choose Mode', - default = '0') # drawing the user interface class LipSyncBoneUI(bpy.types.Panel): @@ -297,61 +371,50 @@ class LipSyncBoneUI(bpy.types.Panel): bl_region_type = "UI" bl_label = "Phonemes" bl_category = 'Animation' - + def draw(self, context): layout = self.layout col = layout.column() bone = bpy.context.active_pose_bone - #showing the current object type - if bone: #and if scn.regMenuTypes.enumModeTypes == '0': + # showing the current object type + if bone: # and if scn.regMenuTypes.enumModeTypes == '0': col.prop(bone, "location", index=0, text="AI") col.prop(bone, "location", index=1, text="E") col.prop(bone, "location", index=2, text="FV") + if bpy.context.scene.unit_settings.system_rotation == 'RADIANS': col.prop(bone, "rotation_euler", index=0, text="L") col.prop(bone, "rotation_euler", index=1, text="MBP") col.prop(bone, "rotation_euler", index=2, text="O") else: - row=col.row() + row = col.row() row.prop(bone, "rotation_euler", index=0, text="L") row.label(text=str("%4.2f" % (bone.rotation_euler.x))) - row=col.row() + + row = col.row() row.prop(bone, "rotation_euler", index=1, text="MBP") row.label(text=str("%4.2f" % (bone.rotation_euler.y))) - row=col.row() + + row = col.row() row.prop(bone, "rotation_euler", index=2, text="O") row.label(text=str("%4.2f" % (bone.rotation_euler.z))) + col.prop(bone, "scale", index=0, text="U") col.prop(bone, "scale", index=1, text="WQ") col.prop(bone, "scale", index=2, text="etc") else: layout.label(text="No good bone is selected") + # drawing the user interface class LipSyncUI(bpy.types.Panel): bl_space_type = "VIEW_3D" bl_region_type = "TOOL_PROPS" bl_label = "LipSync Importer & Blinker" - newType= bpy.types.Scene - - newType.fpath = StringProperty(name="Import File ", description="Select your voice file", subtype="FILE_PATH") - newType.skscale = FloatProperty(description="Smoothing shape key values", min=0.1, max=1.0, default=0.8) - newType.offset = IntProperty(description="Offset your frames", default=0) - - newType.easeIn = IntProperty(description="Smoothing In curve", min=1, default=3) - newType.easeOut = IntProperty(description="Smoothing Out curve", min=1, default=3) - newType.holdGap = IntProperty(description="Holding for slow keys", min=0, default=0) - - newType.blinkSp = IntProperty(description="Space between blinks", min=1, default=100) - newType.blinkNm = IntProperty(description="Number of blinks", min=1, default=10) - - newType.blinkMod = IntProperty(description="Randomzing keyframe placment", min=1, default=10) - def draw(self, context): - obj = bpy.context.active_object scn = bpy.context.scene @@ -359,13 +422,14 @@ class LipSyncUI(bpy.types.Panel): col = layout.column() # showing the current object type - if obj != None: + if obj is not None: if obj.type == "MESH": split = col.split(align=True) split.label(text="The active object is: ", icon="OBJECT_DATA") split.label(obj.name, icon="EDITMODE_HLT") - elif obj.type == "ARMATURE": # bone needs to be selected - if obj.mode == "POSE": # mode needs to be pose + + elif obj.type == "ARMATURE": # bone needs to be selected + if obj.mode == "POSE": # mode needs to be pose split = col.split(align=True) split.label(text="The active object is: ", icon="ARMATURE_DATA") split.label(obj.name, icon="EDITMODE_HLT") @@ -382,100 +446,95 @@ class LipSyncUI(bpy.types.Panel): # the lipsyncer panel if scn.regMenuTypes.enumModeTypes == '0': # choose the file format - col.row().prop(scn.regMenuTypes, 'enumFileTypes', text = ' ', expand = True) + col.row().prop(scn.regMenuTypes, 'enumFileTypes', text=' ', expand=True) # Papagayo panel if scn.regMenuTypes.enumFileTypes == '0': - col.prop(context.scene, "fpath") + col.prop(scn.regMenuTypes, "fpath") + split = col.split(align=True) split.label("Key Value :") - split.prop(context.scene, "skscale") + split.prop(scn.regMenuTypes, "skscale") + split = col.split(align=True) split.label("Frame Offset :") - split.prop(context.scene, "offset") + split.prop(scn.regMenuTypes, "offset") + split = col.split(align=True) - split.prop(context.scene, "easeIn", "Ease In") - split.prop(context.scene, "holdGap", "Hold Gap") - split.prop(context.scene, "easeOut", "Ease Out") + split.prop(scn.regMenuTypes, "easeIn", "Ease In") + split.prop(scn.regMenuTypes, "holdGap", "Hold Gap") + split.prop(scn.regMenuTypes, "easeOut", "Ease Out") col.operator('lipsync.go', text='Plot Keys to the Timeline') # Jlipsync & Yolo panel elif scn.regMenuTypes.enumFileTypes == '1': - col.prop(context.scene, "fpath") + col.prop(scn.regMenuTypes, "fpath") split = col.split(align=True) split.label("Key Value :") - split.prop(context.scene, "skscale") + split.prop(scn.regMenuTypes, "skscale") + split = col.split(align=True) split.label("Frame Offset :") - split.prop(context.scene, "offset") + split.prop(scn.regMenuTypes, "offset") col.operator('lipsync.go', text='Plot Keys to the Timeline') # the blinker panel elif scn.regMenuTypes.enumModeTypes == '1': # choose blink type - col.row().prop(scn.regMenuTypes, 'enumBlinkTypes', text = ' ', expand = True) + col.row().prop(scn.regMenuTypes, 'enumBlinkTypes', text=' ', expand=True) # specific panel if scn.regMenuTypes.enumBlinkTypes == '0': split = col.split(align=True) split.label("Key Value :") - split.prop(context.scene, "skscale") + split.prop(scn.regMenuTypes, "skscale") + split = col.split(align=True) split.label("Frame Offset :") - split.prop(context.scene, "offset") + split.prop(scn.regMenuTypes, "offset") + split = col.split(align=True) - split.prop(context.scene, "easeIn", "Ease In") - split.prop(context.scene, "holdGap", "Hold Gap") - split.prop(context.scene, "easeOut", "Ease Out") - col.prop(context.scene, "blinkSp", "Spacing") - col.prop(context.scene, "blinkNm", "Times") + split.prop(scn.regMenuTypes, "easeIn", "Ease In") + split.prop(scn.regMenuTypes, "holdGap", "Hold Gap") + split.prop(scn.regMenuTypes, "easeOut", "Ease Out") + col.prop(scn.regMenuTypes, "blinkSp", "Spacing") + col.prop(scn.regMenuTypes, "blinkNm", "Times") col.operator('blink.go', text='Add Keys to the Timeline') # Random panel elif scn.regMenuTypes.enumBlinkTypes == '1': split = col.split(align=True) split.label("Key Value :") - split.prop(context.scene, "skscale") + split.prop(scn.regMenuTypes, "skscale") + split = col.split(align=True) split.label("Frame Start :") - split.prop(context.scene, "offset") + split.prop(scn.regMenuTypes, "offset") + split = col.split(align=True) - split.prop(context.scene, "easeIn", "Ease In") - split.prop(context.scene, "holdGap", "Hold Gap") - split.prop(context.scene, "easeOut", "Ease Out") + split.prop(scn.regMenuTypes, "easeIn", "Ease In") + split.prop(scn.regMenuTypes, "holdGap", "Hold Gap") + split.prop(scn.regMenuTypes, "easeOut", "Ease Out") + split = col.split(align=True) - split.prop(context.scene, "blinkSp", "Spacing") - split.prop(context.scene, "blinkMod", "Random Modifier") - col.prop(context.scene, "blinkNm", "Times") + split.prop(scn.regMenuTypes, "blinkSp", "Spacing") + split.prop(scn.regMenuTypes, "blinkMod", "Random Modifier") + col.prop(scn.regMenuTypes, "blinkNm", "Times") col.operator('blink.go', text='Add Keys to the Timeline') -# clearing vars -def clear_properties(): - - # can happen on reload - if bpy.context.scene is None: - return - - props = ["fpath", "skscale", "offset", "easeIn", "easeOut", "holdGap", "blinkSp", "blinkNm", "blinkMod"] - for p in props: - if p in bpy.types.Scene.bl_rna.properties: - exec("del bpy.types.Scene."+p) - if p in bpy.context.scene: - del bpy.context.scene[p] - # registering the script def register(): bpy.utils.register_module(__name__) - bpy.types.Scene.regMenuTypes = PointerProperty(type = menuTypes) + bpy.types.Scene.regMenuTypes = PointerProperty(type=menuTypes) + def unregister(): bpy.utils.unregister_module(__name__) del bpy.types.Scene.regMenuTypes - clear_properties() if __name__ == "__main__": register()