Python实现mic录音实时播放、实时显示波形及频谱

import wave
import math
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pylab import mpl
from matplotlib.animation import FuncAnimation
import pyaudio
import time
import threading
from scipy.fftpack import fft, ifft,irfft
from threading import Lock,Thread
import codecs
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['font.sans-serif'] = ['SimHei']   #显示中文
mpl.rcParams['axes.unicode_minus']=False       #显示负号

class Audiowave:

    def __init__(self):

        self.wavedata=[]
        self.wavewidth=2
        self.wavechannel=1
        self.framerate = 48000
        self.fps=24
        self.Timedata=[]
        self.nframes=0
        self.N=0
        self.data=[]
        self.dataall = []
        np.array(self.dataall)
        # plt.figure(figsize=(16, 8))
        self.fig, self.ax = plt.subplots(2,1,figsize=(8, 6))
        self.p=pyaudio.PyAudio()  # 实例化对象
        self.q=pyaudio.PyAudio()  # 实例化对象
        if self.wavewidth == 1:
            format= pyaudio.paInt8
        elif self.wavewidth == 2:
            format= pyaudio.paInt16
        elif self.wavewidth == 3:
            format= pyaudio.paInt24
        elif self.wavewidth == 4:
            format= pyaudio.paFloat32
        # fps=waveframerate/waveCHUNK  #每秒数据更新次数
        self.waveCHUNK = int(self.framerate / self.fps)
        # a=time.time()
        self.stream =self.p.open(format=format,
                        channels=self.wavechannel,
                        rate=self.framerate,
                        input=True,
                        frames_per_buffer=self.waveCHUNK)  #录音
        self.stream1 =self.q.open(format=format,
                        channels=self.wavechannel,
                        rate=self.framerate,
                        output=True,
                        frames_per_buffer=self.waveCHUNK) #播放
        self.c = 0
        self.a = time.time()
        self.b = 0
        self.x=[]
        self.y=[]
        self.fft_int=[]
        np.array(self.x)
        np.array(self.y)
        self.wf = wave.open(r"D:\pythonProject2\wav\test.wav", 'wb')
        self.wf.setnchannels(self.wavechannel)  # 声道设置
        self.wf.setsampwidth(self.p.get_sample_size(format))  # 采样位数设置
        self.wf.setframerate(self.framerate)
        self.wf1 = wave.open(r"D:\pythonProject2\wav\test1.wav", 'wb')
        self.wf1.setnchannels(self.wavechannel)  # 声道设置
        self.wf1.setsampwidth(self.p.get_sample_size(format))  # 采样位数设置
        self.wf1.setframerate(self.framerate)

    def waveopen(self,filedir):
        wf=wave.open(filedir,"rb")
        self.nframes = wf.getnframes()
        self.wavedata = wf.readframes(self.nframes)
        self.wavewidth=wf.getsampwidth()
        self.wavechannel=wf.getnchannels()
        self.framerate = wf.getframerate()
        self.time=self.nframes/self.framerate
        bps=self.framerate*self.wavewidth*8*self.wavechannel
        print("总帧数:"+str(self.nframes)+"帧")
        print("采样率:"+str(self.framerate)+"帧/s")
        print("声道数:"+str(self.wavechannel)+"个")
        print("位深:"+str(self.wavewidth*8)+"bit")
        print("比特率:"+str(bps/1000)+"kbps")
        print("时间:"+ str(self.time)+"s")
        print("文件大小:"+ str(self.time*bps/8/1024/1024)+"MB")
        return self.wavedata,self.wavewidth,self.wavechannel,self.framerate,self.time



    def wavehex_to_DEC(self,wavedata,wavewidth,wavechannel):
        print("#####################")


        print(type(self.Timedata))
        n = int(len(wavedata) / wavewidth)
        i = 0
        j = 0
        for i in range(0, n):
            b = 0
            for j in range(0, wavewidth):
                temp = wavedata[i * wavewidth:(i + 1) * wavewidth][j] * int(math.pow(2, 8 * j))
                b += temp
            if b > int(math.pow(2, 8 * wavewidth - 1)):
                b = b - int(math.pow(2, 8 * wavewidth))
            self.Timedata.append(b)
        self.Timedata = np.array(self.Timedata)
        # print(len(self.Timedata))
        self.Timedata.shape = -1, wavechannel
        self.Timedata = self.Timedata.T

        x = np.linspace(0, len(self.Timedata[0])-1, len(self.Timedata[0])) / self.framerate

        return x,self.Timedata

    def to_fft(self,N,data):#转换为频域数据,并进行取半、归一化等处理
        # N=self.nframes #取样点数
        df = self.framerate / (N - 1)  #每个点分割的频率 如果你采样频率是4096,你FFT以后频谱是从-2048到+2048hz(4096除以2),然后你的1024个点均匀分布,相当于4个HZ你有一个点,那个复数的模就对应了频谱上的高度
        freq = [df * n for n in range(0, N)]

        wave_data2 = data[0:N]
        self.fft_int=np.fft.fft(wave_data2)
        # print(N, len(data),len(wave_data2))
        c = self.fft_int * 2 / N  #*2能量集中化  /N归一化
        d = int(len(c) / 2)  #对称取半
        freq=freq[:d - 1]
        fredata=abs(c[:d - 1])

        return freq,fredata



    def wavedraw1(self,filedir):
        self.waveopen(filedir)
        timedata=self.wavehex_to_DEC(self.wavedata,self.wavewidth,self.wavechannel)
        fredata=self.to_fft(self.nframes,timedata[1][0])


        plt.figure(figsize=(16, 8))
        plt.subplot(2,1,1)
        plt.plot(timedata[0], timedata[1][0])
        plt.xlabel(u"Time(S)")
        plt.subplot(212)
        plt.plot(fredata[0],fredata[1])
        plt.xlim(0, 800)
        plt.xlabel(u"Freq(Hz)")

        plt.subplots_adjust(hspace=0.4)
        plt.show()

    def wavedrawall(self,filedir):
        self.waveopen(filedir)
        n=self.wavechannel
        timedata = self.wavehex_to_DEC(self.wavedata, self.wavewidth, self.wavechannel)
        xtimedata=timedata[0]
        ytimedata=timedata[1]
        # print(ytimedata)
        i=0
        plt.figure(figsize=(16, 8))
        # plt.legend(prop=font_set)
        for i in range(0,n):
            a=plt.subplot(2, n, i+1)
            a.set_title("track"+str(i+1))
            plt.plot(xtimedata, ytimedata[i])
            plt.xlabel(u"Time(S)")
            # print(ytimedata[i])
            fredata = self.to_fft(self.nframes,ytimedata[i])
            plt.subplot(2,n,i+1+n)
            plt.plot(fredata[0], fredata[1])
            plt.xlim(0, 4000)
            plt.xlabel(u"Freq(Hz)")
        plt.subplots_adjust(hspace=0.4)
        plt.show()

    def Dynamic_init(self):

        # self.fig.figsize(16,8)
        # print(self.Timedata)
        # Y_max=max(list(self.Timedata)
        Y_max=max(self.Timedata)*5/4
        self.ax[0].set_xlim(0, int(self.time)*5/4)
        self.ax[0].set_ylim(-(Y_max),(Y_max))
        self.ax[1].set_xlim(0, 10000)
        # self.ax.set_ylim(0,20000)
        ln, = self.ax[0].plot([], [], animated=False)
        return ln,  # 返回曲线

    def Dynamic_updata(self,n):
        # print("#####",n)
        N=self.N
        xdata=np.linspace(0,len(self.Timedata),len(self.Timedata)+1)
        # xdata.pop()
        xdata=np.delete(xdata,-1)
        ydata=self.Timedata
        # print(len(xdata),len(ydata))
        # print(ydata)
        x_t=xdata[0:int((n+1)*N)]/self.framerate
        # print(len(x_t))
        y_t=ydata[0:int((n+1)*N)]
        fre_data=self.Timedata[int(n*N):int((n+1)*N)]
        if len(fre_data)>0:
            a=self.to_fft(N,fre_data)
            x=a[0]
            y=a[1]
        else:
            x=0
            y=0
        # print(x,y)

        ln,=self.ax[0].plot(x_t,y_t,"g-")
        ln1,=self.ax[1].plot(x,y,"g-")

        # ln1=ln# 重新设置曲线的值
        return ln,ln1,

    def Dynamic_run(self,filedir): #
        self.waveopen(filedir)
        FPS=24
        self.N=int(self.framerate/FPS)#每次fft取样点数
        self.Timedata = self.wavehex_to_DEC(self.wavedata, self.wavewidth, self.wavechannel)[1][0]
        print(len(self.Timedata))
        temp = list(np.linspace(0, int(self.nframes/self.N),int(self.nframes/self.N)+1))
        # temp.pop()
        ani = FuncAnimation(self.fig, self.Dynamic_updata, frames=temp, interval=self.N/self.framerate*1000,
                            init_func=self.Dynamic_init, blit=True)
        plt.show()
    def wavehex_to_DEC_n(self,wavedata,wavewidth,wavechannel):#录音存储数据十六进制数据转换十进制
        # print("#####################")
        Timedata=[]


        # print(type(self.Timedata))
        n = int(len(wavedata) / wavewidth)
        i = 0
        j = 0
        for i in range(0, n):
            b = 0
            for j in range(0, wavewidth):
                temp = wavedata[i * wavewidth:(i + 1) * wavewidth][j] * int(math.pow(2, 8 * j))
                b += temp
            if b > int(math.pow(2, 8 * wavewidth - 1)):
                b = b - int(math.pow(2, 8 * wavewidth))
            Timedata.append(b)
        Timedata = np.array(Timedata)
        # print(len(self.Timedata))
        Timedata.shape = -1, wavechannel
        Timedata = Timedata.T

        x = np.linspace(0, len(Timedata[0])-1, len(Timedata[0])) / self.framerate

        return x,Timedata



    def DEC_to_wavehex(self,DEC_data, wavewidth=2, wavechannel=1):
        wavewidth=self.wavewidth
        wavedata = ""
        for data in DEC_data:
            data = int(data)

            if data < 0:
                data += int(math.pow(2, 8 * wavewidth))

                # print(data)
            a = hex(data)[2:]
            a = a[::-1]
            while len(a) < 2 * wavewidth:
                a += "0"
            for i in range(0, wavewidth):
                # print(a[i * 2:2 * i + 2])
                b = r"\x" + a[i * 2:2 * i + 2]
                wavedata += b
            # wavedata.append(b)
        wavedata=bytes(wavedata, encoding="utf8")

        return codecs.escape_decode(wavedata, "hex-escape")[0]

    def micdata(self):#录音数据,存储,播放
        t00=time.time()
        data=self.stream.read(self.waveCHUNK) #录音
        # data=b'\x00\x00\x00\x00\xff\xff'
        # print(data)
        # print(len(data),type(data))

        self.data = data
        filter_data=self.filter(data,0,600)   ###这个要转成16进制进行播放
        # print(filter_data)
        # print(filter_data)
        # print(len(filter_data))

        # print(wave_data)
        t11=time.time()
        # print(t11-t00)
        # #
        # print(len(data))
        # print(len(filter_data))
        # print(data==filter_data)
        # x=np.linspace(0,len(filter_data),len(filter_data))
        # plt.subplot(2,1,1)
        # plt.plot(x,data)
        # plt.subplot(2,1,2)
        # plt.plot(x,filter_data)
        # print(len(wave_data),type(wave_data))
        # print(wave_data)
        # print("###########################")
        # print(data)
        # print(wave_data)
        self.stream1.write(data) #播放
        self.wf.writeframes(data)#写入存储
        self.wf1.writeframes(filter_data)#写入存储
        return data,filter_data



        # print(len(self.dataall))
        # b=time.time()
        # print(b-a)
        # print(data)
        return data

    def Dynamic_micwave_init(self):#动态显示图像-初始化图像

        self.ax[0].set_xlim(0, 1/self.fps)
        self.ax[1].set_xlim(0,2000)

        ln, = self.ax[0].plot([], [], animated=False)
        return ln,  # 返回曲线

    def Dynamic_micwave_update(self,n):#动态显示图像-更新图像

        # print(self.data)
        # b=time.time()
        # d=b-self.a
        # self.a=b
        # self.c+=d
        # print(self.c)
        x, y = self.wavehex_to_DEC_n(self.data, self.wavewidth, self.wavechannel)

        # self.dataall=np.append(self.dataall,y[0])
        # self.b+=len(y[0])
        # x_t = np.linspace(0, self.c, self.b)
        # y_t = self.dataall
        # # print(len(x_t),len(y_t))
        # # print(len(self.dataall))
        # if self.c>10:
        #     print(self.c)
        #     self.ax[0].set_xlim(self.c-10, self.c)
        # # print(len(self.dataall))
        fre_x,fre_y=self.to_fft(self.waveCHUNK,y[0])

        ln, = self.ax[0].plot(x, y[0], "g-")
        # print("###############")
        # print(len(fre_y))
        ln1, = self.ax[1].plot(fre_x, fre_y, "g-")

        return ln,ln1,

    def Dynamic_micwave_run(self): #动态显示图像

        ani = FuncAnimation(self.fig, self.Dynamic_micwave_update,
                            interval=1000/self.fps, init_func=self.Dynamic_micwave_init, blit=True)
        plt.show()

    def filter(self,data,m,n):
        x,DEC_data=self.wavehex_to_DEC_n(data,self.wavewidth,self.wavechannel)
        self.to_fft(self.waveCHUNK, DEC_data[0])
        # print(DEC_data[0][0:10])
        # print(fre_x[-1])
        # print(DEC_data)
        a=int(m*(self.waveCHUNK-1)/self.framerate)
        b=int(n*(self.waveCHUNK-1)/self.framerate)

        # print("#####")
        # print(len(self.fft_int))
        # print(a,b)
        # print(self.fft_int[0:10])
        self.fft_int[a:b]=0
        self.fft_int[-b:-a]=0

        # print(self.fft_int[0:10])
        # print(self.fft_int)
        ifft_y = np.fft.ifft(self.fft_int).real
        # print(ifft_y[0:10])
        ifft_y=np.trunc(ifft_y)
        wave_data = self.DEC_to_wavehex(ifft_y)
        return wave_data



# a=Audiowave().wavedraw1(r"E:\pythonProject2\wav\test.wav")
# a=Audiowave().wavedrawall(r"E:\pythonProject2\wav\P月23日 下午1点03分.wav")
# a=Audiowave().Dynamic_run(r"E:\pythonProject2\wav\test.wave")
# b=b'\xfc\xff\x0b\x00\x11\x00\x10\x00\r\x00\x0c\x00\x0b\x00\t\x00\x08\x00\x08\x00\x06\x00\x06\x00\x04\x00\x03\x00\x02\x00\x00\x00\x00\x00\xfe\xff\xfd\xff\xfb\xff\xff'
#
# a=Audiowave().wavehex_to_DEC(b,2,2)
# print(a)



a=Audiowave()

def recorder_run():
    while True:
        a.micdata()

def draw_run():
    a.Dynamic_micwave_run()

#
#
if __name__ == '__main__':
    t1 = threading.Thread(target=recorder_run,args=())     # target是要执行的函数名(不是函数),args是函数对应的参数,以元组的形式存在
    # t2 = threading.Thread(target=draw_run,args=())
    # t2.setDaemon(True)
    t1.setDaemon(True)
    t1.start()
    a.Dynamic_micwave_run()





实时显示效果如下:

Python实现mic录音实时播放、实时显示波形及频谱_第1张图片

 

你可能感兴趣的:(python,开发语言,可视化)