2016-12-26 66 views
0

我一直在寻找线程和多线程页面和教程整天,我仍然不知道如何实现我所需要的。我有一节课读取音频流,一节用Tkinter(每个人最喜欢的包)对它进行可视化。Python多处理,不知道如何处理

import numpy as np 
from Tkinter import * 
from cmath import exp,pi 
import audioop,time,colorsys,pyaudio 
import multiprocessing 

class Recorder(): 
    def __init__(self): 
     self.p=pyaudio.PyAudio() 
     self.stream=self.p.open(format=pyaudio.paInt16,channels=1,rate=RATE,input=True,frames_per_buffer=CHUNK) 
     self.buff = None 
     self.rms = None 
     self.m = None 
     self.running = True 
     return 
    def run(self,q=None): 
     while self.running: 
      self.buff = np.fromstring(self.stream.read(CHUNK),dtype=np.int16) 
      self.buff = np.fft.fft(self.buff)/CHUNK 
      self.rms = audioop.rms(self.buff,2) 
      self.buff = map(lambda y:(y.real**2+y.imag**2)**(0.5)/(1.516122797*self.rms),self.buff)[:len(self.buff)/2] 
      self.m = float(max(self.buff)) 
    def get(self,q): 
     q.put((self.buff,self.rms,self.m)) 
    def end(self): 
     self.runing = False 
     self.stream.stop_stream() 
     self.stream.close() 
     self.p.terminate() 
class Drawer(): 
    def __init__(self): 
     self.m = 0 
     self.text = '' 
    def draw(self,q): 
     data,rms,m = q.get() 
     if rms == 0: return False 
     if m == 0: return False 
     nData = list() 
     i = 1 
     while i*2 < len(data): 
      nData.append(sum(data[i:i*2])/(i*2-1)) 
      i *= 2 
     data = nData 
     maxi = float(max(data)) 
     if maxi > self.m: 
      self.m = maxi 
     elif maxi <= 0.5*self.m: 
      self.m *= 0.75 
     bWidth = WIDTH/len(data) 
     for x,y in enumerate(data):  
      canvas.delete("bar"+str(x)) 
      if GHEIGHT == tBarHeight: 
       hexcode = "#%02x%02x%02x" % hsv2rgb(1-((y/self.m)*0.75),1,1) 
       canvas.create_rectangle(x*(WIDTH/len(data)),HEIGHT,x*(WIDTH/len(data))+bWidth,HEIGHT-((y/self.m)*GHEIGHT),tag="bar"+str(x),fill=hexcode) 
      else: 
       drawBar(x,x*(WIDTH/len(data)),y,bWidth, self.m) 
     canvas.delete('display') 
     canvas.create_text(WIDTH/2, 20, text=self.text, tag = 'display') 
     return True 
def hsv2rgb(h,s,v): 
    return tuple(int(i * 255) for i in colorsys.hsv_to_rgb(h,s,v)) 
def update(): 
    global times 
    t1 = time.time() 
## recorder.run() 
    if not drawer.draw(q): 
     drawer.m = 0 
    times.append(time.time()-t1) 
    drawer.text = ("%.03f"%(sum(times)/len(times)))[2:] 
    window.after(1,update) 
def drawBar(sid, x, y, w, m): 
    yVal = int(y/m*nBars) 
    yN = HEIGHT 
    h = GHEIGHT/nBars 
    for bar in xrange(yVal): 
     Hue = 1-(float(bar)/nBars)-0.3*1.1 
     if Hue < 0: Hue = 0 
     gradColor = '#%02x%02x%02x' % hsv2rgb(Hue,1,1) 
     canvas.create_rectangle(x , HEIGHT-(h*bar), x + w, yN - h, fill = gradColor ,outline = "#FFFFFF", tag="bar"+str(sid)) 
     yN -= h 
def click(event): 
    global GHEIGHT 
    if event.x <= WIDTH/2: 
     GHEIGHT = window.winfo_screenheight() 
    else: 
     GHEIGHT = tBarHeight 

global times 
times = list() 
CHUNK = 2048 
RATE = 44100 
WIDTH, HEIGHT = 1920, 1080 
divs = CHUNK 
mSec = 5 
tBarHeight = 30 
nBars = 20 
window = Tk() 
global GHEIGHT 
GHEIGHT = window.winfo_screenheight() 
window.attributes("-fullscreen",True) 
canvas = Canvas(window, width=WIDTH, height=HEIGHT, bg="#FFFFFF") 
canvas.bind(sequence = "<Button-1>",func = click) 
canvas.pack() 
######### 
recorder = Recorder() 
q = multiprocessing.Queue() 
p = multiprocessing.Process(target=recorder.run, args=(q,)) 
p.start() 
p.join() 
drawer = Drawer() 
######### 
window.after(0,update) 
window.mainloop() 
recorder.end() 

我知道这是不是最好的代码,它的某些部分是其进化的残余,但现在我希望能够有刻录机运行其运行功能永远,并在其上调用draw() 。问题是我不知道如何让run()永远运行并将数据放入队列中。我已经在put()行接收到一条pickle错误,后面跟着一条追溯文章。

PicklingError: Can't pickle <type '_portaudio.Stream'>: it's not found as _portaudio.Stream 

这要追溯到

File "C:\Users\My Name\Documents\Programming\visualizer.py", line 108, in <module> 
    p.start() 

回答

1

的问题很可能要么audiooppyaudio返回一个_portaudio.Stream对象,它是unpickleable。由于多个进程不能共享内存,因此它们必须使用一些序列化方法来回传递消息,其中multiprocessing使用pickle模块。如果你不能腌一个对象,你不能在进程间传递它。

除非您需要使用多个CPU内核的性能优势,否则您可能不能使用threading模块而不是multiprocessing

+0

另请参阅http://stackoverflow.com/questions/7894791/use-numpy-array-in-shared-memory-for-multiprocessing和http://stackoverflow.com/questions/15414027/multiprocessing-pool-makes -numpy-matrix-multiplication-slow – torek

+0

我将打印语句添加到记录器类,并且run()和get()都不被调用。我也尝试将所有东西都转换为python的本地列表,float和float放入元组,但仍然抱怨audiostream,即使永远不会放入队列。至于线程,是的,我需要的力量,因为可视化工具大约花费1/3左右的时间在run()中进行计算,所以我希望在我需要它们之前完成这些工作。 – Neywiny

+0

好吧我已经移动了run()中的循环之前的所有pyaudio的东西,并且get()在正确的时间被调用,但由于run()由于某种原因没有运行,所以get()不能()值 – Neywiny