Skip to content
Snippets Groups Projects
io_import_sound_to_anim.py 56.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • Eng vlassius santos's avatar
    Eng vlassius santos committed
    #!/usr/bin/python3
    # To change this template, choose Tools | Templates
    # and open the template in the editor.
    #  ***** GPL LICENSE BLOCK *****
    #
    #  This program is free software: you can redistribute it and/or modify
    #  it under the terms of the GNU General Public License as published by
    #  the Free Software Foundation, either version 3 of the License, or
    #  (at your option) any later version.
    #
    #  This program is distributed in the hope that it will be useful,
    #  but WITHOUT ANY WARRANTY; without even the implied warranty of
    #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #  GNU General Public License for more details.
    #
    #  You should have received a copy of the GNU General Public License
    #  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    #  All rights reserved.
    #  ***** GPL LICENSE BLOCK *****
    
    bl_info = {
        "name": "Import: Sound to Animation",
        "author": "Vlassius",
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        "version": (0, 60),
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        "blender": (2, 57, 0),
        "api": 37023,
        "location": "Select a object -> go to the Object tab ->  Import Movement From Wav File",
        "description": "Extract movement from sound file. See the Object Panel at the end.",
        "warning": "",
    
        "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Import-Export/Import_Movement_From_Audio_File",
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        "tracker_url": "http://projects.blender.org/tracker/index.php?func=detail&aid=23565&group_id=153&atid=467",
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        "category": "Import-Export"}
    
    """
    -- Extract movement from sound file, to help in animation - import script --<br> 
    
    - NOTES:
    - This script takes a wav file and get sound "movement" to help you in sync the movement to words in the wave file. <br>
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    - Supported Audio: .wav (wave) 8 bits and 16 bits <br>
    - At least Blender 2.5.7 is necessary to run this program.
    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    -v 0.60Beta- 
        Included: Option to use just the beat from the audio sound
        Included: Option to exclude the beat from the audio sound
        Included: More or less sensibility options when using the beat
        Included: Audio Channel Select option
    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    -v 0.50Beta- 
        Included: Auto Adjust Audio Sensity option    
        Included: 8 bits .wav file support
        Recalibrated: Manual audio sense 1    
        Cosmetic: Many changes in panel and terminal window info
        Corrected: Tracker_url
        Corrected: a few bytes in Memory Leaks
        work around: memory leak in function: bpy.ops.transform.rotate
        work around: memory leak in function: bpy.ops.anim.keyframe_insert
        
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    -v 0.22Beta- 
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        Included: 
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        Camera Rotation
        Empty Location-Rotation-Scale
        
    
    -v 0.21Beta- 
        Changed just the meta informations like version and wiki page.
        
    
    -v 0.20 Beta- 
        New Panel
        
        
    -v 0.1.5 Beta- 
        Change in API-> Properties
        Included the button "Get FPS from Scene" due to a problem to get it in the start 
        Return to Frame 1 after import
        Filter .wav type file (by batFINGER)
        
    -v 0.1.4 Beta- 
        If choose negative in rotation, auto check the rotation negative to Bones
        change in register()  unregister():
    
    -v 0.1.3 Beta- 
        File Cleanup
        Change to bl_info. 
        Cosmetic Changes. 
        Minor change in API in how to define buttons. 
        Adjust in otimization.
    
    -v 0.1.2 Beta
    change in API- Update function bpy.ops.anim.keyframe_insert_menu 
    
    -v 0.1.1 Beta
    change in API- Update property of  window_manager.fileselect_add
    
    -v 0.1.0 Beta
    new - Added support to LAMP object         
    new - improved flow to import
    new - check the type of object before show options
    bug - option max. and min. values
    change- Updated scene properties for changes in property API.
            See http://lists.blender.org/pipermail/bf-committers/2010-September/028654.html
    
    new flow:
              1) Process the sound file
              2) Show Button to import key frames 
    
    
    - v0.0.4 ALPHA
    new - Added destructive optimizer option - LostLestSignificativeDigit lost/total -> 10/255 default
    new - Visual Graph to samples
    new - Option to just process audio file and do not import - this is to help adjust the audio values
    new - Get and show automatically the FPS (in proper field) information taking the information from scene
    bug- Display sensitivity +1
    bug - Corrected location of the script in description
    
    - v0.0.3
    Main change: Corrected to work INSIDE dir /install/linux2/2.53/scripts/addons
    Corrected position of label "Rotation Negative"
    Added correct way to deal with paths in Python os.path.join - os.path.normpath
    
    - v0.0.2
    Corrected initial error (Register() function)
    Corrected some labels R. S. L.
    Turned off "object field" for now
    Changed target default to Z location 
    
    - v0.0.1
    Initial version
    
    
    
    Credit to:
    Vlassius
    
    - http://vlassius.com.br
    - vlassius@vlassius.com.br
    
    """
    
    import bpy
    from bpy.props import *
    #from io_utils import ImportHelper
    import wave
    
    #TODO
    #
    #   colocar CANCELAR com ESC
    #
    #
    
    
    
    #para deixar array global 
    def _Interna_Globals(BytesDadosTotProcess, context):
        global array
        
        array= bytearray(BytesDadosTotProcess)  # cria array  
        context.scene.imp_sound_to_anim.bArrayCriado=True
    
    
    def wavimport(context):
        #================================================================================================== 
        # Insert Key Frame
        #================================================================================================== 
        
    #    print("Inside Wave Import...")   
        
        iDivScala= int(context.scene.imp_sound_to_anim.action_escale)     #scala do valor do movimento. [se =1 - 0 a 255 ] [se=255 - 0,00000 a 1,00000] [se=1000 - 0 a 0.255]
    
        bNaoValorIgual=True
        if context.scene.imp_sound_to_anim.action_valor_igual: bNaoValorIgual= False    # não deixa repetir valores
        
        iStartFrame= int(context.scene.imp_sound_to_anim.frames_initial)
    
        iMaxValue= context.scene.imp_sound_to_anim.action_max_value
        iMinValue= context.scene.imp_sound_to_anim.action_min_value
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        bEscala=bRotacao=bEixo=False   
        if context.scene.imp_sound_to_anim.import_type=='imp_t_Scale':
            bEscala=True;
            
        if context.scene.imp_sound_to_anim.import_type=='imp_t_Rotation':
            bRotacao=True;
    
        if context.scene.imp_sound_to_anim.import_type=='imp_t_Location':
            bEixo=True;
    
        # atencao, nao é boolean
        iEixoXneg= iEixoYneg= iEixoZneg=1
        # atencao, nao é boolean
        iRotationNeg=1
        # atencao, nao é boolean
        iEscalaYneg= iEscalaZneg= iEscalaXneg=1
        bEixoX=bEixoY=bEixoZ=bEscalaX=bEscalaY=bEscalaZ=bRotationX=bRotationY=bRotationZ=False 
    
        # LOCAL 1
        if context.scene.imp_sound_to_anim.import_where1== 'imp_w_x':
            bEixoX=True
            bEscalaX=True
            bRotationX=True
            
        if context.scene.imp_sound_to_anim.import_where1== 'imp_w_y':
            bEixoY=True
            bEscalaY=True
            bRotationY=True
    
        if context.scene.imp_sound_to_anim.import_where1== 'imp_w_z':
            bEixoZ=True
            bEscalaZ=True
            bRotationZ=True
    
        if context.scene.imp_sound_to_anim.import_where1== 'imp_w_-x':
            bEixoX=True
            bEscalaX=True
            bRotationX=True
            iEixoXneg=-1
            iEscalaXneg=-1
            iRotationNeg=-1
    
        if context.scene.imp_sound_to_anim.import_where1== 'imp_w_-y':
            bEixoY=True
            bEscalaY=True
            bRotationY=True
            iEixoYneg=-1
            iRotationNeg=-1
            iEscalaYneg=-1
    
        if context.scene.imp_sound_to_anim.import_where1== 'imp_w_-z':
            bEixoZ=True
            bEscalaZ=True
            bRotationZ=True
            iEixoZneg=-1
            iRotationNeg=-1
            iEscalaZneg=-1
    
    
        # LOCAL 2
        if context.scene.imp_sound_to_anim.import_where2== 'imp_w_x':
            bEixoX=True
            bEscalaX=True
            bRotationX=True
            
        if context.scene.imp_sound_to_anim.import_where2== 'imp_w_y':
            bEixoY=True
            bEscalaY=True
            bRotationY=True
    
        if context.scene.imp_sound_to_anim.import_where2== 'imp_w_z':
            bEixoZ=True
            bEscalaZ=True
            bRotationZ=True
    
        if context.scene.imp_sound_to_anim.import_where2== 'imp_w_-x':
            bEixoX=True
            bEscalaX=True
            bRotationX=True
            iEixoXneg=-1
            iEscalaXneg=-1
            iRotationNeg=-1
    
        if context.scene.imp_sound_to_anim.import_where2== 'imp_w_-y':
            bEixoY=True
            bEscalaY=True
            bRotationY=True
            iEixoYneg=-1
            iRotationNeg=-1
            iEscalaYneg=-1
    
        if context.scene.imp_sound_to_anim.import_where2== 'imp_w_-z':
            bEixoZ=True
            bEscalaZ=True
            bRotationZ=True
            iEixoZneg=-1
            iRotationNeg=-1
            iEscalaZneg=-1
    
    
        # LOCAL 3
        if context.scene.imp_sound_to_anim.import_where3== 'imp_w_x':
            bEixoX=True
            bEscalaX=True
            bRotationX=True
            
        if context.scene.imp_sound_to_anim.import_where3== 'imp_w_y':
            bEixoY=True
            bEscalaY=True
            bRotationY=True
    
        if context.scene.imp_sound_to_anim.import_where3== 'imp_w_z':
            bEixoZ=True
            bEscalaZ=True
            bRotationZ=True
    
        if context.scene.imp_sound_to_anim.import_where3== 'imp_w_-x':
            bEixoX=True
            bEscalaX=True
            bRotationX=True
            iEixoXneg=-1
            iEscalaXneg=-1
            iRotationNeg=-1
    
        if context.scene.imp_sound_to_anim.import_where3== 'imp_w_-y':
            bEixoY=True
            bEscalaY=True
            bRotationY=True
            iEixoYneg=-1
            iRotationNeg=-1
            iEscalaYneg=-1
    
        if context.scene.imp_sound_to_anim.import_where3== 'imp_w_-z':
            bEixoZ=True
            bEscalaZ=True
            bRotationZ=True
            iEixoZneg=-1
            iRotationNeg=-1
            iEscalaZneg=-1
    
        iMinBaseX=iMinScaleBaseX=context.scene.imp_sound_to_anim.action_offset_x
        iMinBaseY=iMinScaleBaseY=context.scene.imp_sound_to_anim.action_offset_y
        iMinBaseZ=iMinScaleBaseZ=context.scene.imp_sound_to_anim.action_offset_z
    
        #escala inicia com 1 e não com zero
        iRotationAxisBaseX=context.scene.imp_sound_to_anim.action_offset_x  +1
        iRotationAxisBaseY=context.scene.imp_sound_to_anim.action_offset_y  +1
        iRotationAxisBaseZ=context.scene.imp_sound_to_anim.action_offset_z  +1
    
        #Added destructive optimizer option - LostLestSignificativeDigit lost/total
        iDestructiveOptimizer=context.scene.imp_sound_to_anim.optimization_destructive
    
        bLimitValue=False    #limita ou nao o valor - velocidade        
    
        if iMinValue<0: iMinValue=0
        if iMaxValue>255: iMaxValue=255
        if iMinValue>255: iMinValue=255
        if iMaxValue<0: iMaxValue=0    
        if iMinValue!= 0: bLimitValue= True
        if iMaxValue!= 255: bLimitValue= True
    
    
        print('')
        print("================================================================")   
        from time import strftime
        print(strftime("Start Import:  %H:%M:%S"))
        print("================================================================")   
        print('')
    
        ilocationXAnt=0
        ilocationYAnt=0
        ilocationZAnt=0
        iscaleXAnt=0
        iscaleYAnt=0
        iscaleZAnt=0
        iRotateValAnt=0
        iSumOptimizerP1=0
        iSumOptimizerP2=0
        iSumOptimizerP3=0
        iSumImportFrames=0
    
        # variavel global _Interna_Globals
        if context.scene.imp_sound_to_anim.bArrayCriado:
            for i in range(len(array)):
    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                #print(array[i])
                
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                ival=array[i]/iDivScala
                #valor pequeno demais, vai dar zero na hora de aplicar
                if ival < 0.001: 
                     array[i]=0
                     ival=0
                     #print ("Valor Pequeno Demais, Zerando")
                   
                # opcao de NAO colocar valores iguais sequenciais
                if i>0 and bNaoValorIgual and array[i-1]== array[i]:
                    print("Importing Blender Frame: "+str(i)+"\tof "+str(len(array)-1) + "\t(skipped by optimizer)")
                    iSumOptimizerP3+=1
                    
                else:                 
    
                    # otimizacao - não preciso mais que 2 valores iguais. pular key frame intermediario - Ex b, a, -, -, -, a
                    # tambem otimiza pelo otimizador com perda
                    if i>0 and i< len(array)-1 and abs(array[i] - array[i-1])<=iDestructiveOptimizer and abs(array[i] - array[i+1])<=iDestructiveOptimizer:# valor atual == anterior e posterior -> pula 
                            print("Importing Blender Frame: "+str(i)+"\tof "+str(len(array)-1) + "\t(skipped by optimizer)")
                            if iDestructiveOptimizer>0 and array[i] != array[i-1] or array[i] != array[i+1]: 
                                iSumOptimizerP1+=1
                                #print(array[i], iSumOptimizerP1) 
                            else: iSumOptimizerP2+=1
                    else:           
                            if bLimitValue:
                                if array[i] > iMaxValue: array[i]=iMaxValue
                                if array[i] < iMinValue: array[i]=iMinValue
    
                            ival=array[i]/iDivScala
                            #print("teste ival= " + str(ival))    ####
                            #passa para float com somente 3 digitos caso seja float
                            m_ival=ival*1000
                            if int(m_ival) != m_ival:
                                ival= int(m_ival)
                                ival = ival /1000
                                #print("Novo ival= " + str(ival))    ####
    
                            bpy.context.scene.frame_current = i+iStartFrame
    
                            if bpy.context.active_object.type=='MESH' or bpy.context.active_object.type=='CAMERA' or bpy.context.active_object.type=='EMPTY':   #precisa fazer objeto ativo
                                if bEixo:                   
                                    if bEixoX: bpy.context.active_object.location.x = ival*iEixoXneg+iMinBaseX
                                    if bEixoY: bpy.context.active_object.location.y = ival*iEixoYneg+iMinBaseY
                                    if bEixoZ: bpy.context.active_object.location.z = ival*iEixoZneg+iMinBaseZ               
                                    #print("mesh ou camera em eixo")  ####
                                
                                if bEscala:
                                    if bEscalaX: bpy.context.active_object.scale.x = ival*iEscalaXneg+iMinScaleBaseX
                                    if bEscalaY: bpy.context.active_object.scale.y = ival*iEscalaYneg+iMinScaleBaseY
                                    if bEscalaZ: bpy.context.active_object.scale.z = ival*iEscalaZneg+iMinScaleBaseZ 
    
                            # 'ARMATURE' or ('MESH' and bRotacao) or ('CAMERA' and bRotacao) or 'LAMP' or 'EMPTY' and bRotacao)
                            if bpy.context.active_object.type=='ARMATURE' or (bpy.context.active_object.type=='MESH' and bRotacao) or (bpy.context.active_object.type=='CAMERA' and bRotacao) or bpy.context.active_object.type=='LAMP' or (bpy.context.active_object.type=='EMPTY' and bRotacao):
    
                                    ###############  BONE ######################
                                    if bpy.context.active_object.type=='ARMATURE':   #precisa ser objeto ativo. Nao achei como passar para editmode
                                        if bpy.context.mode!= 'POSE':    #posemode 
                                            bpy.ops.object.posemode_toggle()
                                            #print("bone pose mode")   ####
        
                                    ###############  ALL ######################    
                                    if bEixo:
                                        if ilocationXAnt!=0 or ilocationYAnt!=0 or ilocationZAnt!=0: 
                                            bpy.ops.transform.translate(value=(ilocationXAnt*-1, ilocationYAnt*-1, ilocationZAnt*-1), constraint_axis=(bEixoX, bEixoY,bEixoZ), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, snap_normal=(0, 0, 0), release_confirm=False)  
                                        
                                        ilocationX=ilocationY=ilocationZ=0                
                                        if bEixoX: ilocationX = ival*iEixoXneg+iMinBaseX
                                        if bEixoY: ilocationY = ival*iEixoYneg+iMinBaseY
                                        if bEixoZ: ilocationZ = ival*iEixoZneg+iMinBaseZ  
                                        bpy.ops.transform.translate(value=(ilocationX, ilocationY, ilocationZ), constraint_axis=(bEixoX, bEixoY,bEixoZ), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, snap_normal=(0, 0, 0), release_confirm=False)
                                        ilocationXAnt= ilocationX
                                        ilocationYAnt= ilocationY
                                        ilocationZAnt= ilocationZ 
                
                                    if bEscala:
                                        if iscaleXAnt!=0 or iscaleYAnt!=0 or iscaleZAnt!=0:
                                            tmpscaleXAnt=0
                                            tmpscaleYAnt=0
                                            tmpscaleZAnt=0
                                            if iscaleXAnt: tmpscaleXAnt=1/iscaleXAnt
                                            if iscaleYAnt: tmpscaleYAnt=1/iscaleYAnt
                                            if iscaleZAnt: tmpscaleZAnt=1/iscaleZAnt 
                                            bpy.ops.transform.resize(value=(tmpscaleXAnt, tmpscaleYAnt, tmpscaleZAnt ), constraint_axis=(False, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, snap_normal=(0, 0, 0), release_confirm=False)  
                                        
                                        iscaleX=iscaleY=iscaleZ=0                
                                        if bEscalaX: iscaleX = ival*iEscalaXneg+iMinScaleBaseX
                                        if bEscalaY: iscaleY = ival*iEscalaYneg+iMinScaleBaseY
                                        if bEscalaZ: iscaleZ = ival*iEscalaZneg+iMinScaleBaseZ                        
                                        bpy.ops.transform.resize(value=(iscaleX, iscaleY, iscaleZ), constraint_axis=(False, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, snap_normal=(0, 0, 0), release_confirm=False)
                                        iscaleXAnt= iscaleX
                                        iscaleYAnt= iscaleY
                                        iscaleZAnt= iscaleZ                       
                                        
                                    if bRotacao:                        
                                        if iRotateValAnt!=0: 
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                                            # memory leak
                                            #bpy.ops.transform.rotate(value= (iRotateValAnt*-1), axis=(iRotationAxisBaseX, iRotationAxisBaseY, iRotationAxisBaseZ), constraint_axis=(bRotationX, bRotationY, bRotationZ), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, snap_normal=(0, 0, 0), release_confirm=False)                                                                   
                                            bpy.context.active_object.rotation_euler= ((iRotateValAnt*-1)+iRotationAxisBaseX)*bRotationX , ((iRotateValAnt*-1)+iRotationAxisBaseY)*bRotationY , ((iRotateValAnt*-1)+iRotationAxisBaseZ)*bRotationZ 
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                                        #memory leak    
                                        #bpy.ops.transform.rotate(value= (ival*iRotationNeg), axis=(iRotationAxisBaseX, iRotationAxisBaseY, iRotationAxisBaseZ), constraint_axis=(bRotationX, bRotationY, bRotationZ), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, snap_normal=(0, 0, 0), release_confirm=False)
                                        bpy.context.active_object.rotation_euler= ((ival*iRotationNeg)+ iRotationAxisBaseX)* bRotationX, ((ival*iRotationNeg)+ iRotationAxisBaseY)* bRotationY, ((ival*iRotationNeg)+ iRotationAxisBaseZ)* bRotationZ
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                                        iRotateValAnt= ival*iRotationNeg
                           
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                            ob = bpy.context.active_object
                        
                            if bEixo:
                                ob.keyframe_insert(data_path="location")                          
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                            if bRotacao:
                                ob.keyframe_insert(data_path="rotation_euler")                            
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                            if bEscala:
                                ob.keyframe_insert(data_path="scale")
                        
                        
                            #   *** Problem Memory Leak ***
                            #if bEixo and not bEscala and not bRotacao:
                            #    bpy.ops.anim.keyframe_insert(type='Location')                 
                                                            
                            #if bRotacao and not bEixo and not bEscala:
                            #    bpy.ops.anim.keyframe_insert(type='Rotation')
                                
                            #if bEscala and not bEixo and not bRotacao:
                            #   bpy.ops.anim.keyframe_insert(type='Scaling')
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                            #if bEixo and bRotacao:
                            #    bpy.ops.anim.keyframe_insert(type='LocRot')
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                            #if bEscala and bEixo:
                            #    bpy.ops.anim.keyframe_insert(type='LocScale')
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                            #if bEixo and bRotacao and bEscala:
                            #    bpy.ops.anim.keyframe_insert(type='LocRotScale')
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                            #if bEscala and bRotacao:
                            #    bpy.ops.anim.keyframe_insert(type='RotScale')
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                                         
                        
                            print("Importing Blender Frame: "+str(i)+"\tof "+str(len(array)-1) + "\tValue: "+ str(ival))
    #                        context.scene.imp_sound_to_anim.Info_Import= "Importing Frame: "+str(i)+" of "+str(len(array)-1)
    #                        bpy.context.scene.imp_sound_to_anim.update()   
    
                            iSumImportFrames+=1
                            
                    # FIm do ELSE otimizador 
                # Fim bNaoValorIgual
    
        bpy.context.scene.frame_current = 1
    
        context.scene.imp_sound_to_anim.Info_Import="Done. Imported " + str(iSumImportFrames) + " Frames" 
    #    context.scene.imp_sound_to_anim.bArrayCriado=False   # nao precisa importar novamente sem processar audio novamente
        
        print('')
        print("================================================================")
        print("Imported: " +str(iSumImportFrames) + " Key Frames")
        print("Optimizer Pass 1 prepared to optimize: " +str(iSumOptimizerP1) + " blocks of Frames")
        print("Optimizer Pass 2 has optimized: " +str(iSumOptimizerP2) + " Frames")
        print("Optimizer Pass 3 has optimized: " +str(iSumOptimizerP3) + " Frames")
        print("Optimizer has optimized: " +str(iSumOptimizerP1 + iSumOptimizerP2+iSumOptimizerP3) + " Frames")       
        print(strftime("End Import:  %H:%M:%S - by Vlassius"))
        print("================================================================")   
        print('')
       
        
    #================================================================================================== 
    # Sound Converter
    #================================================================================================== 
    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    def SoundConv(File, DivSens, Sensibil, Resol, context, bAutoSense, bRemoveBeat, bUseBeat, bMoreSensible, bLessSensible, AudioChannel):
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
        try:
            Wave_read= wave.open(File, 'rb')
        except IOError as e:
            print("File Open Error: ", e)
            return False
    
        NumCh=      Wave_read.getnchannels()
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        SampW=      Wave_read.getsampwidth() # 8, 16, 24 32 bits
        FrameR=     Wave_read.getframerate() 
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        NumFr=      Wave_read.getnframes()
        ChkCompr=   Wave_read.getcomptype()
        
        if ChkCompr != "NONE":
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            print('Sorry, this compressed Format is NOT Supported ', ChkCompr)
            context.scene.imp_sound_to_anim.Info_Import= "Sorry, this compressed Format is NOT Supported " 
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            return False
        
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        if SampW > 2:
            context.scene.imp_sound_to_anim.Info_Import= "Sorry, supported .wav files 8 and 16 bits only" 
            print('Sorry, supported .wav files 8 and 16 bits only')
            return False
    
        context.scene.imp_sound_to_anim.Info_Import=""
        
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        # controla numero do canal
        if AudioChannel > NumCh:
            print("Channel number " + str(AudioChannel) + " is selected but this audio file has just " + str(NumCh) + " channels, so selecting channel "  + str(NumCh) + "!")
            AudioChannel = NumCh
        
        tmpAudioChannel= AudioChannel # apenas para por na tela
            
        AudioChannel -= 1  #used in index sum to find the channe, adjust to first byte sample index
        
        if SampW ==2:  AudioChannel*=2   # se dois canais, AudioChannel=4 porque são 4 bytes    
        
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        # usado para achar contorno da onda - achando picos 
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        # numero de audio frames para cada video frame
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        BytesResol= int(FrameR/Resol)
        
        # com 8 bits/S - razao Sample/s por resolucao
        # tamanho do array
        BytesDadosTotProcess= NumFr // BytesResol 
    
        # inicia array
        _Interna_Globals(BytesDadosTotProcess, context)
        
        print('')
        print("================================================================")   
        from time import strftime
        print(strftime("Go!  %H:%M:%S"))
        print("================================================================")   
        print('')   
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        print('Total Audio Time: \t ' + str(NumFr//FrameR) + 's (' + str(NumFr//FrameR//60) + 'min)')
        print('Total # Interactions: \t', BytesDadosTotProcess)
        print('Total Audio Frames: \t', NumFr)
        print('Frames/s: \t\t ' + str(FrameR))
        print('# Chanels in File: \t', NumCh)
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        print('Channel to use:\t\t', tmpAudioChannel)    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        print('Bit/Sample/Chanel: \t ' + str(SampW*8))
        print('# Frames/Act: \t\t', DivSens)
        
        if bAutoSense==0:
            print('Audio Sensitivity: \t', Sensibil+1)
        else:
            print('Using Auto Audio Sentivity. This is pass 1 of 2.')
            Sensibil=0  # if auto sense, Sensibil must be zero here
            arrayAutoSense= bytearray((BytesDadosTotProcess)*2)  # cria array para AutoAudioSense         
            MaxAudio=0; # valor maximo de audio encontrado
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        print(' ')
    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    #    _array= bytearray(BytesDadosTotProcess)  # cria array
        j=0  # usado de indice
        
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        print ("Sample->[value]\tAudio Frame #   \t\t[Graph Value]")
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
        # laço total leitura bytes
        # armazena dado de pico
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        looptot= int(BytesDadosTotProcess // DivSens)    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        for jj in range(looptot):      
            
            # caso de 2 canais (esterio)
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            # uso apenas 2 bytes em 16 bits, ie, apenas canal esquerdo
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            # [0] e [1] para CH L
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            # [2] e [3] para CH R   and so on   
            # mono:1 byte to 8 bits, 2 bytes to 16 bits
            # sterio: 2 byte to 8 bits, 4 bytes to 16 bits
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            ValorPico=0
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            for i in range(BytesResol):    # leio o numero de frames de audio para cada frame de video, valor em torno de 1000
                frame = Wave_read.readframes(DivSens) #loop exterior copia DivSens frames a cada frame calculado
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                if len(frame)==0: break
    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                if bAutoSense==0:    # AutoAudioSense Desligado
                    if SampW ==1:
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                        if Sensibil ==5:
                            frame0= frame[AudioChannel] << 6 & 255
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                        elif Sensibil ==4:
                            frame0= frame[AudioChannel] << 5 & 255
                            
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                        elif Sensibil ==3:
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                            frame0= frame[AudioChannel] << 4 & 255
                            
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                        elif Sensibil ==2:
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                            frame0= frame[AudioChannel] << 3 & 255
                            
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                        elif Sensibil ==1:
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                            frame0= frame[AudioChannel] << 2 & 255
                            
                        elif Sensibil ==0:
                            frame0= frame[AudioChannel]
    
                        if frame0> ValorPico: 
                            ValorPico= frame0    
    
                    if SampW ==2:                # frame[0] baixa       frame[1] ALTA BIT 1 TEM SINAL!
                        if Sensibil ==5:
                            frame0=frame[AudioChannel]                    
                        
                        elif frame[1+AudioChannel] <127:    # se bit1 =0, usa o valor - se bit1=1 quer dizer numero negativo
                            if Sensibil ==0:
                                frame0= frame[1+AudioChannel]
    
                            elif Sensibil ==4:
                                frame0= ((frame[AudioChannel] & 0b11111100) >> 2) | ((frame[1+AudioChannel] & 0b00000011) << 6)                        
    
                            elif Sensibil ==3:
                                frame0= ((frame[AudioChannel] & 0b11110000) >> 4) | ((frame[1+AudioChannel] & 0b00001111) << 4)                        
    
                            elif Sensibil ==2:
                                frame0= ((frame[AudioChannel] & 0b11100000) >> 5) | ((frame[1+AudioChannel] & 0b00011111) << 3)                        
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                            elif Sensibil ==1:
                                frame0= ((frame[AudioChannel] & 0b11000000) >> 6) | ((frame[1+AudioChannel] & 0b00111111) << 2)                        
    
                        if frame0 > ValorPico: 
                            ValorPico= frame0
                        
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
                else:   # AutoAudioSense Ligado
                    if SampW ==1:
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                        if frame[AudioChannel]> MaxAudio:                   
                            MaxAudio = frame[AudioChannel] 
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                        if frame[AudioChannel]> ValorPico: 
                            ValorPico=frame[AudioChannel]
                    
                        #print("0-> " + str(frame[0]) + "  1-> " + str(frame[1]))
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    
                    if SampW ==2:   
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                        if frame[1+AudioChannel] < 127:
                            tmpValorPico= frame[1+AudioChannel] << 8
                            tmpValorPico+=  frame[AudioChannel]
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                            
                            if tmpValorPico > MaxAudio:
                                MaxAudio = tmpValorPico 
                                
                            if tmpValorPico > ValorPico:
                                ValorPico= tmpValorPico
                    
    
            if bAutoSense==0:    #autoaudiosense desligado
                # repito o valor de frames por actions (OTIMIZAR)
                for ii in range(DivSens):           
                    array[j]=ValorPico  # valor de pico encontrado
                    j +=1           # incrementa indice prox local
            else:
                
                arrayAutoSense[j]= (ValorPico & 0b0000000011111111) #copia valores baixos
                arrayAutoSense[j+1]= (ValorPico & 0b1111111100000000) >> 8   #copia valores altos
                j+=2
                
                #print("baixo=" + str(arrayAutoSense[j-2]) + "  alto= " + str(arrayAutoSense[j-1]))
    
            if bAutoSense==0:    #autoaudiosense desligado
                igraph= ValorPico//10
            else:
                if SampW ==2:
                    igraph= ValorPico//1261
                
                else:
                    igraph= ValorPico//10    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            
            stgraph="["        
            for iii in range(igraph): 
                stgraph+="+" 
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            for iiii in range(26-igraph): 
                stgraph+=" " 
            stgraph+="]"
            
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            print ("Sample-> " + str(ValorPico) + "\tAudio Frame #  " + str(jj) + " of " + str(looptot-1) + "\t"+ stgraph)
                            
            #print (str(MaxAudio))
    
    
        if bAutoSense==1:
            print(".")   
            print("================================================================")           
            print('Calculating Auto Audio Sentivity, pass 2 of 2.')
            print("================================================================")           
            
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            # caso usar batida, procurar por valores próximos do maximo e zerar restante.
            # caso retirar batida, zerar valores próximos do maximo
            
            UseMinim=0
            UseMax=0
       
            if bUseBeat==1:
                print("Trying to use just the beat.")           
                UseMinim= MaxAudio*0.8
                if bMoreSensible:            
                    UseMinim= MaxAudio*0.7
                elif bLessSensible:            
                    UseMinim= MaxAudio*0.9
                        
            if bRemoveBeat==1:
                print("Trying to exclude the beat.")           
                UseMax= MaxAudio*0.7            
                if bMoreSensible:            
                    UseMax= MaxAudio*0.8
                elif bLessSensible:            
                    UseMax= MaxAudio*0.7
           
            print(".")
    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            # para transformar 15 bits em 8 calibrando valor maximo -> fazer regra de 3
            # MaxAudio -> 255
            # outros valores => valor calibrado= (255 * Valor) / MaxAudio    
    
            # passar do arrayAutoSense[] para array[]
            # reimprimir grafico 
    
            scale= 255/MaxAudio
            
            j=0
            jj=0
            print ("Sample->[value]\tAudio Frame #    \t\t[Graph Value]")    
            
            for i in range(BytesDadosTotProcess // DivSens): 
                
                ValorOriginal= arrayAutoSense[j+1] << 8
                ValorOriginal+= arrayAutoSense[j]
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                                     
                if bUseBeat==1:
                    if ValorOriginal < UseMinim:
                        ValorOriginal = 0
                    
                elif bRemoveBeat==1:
                    if ValorOriginal > UseMax:
                        ValorOriginal = 0 
                          
                ValorOriginal= ((round(ValorOriginal * scale)) & 0b11111111)    #aplica a escala
    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                for ii in range(DivSens):
                    array[jj] = ValorOriginal
                    jj += 1   # se autoaudiosense, o array tem dois bytes para cada valor
    
                j+=2            
                #print(" baixo=" + str(arrayAutoSense[j-2]) + "  alto= " + str(arrayAutoSense[j-1]) + " junto= " + str(ValorOriginal) + " array= " + str(array[jj-1]))            
                
                igraph= round(array[jj-1]/10)
                
                stgraph="["        
                for iii in range(igraph): 
                    stgraph+="+" 
               
                for iiii in range(26-igraph): 
                    stgraph+=" " 
                stgraph+="]"
                print ("Sample-> " + str(array[jj-1]) + "\tAudio Frame #  " + str(i) + " of " + str(looptot-1) + "\t"+ stgraph)    
                
            #limpa array tmp
            del arrayAutoSense[:]
    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    # fim
    #    print(_array)
        context.scene.imp_sound_to_anim.Info_Import= "Click \"Import Key frames\" to begin import" #this set the initial text
    
        print("================================================================")   
        print(strftime("End Process:  %H:%M:%S"))
        print("================================================================")   
    
        try:
            Wave_read.close()
        except:
            print('File Close Error')
            
        return
    
    #
    #
    #================================================================================================== 
    #================================================================================================== 
    #================================================================================================== 
    #
    #
    # BLENDER Configuration - Blender Beta
    #
    #
    #================================================================================================== 
    #================================================================================================== 
    #================================================================================================== 
    #    
    #
    
    class VIEW3D_PT_CustomMenuPanel(bpy.types.Panel):
        bl_space_type = "PROPERTIES"
        bl_region_type = "WINDOW"
        bl_context = "object"
        bl_label = "Import Movement From Wav File"
        bl_options = {'DEFAULT_CLOSED'}   
    
        def draw(self, context):
            layout = self.layout
    
            b=bpy.context.active_object.type=='EMPTY' or bpy.context.active_object.type=='ARMATURE' or bpy.context.active_object.type=='MESH' or bpy.context.active_object.type=='CAMERA' or bpy.context.active_object.type=='LAMP' 
            if not b:
                row=layout.row()
                row.label(text="The Selected Object is: type \"" + bpy.context.active_object.type + "\", and it is not supported.") 
                row=layout.row()
                row.label(text="Supported Object are Type: Armature, Mesh, Camera and Lamp") 
                row=layout.row()
            else:
    
                #print(context.scene.imp_sound_to_anim.bTypeImport)
        
                if context.scene.imp_sound_to_anim.bTypeImport == 0:
                    #To use Direct 
                    #mount panel to Direct animation 
                    row=layout.row()
                    layout.operator("import.sound_animation_botao_udirect")           
    
    
                #-----------------------------
                #Direct Animation
                #-----------------------------
                if context.scene.imp_sound_to_anim.bTypeImport == 1:
                    row=layout.row()
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row.label(text="With Object Selected,") 
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row=layout.row()
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row.label(text="1)Click button \"Process Wav\",")
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row=layout.row()
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row.label(text="(Check the Terminal Window)")
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row=layout.row()
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row.label(text="2)Click Button \"Import Key Frames\",")
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row=layout.row()        
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row.label(text="Run the animation (alt A) and Enjoy!")        
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row=layout.row()
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row.prop(context.scene.imp_sound_to_anim,"action_auto_audio_sense")
                    row=layout.row()        
                    if context.scene.imp_sound_to_anim.action_auto_audio_sense == 0:   # se auto audio sense desligado
                        row.prop(context.scene.imp_sound_to_anim,"audio_sense")
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                        row=layout.row()  
                    
                    else: #somente se autosense ligado
                        if context.scene.imp_sound_to_anim.remove_beat == 0 :   
                            row.prop(context.scene.imp_sound_to_anim,"use_just_beat")
                        
                        if context.scene.imp_sound_to_anim.use_just_beat == 0:    
                            row.prop(context.scene.imp_sound_to_anim,"remove_beat")
                     
                        if context.scene.imp_sound_to_anim.use_just_beat or context.scene.imp_sound_to_anim.remove_beat:
                            if not context.scene.imp_sound_to_anim.beat_less_sensible and not context.scene.imp_sound_to_anim.beat_more_sensible:                  
                                row=layout.row()
                            if context.scene.imp_sound_to_anim.beat_less_sensible ==0:
                                row.prop(context.scene.imp_sound_to_anim,"beat_more_sensible")
                                
                            if context.scene.imp_sound_to_anim.beat_more_sensible ==0:
                                row.prop(context.scene.imp_sound_to_anim,"beat_less_sensible")                  
                        
                    row=layout.row()                          
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row.prop(context.scene.imp_sound_to_anim,"action_per_second")
                    row=layout.row()
                    row.prop(context.scene.imp_sound_to_anim,"action_escale")
        
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    #row=layout.row()
                    row.label(text="Result from 0 to " + str(   round(255/context.scene.imp_sound_to_anim.action_escale,4)  ) + "")
                    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row=layout.row()
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row.label(text="Property to Change:")
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row.prop(context.scene.imp_sound_to_anim,"import_type")
    
                    #coluna
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row=layout.row()
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row.prop(context.scene.imp_sound_to_anim,"import_where1")
                    row.prop(context.scene.imp_sound_to_anim,"import_where2")
                    row.prop(context.scene.imp_sound_to_anim,"import_where3")
    
                    row=layout.row()   
                    row.label(text='Optional Configurations:')
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row=layout.row()   
                    
                    row.prop(context.scene.imp_sound_to_anim,"frames_per_second")
                    row=layout.row()     
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    #coluna
                    column= layout.column()
                    split=column.split(percentage=0.5)
                    col=split.column()
    
                    row=col.row()
                    row.prop(context.scene.imp_sound_to_anim,"frames_initial")
                    
                    row=col.row()
                    row.prop(context.scene.imp_sound_to_anim,"action_min_value")
    
                    col=split.column()          
    
                    row=col.row()
                    row.prop(context.scene.imp_sound_to_anim,"optimization_destructive")               
    
                    row=col.row()
                    row.prop(context.scene.imp_sound_to_anim,"action_max_value")
                    
                    row=layout.row()
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row.prop(context.scene.imp_sound_to_anim,"action_offset_x")
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row.prop(context.scene.imp_sound_to_anim,"action_offset_y")
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row.prop(context.scene.imp_sound_to_anim,"action_offset_z")
                    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row=layout.row()                
                    row.prop(context.scene.imp_sound_to_anim,"audio_channel_select") 
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row.prop(context.scene.imp_sound_to_anim,"action_valor_igual")        
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    
                    #operator button
                    #OBJECT_OT_Botao_Go => Botao_GO
                    row=layout.row()
                    layout.operator(OBJECT_OT_Botao_Go.bl_idname)
        
                    row=layout.row()
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    row.label(text=context.scene.imp_sound_to_anim.Info_Import)
                    if context.scene.imp_sound_to_anim.bArrayCriado:                              
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                        layout.operator(OBJECT_OT_Botao_Import.bl_idname)
                        row=layout.row()
        
    
    
        
                #-----------------------------
                #Use Driver
                #-----------------------------            
                if context.scene.imp_sound_to_anim.bTypeImport == 2:            
    
                    row=layout.row()        
                    row.prop(context.scene.imp_sound_to_anim,"audio_sense")
                    row=layout.row()
                    row.prop(context.scene.imp_sound_to_anim,"frames_per_second")
                    row=layout.row()     
                    row.prop(context.scene.imp_sound_to_anim,"action_per_second")
    
                    row=layout.row()
                    layout.operator(ImportWavFile.bl_idname)
                
    
    
    
    class ImpSoundtoAnim(bpy.types.PropertyGroup):
        
                        
            bArrayCriado = IntProperty(name="", 
                description="Avisa que rodou process de som",
                default=0)
     
            #Nome do objeto
            Info_Import = StringProperty(name="",