I'm writing a program that is continuously taking input from a microphone using pyaudio and every 5 seconds does some calculations after which it updates some matplotlib plot in a tkinter widget. I got so far:
import threading
from array import array
from Queue import Queue, Full
import pyaudio
from matplotlib import pyplot as plt
import numpy as np
CHUNK_SIZE = 1000
MIN_VOLUME = 500
PLOT_CHUNK_SIZE = CHUNK_SIZE * 5
BUF_MAX_SIZE = CHUNK_SIZE * 10
PLOT_MAX_SIZE = PLOT_CHUNK_SIZE * 10
big_chunk = np.array( [])
def main():
stopped = threading.Event()
q = Queue(maxsize=int(round(BUF_MAX_SIZE / CHUNK_SIZE)))
plot_queue = Queue(maxsize=int(round(PLOT_MAX_SIZE / PLOT_CHUNK_SIZE)))
listen_t = threading.Thread(target=listen, args=(stopped, q))
listen_t.start()
record_t = threading.Thread(target=record, args=(stopped, q, plot_queue))
record_t.start()
plot_t = threading.Thread(target=plot_chunk, args=(stopped, plot_queue))
plot_t.start()
try:
while True:
listen_t.join(0.1)
record_t.join(0.1)
plot_t.join(0.1)
except KeyboardInterrupt:
stopped.set()
listen_t.join()
record_t.join()
plot_t.join()
def record(stopped, q, plot_queue):
global big_chunk, p, ready
while True:
if stopped.wait(timeout=0):
break
vol = max(q.get())
if vol >= MIN_VOLUME:
big_chunk = np.append(big_chunk, q.get())
print 'new chunk'
if len(big_chunk) > PLOT_CHUNK_SIZE-1:
plot_queue.put(big_chunk)
big_chunk = np.array( [])
else:
print "-",
def plot_chunk(stopped, plot_queue):
while True:
if stopped.wait(timeout=0):
break
features = plot_queue.get()
my_features = do_calculations(features)
plt.imshow(my_features)
def listen(stopped, q):
stream = pyaudio.PyAudio().open(
format=pyaudio.paInt16,
channels=1,
rate=44100,
input=True,
frames_per_buffer=1024,
)
while True:
if stopped.wait(timeout=0):
break
try:
q.put(array('h', stream.read(CHUNK_SIZE)))
except Full:
pass # discard
if __name__ == '__main__':
main()
I tried to do it with threads and it works fine except for the plotting. It seems matplotlib and tkinter don't work with threads and multiprocessing would be the way to go. So I tried this:
import Tkinter as Tk
import multiprocessing
from Queue import Empty, Full
import time
import pyaudio
import array
class GuiApp(object):
def __init__(self,q):
self.root = Tk.Tk()
self.root.geometry('300x100')
self.text_wid = Tk.Text(self.root,height=100,width=100)
self.text_wid.pack(expand=1,fill=Tk.BOTH)
self.root.after(100,self.CheckQueuePoll,q)
def CheckQueuePoll(self,c_queue):
try:
str = c_queue.get(0)
self.text_wid.insert('end',str)
except Empty:
pass
finally:
self.root.after(100, self.CheckQueuePoll, c_queue)
# Data Generator which will generate Data
def GenerateData(q):
for i in range(10):
print "Generating Some Data, Iteration %s" %(i)
time.sleep(0.1)
q.put("Some Data from iteration %s \n" %(i))
def listen( q):
CHUNK_SIZE = 100
stream = pyaudio.PyAudio().open(
format=pyaudio.paInt16,
channels=1,
rate=44100,
input=True,
frames_per_buffer=1024,
)
while True:
try:
q.put(array('h', stream.read(CHUNK_SIZE)))
except Full:
pass # discard
if __name__ == '__main__':
# Queue which will be used for storing Data
q = multiprocessing.Queue()
q2 = multiprocessing.Queue()
q.cancel_join_thread() # or else thread that puts data will not term
q2.cancel_join_thread() # or else thread that puts data will not term
gui = GuiApp(q)
t1 = multiprocessing.Process(target=GenerateData,args=(q,))
t2 = multiprocessing.Process(target=listen,args=(q2,))
t1.start()
t2.start()
gui.root.mainloop()
t1.join()
t2.join()
Where I get the following error:
q.put(array('h', stream.read(CHUNK_SIZE)))
TypeError: 'module' object is not callable
Any Ideas?