Import Export Vertex Groups rewritten
[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, 70),
25     "blender": (2, 64, 0),
26     "location": "Select a object > Object tab > Import Movement From Wav File",
27     "description": "Extract movement from sound file. "
28         "See the Object Panel at the end.",
29     "warning": "",
30     "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
31         "Scripts/Import-Export/Import_Movement_From_Audio_File",
32     "tracker_url": "https://developer.blender.org/T23565",
33     "category": "Import-Export"}
34
35 """
36 -- Extract movement from sound file, to help in animation - import script --<br>
37
38 - NOTES:
39 - This script takes a wav file and get sound "movement" to help you in sync the movement to words in the wave file. <br>
40 - Supported Audio: .wav (wave) 8 bits and 16 bits - mono and multichanel file<br>
41 - At least Blender 2.64.9 is necessary to run this program.
42 - Curitiba - Brasil
43
44
45 -v 0.70Beta-
46     Included: SmartRender - Render just the frames that has changes
47     Included: Options to check SmartRender for Blender Internal Render Engine:LocRotScale, Material, Transp, Mirror
48     Included: User can Cancel all functions with CANCEL button- Extensive Code and flux change (bugs expected)
49     Included: User can Cancel all functions with ESC
50     Inclused: User friendly messages into UI while running (its no more necessary to look at terminal window to most users)
51     Cleanup:  Non Stardard Chars in coments
52     To Do:    Decrease overhead of timer loops
53     To Do:    Try to implement Smart Render for Cycles
54
55 -v 0.60Beta-
56     Included: Option to use just the beat from the audio sound
57     Included: Option to exclude the beat from the audio sound
58     Included: More or less sensibility options when using the beat
59     Included: Audio Channel Select option
60
61 -v 0.50Beta-
62     Included: Auto Adjust Audio Sensity option
63     Included: 8 bits .wav file support
64     Recalibrated: Manual audio sense 1
65     Cosmetic: Many changes in panel and terminal window info
66     Corrected: Tracker_url
67     Corrected: a few bytes in Memory Leaks
68     work around: memory leak in function: bpy.ops.transform.rotate
69     work around: memory leak in function: bpy.ops.anim.keyframe_insert
70
71 -v 0.22Beta-
72     Included:
73     Camera Rotation
74     Empty Location-Rotation-Scale
75
76 -v 0.21Beta-
77     Changed just the meta informations like version and wiki page.
78
79 -v 0.20 Beta-
80     New Panel
81
82 -v 0.1.5 Beta-
83     Change in API-> Properties
84     Included the button "Get FPS from Scene" due to a problem to get it in the start
85     Return to Frame 1 after import
86     Filter .wav type file (by batFINGER)
87
88 -v 0.1.4 Beta-
89     If choose negative in rotation, auto check the rotation negative to Bones
90     change in register()  unregister():
91
92 -v 0.1.3 Beta-
93     File Cleanup
94     Change to bl_info.
95     Cosmetic Changes.
96     Minor change in API in how to define buttons.
97     Adjust in otimization.
98
99 -v 0.1.2 Beta
100 change in API- Update function bpy.ops.anim.keyframe_insert_menu
101
102 -v 0.1.1 Beta
103 change in API- Update property of  window_manager.fileselect_add
104
105 -v 0.1.0 Beta
106 new - Added support to LAMP object
107 new - improved flow to import
108 new - check the type of object before show options
109 bug - option max. and min. values
110 change- Updated scene properties for changes in property API.
111         See http://lists.blender.org/pipermail/bf-committers/2010-September/028654.html
112 new flow: 1) Process the sound file    2) Show Button to import key frames
113
114 - v0.0.4 ALPHA
115 new - Added destructive optimizer option - LostLestSignificativeDigit lost/total -> 10/255 default
116 new - Visual Graph to samples
117 new - Option to just process audio file and do not import - this is to help adjust the audio values
118 new - Get and show automatically the FPS (in proper field) information taking the information from scene
119 bug- Display sensitivity +1
120 bug - Corrected location of the script in description
121
122 - v0.0.3
123 Main change: Corrected to work INSIDE dir /install/linux2/2.53/scripts/addons
124 Corrected position of label "Rotation Negative"
125 Added correct way to deal with paths in Python os.path.join - os.path.normpath
126
127 - v0.0.2
128 Corrected initial error (Register() function)
129 Corrected some labels R. S. L.
130 Turned off "object field" for now
131 Changed target default to Z location
132
133 - v0.0.1
134 Initial version
135
136 Credit to:
137 Vlassius
138
139 - http://vlassius.com.br
140 - vlassius@vlassius.com.br
141 - Curitiba - Brasil
142
143 """
144
145 import bpy
146 from bpy.props import *
147 #from io_utils import ImportHelper
148 import wave
149
150 #para deixar global
151 def _Interna_Globals(BytesDadosTotProcess, context):
152     global array
153     global arrayAutoSense
154
155     array= bytearray(BytesDadosTotProcess)  # cria array
156     arrayAutoSense= bytearray((BytesDadosTotProcess)*2)  # cria array para AutoAudioSense
157     context.scene.imp_sound_to_anim.bArrayCriado=True
158
159 #
160 #==================================================================================================
161 # BLENDER UI Panel
162 #==================================================================================================
163 #
164 class VIEW3D_PT_CustomMenuPanel(bpy.types.Panel):
165     bl_space_type = "PROPERTIES"
166     bl_region_type = "WINDOW"
167     bl_context = "object"
168     bl_label = "Import Movement From Wav File"
169     bl_options = {'DEFAULT_CLOSED'}
170
171     def draw(self, context):
172         layout = self.layout
173
174         b=bpy.context.active_object.type=='EMPTY' or bpy.context.active_object.type=='ARMATURE' or \
175                                                             bpy.context.active_object.type=='MESH' or \
176                                                             bpy.context.active_object.type=='CAMERA' or \
177                                                             bpy.context.active_object.type=='LAMP'
178         if not b:
179             row=layout.row()
180             row.label(text="The Selected Object is: type \"" + bpy.context.active_object.type + \
181                                                                     "\", and it is not supported.")
182             row=layout.row()
183             row.label(text="Supported Object are Type: Armature, Mesh, Camera and Lamp")
184             row=layout.row()
185         else:
186             #print(context.scene.imp_sound_to_anim.bTypeImport)
187             if context.scene.imp_sound_to_anim.bTypeImport == 0:
188                 #mount panel to Direct animation
189                 row=layout.row()
190                 layout.operator("import.sound_animation_botao_udirect")
191
192             # monta as telas quando está rodando
193             elif context.scene.imp_sound_to_anim.Working!="":   #its running
194                 row=layout.row()
195                 row=layout.row()
196
197                 if context.scene.imp_sound_to_anim.Working== "CheckSmartRender":
198                     #context.scene.imp_sound_to_anim.Info_check_smartrender=
199                     row=layout.row()
200                     row.label(text="Checking for Smart Render...")
201                     row=layout.row()
202                     row.label(text=context.scene.imp_sound_to_anim.Info_check_smartrender)
203                     row=layout.row()
204
205                 elif context.scene.imp_sound_to_anim.Working== "SmartRender":
206                     #context.scene.imp_sound_to_anim.Info_check_smartrender=
207                     row=layout.row()
208                     row.label(text="Processing Smart Render...")
209                     row=layout.row()
210                     row.label(text=context.scene.imp_sound_to_anim.Info_check_smartrender)
211                     row=layout.row()
212
213                 elif context.scene.imp_sound_to_anim.Working== "ProcessaSom":
214                     #context.scene.imp_sound_to_anim.Info_Import=
215                     row=layout.row()
216                     row.label(text="Processing Sound File...")
217                     row=layout.row()
218                     row.label(text=context.scene.imp_sound_to_anim.Info_Import)
219
220                 elif context.scene.imp_sound_to_anim.Working== "wavimport":
221                     #context.scene.imp_sound_to_anim.Info_Import=
222                     row=layout.row()
223                     row.label(text="Importing Keys...")
224                     row=layout.row()
225                     row.label(text=context.scene.imp_sound_to_anim.Info_Import)
226                     row=layout.row()
227
228                 # botao cancel
229                 layout.operator(OBJECT_OT_Botao_Cancel.bl_idname)
230                 row=layout.row()
231
232             elif context.scene.imp_sound_to_anim.bTypeImport == 1:
233                 row=layout.row()
234                 row.label(text="1)Click button \"Process Wav\",")
235                 row=layout.row()
236                 row.label(text="2)Click Button \"Import Key Frames\",")
237                 row=layout.row()
238                 row.label(text="Run the animation (alt A) and Enjoy!")
239                 row=layout.row()
240                 row.prop(context.scene.imp_sound_to_anim,"action_auto_audio_sense")
241                 row=layout.row()
242                 if context.scene.imp_sound_to_anim.action_auto_audio_sense == 0:   # se auto audio sense desligado
243                     row.prop(context.scene.imp_sound_to_anim,"audio_sense")
244                     row=layout.row()
245
246                 else: #somente se autosense ligado
247                     if context.scene.imp_sound_to_anim.remove_beat == 0 :
248                         row.prop(context.scene.imp_sound_to_anim,"use_just_beat")
249
250                     if context.scene.imp_sound_to_anim.use_just_beat == 0:
251                         row.prop(context.scene.imp_sound_to_anim,"remove_beat")
252
253                     if context.scene.imp_sound_to_anim.use_just_beat or context.scene.imp_sound_to_anim.remove_beat:
254                         if not context.scene.imp_sound_to_anim.beat_less_sensible and not context.scene.imp_sound_to_anim.beat_more_sensible:
255                             row=layout.row()
256                         if context.scene.imp_sound_to_anim.beat_less_sensible ==0:
257                             row.prop(context.scene.imp_sound_to_anim,"beat_more_sensible")
258
259                         if context.scene.imp_sound_to_anim.beat_more_sensible ==0:
260                             row.prop(context.scene.imp_sound_to_anim,"beat_less_sensible")
261
262                 row=layout.row()
263                 row.prop(context.scene.imp_sound_to_anim,"action_per_second")
264                 row=layout.row()
265                 row.prop(context.scene.imp_sound_to_anim,"action_escale")
266
267                 #row=layout.row()
268                 row.label(text="Result from 0 to " + str(round(255/context.scene.imp_sound_to_anim.action_escale,4)) + "")
269
270                 row=layout.row()
271                 row.label(text="Property to Change:")
272                 row.prop(context.scene.imp_sound_to_anim,"import_type")
273
274                 #coluna
275                 row=layout.row()
276                 row.prop(context.scene.imp_sound_to_anim,"import_where1")
277                 row.prop(context.scene.imp_sound_to_anim,"import_where2")
278                 row.prop(context.scene.imp_sound_to_anim,"import_where3")
279
280                 row=layout.row()
281                 row.label(text='Optional Configurations:')
282                 row=layout.row()
283
284                 row.prop(context.scene.imp_sound_to_anim,"frames_per_second")
285                 row=layout.row()
286                 #coluna
287                 column= layout.column()
288                 split=column.split(percentage=0.5)
289                 col=split.column()
290
291                 row=col.row()
292                 row.prop(context.scene.imp_sound_to_anim,"frames_initial")
293
294                 row=col.row()
295                 row.prop(context.scene.imp_sound_to_anim,"action_min_value")
296
297                 col=split.column()
298
299                 row=col.row()
300                 row.prop(context.scene.imp_sound_to_anim,"optimization_destructive")
301
302                 row=col.row()
303                 row.prop(context.scene.imp_sound_to_anim,"action_max_value")
304
305                 row=layout.row()
306
307                 row.prop(context.scene.imp_sound_to_anim,"action_offset_x")
308                 row.prop(context.scene.imp_sound_to_anim,"action_offset_y")
309                 row.prop(context.scene.imp_sound_to_anim,"action_offset_z")
310
311                 row=layout.row()
312                 row.prop(context.scene.imp_sound_to_anim,"audio_channel_select")
313                 row.prop(context.scene.imp_sound_to_anim,"action_valor_igual")
314
315                 #operator button
316                 #OBJECT_OT_Botao_Go => Botao_GO
317                 row=layout.row()
318                 layout.operator(OBJECT_OT_Botao_Go.bl_idname)
319
320                 row=layout.row()
321                 row.label(text=context.scene.imp_sound_to_anim.Info_Import)
322
323                 # preciso garantir a existencia do array porque o Blender salva no arquivo como existente sem o array existir
324                 try:
325                     array
326                 except NameError:
327                     nada=0 #dummy
328                 else:
329                     if context.scene.imp_sound_to_anim.bArrayCriado:
330                         layout.operator(OBJECT_OT_Botao_Import.bl_idname)
331                         row=layout.row()
332
333                 #Layout SmartRender, somente para Blender_render
334                 if bpy.context.scene.render.engine == "BLENDER_RENDER":
335                     row=layout.row()
336                     row.label(text="----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------")
337                     row=layout.row()
338                     if context.scene.imp_sound_to_anim.Info_check_smartrender!= "":
339                         row=layout.row()
340                         row.label(text=context.scene.imp_sound_to_anim.Info_check_smartrender)
341
342                     row=layout.row()
343                     row.operator(OBJECT_OT_Botao_Check_SmartRender.bl_idname)
344                     if context.scene.imp_sound_to_anim.Info_check_smartrender!= "":
345                         row.operator(OBJECT_OT_Botao_SmartRender.bl_idname)
346
347                     row=layout.row()
348                     row.prop(context.scene.imp_sound_to_anim,"check_smartrender_loc_rot_sc")
349                     row.prop(context.scene.imp_sound_to_anim,"check_smartrender_material_basic")
350                     row=layout.row()
351                     row.prop(context.scene.imp_sound_to_anim,"check_smartrender_material_transparence")
352                     row.prop(context.scene.imp_sound_to_anim,"check_smartrender_material_mirror")
353
354             #-----------------------------
355             #Use Driver
356             #-----------------------------
357             if context.scene.imp_sound_to_anim.bTypeImport == 2:
358
359                 row=layout.row()
360                 row.prop(context.scene.imp_sound_to_anim,"audio_sense")
361                 row=layout.row()
362                 row.prop(context.scene.imp_sound_to_anim,"frames_per_second")
363                 row=layout.row()
364                 row.prop(context.scene.imp_sound_to_anim,"action_per_second")
365                 row=layout.row()
366                 layout.operator(ImportWavFile.bl_idname)
367
368
369 #
370 #==================================================================================================
371 # BLENDER UI PropertyGroup
372 #==================================================================================================
373 #
374 class ImpSoundtoAnim(bpy.types.PropertyGroup):
375
376         #Array created
377         bArrayCriado = IntProperty(name="",
378             description="Avisa que rodou process de som",
379             default=0)
380
381         #Script Running
382         Working = StringProperty(name="",
383             description="Script esta trabalhando",
384             maxlen= 1024,
385             default="")
386
387         #Nome do objeto
388         Info_Import = StringProperty(name="",
389             description="Info about Import",
390             maxlen= 1024,
391             default= "")#this set the initial text
392
393         #Mensagem Smart Render
394         Info_check_smartrender = StringProperty(name="",
395             description="Smart Render Message",
396             maxlen= 1024,
397             default= "")#this set the initial text
398
399         #iAudioSensib=0    #sensibilidade volume do audio 0 a 5. Quanto maior, mais sensibilidade
400         audio_sense = IntProperty(name="Audio Sens",
401             description="Audio Sensibility.",
402             min=1,
403             max=6,
404             step=1,
405             default= 1)
406
407         #iFramesPorSeg=15  #Frames por segundo para key frame
408         #fps= (bpy.types.Scene) bpy.context.scene.render.fps
409         frames_per_second = IntProperty(name="#Frames/s",
410             description="Frames you want per second. Better match your set up in Blender scene.",
411             min=1,
412             max=120,
413             step=1)
414
415         #iMovPorSeg=1      #Sensibilidade de movimento. 3= 3 movimentos por segundo
416         action_per_second = IntProperty(name="Act/s",
417             description="Actions per second. From 1 to #Frames/s",
418             min=1,
419             max=120,
420             step=1,
421             default= 4)#this set the initial text
422
423         #iDivScala=200
424         #scala do valor do movimento. [se =1 - 0 a 255 ] [se=255 - 0,00000 a 1,00000] [se=1000 - 0 a 0.255]
425         action_escale = IntProperty(name="Scale",
426             description="Scale the result values. See the text at right side of the field",
427             min=1,
428             max=99999,
429             step=100,
430             default= 100)#this set the initial text
431
432         #iMaxValue=255
433         action_max_value = IntProperty(name="Clip Max",
434             description="Set the max value (clip higher values).",
435             min=1,
436             max=255,
437             step=1,
438             default= 255)#this set the initial text
439
440         #iMinValue=0
441         action_min_value = IntProperty(name="Clip Min",
442             description="Set the min value. (clip lower values)",
443             min=0,
444             max=255,
445             step=1,
446             default= 0)#this set the initial text
447
448         #iStartFrame=0#
449         frames_initial = IntProperty(name="Frame Ini",
450             description="Where to start to put the computed values.",
451             min=0,
452             max=999999999,
453             step=1,
454             default= 0)
455
456         audio_channel_select = IntProperty(name="Audio Channel",
457             description="Choose the audio channel to use",
458             min=1,
459             max=10,
460             step=1,
461             default= 1)
462
463         action_offset_x = FloatProperty(name="XOffset",
464             description="Offset X Values",
465             min=-999999,
466             max=999999,
467             step=1,
468             default= 0)
469
470         action_offset_y = FloatProperty(name="YOffset",
471             description="Offset Y Values",
472             min=-999999,
473             max=999999,
474             step=1,
475             default= 0)
476
477         action_offset_z = FloatProperty(name="ZOffset",
478             description="Offset Z Values",
479             min=-999999,
480             max=999999,
481             step=1,
482             default= 0)
483
484         import_type= EnumProperty(items=(('imp_t_Scale', "Scale", "Apply to Scale"),
485                                          ('imp_t_Rotation', "Rotation", "Apply to Rotation"),
486                                          ('imp_t_Location', "Location", "Apply to Location")
487                                         ),
488                                  name="",
489                                  description= "Property to Import Values",
490                                  default='imp_t_Location')
491
492         import_where1= EnumProperty(items=(('imp_w_-z', "-z", "Apply to -z"),
493                                           ('imp_w_-y', "-y", "Apply to -y"),
494                                           ('imp_w_-x', "-x", "Apply to -x"),
495                                           ('imp_w_z', "z", "Apply to z"),
496                                           ('imp_w_y', "y", "Apply to y"),
497                                           ('imp_w_x', "x", "Apply to x")
498                                         ),
499                                  name="",
500                                  description= "Where to Import",
501                                  default='imp_w_z')
502
503         import_where2= EnumProperty(items=(('imp_w_none', "None", ""),
504                                           ('imp_w_-z', "-z", "Apply to -z"),
505                                           ('imp_w_-y', "-y", "Apply to -y"),
506                                           ('imp_w_-x', "-x", "Apply to -x"),
507                                           ('imp_w_z', "z", "Apply to z"),
508                                           ('imp_w_y', "y", "Apply to y"),
509                                           ('imp_w_x', "x", "Apply to x")
510                                         ),
511                                  name="",
512                                  description= "Where to Import",
513                                  default='imp_w_none')
514
515         import_where3= EnumProperty(items=(('imp_w_none', "None", ""),
516                                           ('imp_w_-z', "-z", "Apply to -z"),
517                                           ('imp_w_-y', "-y", "Apply to -y"),
518                                           ('imp_w_-x', "-x", "Apply to -x"),
519                                           ('imp_w_z', "z", "Apply to z"),
520                                           ('imp_w_y', "y", "Apply to y"),
521                                           ('imp_w_x', "x", "Apply to x")
522                                         ),
523                                  name="",
524                                  description= "Where to Import",
525                                  default='imp_w_none')
526
527
528         #========== Propriedades boolean  =============#
529
530         #  INVERTIDO!!!  bNaoValorIgual=True    # nao deixa repetir valores     INVERTIDO!!!
531         action_valor_igual = BoolProperty(name="Hard Transition",
532             description="Use to movements like a mouth, to a arm movement, maybe you will not use this.",
533             default=1)
534
535         action_auto_audio_sense = BoolProperty(name="Auto Audio Sensitivity",
536             description="Try to discover best audio scale. ",
537             default=1)
538
539         use_just_beat=BoolProperty(name="Just Use The Beat",
540             description="Try to use just the beat to extract movement.",
541             default=0)
542
543         remove_beat=BoolProperty(name="Remove The Beat",
544             description="Try to remove the beat to extract movement.",
545             default=0)
546
547         beat_more_sensible=BoolProperty(name="More Sensible",
548             description="Try To be more sensible about the beat.",
549             default=0)
550
551         beat_less_sensible=BoolProperty(name="Less Sensible",
552             description="Try to be less sensible about the beat.",
553             default=0)
554
555         check_smartrender_loc_rot_sc=BoolProperty(name="Loc Rot Scale",
556             description="Find changes in Location, Rotation and Scale Frame by Frame.",
557             default=1)
558
559         check_smartrender_material_basic=BoolProperty(name="Basic Material",
560             description="Find changes in basic material settings Frame by Frame.",
561             default=1)
562
563         check_smartrender_material_transparence=BoolProperty(name="Material Transparence",
564             description="Find changes in material transparence settings Frame by Frame.",
565             default=0)
566
567         check_smartrender_material_mirror=BoolProperty(name="Material Mirror",
568             description="Find changes in material mirror settings Frame by Frame.",
569             default=0)
570
571         timer_reset_func=BoolProperty(name="Reset Counters",
572             description="Reset Counters after stop",
573             default=0)
574
575         cancel_button_hit=BoolProperty(name="Cancel Hit",
576             description="Cancel Hit",
577             default=0)
578
579         #  Optimization
580         optimization_destructive = IntProperty(name="Optimization",
581             description="Hi value = Hi optimization -> Hi loss of information.",
582             min=0,
583             max=254,
584             step=10,
585             default= 10)
586
587         # import as driver or direct   NOT IN USE!!
588         # not defined
589         # Direct=1
590         # Driver=2
591         bTypeImport = IntProperty(name="",
592             description="Import Direct or Driver",
593             default=0)
594
595         # globais do dialog open wave
596         filter_glob = StringProperty(default="*.wav", options={'HIDDEN'})
597         path =        StringProperty(name="File Path", description="Filepath used for importing the WAV file", \
598                                                                                         maxlen= 1024, default= "")
599         filename =    StringProperty(name="File Name", description="Name of the file")
600         directory =   StringProperty(name="Directory", description="Directory of the file")
601
602 from bpy.props import *
603
604 def WavFileImport(self, context):
605     self.layout.operator(ImportWavFile.bl_idname, text="Import a wav file", icon='PLUGIN')
606
607
608 #
609 #==================================================================================================
610 # Use Direct
611 #==================================================================================================
612 #
613 class OBJECT_OT_Botao_uDirect(bpy.types.Operator):
614     '''Import as Direct Animation'''
615     bl_idname = "import.sound_animation_botao_udirect"
616     bl_label = "Direct to a Property"
617
618     def execute(self, context):
619         context.scene.imp_sound_to_anim.bTypeImport= 1
620         if context.scene.imp_sound_to_anim.frames_per_second == 0:
621              context.scene.imp_sound_to_anim.frames_per_second= bpy.context.scene.render.fps
622         return{'FINISHED'}
623
624     def invoke(self, context, event):
625         self.execute(context)
626         return {'FINISHED'}
627
628 #
629 #==================================================================================================
630 # Button - Import
631 #==================================================================================================
632 #
633 class OBJECT_OT_Botao_Import(bpy.types.Operator):
634     '''Import Key Frames to Blender'''
635     bl_idname = "import.sound_animation_botao_import"
636     bl_label = "Import Key Frames"
637
638     RunFrom=0
639     iSumImportFrames=0
640     iSumOptimizerP1=0
641     iSumOptimizerP2=0
642     iSumOptimizerP3=0
643
644     def wavimport(context, loop):
645         obi=OBJECT_OT_Botao_Import
646
647         # para de entrar no timer
648         context.scene.imp_sound_to_anim.Working=""
649         #reseta contadores caso seja pedido
650         if context.scene.imp_sound_to_anim.timer_reset_func:
651             obi.RunFrom=0
652             obi.iSumOptimizerP1=0
653             obi.iSumOptimizerP2=0
654             obi.iSumOptimizerP3=0
655             obi.iSumImportFrames=0
656             context.scene.imp_sound_to_anim.timer_reset_func=False
657
658         #limita o loop se estiver no fim
659         tot=len(array)-1
660         if obi.RunFrom+loop > tot:
661             loop= tot - obi.RunFrom
662
663         #scala do valor do movimento. [se =1 - 0 a 255 ] [se=255 - 0,00000 a 1,00000] [se=1000 - 0 a 0.255]
664         iDivScala= int(context.scene.imp_sound_to_anim.action_escale)
665
666         # nao deixa repetir valores
667         bNaoValorIgual=True
668         if context.scene.imp_sound_to_anim.action_valor_igual: bNaoValorIgual= False
669
670         # inicia no inicio pedido pelo usuario mais ponteiro RunFrom
671         iStartFrame= int(context.scene.imp_sound_to_anim.frames_initial) + obi.RunFrom
672
673         iMaxValue= context.scene.imp_sound_to_anim.action_max_value
674         iMinValue= context.scene.imp_sound_to_anim.action_min_value
675
676         bEscala=bRotacao=bEixo=False
677         if context.scene.imp_sound_to_anim.import_type=='imp_t_Scale':
678             bEscala=True;
679
680         if context.scene.imp_sound_to_anim.import_type=='imp_t_Rotation':
681             bRotacao=True;
682
683         if context.scene.imp_sound_to_anim.import_type=='imp_t_Location':
684             bEixo=True;
685
686         # atencao, nao eh boolean
687         iEixoXneg= iEixoYneg= iEixoZneg=1
688         # atencao, nao eh boolean
689         iRotationNeg=1
690         # atencao, nao eh boolean
691         iEscalaYneg= iEscalaZneg= iEscalaXneg=1
692         bEixoX=bEixoY=bEixoZ=bEscalaX=bEscalaY=bEscalaZ=bRotationX=bRotationY=bRotationZ=False
693
694         # LOCAL 1
695         if context.scene.imp_sound_to_anim.import_where1== 'imp_w_x':
696             bEixoX=True
697             bEscalaX=True
698             bRotationX=True
699
700         if context.scene.imp_sound_to_anim.import_where1== 'imp_w_y':
701             bEixoY=True
702             bEscalaY=True
703             bRotationY=True
704
705         if context.scene.imp_sound_to_anim.import_where1== 'imp_w_z':
706             bEixoZ=True
707             bEscalaZ=True
708             bRotationZ=True
709
710         if context.scene.imp_sound_to_anim.import_where1== 'imp_w_-x':
711             bEixoX=True
712             bEscalaX=True
713             bRotationX=True
714             iEixoXneg=-1
715             iEscalaXneg=-1
716             iRotationNeg=-1
717
718         if context.scene.imp_sound_to_anim.import_where1== 'imp_w_-y':
719             bEixoY=True
720             bEscalaY=True
721             bRotationY=True
722             iEixoYneg=-1
723             iRotationNeg=-1
724             iEscalaYneg=-1
725
726         if context.scene.imp_sound_to_anim.import_where1== 'imp_w_-z':
727             bEixoZ=True
728             bEscalaZ=True
729             bRotationZ=True
730             iEixoZneg=-1
731             iRotationNeg=-1
732             iEscalaZneg=-1
733
734
735         # LOCAL 2
736         if context.scene.imp_sound_to_anim.import_where2== 'imp_w_x':
737             bEixoX=True
738             bEscalaX=True
739             bRotationX=True
740
741         if context.scene.imp_sound_to_anim.import_where2== 'imp_w_y':
742             bEixoY=True
743             bEscalaY=True
744             bRotationY=True
745
746         if context.scene.imp_sound_to_anim.import_where2== 'imp_w_z':
747             bEixoZ=True
748             bEscalaZ=True
749             bRotationZ=True
750
751         if context.scene.imp_sound_to_anim.import_where2== 'imp_w_-x':
752             bEixoX=True
753             bEscalaX=True
754             bRotationX=True
755             iEixoXneg=-1
756             iEscalaXneg=-1
757             iRotationNeg=-1
758
759         if context.scene.imp_sound_to_anim.import_where2== 'imp_w_-y':
760             bEixoY=True
761             bEscalaY=True
762             bRotationY=True
763             iEixoYneg=-1
764             iRotationNeg=-1
765             iEscalaYneg=-1
766
767         if context.scene.imp_sound_to_anim.import_where2== 'imp_w_-z':
768             bEixoZ=True
769             bEscalaZ=True
770             bRotationZ=True
771             iEixoZneg=-1
772             iRotationNeg=-1
773             iEscalaZneg=-1
774
775
776         # LOCAL 3
777         if context.scene.imp_sound_to_anim.import_where3== 'imp_w_x':
778             bEixoX=True
779             bEscalaX=True
780             bRotationX=True
781
782         if context.scene.imp_sound_to_anim.import_where3== 'imp_w_y':
783             bEixoY=True
784             bEscalaY=True
785             bRotationY=True
786
787         if context.scene.imp_sound_to_anim.import_where3== 'imp_w_z':
788             bEixoZ=True
789             bEscalaZ=True
790             bRotationZ=True
791
792         if context.scene.imp_sound_to_anim.import_where3== 'imp_w_-x':
793             bEixoX=True
794             bEscalaX=True
795             bRotationX=True
796             iEixoXneg=-1
797             iEscalaXneg=-1
798             iRotationNeg=-1
799
800         if context.scene.imp_sound_to_anim.import_where3== 'imp_w_-y':
801             bEixoY=True
802             bEscalaY=True
803             bRotationY=True
804             iEixoYneg=-1
805             iRotationNeg=-1
806             iEscalaYneg=-1
807
808         if context.scene.imp_sound_to_anim.import_where3== 'imp_w_-z':
809             bEixoZ=True
810             bEscalaZ=True
811             bRotationZ=True
812             iEixoZneg=-1
813             iRotationNeg=-1
814             iEscalaZneg=-1
815
816         iMinBaseX=iMinScaleBaseX=context.scene.imp_sound_to_anim.action_offset_x
817         iMinBaseY=iMinScaleBaseY=context.scene.imp_sound_to_anim.action_offset_y
818         iMinBaseZ=iMinScaleBaseZ=context.scene.imp_sound_to_anim.action_offset_z
819
820         #escala inicia com 1 e nao com zero
821         iRotationAxisBaseX=context.scene.imp_sound_to_anim.action_offset_x  +1
822         iRotationAxisBaseY=context.scene.imp_sound_to_anim.action_offset_y  +1
823         iRotationAxisBaseZ=context.scene.imp_sound_to_anim.action_offset_z  +1
824
825         #Added destructive optimizer option - LostLestSignificativeDigit lost/total
826         iDestructiveOptimizer=context.scene.imp_sound_to_anim.optimization_destructive
827
828         #limita ou nao o valor - velocidade
829         bLimitValue=False
830
831         if iMinValue<0: iMinValue=0
832         if iMaxValue>255: iMaxValue=255
833         if iMinValue>255: iMinValue=255
834         if iMaxValue<0: iMaxValue=0
835         if iMinValue!= 0: bLimitValue= True
836         if iMaxValue!= 255: bLimitValue= True
837
838         if obi.RunFrom==0:
839             print('')
840             print("================================================================")
841             from time import strftime
842             print(strftime("Start Import:  %H:%M:%S"))
843             print("================================================================")
844             print('')
845
846         ilocationXAnt=0
847         ilocationYAnt=0
848         ilocationZAnt=0
849         iscaleXAnt=0
850         iscaleYAnt=0
851         iscaleZAnt=0
852         iRotateValAnt=0
853
854         # variavel global _Interna_Globals
855         if context.scene.imp_sound_to_anim.bArrayCriado:
856             for i in range(loop):
857                 ival=array[i+obi.RunFrom]/iDivScala
858                 #valor pequeno demais, vai dar zero na hora de aplicar
859                 if ival < 0.001:
860                      array[i+obi.RunFrom]=0
861                      ival=0
862
863                 # to increase performance and legibility
864                 arrayI= array[i+obi.RunFrom]
865                 arrayIP1= array[i+1+obi.RunFrom]
866                 arrayIL1= array[i-1+obi.RunFrom]
867
868                 # opcao de NAO colocar valores iguais sequenciais
869                 if i>0 and bNaoValorIgual and arrayIL1== arrayI:
870                     print("Importing Blender Frame: "+str(i+obi.RunFrom+1)+"\tof "+str(len(array)-1) + \
871                                                                             "\t(skipped by optimizer)")
872                     obi.iSumOptimizerP3+=1
873                 else:
874                     # otimizacao - nao preciso mais que 2 valores iguais.
875                     # pular key frame intermediario - Ex b, a, -, -, -, a
876                     # tambem otimiza pelo otimizador com perda
877                     # valor atual == anterior e posterior -> pula
878                     if i>0 and i< len(array)-1 and abs(arrayI - arrayIL1)<=iDestructiveOptimizer and \
879                                                         abs(arrayI - arrayIP1)<=iDestructiveOptimizer:
880                             print("Importing Blender Frame: "+str(i+obi.RunFrom+1)+"\tof "+str(len(array)-1) + \
881                                                                                     "\t(skipped by optimizer)")
882                             if iDestructiveOptimizer>0 and arrayI != arrayIL1 or arrayI != arrayIP1:
883                                 obi.iSumOptimizerP1+=1
884                             else: obi.iSumOptimizerP2+=1
885                     else:
886                             if bLimitValue:
887                                 if arrayI > iMaxValue: array[i+obi.RunFrom]=iMaxValue
888                                 if arrayI < iMinValue: array[i+obi.RunFrom]=iMinValue
889
890                             ival=array[i+obi.RunFrom]/iDivScala
891                             #passa para float com somente 3 digitos caso seja float
892                             m_ival=ival*1000
893                             if int(m_ival) != m_ival:
894                                 ival= int(m_ival)
895                                 ival = ival /1000
896
897                             bpy.context.scene.frame_current = i+iStartFrame
898
899                             #precisa fazer objeto ativo
900                             if bpy.context.active_object.type=='MESH' or bpy.context.active_object.type=='CAMERA' or \
901                                                                             bpy.context.active_object.type=='EMPTY':
902                                 if bEixo:
903                                     if bEixoX: bpy.context.active_object.location.x = ival*iEixoXneg+iMinBaseX
904                                     if bEixoY: bpy.context.active_object.location.y = ival*iEixoYneg+iMinBaseY
905                                     if bEixoZ: bpy.context.active_object.location.z = ival*iEixoZneg+iMinBaseZ
906
907                                 if bEscala:
908                                     if bEscalaX: bpy.context.active_object.scale.x = ival*iEscalaXneg+iMinScaleBaseX
909                                     if bEscalaY: bpy.context.active_object.scale.y = ival*iEscalaYneg+iMinScaleBaseY
910                                     if bEscalaZ: bpy.context.active_object.scale.z = ival*iEscalaZneg+iMinScaleBaseZ
911
912                             # 'ARMATURE' or ('MESH' and bRotacao) or ('CAMERA' and bRotacao) or 'LAMP' or 'EMPTY' and bRotacao)
913                             if bpy.context.active_object.type=='ARMATURE' or (bpy.context.active_object.type=='MESH' and bRotacao) or \
914                                                                             (bpy.context.active_object.type=='CAMERA' and bRotacao) or \
915                                                                             bpy.context.active_object.type=='LAMP' or \
916                                                                             (bpy.context.active_object.type=='EMPTY' and bRotacao):
917
918                                     #===========  BONE ===========#
919                                     if bpy.context.active_object.type=='ARMATURE':   #precisa ser objeto ativo. Nao achei como passar para editmode
920                                         if bpy.context.mode!= 'POSE':    #posemode
921                                             bpy.ops.object.posemode_toggle()
922
923                                     #============= ALL ===========#
924                                     if bEixo:
925                                         if ilocationXAnt!=0 or ilocationYAnt!=0 or ilocationZAnt!=0:
926
927                                             bpy.ops.transform.translate(value=(ilocationXAnt*-1,                ilocationYAnt*-1, \
928                                                                                 ilocationZAnt*-1),               constraint_axis=(bEixoX, bEixoY,bEixoZ), \
929                                                                                 constraint_orientation='GLOBAL', mirror=False, \
930                                                                                 proportional='DISABLED',         proportional_edit_falloff='SMOOTH', \
931                                                                                 proportional_size=1,             snap=False, \
932                                                                                 snap_target='CLOSEST',           snap_point=(0, 0, 0), \
933                                                                                 snap_align=False,               snap_normal=(0, 0, 0), \
934                                                                                 release_confirm=False)
935
936                                         ilocationX=ilocationY=ilocationZ=0
937                                         if bEixoX: ilocationX = ival*iEixoXneg+iMinBaseX
938                                         if bEixoY: ilocationY = ival*iEixoYneg+iMinBaseY
939                                         if bEixoZ: ilocationZ = ival*iEixoZneg+iMinBaseZ
940
941                                         bpy.ops.transform.translate(value=(ilocationX,                       ilocationY, \
942                                                                             ilocationZ),                      constraint_axis=(bEixoX, bEixoY,bEixoZ), \
943                                                                             constraint_orientation='GLOBAL',  mirror=False, \
944                                                                             proportional='DISABLED',          proportional_edit_falloff='SMOOTH', \
945                                                                             proportional_size=1,              snap=False, \
946                                                                             snap_target='CLOSEST',            snap_point=(0, 0, 0), snap_align=False, \
947                                                                             snap_normal=(0, 0, 0),           release_confirm=False)
948                                         ilocationXAnt= ilocationX
949                                         ilocationYAnt= ilocationY
950                                         ilocationZAnt= ilocationZ
951
952                                     if bEscala:
953                                         if iscaleXAnt!=0 or iscaleYAnt!=0 or iscaleZAnt!=0:
954                                             tmpscaleXAnt=0
955                                             tmpscaleYAnt=0
956                                             tmpscaleZAnt=0
957                                             if iscaleXAnt: tmpscaleXAnt=1/iscaleXAnt
958                                             if iscaleYAnt: tmpscaleYAnt=1/iscaleYAnt
959                                             if iscaleZAnt: tmpscaleZAnt=1/iscaleZAnt
960
961                                             bpy.ops.transform.resize(value=(tmpscaleXAnt,                    tmpscaleYAnt, \
962                                                                             tmpscaleZAnt ),                   constraint_axis=(False, False, False), \
963                                                                             constraint_orientation='GLOBAL',  mirror=False, \
964                                                                             proportional='DISABLED',          proportional_edit_falloff='SMOOTH', \
965                                                                             proportional_size=1, snap=False, snap_target='CLOSEST', \
966                                                                             snap_point=(0, 0, 0),             snap_align=False, \
967                                                                             snap_normal=(0, 0, 0),            release_confirm=False)
968
969                                         iscaleX=iscaleY=iscaleZ=0
970                                         if bEscalaX: iscaleX = ival*iEscalaXneg+iMinScaleBaseX
971                                         if bEscalaY: iscaleY = ival*iEscalaYneg+iMinScaleBaseY
972                                         if bEscalaZ: iscaleZ = ival*iEscalaZneg+iMinScaleBaseZ
973
974                                         bpy.ops.transform.resize(value=(iscaleX,                        iscaleY, \
975                                                                         iscaleZ),                        constraint_axis=(False, False, False), \
976                                                                         constraint_orientation='GLOBAL', mirror=False, \
977                                                                         proportional='DISABLED',         proportional_edit_falloff='SMOOTH', \
978                                                                         proportional_size=1,             snap=False, \
979                                                                         snap_target='CLOSEST',           snap_point=(0, 0, 0), \
980                                                                         snap_align=False,               snap_normal=(0, 0, 0), \
981                                                                         release_confirm=False)
982                                         iscaleXAnt= iscaleX
983                                         iscaleYAnt= iscaleY
984                                         iscaleZAnt= iscaleZ
985
986                                     if bRotacao:
987                                         if iRotateValAnt!=0:
988                                             bpy.context.active_object.rotation_euler= ((iRotateValAnt*-1)+    iRotationAxisBaseX) *bRotationX , \
989                                                                                         ((iRotateValAnt*-1)+  iRotationAxisBaseY) *bRotationY , \
990                                                                                         ((iRotateValAnt*-1)+  iRotationAxisBaseZ) *bRotationZ
991
992                                         bpy.context.active_object.rotation_euler= ((ival*iRotationNeg)+   iRotationAxisBaseX) * bRotationX, \
993                                                                                     ((ival*iRotationNeg)+ iRotationAxisBaseY)  * bRotationY, \
994                                                                                     ((ival*iRotationNeg)+ iRotationAxisBaseZ)  * bRotationZ
995                                         iRotateValAnt= ival*iRotationNeg
996
997                             ob = bpy.context.active_object
998
999                             if bEixo:
1000                                 ob.keyframe_insert(data_path="location")
1001
1002                             if bRotacao:
1003                                 ob.keyframe_insert(data_path="rotation_euler")
1004
1005                             if bEscala:
1006                                 ob.keyframe_insert(data_path="scale")
1007
1008                             print("Importing Blender Frame: "+str(i+obi.RunFrom+1)+"\tof "+str(len(array)-1) + "\tValue: "+ str(ival))
1009
1010                             obi.iSumImportFrames+=1
1011                     # Fim do ELSE otimizador
1012                 # Fim bNaoValorIgual
1013
1014             if obi.RunFrom>= tot:
1015                 bpy.context.scene.frame_current = 1
1016                 context.scene.imp_sound_to_anim.Info_Import="Done. Imported " + str(obi.iSumImportFrames) + " Frames"
1017                 from time import strftime
1018                 print('')
1019                 print("================================================================")
1020                 print("Imported: " +str(obi.iSumImportFrames) + " Key Frames")
1021                 print("Optimizer Pass 1 prepared to optimize: " +str(obi.iSumOptimizerP1) + " blocks of Frames")
1022                 print("Optimizer Pass 2 has optimized: " +str(obi.iSumOptimizerP2) + " Frames")
1023                 print("Optimizer Pass 3 has optimized: " +str(obi.iSumOptimizerP3) + " Frames")
1024                 print("Optimizer has optimized: " +str(obi.iSumOptimizerP1 + obi.iSumOptimizerP2 + obi.iSumOptimizerP3) + " Frames")
1025                 print(strftime("End Import:  %H:%M:%S - by Vlassius"))
1026                 print("================================================================")
1027                 print('')
1028                 obi.RunFrom=0
1029                 obi.iSumImportFrames=0
1030                 obi.iSumOptimizerP1=0
1031                 obi.iSumOptimizerP2=0
1032                 obi.iSumOptimizerP3=0
1033                 return obi.RunFrom
1034             else:
1035                 obi.RunFrom+= loop
1036                 context.scene.imp_sound_to_anim.Info_Import="Processing Frame " + str(obi.RunFrom+loop) + \
1037                                                                             " of " + str(tot-1) + " Frames"
1038                 return obi.RunFrom
1039
1040
1041     def execute(self, context):
1042         #wavimport(context)
1043         #return{'FINISHED'}
1044         context.scene.imp_sound_to_anim.Working= "wavimport"
1045         bpy.ops.wm.modal_timer_operator()
1046
1047     def invoke(self, context, event):
1048         self.execute(context)
1049         return {'FINISHED'}
1050
1051
1052
1053 #
1054 #==================================================================================================
1055 # Button - Sound Process
1056 #==================================================================================================
1057 #
1058 class OBJECT_OT_Botao_Go(bpy.types.Operator):
1059     ''''''
1060     bl_idname = "import.sound_animation_botao_go"
1061     # change in API
1062     bl_description = "Process a .wav file, take movement from the sound and import to the scene as Key"
1063     bl_label = "Process Wav"
1064
1065     filter_glob = StringProperty(default="*.wav", options={'HIDDEN'})
1066     path = StringProperty(name="File Path", description="Filepath used for importing the WAV file", \
1067                                                                             maxlen= 1024, default= "")
1068     filename = StringProperty(name="File Name", description="Name of the file")
1069     directory = StringProperty(name="Directory", description="Directory of the file")
1070
1071     RunFrom=0
1072     Wave_read=0
1073     MaxAudio=0
1074
1075
1076     def SoundConv(File, DivSens, Sensibil, Resol, context, bAutoSense, bRemoveBeat, bUseBeat, bMoreSensible, \
1077                                                                             bLessSensible, AudioChannel, loop):
1078         obg= OBJECT_OT_Botao_Go
1079         #reseta contadores caso seja pedido
1080         if context.scene.imp_sound_to_anim.timer_reset_func:
1081             obc.RunFrom=0
1082             Wave_read=0
1083             MaxAudio=0
1084             context.scene.imp_sound_to_anim.timer_reset_func=False
1085
1086         #abre arquivo se primeira rodada
1087         if obg.RunFrom==0:
1088             try:
1089                 obg.Wave_read= wave.open(File, 'rb')
1090             except IOError as e:
1091                 print("File Open Error: ", e)
1092                 return False
1093
1094         NumCh=      obg.Wave_read.getnchannels()
1095         SampW=      obg.Wave_read.getsampwidth() # 8, 16, 24 32 bits
1096         FrameR=     obg.Wave_read.getframerate()
1097         NumFr=      obg.Wave_read.getnframes()
1098         ChkCompr=   obg.Wave_read.getcomptype()
1099
1100         if ChkCompr != "NONE":
1101             print('Sorry, this compressed Format is NOT Supported ', ChkCompr)
1102             context.scene.imp_sound_to_anim.Info_Import= "Sorry, this compressed Format is NOT Supported "
1103             return False
1104
1105         if SampW > 2:
1106             context.scene.imp_sound_to_anim.Info_Import= "Sorry, supported .wav files 8 and 16 bits only"
1107             print('Sorry, supported .wav files 8 and 16 bits only')
1108             return False
1109
1110         context.scene.imp_sound_to_anim.Info_Import=""
1111
1112         # controla numero do canal
1113         if AudioChannel > NumCh:
1114             if obg.RunFrom==0:
1115                 print("Channel number " + str(AudioChannel) + " is selected but this audio file has just " + \
1116                                                             str(NumCh) + " channels, so selecting channel " \
1117                                                                                             + str(NumCh) + "!")
1118             AudioChannel = NumCh
1119
1120         # apenas para por na tela
1121         tmpAudioChannel= AudioChannel
1122
1123         #used in index sum to find the channe, adjust to first byte sample index
1124         AudioChannel -= 1
1125
1126         # se dois canais, AudioChannel=4 porque sao 4 bytes
1127         if SampW ==2:  AudioChannel*=2
1128
1129         # usado para achar contorno da onda - achando picos
1130         # numero de audio frames para cada video frame
1131         BytesResol= int(FrameR/Resol)
1132
1133         # com 8 bits/S - razao Sample/s por resolucao
1134         # tamanho do array
1135         BytesDadosTotProcess= NumFr // BytesResol
1136
1137         if obg.RunFrom==0:   # primeira rodada
1138             # inicia array
1139             _Interna_Globals(BytesDadosTotProcess, context)
1140             print('')
1141             print("================================================================")
1142             from time import strftime
1143             print(strftime("Go!  %H:%M:%S"))
1144             print("================================================================")
1145             print('')
1146             print('Total Audio Time: \t ' + str(NumFr//FrameR) + 's (' + str(NumFr//FrameR//60) + 'min)')
1147             print('Total # Interactions: \t', BytesDadosTotProcess)
1148             print('Total Audio Frames: \t', NumFr)
1149             print('Frames/s: \t\t ' + str(FrameR))
1150             print('# Chanels in File: \t', NumCh)
1151             print('Channel to use:\t\t', tmpAudioChannel)
1152             print('Bit/Sample/Chanel: \t ' + str(SampW*8))
1153             print('# Frames/Act: \t\t', DivSens)
1154
1155             if bAutoSense==0:
1156                 print('Audio Sensitivity: \t', Sensibil+1)
1157             else:
1158                 print('Using Auto Audio Sentivity. This is pass 1 of 2.')
1159
1160             print('')
1161             print ("Sample->[value]\tAudio Frame #   \t\t[Graph Value]")
1162
1163         if obg.RunFrom==0 and bAutoSense!=0:
1164             Sensibil=0  # if auto sense, Sensibil must be zero here
1165             obg.MaxAudio=0  # valor maximo de audio encontrado
1166
1167         # verifica limite total do audio
1168         looptot= int(BytesDadosTotProcess // DivSens)
1169         if obg.RunFrom+loop > looptot:
1170             loop= looptot-obg.RunFrom
1171
1172         j=0  # usado de indice
1173         # laco total leitura bytes
1174         # armazena dado de pico
1175         for jj in range(loop):
1176             # caso de 2 canais (esterio)
1177             # uso apenas 2 bytes em 16 bits, ie, apenas canal esquerdo
1178             # [0] e [1] para CH L
1179             # [2] e [3] para CH R   and so on
1180             # mono:1 byte to 8 bits, 2 bytes to 16 bits
1181             # sterio: 2 byte to 8 bits, 4 bytes to 16 bits
1182             ValorPico=0
1183             # leio o numero de frames de audio para cada frame de video, valor em torno de 1000
1184             for i in range(BytesResol):
1185                 #loop exterior copia DivSens frames a cada frame calculado
1186                 frame = obg.Wave_read.readframes(DivSens)
1187
1188                 if len(frame)==0: break
1189
1190                 if bAutoSense==0:    # AutoAudioSense Desligado
1191                     if SampW ==1:
1192                         if Sensibil ==5:
1193                             frame0= frame[AudioChannel] << 6 & 255
1194
1195                         elif Sensibil ==4:
1196                             frame0= frame[AudioChannel] << 5 & 255
1197
1198                         elif Sensibil ==3:
1199                             frame0= frame[AudioChannel] << 4 & 255
1200
1201                         elif Sensibil ==2:
1202                             frame0= frame[AudioChannel] << 3 & 255
1203
1204                         elif Sensibil ==1:
1205                             frame0= frame[AudioChannel] << 2 & 255
1206
1207                         elif Sensibil ==0:
1208                             frame0= frame[AudioChannel]
1209
1210                         if frame0> ValorPico:
1211                             ValorPico= frame0
1212
1213                     if SampW ==2:   # frame[0] baixa       frame[1] ALTA BIT 1 TEM SINAL!
1214                         if frame[1+AudioChannel] <127:    # se bit1 =0, usa o valor - se bit1=1 quer dizer numero negativo
1215                             if Sensibil ==0:
1216                                 frame0= frame[1+AudioChannel]
1217
1218                             elif Sensibil ==4:
1219                                 frame0= ((frame[AudioChannel] & 0b11111100) >> 2) | ((frame[1+AudioChannel] & 0b00000011) << 6)
1220
1221                             elif Sensibil ==3:
1222                                 frame0= ((frame[AudioChannel] & 0b11110000) >> 4) | ((frame[1+AudioChannel] & 0b00001111) << 4)
1223
1224                             elif Sensibil ==2:
1225                                 frame0= ((frame[AudioChannel] & 0b11100000) >> 5) | ((frame[1+AudioChannel] & 0b00011111) << 3)
1226
1227                             elif Sensibil ==1:
1228                                 frame0= ((frame[AudioChannel] & 0b11000000) >> 6) | ((frame[1+AudioChannel] & 0b00111111) << 2)
1229
1230                             elif Sensibil ==5:
1231                                 frame0=frame[AudioChannel]
1232
1233                             if frame0 > ValorPico:
1234                                 ValorPico= frame0
1235
1236                 else:   # AutoAudioSense Ligado
1237                     if SampW ==1:
1238                         if frame[AudioChannel]> obg.MaxAudio:
1239                             obg.MaxAudio = frame[AudioChannel]
1240
1241                         if frame[AudioChannel]> ValorPico:
1242                             ValorPico=frame[AudioChannel]
1243
1244                     if SampW ==2:
1245                         if frame[1+AudioChannel] < 127:
1246                             tmpValorPico= frame[1+AudioChannel] << 8
1247                             tmpValorPico+=  frame[AudioChannel]
1248
1249                             if tmpValorPico > obg.MaxAudio:
1250                                 obg.MaxAudio = tmpValorPico
1251
1252                             if tmpValorPico > ValorPico:
1253                                 ValorPico= tmpValorPico
1254
1255             if bAutoSense==0:    #autoaudiosense desligado
1256                 # repito o valor de frames por actions (OTIMIZAR)
1257                 for ii in range(DivSens):
1258                     array[j+obg.RunFrom]=ValorPico  # valor de pico encontrado
1259                     j +=1           # incrementa indice prox local
1260             else:
1261                 idx=obg.RunFrom*2 # porque sao dois bytes
1262                 arrayAutoSense[j+idx]= (ValorPico & 0b0000000011111111) #copia valores baixos
1263                 arrayAutoSense[j+1+idx]= (ValorPico & 0b1111111100000000) >> 8   #copia valores altos
1264                 j+=2
1265
1266             if bAutoSense==0:    #autoaudiosense desligado
1267                 igraph= ValorPico//10
1268             else:
1269                 if SampW ==2:
1270                     igraph= ValorPico//1261
1271
1272                 else:
1273                     igraph= ValorPico//10
1274
1275             stgraph="["
1276             for iii in range(igraph):
1277                 stgraph+="+"
1278
1279             for iiii in range(26-igraph):
1280                 stgraph+=" "
1281             stgraph+="]"
1282
1283             print ("Sample-> " + str(ValorPico) + "\tAudio Frame #  " + str(jj+obg.RunFrom) + " of " + str(looptot-1) + "\t"+ stgraph)
1284
1285         # acabou primeira fase roda toda de uma vez
1286         if obg.RunFrom+loop == looptot:
1287             if bAutoSense==1:
1288                 print("")
1289                 print("================================================================")
1290                 print('Calculating Auto Audio Sentivity, pass 2 of 2.')
1291                 print("================================================================")
1292
1293                 # caso usar batida, procurar por valores proximos do maximo e zerar restante.
1294                 # caso retirar batida, zerar valores proximos do maximo
1295                 UseMinim=0
1296                 UseMax=0
1297
1298                 if bUseBeat==1:
1299                     print("Trying to use just the beat.")
1300                     UseMinim= obg.MaxAudio*0.8
1301                     if bMoreSensible:
1302                         UseMinim= obg.MaxAudio*0.7
1303                     elif bLessSensible:
1304                         UseMinim= obg.MaxAudio*0.9
1305
1306                 if bRemoveBeat==1:
1307                     print("Trying to exclude the beat.")
1308                     UseMax= obg.MaxAudio*0.7
1309                     if bMoreSensible:
1310                         UseMax= obg.MaxAudio*0.8
1311                     elif bLessSensible:
1312                         UseMax= obg.MaxAudio*0.7
1313
1314                 print("")
1315                 # para transformar 15 bits em 8 calibrando valor maximo -> fazer regra de 3
1316                 # obg.MaxAudio -> 255
1317                 # outros valores => valor calibrado= (255 * Valor) / obg.MaxAudio
1318                 scale= 255/obg.MaxAudio
1319
1320                 j=0
1321                 jj=0
1322                 print ("Sample->[value]\tAudio Frame #    \t\t[Graph Value]")
1323
1324                 for i in range(BytesDadosTotProcess // DivSens):
1325
1326                     ValorOriginal= arrayAutoSense[j+1] << 8
1327                     ValorOriginal+= arrayAutoSense[j]
1328
1329                     if bUseBeat==1:
1330                         if ValorOriginal < UseMinim:
1331                             ValorOriginal = 0
1332
1333                     elif bRemoveBeat==1:
1334                         if ValorOriginal > UseMax:
1335                             ValorOriginal = 0
1336
1337                     ValorOriginal= ((round(ValorOriginal * scale)) & 0b11111111)    #aplica a escala
1338
1339                     for ii in range(DivSens):
1340                         array[jj] = ValorOriginal
1341                         jj += 1   # se autoaudiosense, o array tem dois bytes para cada valor
1342
1343                     j+=2
1344                     igraph= round(array[jj-1]/10)
1345                     stgraph="["
1346                     for iii in range(igraph):
1347                         stgraph+="+"
1348
1349                     for iiii in range(26-igraph):
1350                         stgraph+=" "
1351                     stgraph+="]"
1352                     print ("Sample-> " + str(array[jj-1]) + "\tAudio Frame #  " + str(i) + " of " + str(looptot-1) + "\t"+ stgraph)
1353
1354                 #limpa array tmp
1355                 del arrayAutoSense[:]
1356
1357             # mensagens finais
1358             context.scene.imp_sound_to_anim.Info_Import= "Click \"Import Key frames\" to begin import" #this set the initial text
1359
1360             print("================================================================")
1361             from time import strftime
1362             print(strftime("End Process:  %H:%M:%S"))
1363             print("================================================================")
1364
1365             try:
1366                 obg.Wave_read.close()
1367             except:
1368                 print('File Close Error')
1369
1370             obg.RunFrom=0
1371             return obg.RunFrom   # acabou tudo
1372
1373         else:#ainda nao acabou o arquivo todo if RunFrom+loop = looptot:
1374             context.scene.imp_sound_to_anim.Info_Import="Processing " + str(obg.RunFrom) + " of " + str(looptot) +" Audio Frames"
1375             # force update info text in UI
1376             bpy.context.scene.frame_current= bpy.context.scene.frame_current
1377             obg.RunFrom+=loop
1378             return obg.RunFrom
1379
1380
1381
1382
1383     def ProcessaSom(context, loop):
1384         obg= OBJECT_OT_Botao_Go
1385         # para de entrar o timer
1386         context.scene.imp_sound_to_anim.Working=""
1387         #reseta contadores caso seja pedido
1388         if context.scene.imp_sound_to_anim.timer_reset_func:
1389             obg.RunFrom=0
1390             context.scene.imp_sound_to_anim.timer_reset_func=False
1391
1392         import os
1393         f= os.path.join(context.scene.imp_sound_to_anim.directory, context.scene.imp_sound_to_anim.filename)
1394         f= os.path.normpath(f)
1395
1396         if obg.RunFrom==0:
1397             print ("")
1398             print ("")
1399             print ("Selected file = ",f)
1400         checktype = f.split('\\')[-1].split('.')[1]
1401         if checktype.upper() != 'WAV':
1402             print ("ERROR!! Selected file = ", f)
1403             print ("ERROR!! Its not a .wav file")
1404             return
1405
1406         #sensibilidade volume do audio 0 a 5. Quanto maior, mais sensibilidade
1407         iAudioSensib= int(context.scene.imp_sound_to_anim.audio_sense)-1
1408         if iAudioSensib <0: iAudioSensib=0
1409         elif iAudioSensib>5: iAudioSensib=5
1410
1411         #act/s nao pode se maior que frames/s
1412         if context.scene.imp_sound_to_anim.action_per_second > context.scene.imp_sound_to_anim.frames_per_second:
1413             context.scene.imp_sound_to_anim.action_per_second = context.scene.imp_sound_to_anim.frames_per_second
1414
1415         #Frames por segundo para key frame
1416         iFramesPorSeg= int(context.scene.imp_sound_to_anim.frames_per_second)
1417
1418         #Sensibilidade de movimento. 3= 3 movimentos por segundo
1419         iMovPorSeg= int(context.scene.imp_sound_to_anim.action_per_second)
1420
1421         #iDivMovPorSeg Padrao - taxa 4/s ou a cada 0,25s  => iFramesPorSeg/iDivMovPorSeg= ~0.25
1422         for i in range(iFramesPorSeg):
1423             iDivMovPorSeg=iFramesPorSeg/(i+1)
1424             if iFramesPorSeg/iDivMovPorSeg >=iMovPorSeg:
1425                 break
1426
1427         bRemoveBeat=    context.scene.imp_sound_to_anim.remove_beat
1428         bUseBeat=       context.scene.imp_sound_to_anim.use_just_beat
1429         bLessSensible=  context.scene.imp_sound_to_anim.beat_less_sensible
1430         bMoreSensible=  context.scene.imp_sound_to_anim.beat_more_sensible
1431         AudioChannel=   context.scene.imp_sound_to_anim.audio_channel_select
1432
1433         # chama funcao de converter som, retorna preenchendo _Interna_Globals.array
1434         index= OBJECT_OT_Botao_Go.SoundConv(f, int(iDivMovPorSeg), iAudioSensib, iFramesPorSeg, context, \
1435                                     context.scene.imp_sound_to_anim.action_auto_audio_sense, bRemoveBeat, \
1436                                     bUseBeat, bMoreSensible, bLessSensible, AudioChannel, loop)
1437         return index
1438
1439
1440     def execute(self, context):
1441
1442         # copia dados dialof open wave
1443         context.scene.imp_sound_to_anim.filter_glob= self.filter_glob
1444         context.scene.imp_sound_to_anim.path = self.path
1445         context.scene.imp_sound_to_anim.filename = self.filename
1446         context.scene.imp_sound_to_anim.directory = self.directory
1447
1448         context.scene.imp_sound_to_anim.Working= "ProcessaSom"
1449         bpy.ops.wm.modal_timer_operator()
1450         #ProcessaSom(context)
1451         return{'FINISHED'}
1452
1453     def invoke(self, context, event):
1454         #need to set a path so so we can get the file name and path
1455         wm = context.window_manager
1456         wm.fileselect_add(self)
1457
1458         return {'RUNNING_MODAL'}
1459
1460
1461 #
1462 #==================================================================================================
1463 # Button - Check Smart Render
1464 #==================================================================================================
1465 #
1466 class OBJECT_OT_Botao_Check_SmartRender(bpy.types.Operator):
1467     '''Check for Reduction'''
1468     bl_idname = "import.sound_animation_botao_check_smartrender"
1469     bl_label = "Check Smart Render"
1470
1471     RunFrom=0
1472     Frames_Renderizar=0
1473     Frames_Pular=0
1474
1475     def CheckSmartRender(context, loop):
1476         obc= OBJECT_OT_Botao_Check_SmartRender
1477
1478         #reseta contadores caso seja pedido
1479         if context.scene.imp_sound_to_anim.timer_reset_func:
1480             obc.RunFrom=0
1481             obc.Frames_Pular=0
1482             obc.Frames_Renderizar=0
1483             context.scene.imp_sound_to_anim.timer_reset_func=False
1484
1485         if obc.RunFrom==0:
1486             if loop !=1: # loop==1 quando estou chamando de dentro da funcao render
1487                 print("")
1488                 print("================================================================")
1489                 print('Running Check Smart Render...')
1490
1491         #garante ao menos locrotscale ligado
1492         if context.scene.imp_sound_to_anim.check_smartrender_loc_rot_sc==False and \
1493                         context.scene.imp_sound_to_anim.check_smartrender_material_basic==False and \
1494                         context.scene.imp_sound_to_anim.check_smartrender_material_transparence==False and \
1495                         context.scene.imp_sound_to_anim.check_smartrender_material_mirror==False:
1496             context.scene.imp_sound_to_anim.check_smartrender_loc_rot_sc=True
1497
1498         chkLocRotSc=  context.scene.imp_sound_to_anim.check_smartrender_loc_rot_sc
1499         chkMatBas=    context.scene.imp_sound_to_anim.check_smartrender_material_basic
1500         chkMatTransp= context.scene.imp_sound_to_anim.check_smartrender_material_transparence
1501         chkMatMirror= context.scene.imp_sound_to_anim.check_smartrender_material_mirror
1502
1503         ToRender=[]
1504         origloop=loop
1505         from copy import copy
1506         RunMax= bpy.context.scene.frame_end - bpy.context.scene.frame_start+1
1507         if obc.RunFrom+loop > RunMax:
1508             loop= RunMax-obc.RunFrom
1509             if loop<=0:   #acabou
1510                 if origloop !=1: # loop==1 quando estou chamando de dentro da funcao render
1511                     print("")
1512                     print("Frames to copy: " + str(obc.Frames_Pular) + " Frames to really render= " + str(obc.Frames_Renderizar))
1513                     print("================================================================")
1514                     print("")
1515                 obc.RunFrom=0
1516                 obc.Frames_Pular=0
1517                 obc.Frames_Renderizar=0
1518                 return (ToRender, obc.RunFrom)
1519
1520         #move para o primeiro frame a renderizar
1521         #RunFrom inicia em zero - frames inicia em 1
1522         bpy.context.scene.frame_current = obc.RunFrom+bpy.context.scene.frame_start
1523
1524         for k in range(loop):
1525             if obc.RunFrom==0 and k==0: #primeiro sempre renderiza
1526                 ToRender.append(bpy.context.scene.frame_current)
1527                 obc.Frames_Renderizar+=1
1528                 bpy.context.scene.frame_set(bpy.context.scene.frame_current + 1)
1529             else:
1530                 if origloop !=1: # loop==1 quando estou chamando de dentro da funcao render
1531                     import sys
1532                     sys.stdout.write("\rChecking Frame "+str(bpy.context.scene.frame_current) + "  ")
1533                     sys.stdout.flush()
1534                 #buffer de todos os objetos
1535                 a=[]
1536                 for obj in bpy.data.objects:
1537                     if chkLocRotSc:
1538                         # loc rot scale
1539                         a.append(copy(obj.location))
1540                         a.append(copy(obj.rotation_euler))
1541                         a.append(copy(obj.scale))
1542                     if hasattr(obj.data, 'materials') and obj.data.materials.keys()!=[] :
1543                         if bpy.context.scene.render.engine == "BLENDER_RENDER":
1544                             #pega somente primeiro material sempre
1545                             if chkMatBas:
1546                                 # cores
1547                                 a.append(copy(obj.data.materials[0].type))
1548                                 a.append(copy(obj.data.materials[0].emit))
1549                                 a.append(copy(obj.data.materials[0].diffuse_color))
1550                                 a.append(copy(obj.data.materials[0].diffuse_intensity))
1551                                 a.append(copy(obj.data.materials[0].specular_intensity))
1552                                 a.append(copy(obj.data.materials[0].specular_color))
1553                                 a.append(copy(obj.data.materials[0].alpha))
1554                                 a.append(copy(obj.data.materials[0].diffuse_shader))
1555                                 a.append(copy(obj.data.materials[0].specular_shader))
1556                                 a.append(copy(obj.data.materials[0].specular_hardness))
1557
1558                             if chkMatTransp:
1559                                 # transp
1560                                 a.append(copy(obj.data.materials[0].transparency_method))
1561                                 a.append(copy(obj.data.materials[0].specular_alpha))
1562                                 a.append(copy(obj.data.materials[0].raytrace_transparency.fresnel))
1563                                 a.append(copy(obj.data.materials[0].raytrace_transparency.ior))
1564                                 a.append(copy(obj.data.materials[0].raytrace_transparency.filter))
1565                                 a.append(copy(obj.data.materials[0].raytrace_transparency.depth))
1566                                 a.append(copy(obj.data.materials[0].translucency))
1567                                 a.append(copy(obj.data.materials[0].specular_alpha))
1568
1569                             if chkMatMirror:
1570                                 #mirror
1571                                 a.append(copy(obj.data.materials[0].raytrace_mirror.reflect_factor))
1572                                 a.append(copy(obj.data.materials[0].raytrace_mirror.fresnel))
1573                                 a.append(copy(obj.data.materials[0].raytrace_mirror.fresnel_factor))
1574                                 a.append(copy(obj.data.materials[0].mirror_color))
1575                                 a.append(copy(obj.data.materials[0].raytrace_mirror.depth))
1576                                 a.append(copy(obj.data.materials[0].raytrace_mirror.gloss_factor))
1577
1578                 # tenho todos os objetos em a[]
1579                 # incrementar um frame e checar se eh igual
1580                 bpy.context.scene.frame_set(bpy.context.scene.frame_current + 1)
1581
1582                 j=0
1583                 dif=0
1584                 for obj in bpy.data.objects:
1585                     if chkLocRotSc:
1586                         if a[j]!= obj.location or a[j+1]!= obj.rotation_euler or a[j+2]!= obj.scale:
1587                             dif=1
1588                             #break
1589                         j+=3
1590
1591                     if hasattr(obj.data, 'materials') and obj.data.materials.keys()!=[] :
1592                         if bpy.context.scene.render.engine == "BLENDER_RENDER":
1593                             if chkMatBas:
1594                                 # cores
1595                                 if a[j]!= obj.data.materials[0].type or   a[j+1]!= obj.data.materials[0].emit or \
1596                                                                             a[j+2]!= obj.data.materials[0].diffuse_color or \
1597                                                                             a[j+3]!= obj.data.materials[0].diffuse_intensity or \
1598                                                                             a[j+4]!= obj.data.materials[0].specular_intensity or \
1599                                                                             a[j+5]!= obj.data.materials[0].specular_color or \
1600                                                                             a[j+6]!= obj.data.materials[0].alpha or \
1601                                                                             a[j+7]!= obj.data.materials[0].diffuse_shader or \
1602                                                                             a[j+8]!= obj.data.materials[0].specular_shader or \
1603                                                                             a[j+9]!= obj.data.materials[0].specular_hardness:
1604                                     dif=1
1605                                     print("mat")
1606                                     j+= 10  # ajusta ponteiro j
1607                                     if chkMatTransp: j+=8
1608                                     if chkMatMirror: j+=6
1609                                     break
1610                                 j+=10
1611
1612                             if chkMatTransp:
1613                                 #transp
1614                                 if a[j]!= obj.data.materials[0].transparency_method or    a[j+1]!= obj.data.materials[0].specular_alpha or \
1615                                                                                             a[j+2]!= obj.data.materials[0].raytrace_transparency.fresnel or \
1616                                                                                             a[j+3]!= obj.data.materials[0].raytrace_transparency.ior or \
1617                                                                                             a[j+4]!= obj.data.materials[0].raytrace_transparency.filter or \
1618                                                                                             a[j+5]!= obj.data.materials[0].raytrace_transparency.depth or \
1619                                                                                             a[j+6]!= obj.data.materials[0].translucency or \
1620                                                                                             a[j+7]!= obj.data.materials[0].specular_alpha:
1621                                     dif=1
1622                                     j+= 8     # ajusta ponteiro j
1623                                     if chkMatMirror: j+=6
1624
1625                                     break
1626                                 j+=8
1627
1628                             if chkMatMirror:
1629                                 #mirror
1630                                 if a[j]!= obj.data.materials[0].raytrace_mirror.reflect_factor or a[j+1]!= obj.data.materials[0].raytrace_mirror.fresnel or \
1631                                                                                                     a[j+2]!= obj.data.materials[0].raytrace_mirror.fresnel_factor or \
1632                                                                                                     a[j+3]!= obj.data.materials[0].mirror_color or \
1633                                                                                                     a[j+4]!= obj.data.materials[0].raytrace_mirror.depth or \
1634                                                                                                     a[j+5]!= obj.data.materials[0].raytrace_mirror.gloss_factor:
1635                                     dif=1
1636                                     j+= 6     # ajusta ponteiro j
1637                                     break
1638                                 j+=6
1639                 # finaliza
1640                 if dif==0:
1641                     obc.Frames_Pular+=1
1642                 else:
1643                     obc.Frames_Renderizar+=1
1644                     ToRender.append(bpy.context.scene.frame_current)
1645
1646                 del a
1647         # para nao sair do index - nunca chega nesse frame
1648         ToRender.append(bpy.context.scene.frame_end+1)
1649
1650         if obc.RunFrom+loop < RunMax:
1651             context.scene.imp_sound_to_anim.Info_check_smartrender= "["+str(obc.RunFrom+loop) + "/" + \
1652                                         str(RunMax) + "] Frames to Render= " + str(obc.Frames_Renderizar) + \
1653                                         " -> Reduction " + str(round((obc.Frames_Pular/RunMax)*100,1)) + "%"
1654         else:
1655             context.scene.imp_sound_to_anim.Info_check_smartrender= "Frames to Render= " + str(obc.Frames_Renderizar) + \
1656                                                     " -> Reduction " + str(round((obc.Frames_Pular/RunMax)*100,1)) + "%"
1657
1658         #incrementa indice
1659         obc.RunFrom+= loop
1660         return (ToRender, obc.RunFrom)
1661
1662     def execute(self, context):
1663         context.scene.imp_sound_to_anim.Working= "CheckSmartRender"
1664         #context.scene.imp_sound_to_anim.timer_reset_func=True
1665         bpy.ops.wm.modal_timer_operator()
1666         #CheckSmartRender(context)
1667         return{'FINISHED'}
1668
1669     def invoke(self, context, event):
1670         self.execute(context)
1671         return {'FINISHED'}
1672
1673
1674 #
1675 #==================================================================================================
1676 # Button - Smart Render
1677 #==================================================================================================
1678 #
1679 class OBJECT_OT_Botao_SmartRender(bpy.types.Operator):
1680     '''Render Only Modified Frames and Copy the Others'''
1681     bl_idname = "import.sound_animation_smart_render"
1682     bl_label = "Smart Render"
1683
1684     BaseRenderToCopy=0
1685
1686     def SmartRender(context):
1687         obs=OBJECT_OT_Botao_SmartRender
1688
1689         index=0
1690         pad=4
1691         #calcula zero pad
1692         if bpy.context.scene.frame_end //1000000 > 0:  #default 999999 1000000//1000000=1
1693             pad=7
1694         elif bpy.context.scene.frame_end //100000 > 0:  #default 99999 100000//100000=1
1695             pad=6
1696         elif bpy.context.scene.frame_end //10000 > 0:  #default 9999 10000//10000=1
1697             pad=5
1698
1699         #bpy.data.images['Render Result'].file_format ='PNG'
1700         bpy.context.scene.render.image_settings.file_format = 'PNG'
1701
1702         #info dos arquivos
1703         path= bpy.context.scene.render.filepath
1704
1705         import shutil
1706
1707         tot=bpy.context.scene.frame_end - bpy.context.scene.frame_start+1
1708         i=0
1709         # checa apenas 1 frame    o indice é interno em ChackSmartRender
1710         r= OBJECT_OT_Botao_Check_SmartRender.CheckSmartRender(context, 1)
1711         ToRender= r[0] # tem numero do frame se for para renderizar
1712         index= r[1]
1713
1714         #copia frame atual  #se o frame ja não foi renderizado
1715         if (obs.BaseRenderToCopy!=(index+bpy.context.scene.frame_start-1)) and index > 1:   #index!=1 and index !=0:
1716             print("Copying: " + str(obs.BaseRenderToCopy) + "-> " + str(index+bpy.context.scene.frame_start-1) + \
1717                                 "  To " + path + str(index+bpy.context.scene.frame_start-1).zfill(pad)  + ".png")
1718             shutil.copy2(path + str(obs.BaseRenderToCopy).zfill(pad)  + ".png", path + \
1719                         str(index+bpy.context.scene.frame_start-1).zfill(pad)  + ".png")
1720
1721         if ToRender.__len__()>1:   #renderizar 1 item em ToRender nao renderiza, (sempre vem com no minimo 1)
1722             if index==1:
1723                 print("================================================================")
1724                 from time import strftime
1725                 print(strftime("Running Smart Render:  %H:%M:%S"))
1726                 print("================================================================")
1727                 BaseRenderToCopy=0
1728
1729             if ToRender[0] <= bpy.context.scene.frame_end:
1730                 #renderiza proximo frame
1731                 print("Rendering-> " + str(ToRender[0]))
1732                 obs.BaseRenderToCopy= ToRender[0]
1733                 bpy.ops.render.render(animation=False, write_still=False)
1734                 bpy.data.images['Render Result'].save_render(filepath=path + str(ToRender[0]).zfill(pad)  + ".png")
1735                 i+=1
1736
1737         if index==tot:
1738             print("================================================================")
1739             from time import strftime
1740             print(strftime("Finish Render:  %H:%M:%S"))
1741             print("================================================================")
1742             print(".")
1743
1744         if index==tot+1:
1745             obs.BaseRenderToCopy=0
1746             return 0
1747
1748         return index
1749
1750
1751     def execute(self, context):
1752         # se for CYCLES, nao funciona com timer, preciso rodar direto
1753         context.scene.imp_sound_to_anim.Working= "SmartRender"
1754         bpy.ops.wm.modal_timer_operator()
1755         #SmartRender(context)
1756         return{'FINISHED'}
1757
1758     def invoke(self, context, event):
1759         self.execute(context)
1760         return {'FINISHED'}
1761
1762
1763
1764 #
1765 #==================================================================================================
1766 # Button - Cancel
1767 #==================================================================================================
1768 #
1769 class OBJECT_OT_Botao_Cancel(bpy.types.Operator):
1770     '''Cancel Actual Operation'''
1771     bl_idname = "import.sound_animation_botao_cancel"
1772     bl_label = "CANCEL"
1773
1774     def execute(self, context):
1775         context.scene.imp_sound_to_anim.cancel_button_hit=True
1776         return{'FINISHED'}
1777
1778     def invoke(self, context, event):
1779         self.execute(context)
1780         return {'FINISHED'}
1781
1782
1783 #
1784 #==================================================================================================
1785 #     TIMER - controla a execucao das funcoes
1786 #           Responsavel por rodar em partes usando o timer e possibilitando
1787 #           o cancelamento e textos informativos
1788 #==================================================================================================
1789 #
1790 class ModalTimerOperator(bpy.types.Operator):
1791     """Internal Script Control"""
1792     bl_idname = "wm.modal_timer_operator"
1793     bl_label = "Internal Script Control"
1794
1795     _timer = None
1796     Running= False
1797
1798     def CheckRunStop(self, context, func, index):
1799         # forca update do UI
1800         bpy.context.scene.frame_set(bpy.context.scene.frame_current)
1801         if index!=0:
1802             #configura timer para a funcao
1803             context.scene.imp_sound_to_anim.Working= func
1804             self.Running=True
1805             return {'PASS_THROUGH'}
1806         else: # posso desligar o timer e modal
1807             if self._timer!= None:
1808                 context.window_manager.event_timer_remove(self._timer)
1809                 self._timer= None
1810             return {'FINISHED'}
1811
1812
1813     def modal(self, context, event):
1814         if event.type == 'ESC'and self.Running:
1815             print("-- ESC Pressed --")
1816             self.cancel(context)
1817             context.scene.imp_sound_to_anim.Working=""
1818             self.Running=False
1819             #reseta contadores
1820             context.scene.imp_sound_to_anim.timer_reset_func=True
1821             # forca update do UI
1822             bpy.context.scene.frame_set(bpy.context.scene.frame_current)
1823             return {'CANCELLED'}
1824
1825         if event.type == 'TIMER':
1826             #print("timer")
1827             #CheckSmartRender
1828             if context.scene.imp_sound_to_anim.Working== "CheckSmartRender":
1829                 self.parar(context)
1830                 #5= frames para rodar antes de voltar    [1]= indice de posicao atual
1831                 index= OBJECT_OT_Botao_Check_SmartRender.CheckSmartRender(context, 5)[1]
1832                 return self.CheckRunStop(context, "CheckSmartRender", index)
1833
1834             #SmartRender
1835             elif context.scene.imp_sound_to_anim.Working== "SmartRender":
1836                 self.parar(context)
1837                 #render/copia 1 e volta     index>=0 indice posicao atual
1838                 index= OBJECT_OT_Botao_SmartRender.SmartRender(context)
1839                 return self.CheckRunStop(context, "SmartRender", index)
1840
1841             #ProcessaSom
1842             elif context.scene.imp_sound_to_anim.Working== "ProcessaSom":
1843                 self.parar(context)
1844                 # loop = numero de frames de audio    index=0 se terminou ou >0 se não acabou
1845                 index= OBJECT_OT_Botao_Go.ProcessaSom(context, 50)
1846                 return self.CheckRunStop(context, "ProcessaSom", index)
1847
1848             #wavimport(context)
1849             elif context.scene.imp_sound_to_anim.Working== "wavimport":
1850                 self.parar(context)
1851                 # 5= numero de frames to import por timer
1852                 index=OBJECT_OT_Botao_Import.wavimport(context, 50)
1853                 return self.CheckRunStop(context, "wavimport", index)
1854
1855             #passa por aqui quando as funcoes estao sendo executadas mas
1856             #configuradas para nao entrar porque  context.scene.imp_sound_to_anim.Working== ""
1857             return {'PASS_THROUGH'}
1858
1859         # reseta e para tudo botao CANCEL pressionado
1860         if context.scene.imp_sound_to_anim.cancel_button_hit==True:
1861             context.scene.imp_sound_to_anim.Working=""
1862             #pede reset contadores
1863             context.scene.imp_sound_to_anim.timer_reset_func=True
1864             if self._timer!= None:
1865                 context.window_manager.event_timer_remove(self._timer)
1866                 self._timer= None
1867             print("-- Cancel Pressed --")
1868             context.scene.imp_sound_to_anim.cancel_button_hit=False
1869             return {'FINISHED'}
1870
1871         #print("modal")
1872
1873         # se o timer esta ativado, continua, (senao termina).
1874         # desligar a chamada ao modal se caso chegar aqui (nao deveria)
1875         if self._timer!= None:
1876             return{'PASS_THROUGH'}
1877         else:
1878             return {'FINISHED'}
1879
1880     def execute(self, context):
1881         if self._timer==None:
1882             self._timer = context.window_manager.event_timer_add(0.2, context.window)
1883             context.window_manager.modal_handler_add(self)
1884         #para deixar rodar sem deligar o timer
1885         context.scene.imp_sound_to_anim.timer_desligar=False
1886         self.Running=True
1887         return {'RUNNING_MODAL'}
1888
1889     def cancel(self, context):
1890         if self._timer!= None:
1891             context.window_manager.event_timer_remove(self._timer)
1892         self._timer= None
1893
1894     def parar(self, context):
1895         if self.Running:
1896             context.scene.imp_sound_to_anim.Working=""
1897             self.Running=False
1898
1899
1900
1901 #
1902 #==================================================================================================
1903 #     Register - Unregister - MAIN
1904 #==================================================================================================
1905 #
1906 def register():
1907     bpy.utils.register_module(__name__)
1908     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.")
1909     bpy.types.INFO_MT_file_import.append(WavFileImport)
1910
1911 def unregister():
1912
1913     try:
1914         bpy.utils.unregister_module(__name__)
1915     except:
1916         pass
1917
1918     try:
1919         bpy.types.INFO_MT_file_import.remove(WavFileImport)
1920     except:
1921         pass
1922
1923
1924
1925 if __name__ == "__main__":
1926     register()
1927
1928
1929
1930