authentication-ACSAC / toolbox / audio_processing.py
audio_processing.py
Raw
# -*- coding: utf-8 -*-
"""
Created on Thu Aug 12 18:16:21 2021

@author: Eidos
"""

import wave
import sys
import os

# Add the top level directory in system path
top_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
if not top_path in sys.path:
    sys.path.append(top_path)

import numpy as np
from scipy import signal

from toolbox import pyeidos_fft as e_fft

def audio_load(audio):
    params = audio.getparams()
    nchannels, sampwidth, framerate, nframes = params[:4]
    strData = audio.readframes(nframes)
    waveData = np.frombuffer(strData,dtype=np.int16)
    waveData = np.reshape(waveData,[nframes,nchannels])
    wave_data_left = waveData[:,0]    
    return wave_data_left

def audio_filter(audio_data, cutOff_freq, filter_type='highpass',N=8, sample_rate=44100):
    Wn = 2*cutOff_freq/sample_rate
    b, a = signal.butter(N, Wn, filter_type)
    audio_filt = signal.filtfilt(b, a, audio_data)
    return audio_filt
    
def time2nfft(timestep,fs):
    sa_point = timestep*fs
    nfft = 0
    
    for i in range(100):
        nfft = 2**i
        if (nfft >= sa_point):
            break
    
    return nfft

def time2nfft_win(timestep,fs):
    winlen = timestep
    winstep = timestep/2
    sa_point = timestep*fs
    nfft = 0
    
    for i in range(100):
        nfft = 2**i
        if (nfft >= sa_point):
            break
    
    return winlen, winstep, nfft

def audio_segment(audio_wav, time_step=0.8, time_shift=0.1):
    '''

    Parameters
    ----------
    audio_wav : wav
        single or multi channel
    time_step : float or int, optional
        the time length per sub-audio. The default is 0.8.
    time_shift : float or int
        the time shift per sub-audio.
    
    Returns
    -------
    wave_data_seg : array
        Batch * Data

    '''
    
    audio = [None]
    params = [None]
    nchannels, sampwidth, framerate, nframes = [None], [None], [None], [None]
    strData = [None]
    waveData = [None]
    
    wave_data_left = [None]
    wave_data_seg = []
    
    audio[0] = audio_wav
    
    audio_load(0, audio, params, nchannels, sampwidth, framerate, nframes, strData, waveData, wave_data_left)
    wave_data_left[0] = wave_data_left[0].reshape(-1,1)
    
    seg_length = int(time_step*framerate[0])
    
    seg_move = int(time_shift*framerate[0])
    
    seg_number = int((len(wave_data_left[0])-seg_length)/seg_move)+1
    
    for i in range(seg_number):
        wave_data_seg.append(wave_data_left[0][i*seg_move:i*seg_move+seg_length,0])
    wave_data_seg = np.array(wave_data_seg)
    return wave_data_seg
    
def audio_fft(audio_clip, nfft, origin_normalize=False, fft_normalize=True):
    '''
    
    Parameters
    ----------
    audio_clip : array
        Batch * Data
    nfft : int
        n point fft

    Returns
    -------
    audio_fft : array
        Batch * Data

    '''
    # 
    if origin_normalize:
        audio_clip_max = audio_clip.max(1).reshape(-1,1)
        audio_clip_min = audio_clip.min(1).reshape(-1,1)
        audio_clip = (audio_clip-audio_clip_min)/(audio_clip_max-audio_clip_min)
    
    audio_fft = e_fft.fft_group(audio_clip, nfft)
    
    if fft_normalize:
        audio_fft_max = audio_fft.max(1).reshape(-1,1)
        audio_fft_min = audio_fft.min(1).reshape(-1,1)
        audio_fft = (audio_fft-audio_fft_min)/(audio_fft_max-audio_fft_min)
        
    return audio_fft



if __name__=="__main__":
    import os
    import winsound
    import time
    import matplotlib.pyplot as plt
    
    
    fs = 1000
    
    N = 2**15
    omega_range = np.array(range(0,N)).reshape(-1,1)
    
    omega=omega_range*2*np.pi/N;
    
    Omega = omega*fs;
    
    f = Omega/2/np.pi;
    
    y_number = 3
    y = [None]*y_number
    
    x = np.arange(-1,1,0.001)
    y[0] = 5*np.cos(2*np.pi*100*x)+1
    y[1] = 10*np.cos(2*np.pi*200*x)+2
    y[2] = 15*np.cos(2*np.pi*300*x)+3
    
    y_np = np.array(y).reshape(len(y),-1)
    
    y_fft = audio_fft(y_np,N)
    
    for i in range(y_number):
        plt.subplot(y_number,1,i+1)
        plt.plot(f[0:int(N/2)], y_fft[i, 0:int(N/2)])