前言

最近同学有个作业,做音乐可视化播放器,为了学习PyQt,我就尝试做了做。该设计主要分为音乐播放器可视化两部分。两部分单独做相对于结合在一起容易很多,结合的过程遇到了很多麻烦。

音乐播放器:

  • 采用QtDesigner进行界面设计。
  • 采用PyQt5.QtMultimedia进行功能设计,包含文件读取、播放、暂停、进度条、时间显示。

可视化:

  • 采用pydub结合ffmpeg将.mp3转成.wav。
  • 采用wave读取音频文件(.wav)。
  • 采用matplotlib.animation方法动态显示图像。

参考博客:
1 python 将MP3格式转换为WAV格式(ffmpeg安装,使用pycharm安装包)
2 pyqt5+matplotlib+Funcanimation+scatter(qt5+动态散点图)
3 python 音频可视化


正文开始

  • 一 界面设计
    • 1.1 QtDesigner界面设计
    • 1.2 导出代码
  • 二 播放器及可视化
    • 2.1 演示效果
    • 2.2 代码:

一 界面设计

1.1 QtDesigner界面设计

界面设计采用QtDesigner进行设计,如下图:

包含对象如下:

1.2 导出代码

使用pyuic编译出.py代码。

# -*- coding: utf-8 -*-# Form implementation generated from reading ui file 'gui.ui'
#
# Created by: PyQt5 UI code generator 5.14.1
#
# WARNING! All changes made in this file will be lost!from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_MainWindow(object):def setupUi(self, MainWindow):MainWindow.setObjectName("MainWindow")MainWindow.resize(449, 439)MainWindow.setAnimated(True)self.centralwidget = QtWidgets.QWidget(MainWindow)sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)sizePolicy.setHorizontalStretch(0)sizePolicy.setVerticalStretch(0)sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())self.centralwidget.setSizePolicy(sizePolicy)self.centralwidget.setObjectName("centralwidget")self.layoutWidget = QtWidgets.QWidget(self.centralwidget)self.layoutWidget.setGeometry(QtCore.QRect(11, 11, 431, 30))self.layoutWidget.setObjectName("layoutWidget")self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.layoutWidget)self.horizontalLayout_2.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)self.horizontalLayout_2.setObjectName("horizontalLayout_2")self.lab_name = QtWidgets.QLabel(self.layoutWidget)sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum)sizePolicy.setHorizontalStretch(0)sizePolicy.setVerticalStretch(0)sizePolicy.setHeightForWidth(self.lab_name.sizePolicy().hasHeightForWidth())self.lab_name.setSizePolicy(sizePolicy)self.lab_name.setAlignment(QtCore.Qt.AlignCenter)self.lab_name.setObjectName("lab_name")self.horizontalLayout_2.addWidget(self.lab_name)self.btn_openFile = QtWidgets.QPushButton(self.layoutWidget)sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Maximum)sizePolicy.setHorizontalStretch(0)sizePolicy.setVerticalStretch(0)sizePolicy.setHeightForWidth(self.btn_openFile.sizePolicy().hasHeightForWidth())self.btn_openFile.setSizePolicy(sizePolicy)self.btn_openFile.setObjectName("btn_openFile")self.horizontalLayout_2.addWidget(self.btn_openFile)self.layoutWidget1 = QtWidgets.QWidget(self.centralwidget)self.layoutWidget1.setGeometry(QtCore.QRect(11, 400, 431, 30))self.layoutWidget1.setObjectName("layoutWidget1")self.horizontalLayout = QtWidgets.QHBoxLayout(self.layoutWidget1)self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetMaximumSize)self.horizontalLayout.setContentsMargins(0, 0, 0, 0)self.horizontalLayout.setObjectName("horizontalLayout")self.lab_time = QtWidgets.QLabel(self.layoutWidget1)sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)sizePolicy.setHorizontalStretch(0)sizePolicy.setVerticalStretch(0)sizePolicy.setHeightForWidth(self.lab_time.sizePolicy().hasHeightForWidth())self.lab_time.setSizePolicy(sizePolicy)self.lab_time.setObjectName("lab_time")self.horizontalLayout.addWidget(self.lab_time)self.slider_time = QtWidgets.QSlider(self.layoutWidget1)sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum)sizePolicy.setHorizontalStretch(0)sizePolicy.setVerticalStretch(0)sizePolicy.setHeightForWidth(self.slider_time.sizePolicy().hasHeightForWidth())self.slider_time.setSizePolicy(sizePolicy)self.slider_time.setOrientation(QtCore.Qt.Horizontal)self.slider_time.setObjectName("slider_time")self.horizontalLayout.addWidget(self.slider_time)self.lab_duration = QtWidgets.QLabel(self.layoutWidget1)sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)sizePolicy.setHorizontalStretch(0)sizePolicy.setVerticalStretch(0)sizePolicy.setHeightForWidth(self.lab_duration.sizePolicy().hasHeightForWidth())self.lab_duration.setSizePolicy(sizePolicy)self.lab_duration.setObjectName("lab_duration")self.horizontalLayout.addWidget(self.lab_duration)self.btn_start = QtWidgets.QPushButton(self.layoutWidget1)sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Maximum)sizePolicy.setHorizontalStretch(0)sizePolicy.setVerticalStretch(0)sizePolicy.setHeightForWidth(self.btn_start.sizePolicy().hasHeightForWidth())self.btn_start.setSizePolicy(sizePolicy)self.btn_start.setObjectName("btn_start")self.horizontalLayout.addWidget(self.btn_start)self.verticalLayoutWidget = QtWidgets.QWidget(self.centralwidget)self.verticalLayoutWidget.setGeometry(QtCore.QRect(10, 40, 431, 361))self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")self.container = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)self.container.setContentsMargins(0, 0, 0, 0)self.container.setObjectName("container")MainWindow.setCentralWidget(self.centralwidget)self.retranslateUi(MainWindow)QtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow):_translate = QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate("MainWindow", "音乐播放器"))self.lab_name.setText(_translate("MainWindow", "暂无歌曲导入"))self.btn_openFile.setText(_translate("MainWindow", "打开文件"))self.lab_time.setText(_translate("MainWindow", "00:00"))self.lab_duration.setText(_translate("MainWindow", "00:00"))self.btn_start.setText(_translate("MainWindow", "播放"))

二 播放器及可视化

输入音频格式为mp3wav,如果输入mp3会自动将其转换为wav进行下一步处理,mp3wav需要安装ffmpeg。

为什么要将 mp3 转成 wav 格式的文件?
因为 mp3 格式为了减小体积牺牲了音质,转成无损的 wav格式之后,可以读取到更详细的信息。如果未安装ffmpeg,建议导入wav文件。

2.1 演示效果


视频播放链接:https://www.bilibili.com/video/av95442718/

2.2 代码:

from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog
from PyQt5.QtMultimedia import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.animation import FuncAnimation
from gui.gui import Ui_MainWindow
from scipy.signal import detrend
from pydub import AudioSegmentimport matplotlib.pyplot as plt
import numpy as np
import struct
import wave
import os
import sys
import timechunk = 1024# 将该路径文件从mp3转为wav
def change_format(path):new_path = path.replace('mp3', 'wav')# 将mp3文件转换成wavsound = AudioSegment.from_mp3(path)sound.export(new_path, format="wav")# FigureCanvas 对象
class MyMplCanvas(FigureCanvas):def __init__(self, parent=None, width=5, height=4, dpi=100):fig = plt.figure(figsize=(width, height), dpi=dpi, facecolor='#f0f0f0')       # facecolor 背景色self.ax = fig.gca(projection='polar')self.ax.set_axis_off()self.ln, = self.ax.plot([], [])FigureCanvas.__init__(self, fig)class MyWindow(QMainWindow, Ui_MainWindow):def __init__(self):super(MyWindow, self).__init__()self.setupUi(self)self.initialize()'''初始化'''def initialize(self):self.setWindowTitle("音乐播放器^_^")self.setWindowIcon(QIcon('icon/音乐.png'))self.fileName = ""self.cur_song = ''self.is_pause = Trueself.y_temp = np.zeros(chunk)self.playlist = QMediaPlaylist()  # 播放列表self.playlist.setPlaybackMode(QMediaPlaylist.Loop)  # 列表循环self.player = QMediaPlayer(self)self.player.setPlaylist(self.playlist)self.player.setVolume(50.0)# 按键self.btn_openFile.clicked.connect(lambda: self.btn_openFile_click())self.btn_start.clicked.connect(lambda: self.btn_start_click())# 进度条self.slider_time.sliderMoved[int].connect(lambda: self.player.setPosition(self.slider_time.value()))# 计时器:控制进度条和进度时间self.timer = QTimer(self)self.timer.start(1000)self.timer.timeout.connect(self.player_timer)# 音乐可视化self.isualization()# 坐标初始化def init_draw(self):self.canvas.ax.set_ylim(-0.1, 0.1)self.canvas.ln.set_data(np.linspace(0, 2 * np.pi, chunk), np.zeros(chunk))return self.canvas.ln,# 坐标更新def update_line(self, frame):if self.is_pause is False:data = self.wf.readframes(chunk)data_int = struct.unpack(str(chunk * 4) + 'B', data)y_detrend = detrend(data_int)yft = np.abs(np.fft.fft(y_detrend))y_vals = yft[:chunk] / (chunk * chunk * 4)ind = np.where(y_vals > (np.max(y_vals) + np.min(y_vals)) / 2)y_vals[ind[0]] *= 3self.y_temp = y_valselse:y_vals = self.y_temp       # 当暂停时,保存的是上一次的值self.canvas.ln.set_ydata(y_vals)return self.canvas.ln,# 音乐可视化def isualization(self):self.canvas = MyMplCanvas(self.container, width=6, height=6, dpi=100)self.container.addWidget(self.canvas)  # 6self.ani = FuncAnimation(self.canvas.figure, self.update_line, init_func=self.init_draw, interval=32, blit=True)# 设置进度条和播放时间def player_timer(self):self.slider_time.setMinimum(0)self.slider_time.setMaximum(self.player.duration())self.slider_time.setValue(self.slider_time.value() + 1000)self.lab_time.setText(time.strftime('%M:%S', time.localtime(self.player.position() / 1000)))self.lab_duration.setText(time.strftime('%M:%S', time.localtime(self.player.duration() / 1000)))# 进度条满了之后回零if self.player.duration() == self.slider_time.value():self.slider_time.setValue(0)# 打开音乐文件,并添加至playlistdef btn_openFile_click(self):self.playlist.clear()     # 读取歌曲前,清空playlistself.fileName, filetype = QFileDialog.getOpenFileName(self, '选择文件', '', '音频文件 (*.mp3; *.wav)')if len(self.fileName) == 0:print("取消选择")returnelse:print('当前歌曲路径:' + self.fileName)self.cur_song = os.path.basename(self.fileName)self.lab_name.setText(self.cur_song)# 如果是mp3格式,则将mp3转换wav,保存到同一目录下if self.cur_song[-3:] == 'mp3':change_format(self.fileName)self.fileName = self.fileName.replace('mp3', 'wav')print('new'+ self.fileName)# 将音频文件添加到playlistself.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(self.fileName)))# 可视化部分waveself.wf = wave.open(self.fileName)# 正在播放音乐时,中断播放if self.is_pause is False:self.player.pause()self.btn_start.setText('播放')def btn_start_click(self):if self.is_pause:self.is_pause = Falseself.player.play()self.btn_start.setText('暂停')print('当前播放歌曲: ' + self.cur_song)else:self.is_pause = Trueself.player.pause()self.btn_start.setText('播放')if __name__ == '__main__':app = QApplication(sys.argv)myWin = MyWindow()myWin.show()sys.exit(app.exec_())

【Python】音乐可视化播放器(PyQt5 + matplotlib.animation)相关推荐

  1. 用Python实现序列帧播放器

    用Python实现序列帧播放器 注意 以下所有代码不可直接使用,若要使用请到百度网盘上下载源码! 链接:https://pan.baidu.com/s/1P0x8ddbnn5veFnFQJLQ0tw ...

  2. 解决Chrome浏览器打开虾米音乐网页播放器时的排版问题

    2019独角兽企业重金招聘Python工程师标准>>> 几年了,虾米音乐网页播放器听音乐都有个纠结的地方,就是用Chrome浏览器打开时,排版会出错,表现为播放器右边一部分显示不出来 ...

  3. 网易云音乐——歌曲播放器页面

    网易云音乐--歌曲播放器页面 git地址 https://gitee.com/chen-haibin799/netease-cloud-music.git 实现步骤 效果图 1.实现顶部导航栏 这个写 ...

  4. html在线音频播放器实训总结,HTML5音乐列表播放器SMusic开发总结

    前段时间写过一篇介绍简单音乐播放器效果开发的博文<为你的博客添加简单的CSS3音乐播放器>,实现了单曲循环播放效果,这个效果也是我的博客首页一直有的效果,同时文中也介绍了一些简单的HTML ...

  5. 【如意影视】运营级+完整类库+解析线路+无限增加或删减解析接口+如意可视化播放器1.1

    简介: 1.后台了无限增加或删减接口(测试程序的接口都是百度找的) 2.未登入用户所有影片只能观看前6分钟(快进超过6分钟直接提示),后提示登入 3.非会员用户只能观看前6分钟(快进超过6分钟直接提示 ...

  6. python生成USB播放器歌单

    用python生成USB播放器歌单 个人比较喜欢听歌,前段时间还买了个可以插U盘和储存卡的播放器,它支持直接按数字跳转歌曲,但自己却不知道歌曲对应的号码. 测试发现歌曲顺序并不是按文件名排序,也不是按 ...

  7. android第三方开源音频播放器,Android第三方开源SeekBarCompat:音乐类播放器等APP进度条常用...

     Android第三方开源SeekBarCompat:音乐类播放器等APP进度条常用 Android平台原生的SeekBar设计简单,然而,比如现在流行的一些音乐播放器的播放进度控制条,如果直接使 ...

  8. android图片本地播放器下载,安卓音乐照片播放器

    音乐照片播放器app是一个给力的图像工具,可以提供非常好用的幻灯片播放功能,同时还有超级享受的相册图库应用功能,音乐照片播放器app在西西软件园下载之后,你绝对不会后悔的. 功能介绍 用户通过软件可以 ...

  9. 用Python制作简易播放器(电子钢琴) mac系统

    用Python制作简易播放器(电子钢琴) 开发环境:Python3.7 Mac OS 思路: 先根据需要设计GUI的样式,并思考需要定义什么功能 把功能写出来 把功能填入GUI之中 用曲子测试完整的程 ...

最新文章

  1. Log4net中的RollingFileAppender解析
  2. 微信小程序设置云函数使用的环境
  3. MySQL删除数据表(DORP TABLE语句)
  4. 【拥抱大厂系列】面试官100%会严刑拷打的 CMS 垃圾回收器,下次面试就拿这篇文章怼回去!
  5. 亿级流量系统架构演进之路
  6. Apache HttpClient库的日志级别设置原理
  7. My in 2007
  8. scala解析xml_Scala XML处理–文字,序列化,解析,保存和加载示例
  9. HTML在线visio进行简单布局,visio2007教程
  10. win7笔记本外接显示器html,win7系统笔记本怎样外接一个显示器
  11. DataGrip 保姆级教程 !
  12. FPGA基础之cyclone_iv资源概述
  13. 方面级情感分析论文阅读《A Survey on Aspect-Based Sentiment Analysis: Tasks, Methods, and Challenges》
  14. python的dispatch_win32com.client.Dispatch()函数用法
  15. 【年终总结】你好2021,再见2020。
  16. 支付宝支付接口、支付宝订单查询接口 前端为APP
  17. 蓝奏云分享链接打不开修改host
  18. 汽车SoC安全故障的自动识别(下):案例展示和指标分析
  19. 如何给导师发邮件?【附带邮件模板】
  20. 基于GMapping的栅格地图的构建

热门文章

  1. ZOJ 3328 Wu Xing (五行相生相克找关系)
  2. VL31N创建内向交货函数GN_DELIVERY_CREATE及增强字段
  3. HDMI ite6801的开发板
  4. 常见的100个推广创意
  5. 比尔-盖茨2010年年信:世界首富的幸福观
  6. 【DispNet_CVPR_2016】论文阅读之一
  7. 蓝桥杯例题练习(简单)--绘制四叶风车
  8. PV操作每日一题-吸烟者问题
  9. 摘自《PPT设计思维》
  10. 新概念2 课文和单词(6)