需求

  • 打开音频文件
  • 录音
  • 播放打开的音频文件或录音
  • 将音频文件转为频谱图等(具体需要转换图的形式后续增加)
  • 裁剪音频
  • 将音频中人声与背景音乐声音的分离(需要自己训练模型)

界面代码

选择python,页面采用第三方库pyqt5。
对于界面的布局,简单如下所示:

# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QAction, qAppclass Example(QMainWindow):def __init__(self):super().__init__()self.initUI()  # 界面绘制交给InitUi方法def initUI(self):# 设置窗口的位置和大小self.setGeometry(300, 300, 800, 520)# 创建一个菜单栏menubar = self.menuBar()# 添加菜单fileMenu = menubar.addMenu('&选择文件')imageMenu = menubar.addMenu('&更多图像')functionMenu = menubar.addMenu('&功能')filterMenu = menubar.addMenu('&音频提取')# self.statusBar()openAction = QAction('打开文件', self)openAction.setShortcut('Ctrl+F')openAction.setStatusTip('打开所需的音频文件')openAction.triggered.connect(self.getfile)spectrogramAction = QAction('频谱图', self)spectrogramAction.triggered.connect(self.getfile)recordAction = QAction('录音', self)recordAction.triggered.connect(self.getfile)playAction = QAction('播放', self)playAction.triggered.connect(self.getfile)cutAction = QAction('截取', self)cutAction.triggered.connect(self.getfile)separateAction = QAction('音频分离', self)separateAction.triggered.connect(self.getfile)# 添加事件fileMenu.addAction(openAction)imageMenu.addAction(spectrogramAction)functionMenu.addAction(recordAction)functionMenu.addAction(playAction)functionMenu.addAction(cutAction)filterMenu.addAction(separateAction)# 显示窗口self.show()def getfile(self):return 0if __name__ == '__main__':# 创建应用程序和对象app = QApplication(sys.argv)ex = Example()sys.exit(app.exec_())

大体样子:

打开文件弹出弹框

功能介绍,首先要打开我们所选择的wav文件,其代码如下:

openfile_name = QFileDialog.getOpenFileName(self, '选择文件', '', 'wav files(*.wav)')

其次,要弹出弹框,对于弹出弹框,采用的是MDI框架框架,即主要组件为QMdiArea和QMdiSubWindow,其中QMdiArea一般使用于主窗口中,用于容纳多个子窗口QMdiSubWindow。
主要代码如下:

class MainWindow(QMainWindow):count = 0def __init__(self,parent=None):super(MainWindow, self).__init__(parent)self.initUI()  # 界面绘制交给InitUi方法# 实例化Qmidarea区域self.mdi = QMdiArea()# cascadeSubWindows():安排子窗口在Mdi区域级联显示self.mdi.cascadeSubWindows()# 设置为中间控件self.setCentralWidget(self.mdi)def initUI(self):...def getfile(self):openfile_name = QFileDialog.getOpenFileName(self, '选择文件', '', 'wav files(*.wav)')if openfile_name[0]!='':print(openfile_name)self.count = self.count + 1# 实例化多文档界面对象sub = QMdiSubWindow()# 向sub内部添加控件sub.setWidget(QTextEdit())sub.setWindowTitle("subWindow %d" % self.count)self.mdi.addSubWindow(sub)sub.show()else:print("取消音频文件")return 0

将Matplotlib生成的图像用pyqt5展示出来

绘制WAV文件的波形

librosa.display.waveplot

librosa.display.waveplot(y,sr = 22050,max_points = 50000.0,x_axis =‘time’,offset = 0.0,max_sr = 1000,ax = None, kwargs )
绘制波形的幅度包络线。

  • 如果y是单声道的,则在[-abs(y),abs(y)]之间绘制一条填充曲线。
  • 如果y为立体声,则在[-abs(y [1]),abs(y [0])]之间绘制曲线,以便分别在轴的上方和下方绘制左通道和右通道。
    在绘制之前,长信号(duration >= max_points)被下采样至最高max_sr。

参数:

  • y :np.ndarray [shape =(n,)或(2,n)] 音频时间序列(单声道或立体声)
  • sr :数字> 0 [标量] y的采样率
  • max_points :正数或无 要绘制的最大时间点数:如果max_points超过y的持续时间,则对y进行下采样。如果为None,则不执行下采样。
  • x_axis :str或无 显示x轴刻度和刻度标记。可接受的值为: ‘time’ :标记以毫秒,秒,分钟或小时显示。值以秒为单位绘制。 ‘s’:标记显示为秒。 ‘ms’:标记以毫秒为单位显示。
    “lag”:与时间一样,但超过中途点则视为负值。 ‘lag_s’:与滞后相同,但以秒为单位。
    ‘lag_ms’:与lag相同,但以毫秒为单位。 None,‘none’或’off’:刻度线和刻度线标记被隐藏。
  • ax:matplotlib.axes.Axes or None 要绘制的轴,而不是默认的plt.gca()。
  • offset:float 水平偏移(以秒为单位)以开始波形图
  • max_sr :数字> 0 [标量] 可视化的最大采样率

具体可参考原文档https://librosa.org/librosa/generated/librosa.display.waveplot.html

利用matplotlib中FigureCanvasXAgg将图像渲染到qt上

采用的技术:基于PyQt Canvas Matplotlib图形绘制
(1)首先实现一个画布
画布MatplotlibWidget继承MyMplCanvas,
MyMplCanvas继承matplotlib.backends.backend_qt5agg.FigureCanvasQTAgg类
其中MyMplCanvas画布中通过tup,将画布分为一个或者两个子plot。

from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5 import NavigationToolbar2QT as NavigationToolbar
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.pyplot as plt
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QSizePolicy
from matplotlib import axesimport matplotlibmatplotlib.use("Qt5Agg")# 画布控件继承自matplotlib.backends.backend_qt5agg.FigureCanvasQTAgg类
class MyMplCanvas(FigureCanvas):# tup(x1,x2)——x1->行,x2->列,你明明全是tup(1,1)def __init__(self, tup, width=5, height=4, dpi=100):plt.rcParams['font.family'] = ['SimHei']plt.rcParams['axes.unicode_minus'] = Falseself.fig = Figure(figsize=(width, height), dpi=dpi)self.tup=tupself.checknumber(self.tup[0]*self.tup[1])# 调用基类的初始化函数FigureCanvas.__init__(self, self.fig)# self.setParent(parent)# 尺寸缩放策略FigureCanvas.setSizePolicy(self,QSizePolicy.Expanding,QSizePolicy.Expanding)FigureCanvas.updateGeometry(self)def checknumber(self,number):if number==1:self.createaxes1()if number==2:self.createaxes2()def createaxes1(self):self.axes = self.fig.add_subplot(111)def createaxes2(self):self.axes1 = self.fig.add_subplot(211)self.axes2 = self.fig.add_subplot(212)# 再继承一个自定义画布控件类
class MatplotlibWidget(QWidget):def __init__(self, tup, parent=None):self.tup = tupsuper(MatplotlibWidget, self).__init__(parent)self.initUi()def initUi(self):self.layout = QVBoxLayout(self)self.mpl = MyMplCanvas(self.tup, width=5, height=4, dpi=100)self.mpl_ntb = NavigationToolbar(self.mpl, self)self.layout.addWidget(self.mpl)self.layout.addWidget(self.mpl_ntb)def getaxes(self):return self.mpl.axesdef getaxes1(self):return self.mpl.axes1def getaxes2(self):return self.mpl.axes2def getntb(self):return self.mpl_ntbdef getfig(self):return self.mpl.fig

(2)将音频数据在画布上加载
用了线程,因为可能会同时打开多个音频,打开音频的操作需要异步操作。因此用到threading,具体threading使用查看本作者前一篇博文。
在重定义的run函数中,首先ibrosa.load(self.audiofile, sr=None)加载了音频,
再librosa.display.waveplot(y, sr, x_axis=‘time’, ax=self.widget.getaxes())展示在画布上

import librosa
import threading
import librosa.displayfrom Matplotlib import MatplotlibWidgetclass WaveDisplayThreadEx(threading.Thread):def __init__(self,audiofile):threading.Thread.__init__(self)self.audiofile=audiofileself.tup=(1,1)self.widget=MatplotlibWidget.MatplotlibWidget(self.tup)# self.bDisplay = Truedef run(self):y, sr = librosa.load(self.audiofile, sr=None)librosa.display.waveplot(y, sr, x_axis='time', ax=self.widget.getaxes())self.widget.show()# def stopdisplay(self):#     self.bDisplay = Falsedef getwidget(self):return self.widget

(3)调用显示音频波形图
start()时候会调用run()

    def getfile(self):self.openfile_name = QFileDialog.getOpenFileName(self, '选择文件', '', 'wav files(*.wav)')if self.openfile_name[0] != '':print(self.openfile_name)self.count = self.count + 1# 实例化多文档界面对象sub = QMdiSubWindow()# 向sub内部添加控件waveui = WaveDisplayThreadEx(self.openfile_name[0])waveui.start()sub.setWidget(waveui.getwidget())sub.setWindowTitle("%s" % self.openfile_name[0])sub.setGeometry(0, 0, 800, 480)self.mdi.addSubWindow(sub)sub.show()else:print("取消音频文件")return 0

录音

涉及到的代码段有recordUi.py(录音功能界面)、Record.py(录音)、WaveDisplay.py(录音过程中实时更新波形图)

录音界面

参考连接https://blog.csdn.net/liang19890820/article/details/51537246

class recordUi(QWidget):def __init__(self, parent=None):super(recordUi, self).__init__(parent)self.setupUi()def setupUi(self):self.resize(543, 416)self.verticalLayout = QtWidgets.QVBoxLayout(self)self.verticalLayout.setContentsMargins(0, 0, 0, 0)self.verticalLayout.setObjectName("verticalLayout")self.verticalLayout.addWidget(self.widget)self.horizontalLayout = QtWidgets.QHBoxLayout()self.horizontalLayout.setObjectName("horizontalLayout")self.pushButton_2 = QtWidgets.QPushButton(self)self.pushButton_2.setObjectName("pushButton_2")self.pushButton_2.setText('开始录音')self.pushButton_2.clicked.connect(self.record)self.horizontalLayout.addWidget(self.pushButton_2)self.pushButton = QtWidgets.QPushButton(self)self.pushButton.setObjectName("pushButton")self.pushButton.setText('停止录音')self.pushButton.clicked.connect(self.stoprecord)self.horizontalLayout.addWidget(self.pushButton)self.verticalLayout.addLayout(self.horizontalLayout)

录音功能

需要wave模块与pyaudio模块相互作用,共同实现。其中wave实现音频文件的存储,pyaudio实现音频文件的录音。
wave写操作:

def save_wave_file(filename,data):'''save the date to the wavfile'''wf=wave.open(filename,'wb')wf.setnchannels(channels)#声道wf.setsampwidth(sampwidth)#采样字节 1 or 2wf.setframerate(framerate)#采样频率 8000 or 16000wf.writeframes(b"".join(data))#https://stackoverflow.com/questions/32071536/typeerror-sequence-item-0-expected-str-instance-bytes-foundwf.close()

pyaudio录音

def get_audio(filepath):isstart = str(input("是否开始录音? (是/否)")) #输出提示文本,input接收一个值,转为str,赋值给aaif isstart == str("是"):pa = PyAudio()stream = pa.open(format=FORMAT,channels=CHANNELS,rate=RATE,input=True,frames_per_buffer=CHUNK)print("*" * 10, "开始录音:请在5秒内输入语音")frames = []  # 定义一个列表for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):  # 循环,采样率 44100 / 1024 * 5data = stream.read(CHUNK)  # 读取chunk个字节 保存到data中frames.append(data)  # 向列表frames中添加数据dataprint(frames)print("*" * 10, "录音结束\n")stream.stop_stream()stream.close()  # 关闭pa.terminate()  # 终结save_wave_file(pa, filepath, frames)elif isstart == str("否"):exit()else:print("无效输入,请重新选择")get_audio(filepath)

参考代码有https://blog.csdn.net/qq_29934825/article/details/82982737
https://blog.csdn.net/qq_36387683/article/details/91901815
https://blog.csdn.net/c602273091/article/details/46502527#pyaudio
结合以上两个功能,即可实现录音的整体功能,如下:
在录音时候利用while循环进行声音的录入,判定条件为bRecord,该值的改变,由停止录音按钮上绑定的一个函数调用stoprecord()函数实现

    def stoprecord(self):self.timer.stop()self.record.stoprecord()

录音实际实现类

import pyaudio
import librosa
import wave
import librosa.display
from PyQt5.QtCore import *
from Matplotlib import MatplotlibWidget
from pydub import AudioSegment
class RecordThread(QThread):def  __init__(self,audiofile='./record.wav',parent=None):super(RecordThread,self).__init__(parent)self.bRecord=Trueself.audiofile=audiofileself.chunk=1024self.format=pyaudio.paInt16self.channels=2self.rate=16000def run(self):audio=pyaudio.PyAudio()wavfile=wave.open(self.audiofile,"wb")wavfile.setnchannels(self.channels)wavfile.setsampwidth(audio.get_sample_size(self.format))wavfile.setframerate(self.rate)wavstream=audio.open(format=self.format,channels=self.channels,rate=self.rate,input=True,frames_per_buffer=self.chunk)# self.dynamic_plot()while self.bRecord:wavfile.writeframes(wavstream.read(self.chunk))wavstream.stop_stream()wavstream.close()def stoprecord(self):self.bRecord=Falsedef __del__(self):self.working=Falseself.wait()

实时更改录音波形

对于一个反复重复的过程,我们可以使用pt中的QTimer,它提供了定时器信号和单触发定时器。

QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1000);

start()之后,每秒都会调用update()。
参考链接https://blog.csdn.net/zz2862625432/article/details/79550285


在本功能实现中:
recordUI.py中定义的函数,setUI中的按钮会调用以下函数功能。

    def record(self):self.record=RecordThread()self.record.start()self.start_dynamic()def start_dynamic(self):time.sleep(0.2)self.wave_display.update()self.timer=QTimer(self)self.timer.timeout.connect(lambda: self.wave_display.update())self.timer.start(100)

以上代码中start(100)即为每100ms会自动执行一次update()函数
以下对应的是self.wave_display.update()函数的具体实现。

from math import piimport librosa
import wave
import librosa.display
import numpy as np
from PyQt5.QtCore import *
from numpy.ma import sin
from scipy.io import wavfilefrom Matplotlib import MatplotlibWidget
from pydub import AudioSegmentclass WaveDisplayThread:def __init__(self,widget,audiofile='./record.wav',parent=None):self.audiofile=audiofileself.bDisplay=Trueself.widget=widgetself.partfile='./part.wav'self.start_time = 0self.end_time = 100self.axes=self.widget.getaxes()self.ntb=self.widget.getntb()def stopdisplay(self):self.bDisplay=Falsedef update(self):self.axes.clear()self.get_ms_part_wav(self.audiofile, self.start_time, self.end_time, self.partfile)y, sr = librosa.load(self.partfile, sr=None)librosa.display.waveplot(y, sr, ax=self.axes)self.ntb.draw()self.start_time += 100self.end_time += 100def getwidget(self):return self.widget# 按照每100sm的初末位置对音频进行截取,获取到当前100sm的音频文件保存在part.wav中,再显示出来波形,方式与上一部分的一致def get_ms_part_wav(self,main_wav_path,start_time,end_time,part_wav_path):start_time=int(start_time)end_time=int(end_time)sound=AudioSegment.from_wav(main_wav_path)part=sound[start_time:end_time]part.export(part_wav_path,format="wav")

音频工具(pyqt)相关推荐

  1. IOS开发基础之音频工具类封装AVAudioPlayer

    IOS开发基础之音频工具类封装AVAudioPlayer 源码在我的主页下面 ,项目名称是AVAudioPlayer 关键性代码 工具类的封装 // // LJAudioTool.h // AVAud ...

  2. ALSA音频工具amixer,aplay,arecord

    ALSA音频工具amixer,aplay,arecord http://www.cnblogs.com/cslunatic/p/3227655.html ALSA音频工具编译安装 ========== ...

  3. 多功能音频工具的旗舰音乐编辑工具!Music Studio

    Ashampoo Music Studio Ashampoo Music Studio 是一款集成了多种音频工具的旗舰级音乐编辑软件,功能包括音频文件编辑.格式转换,抓取 & 刻录音频 CD, ...

  4. 80+的AI音频工具你值得拥有

    80+的AI音频工具你值得拥有 文章目录 AI 文本转语音 AI 音频 AI 音频编辑 AI 音乐 AI 文本转语音 工具 简介 链接 分类 描述1 描述2 是否收费 Blakify Blakify是 ...

  5. C++常用的音频工具库

        由于C++这种语言改装于C语言,它在C语言的基础上加了继承.封装.多态,使编程风格更接近面向对象(OO:object-oriented),在游戏开发.服务器编程.音视频处理.网络通信等领域应用 ...

  6. 常用音频工具介绍与汇总

    音频cluster 常用音频工具介绍与汇总 音频文章 音频网站记录 python工具包 常用音频工具介绍与汇总 音频文章 来源 说明 链接 ESC-50 说明文档中有关于各种深度学习网络在数据集上的表 ...

  7. linux 查看声卡设备并测试录音 (ALSA 音频工具)

    测试环境 ubuntu12 与其他linux 系统大同小异 高级Linux声音体系(英语:Advanced Linux Sound Architecture,缩写为ALSA)是Linux内核中,为声卡 ...

  8. 专业音频工具au 2019 mac 直装版——Audition CC 2019 for Mac 12.1.0.182中文特别版

    Audition CC 2019 Mac版是Mac平台上的一款用于混音.修整和精确编辑的专业音频工具.用于创建.混合.编辑和复原音频内容的多轨.波形和光谱显示功能.该软件最多混合128个声道,可编辑单 ...

  9. amixer 如何切通道_ALSA音频工具amixer,aplay,arecord

    ALSA音频工具编译安装 ========================================================================1.官网http://www. ...

最新文章

  1. 【ubuntu】在ubuntu下无法输出拼音输入法中的中括号“【” 和 “】”的解决方法
  2. 代理上网环境下配置TortoiseCVS
  3. 有哪些好的 LaTeX 编辑器?
  4. 【路由交换实验】OSPF
  5. javascript控制html高,Javascript可以控制css吗?
  6. Spring Integration 4.0:完整的无XML示例
  7. 个人收集一些程序员面试题目(一) 一起分享
  8. Material Design入门
  9. kafka 如何做到1秒发布百万级条消息?
  10. 创建数据库_详解Oracle数据库物化视图及创建物化视图索引
  11. 平安夜、圣诞节设计素材和灵感|撒糖(PNG免扣素材)
  12. visualvm远程监控jvm_别再说你不会 JVM 性能监控和调优了,看完这篇再发言
  13. Oracle锁庞大大引见
  14. 网络安全实验室 基础题 解析
  15. 信息系统项目管理师 第二章 信息系统项目管理基础 核心知识点总结
  16. 2022爱分析·国央企数字化实践报告
  17. (转)JS事件循环和宏任务和微任务
  18. winpe 能否修复服务器系统盘,U盘WINPE、光盘WINPE系统(启动修复盘)制作图文教程...
  19. Coap在Andorid中的简单应用
  20. 简体和繁体之间的转换

热门文章

  1. 利用前三年的数据预测2018年NBA常规赛东西部前八的详细过程和解决思路(19年类似)
  2. Word:无法启动转换器WPFT532 WPFT632 解决方法
  3. 一款神仙接私活低代码平台,吊到不行!
  4. 国产麒麟命令更新软件
  5. there's not enought memory to perform the requrested operation.解决方法
  6. PAT乙级刷题/1094 谷歌的招聘/C++实现
  7. 什么是桩模块?什么是驱动模块?
  8. BSD HD 声卡驱动安装,ntfs-3g安装
  9. c++计算两个日期相隔的天数
  10. php调用itunes.dll,解决iTunes.dll丢失或损坏的问题