我们还是先来看看代码👇:

import pyaudio
import time
import threading
import wave
import winsound
import matplotlib.pyplot as pl
import numpy as np
import sys
from PyQt5.Qt import *


class Recorder:
    def __init__(self, chunk=1024, channels=2, rate=64000):
        self.CHUNK = chunk
        self.FORMAT = pyaudio.paInt16
        self.CHANNELS = channels
        self.RATE = rate
        self._running = True
        self._frames = []

    def start(self):
        threading._start_new_thread(self.__recording, ())

    def __recording(self):
        self._running = True
        print('start recording')
        self._frames = []
        p = pyaudio.PyAudio()
        stream = p.open(format=self.FORMAT,
                        channels=self.CHANNELS,
                        rate=self.RATE,
                        input=True,
                        frames_per_buffer=self.CHUNK)
        while (self._running):
            data = stream.read(self.CHUNK)
            self._frames.append(data)
        stream.stop_stream()
        stream.close()
        p.terminate()

    #def stop(self):
        self._running = False

    def save(self):
        self._running = False


        p = pyaudio.PyAudio()

        wf = wave.open("001.wav", 'wb')
        wf.setnchannels(self.CHANNELS)
        wf.setsampwidth(p.get_sample_size(self.FORMAT))
        wf.setframerate(self.RATE)
        wf.writeframes(b''.join(self._frames))
        wf.close()
        print("Saved")

    def play(self):
        winsound.PlaySound("001.wav", winsound.SND_FILENAME)
        # 打开wav文档
        file = wave.open("001.wav", "rb")

        # 读取参数信息
        # nchannels, sampwidth, framerate, nframes, comptype, compname
        params = file.getparams()
        nchannels, sampwidth, framerate, nframes = params[:4]
        print(params)

        # 将字符转格式的数据转成int型
        str_data = file.readframes(nframes)
        wave_data = np.frombuffer(str_data, dtype=np.short)

        # 归一化
        wave_data = wave_data * 1.0 / max(abs(wave_data))

        # 将音频信号规整成每行一路通道信号的格式,即该矩阵一行为一个通道的采样点,共nchannels行
        wave_data = np.reshape(wave_data, [nframes, nchannels]).T  # T表示转置
        print(wave_data)

        # 文件使用完毕,关闭文件
        file.close()

        # 绘制语音波形
        time = np.arange(0, nframes) * (1.0 / framerate)  # 时间=n/fs
        time = np.reshape(time, [nframes, 1]).T
        pl.plot(time[0, :nframes], wave_data[0, :nframes], c="b")
        pl.xlabel("time(seconds)")
        pl.ylabel("amplitude")
        pl.title("original wave")
        pl.show()



#创建应用程序
app = QApplication(sys.argv)
re = Recorder()

#创建窗口
window = QWidget()
window.setWindowTitle("111")
window.resize(500,500)

btn1 = QPushButton(window)
btn1.move(100, 50)
btn1.setText("播放并画图")
btn1.clicked.connect(re.play)

btn2 = QPushButton(window)
btn2.move(100, 90)
btn2.setText("开始录音")
btn2.clicked.connect(re.start)

btn3 = QPushButton(window)
btn3.move(100, 130)
btn3.setText("结束录音")
btn3.clicked.connect(re.save)

#lable.show()
window.show()

#等待窗口停止
sys.exit(app.exec())

这个程序是在原有的程序上使用PyQt5进行了GUI界面的改进。详细代码请见:用python编写录音机——通过输入控制录音的开始和结束


这里引入了第三方库:PyQt5。在使用之前,需要先在pip中进行安装,并import引入。

PyQt5这个第三方库功能比较强大,所以占用的空间就比较大,安装时间可能会稍长,请耐心等待。

使用PyQt5编写,实现GUI有两种方法:第一种是在designer中进行拖拽,然后形成.py文件后,将按键与按键后所执行的代码进行关联;第二种是直接在.py文件中进行代码的编写,以实现在界面中放置对应元件的目的。因为第一种方法生成的.py文件比较冗长,而录音机所需的要求并不是很严苛,所以本文运用了第二种方式进行编写。


与上一个程序相比,增加的部分为主程序的部分:

#创建应用程序
app = QApplication(sys.argv)
re = Recorder()

#创建窗口
window = QWidget()
window.setWindowTitle("111")
window.resize(500,500)

btn1 = QPushButton(window)
btn1.move(100, 50)
btn1.setText("播放并画图")
btn1.clicked.connect(re.play)

btn2 = QPushButton(window)
btn2.move(100, 90)
btn2.setText("开始录音")
btn2.clicked.connect(re.start)

btn3 = QPushButton(window)
btn3.move(100, 130)
btn3.setText("结束录音")
btn3.clicked.connect(re.save)

#lable.show()
window.show()

#等待窗口停止
sys.exit(app.exec())

这里详细说明一下创建窗口和按钮的部分:

先是创建窗口:

window = QWidget()#创建窗口
window.setWindowTitle("111")#给窗口命名
window.resize(500,500)#规定窗口大小


然后是创建按键:

btn1 = QPushButton(window)#将按键放置到创建的窗口中
btn1.move(100, 50)#定义按键位置
btn1.setText("播放并画图")#按键名称
btn1.clicked.connect(re.play)#按下按键所关联的函数,即按键功能

 另外说明:按键位置的坐标采用笛卡尔坐标系,坐上为坐标原点,分别以向右,向下为正方向。