音频图表.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 命令生成可执行文件后,我尝试从平板电脑运行程序,但没有成功(应用程序几乎崩溃)。
任何建议都会很有用,克里斯·帕帕斯
- 我用 pyqtgraph 做了一个类似的程序,但它有同样的延迟问题......:/