#!/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",
    "version": (0, 70),
    "blender": (2, 64, 0),
    "location": "Select a object > 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",
    "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
    "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>
- Supported Audio: .wav (wave) 8 bits and 16 bits - mono and multichanel file<br>
- At least Blender 2.64.9 is necessary to run this program.
- Curitiba - Brasil


-v 0.70Beta-
    Included: SmartRender - Render just the frames that has changes
    Included: Options to check SmartRender for Blender Internal Render Engine:LocRotScale, Material, Transp, Mirror
    Included: User can Cancel all functions with CANCEL button- Extensive Code and flux change (bugs expected)
    Included: User can Cancel all functions with ESC
    Inclused: User friendly messages into UI while running (its no more necessary to look at terminal window to most users)
    Cleanup:  Non Stardard Chars in coments
    To Do:    Decrease overhead of timer loops
    To Do:    Try to implement Smart Render for Cycles

-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

-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

-v 0.22Beta-
    Included:
    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
- Curitiba - Brasil

"""

import bpy
from bpy.props import *
#from io_utils import ImportHelper
import wave

#para deixar global
def _Interna_Globals(BytesDadosTotProcess, context):
    global array
    global arrayAutoSense

    array= bytearray(BytesDadosTotProcess)  # cria array
    arrayAutoSense= bytearray((BytesDadosTotProcess)*2)  # cria array para AutoAudioSense
    context.scene.imp_sound_to_anim.bArrayCriado=True

#
#==================================================================================================
# BLENDER UI Panel
#==================================================================================================
#
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:
                #mount panel to Direct animation
                row=layout.row()
                layout.operator("import.sound_animation_botao_udirect")

            # monta as telas quando está rodando
            elif context.scene.imp_sound_to_anim.Working!="":   #its running
                row=layout.row()
                row=layout.row()

                if context.scene.imp_sound_to_anim.Working== "CheckSmartRender":
                    #context.scene.imp_sound_to_anim.Info_check_smartrender=
                    row=layout.row()
                    row.label(text="Checking for Smart Render...")
                    row=layout.row()
                    row.label(text=context.scene.imp_sound_to_anim.Info_check_smartrender)
                    row=layout.row()

                elif context.scene.imp_sound_to_anim.Working== "SmartRender":
                    #context.scene.imp_sound_to_anim.Info_check_smartrender=
                    row=layout.row()
                    row.label(text="Processing Smart Render...")
                    row=layout.row()
                    row.label(text=context.scene.imp_sound_to_anim.Info_check_smartrender)
                    row=layout.row()

                elif context.scene.imp_sound_to_anim.Working== "ProcessaSom":
                    #context.scene.imp_sound_to_anim.Info_Import=
                    row=layout.row()
                    row.label(text="Processing Sound File...")
                    row=layout.row()
                    row.label(text=context.scene.imp_sound_to_anim.Info_Import)

                elif context.scene.imp_sound_to_anim.Working== "wavimport":
                    #context.scene.imp_sound_to_anim.Info_Import=
                    row=layout.row()
                    row.label(text="Importing Keys...")
                    row=layout.row()
                    row.label(text=context.scene.imp_sound_to_anim.Info_Import)
                    row=layout.row()

                # botao cancel
                layout.operator(OBJECT_OT_Botao_Cancel.bl_idname)
                row=layout.row()

            elif context.scene.imp_sound_to_anim.bTypeImport == 1:
                row=layout.row()
                row.label(text="1)Click button \"Process Wav\",")
                row=layout.row()
                row.label(text="2)Click Button \"Import Key Frames\",")
                row=layout.row()
                row.label(text="Run the animation (alt A) and Enjoy!")
                row=layout.row()
                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")
                    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()
                row.prop(context.scene.imp_sound_to_anim,"action_per_second")
                row=layout.row()
                row.prop(context.scene.imp_sound_to_anim,"action_escale")

                #row=layout.row()
                row.label(text="Result from 0 to " + str(round(255/context.scene.imp_sound_to_anim.action_escale,4)) + "")

                row=layout.row()
                row.label(text="Property to Change:")
                row.prop(context.scene.imp_sound_to_anim,"import_type")

                #coluna
                row=layout.row()
                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:')
                row=layout.row()

                row.prop(context.scene.imp_sound_to_anim,"frames_per_second")
                row=layout.row()
                #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()

                row.prop(context.scene.imp_sound_to_anim,"action_offset_x")
                row.prop(context.scene.imp_sound_to_anim,"action_offset_y")
                row.prop(context.scene.imp_sound_to_anim,"action_offset_z")

                row=layout.row()
                row.prop(context.scene.imp_sound_to_anim,"audio_channel_select")
                row.prop(context.scene.imp_sound_to_anim,"action_valor_igual")

                #operator button
                #OBJECT_OT_Botao_Go => Botao_GO
                row=layout.row()
                layout.operator(OBJECT_OT_Botao_Go.bl_idname)

                row=layout.row()
                row.label(text=context.scene.imp_sound_to_anim.Info_Import)

                # preciso garantir a existencia do array porque o Blender salva no arquivo como existente sem o array existir
                try:
                    array
                except NameError:
                    nada=0 #dummy
                else:
                    if context.scene.imp_sound_to_anim.bArrayCriado:
                        layout.operator(OBJECT_OT_Botao_Import.bl_idname)
                        row=layout.row()

                #Layout SmartRender, somente para Blender_render
                if bpy.context.scene.render.engine == "BLENDER_RENDER":
                    row=layout.row()
                    row.label(text="----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------")
                    row=layout.row()
                    if context.scene.imp_sound_to_anim.Info_check_smartrender!= "":
                        row=layout.row()
                        row.label(text=context.scene.imp_sound_to_anim.Info_check_smartrender)

                    row=layout.row()
                    row.operator(OBJECT_OT_Botao_Check_SmartRender.bl_idname)
                    if context.scene.imp_sound_to_anim.Info_check_smartrender!= "":
                        row.operator(OBJECT_OT_Botao_SmartRender.bl_idname)

                    row=layout.row()
                    row.prop(context.scene.imp_sound_to_anim,"check_smartrender_loc_rot_sc")
                    row.prop(context.scene.imp_sound_to_anim,"check_smartrender_material_basic")
                    row=layout.row()
                    row.prop(context.scene.imp_sound_to_anim,"check_smartrender_material_transparence")
                    row.prop(context.scene.imp_sound_to_anim,"check_smartrender_material_mirror")

            #-----------------------------
            #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)


#
#==================================================================================================
# BLENDER UI PropertyGroup
#==================================================================================================
#
class ImpSoundtoAnim(bpy.types.PropertyGroup):

        #Array created
        bArrayCriado = IntProperty(name="",
            description="Avisa que rodou process de som",
            default=0)

        #Script Running
        Working = StringProperty(name="",
            description="Script esta trabalhando",
            maxlen= 1024,
            default="")

        #Nome do objeto
        Info_Import = StringProperty(name="",
            description="Info about Import",
            maxlen= 1024,
            default= "")#this set the initial text

        #Mensagem Smart Render
        Info_check_smartrender = StringProperty(name="",
            description="Smart Render Message",
            maxlen= 1024,
            default= "")#this set the initial text

        #iAudioSensib=0    #sensibilidade volume do audio 0 a 5. Quanto maior, mais sensibilidade
        audio_sense = IntProperty(name="Audio Sens",
            description="Audio Sensibility.",
            min=1,
            max=6,
            step=1,
            default= 1)

        #iFramesPorSeg=15  #Frames por segundo para key frame
        #fps= (bpy.types.Scene) bpy.context.scene.render.fps
        frames_per_second = IntProperty(name="#Frames/s",
            description="Frames you want per second. Better match your set up in Blender scene.",
            min=1,
            max=120,
            step=1)

        #iMovPorSeg=1      #Sensibilidade de movimento. 3= 3 movimentos por segundo
        action_per_second = IntProperty(name="Act/s",
            description="Actions per second. From 1 to #Frames/s",
            min=1,
            max=120,
            step=1,
            default= 4)#this set the initial text

        #iDivScala=200
        #scala do valor do movimento. [se =1 - 0 a 255 ] [se=255 - 0,00000 a 1,00000] [se=1000 - 0 a 0.255]
        action_escale = IntProperty(name="Scale",
            description="Scale the result values. See the text at right side of the field",
            min=1,
            max=99999,
            step=100,
            default= 100)#this set the initial text

        #iMaxValue=255
        action_max_value = IntProperty(name="Clip Max",
            description="Set the max value (clip higher values).",
            min=1,
            max=255,
            step=1,
            default= 255)#this set the initial text

        #iMinValue=0
        action_min_value = IntProperty(name="Clip Min",
            description="Set the min value. (clip lower values)",
            min=0,
            max=255,
            step=1,
            default= 0)#this set the initial text

        #iStartFrame=0#
        frames_initial = IntProperty(name="Frame Ini",
            description="Where to start to put the computed values.",
            min=0,
            max=999999999,
            step=1,
            default= 0)

        audio_channel_select = IntProperty(name="Audio Channel",
            description="Choose the audio channel to use",
            min=1,
            max=10,
            step=1,
            default= 1)

        action_offset_x = FloatProperty(name="XOffset",
            description="Offset X Values",
            min=-999999,
            max=999999,
            step=1,
            default= 0)

        action_offset_y = FloatProperty(name="YOffset",
            description="Offset Y Values",
            min=-999999,
            max=999999,
            step=1,
            default= 0)

        action_offset_z = FloatProperty(name="ZOffset",
            description="Offset Z Values",
            min=-999999,
            max=999999,
            step=1,
            default= 0)

        import_type= EnumProperty(items=(('imp_t_Scale', "Scale", "Apply to Scale"),
                                         ('imp_t_Rotation', "Rotation", "Apply to Rotation"),
                                         ('imp_t_Location', "Location", "Apply to Location")
                                        ),
                                 name="",
                                 description= "Property to Import Values",
                                 default='imp_t_Location')

        import_where1= EnumProperty(items=(('imp_w_-z', "-z", "Apply to -z"),
                                          ('imp_w_-y', "-y", "Apply to -y"),
                                          ('imp_w_-x', "-x", "Apply to -x"),
                                          ('imp_w_z', "z", "Apply to z"),
                                          ('imp_w_y', "y", "Apply to y"),
                                          ('imp_w_x', "x", "Apply to x")
                                        ),
                                 name="",
                                 description= "Where to Import",
                                 default='imp_w_z')

        import_where2= EnumProperty(items=(('imp_w_none', "None", ""),
                                          ('imp_w_-z', "-z", "Apply to -z"),
                                          ('imp_w_-y', "-y", "Apply to -y"),
                                          ('imp_w_-x', "-x", "Apply to -x"),
                                          ('imp_w_z', "z", "Apply to z"),
                                          ('imp_w_y', "y", "Apply to y"),
                                          ('imp_w_x', "x", "Apply to x")
                                        ),
                                 name="",
                                 description= "Where to Import",
                                 default='imp_w_none')

        import_where3= EnumProperty(items=(('imp_w_none', "None", ""),
                                          ('imp_w_-z', "-z", "Apply to -z"),
                                          ('imp_w_-y', "-y", "Apply to -y"),
                                          ('imp_w_-x', "-x", "Apply to -x"),
                                          ('imp_w_z', "z", "Apply to z"),
                                          ('imp_w_y', "y", "Apply to y"),
                                          ('imp_w_x', "x", "Apply to x")
                                        ),
                                 name="",
                                 description= "Where to Import",
                                 default='imp_w_none')


        #========== Propriedades boolean  =============#

        #  INVERTIDO!!!  bNaoValorIgual=True    # nao deixa repetir valores     INVERTIDO!!!
        action_valor_igual = BoolProperty(name="Hard Transition",
            description="Use to movements like a mouth, to a arm movement, maybe you will not use this.",
            default=1)

        action_auto_audio_sense = BoolProperty(name="Auto Audio Sensitivity",
            description="Try to discover best audio scale. ",
            default=1)

        use_just_beat=BoolProperty(name="Just Use The Beat",
            description="Try to use just the beat to extract movement.",
            default=0)

        remove_beat=BoolProperty(name="Remove The Beat",
            description="Try to remove the beat to extract movement.",
            default=0)

        beat_more_sensible=BoolProperty(name="More Sensible",
            description="Try To be more sensible about the beat.",
            default=0)

        beat_less_sensible=BoolProperty(name="Less Sensible",
            description="Try to be less sensible about the beat.",
            default=0)

        check_smartrender_loc_rot_sc=BoolProperty(name="Loc Rot Scale",
            description="Find changes in Location, Rotation and Scale Frame by Frame.",
            default=1)

        check_smartrender_material_basic=BoolProperty(name="Basic Material",
            description="Find changes in basic material settings Frame by Frame.",
            default=1)

        check_smartrender_material_transparence=BoolProperty(name="Material Transparence",
            description="Find changes in material transparence settings Frame by Frame.",
            default=0)

        check_smartrender_material_mirror=BoolProperty(name="Material Mirror",
            description="Find changes in material mirror settings Frame by Frame.",
            default=0)

        timer_reset_func=BoolProperty(name="Reset Counters",
            description="Reset Counters after stop",
            default=0)

        cancel_button_hit=BoolProperty(name="Cancel Hit",
            description="Cancel Hit",
            default=0)

        #  Optimization
        optimization_destructive = IntProperty(name="Optimization",
            description="Hi value = Hi optimization -> Hi loss of information.",
            min=0,
            max=254,
            step=10,
            default= 10)

        # import as driver or direct   NOT IN USE!!
        # not defined
        # Direct=1
        # Driver=2
        bTypeImport = IntProperty(name="",
            description="Import Direct or Driver",
            default=0)

        # globais do dialog open wave
        filter_glob = StringProperty(default="*.wav", options={'HIDDEN'})
        path =        StringProperty(name="File Path", description="Filepath used for importing the WAV file", \
                                                                                        maxlen= 1024, default= "")
        filename =    StringProperty(name="File Name", description="Name of the file")
        directory =   StringProperty(name="Directory", description="Directory of the file")

from bpy.props import *

def WavFileImport(self, context):
    self.layout.operator(ImportWavFile.bl_idname, text="Import a wav file", icon='PLUGIN')


#
#==================================================================================================
# Use Direct
#==================================================================================================
#
class OBJECT_OT_Botao_uDirect(bpy.types.Operator):
    '''Import as Direct Animation'''
    bl_idname = "import.sound_animation_botao_udirect"
    bl_label = "Direct to a Property"

    def execute(self, context):
        context.scene.imp_sound_to_anim.bTypeImport= 1
        if context.scene.imp_sound_to_anim.frames_per_second == 0:
             context.scene.imp_sound_to_anim.frames_per_second= bpy.context.scene.render.fps
        return{'FINISHED'}

    def invoke(self, context, event):
        self.execute(context)
        return {'FINISHED'}

#
#==================================================================================================
# Button - Import
#==================================================================================================
#
class OBJECT_OT_Botao_Import(bpy.types.Operator):
    '''Import Key Frames to Blender'''
    bl_idname = "import.sound_animation_botao_import"
    bl_label = "Import Key Frames"

    RunFrom=0
    iSumImportFrames=0
    iSumOptimizerP1=0
    iSumOptimizerP2=0
    iSumOptimizerP3=0

    def wavimport(context, loop):
        obi=OBJECT_OT_Botao_Import

        # para de entrar no timer
        context.scene.imp_sound_to_anim.Working=""
        #reseta contadores caso seja pedido
        if context.scene.imp_sound_to_anim.timer_reset_func:
            obi.RunFrom=0
            obi.iSumOptimizerP1=0
            obi.iSumOptimizerP2=0
            obi.iSumOptimizerP3=0
            obi.iSumImportFrames=0
            context.scene.imp_sound_to_anim.timer_reset_func=False

        #limita o loop se estiver no fim
        tot=len(array)-1
        if obi.RunFrom+loop > tot:
            loop= tot - obi.RunFrom

        #scala do valor do movimento. [se =1 - 0 a 255 ] [se=255 - 0,00000 a 1,00000] [se=1000 - 0 a 0.255]
        iDivScala= int(context.scene.imp_sound_to_anim.action_escale)

        # nao deixa repetir valores
        bNaoValorIgual=True
        if context.scene.imp_sound_to_anim.action_valor_igual: bNaoValorIgual= False

        # inicia no inicio pedido pelo usuario mais ponteiro RunFrom
        iStartFrame= int(context.scene.imp_sound_to_anim.frames_initial) + obi.RunFrom

        iMaxValue= context.scene.imp_sound_to_anim.action_max_value
        iMinValue= context.scene.imp_sound_to_anim.action_min_value

        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 eh boolean
        iEixoXneg= iEixoYneg= iEixoZneg=1
        # atencao, nao eh boolean
        iRotationNeg=1
        # atencao, nao eh 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 nao 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

        #limita ou nao o valor - velocidade
        bLimitValue=False

        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

        if obi.RunFrom==0:
            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

        # variavel global _Interna_Globals
        if context.scene.imp_sound_to_anim.bArrayCriado:
            for i in range(loop):
                ival=array[i+obi.RunFrom]/iDivScala
                #valor pequeno demais, vai dar zero na hora de aplicar
                if ival < 0.001:
                     array[i+obi.RunFrom]=0
                     ival=0

                # to increase performance and legibility
                arrayI= array[i+obi.RunFrom]
                arrayIP1= array[i+1+obi.RunFrom]
                arrayIL1= array[i-1+obi.RunFrom]

                # opcao de NAO colocar valores iguais sequenciais
                if i>0 and bNaoValorIgual and arrayIL1== arrayI:
                    print("Importing Blender Frame: "+str(i+obi.RunFrom+1)+"\tof "+str(len(array)-1) + \
                                                                            "\t(skipped by optimizer)")
                    obi.iSumOptimizerP3+=1
                else:
                    # otimizacao - nao preciso mais que 2 valores iguais.
                    # pular key frame intermediario - Ex b, a, -, -, -, a
                    # tambem otimiza pelo otimizador com perda
                    # valor atual == anterior e posterior -> pula
                    if i>0 and i< len(array)-1 and abs(arrayI - arrayIL1)<=iDestructiveOptimizer and \
                                                        abs(arrayI - arrayIP1)<=iDestructiveOptimizer:
                            print("Importing Blender Frame: "+str(i+obi.RunFrom+1)+"\tof "+str(len(array)-1) + \
                                                                                    "\t(skipped by optimizer)")
                            if iDestructiveOptimizer>0 and arrayI != arrayIL1 or arrayI != arrayIP1:
                                obi.iSumOptimizerP1+=1
                            else: obi.iSumOptimizerP2+=1
                    else:
                            if bLimitValue:
                                if arrayI > iMaxValue: array[i+obi.RunFrom]=iMaxValue
                                if arrayI < iMinValue: array[i+obi.RunFrom]=iMinValue

                            ival=array[i+obi.RunFrom]/iDivScala
                            #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

                            bpy.context.scene.frame_current = i+iStartFrame

                            #precisa fazer objeto ativo
                            if bpy.context.active_object.type=='MESH' or bpy.context.active_object.type=='CAMERA' or \
                                                                            bpy.context.active_object.type=='EMPTY':
                                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

                                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()

                                    #============= 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:
                                            bpy.context.active_object.rotation_euler= ((iRotateValAnt*-1)+    iRotationAxisBaseX) *bRotationX , \
                                                                                        ((iRotateValAnt*-1)+  iRotationAxisBaseY) *bRotationY , \
                                                                                        ((iRotateValAnt*-1)+  iRotationAxisBaseZ) *bRotationZ

                                        bpy.context.active_object.rotation_euler= ((ival*iRotationNeg)+   iRotationAxisBaseX) * bRotationX, \
                                                                                    ((ival*iRotationNeg)+ iRotationAxisBaseY)  * bRotationY, \
                                                                                    ((ival*iRotationNeg)+ iRotationAxisBaseZ)  * bRotationZ
                                        iRotateValAnt= ival*iRotationNeg

                            ob = bpy.context.active_object

                            if bEixo:
                                ob.keyframe_insert(data_path="location")

                            if bRotacao:
                                ob.keyframe_insert(data_path="rotation_euler")

                            if bEscala:
                                ob.keyframe_insert(data_path="scale")

                            print("Importing Blender Frame: "+str(i+obi.RunFrom+1)+"\tof "+str(len(array)-1) + "\tValue: "+ str(ival))

                            obi.iSumImportFrames+=1
                    # Fim do ELSE otimizador
                # Fim bNaoValorIgual

            if obi.RunFrom>= tot:
                bpy.context.scene.frame_current = 1
                context.scene.imp_sound_to_anim.Info_Import="Done. Imported " + str(obi.iSumImportFrames) + " Frames"
                from time import strftime
                print('')
                print("================================================================")
                print("Imported: " +str(obi.iSumImportFrames) + " Key Frames")
                print("Optimizer Pass 1 prepared to optimize: " +str(obi.iSumOptimizerP1) + " blocks of Frames")
                print("Optimizer Pass 2 has optimized: " +str(obi.iSumOptimizerP2) + " Frames")
                print("Optimizer Pass 3 has optimized: " +str(obi.iSumOptimizerP3) + " Frames")
                print("Optimizer has optimized: " +str(obi.iSumOptimizerP1 + obi.iSumOptimizerP2 + obi.iSumOptimizerP3) + " Frames")
                print(strftime("End Import:  %H:%M:%S - by Vlassius"))
                print("================================================================")
                print('')
                obi.RunFrom=0
                obi.iSumImportFrames=0
                obi.iSumOptimizerP1=0
                obi.iSumOptimizerP2=0
                obi.iSumOptimizerP3=0
                return obi.RunFrom
            else:
                obi.RunFrom+= loop
                context.scene.imp_sound_to_anim.Info_Import="Processing Frame " + str(obi.RunFrom+loop) + \
                                                                            " of " + str(tot-1) + " Frames"
                return obi.RunFrom


    def execute(self, context):
        #wavimport(context)
        #return{'FINISHED'}
        context.scene.imp_sound_to_anim.Working= "wavimport"
        bpy.ops.wm.modal_timer_operator()

    def invoke(self, context, event):
        self.execute(context)
        return {'FINISHED'}



#
#==================================================================================================
# Button - Sound Process
#==================================================================================================
#
class OBJECT_OT_Botao_Go(bpy.types.Operator):
    ''''''
    bl_idname = "import.sound_animation_botao_go"
    # change in API
    bl_description = "Process a .wav file, take movement from the sound and import to the scene as Key"
    bl_label = "Process Wav"

    filter_glob = StringProperty(default="*.wav", options={'HIDDEN'})
    path = StringProperty(name="File Path", description="Filepath used for importing the WAV file", \
                                                                            maxlen= 1024, default= "")
    filename = StringProperty(name="File Name", description="Name of the file")
    directory = StringProperty(name="Directory", description="Directory of the file")

    RunFrom=0
    Wave_read=0
    MaxAudio=0


    def SoundConv(File, DivSens, Sensibil, Resol, context, bAutoSense, bRemoveBeat, bUseBeat, bMoreSensible, \
                                                                            bLessSensible, AudioChannel, loop):
        obg= OBJECT_OT_Botao_Go
        #reseta contadores caso seja pedido
        if context.scene.imp_sound_to_anim.timer_reset_func:
            obc.RunFrom=0
            Wave_read=0
            MaxAudio=0
            context.scene.imp_sound_to_anim.timer_reset_func=False

        #abre arquivo se primeira rodada
        if obg.RunFrom==0:
            try:
                obg.Wave_read= wave.open(File, 'rb')
            except IOError as e:
                print("File Open Error: ", e)
                return False

        NumCh=      obg.Wave_read.getnchannels()
        SampW=      obg.Wave_read.getsampwidth() # 8, 16, 24 32 bits
        FrameR=     obg.Wave_read.getframerate()
        NumFr=      obg.Wave_read.getnframes()
        ChkCompr=   obg.Wave_read.getcomptype()

        if ChkCompr != "NONE":
            print('Sorry, this compressed Format is NOT Supported ', ChkCompr)
            context.scene.imp_sound_to_anim.Info_Import= "Sorry, this compressed Format is NOT Supported "
            return False

        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=""

        # controla numero do canal
        if AudioChannel > NumCh:
            if obg.RunFrom==0:
                print("Channel number " + str(AudioChannel) + " is selected but this audio file has just " + \
                                                            str(NumCh) + " channels, so selecting channel " \
                                                                                            + str(NumCh) + "!")
            AudioChannel = NumCh

        # apenas para por na tela
        tmpAudioChannel= AudioChannel

        #used in index sum to find the channe, adjust to first byte sample index
        AudioChannel -= 1

        # se dois canais, AudioChannel=4 porque sao 4 bytes
        if SampW ==2:  AudioChannel*=2

        # usado para achar contorno da onda - achando picos
        # numero de audio frames para cada video frame
        BytesResol= int(FrameR/Resol)

        # com 8 bits/S - razao Sample/s por resolucao
        # tamanho do array
        BytesDadosTotProcess= NumFr // BytesResol

        if obg.RunFrom==0:   # primeira rodada
            # inicia array
            _Interna_Globals(BytesDadosTotProcess, context)
            print('')
            print("================================================================")
            from time import strftime
            print(strftime("Go!  %H:%M:%S"))
            print("================================================================")
            print('')
            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)
            print('Channel to use:\t\t', tmpAudioChannel)
            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.')

            print('')
            print ("Sample->[value]\tAudio Frame #   \t\t[Graph Value]")

        if obg.RunFrom==0 and bAutoSense!=0:
            Sensibil=0  # if auto sense, Sensibil must be zero here
            obg.MaxAudio=0  # valor maximo de audio encontrado

        # verifica limite total do audio
        looptot= int(BytesDadosTotProcess // DivSens)
        if obg.RunFrom+loop > looptot:
            loop= looptot-obg.RunFrom

        j=0  # usado de indice
        # laco total leitura bytes
        # armazena dado de pico
        for jj in range(loop):
            # caso de 2 canais (esterio)
            # uso apenas 2 bytes em 16 bits, ie, apenas canal esquerdo
            # [0] e [1] para CH L
            # [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
            ValorPico=0
            # leio o numero de frames de audio para cada frame de video, valor em torno de 1000
            for i in range(BytesResol):
                #loop exterior copia DivSens frames a cada frame calculado
                frame = obg.Wave_read.readframes(DivSens)

                if len(frame)==0: break

                if bAutoSense==0:    # AutoAudioSense Desligado
                    if SampW ==1:
                        if Sensibil ==5:
                            frame0= frame[AudioChannel] << 6 & 255

                        elif Sensibil ==4:
                            frame0= frame[AudioChannel] << 5 & 255

                        elif Sensibil ==3:
                            frame0= frame[AudioChannel] << 4 & 255

                        elif Sensibil ==2:
                            frame0= frame[AudioChannel] << 3 & 255

                        elif Sensibil ==1:
                            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 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)

                            elif Sensibil ==1:
                                frame0= ((frame[AudioChannel] & 0b11000000) >> 6) | ((frame[1+AudioChannel] & 0b00111111) << 2)

                            elif Sensibil ==5:
                                frame0=frame[AudioChannel]

                            if frame0 > ValorPico:
                                ValorPico= frame0

                else:   # AutoAudioSense Ligado
                    if SampW ==1:
                        if frame[AudioChannel]> obg.MaxAudio:
                            obg.MaxAudio = frame[AudioChannel]

                        if frame[AudioChannel]> ValorPico:
                            ValorPico=frame[AudioChannel]

                    if SampW ==2:
                        if frame[1+AudioChannel] < 127:
                            tmpValorPico= frame[1+AudioChannel] << 8
                            tmpValorPico+=  frame[AudioChannel]

                            if tmpValorPico > obg.MaxAudio:
                                obg.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+obg.RunFrom]=ValorPico  # valor de pico encontrado
                    j +=1           # incrementa indice prox local
            else:
                idx=obg.RunFrom*2 # porque sao dois bytes
                arrayAutoSense[j+idx]= (ValorPico & 0b0000000011111111) #copia valores baixos
                arrayAutoSense[j+1+idx]= (ValorPico & 0b1111111100000000) >> 8   #copia valores altos
                j+=2

            if bAutoSense==0:    #autoaudiosense desligado
                igraph= ValorPico//10
            else:
                if SampW ==2:
                    igraph= ValorPico//1261

                else:
                    igraph= ValorPico//10

            stgraph="["
            for iii in range(igraph):
                stgraph+="+"

            for iiii in range(26-igraph):
                stgraph+=" "
            stgraph+="]"

            print ("Sample-> " + str(ValorPico) + "\tAudio Frame #  " + str(jj+obg.RunFrom) + " of " + str(looptot-1) + "\t"+ stgraph)

        # acabou primeira fase roda toda de uma vez
        if obg.RunFrom+loop == looptot:
            if bAutoSense==1:
                print("")
                print("================================================================")
                print('Calculating Auto Audio Sentivity, pass 2 of 2.')
                print("================================================================")

                # caso usar batida, procurar por valores proximos do maximo e zerar restante.
                # caso retirar batida, zerar valores proximos do maximo
                UseMinim=0
                UseMax=0

                if bUseBeat==1:
                    print("Trying to use just the beat.")
                    UseMinim= obg.MaxAudio*0.8
                    if bMoreSensible:
                        UseMinim= obg.MaxAudio*0.7
                    elif bLessSensible:
                        UseMinim= obg.MaxAudio*0.9

                if bRemoveBeat==1:
                    print("Trying to exclude the beat.")
                    UseMax= obg.MaxAudio*0.7
                    if bMoreSensible:
                        UseMax= obg.MaxAudio*0.8
                    elif bLessSensible:
                        UseMax= obg.MaxAudio*0.7

                print("")
                # para transformar 15 bits em 8 calibrando valor maximo -> fazer regra de 3
                # obg.MaxAudio -> 255
                # outros valores => valor calibrado= (255 * Valor) / obg.MaxAudio
                scale= 255/obg.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]

                    if bUseBeat==1:
                        if ValorOriginal < UseMinim:
                            ValorOriginal = 0

                    elif bRemoveBeat==1:
                        if ValorOriginal > UseMax:
                            ValorOriginal = 0

                    ValorOriginal= ((round(ValorOriginal * scale)) & 0b11111111)    #aplica a escala

                    for ii in range(DivSens):
                        array[jj] = ValorOriginal
                        jj += 1   # se autoaudiosense, o array tem dois bytes para cada valor

                    j+=2
                    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[:]

            # mensagens finais
            context.scene.imp_sound_to_anim.Info_Import= "Click \"Import Key frames\" to begin import" #this set the initial text

            print("================================================================")
            from time import strftime
            print(strftime("End Process:  %H:%M:%S"))
            print("================================================================")

            try:
                obg.Wave_read.close()
            except:
                print('File Close Error')

            obg.RunFrom=0
            return obg.RunFrom   # acabou tudo

        else:#ainda nao acabou o arquivo todo if RunFrom+loop = looptot:
            context.scene.imp_sound_to_anim.Info_Import="Processing " + str(obg.RunFrom) + " of " + str(looptot) +" Audio Frames"
            # force update info text in UI
            bpy.context.scene.frame_current= bpy.context.scene.frame_current
            obg.RunFrom+=loop
            return obg.RunFrom




    def ProcessaSom(context, loop):
        obg= OBJECT_OT_Botao_Go
        # para de entrar o timer
        context.scene.imp_sound_to_anim.Working=""
        #reseta contadores caso seja pedido
        if context.scene.imp_sound_to_anim.timer_reset_func:
            obg.RunFrom=0
            context.scene.imp_sound_to_anim.timer_reset_func=False

        import os
        f= os.path.join(context.scene.imp_sound_to_anim.directory, context.scene.imp_sound_to_anim.filename)
        f= os.path.normpath(f)

        if obg.RunFrom==0:
            print ("")
            print ("")
            print ("Selected file = ",f)
        checktype = f.split('\\')[-1].split('.')[1]
        if checktype.upper() != 'WAV':
            print ("ERROR!! Selected file = ", f)
            print ("ERROR!! Its not a .wav file")
            return

        #sensibilidade volume do audio 0 a 5. Quanto maior, mais sensibilidade
        iAudioSensib= int(context.scene.imp_sound_to_anim.audio_sense)-1
        if iAudioSensib <0: iAudioSensib=0
        elif iAudioSensib>5: iAudioSensib=5

        #act/s nao pode se maior que frames/s
        if context.scene.imp_sound_to_anim.action_per_second > context.scene.imp_sound_to_anim.frames_per_second:
            context.scene.imp_sound_to_anim.action_per_second = context.scene.imp_sound_to_anim.frames_per_second

        #Frames por segundo para key frame
        iFramesPorSeg= int(context.scene.imp_sound_to_anim.frames_per_second)

        #Sensibilidade de movimento. 3= 3 movimentos por segundo
        iMovPorSeg= int(context.scene.imp_sound_to_anim.action_per_second)

        #iDivMovPorSeg Padrao - taxa 4/s ou a cada 0,25s  => iFramesPorSeg/iDivMovPorSeg= ~0.25
        for i in range(iFramesPorSeg):
            iDivMovPorSeg=iFramesPorSeg/(i+1)
            if iFramesPorSeg/iDivMovPorSeg >=iMovPorSeg:
                break

        bRemoveBeat=    context.scene.imp_sound_to_anim.remove_beat
        bUseBeat=       context.scene.imp_sound_to_anim.use_just_beat
        bLessSensible=  context.scene.imp_sound_to_anim.beat_less_sensible
        bMoreSensible=  context.scene.imp_sound_to_anim.beat_more_sensible
        AudioChannel=   context.scene.imp_sound_to_anim.audio_channel_select

        # chama funcao de converter som, retorna preenchendo _Interna_Globals.array
        index= OBJECT_OT_Botao_Go.SoundConv(f, int(iDivMovPorSeg), iAudioSensib, iFramesPorSeg, context, \
                                    context.scene.imp_sound_to_anim.action_auto_audio_sense, bRemoveBeat, \
                                    bUseBeat, bMoreSensible, bLessSensible, AudioChannel, loop)
        return index


    def execute(self, context):

        # copia dados dialof open wave
        context.scene.imp_sound_to_anim.filter_glob= self.filter_glob
        context.scene.imp_sound_to_anim.path = self.path
        context.scene.imp_sound_to_anim.filename = self.filename
        context.scene.imp_sound_to_anim.directory = self.directory

        context.scene.imp_sound_to_anim.Working= "ProcessaSom"
        bpy.ops.wm.modal_timer_operator()
        #ProcessaSom(context)
        return{'FINISHED'}

    def invoke(self, context, event):
        #need to set a path so so we can get the file name and path
        wm = context.window_manager
        wm.fileselect_add(self)

        return {'RUNNING_MODAL'}


#
#==================================================================================================
# Button - Check Smart Render
#==================================================================================================
#
class OBJECT_OT_Botao_Check_SmartRender(bpy.types.Operator):
    '''Check for Reduction'''
    bl_idname = "import.sound_animation_botao_check_smartrender"
    bl_label = "Check Smart Render"

    RunFrom=0
    Frames_Renderizar=0
    Frames_Pular=0

    def CheckSmartRender(context, loop):
        obc= OBJECT_OT_Botao_Check_SmartRender

        #reseta contadores caso seja pedido
        if context.scene.imp_sound_to_anim.timer_reset_func:
            obc.RunFrom=0
            obc.Frames_Pular=0
            obc.Frames_Renderizar=0
            context.scene.imp_sound_to_anim.timer_reset_func=False

        if obc.RunFrom==0:
            if loop !=1: # loop==1 quando estou chamando de dentro da funcao render
                print("")
                print("================================================================")
                print('Running Check Smart Render...')

        #garante ao menos locrotscale ligado
        if context.scene.imp_sound_to_anim.check_smartrender_loc_rot_sc==False and \
                        context.scene.imp_sound_to_anim.check_smartrender_material_basic==False and \
                        context.scene.imp_sound_to_anim.check_smartrender_material_transparence==False and \
                        context.scene.imp_sound_to_anim.check_smartrender_material_mirror==False:
            context.scene.imp_sound_to_anim.check_smartrender_loc_rot_sc=True

        chkLocRotSc=  context.scene.imp_sound_to_anim.check_smartrender_loc_rot_sc
        chkMatBas=    context.scene.imp_sound_to_anim.check_smartrender_material_basic
        chkMatTransp= context.scene.imp_sound_to_anim.check_smartrender_material_transparence
        chkMatMirror= context.scene.imp_sound_to_anim.check_smartrender_material_mirror

        ToRender=[]
        origloop=loop
        from copy import copy
        RunMax= bpy.context.scene.frame_end - bpy.context.scene.frame_start+1
        if obc.RunFrom+loop > RunMax:
            loop= RunMax-obc.RunFrom
            if loop<=0:   #acabou
                if origloop !=1: # loop==1 quando estou chamando de dentro da funcao render
                    print("")
                    print("Frames to copy: " + str(obc.Frames_Pular) + " Frames to really render= " + str(obc.Frames_Renderizar))
                    print("================================================================")
                    print("")
                obc.RunFrom=0
                obc.Frames_Pular=0
                obc.Frames_Renderizar=0
                return (ToRender, obc.RunFrom)

        #move para o primeiro frame a renderizar
        #RunFrom inicia em zero - frames inicia em 1
        bpy.context.scene.frame_current = obc.RunFrom+bpy.context.scene.frame_start

        for k in range(loop):
            if obc.RunFrom==0 and k==0: #primeiro sempre renderiza
                ToRender.append(bpy.context.scene.frame_current)
                obc.Frames_Renderizar+=1
                bpy.context.scene.frame_set(bpy.context.scene.frame_current + 1)
            else:
                if origloop !=1: # loop==1 quando estou chamando de dentro da funcao render
                    import sys
                    sys.stdout.write("\rChecking Frame "+str(bpy.context.scene.frame_current) + "  ")
                    sys.stdout.flush()
                #buffer de todos os objetos
                a=[]
                for obj in bpy.data.objects:
                    if chkLocRotSc:
                        # loc rot scale
                        a.append(copy(obj.location))
                        a.append(copy(obj.rotation_euler))
                        a.append(copy(obj.scale))
                    if hasattr(obj.data, 'materials') and obj.data.materials.keys()!=[] :
                        if bpy.context.scene.render.engine == "BLENDER_RENDER":
                            #pega somente primeiro material sempre
                            if chkMatBas:
                                # cores
                                a.append(copy(obj.data.materials[0].type))
                                a.append(copy(obj.data.materials[0].emit))
                                a.append(copy(obj.data.materials[0].diffuse_color))
                                a.append(copy(obj.data.materials[0].diffuse_intensity))
                                a.append(copy(obj.data.materials[0].specular_intensity))
                                a.append(copy(obj.data.materials[0].specular_color))
                                a.append(copy(obj.data.materials[0].alpha))
                                a.append(copy(obj.data.materials[0].diffuse_shader))
                                a.append(copy(obj.data.materials[0].specular_shader))
                                a.append(copy(obj.data.materials[0].specular_hardness))

                            if chkMatTransp:
                                # transp
                                a.append(copy(obj.data.materials[0].transparency_method))
                                a.append(copy(obj.data.materials[0].specular_alpha))
                                a.append(copy(obj.data.materials[0].raytrace_transparency.fresnel))
                                a.append(copy(obj.data.materials[0].raytrace_transparency.ior))
                                a.append(copy(obj.data.materials[0].raytrace_transparency.filter))
                                a.append(copy(obj.data.materials[0].raytrace_transparency.depth))
                                a.append(copy(obj.data.materials[0].translucency))
                                a.append(copy(obj.data.materials[0].specular_alpha))

                            if chkMatMirror:
                                #mirror
                                a.append(copy(obj.data.materials[0].raytrace_mirror.reflect_factor))
                                a.append(copy(obj.data.materials[0].raytrace_mirror.fresnel))
                                a.append(copy(obj.data.materials[0].raytrace_mirror.fresnel_factor))
                                a.append(copy(obj.data.materials[0].mirror_color))
                                a.append(copy(obj.data.materials[0].raytrace_mirror.depth))
                                a.append(copy(obj.data.materials[0].raytrace_mirror.gloss_factor))

                # tenho todos os objetos em a[]
                # incrementar um frame e checar se eh igual
                bpy.context.scene.frame_set(bpy.context.scene.frame_current + 1)

                j=0
                dif=0
                for obj in bpy.data.objects:
                    if chkLocRotSc:
                        if a[j]!= obj.location or a[j+1]!= obj.rotation_euler or a[j+2]!= obj.scale:
                            dif=1
                            #break
                        j+=3

                    if hasattr(obj.data, 'materials') and obj.data.materials.keys()!=[] :
                        if bpy.context.scene.render.engine == "BLENDER_RENDER":
                            if chkMatBas:
                                # cores
                                if a[j]!= obj.data.materials[0].type or   a[j+1]!= obj.data.materials[0].emit or \
                                                                            a[j+2]!= obj.data.materials[0].diffuse_color or \
                                                                            a[j+3]!= obj.data.materials[0].diffuse_intensity or \
                                                                            a[j+4]!= obj.data.materials[0].specular_intensity or \
                                                                            a[j+5]!= obj.data.materials[0].specular_color or \
                                                                            a[j+6]!= obj.data.materials[0].alpha or \
                                                                            a[j+7]!= obj.data.materials[0].diffuse_shader or \
                                                                            a[j+8]!= obj.data.materials[0].specular_shader or \
                                                                            a[j+9]!= obj.data.materials[0].specular_hardness:
                                    dif=1
                                    print("mat")
                                    j+= 10  # ajusta ponteiro j
                                    if chkMatTransp: j+=8
                                    if chkMatMirror: j+=6
                                    break
                                j+=10

                            if chkMatTransp:
                                #transp
                                if a[j]!= obj.data.materials[0].transparency_method or    a[j+1]!= obj.data.materials[0].specular_alpha or \
                                                                                            a[j+2]!= obj.data.materials[0].raytrace_transparency.fresnel or \
                                                                                            a[j+3]!= obj.data.materials[0].raytrace_transparency.ior or \
                                                                                            a[j+4]!= obj.data.materials[0].raytrace_transparency.filter or \
                                                                                            a[j+5]!= obj.data.materials[0].raytrace_transparency.depth or \
                                                                                            a[j+6]!= obj.data.materials[0].translucency or \
                                                                                            a[j+7]!= obj.data.materials[0].specular_alpha:
                                    dif=1
                                    j+= 8     # ajusta ponteiro j
                                    if chkMatMirror: j+=6

                                    break
                                j+=8

                            if chkMatMirror:
                                #mirror
                                if a[j]!= obj.data.materials[0].raytrace_mirror.reflect_factor or a[j+1]!= obj.data.materials[0].raytrace_mirror.fresnel or \
                                                                                                    a[j+2]!= obj.data.materials[0].raytrace_mirror.fresnel_factor or \
                                                                                                    a[j+3]!= obj.data.materials[0].mirror_color or \
                                                                                                    a[j+4]!= obj.data.materials[0].raytrace_mirror.depth or \
                                                                                                    a[j+5]!= obj.data.materials[0].raytrace_mirror.gloss_factor:
                                    dif=1
                                    j+= 6     # ajusta ponteiro j
                                    break
                                j+=6
                # finaliza
                if dif==0:
                    obc.Frames_Pular+=1
                else:
                    obc.Frames_Renderizar+=1
                    ToRender.append(bpy.context.scene.frame_current)

                del a
        # para nao sair do index - nunca chega nesse frame
        ToRender.append(bpy.context.scene.frame_end+1)

        if obc.RunFrom+loop < RunMax:
            context.scene.imp_sound_to_anim.Info_check_smartrender= "["+str(obc.RunFrom+loop) + "/" + \
                                        str(RunMax) + "] Frames to Render= " + str(obc.Frames_Renderizar) + \
                                        " -> Reduction " + str(round((obc.Frames_Pular/RunMax)*100,1)) + "%"
        else:
            context.scene.imp_sound_to_anim.Info_check_smartrender= "Frames to Render= " + str(obc.Frames_Renderizar) + \
                                                    " -> Reduction " + str(round((obc.Frames_Pular/RunMax)*100,1)) + "%"

        #incrementa indice
        obc.RunFrom+= loop
        return (ToRender, obc.RunFrom)

    def execute(self, context):
        context.scene.imp_sound_to_anim.Working= "CheckSmartRender"
        #context.scene.imp_sound_to_anim.timer_reset_func=True
        bpy.ops.wm.modal_timer_operator()
        #CheckSmartRender(context)
        return{'FINISHED'}

    def invoke(self, context, event):
        self.execute(context)
        return {'FINISHED'}


#
#==================================================================================================
# Button - Smart Render
#==================================================================================================
#
class OBJECT_OT_Botao_SmartRender(bpy.types.Operator):
    '''Render Only Modified Frames and Copy the Others'''
    bl_idname = "import.sound_animation_smart_render"
    bl_label = "Smart Render"

    BaseRenderToCopy=0

    def SmartRender(context):
        obs=OBJECT_OT_Botao_SmartRender

        index=0
        pad=4
        #calcula zero pad
        if bpy.context.scene.frame_end //1000000 > 0:  #default 999999 1000000//1000000=1
            pad=7
        elif bpy.context.scene.frame_end //100000 > 0:  #default 99999 100000//100000=1
            pad=6
        elif bpy.context.scene.frame_end //10000 > 0:  #default 9999 10000//10000=1
            pad=5

        #bpy.data.images['Render Result'].file_format ='PNG'
        bpy.context.scene.render.image_settings.file_format = 'PNG'

        #info dos arquivos
        path= bpy.context.scene.render.filepath

        import shutil

        tot=bpy.context.scene.frame_end - bpy.context.scene.frame_start+1
        i=0
        # checa apenas 1 frame    o indice é interno em ChackSmartRender
        r= OBJECT_OT_Botao_Check_SmartRender.CheckSmartRender(context, 1)
        ToRender= r[0] # tem numero do frame se for para renderizar
        index= r[1]

        #copia frame atual  #se o frame ja não foi renderizado
        if (obs.BaseRenderToCopy!=(index+bpy.context.scene.frame_start-1)) and index > 1:   #index!=1 and index !=0:
            print("Copying: " + str(obs.BaseRenderToCopy) + "-> " + str(index+bpy.context.scene.frame_start-1) + \
                                "  To " + path + str(index+bpy.context.scene.frame_start-1).zfill(pad)  + ".png")
            shutil.copy2(path + str(obs.BaseRenderToCopy).zfill(pad)  + ".png", path + \
                        str(index+bpy.context.scene.frame_start-1).zfill(pad)  + ".png")

        if ToRender.__len__()>1:   #renderizar 1 item em ToRender nao renderiza, (sempre vem com no minimo 1)
            if index==1:
                print("================================================================")
                from time import strftime
                print(strftime("Running Smart Render:  %H:%M:%S"))
                print("================================================================")
                BaseRenderToCopy=0

            if ToRender[0] <= bpy.context.scene.frame_end:
                #renderiza proximo frame
                print("Rendering-> " + str(ToRender[0]))
                obs.BaseRenderToCopy= ToRender[0]
                bpy.ops.render.render(animation=False, write_still=False)
                bpy.data.images['Render Result'].save_render(filepath=path + str(ToRender[0]).zfill(pad)  + ".png")
                i+=1

        if index==tot:
            print("================================================================")
            from time import strftime
            print(strftime("Finish Render:  %H:%M:%S"))
            print("================================================================")
            print(".")

        if index==tot+1:
            obs.BaseRenderToCopy=0
            return 0

        return index


    def execute(self, context):
        # se for CYCLES, nao funciona com timer, preciso rodar direto
        context.scene.imp_sound_to_anim.Working= "SmartRender"
        bpy.ops.wm.modal_timer_operator()
        #SmartRender(context)
        return{'FINISHED'}

    def invoke(self, context, event):
        self.execute(context)
        return {'FINISHED'}



#
#==================================================================================================
# Button - Cancel
#==================================================================================================
#
class OBJECT_OT_Botao_Cancel(bpy.types.Operator):
    '''Cancel Actual Operation'''
    bl_idname = "import.sound_animation_botao_cancel"
    bl_label = "CANCEL"

    def execute(self, context):
        context.scene.imp_sound_to_anim.cancel_button_hit=True
        return{'FINISHED'}

    def invoke(self, context, event):
        self.execute(context)
        return {'FINISHED'}


#
#==================================================================================================
#     TIMER - controla a execucao das funcoes
#           Responsavel por rodar em partes usando o timer e possibilitando
#           o cancelamento e textos informativos
#==================================================================================================
#
class ModalTimerOperator(bpy.types.Operator):
    """Internal Script Control"""
    bl_idname = "wm.modal_timer_operator"
    bl_label = "Internal Script Control"

    _timer = None
    Running= False

    def CheckRunStop(self, context, func, index):
        # forca update do UI
        bpy.context.scene.frame_set(bpy.context.scene.frame_current)
        if index!=0:
            #configura timer para a funcao
            context.scene.imp_sound_to_anim.Working= func
            self.Running=True
            return {'PASS_THROUGH'}
        else: # posso desligar o timer e modal
            if self._timer!= None:
                context.window_manager.event_timer_remove(self._timer)
                self._timer= None
            return {'FINISHED'}


    def modal(self, context, event):
        if event.type == 'ESC'and self.Running:
            print("-- ESC Pressed --")
            self.cancel(context)
            context.scene.imp_sound_to_anim.Working=""
            self.Running=False
            #reseta contadores
            context.scene.imp_sound_to_anim.timer_reset_func=True
            # forca update do UI
            bpy.context.scene.frame_set(bpy.context.scene.frame_current)
            return {'CANCELLED'}

        if event.type == 'TIMER':
            #print("timer")
            #CheckSmartRender
            if context.scene.imp_sound_to_anim.Working== "CheckSmartRender":
                self.parar(context)
                #5= frames para rodar antes de voltar    [1]= indice de posicao atual
                index= OBJECT_OT_Botao_Check_SmartRender.CheckSmartRender(context, 5)[1]
                return self.CheckRunStop(context, "CheckSmartRender", index)

            #SmartRender
            elif context.scene.imp_sound_to_anim.Working== "SmartRender":
                self.parar(context)
                #render/copia 1 e volta     index>=0 indice posicao atual
                index= OBJECT_OT_Botao_SmartRender.SmartRender(context)
                return self.CheckRunStop(context, "SmartRender", index)

            #ProcessaSom
            elif context.scene.imp_sound_to_anim.Working== "ProcessaSom":
                self.parar(context)
                # loop = numero de frames de audio    index=0 se terminou ou >0 se não acabou
                index= OBJECT_OT_Botao_Go.ProcessaSom(context, 50)
                return self.CheckRunStop(context, "ProcessaSom", index)

            #wavimport(context)
            elif context.scene.imp_sound_to_anim.Working== "wavimport":
                self.parar(context)
                # 5= numero de frames to import por timer
                index=OBJECT_OT_Botao_Import.wavimport(context, 50)
                return self.CheckRunStop(context, "wavimport", index)

            #passa por aqui quando as funcoes estao sendo executadas mas
            #configuradas para nao entrar porque  context.scene.imp_sound_to_anim.Working== ""
            return {'PASS_THROUGH'}

        # reseta e para tudo botao CANCEL pressionado
        if context.scene.imp_sound_to_anim.cancel_button_hit==True:
            context.scene.imp_sound_to_anim.Working=""
            #pede reset contadores
            context.scene.imp_sound_to_anim.timer_reset_func=True
            if self._timer!= None:
                context.window_manager.event_timer_remove(self._timer)
                self._timer= None
            print("-- Cancel Pressed --")
            context.scene.imp_sound_to_anim.cancel_button_hit=False
            return {'FINISHED'}

        #print("modal")

        # se o timer esta ativado, continua, (senao termina).
        # desligar a chamada ao modal se caso chegar aqui (nao deveria)
        if self._timer!= None:
            return{'PASS_THROUGH'}
        else:
            return {'FINISHED'}

    def execute(self, context):
        if self._timer==None:
            self._timer = context.window_manager.event_timer_add(0.2, context.window)
            context.window_manager.modal_handler_add(self)
        #para deixar rodar sem deligar o timer
        context.scene.imp_sound_to_anim.timer_desligar=False
        self.Running=True
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        if self._timer!= None:
            context.window_manager.event_timer_remove(self._timer)
        self._timer= None

    def parar(self, context):
        if self.Running:
            context.scene.imp_sound_to_anim.Working=""
            self.Running=False



#
#==================================================================================================
#     Register - Unregister - MAIN
#==================================================================================================
#
def register():
    bpy.utils.register_module(__name__)
    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.")
    bpy.types.INFO_MT_file_import.append(WavFileImport)

def unregister():

    try:
        bpy.utils.unregister_module(__name__)
    except:
        pass

    try:
        bpy.types.INFO_MT_file_import.remove(WavFileImport)
    except:
        pass



if __name__ == "__main__":
    register()
