1
# ##### BEGIN GPL LICENSE BLOCK #####
3
# This program is free software; you can redistribute it and/or
4
# modify it under the terms of the GNU General Public License
5
# as published by the Free Software Foundation; either version 2
6
# of the License, or (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software Foundation,
15
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
# ##### END GPL LICENSE BLOCK #####
20
"name": "LipSync Importer & Blinker",
21
"author": "Yousef Harfoush - bat3a ;)",
24
"location": "3D window > Tool Shelf",
25
"description": "Plot Moho (Papagayo, Jlipsync, Yolo) file to frames and adds automatic blinking",
27
"wiki_url": "http://wiki.blender.org/index.php?title=Extensions:2.5/Py/Scripts/Import-Export/Lipsync_Importer",
28
"tracker_url": "http://projects.blender.org/tracker/index.php?func=detail&aid=24080&group_id=153&atid=468",
29
"category": "Import-Export"}
33
from random import random
34
from bpy.props import *
35
from bpy.props import IntProperty, FloatProperty, StringProperty
40
# truning off relative path - it causes an error if it was true
41
if bpy.context.user_preferences.filepaths.use_relative_paths == True:
42
bpy.context.user_preferences.filepaths.use_relative_paths = False
47
scn = bpy.context.scene
48
obj = bpy.context.object
50
if scn.regMenuTypes.enumBlinkTypes == '0':
52
elif scn.regMenuTypes.enumBlinkTypes == '1':
53
modifier = scn.blinkMod
55
#creating keys with blinkNm count
56
for y in range(scn.blinkNm):
57
frame = y * scn.blinkSp + int(random()*modifier)
58
createShapekey('blink', frame)
60
# -----------code contributed by dalai felinto adds armature support modified by me-------------------
63
"AI": ('location', 0),
65
"FV": ('location', 2),
66
"L": ('rotation_euler', 0),
67
"MBP": ('rotation_euler', 1),
68
"O": ('rotation_euler', 2),
72
"rest": ('ik_stretch', -1)
76
# reading imported file & creating keys
77
object = bpy.context.object
78
scene = bpy.context.scene
79
bone = bpy.context.active_pose_bone
83
f=open(scene.fpath) # importing file
84
f.readline() # reading the 1st line that we don"t need
88
lsta = re.split("\n+", line)
90
# building a list of frames & shapes indexes
91
lst = re.split(":? ", lsta[0])# making a list of a frame & number
94
for key,attribute in bone_keys.items():
96
createBoneKeys(key, bone, attribute, frame)
98
def resetBoneScale(bone):
99
# set the attributes used by papagayo to 0.0
100
for attribute,index in bone_keys.values():
102
#bone.location[0] = 0.0
103
exec("bone.%s[%d] = %f" % (attribute, index, 0.0))
105
exec("bone.%s = %f" % (attribute, 0.0))
107
def addBoneKey(bone, data_path, index=-1, value=None, frame=bpy.context.scene.frame_current, group=""):
108
# set a value and keyframe for the bone
109
# it assumes the 'bone' variable was defined before
110
# and it's the current selected bone
114
# bone.location[0] = 0.0
115
exec("bone.%s[%d] = %f" % (data_path, index, value))
117
exec("bone.%s = %f" % (data_path, value))
119
# bone.keyframe_insert("location", 0, 10.0, "Lipsync")
120
exec('bone.keyframe_insert("%s", %d, %f, "%s")' % (data_path, index, frame, group))
122
# creating keys with offset and eases for a phonem @ the Skframe
123
def createBoneKeys(phoneme, bone, attribute, frame):
126
scene = bpy.context.scene
127
object = bpy.context.object
129
offst = scene.offset # offset value
130
skVlu = scene.skscale # shape key value
132
#in case of Papagayo format
133
if scene.regMenuTypes.enumFileTypes == '0' :
134
frmIn = scene.easeIn # ease in value
135
frmOut = scene.easeOut # ease out value
136
hldIn = scene.holdGap # holding time value
138
#in case of Jlipsync format or Yolo
139
elif scene.regMenuTypes.enumFileTypes == '1' :
144
# inserting the In key only when phonem change or when blinking
145
if lastPhoneme!=phoneme or eval(scene.regMenuTypes.enumModeTypes) == 1:
146
addBoneKey(bone, attribute[0], attribute[1], 0.0, offst+frame-frmIn, "Lipsync")
148
addBoneKey(bone, attribute[0], attribute[1], skVlu, offst+frame, "Lipsync")
149
addBoneKey(bone, attribute[0], attribute[1], skVlu, offst+frame+hldIn, "Lipsync")
150
addBoneKey(bone, attribute[0], attribute[1], 0.0, offst+frame+hldIn+frmOut, "Lipsync")
154
# -------------------------------------------------------------------------------
156
# reading imported file & creating keys
159
obj = bpy.context.object
160
scn = bpy.context.scene
162
f=open(scn.fpath) # importing file
163
f.readline() # reading the 1st line that we don"t need
168
lsta = re.split("\n+", line)
170
# building a list of frames & shapes indexes
171
lst = re.split(":? ", lsta[0])# making a list of a frame & number
174
for key in obj.data.shape_keys.key_blocks:
175
if lst[1] == key.name:
176
createShapekey(key.name, frame)
178
# creating keys with offset and eases for a phonem @ the frame
179
def createShapekey(phoneme, frame):
183
scn = bpy.context.scene
184
obj = bpy.context.object
185
objSK = obj.data.shape_keys
187
offst = scn.offset # offset value
188
skVlu = scn.skscale # shape key value
190
#in case of Papagayo format
191
if scn.regMenuTypes.enumFileTypes == '0' :
192
frmIn = scn.easeIn # ease in value
193
frmOut = scn.easeOut # ease out value
194
hldIn = scn.holdGap # holding time value
196
#in case of Jlipsync format or Yolo
197
elif scn.regMenuTypes.enumFileTypes == '1' :
202
# inserting the In key only when phonem change or when blinking
203
if lastPhoneme!=phoneme or eval(scn.regMenuTypes.enumModeTypes) == 1:
204
objSK.key_blocks[phoneme].value=0.0
205
objSK.key_blocks[phoneme].keyframe_insert("value",
206
-1, offst+frame-frmIn, "Lipsync")
208
objSK.key_blocks[phoneme].value=skVlu
209
objSK.key_blocks[phoneme].keyframe_insert("value",
210
-1, offst+frame, "Lipsync")
212
objSK.key_blocks[phoneme].value=skVlu
213
objSK.key_blocks[phoneme].keyframe_insert("value",
214
-1, offst+frame+hldIn, "Lipsync")
216
objSK.key_blocks[phoneme].value=0.0
217
objSK.key_blocks[phoneme].keyframe_insert("value",
218
-1, offst+frame+hldIn+frmOut, "Lipsync")
220
lastPhoneme = phoneme
222
# lipsyncer operation start
223
class btn_lipsyncer(bpy.types.Operator):
224
bl_idname = 'lipsync.go'
225
bl_label = 'Start Processing'
226
bl_description = 'Plots the voice file keys to timeline'
228
def execute(self, context):
231
obj = context.active_object
233
# testing if object is valid
236
if obj.data.shape_keys!=None:
237
if scn.fpath!='': lipsyncer()
238
else: print ("select a Moho file")
239
else: print("No shape keys")
241
elif obj.type=="ARMATURE":
242
if 1:#XXX add prop test
243
if scn.fpath!='': lipsyncerBone()
244
else: print ("select a Moho file")
245
else: print("Create Pose properties")
247
else: print ("Object is not a mesh ot bone")
248
else: print ("Select object")
251
# blinker operation start
252
class btn_blinker(bpy.types.Operator):
253
bl_idname = 'blink.go'
254
bl_label = 'Start Processing'
255
bl_description = 'Add blinks at random or specifice frames'
257
def execute(self, context):
262
# testing if object is valid
265
if obj.data.shape_keys!=None:
266
for key in obj.data.shape_keys.key_blocks:
267
if key.name=='blink':
270
else: print("No shape keys")
271
else: print ("Object is not a mesh ot bone")
272
else: print ("Select object")
276
#defining custom enumeratos
277
class menuTypes(bpy.types.PropertyGroup):
279
enumFileTypes = EnumProperty(items =(('0', 'Papagayo', ''),
280
('1', 'Jlipsync Or Yolo', '')
281
#,('2', 'Retarget', '')
283
name = 'Choose FileType',
286
enumBlinkTypes = EnumProperty(items =(('0', 'Specific', ''),
288
name = 'Choose BlinkType',
291
enumModeTypes = EnumProperty(items =(('0', 'Lipsyncer',''),
292
('1', 'Blinker','')),
293
name = 'Choose Mode',
296
# drawing the user interface
297
class LipSyncBoneUI(bpy.types.Panel):
298
bl_space_type = "VIEW_3D"
299
bl_region_type = "UI"
300
bl_label = "Phonemes"
302
def draw(self, context):
304
col = layout.column()
306
bone = bpy.context.active_pose_bone
308
#showing the current object type
309
if bone: #and if scn.regMenuTypes.enumModeTypes == '0':
310
col.prop(bone, "location", index=0, text="AI")
311
col.prop(bone, "location", index=1, text="E")
312
col.prop(bone, "location", index=2, text="FV")
313
if bpy.context.scene.unit_settings.system_rotation == 'RADIANS':
314
col.prop(bone, "rotation_euler", index=0, text="L")
315
col.prop(bone, "rotation_euler", index=1, text="MBP")
316
col.prop(bone, "rotation_euler", index=2, text="O")
319
row.prop(bone, "rotation_euler", index=0, text="L")
320
row.label(text=str("%4.2f" % (bone.rotation_euler.x)))
322
row.prop(bone, "rotation_euler", index=1, text="MBP")
323
row.label(text=str("%4.2f" % (bone.rotation_euler.y)))
325
row.prop(bone, "rotation_euler", index=2, text="O")
326
row.label(text=str("%4.2f" % (bone.rotation_euler.z)))
327
col.prop(bone, "scale", index=0, text="U")
328
col.prop(bone, "scale", index=1, text="WQ")
329
col.prop(bone, "scale", index=2, text="etc")
331
layout.label(text="No good bone is selected")
333
# drawing the user interface
334
class LipSyncUI(bpy.types.Panel):
335
bl_space_type = "VIEW_3D"
336
bl_region_type = "TOOL_PROPS"
337
bl_label = "LipSync Importer & Blinker"
339
newType= bpy.types.Scene
340
scn = bpy.context.scene
342
newType.fpath = StringProperty(name="Import File ", description="Select your voice file", subtype="FILE_PATH")
343
newType.skscale = FloatProperty(description="Smoothing shape key values", min=0.1, max=1.0, default=0.8)
344
newType.offset = IntProperty(description="Offset your frames", default=0)
346
newType.easeIn = IntProperty(description="Smoothing In curve", min=1, default=3)
347
newType.easeOut = IntProperty(description="Smoothing Out curve", min=1, default=3)
348
newType.holdGap = IntProperty(description="Holding for slow keys", min=0, default=0)
350
newType.blinkSp = IntProperty(description="Space between blinks", min=1, default=100)
351
newType.blinkNm = IntProperty(description="Number of blinks", min=1, default=10)
353
newType.blinkMod = IntProperty(description="Randomzing keyframe placment", min=1, default=10)
355
def draw(self, context):
357
obj = bpy.context.active_object
358
scn = bpy.context.scene
361
col = layout.column()
363
# showing the current object type
365
if obj.type == "MESH":
366
split = col.split(align=True)
367
split.label(text="The active object is: ", icon="OBJECT_DATA")
368
split.label(obj.name, icon="EDITMODE_HLT")
369
elif obj.type == "ARMATURE": # bone needs to be selected
370
if obj.mode == "POSE": # mode needs to be pose
371
split = col.split(align=True)
372
split.label(text="The active object is: ", icon="ARMATURE_DATA")
373
split.label(obj.name, icon="EDITMODE_HLT")
375
col.label(text="You need to select Pose mode!", icon="OBJECT_DATA")
377
col.label(text="The active object is not a Mesh or Armature!", icon="OBJECT_DATA")
379
layout.label(text="No object is selected", icon="OBJECT_DATA")
381
col.row().prop(scn.regMenuTypes, 'enumModeTypes')
384
# the lipsyncer panel
385
if scn.regMenuTypes.enumModeTypes == '0':
386
# choose the file format
387
col.row().prop(scn.regMenuTypes, 'enumFileTypes', text = ' ', expand = True)
390
if scn.regMenuTypes.enumFileTypes == '0':
391
col.prop(context.scene, "fpath")
392
split = col.split(align=True)
393
split.label("Key Value :")
394
split.prop(context.scene, "skscale")
395
split = col.split(align=True)
396
split.label("Frame Offset :")
397
split.prop(context.scene, "offset")
398
split = col.split(align=True)
399
split.prop(context.scene, "easeIn", "Ease In")
400
split.prop(context.scene, "holdGap", "Hold Gap")
401
split.prop(context.scene, "easeOut", "Ease Out")
403
col.operator('lipsync.go', text='Plot Keys to the Timeline')
405
# Jlipsync & Yolo panel
406
elif scn.regMenuTypes.enumFileTypes == '1':
407
col.prop(context.scene, "fpath")
408
split = col.split(align=True)
409
split.label("Key Value :")
410
split.prop(context.scene, "skscale")
411
split = col.split(align=True)
412
split.label("Frame Offset :")
413
split.prop(context.scene, "offset")
415
col.operator('lipsync.go', text='Plot Keys to the Timeline')
418
elif scn.regMenuTypes.enumModeTypes == '1':
420
col.row().prop(scn.regMenuTypes, 'enumBlinkTypes', text = ' ', expand = True)
423
if scn.regMenuTypes.enumBlinkTypes == '0':
424
split = col.split(align=True)
425
split.label("Key Value :")
426
split.prop(context.scene, "skscale")
427
split = col.split(align=True)
428
split.label("Frame Offset :")
429
split.prop(context.scene, "offset")
430
split = col.split(align=True)
431
split.prop(context.scene, "easeIn", "Ease In")
432
split.prop(context.scene, "holdGap", "Hold Gap")
433
split.prop(context.scene, "easeOut", "Ease Out")
434
col.prop(context.scene, "blinkSp", "Spacing")
435
col.prop(context.scene, "blinkNm", "Times")
436
col.operator('blink.go', text='Add Keys to the Timeline')
439
elif scn.regMenuTypes.enumBlinkTypes == '1':
440
split = col.split(align=True)
441
split.label("Key Value :")
442
split.prop(context.scene, "skscale")
443
split = col.split(align=True)
444
split.label("Frame Start :")
445
split.prop(context.scene, "offset")
446
split = col.split(align=True)
447
split.prop(context.scene, "easeIn", "Ease In")
448
split.prop(context.scene, "holdGap", "Hold Gap")
449
split.prop(context.scene, "easeOut", "Ease Out")
450
split = col.split(align=True)
451
split.prop(context.scene, "blinkSp", "Spacing")
452
split.prop(context.scene, "blinkMod", "Random Modifier")
453
col.prop(context.scene, "blinkNm", "Times")
454
col.operator('blink.go', text='Add Keys to the Timeline')
458
def clear_properties():
460
# can happen on reload
461
if bpy.context.scene is None:
464
props = ["fpath", "skscale", "offset", "easeIn", "easeOut", "holdGap", "blinkSp", "blinkNm", "blinkMod"]
466
if p in bpy.types.Scene.bl_rna.properties:
467
exec("del bpy.types.Scene."+p)
468
if p in bpy.context.scene:
469
del bpy.context.scene[p]
471
# registering the script
473
bpy.utils.register_module(__name__)
474
bpy.types.Scene.regMenuTypes = PointerProperty(type = menuTypes)
477
bpy.utils.unregister_module(__name__)
478
del bpy.context.scene.regMenuTypes
482
if __name__ == "__main__":