UI: Move Extensions repositories popover to header
[blender-addons-contrib.git] / io_import_sound_to_anim.py
blobf400483ffb5aadd66adf537995be5af6faf852d8
1 #!/usr/bin/python3
2 # To change this template, choose Tools | Templates
3 # and open the template in the editor.
4 # ***** GPL LICENSE BLOCK *****
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 # All rights reserved.
19 # ***** GPL LICENSE BLOCK *****
21 bl_info = {
22 "name": "Import: Sound to Animation",
23 "author": "Vlassius",
24 "version": (0, 80),
25 "blender": (2, 80, 0),
26 "location": "Select a object > View3D > Tool Shelf > Import Movement From .Wav File",
27 "description": "Extract movement from .wav sound file.",
28 "warning": "",
29 "doc_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
30 "Scripts/Import-Export/Import_Movement_From_Audio_File",
31 "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
32 "category": "Import-Export"}
34 """
35 -- Extract movement from sound file, to help in animation - import script --<br>
37 - NOTES:
38 - This script takes a wav file and get sound "movement" to help you in sync the movement to words in the wave file. <br>
39 - Supported Audio: .wav (wave) 8 bits and 16 bits - mono and multichanel file<br>
40 - At least Blender 2.80 is necessary to run this program.
41 - Brazil
43 """
45 import bpy
46 from bpy.props import *
47 #from io_utils import ImportHelper
48 import wave
50 #para deixar global
51 def _Interna_Globals(BytesDadosTotProcess, context):
52 global array
53 global arrayAutoSense
55 array= bytearray(BytesDadosTotProcess) # cria array
56 arrayAutoSense= bytearray((BytesDadosTotProcess)*2) # cria array para AutoAudioSense
57 context.object.imp_sound_to_anim.bArrayCriado=True
60 #==================================================================================================
61 # BLENDER UI Panel
62 #==================================================================================================
64 """class VIEW3D_PT_CustomMenuPanel(bpy.types.Panel):
65 bl_space_type = "PROPERTIES"
66 bl_region_type = "WINDOW"
67 bl_context = "object"
68 bl_label = "Import Movement From Wav File"
69 bl_options = {'DEFAULT_CLOSED'}"""
71 class VIEW3D_PT_SoundPanel(bpy.types.Panel):
72 bl_idname = "IMPORTWAVTOOL_PT_tools"
73 bl_space_type = "VIEW_3D"
74 bl_context = "objectmode"
75 bl_region_type = "UI"
76 bl_label = "Import Tool"
77 bl_category = "Animate"
78 bl_options = {'DEFAULT_CLOSED'}
80 def draw(self, context):
81 layout = self.layout
83 b=bpy.context.active_object.type=='EMPTY' or bpy.context.active_object.type=='ARMATURE' or \
84 bpy.context.active_object.type=='MESH' or \
85 bpy.context.active_object.type=='CAMERA' or \
86 bpy.context.active_object.type=='LAMP'
87 if not b:
88 row=layout.row()
89 row.label(text="The Selected Object is: type \"" + bpy.context.active_object.type + \
90 "\", and it is not supported.")
91 row=layout.row()
92 row.label(text="Supported Object are Type: Armature, Mesh, Camera and Lamp")
93 row=layout.row()
94 else:
95 #print(context.object.imp_sound_to_anim.bTypeImport)
96 if context.object.imp_sound_to_anim.bTypeImport == 0:
97 #mount panel to Direct animation
98 row=layout.row()
99 layout.operator("import.sound_animation_botao_udirect")
101 # monta as telas quando está rodando
102 elif context.object.imp_sound_to_anim.Working!="": #its running
103 row=layout.row()
104 row=layout.row()
106 if context.object.imp_sound_to_anim.Working== "CheckSmartRender":
107 #context.object.imp_sound_to_anim.Info_check_smartrender=
108 row=layout.row()
109 row.label(text="Checking for Smart Render...")
110 row=layout.row()
111 row.label(text=context.object.imp_sound_to_anim.Info_check_smartrender)
112 row=layout.row()
114 elif context.object.imp_sound_to_anim.Working== "SmartRender":
115 #context.object.imp_sound_to_anim.Info_check_smartrender=
116 row=layout.row()
117 row.label(text="Processing Smart Render...")
118 row=layout.row()
119 row.label(text=context.object.imp_sound_to_anim.Info_check_smartrender)
120 row=layout.row()
122 elif context.object.imp_sound_to_anim.Working== "ProcessaSom":
123 #context.object.imp_sound_to_anim.Info_Import=
124 row=layout.row()
125 row.label(text="Processing Sound File...")
126 row=layout.row()
127 row.label(text=context.object.imp_sound_to_anim.Info_Import)
129 elif context.object.imp_sound_to_anim.Working== "wavimport":
130 #context.object.imp_sound_to_anim.Info_Import=
131 row=layout.row()
132 row.label(text="Importing Keys...")
133 row=layout.row()
134 row.label(text=context.object.imp_sound_to_anim.Info_Import)
135 row=layout.row()
137 # botao cancel
138 layout.operator(OBJECT_OT_Botao_Cancel.bl_idname)
139 row=layout.row()
141 elif context.object.imp_sound_to_anim.bTypeImport == 1:
142 row=layout.row()
143 row.label(text="1)Click button \"Process Wav\",")
144 row=layout.row()
145 row.label(text="2)Click Button \"Import Key Frames\",")
146 row=layout.row()
147 row.label(text="Run the animation and Enjoy!")
148 row=layout.row()
149 row.prop(context.object.imp_sound_to_anim,"action_auto_audio_sense")
150 row=layout.row()
151 if context.object.imp_sound_to_anim.action_auto_audio_sense == 0: # se auto audio sense desligado
152 row.prop(context.object.imp_sound_to_anim,"audio_sense")
153 row=layout.row()
155 else: #somente se autosense ligado
156 if context.object.imp_sound_to_anim.remove_beat == 0 :
157 row.prop(context.object.imp_sound_to_anim,"use_just_beat")
159 if context.object.imp_sound_to_anim.use_just_beat == 0:
160 row.prop(context.object.imp_sound_to_anim,"remove_beat")
162 if context.object.imp_sound_to_anim.use_just_beat or context.object.imp_sound_to_anim.remove_beat:
163 if not context.object.imp_sound_to_anim.beat_less_sensible and not context.object.imp_sound_to_anim.beat_more_sensible:
164 row=layout.row()
165 if context.object.imp_sound_to_anim.beat_less_sensible ==0:
166 row.prop(context.object.imp_sound_to_anim,"beat_more_sensible")
168 if context.object.imp_sound_to_anim.beat_more_sensible ==0:
169 row.prop(context.object.imp_sound_to_anim,"beat_less_sensible")
171 row=layout.row()
172 row.prop(context.object.imp_sound_to_anim,"action_per_second")
173 row=layout.row()
174 row.prop(context.object.imp_sound_to_anim,"action_escale")
176 #row=layout.row()
177 row.label(text="Result from 0 to " + str(round(255/context.object.imp_sound_to_anim.action_escale,4)) + "")
179 row=layout.row()
180 row.label(text="Property to Change:")
181 row.prop(context.object.imp_sound_to_anim,"import_type")
183 #coluna
184 row=layout.row()
185 row.prop(context.object.imp_sound_to_anim,"import_where1")
186 row.prop(context.object.imp_sound_to_anim,"import_where2")
187 row.prop(context.object.imp_sound_to_anim,"import_where3")
189 row=layout.row()
190 row.label(text='Optional Configurations:')
191 row=layout.row()
193 row.prop(context.object.imp_sound_to_anim,"frames_per_second")
194 row=layout.row()
195 #coluna
196 column= layout.column()
197 split=column.split(factor=0.5) #percentage=0.5
198 col=split.column()
200 row=col.row()
201 row.prop(context.object.imp_sound_to_anim,"frames_initial")
203 row=col.row()
204 row.prop(context.object.imp_sound_to_anim,"action_min_value")
206 col=split.column()
208 row=col.row()
209 row.prop(context.object.imp_sound_to_anim,"optimization_destructive")
211 row=col.row()
212 row.prop(context.object.imp_sound_to_anim,"action_max_value")
214 row=layout.row()
216 row.prop(context.object.imp_sound_to_anim,"action_offset_x")
217 row.prop(context.object.imp_sound_to_anim,"action_offset_y")
218 row.prop(context.object.imp_sound_to_anim,"action_offset_z")
220 row=layout.row()
221 row.prop(context.object.imp_sound_to_anim,"audio_channel_select")
222 row.prop(context.object.imp_sound_to_anim,"action_valor_igual")
224 #operator button
225 #OBJECT_OT_Botao_Go => Botao_GO
226 row=layout.row()
227 layout.operator(OBJECT_OT_Botao_Go.bl_idname)
229 row=layout.row()
230 row.label(text=context.object.imp_sound_to_anim.Info_Import)
232 # preciso garantir a existencia do array porque o Blender salva no arquivo como existente sem o array existir
233 try:
234 array
235 except NameError:
236 nada=0 #dummy
237 else:
238 if context.object.imp_sound_to_anim.bArrayCriado:
239 layout.operator(OBJECT_OT_Botao_Import.bl_idname)
240 row=layout.row()
242 #Layout SmartRender, somente para Blender_render
243 if bpy.context.scene.render.engine == "BLENDER_RENDER":
244 row=layout.row()
245 row.label(text="----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------")
246 row=layout.row()
247 if context.object.imp_sound_to_anim.Info_check_smartrender!= "":
248 row=layout.row()
249 row.label(text=context.object.imp_sound_to_anim.Info_check_smartrender)
251 row=layout.row()
252 row.operator(OBJECT_OT_Botao_Check_SmartRender.bl_idname)
253 if context.object.imp_sound_to_anim.Info_check_smartrender!= "":
254 row.operator(OBJECT_OT_Botao_SmartRender.bl_idname)
256 row=layout.row()
257 row.prop(context.object.imp_sound_to_anim,"check_smartrender_loc_rot_sc")
258 row.prop(context.object.imp_sound_to_anim,"check_smartrender_material_basic")
259 row=layout.row()
260 row.prop(context.object.imp_sound_to_anim,"check_smartrender_material_transparence")
261 row.prop(context.object.imp_sound_to_anim,"check_smartrender_material_mirror")
263 #-----------------------------
264 #Use Driver
265 #-----------------------------
266 if context.object.imp_sound_to_anim.bTypeImport == 2:
268 row=layout.row()
269 #row.prop(context.object.imp_sound_to_anim,"audio_sense")
270 #row=layout.row()
271 #row.prop(context.object.imp_sound_to_anim,"frames_per_second")
272 #row=layout.row()
273 #row.prop(context.object.imp_sound_to_anim,"action_per_second")
274 #row=layout.row()
275 #layout.operator(ImportWavFile.bl_idname)
279 #==================================================================================================
280 # BLENDER UI PropertyGroup
281 #==================================================================================================
283 class ImpSoundtoAnim(bpy.types.PropertyGroup):
285 #Array created
286 bArrayCriado: IntProperty(name="",
287 description="Avisa que rodou process de som",
288 default=0)
290 #Script Running
291 Working: StringProperty(name="Working",
292 description="Script esta trabalhando",
293 maxlen= 1024,
294 default="")
296 #Nome do objeto
297 Info_Import: StringProperty(name="Info_Import",
298 description="Info about Import",
299 maxlen= 1024,
300 default= "")#this set the initial text
302 #Mensagem Smart Render
303 Info_check_smartrender: StringProperty(name="Info_check_smartrender",
304 description="Smart Render Message",
305 maxlen= 1024,
306 default= "")#this set the initial text
308 #iAudioSensib=0 #sensibilidade volume do audio 0 a 5. Quanto maior, mais sensibilidade
309 audio_sense: IntProperty(name="Audio Sens",
310 description="Audio Sensibility",
311 min=1,
312 max=6,
313 step=1,
314 default= 1)
316 #iFramesPorSeg=15 #Frames por segundo para key frame
317 #fps= (bpy.types.Scene) bpy.context.object.render.fps
318 frames_per_second: IntProperty(name="#Frames/s",
319 description="Frames you want per second. Better match your set up in Blender scene",
320 min=1,
321 max=120,
322 step=1,
323 default= 10)
325 #iMovPorSeg=1 #Sensibilidade de movimento. 3= 3 movimentos por segundo
326 action_per_second: IntProperty(name="Act/s",
327 description="Actions per second. From 1 to #Frames/s",
328 min=1,
329 max=120,
330 step=1,
331 default= 4)#this set the initial text
333 #iDivScala=200
334 #scala do valor do movimento. [se =1 - 0 a 255 ] [se=255 - 0,00000 a 1,00000] [se=1000 - 0 a 0.255]
335 action_escale: IntProperty(name="Scale",
336 description="Scale the result values. See the text at right side of the field",
337 min=1,
338 max=99999,
339 step=100,
340 default= 100)#this set the initial text
342 #iMaxValue=255
343 action_max_value: IntProperty(name="Clip Max",
344 description="Set the max value (clip higher values)",
345 min=1,
346 max=255,
347 step=1,
348 default= 255)#this set the initial text
350 #iMinValue=0
351 action_min_value: IntProperty(name="Clip Min",
352 description="Set the min value. (clip lower values)",
353 min=0,
354 max=255,
355 step=1,
356 default= 0)#this set the initial text
358 #iStartFrame=0#
359 frames_initial: IntProperty(name="Frame Ini",
360 description="Where to start to put the computed values",
361 min=0,
362 max=999999999,
363 step=1,
364 default= 0)
366 audio_channel_select: IntProperty(name="Audio Channel",
367 description="Choose the audio channel to use",
368 min=1,
369 max=10,
370 step=1,
371 default= 1)
373 action_offset_x: FloatProperty(name="XOffset",
374 description="Offset X Values",
375 min=-999999,
376 max=999999,
377 step=1,
378 default= 0)
380 action_offset_y: FloatProperty(name="YOffset",
381 description="Offset Y Values",
382 min=-999999,
383 max=999999,
384 step=1,
385 default= 0)
387 action_offset_z: FloatProperty(name="ZOffset",
388 description="Offset Z Values",
389 min=-999999,
390 max=999999,
391 step=1,
392 default= 0)
394 import_type: EnumProperty(items=(('imp_t_Scale', "Scale", "Apply to Scale"),
395 ('imp_t_Rotation', "Rotation", "Apply to Rotation"),
396 ('imp_t_Location', "Location", "Apply to Location")
398 name="",
399 description= "Property to Import Values",
400 default='imp_t_Location')
402 import_where1: EnumProperty(items=(('imp_w_-z', "-z", "Apply to -z"),
403 ('imp_w_-y', "-y", "Apply to -y"),
404 ('imp_w_-x', "-x", "Apply to -x"),
405 ('imp_w_z', "z", "Apply to z"),
406 ('imp_w_y', "y", "Apply to y"),
407 ('imp_w_x', "x", "Apply to x")
409 name="",
410 description= "Where to Import",
411 default='imp_w_z')
413 import_where2: EnumProperty(items=(('imp_w_none', "None", ""),
414 ('imp_w_-z', "-z", "Apply to -z"),
415 ('imp_w_-y', "-y", "Apply to -y"),
416 ('imp_w_-x', "-x", "Apply to -x"),
417 ('imp_w_z', "z", "Apply to z"),
418 ('imp_w_y', "y", "Apply to y"),
419 ('imp_w_x', "x", "Apply to x")
421 name="",
422 description= "Where to Import",
423 default='imp_w_none')
425 import_where3: EnumProperty(items=(('imp_w_none', "None", ""),
426 ('imp_w_-z', "-z", "Apply to -z"),
427 ('imp_w_-y', "-y", "Apply to -y"),
428 ('imp_w_-x', "-x", "Apply to -x"),
429 ('imp_w_z', "z", "Apply to z"),
430 ('imp_w_y', "y", "Apply to y"),
431 ('imp_w_x', "x", "Apply to x")
433 name="",
434 description= "Where to Import",
435 default='imp_w_none')
438 #========== Propriedades boolean =============#
440 # INVERTIDO!!! bNaoValorIgual=True # nao deixa repetir valores INVERTIDO!!!
441 action_valor_igual: BoolProperty(name="Hard Transition",
442 description="Default. Movements like a beat",
443 default=1)
445 action_auto_audio_sense: BoolProperty(name="Auto Audio Sensitivity",
446 description="Try to discover best audio scale. ",
447 default=1)
449 use_just_beat:BoolProperty(name="Only Use The Beat",
450 description="Try to use only the beat to extract movement",
451 default=0)
453 remove_beat:BoolProperty(name="Remove The Beat",
454 description="Try to remove the beat to extract movement",
455 default=0)
457 beat_more_sensible:BoolProperty(name="More Sensible",
458 description="Try To be more sensible about the beat",
459 default=0)
461 beat_less_sensible:BoolProperty(name="Less Sensible",
462 description="Try to be less sensible about the beat",
463 default=0)
465 check_smartrender_loc_rot_sc:BoolProperty(name="Loc Rot Scale",
466 description="Find changes in Location, Rotation and Scale Frame by Frame",
467 default=1)
469 check_smartrender_material_basic:BoolProperty(name="Basic Material",
470 description="Find changes in basic material settings Frame by Frame",
471 default=1)
473 check_smartrender_material_transparence:BoolProperty(name="Material Transparence",
474 description="Find changes in material transparence settings Frame by Frame",
475 default=0)
477 check_smartrender_material_mirror:BoolProperty(name="Material Mirror",
478 description="Find changes in material mirror settings Frame by Frame",
479 default=0)
481 timer_reset_func:BoolProperty(name="Reset Counters",
482 description="Reset Counters after stop",
483 default=0)
485 cancel_button_hit:BoolProperty(name="Cancel Hit",
486 description="Cancel Hit",
487 default=0)
489 # Optimization
490 optimization_destructive: IntProperty(name="Optimization",
491 description="Hi value = Hi optimization -> Hi loss of information",
492 min=0,
493 max=254,
494 step=10,
495 default= 10)
497 # import as driver or direct NOT IN USE!!
498 # not defined
499 # Direct=1
500 # Driver=2
501 bTypeImport: IntProperty(name="bTypeImport",
502 description="Import Direct or Driver",
503 default=1)
505 # globais do dialog open wave
506 filter_glob: StringProperty(default="*.wav", options={'HIDDEN'})
507 path: StringProperty(name="File Path", description="Filepath used for importing the WAV file", \
508 maxlen= 1024, default= "")
509 filename: StringProperty(name="File Name", description="Name of the file")
510 directory: StringProperty(name="Directory", description="Directory of the file")
512 from bpy.props import *
514 def WavFileImport(self, context):
515 self.layout.operator(ImportWavFile.bl_idname, text="Import a wav file", icon='PLUGIN')
519 #==================================================================================================
520 # Use Direct
521 #==================================================================================================
523 class OBJECT_OT_Botao_uDirect(bpy.types.Operator):
524 '''Import as Direct Animation'''
525 bl_idname = "import.sound_animation_botao_udirect"
526 bl_label = "Direct to a Property"
528 def execute(self, context):
529 context.object.imp_sound_to_anim.bTypeImport= 1
530 if context.object.imp_sound_to_anim.frames_per_second == 0:
531 context.object.imp_sound_to_anim.frames_per_second= bpy.context.scene.render.fps
532 return{'FINISHED'}
534 def invoke(self, context, event):
535 self.execute(context)
536 return {'FINISHED'}
539 #==================================================================================================
540 # Button - Import
541 #==================================================================================================
543 class OBJECT_OT_Botao_Import(bpy.types.Operator):
544 '''Import Key Frames to Blender'''
545 bl_idname = "import.sound_animation_botao_import"
546 bl_label = "Import Key Frames"
548 RunFrom=0
549 iSumImportFrames=0
550 iSumOptimizerP1=0
551 iSumOptimizerP2=0
552 iSumOptimizerP3=0
554 def wavimport(context, loop):
555 obi=OBJECT_OT_Botao_Import
557 # para de entrar no timer
558 context.object.imp_sound_to_anim.Working=""
559 #reseta contadores caso seja pedido
560 if context.object.imp_sound_to_anim.timer_reset_func:
561 obi.RunFrom=0
562 obi.iSumOptimizerP1=0
563 obi.iSumOptimizerP2=0
564 obi.iSumOptimizerP3=0
565 obi.iSumImportFrames=0
566 context.object.imp_sound_to_anim.timer_reset_func=False
568 #limita o loop se estiver no fim
569 tot=len(array)-1
570 if obi.RunFrom+loop > tot:
571 loop= tot - obi.RunFrom
573 #scala do valor do movimento. [se =1 - 0 a 255 ] [se=255 - 0,00000 a 1,00000] [se=1000 - 0 a 0.255]
574 iDivScala= int(context.object.imp_sound_to_anim.action_escale)
576 # nao deixa repetir valores
577 bNaoValorIgual=True
578 if context.object.imp_sound_to_anim.action_valor_igual: bNaoValorIgual= False
580 # inicia no inicio pedido pelo usuario mais ponteiro RunFrom
581 iStartFrame= int(context.object.imp_sound_to_anim.frames_initial) + obi.RunFrom
583 iMaxValue= context.object.imp_sound_to_anim.action_max_value
584 iMinValue= context.object.imp_sound_to_anim.action_min_value
586 bEscala=bRotacao=bEixo=False
587 if context.object.imp_sound_to_anim.import_type=='imp_t_Scale':
588 bEscala=True;
590 if context.object.imp_sound_to_anim.import_type=='imp_t_Rotation':
591 bRotacao=True;
593 if context.object.imp_sound_to_anim.import_type=='imp_t_Location':
594 bEixo=True;
596 # atencao, nao eh boolean
597 iEixoXneg= iEixoYneg= iEixoZneg=1
598 # atencao, nao eh boolean
599 iRotationNeg=1
600 # atencao, nao eh boolean
601 iEscalaYneg= iEscalaZneg= iEscalaXneg=1
602 bEixoX=bEixoY=bEixoZ=bEscalaX=bEscalaY=bEscalaZ=bRotationX=bRotationY=bRotationZ=False
604 # LOCAL 1
605 if context.object.imp_sound_to_anim.import_where1== 'imp_w_x':
606 bEixoX=True
607 bEscalaX=True
608 bRotationX=True
610 if context.object.imp_sound_to_anim.import_where1== 'imp_w_y':
611 bEixoY=True
612 bEscalaY=True
613 bRotationY=True
615 if context.object.imp_sound_to_anim.import_where1== 'imp_w_z':
616 bEixoZ=True
617 bEscalaZ=True
618 bRotationZ=True
620 if context.object.imp_sound_to_anim.import_where1== 'imp_w_-x':
621 bEixoX=True
622 bEscalaX=True
623 bRotationX=True
624 iEixoXneg=-1
625 iEscalaXneg=-1
626 iRotationNeg=-1
628 if context.object.imp_sound_to_anim.import_where1== 'imp_w_-y':
629 bEixoY=True
630 bEscalaY=True
631 bRotationY=True
632 iEixoYneg=-1
633 iRotationNeg=-1
634 iEscalaYneg=-1
636 if context.object.imp_sound_to_anim.import_where1== 'imp_w_-z':
637 bEixoZ=True
638 bEscalaZ=True
639 bRotationZ=True
640 iEixoZneg=-1
641 iRotationNeg=-1
642 iEscalaZneg=-1
645 # LOCAL 2
646 if context.object.imp_sound_to_anim.import_where2== 'imp_w_x':
647 bEixoX=True
648 bEscalaX=True
649 bRotationX=True
651 if context.object.imp_sound_to_anim.import_where2== 'imp_w_y':
652 bEixoY=True
653 bEscalaY=True
654 bRotationY=True
656 if context.object.imp_sound_to_anim.import_where2== 'imp_w_z':
657 bEixoZ=True
658 bEscalaZ=True
659 bRotationZ=True
661 if context.object.imp_sound_to_anim.import_where2== 'imp_w_-x':
662 bEixoX=True
663 bEscalaX=True
664 bRotationX=True
665 iEixoXneg=-1
666 iEscalaXneg=-1
667 iRotationNeg=-1
669 if context.object.imp_sound_to_anim.import_where2== 'imp_w_-y':
670 bEixoY=True
671 bEscalaY=True
672 bRotationY=True
673 iEixoYneg=-1
674 iRotationNeg=-1
675 iEscalaYneg=-1
677 if context.object.imp_sound_to_anim.import_where2== 'imp_w_-z':
678 bEixoZ=True
679 bEscalaZ=True
680 bRotationZ=True
681 iEixoZneg=-1
682 iRotationNeg=-1
683 iEscalaZneg=-1
686 # LOCAL 3
687 if context.object.imp_sound_to_anim.import_where3== 'imp_w_x':
688 bEixoX=True
689 bEscalaX=True
690 bRotationX=True
692 if context.object.imp_sound_to_anim.import_where3== 'imp_w_y':
693 bEixoY=True
694 bEscalaY=True
695 bRotationY=True
697 if context.object.imp_sound_to_anim.import_where3== 'imp_w_z':
698 bEixoZ=True
699 bEscalaZ=True
700 bRotationZ=True
702 if context.object.imp_sound_to_anim.import_where3== 'imp_w_-x':
703 bEixoX=True
704 bEscalaX=True
705 bRotationX=True
706 iEixoXneg=-1
707 iEscalaXneg=-1
708 iRotationNeg=-1
710 if context.object.imp_sound_to_anim.import_where3== 'imp_w_-y':
711 bEixoY=True
712 bEscalaY=True
713 bRotationY=True
714 iEixoYneg=-1
715 iRotationNeg=-1
716 iEscalaYneg=-1
718 if context.object.imp_sound_to_anim.import_where3== 'imp_w_-z':
719 bEixoZ=True
720 bEscalaZ=True
721 bRotationZ=True
722 iEixoZneg=-1
723 iRotationNeg=-1
724 iEscalaZneg=-1
726 iMinBaseX=iMinScaleBaseX=context.object.imp_sound_to_anim.action_offset_x
727 iMinBaseY=iMinScaleBaseY=context.object.imp_sound_to_anim.action_offset_y
728 iMinBaseZ=iMinScaleBaseZ=context.object.imp_sound_to_anim.action_offset_z
730 #escala inicia com 1 e nao com zero
731 iRotationAxisBaseX=context.object.imp_sound_to_anim.action_offset_x +1
732 iRotationAxisBaseY=context.object.imp_sound_to_anim.action_offset_y +1
733 iRotationAxisBaseZ=context.object.imp_sound_to_anim.action_offset_z +1
735 #Added destructive optimizer option - LostLestSignificativeDigit lost/total
736 iDestructiveOptimizer=context.object.imp_sound_to_anim.optimization_destructive
738 #limita ou nao o valor - velocidade
739 bLimitValue=False
741 if iMinValue<0: iMinValue=0
742 if iMaxValue>255: iMaxValue=255
743 if iMinValue>255: iMinValue=255
744 if iMaxValue<0: iMaxValue=0
745 if iMinValue!= 0: bLimitValue= True
746 if iMaxValue!= 255: bLimitValue= True
748 if obi.RunFrom==0:
749 print('')
750 print("================================================================")
751 from time import strftime
752 print(strftime("Start Import: %H:%M:%S"))
753 print("================================================================")
754 print('')
756 ilocationXAnt=0
757 ilocationYAnt=0
758 ilocationZAnt=0
759 iscaleXAnt=0
760 iscaleYAnt=0
761 iscaleZAnt=0
762 iRotateValAnt=0
764 # variavel global _Interna_Globals
765 if context.object.imp_sound_to_anim.bArrayCriado:
766 for i in range(loop):
767 ival=array[i+obi.RunFrom]/iDivScala
768 #valor pequeno demais, vai dar zero na hora de aplicar
769 if ival < 0.001:
770 array[i+obi.RunFrom]=0
771 ival=0
773 # to increase performance and legibility
774 arrayI= array[i+obi.RunFrom]
775 arrayIP1= array[i+1+obi.RunFrom]
776 arrayIL1= array[i-1+obi.RunFrom]
778 # opcao de NAO colocar valores iguais sequenciais
779 if i>0 and bNaoValorIgual and arrayIL1== arrayI:
780 print("Importing Blender Frame: "+str(i+obi.RunFrom+1)+"\tof "+str(len(array)-1) + \
781 "\t(skipped by optimizer)")
782 obi.iSumOptimizerP3+=1
783 else:
784 # otimizacao - nao preciso mais que 2 valores iguais.
785 # pular key frame intermediario - Ex b, a, -, -, -, a
786 # tambem otimiza pelo otimizador com perda
787 # valor atual == anterior e posterior -> pula
788 if i>0 and i< len(array)-1 and abs(arrayI - arrayIL1)<=iDestructiveOptimizer and \
789 abs(arrayI - arrayIP1)<=iDestructiveOptimizer:
790 print("Importing Blender Frame: "+str(i+obi.RunFrom+1)+"\tof "+str(len(array)-1) + \
791 "\t(skipped by optimizer)")
792 if iDestructiveOptimizer>0 and arrayI != arrayIL1 or arrayI != arrayIP1:
793 obi.iSumOptimizerP1+=1
794 else: obi.iSumOptimizerP2+=1
795 else:
796 if bLimitValue:
797 if arrayI > iMaxValue: array[i+obi.RunFrom]=iMaxValue
798 if arrayI < iMinValue: array[i+obi.RunFrom]=iMinValue
800 ival=array[i+obi.RunFrom]/iDivScala
801 #passa para float com somente 3 digitos caso seja float
802 m_ival=ival*1000
803 if int(m_ival) != m_ival:
804 ival= int(m_ival)
805 ival = ival /1000
807 bpy.context.scene.frame_current = i+iStartFrame
809 #precisa fazer objeto ativo
810 if bpy.context.active_object.type=='MESH' or bpy.context.active_object.type=='CAMERA' or \
811 bpy.context.active_object.type=='EMPTY':
812 if bEixo:
813 if bEixoX: bpy.context.active_object.location.x = ival*iEixoXneg+iMinBaseX
814 if bEixoY: bpy.context.active_object.location.y = ival*iEixoYneg+iMinBaseY
815 if bEixoZ: bpy.context.active_object.location.z = ival*iEixoZneg+iMinBaseZ
817 if bEscala:
818 if bEscalaX: bpy.context.active_object.scale.x = ival*iEscalaXneg+iMinScaleBaseX
819 if bEscalaY: bpy.context.active_object.scale.y = ival*iEscalaYneg+iMinScaleBaseY
820 if bEscalaZ: bpy.context.active_object.scale.z = ival*iEscalaZneg+iMinScaleBaseZ
822 # 'ARMATURE' or ('MESH' and bRotacao) or ('CAMERA' and bRotacao) or 'LAMP' or 'EMPTY' and bRotacao)
823 if bpy.context.active_object.type=='ARMATURE' or (bpy.context.active_object.type=='MESH' and bRotacao) or \
824 (bpy.context.active_object.type=='CAMERA' and bRotacao) or \
825 bpy.context.active_object.type=='LAMP' or \
826 (bpy.context.active_object.type=='EMPTY' and bRotacao):
828 #=========== BONE ===========#
829 if bpy.context.active_object.type=='ARMATURE': #precisa ser objeto ativo. Nao achei como passar para editmode
830 if bpy.context.mode!= 'POSE': #posemode
831 bpy.ops.object.posemode_toggle()
833 #============= ALL ===========#
834 if bEixo:
835 if ilocationXAnt!=0 or ilocationYAnt!=0 or ilocationZAnt!=0:
837 bpy.ops.transform.translate(value=(ilocationXAnt*-1, ilocationYAnt*-1, \
838 ilocationZAnt*-1), constraint_axis=(bEixoX, bEixoY,bEixoZ), \
839 orient_type='GLOBAL', mirror=False, \
840 proportional='DISABLED', proportional_edit_falloff='SMOOTH', \
841 proportional_size=1, snap=False, \
842 snap_target='CLOSEST', snap_point=(0, 0, 0), \
843 snap_align=False, snap_normal=(0, 0, 0), \
844 release_confirm=False)
846 ilocationX=ilocationY=ilocationZ=0
847 if bEixoX: ilocationX = ival*iEixoXneg+iMinBaseX
848 if bEixoY: ilocationY = ival*iEixoYneg+iMinBaseY
849 if bEixoZ: ilocationZ = ival*iEixoZneg+iMinBaseZ
851 bpy.ops.transform.translate(value=(ilocationX, ilocationY, \
852 ilocationZ), constraint_axis=(bEixoX, bEixoY,bEixoZ), \
853 orient_type='GLOBAL', mirror=False, \
854 proportional='DISABLED', proportional_edit_falloff='SMOOTH', \
855 proportional_size=1, snap=False, \
856 snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, \
857 snap_normal=(0, 0, 0), release_confirm=False)
858 ilocationXAnt= ilocationX
859 ilocationYAnt= ilocationY
860 ilocationZAnt= ilocationZ
862 if bEscala:
863 if iscaleXAnt!=0 or iscaleYAnt!=0 or iscaleZAnt!=0:
864 tmpscaleXAnt=0
865 tmpscaleYAnt=0
866 tmpscaleZAnt=0
867 if iscaleXAnt: tmpscaleXAnt=1/iscaleXAnt
868 if iscaleYAnt: tmpscaleYAnt=1/iscaleYAnt
869 if iscaleZAnt: tmpscaleZAnt=1/iscaleZAnt
871 bpy.ops.transform.resize(value=(tmpscaleXAnt, tmpscaleYAnt, \
872 tmpscaleZAnt ), constraint_axis=(False, False, False), \
873 orient_type='GLOBAL', mirror=False, \
874 proportional='DISABLED', proportional_edit_falloff='SMOOTH', \
875 proportional_size=1, snap=False, snap_target='CLOSEST', \
876 snap_point=(0, 0, 0), snap_align=False, \
877 snap_normal=(0, 0, 0), release_confirm=False)
879 iscaleX=iscaleY=iscaleZ=0
880 if bEscalaX: iscaleX = ival*iEscalaXneg+iMinScaleBaseX
881 if bEscalaY: iscaleY = ival*iEscalaYneg+iMinScaleBaseY
882 if bEscalaZ: iscaleZ = ival*iEscalaZneg+iMinScaleBaseZ
884 bpy.ops.transform.resize(value=(iscaleX, iscaleY, \
885 iscaleZ), constraint_axis=(False, False, False), \
886 orient_type='GLOBAL', mirror=False, \
887 proportional='DISABLED', proportional_edit_falloff='SMOOTH', \
888 proportional_size=1, snap=False, \
889 snap_target='CLOSEST', snap_point=(0, 0, 0), \
890 snap_align=False, snap_normal=(0, 0, 0), \
891 release_confirm=False)
892 iscaleXAnt= iscaleX
893 iscaleYAnt= iscaleY
894 iscaleZAnt= iscaleZ
896 if bRotacao:
897 if iRotateValAnt!=0:
898 bpy.context.active_object.rotation_euler= ((iRotateValAnt*-1)+ iRotationAxisBaseX) *bRotationX , \
899 ((iRotateValAnt*-1)+ iRotationAxisBaseY) *bRotationY , \
900 ((iRotateValAnt*-1)+ iRotationAxisBaseZ) *bRotationZ
902 bpy.context.active_object.rotation_euler= ((ival*iRotationNeg)+ iRotationAxisBaseX) * bRotationX, \
903 ((ival*iRotationNeg)+ iRotationAxisBaseY) * bRotationY, \
904 ((ival*iRotationNeg)+ iRotationAxisBaseZ) * bRotationZ
905 iRotateValAnt= ival*iRotationNeg
907 ob = bpy.context.active_object
909 if bEixo:
910 ob.keyframe_insert(data_path="location")
912 if bRotacao:
913 ob.keyframe_insert(data_path="rotation_euler")
915 if bEscala:
916 ob.keyframe_insert(data_path="scale")
918 print("Importing Blender Frame: "+str(i+obi.RunFrom+1)+"\tof "+str(len(array)-1) + "\tValue: "+ str(ival))
920 obi.iSumImportFrames+=1
921 # Fim do ELSE otimizador
922 # Fim bNaoValorIgual
924 if obi.RunFrom>= tot:
925 bpy.context.scene.frame_current = 1
926 context.object.imp_sound_to_anim.Info_Import="Done. Imported " + str(obi.iSumImportFrames) + " Frames"
927 from time import strftime
928 print('')
929 print("================================================================")
930 print("Imported: " +str(obi.iSumImportFrames) + " Key Frames")
931 print("Optimizer Pass 1 prepared to optimize: " +str(obi.iSumOptimizerP1) + " blocks of Frames")
932 print("Optimizer Pass 2 has optimized: " +str(obi.iSumOptimizerP2) + " Frames")
933 print("Optimizer Pass 3 has optimized: " +str(obi.iSumOptimizerP3) + " Frames")
934 print("Optimizer has optimized: " +str(obi.iSumOptimizerP1 + obi.iSumOptimizerP2 + obi.iSumOptimizerP3) + " Frames")
935 print(strftime("End Import: %H:%M:%S - by Vlassius"))
936 print("================================================================")
937 print('')
938 obi.RunFrom=0
939 obi.iSumImportFrames=0
940 obi.iSumOptimizerP1=0
941 obi.iSumOptimizerP2=0
942 obi.iSumOptimizerP3=0
943 return obi.RunFrom
944 else:
945 obi.RunFrom+= loop
946 context.object.imp_sound_to_anim.Info_Import="Processing Frame " + str(obi.RunFrom+loop) + \
947 " of " + str(tot-1) + " Frames"
948 return obi.RunFrom
951 def execute(self, context):
952 #wavimport(context)
953 #return{'FINISHED'}
954 context.object.imp_sound_to_anim.Working= "wavimport"
955 bpy.ops.wm.modal_timer_operator()
957 def invoke(self, context, event):
958 self.execute(context)
959 return {'FINISHED'}
964 #==================================================================================================
965 # Button - Sound Process
966 #==================================================================================================
968 class OBJECT_OT_Botao_Go(bpy.types.Operator):
969 ''''''
970 bl_idname = "import.sound_animation_botao_go"
971 # change in API
972 bl_description = "Process a .wav file, take movement from the sound and import to the scene as Key"
973 bl_label = "Process Wav"
975 filter_glob: StringProperty(default="*.wav", options={'HIDDEN'})
976 path: StringProperty(name="File Path", description="Filepath used for importing the WAV file", \
977 maxlen= 1024, default= "")
978 filename: StringProperty(name="File Name", description="Name of the file")
979 directory: StringProperty(name="Directory", description="Directory of the file")
981 RunFrom=0
982 Wave_read=0
983 MaxAudio=0
985 def SoundConv(File, DivSens, Sensibil, Resol, context, bAutoSense, bRemoveBeat, bUseBeat, bMoreSensible, \
986 bLessSensible, AudioChannel, loop):
987 obg= OBJECT_OT_Botao_Go
988 #reseta contadores caso seja pedido
989 if context.object.imp_sound_to_anim.timer_reset_func:
990 obc.RunFrom=0
991 Wave_read=0
992 MaxAudio=0
993 context.object.imp_sound_to_anim.timer_reset_func=False
995 #abre arquivo se primeira rodada
996 if obg.RunFrom==0:
997 try:
998 obg.Wave_read= wave.open(File, 'rb')
999 except IOError as e:
1000 print("File Open Error: ", e)
1001 return False
1003 NumCh= obg.Wave_read.getnchannels()
1004 SampW= obg.Wave_read.getsampwidth() # 8, 16, 24 32 bits
1005 FrameR= obg.Wave_read.getframerate()
1006 NumFr= obg.Wave_read.getnframes()
1007 ChkCompr= obg.Wave_read.getcomptype()
1009 if ChkCompr != "NONE":
1010 print('Sorry, this compressed Format is NOT Supported ', ChkCompr)
1011 context.object.imp_sound_to_anim.Info_Import= "Sorry, this compressed Format is NOT Supported "
1012 return False
1014 if SampW > 2:
1015 context.object.imp_sound_to_anim.Info_Import= "Sorry, supported .wav files 8 and 16 bits only"
1016 print('Sorry, supported .wav files 8 and 16 bits only')
1017 return False
1019 context.object.imp_sound_to_anim.Info_Import=""
1021 # controla numero do canal
1022 if AudioChannel > NumCh:
1023 if obg.RunFrom==0:
1024 print("Channel number " + str(AudioChannel) + " is selected but this audio file has just " + \
1025 str(NumCh) + " channels, so selecting channel " \
1026 + str(NumCh) + "!")
1027 AudioChannel = NumCh
1029 # apenas para por na tela
1030 tmpAudioChannel= AudioChannel
1032 #used in index sum to find the channe, adjust to first byte sample index
1033 AudioChannel -= 1
1035 # se dois canais, AudioChannel=4 porque sao 4 bytes
1036 if SampW ==2: AudioChannel*=2
1038 # usado para achar contorno da onda - achando picos
1039 # numero de audio frames para cada video frame
1040 BytesResol= int(FrameR/Resol)
1042 # com 8 bits/S - razao Sample/s por resolucao
1043 # tamanho do array
1044 BytesDadosTotProcess= NumFr // BytesResol
1046 if obg.RunFrom==0: # primeira rodada
1047 # inicia array
1048 _Interna_Globals(BytesDadosTotProcess, context)
1049 print('')
1050 print("================================================================")
1051 from time import strftime
1052 print(strftime("Go! %H:%M:%S"))
1053 print("================================================================")
1054 print('')
1055 print('Total Audio Time: \t ' + str(NumFr//FrameR) + 's (' + str(NumFr//FrameR//60) + 'min)')
1056 print('Total # Interactions: \t', BytesDadosTotProcess)
1057 print('Total Audio Frames: \t', NumFr)
1058 print('Frames/s: \t\t ' + str(FrameR))
1059 print('# Chanels in File: \t', NumCh)
1060 print('Channel to use:\t\t', tmpAudioChannel)
1061 print('Bit/Sample/Chanel: \t ' + str(SampW*8))
1062 print('# Frames/Act: \t\t', DivSens)
1064 if bAutoSense==0:
1065 print('Audio Sensitivity: \t', Sensibil+1)
1066 else:
1067 print('Using Auto Audio Sentivity. This is pass 1 of 2.')
1069 print('')
1070 print ("Sample->[value]\tAudio Frame # \t\t[Graph Value]")
1072 if obg.RunFrom==0 and bAutoSense!=0:
1073 Sensibil=0 # if auto sense, Sensibil must be zero here
1074 obg.MaxAudio=0 # valor maximo de audio encontrado
1076 # verifica limite total do audio
1077 looptot= int(BytesDadosTotProcess // DivSens)
1078 if obg.RunFrom+loop > looptot:
1079 loop= looptot-obg.RunFrom
1081 j=0 # usado de indice
1082 # laco total leitura bytes
1083 # armazena dado de pico
1084 for jj in range(loop):
1085 # caso de 2 canais (esterio)
1086 # uso apenas 2 bytes em 16 bits, ie, apenas canal esquerdo
1087 # [0] e [1] para CH L
1088 # [2] e [3] para CH R and so on
1089 # mono:1 byte to 8 bits, 2 bytes to 16 bits
1090 # sterio: 2 byte to 8 bits, 4 bytes to 16 bits
1091 ValorPico=0
1092 # leio o numero de frames de audio para cada frame de video, valor em torno de 1000
1093 for i in range(BytesResol):
1094 #loop exterior copia DivSens frames a cada frame calculado
1095 frame = obg.Wave_read.readframes(DivSens)
1097 if len(frame)==0: break
1099 if bAutoSense==0: # AutoAudioSense Desligado
1100 if SampW ==1:
1101 if Sensibil ==5:
1102 frame0= frame[AudioChannel] << 6 & 255
1104 elif Sensibil ==4:
1105 frame0= frame[AudioChannel] << 5 & 255
1107 elif Sensibil ==3:
1108 frame0= frame[AudioChannel] << 4 & 255
1110 elif Sensibil ==2:
1111 frame0= frame[AudioChannel] << 3 & 255
1113 elif Sensibil ==1:
1114 frame0= frame[AudioChannel] << 2 & 255
1116 elif Sensibil ==0:
1117 frame0= frame[AudioChannel]
1119 if frame0> ValorPico:
1120 ValorPico= frame0
1122 if SampW ==2: # frame[0] baixa frame[1] ALTA BIT 1 TEM SINAL!
1123 if frame[1+AudioChannel] <127: # se bit1 =0, usa o valor - se bit1=1 quer dizer numero negativo
1124 if Sensibil ==0:
1125 frame0= frame[1+AudioChannel]
1127 elif Sensibil ==4:
1128 frame0= ((frame[AudioChannel] & 0b11111100) >> 2) | ((frame[1+AudioChannel] & 0b00000011) << 6)
1130 elif Sensibil ==3:
1131 frame0= ((frame[AudioChannel] & 0b11110000) >> 4) | ((frame[1+AudioChannel] & 0b00001111) << 4)
1133 elif Sensibil ==2:
1134 frame0= ((frame[AudioChannel] & 0b11100000) >> 5) | ((frame[1+AudioChannel] & 0b00011111) << 3)
1136 elif Sensibil ==1:
1137 frame0= ((frame[AudioChannel] & 0b11000000) >> 6) | ((frame[1+AudioChannel] & 0b00111111) << 2)
1139 elif Sensibil ==5:
1140 frame0=frame[AudioChannel]
1142 if frame0 > ValorPico:
1143 ValorPico= frame0
1145 else: # AutoAudioSense Ligado
1146 if SampW ==1:
1147 if frame[AudioChannel]> obg.MaxAudio:
1148 obg.MaxAudio = frame[AudioChannel]
1150 if frame[AudioChannel]> ValorPico:
1151 ValorPico=frame[AudioChannel]
1153 if SampW ==2:
1154 if frame[1+AudioChannel] < 127:
1155 tmpValorPico= frame[1+AudioChannel] << 8
1156 tmpValorPico+= frame[AudioChannel]
1158 if tmpValorPico > obg.MaxAudio:
1159 obg.MaxAudio = tmpValorPico
1161 if tmpValorPico > ValorPico:
1162 ValorPico= tmpValorPico
1164 if bAutoSense==0: #autoaudiosense desligado
1165 # repito o valor de frames por actions (OTIMIZAR)
1166 for ii in range(DivSens):
1167 array[j+obg.RunFrom]=ValorPico # valor de pico encontrado
1168 j +=1 # incrementa indice prox local
1169 else:
1170 idx=obg.RunFrom*2 # porque sao dois bytes
1171 arrayAutoSense[j+idx]= (ValorPico & 0b0000000011111111) #copia valores baixos
1172 arrayAutoSense[j+1+idx]= (ValorPico & 0b1111111100000000) >> 8 #copia valores altos
1173 j+=2
1175 if bAutoSense==0: #autoaudiosense desligado
1176 igraph= ValorPico//10
1177 else:
1178 if SampW ==2:
1179 igraph= ValorPico//1261
1181 else:
1182 igraph= ValorPico//10
1184 stgraph="["
1185 for iii in range(igraph):
1186 stgraph+="+"
1188 for iiii in range(26-igraph):
1189 stgraph+=" "
1190 stgraph+="]"
1192 print ("Sample-> " + str(ValorPico) + "\tAudio Frame # " + str(jj+obg.RunFrom) + " of " + str(looptot-1) + "\t"+ stgraph)
1194 # acabou primeira fase roda toda de uma vez
1195 if obg.RunFrom+loop == looptot:
1196 if bAutoSense==1:
1197 print("")
1198 print("================================================================")
1199 print('Calculating Auto Audio Sentivity, pass 2 of 2.')
1200 print("================================================================")
1202 # caso usar batida, procurar por valores proximos do maximo e zerar restante.
1203 # caso retirar batida, zerar valores proximos do maximo
1204 UseMinim=0
1205 UseMax=0
1207 if bUseBeat==1:
1208 print("Trying to use only the beat.")
1209 UseMinim= obg.MaxAudio*0.8
1210 if bMoreSensible:
1211 UseMinim= obg.MaxAudio*0.7
1212 elif bLessSensible:
1213 UseMinim= obg.MaxAudio*0.9
1215 if bRemoveBeat==1:
1216 print("Trying to exclude the beat.")
1217 UseMax= obg.MaxAudio*0.7
1218 if bMoreSensible:
1219 UseMax= obg.MaxAudio*0.8
1220 elif bLessSensible:
1221 UseMax= obg.MaxAudio*0.7
1223 print("")
1224 # para transformar 15 bits em 8 calibrando valor maximo -> fazer regra de 3
1225 # obg.MaxAudio -> 255
1226 # outros valores => valor calibrado= (255 * Valor) / obg.MaxAudio
1227 scale= 255/obg.MaxAudio
1230 jj=0
1231 print ("Sample->[value]\tAudio Frame # \t\t[Graph Value]")
1233 for i in range(BytesDadosTotProcess // DivSens):
1235 ValorOriginal= arrayAutoSense[j+1] << 8
1236 ValorOriginal+= arrayAutoSense[j]
1238 if bUseBeat==1:
1239 if ValorOriginal < UseMinim:
1240 ValorOriginal = 0
1242 elif bRemoveBeat==1:
1243 if ValorOriginal > UseMax:
1244 ValorOriginal = 0
1246 ValorOriginal= ((round(ValorOriginal * scale)) & 0b11111111) #aplica a escala
1248 for ii in range(DivSens):
1249 array[jj] = ValorOriginal
1250 jj += 1 # se autoaudiosense, o array tem dois bytes para cada valor
1252 j+=2
1253 igraph= round(array[jj-1]/10)
1254 stgraph="["
1255 for iii in range(igraph):
1256 stgraph+="+"
1258 for iiii in range(26-igraph):
1259 stgraph+=" "
1260 stgraph+="]"
1261 print ("Sample-> " + str(array[jj-1]) + "\tAudio Frame # " + str(i) + " of " + str(looptot-1) + "\t"+ stgraph)
1263 #limpa array tmp
1264 del arrayAutoSense[:]
1266 # mensagens finais
1267 context.object.imp_sound_to_anim.Info_Import= "Click \"Import Key frames\" to begin import" #this set the initial text
1269 print("================================================================")
1270 from time import strftime
1271 print(strftime("End Process: %H:%M:%S"))
1272 print("================================================================")
1274 try:
1275 obg.Wave_read.close()
1276 except:
1277 print('File Close Error')
1279 obg.RunFrom=0
1280 return obg.RunFrom # acabou tudo
1282 else:#ainda nao acabou o arquivo todo if RunFrom+loop = looptot:
1283 context.object.imp_sound_to_anim.Info_Import="Processing " + str(obg.RunFrom) + " of " + str(looptot) +" Audio Frames"
1284 # force update info text in UI
1285 bpy.context.scene.frame_current= bpy.context.scene.frame_current
1286 obg.RunFrom+=loop
1287 return obg.RunFrom
1292 def ProcessaSom(context, loop):
1293 obg= OBJECT_OT_Botao_Go
1294 # para de entrar o timer
1295 context.object.imp_sound_to_anim.Working=""
1296 #reseta contadores caso seja pedido
1297 if context.object.imp_sound_to_anim.timer_reset_func:
1298 obg.RunFrom=0
1299 context.object.imp_sound_to_anim.timer_reset_func=False
1301 import os
1302 f= os.path.join(context.object.imp_sound_to_anim.directory, context.object.imp_sound_to_anim.filename)
1303 f= os.path.normpath(f)
1305 if obg.RunFrom==0:
1306 print ("")
1307 print ("")
1308 print ("Selected file = ",f)
1309 checktype = f.split('\\')[-1].split('.')[1]
1310 if checktype.upper() != 'WAV':
1311 print ("ERROR!! Selected file = ", f)
1312 print ("ERROR!! Its not a .wav file")
1313 return
1315 #sensibilidade volume do audio 0 a 5. Quanto maior, mais sensibilidade
1316 iAudioSensib= int(context.object.imp_sound_to_anim.audio_sense)-1
1317 if iAudioSensib <0: iAudioSensib=0
1318 elif iAudioSensib>5: iAudioSensib=5
1320 #act/s nao pode se maior que frames/s
1321 if context.object.imp_sound_to_anim.action_per_second > context.object.imp_sound_to_anim.frames_per_second:
1322 context.object.imp_sound_to_anim.action_per_second = context.object.imp_sound_to_anim.frames_per_second
1324 #Frames por segundo para key frame
1325 iFramesPorSeg= int(context.object.imp_sound_to_anim.frames_per_second)
1327 #Sensibilidade de movimento. 3= 3 movimentos por segundo
1328 iMovPorSeg= int(context.object.imp_sound_to_anim.action_per_second)
1330 #iDivMovPorSeg Padrao - taxa 4/s ou a cada 0,25s => iFramesPorSeg/iDivMovPorSeg= ~0.25
1331 iDivMovPorSeg=1
1332 for i in range(iFramesPorSeg):
1333 iDivMovPorSeg=iFramesPorSeg/(i+1)
1334 if iFramesPorSeg/iDivMovPorSeg >=iMovPorSeg:
1335 break
1337 bRemoveBeat= context.object.imp_sound_to_anim.remove_beat
1338 bUseBeat= context.object.imp_sound_to_anim.use_just_beat
1339 bLessSensible= context.object.imp_sound_to_anim.beat_less_sensible
1340 bMoreSensible= context.object.imp_sound_to_anim.beat_more_sensible
1341 AudioChannel= context.object.imp_sound_to_anim.audio_channel_select
1343 # chama funcao de converter som, retorna preenchendo _Interna_Globals.array
1344 index= OBJECT_OT_Botao_Go.SoundConv(f, int(iDivMovPorSeg), iAudioSensib, iFramesPorSeg, context, \
1345 context.object.imp_sound_to_anim.action_auto_audio_sense, bRemoveBeat, \
1346 bUseBeat, bMoreSensible, bLessSensible, AudioChannel, loop)
1347 return index
1350 def execute(self, context):
1352 # copia dados dialof open wave
1353 context.object.imp_sound_to_anim.filter_glob= self.filter_glob
1354 context.object.imp_sound_to_anim.path = self.path
1355 context.object.imp_sound_to_anim.filename = self.filename
1356 context.object.imp_sound_to_anim.directory = self.directory
1358 context.object.imp_sound_to_anim.Working= "ProcessaSom"
1359 bpy.ops.wm.modal_timer_operator()
1360 #ProcessaSom(context)
1361 return{'FINISHED'}
1363 def invoke(self, context, event):
1364 #need to set a path so so we can get the file name and path
1365 wm = context.window_manager
1366 wm.fileselect_add(self)
1368 return {'RUNNING_MODAL'}
1372 #==================================================================================================
1373 # Button - Cancel
1374 #==================================================================================================
1376 class OBJECT_OT_Botao_Cancel(bpy.types.Operator):
1377 '''Cancel Actual Operation'''
1378 bl_idname = "import.sound_animation_botao_cancel"
1379 bl_label = "CANCEL"
1381 def execute(self, context):
1382 context.object.imp_sound_to_anim.cancel_button_hit=True
1383 return{'FINISHED'}
1385 def invoke(self, context, event):
1386 self.execute(context)
1387 return {'FINISHED'}
1391 #==================================================================================================
1392 # TIMER - controla a execucao das funcoes
1393 # Responsavel por rodar em partes usando o timer e possibilitando
1394 # o cancelamento e textos informativos
1395 #==================================================================================================
1397 class ModalTimerOperator(bpy.types.Operator):
1398 """Internal Script Control"""
1399 bl_idname = "wm.modal_timer_operator"
1400 bl_label = "Internal Script Control"
1402 _timer = None
1403 Running= False
1405 def CheckRunStop(self, context, func, index):
1406 # forca update do UI
1407 bpy.context.scene.frame_set(bpy.context.scene.frame_current)
1408 if index!=0:
1409 #configura timer para a funcao
1410 context.object.imp_sound_to_anim.Working= func
1411 self.Running=True
1412 return {'PASS_THROUGH'}
1413 else: # posso desligar o timer e modal
1414 if self._timer!= None:
1415 context.window_manager.event_timer_remove(self._timer)
1416 self._timer= None
1417 return {'FINISHED'}
1420 def modal(self, context, event):
1421 if event.type == 'ESC'and self.Running:
1422 print("-- ESC Pressed --")
1423 self.cancel(context)
1424 context.object.imp_sound_to_anim.Working=""
1425 self.Running=False
1426 #reseta contadores
1427 context.object.imp_sound_to_anim.timer_reset_func=True
1428 # forca update do UI
1429 bpy.context.scene.frame_set(bpy.context.scene.frame_current)
1430 return {'CANCELLED'}
1432 if event.type == 'TIMER':
1433 #print("timer")
1434 #CheckSmartRender
1435 if context.object.imp_sound_to_anim.Working== "CheckSmartRender":
1436 self.parar(context)
1437 #5= frames para rodar antes de voltar [1]= indice de posicao atual
1438 index= OBJECT_OT_Botao_Check_SmartRender.CheckSmartRender(context, 5)[1]
1439 return self.CheckRunStop(context, "CheckSmartRender", index)
1441 #SmartRender
1442 elif context.object.imp_sound_to_anim.Working== "SmartRender":
1443 self.parar(context)
1444 #render/copia 1 e volta index>=0 indice posicao atual
1445 index= OBJECT_OT_Botao_SmartRender.SmartRender(context)
1446 return self.CheckRunStop(context, "SmartRender", index)
1448 #ProcessaSom
1449 elif context.object.imp_sound_to_anim.Working== "ProcessaSom":
1450 self.parar(context)
1451 # loop = numero de frames de audio index=0 se terminou ou >0 se não acabou
1452 index= OBJECT_OT_Botao_Go.ProcessaSom(context, 50)
1453 return self.CheckRunStop(context, "ProcessaSom", index)
1455 #wavimport(context)
1456 elif context.object.imp_sound_to_anim.Working== "wavimport":
1457 self.parar(context)
1458 # 5= numero de frames to import por timer
1459 index=OBJECT_OT_Botao_Import.wavimport(context, 50)
1460 return self.CheckRunStop(context, "wavimport", index)
1462 #passa por aqui quando as funcoes estao sendo executadas mas
1463 #configuradas para nao entrar porque context.object.imp_sound_to_anim.Working== ""
1464 return {'PASS_THROUGH'}
1466 # reseta e para tudo botao CANCEL pressionado
1467 if context.object.imp_sound_to_anim.cancel_button_hit==True:
1468 context.object.imp_sound_to_anim.Working=""
1469 #pede reset contadores
1470 context.object.imp_sound_to_anim.timer_reset_func=True
1471 if self._timer!= None:
1472 context.window_manager.event_timer_remove(self._timer)
1473 self._timer= None
1474 print("-- Cancel Pressed --")
1475 context.object.imp_sound_to_anim.cancel_button_hit=False
1476 return {'FINISHED'}
1478 #print("modal")
1480 # se o timer esta ativado, continua, (senao termina).
1481 # desligar a chamada ao modal se caso chegar aqui (nao deveria)
1482 if self._timer!= None:
1483 return{'PASS_THROUGH'}
1484 else:
1485 return {'FINISHED'}
1487 def execute(self, context):
1488 if self._timer==None:
1489 self._timer = context.window_manager.event_timer_add(0.2, window=context.window)
1490 context.window_manager.modal_handler_add(self)
1491 #para deixar rodar sem deligar o timer
1492 context.object.imp_sound_to_anim.timer_desligar=False
1493 self.Running=True
1494 return {'RUNNING_MODAL'}
1496 def cancel(self, context):
1497 if self._timer!= None:
1498 context.window_manager.event_timer_remove(self._timer)
1499 self._timer= None
1501 def parar(self, context):
1502 if self.Running:
1503 context.object.imp_sound_to_anim.Working=""
1504 self.Running=False
1509 #==================================================================================================
1510 # Register - Unregister - MAIN
1511 #==================================================================================================
1513 # ------------------------------------------------------------
1514 # Register:
1515 classes = (
1516 VIEW3D_PT_SoundPanel,
1517 ModalTimerOperator,
1518 OBJECT_OT_Botao_Cancel,
1519 OBJECT_OT_Botao_Go,
1520 OBJECT_OT_Botao_Import,
1521 OBJECT_OT_Botao_uDirect,
1522 ImpSoundtoAnim,
1525 def register():
1526 for cls in classes:
1527 bpy.utils.register_class(cls)
1528 #bpy.types.VIEW3D_MT_mesh_add.append(menu_func_landscape)
1529 bpy.types.TOPBAR_MT_file_import.append(WavFileImport)
1530 #bpy.types.VIEW3D_MT_mesh_add.append(WavFileImport)
1531 #bpy.types.Object.ant_landscape = PointerProperty(type=AntLandscapePropertiesGroup, name="ANT_Landscape", description="Landscape properties")
1532 bpy.types.Object.imp_sound_to_anim = PointerProperty(
1533 type=ImpSoundtoAnim,
1534 name="imp_sound_to_anim",
1535 description="Extract movement from sound file. See the tool shelf",
1539 def unregister():
1540 for cls in reversed(classes):
1541 bpy.utils.unregister_class(cls)
1542 #bpy.types.VIEW3D_MT_mesh_add.remove(WavFileImport)
1543 bpy.types.TOPBAR_MT_file_import.remove(WavFileImport)
1546 if __name__ == "__main__":
1547 register()
1552 def register():
1553 bpy.utils.register_module(__name__)
1554 bpy.types.Scene.imp_sound_to_anim = PointerProperty(type=ImpSoundtoAnim, name="Import: Sound to Animation", description="Extract movement from sound file. See the Object Panel at the end.")
1555 bpy.types.TOPBAR_MT_file_import.append(WavFileImport)
1557 def unregister():
1559 try:
1560 bpy.utils.unregister_module(__name__)
1561 except:
1562 pass
1564 try:
1565 bpy.types.TOPBAR_MT_file_import.remove(WavFileImport)
1566 except:
1567 pass
1571 if __name__ == "__main__":
1572 register()"""