我使用以下代码进行一些即时声音处理/分析 . 它工作,但真的很慢(与计划的速度相比) . 我添加了一些时间标记来找出问题所在,并根据它们不应该有任何问题 . 所有三个计算时间的典型持续时间(见下文)<0.01 s,但完成循环仍需要大约一秒钟 . 问题出在哪儿?
Edit: 请注意,时间测量不是真正的问题 . 为了证明: MyPeaks
基本上只找到相当短的FFT的最大值 - 没什么代价 . 即使这些例程被注释掉,问题仍然存在 .
-
我应该使用与lambda函数不同的东西来制作循环吗?
-
启动和录制流时是否犯了一些错误?
-
等
import pyaudio
import struct
import mute_alsa
import time
import numpy as np
from Tkinter import *
def snd_process(k=0):
if k<1000:
t0=time.clock()
data = stream.read(CHUNK)
t1=time.clock()
fl=CHUNK
int_data = struct.unpack("%sh" %str(fl),data)
ft=np.fft.fft(int_data)
ft=np.fft.fftshift(ft)
ft=np.abs(ft)
t2=time.clock()
pks=MyPeaks(np.log(ft))
freq_out.configure(text=str(pks))
t3=time.clock()
print t1-t0, t2-t1, t3-t2
master.after(1, lambda: snd_process(k+1))
CHUNK = 8000
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 4000
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
#Tkinter stuff
master=Tk()
button_play=Button(master, command=snd_process, bg="yellow", text="Analyze")
button_play.grid(row=0, column=0)
freq_out = Label(master)
freq_out.grid(row=0, column=1)
freq_out.configure(text='base')
mainloop()
3 回答
您正在tk主线程中安排1000个回调;对于每个回调,你使用1毫秒延迟(
after()
的第一个参数) . 这意味着最后一个循环将在第一个循环1000毫秒(1秒)后开始 .也许这就是循环仍然需要大约一秒才能完成的方式 .
所以,尝试使用
after_idle()
. 我认为你真的不需要加速声音处理算法,因为np
已经非常有效 .[EDIT] 惊喜!!你在每次迭代时从音频通道读取1秒8000字节,16位格式,4000帧速率 . 你需要一秒钟才能拥有它 .
像往常一样将I / O和计算压缩到主循环中是经典的解决方案 . 但也有其他选择 .
在第二个线程中进行音频采集和计算 . 由于I / O和numpy都应该释放GIL,因此它可能是一个很好的选择 . 这里有一个警告 . 由于像TKinter这样的GUI工具包通常不是多线程安全的,所以不应该从第二个线程进行Tkinter调用 . 但是你可以设置一个用
after
调用的函数来检查计算的进度,并且每100毫秒更新一次UI .在不同的
multiprocessing.Process
中进行音频采集和计算 . 这使它与GUI完全分离 . 您必须设置一个通信渠道,例如: aQueue
将pks
发送回主进程 . 您应该使用after
函数来检查Queue
是否有可用数据,如果是,则更新显示 .根据操作系统,您需要're running at you might nog be measuring actual '挂钟时间 . 有关详细信息,请参见http://pythoncentral.io/measure-time-in-python-time-time-vs-time-clock/ . 请注意,对于python 3.3,不推荐使用time.clock,建议使用time.process_time()或time.perf_counter() .