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 *****
22 "name": "Import: Sound to Animation",
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.",
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"}
35 -- Extract movement from sound file, to help in animation - import script --<br>
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.
46 from bpy
.props
import *
47 #from io_utils import ImportHelper
51 def _Interna_Globals(BytesDadosTotProcess
, context
):
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 #==================================================================================================
62 #==================================================================================================
64 """class VIEW3D_PT_CustomMenuPanel(bpy.types.Panel):
65 bl_space_type = "PROPERTIES"
66 bl_region_type = "WINDOW"
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"
76 bl_label
= "Import Tool"
77 bl_category
= "Animate"
78 bl_options
= {'DEFAULT_CLOSED'}
80 def draw(self
, context
):
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'
89 row
.label(text
="The Selected Object is: type \"" + bpy
.context
.active_object
.type + \
90 "\", and it is not supported.")
92 row
.label(text
="Supported Object are Type: Armature, Mesh, Camera and Lamp")
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
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
106 if context
.object.imp_sound_to_anim
.Working
== "CheckSmartRender":
107 #context.object.imp_sound_to_anim.Info_check_smartrender=
109 row
.label(text
="Checking for Smart Render...")
111 row
.label(text
=context
.object.imp_sound_to_anim
.Info_check_smartrender
)
114 elif context
.object.imp_sound_to_anim
.Working
== "SmartRender":
115 #context.object.imp_sound_to_anim.Info_check_smartrender=
117 row
.label(text
="Processing Smart Render...")
119 row
.label(text
=context
.object.imp_sound_to_anim
.Info_check_smartrender
)
122 elif context
.object.imp_sound_to_anim
.Working
== "ProcessaSom":
123 #context.object.imp_sound_to_anim.Info_Import=
125 row
.label(text
="Processing Sound File...")
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=
132 row
.label(text
="Importing Keys...")
134 row
.label(text
=context
.object.imp_sound_to_anim
.Info_Import
)
138 layout
.operator(OBJECT_OT_Botao_Cancel
.bl_idname
)
141 elif context
.object.imp_sound_to_anim
.bTypeImport
== 1:
143 row
.label(text
="1)Click button \"Process Wav\",")
145 row
.label(text
="2)Click Button \"Import Key Frames\",")
147 row
.label(text
="Run the animation and Enjoy!")
149 row
.prop(context
.object.imp_sound_to_anim
,"action_auto_audio_sense")
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")
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
:
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")
172 row
.prop(context
.object.imp_sound_to_anim
,"action_per_second")
174 row
.prop(context
.object.imp_sound_to_anim
,"action_escale")
177 row
.label(text
="Result from 0 to " + str(round(255/context
.object.imp_sound_to_anim
.action_escale
,4)) + "")
180 row
.label(text
="Property to Change:")
181 row
.prop(context
.object.imp_sound_to_anim
,"import_type")
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")
190 row
.label(text
='Optional Configurations:')
193 row
.prop(context
.object.imp_sound_to_anim
,"frames_per_second")
196 column
= layout
.column()
197 split
=column
.split(factor
=0.5) #percentage=0.5
201 row
.prop(context
.object.imp_sound_to_anim
,"frames_initial")
204 row
.prop(context
.object.imp_sound_to_anim
,"action_min_value")
209 row
.prop(context
.object.imp_sound_to_anim
,"optimization_destructive")
212 row
.prop(context
.object.imp_sound_to_anim
,"action_max_value")
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")
221 row
.prop(context
.object.imp_sound_to_anim
,"audio_channel_select")
222 row
.prop(context
.object.imp_sound_to_anim
,"action_valor_igual")
225 #OBJECT_OT_Botao_Go => Botao_GO
227 layout
.operator(OBJECT_OT_Botao_Go
.bl_idname
)
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
238 if context
.object.imp_sound_to_anim
.bArrayCriado
:
239 layout
.operator(OBJECT_OT_Botao_Import
.bl_idname
)
242 #Layout SmartRender, somente para Blender_render
243 if bpy
.context
.scene
.render
.engine
== "BLENDER_RENDER":
245 row
.label(text
="----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------")
247 if context
.object.imp_sound_to_anim
.Info_check_smartrender
!= "":
249 row
.label(text
=context
.object.imp_sound_to_anim
.Info_check_smartrender
)
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
)
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")
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 #-----------------------------
265 #-----------------------------
266 if context
.object.imp_sound_to_anim
.bTypeImport
== 2:
269 #row.prop(context.object.imp_sound_to_anim,"audio_sense")
271 #row.prop(context.object.imp_sound_to_anim,"frames_per_second")
273 #row.prop(context.object.imp_sound_to_anim,"action_per_second")
275 #layout.operator(ImportWavFile.bl_idname)
279 #==================================================================================================
280 # BLENDER UI PropertyGroup
281 #==================================================================================================
283 class ImpSoundtoAnim(bpy
.types
.PropertyGroup
):
286 bArrayCriado
: IntProperty(name
="",
287 description
="Avisa que rodou process de som",
291 Working
: StringProperty(name
="Working",
292 description
="Script esta trabalhando",
297 Info_Import
: StringProperty(name
="Info_Import",
298 description
="Info about Import",
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",
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",
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",
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",
331 default
= 4)#this set the initial text
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",
340 default
= 100)#this set the initial text
343 action_max_value
: IntProperty(name
="Clip Max",
344 description
="Set the max value (clip higher values)",
348 default
= 255)#this set the initial text
351 action_min_value
: IntProperty(name
="Clip Min",
352 description
="Set the min value. (clip lower values)",
356 default
= 0)#this set the initial text
359 frames_initial
: IntProperty(name
="Frame Ini",
360 description
="Where to start to put the computed values",
366 audio_channel_select
: IntProperty(name
="Audio Channel",
367 description
="Choose the audio channel to use",
373 action_offset_x
: FloatProperty(name
="XOffset",
374 description
="Offset X Values",
380 action_offset_y
: FloatProperty(name
="YOffset",
381 description
="Offset Y Values",
387 action_offset_z
: FloatProperty(name
="ZOffset",
388 description
="Offset Z Values",
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")
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")
410 description
= "Where to Import",
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")
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")
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",
445 action_auto_audio_sense
: BoolProperty(name
="Auto Audio Sensitivity",
446 description
="Try to discover best audio scale. ",
449 use_just_beat
:BoolProperty(name
="Only Use The Beat",
450 description
="Try to use only the beat to extract movement",
453 remove_beat
:BoolProperty(name
="Remove The Beat",
454 description
="Try to remove the beat to extract movement",
457 beat_more_sensible
:BoolProperty(name
="More Sensible",
458 description
="Try To be more sensible about the beat",
461 beat_less_sensible
:BoolProperty(name
="Less Sensible",
462 description
="Try to be less sensible about the beat",
465 check_smartrender_loc_rot_sc
:BoolProperty(name
="Loc Rot Scale",
466 description
="Find changes in Location, Rotation and Scale Frame by Frame",
469 check_smartrender_material_basic
:BoolProperty(name
="Basic Material",
470 description
="Find changes in basic material settings Frame by Frame",
473 check_smartrender_material_transparence
:BoolProperty(name
="Material Transparence",
474 description
="Find changes in material transparence settings Frame by Frame",
477 check_smartrender_material_mirror
:BoolProperty(name
="Material Mirror",
478 description
="Find changes in material mirror settings Frame by Frame",
481 timer_reset_func
:BoolProperty(name
="Reset Counters",
482 description
="Reset Counters after stop",
485 cancel_button_hit
:BoolProperty(name
="Cancel Hit",
486 description
="Cancel Hit",
490 optimization_destructive
: IntProperty(name
="Optimization",
491 description
="Hi value = Hi optimization -> Hi loss of information",
497 # import as driver or direct NOT IN USE!!
501 bTypeImport
: IntProperty(name
="bTypeImport",
502 description
="Import Direct or Driver",
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 #==================================================================================================
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
534 def invoke(self
, context
, event
):
535 self
.execute(context
)
539 #==================================================================================================
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"
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
:
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
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
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':
590 if context
.object.imp_sound_to_anim
.import_type
=='imp_t_Rotation':
593 if context
.object.imp_sound_to_anim
.import_type
=='imp_t_Location':
596 # atencao, nao eh boolean
597 iEixoXneg
= iEixoYneg
= iEixoZneg
=1
598 # atencao, nao eh boolean
600 # atencao, nao eh boolean
601 iEscalaYneg
= iEscalaZneg
= iEscalaXneg
=1
602 bEixoX
=bEixoY
=bEixoZ
=bEscalaX
=bEscalaY
=bEscalaZ
=bRotationX
=bRotationY
=bRotationZ
=False
605 if context
.object.imp_sound_to_anim
.import_where1
== 'imp_w_x':
610 if context
.object.imp_sound_to_anim
.import_where1
== 'imp_w_y':
615 if context
.object.imp_sound_to_anim
.import_where1
== 'imp_w_z':
620 if context
.object.imp_sound_to_anim
.import_where1
== 'imp_w_-x':
628 if context
.object.imp_sound_to_anim
.import_where1
== 'imp_w_-y':
636 if context
.object.imp_sound_to_anim
.import_where1
== 'imp_w_-z':
646 if context
.object.imp_sound_to_anim
.import_where2
== 'imp_w_x':
651 if context
.object.imp_sound_to_anim
.import_where2
== 'imp_w_y':
656 if context
.object.imp_sound_to_anim
.import_where2
== 'imp_w_z':
661 if context
.object.imp_sound_to_anim
.import_where2
== 'imp_w_-x':
669 if context
.object.imp_sound_to_anim
.import_where2
== 'imp_w_-y':
677 if context
.object.imp_sound_to_anim
.import_where2
== 'imp_w_-z':
687 if context
.object.imp_sound_to_anim
.import_where3
== 'imp_w_x':
692 if context
.object.imp_sound_to_anim
.import_where3
== 'imp_w_y':
697 if context
.object.imp_sound_to_anim
.import_where3
== 'imp_w_z':
702 if context
.object.imp_sound_to_anim
.import_where3
== 'imp_w_-x':
710 if context
.object.imp_sound_to_anim
.import_where3
== 'imp_w_-y':
718 if context
.object.imp_sound_to_anim
.import_where3
== 'imp_w_-z':
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
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
750 print("================================================================")
751 from time
import strftime
752 print(strftime("Start Import: %H:%M:%S"))
753 print("================================================================")
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
770 array
[i
+obi
.RunFrom
]=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
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
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
803 if int(m_ival
) != m_ival
:
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':
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
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 ===========#
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
863 if iscaleXAnt
!=0 or iscaleYAnt
!=0 or iscaleZAnt
!=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)
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
910 ob
.keyframe_insert(data_path
="location")
913 ob
.keyframe_insert(data_path
="rotation_euler")
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
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
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("================================================================")
939 obi
.iSumImportFrames
=0
940 obi
.iSumOptimizerP1
=0
941 obi
.iSumOptimizerP2
=0
942 obi
.iSumOptimizerP3
=0
946 context
.object.imp_sound_to_anim
.Info_Import
="Processing Frame " + str(obi
.RunFrom
+loop
) + \
947 " of " + str(tot
-1) + " Frames"
951 def execute(self
, context
):
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
)
964 #==================================================================================================
965 # Button - Sound Process
966 #==================================================================================================
968 class OBJECT_OT_Botao_Go(bpy
.types
.Operator
):
970 bl_idname
= "import.sound_animation_botao_go"
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")
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
:
993 context
.object.imp_sound_to_anim
.timer_reset_func
=False
995 #abre arquivo se primeira rodada
998 obg
.Wave_read
= wave
.open(File
, 'rb')
1000 print("File Open Error: ", e
)
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 "
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')
1019 context
.object.imp_sound_to_anim
.Info_Import
=""
1021 # controla numero do canal
1022 if AudioChannel
> NumCh
:
1024 print("Channel number " + str(AudioChannel
) + " is selected but this audio file has just " + \
1025 str(NumCh
) + " channels, so selecting channel " \
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
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
1044 BytesDadosTotProcess
= NumFr
// BytesResol
1046 if obg
.RunFrom
==0: # primeira rodada
1048 _Interna_Globals(BytesDadosTotProcess
, context
)
1050 print("================================================================")
1051 from time
import strftime
1052 print(strftime("Go! %H:%M:%S"))
1053 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
)
1065 print('Audio Sensitivity: \t', Sensibil
+1)
1067 print('Using Auto Audio Sentivity. This is pass 1 of 2.')
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
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
1102 frame0
= frame
[AudioChannel
] << 6 & 255
1105 frame0
= frame
[AudioChannel
] << 5 & 255
1108 frame0
= frame
[AudioChannel
] << 4 & 255
1111 frame0
= frame
[AudioChannel
] << 3 & 255
1114 frame0
= frame
[AudioChannel
] << 2 & 255
1117 frame0
= frame
[AudioChannel
]
1119 if frame0
> ValorPico
:
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
1125 frame0
= frame
[1+AudioChannel
]
1128 frame0
= ((frame
[AudioChannel
] & 0b11111100) >> 2) |
((frame
[1+AudioChannel
] & 0b00000011) << 6)
1131 frame0
= ((frame
[AudioChannel
] & 0b11110000) >> 4) |
((frame
[1+AudioChannel
] & 0b00001111) << 4)
1134 frame0
= ((frame
[AudioChannel
] & 0b11100000) >> 5) |
((frame
[1+AudioChannel
] & 0b00011111) << 3)
1137 frame0
= ((frame
[AudioChannel
] & 0b11000000) >> 6) |
((frame
[1+AudioChannel
] & 0b00111111) << 2)
1140 frame0
=frame
[AudioChannel
]
1142 if frame0
> ValorPico
:
1145 else: # AutoAudioSense Ligado
1147 if frame
[AudioChannel
]> obg
.MaxAudio
:
1148 obg
.MaxAudio
= frame
[AudioChannel
]
1150 if frame
[AudioChannel
]> ValorPico
:
1151 ValorPico
=frame
[AudioChannel
]
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
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
1175 if bAutoSense
==0: #autoaudiosense desligado
1176 igraph
= ValorPico
//10
1179 igraph
= ValorPico
//1261
1182 igraph
= ValorPico
//10
1185 for iii
in range(igraph
):
1188 for iiii
in range(26-igraph
):
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
:
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
1208 print("Trying to use only the beat.")
1209 UseMinim
= obg
.MaxAudio
*0.8
1211 UseMinim
= obg
.MaxAudio
*0.7
1213 UseMinim
= obg
.MaxAudio
*0.9
1216 print("Trying to exclude the beat.")
1217 UseMax
= obg
.MaxAudio
*0.7
1219 UseMax
= obg
.MaxAudio
*0.8
1221 UseMax
= obg
.MaxAudio
*0.7
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
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
]
1239 if ValorOriginal
< UseMinim
:
1242 elif bRemoveBeat
==1:
1243 if ValorOriginal
> UseMax
:
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
1253 igraph
= round(array
[jj
-1]/10)
1255 for iii
in range(igraph
):
1258 for iiii
in range(26-igraph
):
1261 print ("Sample-> " + str(array
[jj
-1]) + "\tAudio Frame # " + str(i
) + " of " + str(looptot
-1) + "\t"+ stgraph
)
1264 del arrayAutoSense
[:]
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("================================================================")
1275 obg
.Wave_read
.close()
1277 print('File Close Error')
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
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
:
1299 context
.object.imp_sound_to_anim
.timer_reset_func
=False
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
)
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")
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
1332 for i
in range(iFramesPorSeg
):
1333 iDivMovPorSeg
=iFramesPorSeg
/(i
+1)
1334 if iFramesPorSeg
/iDivMovPorSeg
>=iMovPorSeg
:
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
)
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)
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 #==================================================================================================
1374 #==================================================================================================
1376 class OBJECT_OT_Botao_Cancel(bpy
.types
.Operator
):
1377 '''Cancel Actual Operation'''
1378 bl_idname
= "import.sound_animation_botao_cancel"
1381 def execute(self
, context
):
1382 context
.object.imp_sound_to_anim
.cancel_button_hit
=True
1385 def invoke(self
, context
, event
):
1386 self
.execute(context
)
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"
1405 def CheckRunStop(self
, context
, func
, index
):
1406 # forca update do UI
1407 bpy
.context
.scene
.frame_set(bpy
.context
.scene
.frame_current
)
1409 #configura timer para a funcao
1410 context
.object.imp_sound_to_anim
.Working
= func
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
)
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
=""
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':
1435 if context
.object.imp_sound_to_anim
.Working
== "CheckSmartRender":
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
)
1442 elif context
.object.imp_sound_to_anim
.Working
== "SmartRender":
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
)
1449 elif context
.object.imp_sound_to_anim
.Working
== "ProcessaSom":
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
)
1456 elif context
.object.imp_sound_to_anim
.Working
== "wavimport":
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
)
1474 print("-- Cancel Pressed --")
1475 context
.object.imp_sound_to_anim
.cancel_button_hit
=False
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'}
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
1494 return {'RUNNING_MODAL'}
1496 def cancel(self
, context
):
1497 if self
._timer
!= None:
1498 context
.window_manager
.event_timer_remove(self
._timer
)
1501 def parar(self
, context
):
1503 context
.object.imp_sound_to_anim
.Working
=""
1509 #==================================================================================================
1510 # Register - Unregister - MAIN
1511 #==================================================================================================
1513 # ------------------------------------------------------------
1516 VIEW3D_PT_SoundPanel
,
1518 OBJECT_OT_Botao_Cancel
,
1520 OBJECT_OT_Botao_Import
,
1521 OBJECT_OT_Botao_uDirect
,
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",
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__":
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)
1560 bpy.utils.unregister_module(__name__)
1565 bpy.types.TOPBAR_MT_file_import.remove(WavFileImport)
1571 if __name__ == "__main__":