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