addons-contrib: more view_layer syntax updates
[blender-addons-contrib.git] / io_import_sound_to_anim.py
1 #!/usr/bin/python3
2 # To change this template, choose Tools | Templates
3 # and open the template in the editor.
4 #  ***** GPL LICENSE BLOCK *****
5 #
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.
10 #
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.
15 #
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 *****
20
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     "wiki_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"}
33
34 """
35 -- Extract movement from sound file, to help in animation - import script --<br>
36
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
42
43 """
44
45 import bpy
46 from bpy.props import *
47 #from io_utils import ImportHelper
48 import wave
49
50 #para deixar global
51 def _Interna_Globals(BytesDadosTotProcess, context):
52     global array
53     global arrayAutoSense
54
55     array= bytearray(BytesDadosTotProcess)  # cria array
56     arrayAutoSense= bytearray((BytesDadosTotProcess)*2)  # cria array para AutoAudioSense
57     context.object.imp_sound_to_anim.bArrayCriado=True
58
59 #
60 #==================================================================================================
61 # BLENDER UI Panel
62 #==================================================================================================
63 #
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'}"""
70     
71 class VIEW3D_PT_CustomMenuPanel(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 = "Import Movement From Wav File"
78     #bl_options = {'DEFAULT_CLOSED'}
79     
80     def draw(self, context):
81         layout = self.layout
82
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")
100
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()
105
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()
113
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()
121
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)
128
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()
136
137                 # botao cancel
138                 layout.operator(OBJECT_OT_Botao_Cancel.bl_idname)
139                 row=layout.row()
140
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()
154
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")
158
159                     if context.object.imp_sound_to_anim.use_just_beat == 0:
160                         row.prop(context.object.imp_sound_to_anim,"remove_beat")
161
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")
167
168                         if context.object.imp_sound_to_anim.beat_more_sensible ==0:
169                             row.prop(context.object.imp_sound_to_anim,"beat_less_sensible")
170
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")
175
176                 #row=layout.row()
177                 row.label(text="Result from 0 to " + str(round(255/context.object.imp_sound_to_anim.action_escale,4)) + "")
178
179                 row=layout.row()
180                 row.label(text="Property to Change:")
181                 row.prop(context.object.imp_sound_to_anim,"import_type")
182
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")
188
189                 row=layout.row()
190                 row.label(text='Optional Configurations:')
191                 row=layout.row()
192                 
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()
199
200                 row=col.row()
201                 row.prop(context.object.imp_sound_to_anim,"frames_initial")
202
203                 row=col.row()
204                 row.prop(context.object.imp_sound_to_anim,"action_min_value")
205
206                 col=split.column()
207
208                 row=col.row()
209                 row.prop(context.object.imp_sound_to_anim,"optimization_destructive")
210
211                 row=col.row()
212                 row.prop(context.object.imp_sound_to_anim,"action_max_value")
213
214                 row=layout.row()
215
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")
219
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")
223
224                 #operator button
225                 #OBJECT_OT_Botao_Go => Botao_GO
226                 row=layout.row()
227                 layout.operator(OBJECT_OT_Botao_Go.bl_idname)
228
229                 row=layout.row()
230                 row.label(text=context.object.imp_sound_to_anim.Info_Import)
231
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()
241
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)
250
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)
255
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")
262
263             #-----------------------------
264             #Use Driver
265             #-----------------------------
266             if context.object.imp_sound_to_anim.bTypeImport == 2:
267
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)
276
277
278 #
279 #==================================================================================================
280 # BLENDER UI PropertyGroup
281 #==================================================================================================
282 #
283 class ImpSoundtoAnim(bpy.types.PropertyGroup):
284
285         #Array created
286         bArrayCriado: IntProperty(name="",
287             description="Avisa que rodou process de som",
288             default=0)
289
290         #Script Running
291         Working: StringProperty(name="Working",
292             description="Script esta trabalhando",
293             maxlen= 1024,
294             default="")
295
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
301
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
307
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)
315
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)
324
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
332
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
341
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
349
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
357
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)
365
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)
372
373         action_offset_x: FloatProperty(name="XOffset",
374             description="Offset X Values",
375             min=-999999,
376             max=999999,
377             step=1,
378             default= 0)
379
380         action_offset_y: FloatProperty(name="YOffset",
381             description="Offset Y Values",
382             min=-999999,
383             max=999999,
384             step=1,
385             default= 0)
386
387         action_offset_z: FloatProperty(name="ZOffset",
388             description="Offset Z Values",
389             min=-999999,
390             max=999999,
391             step=1,
392             default= 0)
393
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")
397                                         ),
398                                  name="",
399                                  description= "Property to Import Values",
400                                  default='imp_t_Location')
401
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")
408                                         ),
409                                  name="",
410                                  description= "Where to Import",
411                                  default='imp_w_z')
412
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")
420                                         ),
421                                  name="",
422                                  description= "Where to Import",
423                                  default='imp_w_none')
424
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")
432                                         ),
433                                  name="",
434                                  description= "Where to Import",
435                                  default='imp_w_none')
436
437
438         #========== Propriedades boolean  =============#
439
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)
444
445         action_auto_audio_sense: BoolProperty(name="Auto Audio Sensitivity",
446             description="Try to discover best audio scale. ",
447             default=1)
448
449         use_just_beat:BoolProperty(name="Only Use The Beat",
450             description="Try to use only the beat to extract movement.",
451             default=0)
452
453         remove_beat:BoolProperty(name="Remove The Beat",
454             description="Try to remove the beat to extract movement.",
455             default=0)
456
457         beat_more_sensible:BoolProperty(name="More Sensible",
458             description="Try To be more sensible about the beat.",
459             default=0)
460
461         beat_less_sensible:BoolProperty(name="Less Sensible",
462             description="Try to be less sensible about the beat.",
463             default=0)
464
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)
468
469         check_smartrender_material_basic:BoolProperty(name="Basic Material",
470             description="Find changes in basic material settings Frame by Frame.",
471             default=1)
472
473         check_smartrender_material_transparence:BoolProperty(name="Material Transparence",
474             description="Find changes in material transparence settings Frame by Frame.",
475             default=0)
476
477         check_smartrender_material_mirror:BoolProperty(name="Material Mirror",
478             description="Find changes in material mirror settings Frame by Frame.",
479             default=0)
480
481         timer_reset_func:BoolProperty(name="Reset Counters",
482             description="Reset Counters after stop",
483             default=0)
484
485         cancel_button_hit:BoolProperty(name="Cancel Hit",
486             description="Cancel Hit",
487             default=0)
488
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)
496
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)
504
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")
511
512 from bpy.props import *
513
514 def WavFileImport(self, context):
515     self.layout.operator(ImportWavFile.bl_idname, text="Import a wav file", icon='PLUGIN')
516
517
518 #
519 #==================================================================================================
520 # Use Direct
521 #==================================================================================================
522 #
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"
527
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'}
533
534     def invoke(self, context, event):
535         self.execute(context)
536         return {'FINISHED'}
537
538 #
539 #==================================================================================================
540 # Button - Import
541 #==================================================================================================
542 #
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"
547
548     RunFrom=0
549     iSumImportFrames=0
550     iSumOptimizerP1=0
551     iSumOptimizerP2=0
552     iSumOptimizerP3=0
553
554     def wavimport(context, loop):
555         obi=OBJECT_OT_Botao_Import
556
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
567             
568         #limita o loop se estiver no fim
569         tot=len(array)-1
570         if obi.RunFrom+loop > tot:
571             loop= tot - obi.RunFrom
572
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)
575
576         # nao deixa repetir valores
577         bNaoValorIgual=True
578         if context.object.imp_sound_to_anim.action_valor_igual: bNaoValorIgual= False
579
580         # inicia no inicio pedido pelo usuario mais ponteiro RunFrom
581         iStartFrame= int(context.object.imp_sound_to_anim.frames_initial) + obi.RunFrom
582
583         iMaxValue= context.object.imp_sound_to_anim.action_max_value
584         iMinValue= context.object.imp_sound_to_anim.action_min_value
585
586         bEscala=bRotacao=bEixo=False
587         if context.object.imp_sound_to_anim.import_type=='imp_t_Scale':
588             bEscala=True;
589
590         if context.object.imp_sound_to_anim.import_type=='imp_t_Rotation':
591             bRotacao=True;
592
593         if context.object.imp_sound_to_anim.import_type=='imp_t_Location':
594             bEixo=True;
595
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
603
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
609
610         if context.object.imp_sound_to_anim.import_where1== 'imp_w_y':
611             bEixoY=True
612             bEscalaY=True
613             bRotationY=True
614
615         if context.object.imp_sound_to_anim.import_where1== 'imp_w_z':
616             bEixoZ=True
617             bEscalaZ=True
618             bRotationZ=True
619
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
627
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
635
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
643
644
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
650
651         if context.object.imp_sound_to_anim.import_where2== 'imp_w_y':
652             bEixoY=True
653             bEscalaY=True
654             bRotationY=True
655
656         if context.object.imp_sound_to_anim.import_where2== 'imp_w_z':
657             bEixoZ=True
658             bEscalaZ=True
659             bRotationZ=True
660
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
668
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
676
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
684
685
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
691
692         if context.object.imp_sound_to_anim.import_where3== 'imp_w_y':
693             bEixoY=True
694             bEscalaY=True
695             bRotationY=True
696
697         if context.object.imp_sound_to_anim.import_where3== 'imp_w_z':
698             bEixoZ=True
699             bEscalaZ=True
700             bRotationZ=True
701
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
709
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
717
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
725
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
729
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
734
735         #Added destructive optimizer option - LostLestSignificativeDigit lost/total
736         iDestructiveOptimizer=context.object.imp_sound_to_anim.optimization_destructive
737
738         #limita ou nao o valor - velocidade
739         bLimitValue=False
740
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
747
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('')
755
756         ilocationXAnt=0
757         ilocationYAnt=0
758         ilocationZAnt=0
759         iscaleXAnt=0
760         iscaleYAnt=0
761         iscaleZAnt=0
762         iRotateValAnt=0
763
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
772
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]
777
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
799
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
806
807                             bpy.context.scene.frame_current = i+iStartFrame
808
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
816
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
821
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):
827
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()
832
833                                     #============= ALL ===========#
834                                     if bEixo:
835                                         if ilocationXAnt!=0 or ilocationYAnt!=0 or ilocationZAnt!=0:
836
837                                             bpy.ops.transform.translate(value=(ilocationXAnt*-1,                ilocationYAnt*-1, \
838                                                                                 ilocationZAnt*-1),               constraint_axis=(bEixoX, bEixoY,bEixoZ), \
839                                                                                 constraint_orientation='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)
845
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
850
851                                         bpy.ops.transform.translate(value=(ilocationX,                       ilocationY, \
852                                                                             ilocationZ),                      constraint_axis=(bEixoX, bEixoY,bEixoZ), \
853                                                                             constraint_orientation='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
861
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
870
871                                             bpy.ops.transform.resize(value=(tmpscaleXAnt,                    tmpscaleYAnt, \
872                                                                             tmpscaleZAnt ),                   constraint_axis=(False, False, False), \
873                                                                             constraint_orientation='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)
878
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
883
884                                         bpy.ops.transform.resize(value=(iscaleX,                        iscaleY, \
885                                                                         iscaleZ),                        constraint_axis=(False, False, False), \
886                                                                         constraint_orientation='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
895
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
901
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
906
907                             ob = bpy.context.active_object
908
909                             if bEixo:
910                                 ob.keyframe_insert(data_path="location")
911
912                             if bRotacao:
913                                 ob.keyframe_insert(data_path="rotation_euler")
914
915                             if bEscala:
916                                 ob.keyframe_insert(data_path="scale")
917
918                             print("Importing Blender Frame: "+str(i+obi.RunFrom+1)+"\tof "+str(len(array)-1) + "\tValue: "+ str(ival))
919
920                             obi.iSumImportFrames+=1
921                     # Fim do ELSE otimizador
922                 # Fim bNaoValorIgual
923
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
949
950
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()
956
957     def invoke(self, context, event):
958         self.execute(context)
959         return {'FINISHED'}
960
961
962
963 #
964 #==================================================================================================
965 # Button - Sound Process
966 #==================================================================================================
967 #
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"
974
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")
980
981     RunFrom=0
982     Wave_read=0
983     MaxAudio=0
984         
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
994
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
1002
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()
1008
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
1013
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
1018
1019         context.object.imp_sound_to_anim.Info_Import=""
1020
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
1028
1029         # apenas para por na tela
1030         tmpAudioChannel= AudioChannel
1031
1032         #used in index sum to find the channe, adjust to first byte sample index
1033         AudioChannel -= 1
1034
1035         # se dois canais, AudioChannel=4 porque sao 4 bytes
1036         if SampW ==2:  AudioChannel*=2
1037
1038         # usado para achar contorno da onda - achando picos
1039         # numero de audio frames para cada video frame
1040         BytesResol= int(FrameR/Resol)
1041
1042         # com 8 bits/S - razao Sample/s por resolucao
1043         # tamanho do array
1044         BytesDadosTotProcess= NumFr // BytesResol
1045
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)
1063
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.')
1068
1069             print('')
1070             print ("Sample->[value]\tAudio Frame #   \t\t[Graph Value]")
1071
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
1075
1076         # verifica limite total do audio
1077         looptot= int(BytesDadosTotProcess // DivSens)
1078         if obg.RunFrom+loop > looptot:
1079             loop= looptot-obg.RunFrom
1080
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)
1096
1097                 if len(frame)==0: break
1098
1099                 if bAutoSense==0:    # AutoAudioSense Desligado
1100                     if SampW ==1:
1101                         if Sensibil ==5:
1102                             frame0= frame[AudioChannel] << 6 & 255
1103
1104                         elif Sensibil ==4:
1105                             frame0= frame[AudioChannel] << 5 & 255
1106
1107                         elif Sensibil ==3:
1108                             frame0= frame[AudioChannel] << 4 & 255
1109
1110                         elif Sensibil ==2:
1111                             frame0= frame[AudioChannel] << 3 & 255
1112
1113                         elif Sensibil ==1:
1114                             frame0= frame[AudioChannel] << 2 & 255
1115
1116                         elif Sensibil ==0:
1117                             frame0= frame[AudioChannel]
1118
1119                         if frame0> ValorPico:
1120                             ValorPico= frame0
1121
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]
1126
1127                             elif Sensibil ==4:
1128                                 frame0= ((frame[AudioChannel] & 0b11111100) >> 2) | ((frame[1+AudioChannel] & 0b00000011) << 6)
1129
1130                             elif Sensibil ==3:
1131                                 frame0= ((frame[AudioChannel] & 0b11110000) >> 4) | ((frame[1+AudioChannel] & 0b00001111) << 4)
1132
1133                             elif Sensibil ==2:
1134                                 frame0= ((frame[AudioChannel] & 0b11100000) >> 5) | ((frame[1+AudioChannel] & 0b00011111) << 3)
1135
1136                             elif Sensibil ==1:
1137                                 frame0= ((frame[AudioChannel] & 0b11000000) >> 6) | ((frame[1+AudioChannel] & 0b00111111) << 2)
1138
1139                             elif Sensibil ==5:
1140                                 frame0=frame[AudioChannel]
1141
1142                             if frame0 > ValorPico:
1143                                 ValorPico= frame0
1144
1145                 else:   # AutoAudioSense Ligado
1146                     if SampW ==1:
1147                         if frame[AudioChannel]> obg.MaxAudio:
1148                             obg.MaxAudio = frame[AudioChannel]
1149
1150                         if frame[AudioChannel]> ValorPico:
1151                             ValorPico=frame[AudioChannel]
1152
1153                     if SampW ==2:
1154                         if frame[1+AudioChannel] < 127:
1155                             tmpValorPico= frame[1+AudioChannel] << 8
1156                             tmpValorPico+=  frame[AudioChannel]
1157
1158                             if tmpValorPico > obg.MaxAudio:
1159                                 obg.MaxAudio = tmpValorPico
1160
1161                             if tmpValorPico > ValorPico:
1162                                 ValorPico= tmpValorPico
1163
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
1174
1175             if bAutoSense==0:    #autoaudiosense desligado
1176                 igraph= ValorPico//10
1177             else:
1178                 if SampW ==2:
1179                     igraph= ValorPico//1261
1180
1181                 else:
1182                     igraph= ValorPico//10
1183
1184             stgraph="["
1185             for iii in range(igraph):
1186                 stgraph+="+"
1187
1188             for iiii in range(26-igraph):
1189                 stgraph+=" "
1190             stgraph+="]"
1191
1192             print ("Sample-> " + str(ValorPico) + "\tAudio Frame #  " + str(jj+obg.RunFrom) + " of " + str(looptot-1) + "\t"+ stgraph)
1193
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("================================================================")
1201
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
1206
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
1214
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
1222
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
1228
1229                 j=0
1230                 jj=0
1231                 print ("Sample->[value]\tAudio Frame #    \t\t[Graph Value]")
1232
1233                 for i in range(BytesDadosTotProcess // DivSens):
1234
1235                     ValorOriginal= arrayAutoSense[j+1] << 8
1236                     ValorOriginal+= arrayAutoSense[j]
1237
1238                     if bUseBeat==1:
1239                         if ValorOriginal < UseMinim:
1240                             ValorOriginal = 0
1241
1242                     elif bRemoveBeat==1:
1243                         if ValorOriginal > UseMax:
1244                             ValorOriginal = 0
1245
1246                     ValorOriginal= ((round(ValorOriginal * scale)) & 0b11111111)    #aplica a escala
1247
1248                     for ii in range(DivSens):
1249                         array[jj] = ValorOriginal
1250                         jj += 1   # se autoaudiosense, o array tem dois bytes para cada valor
1251
1252                     j+=2
1253                     igraph= round(array[jj-1]/10)
1254                     stgraph="["
1255                     for iii in range(igraph):
1256                         stgraph+="+"
1257
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)
1262
1263                 #limpa array tmp
1264                 del arrayAutoSense[:]
1265
1266             # mensagens finais
1267             context.object.imp_sound_to_anim.Info_Import= "Click \"Import Key frames\" to begin import" #this set the initial text
1268
1269             print("================================================================")
1270             from time import strftime
1271             print(strftime("End Process:  %H:%M:%S"))
1272             print("================================================================")
1273
1274             try:
1275                 obg.Wave_read.close()
1276             except:
1277                 print('File Close Error')
1278
1279             obg.RunFrom=0
1280             return obg.RunFrom   # acabou tudo
1281
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
1288
1289
1290
1291
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
1300
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)
1304
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
1314
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
1319
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
1323
1324         #Frames por segundo para key frame
1325         iFramesPorSeg= int(context.object.imp_sound_to_anim.frames_per_second)
1326
1327         #Sensibilidade de movimento. 3= 3 movimentos por segundo
1328         iMovPorSeg= int(context.object.imp_sound_to_anim.action_per_second)
1329
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
1336
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
1342
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
1348
1349
1350     def execute(self, context):
1351
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
1357
1358         context.object.imp_sound_to_anim.Working= "ProcessaSom"
1359         bpy.ops.wm.modal_timer_operator()
1360         #ProcessaSom(context)
1361         return{'FINISHED'}
1362
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)
1367
1368         return {'RUNNING_MODAL'}
1369
1370
1371 #
1372 #==================================================================================================
1373 # Button - Cancel
1374 #==================================================================================================
1375 #
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"
1380
1381     def execute(self, context):
1382         context.object.imp_sound_to_anim.cancel_button_hit=True
1383         return{'FINISHED'}
1384
1385     def invoke(self, context, event):
1386         self.execute(context)
1387         return {'FINISHED'}
1388
1389
1390 #
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 #==================================================================================================
1396 #
1397 class ModalTimerOperator(bpy.types.Operator):
1398     """Internal Script Control"""
1399     bl_idname = "wm.modal_timer_operator"
1400     bl_label = "Internal Script Control"
1401
1402     _timer = None
1403     Running= False
1404
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'}
1418
1419
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'}
1431
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)
1440
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)
1447
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)
1454
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)
1461
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'}
1465
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'}
1477
1478         #print("modal")
1479
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'}
1486
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'}
1495
1496     def cancel(self, context):
1497         if self._timer!= None:
1498             context.window_manager.event_timer_remove(self._timer)
1499         self._timer= None
1500
1501     def parar(self, context):
1502         if self.Running:
1503             context.object.imp_sound_to_anim.Working=""
1504             self.Running=False
1505
1506
1507
1508 #
1509 #==================================================================================================
1510 #     Register - Unregister - MAIN
1511 #==================================================================================================
1512 #
1513 # ------------------------------------------------------------
1514 # Register:
1515 classes = (
1516     VIEW3D_PT_CustomMenuPanel,
1517     ModalTimerOperator,
1518     OBJECT_OT_Botao_Cancel,
1519     OBJECT_OT_Botao_Go,
1520     OBJECT_OT_Botao_Import,
1521     OBJECT_OT_Botao_uDirect,
1522     ImpSoundtoAnim,
1523 )
1524
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(type=ImpSoundtoAnim, name="imp_sound_to_anim", description="Extract movement from sound file. See the tool shelf.")
1533
1534
1535 def unregister():
1536     for cls in reversed(classes):
1537         bpy.utils.unregister_class(cls)  
1538     #bpy.types.VIEW3D_MT_mesh_add.remove(WavFileImport)  
1539     bpy.types.TOPBAR_MT_file_import.remove(WavFileImport)
1540
1541
1542 if __name__ == "__main__":
1543     register()
1544
1545
1546
1547 """
1548 def register():
1549     bpy.utils.register_module(__name__)
1550     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.")
1551     bpy.types.TOPBAR_MT_file_import.append(WavFileImport)
1552
1553 def unregister():
1554
1555     try:
1556         bpy.utils.unregister_module(__name__)
1557     except:
1558         pass
1559
1560     try:
1561         bpy.types.TOPBAR_MT_file_import.remove(WavFileImport)
1562     except:
1563         pass
1564
1565
1566
1567 if __name__ == "__main__":
1568     register()"""