首页 > 解决方案 > PyQt5图表实时绘图

问题描述

音频图表.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'audio_chart.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 200)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
        MainWindow.setSizePolicy(sizePolicy)
        MainWindow.setMinimumSize(QtCore.QSize(0, 200))
        MainWindow.setMaximumSize(QtCore.QSize(16777215, 200))
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setSpacing(0)
        self.verticalLayout.setObjectName("verticalLayout")
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Audio chart"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.showMaximized()
    sys.exit(app.exec_())

audio_chart_code.py

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import pyqtSlot
from audio_chart import *
import sys
import pyaudio
from pydub import AudioSegment
import numpy as np
import queue

import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib import dates as mpl_dates
from matplotlib.animation import FuncAnimation


import datetime

class AudioChart:
    def __init__(self):     
        self.app = QtWidgets.QApplication(sys.argv)
        self.MainWindow = QtWidgets.QMainWindow()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self.MainWindow)
        self.MainWindow.showMaximized()
        
        #QoS settings
        self.bit_rate = 128*1024 #128 kb/sec
        self.packet_time = 125 #125 msec
        self.packet_size = int(16384/4)
        
        self.format = pyaudio.paInt16
        self.channels = 2
        
        self.test_sound = AudioSegment.from_file("pokemon.mp3", format="mp3")
        
        slice = self.test_sound[0:1000]
        self.test_sound_1_second_size = len(slice.raw_data)
        self.test_sound_sample_rate = self.test_sound.frame_rate
        self.new_sample_rate = int(self.test_sound_sample_rate*self.bit_rate/self.test_sound_1_second_size)

        self.audio_timedelta = self.packet_time/(2*self.packet_size) #msec
        self.test_sound = self.test_sound.set_frame_rate(self.new_sample_rate)
        
        self.p = pyaudio.PyAudio()
        #self.q = queue.Queue(maxsize=20)
        self.q = queue.Queue()
        self.chunk_number = 0
        
        self.animate_window = 3000 #3 seconds
        
        self.chart = Canvas(self)
        self.chart.ax.set_facecolor((1,1,1))
        #self.chart.ax.spines['top'].set_color('white')
        self.chart.ax.tick_params(labelcolor='white')
        
        
        self.x_vals = []
        self.y_vals = []
        
        self.x_1_vals = []
        self.y_1_vals = []
        
        self.x_2_vals = []
        self.y_2_vals = []
        
        
        self.stream = self.p.open(format=self.format,channels=self.channels,rate=self.new_sample_rate,output=True,stream_callback=self.play_pokemon,frames_per_buffer=self.packet_size)
        
        
        self.stream.start_stream()
        
        self.animate_chunks = self.animate_window/self.packet_time
        self.ani = FuncAnimation(plt.gcf(),self.animate,interval=self.packet_time)
        
        '''
        self.threadpool = QtCore.QThreadPool()  
        worker = Worker(self.start_stream, )
        self.threadpool.start(worker)
        '''
        
        
        
        
        
    def start_stream(self):
        self.stream.start_stream()
        
        self.animate_chunks = self.animate_window/self.packet_time
        self.ani = FuncAnimation(plt.gcf(),self.animate,interval=self.packet_time/2)
        
    def play_pokemon(self,in_data, frame_count, time_info, status):
        slice = self.test_sound[self.chunk_number*(self.packet_time):(self.chunk_number+1)*(self.packet_time)]
        
        self.now = datetime.datetime.now()
        
        frame = np.frombuffer(slice.raw_data, dtype=np.int16)
        #normalized_signal = frame/200000
        
        normalized_signal = frame
        
        '''
        frame = []
        counter = 0
        for audio_number in normalized_signal:
            audio_time = self.now+datetime.timedelta(milliseconds=counter*self.audio_timedelta)
            counter +=1
            frame.append([audio_time,audio_number])
        '''
            
        average_every = len(normalized_signal)/256
        
        frame = []
        self.counter = 0
        total = 0
        for audio_number in normalized_signal:
            #audio_time = self.now+datetime.timedelta(milliseconds=counter*self.audio_timedelta)
            #frame.append([audio_time,audio_number])
            self.counter +=1
            total = total+audio_number
            if(average_every==self.counter):
                audio_average_number = total/self.counter
                if(len(frame)==0):
                    audio_average_time = datetime.datetime(2021,1,1,0,0,0,0)+datetime.timedelta(milliseconds=self.chunk_number*(self.packet_time))
                else:
                    audio_average_time = frame[-1][0]+datetime.timedelta(milliseconds=self.counter*self.audio_timedelta)
                frame.append([audio_average_time,audio_average_number])
                self.counter = 0
                total = 0
                
        
        
        self.q.put(frame)
        
        self.chunk_number = self.chunk_number+1
        return (slice.raw_data, pyaudio.paContinue)
        
    def animate(self,i):
        try:
            while True:
                try:
                    data = self.q.get_nowait()
                    
                    
                    dates_1 = [i[0] for i in data]
                    audio_numbers_1 = [i[1] for i in data]
                    audio_numbers_2 = [i[1]+1 for i in data]
                    audio_numbers_3 = [i[1]-1 for i in data]
                    
                    self.x_vals = self.x_vals+dates_1
                    self.y_vals = self.y_vals+audio_numbers_1
                    
                    self.x_1_vals = self.x_1_vals+dates_1
                    self.y_1_vals = self.y_1_vals+audio_numbers_2
                    
                    self.x_2_vals = self.x_2_vals+dates_1
                    self.y_2_vals = self.y_2_vals+audio_numbers_3
                    
                    if(self.chunk_number>self.animate_chunks):
                        self.x_vals = self.x_vals[len(dates_1)::]
                        self.y_vals = self.y_vals[len(audio_numbers_1)::]
                        
                        self.x_1_vals = self.x_1_vals[len(dates_1)::]
                        self.y_1_vals = self.y_1_vals[len(audio_numbers_1)::]
                        
                        self.x_2_vals = self.x_2_vals[len(dates_1)::]
                        self.y_2_vals = self.y_2_vals[len(audio_numbers_1)::]
                        
                    
                    '''
                    date_1 = data[0]
                    average_number = data[1]
                    
                    self.x_vals.append(date_1)
                    self.y_vals.append(average_number)
                    
                    
                    if(self.chunk_number>self.animate_chunks):
                        self.x_vals = self.x_vals[1::]
                        self.y_vals = self.y_vals[1::]
                    '''
                    
                    plt.cla()
                    
                    self.chart.ax.plot_date(self.x_1_vals,self.y_1_vals,color=(153/255,153/255,0),linestyle='solid',marker=",")
                    
                    self.chart.ax.plot_date(self.x_2_vals,self.y_2_vals,color=(153/255,153/255,0),linestyle='solid',marker=",")
                    
                    self.chart.ax.plot_date(self.x_vals,self.y_vals,color=(0,1,0.29),linestyle='solid',marker=",")
                    
                    
                    date_format = mpl_dates.DateFormatter("%H:%M:%S")
                    plt.gca().xaxis.set_major_formatter(date_format)
                    
                    plt.xticks(fontsize=5)
                    #self.chart.ax.grid(True,linestyle='--')
                    self.chart.ax.grid(False)
                    
                    self.chart.ax.set_xlim([self.x_vals[0],self.x_vals[-1]])
                    
                    
                    ticks = []
                    for timedelta_time in range(0,self.animate_window+1,1000):
                        tick = self.x_vals[0]+datetime.timedelta(milliseconds=timedelta_time)
                        ticks.append(tick)
                    plt.xticks(ticks)
            
        
                except queue.Empty:
                    break
        except:
            pass
        
        return self.chart.ax,
        
class Canvas(FigureCanvas):
    def __init__(self,parent):
        fig , self.ax = plt.subplots(figsize=(5,4),dpi=200)
        
        fig.patch.set_facecolor((6/255,21/255,154/255))
        self.ax.set_position([0., 0, 1., 0.8])
        self.ax.xaxis.tick_top()
        self.ax.tick_params(color=(1,1,1))
        #self.ax.xaxis.set_color((1,1,1))
        super().__init__(fig)
        parent.ui.verticalLayout.addWidget(self)
        
        #t = np.arange(0.0,2.0,0.01)
        #s = 1 +np.sin(2*np.pi*t)
        
        plt.xticks(fontsize=6)
        self.ax.grid(True,linestyle='--')
        
        self.now = datetime.datetime.now()
        self.chart_stop = self.now+datetime.timedelta(milliseconds=3000)
        
        
        plt.cla()
        #self.chart.ax.plot_date(self.x_vals,self.y_vals,color=(0,1,0.29),linestyle='solid')
        date_format = mpl_dates.DateFormatter("%H:%M:%S")
        plt.gca().xaxis.set_major_formatter(date_format)
        
        plt.xticks(fontsize=5)
        self.ax.grid(True,linestyle='--')
        
        self.ax.set_xlim([self.now,self.chart_stop])
        
        plt.xticks([self.now,self.now+datetime.timedelta(milliseconds=1000),self.now+datetime.timedelta(milliseconds=2000)])
        
        self.show()
        

class Worker(QtCore.QRunnable):

    def __init__(self, function, *args, **kwargs):
        super(Worker, self).__init__()
        self.function = function
        self.args = args
        self.kwargs = kwargs

    @pyqtSlot()
    def run(self):

        self.function(*self.args, **self.kwargs)    
        
        
audio_chart = AudioChart()
sys.exit(audio_chart.app.exec_())

使用命令运行程序:运行前,下载精灵宝可梦主题曲python audio_chart_code.py 并将其放在同一目录下。

正如您所听到的 - 看到情节和声音之间存在不匹配延迟。另请注意,在使用 pyinstaller 命令生成可执行文件后,我尝试从平板电脑运行程序,但没有成功(应用程序几乎崩溃)。

任何建议都会很有用,克里斯·帕帕斯

标签: pythonmatplotlibpydubaudiosegment

解决方案


推荐阅读