Skip to content
Snippets Groups Projects
io_import_sound_to_anim.py 67.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • Eng vlassius santos's avatar
    Eng vlassius santos committed
                    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.object.imp_sound_to_anim.Info_Import= "Sorry, this compressed Format is NOT Supported "
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                return False
    
            if SampW > 2:
    
                context.object.imp_sound_to_anim.Info_Import= "Sorry, supported .wav files 8 and 16 bits only"
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                print('Sorry, supported .wav files 8 and 16 bits only')
                return False
    
    
            context.object.imp_sound_to_anim.Info_Import=""
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
            # 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+="]"
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                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 only the beat.")
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                        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.object.imp_sound_to_anim.Info_Import= "Click \"Import Key frames\" to begin import" #this set the initial text
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
                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.object.imp_sound_to_anim.Info_Import="Processing " + str(obg.RunFrom) + " of " + str(looptot) +" Audio Frames"
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                # 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.object.imp_sound_to_anim.Working=""
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            #reseta contadores caso seja pedido
    
            if context.object.imp_sound_to_anim.timer_reset_func:
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                obg.RunFrom=0
    
                context.object.imp_sound_to_anim.timer_reset_func=False
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
            import os
    
            f= os.path.join(context.object.imp_sound_to_anim.directory, context.object.imp_sound_to_anim.filename)
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            f= os.path.normpath(f)
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
            if obg.RunFrom==0:
                print ("")
                print ("")
                print ("Selected file = ",f)
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            checktype = f.split('\\')[-1].split('.')[1]
            if checktype.upper() != 'WAV':
                print ("ERROR!! Selected file = ", f)
                print ("ERROR!! Its not a .wav file")
                return
    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            #sensibilidade volume do audio 0 a 5. Quanto maior, mais sensibilidade
    
            iAudioSensib= int(context.object.imp_sound_to_anim.audio_sense)-1
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            if iAudioSensib <0: iAudioSensib=0
            elif iAudioSensib>5: iAudioSensib=5
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
            #act/s nao pode se maior que frames/s
    
            if context.object.imp_sound_to_anim.action_per_second > context.object.imp_sound_to_anim.frames_per_second:
                context.object.imp_sound_to_anim.action_per_second = context.object.imp_sound_to_anim.frames_per_second
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
            #Frames por segundo para key frame
    
            iFramesPorSeg= int(context.object.imp_sound_to_anim.frames_per_second)
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
            #Sensibilidade de movimento. 3= 3 movimentos por segundo
    
            iMovPorSeg= int(context.object.imp_sound_to_anim.action_per_second)
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            #iDivMovPorSeg Padrao - taxa 4/s ou a cada 0,25s  => iFramesPorSeg/iDivMovPorSeg= ~0.25
    
            iDivMovPorSeg=1
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            for i in range(iFramesPorSeg):
                iDivMovPorSeg=iFramesPorSeg/(i+1)
                if iFramesPorSeg/iDivMovPorSeg >=iMovPorSeg:
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    break
    
    
            bRemoveBeat=    context.object.imp_sound_to_anim.remove_beat
            bUseBeat=       context.object.imp_sound_to_anim.use_just_beat
            bLessSensible=  context.object.imp_sound_to_anim.beat_less_sensible
            bMoreSensible=  context.object.imp_sound_to_anim.beat_more_sensible
            AudioChannel=   context.object.imp_sound_to_anim.audio_channel_select
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            # chama funcao de converter som, retorna preenchendo _Interna_Globals.array
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            index= OBJECT_OT_Botao_Go.SoundConv(f, int(iDivMovPorSeg), iAudioSensib, iFramesPorSeg, context, \
    
                                        context.object.imp_sound_to_anim.action_auto_audio_sense, bRemoveBeat, \
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                                        bUseBeat, bMoreSensible, bLessSensible, AudioChannel, loop)
            return index
    
    
        def execute(self, context):
    
            # copia dados dialof open wave
    
            context.object.imp_sound_to_anim.filter_glob= self.filter_glob
            context.object.imp_sound_to_anim.path = self.path
            context.object.imp_sound_to_anim.filename = self.filename
            context.object.imp_sound_to_anim.directory = self.directory
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
    
            context.object.imp_sound_to_anim.Working= "ProcessaSom"
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            bpy.ops.wm.modal_timer_operator()
            #ProcessaSom(context)
            return{'FINISHED'}
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
        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)
    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            return {'RUNNING_MODAL'}
    
    
    #
    #==================================================================================================
    # 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.object.imp_sound_to_anim.cancel_button_hit=True
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            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.object.imp_sound_to_anim.Working= func
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                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.object.imp_sound_to_anim.Working=""
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                self.Running=False
                #reseta contadores
    
                context.object.imp_sound_to_anim.timer_reset_func=True
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                # 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.object.imp_sound_to_anim.Working== "CheckSmartRender":
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    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.object.imp_sound_to_anim.Working== "SmartRender":
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    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.object.imp_sound_to_anim.Working== "ProcessaSom":
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    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.object.imp_sound_to_anim.Working== "wavimport":
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                    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.object.imp_sound_to_anim.Working== ""
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                return {'PASS_THROUGH'}
    
            # reseta e para tudo botao CANCEL pressionado
    
            if context.object.imp_sound_to_anim.cancel_button_hit==True:
                context.object.imp_sound_to_anim.Working=""
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                #pede reset contadores
    
                context.object.imp_sound_to_anim.timer_reset_func=True
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                if self._timer!= None:
                    context.window_manager.event_timer_remove(self._timer)
                    self._timer= None
                print("-- Cancel Pressed --")
    
                context.object.imp_sound_to_anim.cancel_button_hit=False
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                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, window=context.window)
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                context.window_manager.modal_handler_add(self)
            #para deixar rodar sem deligar o timer
    
            context.object.imp_sound_to_anim.timer_desligar=False
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
            self.Running=True
            return {'RUNNING_MODAL'}
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        def cancel(self, context):
            if self._timer!= None:
                context.window_manager.event_timer_remove(self._timer)
            self._timer= None
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        def parar(self, context):
            if self.Running:
    
                context.object.imp_sound_to_anim.Working=""
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
                self.Running=False
    
    
    
    #
    #==================================================================================================
    #     Register - Unregister - MAIN
    #==================================================================================================
    #
    
    # ------------------------------------------------------------
    # Register:
    classes = (
    
        ModalTimerOperator,
        OBJECT_OT_Botao_Cancel,
        OBJECT_OT_Botao_Go,
        OBJECT_OT_Botao_Import,
        OBJECT_OT_Botao_uDirect,
        ImpSoundtoAnim,
    )
    
    def register():
        for cls in classes:
            bpy.utils.register_class(cls)
        #bpy.types.VIEW3D_MT_mesh_add.append(menu_func_landscape)
        bpy.types.TOPBAR_MT_file_import.append(WavFileImport)
        #bpy.types.VIEW3D_MT_mesh_add.append(WavFileImport)
        #bpy.types.Object.ant_landscape = PointerProperty(type=AntLandscapePropertiesGroup, name="ANT_Landscape", description="Landscape properties")
    
        bpy.types.Object.imp_sound_to_anim = PointerProperty(
            type=ImpSoundtoAnim,
            name="imp_sound_to_anim",
            description="Extract movement from sound file. See the tool shelf",
        )
    
    
    
    def unregister():
        for cls in reversed(classes):
    
            bpy.utils.unregister_class(cls)
        #bpy.types.VIEW3D_MT_mesh_add.remove(WavFileImport)
    
        bpy.types.TOPBAR_MT_file_import.remove(WavFileImport)
    
    
    if __name__ == "__main__":
        register()
    
    
    
    """
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    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.TOPBAR_MT_file_import.append(WavFileImport)
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    def unregister():
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        try:
            bpy.utils.unregister_module(__name__)
        except:
            pass
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
        try:
    
            bpy.types.TOPBAR_MT_file_import.remove(WavFileImport)
    
    Eng vlassius santos's avatar
    Eng vlassius santos committed
    
    if __name__ == "__main__":
    
        register()"""