The Shed is going Social! Join us on FaceBook and Twitter and chime in on the conversation.
|
 |
|
Dev Shed Forums
> Programming Languages
> Python Programming
|
Pyaudio - buffer overflow errors
Discuss Pyaudio - buffer overflow errors in the Python Programming forum on Dev Shed. Pyaudio - buffer overflow errors Python Programming forum discussing coding techniques, tips and tricks, and Zope related information. Python was designed from the ground up to be a completely object-oriented programming language.
|
|
 |
|
|
|
|

Dev Shed Forums Sponsor:
|
|
|

August 5th, 2012, 07:48 AM
|
|
Registered User
|
|
Join Date: Aug 2012
Posts: 1
Time spent in forums: 6 m 41 sec
Reputation Power: 0
|
|
Pyaudio - buffer overflow errors
I am converting a program in python that is written and used on another OS that starts with the letter w.
The script as written works on that OS, but on Linux it seems to fall flat on its face.
First, I do not have access to any non Linux systems. I am strictly 100% Linux and Linux only. (Hence the need to correct this script.)
Second, I need to determine if a few things are even possible or I should just stop now and not waste my time trying to convert it.
a. - Can python via pyaudio listen to the mic/line in monitor for a trigger event, record audio after the trigger event, while still monitoring for additional trigger events that would trigger another recording, and playback whats being recorded while monitoring? All with a SINGLE audio card?
If the answer to the above is NO? Its interesting that this can be done on a non Linux system.
Third, right now I have 2 issues:
a) buffer overflow on reading
b) audio recorded sounds like a chipmunk with the audio recorded at about 20 times normal rate.
Lastly, I think most of these issues can be overcome on Linux, I don't know why not.
So some basic info. I program with all kinds of thinks from assembler to HTML, to PHP to SQL. Python is relatively new.
Development testing system is an old 32bit system using a Kubuntu Precise distro (its more that its customized to include tons of stuff that officially is not included like codex, java etc...)
Python and Tk is all the versions from the Kubuntu repos. Nothing compiled from sources, just apt-get install or synaptic.
I have added: Tk, ffmpeg, numpy, pyaudio, pyserial etc. as this required by this script, along with any dependencies they had to install.
NOTE: Pulseaudio is REMOVED on my distro and all other systems, I do not use it. Strictly just ALSA, and I don't want to make its use required. Nor require others to remove it. pyaudio should deal with that be it ALSA or whatever.
Bug #1: - IOError: [Errno Input overflowed] -9981
Code:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1413, in __call__
return self.func(*args)
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 498, in callit
func(*args)
File "T_mybeta.py", line 896, in start
nextstate()
File "T_mybeta.py", line 547, in Atone1
data = record(.2,0,1)
File "T_mybeta.py", line 341, in record
data = stream.read(chunk)
File "/usr/lib/pymodules/python2.7/pyaudio.py", line 564, in read
return pa.read_stream(self._stream, num_frames)
IOError: [Errno Input overflowed] -9981
The code which causes this error:
Code:
ORIGINAL
def record(seconds,playback,chan):
#function to record audio
#inputs: seconds - number of seconds to record, playback - value of 1 will send audio to output while recording, 0 will not
#outputs: data - recorded audio data
RECORD_SECONDS = seconds
all = []
global RATE
for i in range(0, int(RATE / chunk * RECORD_SECONDS)):
data = stream.read(chunk)
if playback == 1:
stream.write(data)
all.append(data)
data = ''.join(all)
return data
MY ALTERATION to deal with the error:
def record(seconds,playback,chan):
#function to record audio
#inputs: seconds - number of seconds to record, playback - value of 1 will send audio to output while recording, 0 will not
#outputs: data - recorded audio data
RECORD_SECONDS = seconds
all = []
global RATE
for i in range(0, int(RATE / chunk * RECORD_SECONDS)):
#print "i: ", i, "top",int(RATE / chunk * RECORD_SECONDS)
try:
data = stream.read(chunk)
except IOError as ex:
if ex[1] != pyaudio.paInputOverflowed:
raise
print "error read step 1"
#time.sleep(0.05)
wait_sec(0.05)
# data = stream.read(chunk) # data = '\x00' * chunk
if playback == 1:
stream.write(data)
all.append(data)
data = ''.join(all)
return data
I added a wait for the buffer to fill? via a function that was included in the code handle when time.sleep might get used in multiple sub-processes. I've had time.sleep in place of wait_sec.
It seems to handle the overflow.. but the delay causes the trigger mechanism to not trigger unless this error condition does not occur.
I tried to use larger buffer sizes, but it causes two issues, the script uses a FFT based on the chunk size and sample rate. Increasing the buffer past 2176 causes another portion of the sript to fail with another error. I changed this back to the originals 1024, and slowly decreased this wait time to find a point it didn't occur that much, but it still occurs, so this is obviously NOT the answer/solution.
In the original script this error can occur immediately when starting up, crashing the script. Start again its fine till the error. Obviously as seen in my code one idea was just to fill the error condition with 00 which obviously won't trigger a thing.
Any ideas?
Bug #2 - Chipmunk/fast recording
The original script attempted to open the sound card again and then record the audio via this new handle. Linux threw a fit and crashed on that plan.
Code:
Expression 'ret' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 1670
Expression 'AlsaOpen( &alsaApi->baseHostApiRep, params, streamDir, &self->pcm )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 1830
Expression 'PaAlsaStreamComponent_Initialize( &self->capture, alsaApi, inParams, StreamDirection_In, NULL != callback )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 2092
Expression 'PaAlsaStream_Initialize( stream, alsaHostApi, inputParameters, outputParameters, sampleRate, framesPerBuffer, callback, streamFlags, userData )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 2764
Unhandled exception in thread started by <function alert at 0xa6b6684>
Traceback (most recent call last):
File "T_mybeta.py", line 395, in alert
output_device_index = output_device_indices[output_device.get()])
File "/usr/lib/pymodules/python2.7/pyaudio.py", line 714, in open
stream = Stream(self, *args, **kwargs)
File "/usr/lib/pymodules/python2.7/pyaudio.py", line 396, in __init__
self._stream = pa.open(**arguments)
IOError: [Errno Device unavailable] -9985
So I commented out the new open statement, which solves the issue, and it records now.... but I now have this issue with the chipmunk recording. Which is probably related to the original handle being processed through the FFT.
So is there a way to open the card again for input to record it?
I've tested recording using the same settings, 1024 chunk, 11025 sample, thats fine, in a sample/test program.
Bug #1 also occurs when I apply my fix (comment out the 2nd attempt to open the card), so I applied the same concept try, wait_sec option... no buffer errors, but the chipmunks are there.
To record the audio coming in AND monitor for the trigger event, ie there could be multiple trigger events that happening at the same time. ie: trigger 1, trigger2, trigger 3, trigger 4, audio (Yes I am being vague on the trigger event, for a reason. The trigger logic seems to work if I can get past the buffer issue and then resolve the recording issue.)
Ideas? ?
Thank in advance.
|

August 6th, 2012, 02:18 PM
|
 |
Contributing User
|
|
|
|
Terribly sorry, I don't begin to know how to run your code fragment. Python is supposed to have batteries included; you'd expect platform independence. If this were my project, I'd learn about the alsa driver/mixer whatever it is using the bash command line:
Code:
$ apropos alsa
aconnect (1) - ALSA sequencer connection manager
alsactl (1) - advanced controls for ALSA soundcard driver
alsactl_init (7) - alsa control management - initialization
alsaloop (1) - command-line PCM loopback
alsamixer (1) - soundcard mixer for ALSA soundcard driver, with ncurse...
amidi (1) - read from and write to ALSA RawMIDI ports
amixer (1) - command-line mixer for ALSA soundcard driver
aplay (1) - command-line sound recorder and player for ALSA soundc...
arecord (1) - command-line sound recorder and player for ALSA soundc...
aseqdump (1) - show the events received at an ALSA sequencer port
aseqnet (1) - ALSA sequencer connectors over network
speaker-test (1) - command-line speaker test tone generator for ALSA
Browsing Gnu solfege, an ear training program written in python might be useful to you.
Or, put on your lisp programming hat, try nyquist or audacity. (audacity might depend on nyquist.)
__________________
[code] Code tags[/code] are essential for python code!
|

November 9th, 2012, 02:23 PM
|
 |
Contributing User
|
|
|
|
Hey! Did you resolve this problem? I'm writing software to visually display data recorded on the microphone. I'd like to connect with alsa directly. The only thing I've managed so far is to open a pipe to arecord and read data from that. Thanks, Dave.
Code:
#python3import math
import array
import tkinter
import subprocess
TAU=2*math.pi # http://www.youtube.com/watch?v=jG7vhMMXagQ
def interpolate(x,p0,p1):
'''
# provide 2D linear interplation
>>> interpolate(0.5,(0,0),(1,1))
0.5
>>> interpolate(0.5,(1,0),(0,1))
0.5
>>> interpolate(3,(1,0),(5,2))
1.0
'''
(x0,y0) = p0
(x1,y1) = p1
slope = (y1-y0)/(x1-x0)
intercept = y0-slope*x0
return slope*x+intercept
def coordinates(radii,trig,scale,center):
'''
convert amplitude,time data to radius, angle
'''
(sin,cos) = trig
coords = array.array('I',(0,)*(2*len(sin)))
for (i,(s,c,r)) in enumerate(zip(sin,cos,radii)):
coords[2*i] = int(center+scale*r*c)
coords[2*i+1] = int(center+scale*r*s)
return coords
def average(a,c,L):
'''
return list of averages length L centered at intervals spaced c apart.
'''
result = []
h = L//2
H = h+1
for i in range(0,len(a),c):
d = a[max(i-h,0):i+H]
result.append(sum(d)/len(d))
return result
class CircleGraph:
def __init__(self,R = 256):
'''
R: maximum radius
'''
self.tk = tkinter.Tk()
self.tk.wm_geometry(newGeometry='%dx%d+20+20'%(2*R,2*R))
self.canvas = tkinter.Canvas(self.tk)
self.canvas.pack(expand=tkinter.YES,fill=tkinter.BOTH)
self.radius = R
R = float(self.radius)
rreciprocal = 1.0/R
sin = array.array('f',range(len(self))) # precompute re-used trig
cos = sin[:]
self.hftrig = sin,cos
for a in range(len(self)):
angle = a*rreciprocal
sin[a] = math.sin(angle)
cos[a] = math.cos(angle)
self.lftrig = sin[::5], cos[::5]
#self.hf = self.canvas.create_polygon(
# *coordinates((0.5 for i in sin),self.hftrig,R,R),
# outline='red')
self.hf = [self.canvas.create_line(
*coordinates((0.5 for i in sin),self.hftrig,R,R),fill='red')
for i in range(3)
]
self.lf = self.canvas.create_line(
*coordinates((0.5 for i in self.lftrig[0]),self.lftrig,R,R),
fill='darkblue',width=3)
self.controls()
def terminate(self):
self.PROCEED = False
def controls(self):
L = len(self)
master = tkinter.Toplevel(self.tk)
master.wm_geometry(newGeometry='+%d+20'%(40+2*self.radius))
tkinter.Button(master,text='exit',command=self.terminate).pack(side=tkinter.BOTTOM)
rate = tkinter.Scale(master,from_=0,to=100,
label='sample rate',orient=tkinter.HORIZONTAL)
rate.pack(side=tkinter.BOTTOM)
rate.set(50)
avgspan = tkinter.Scale(master,from_=1,to=L//30,
label='filter width',orient=tkinter.HORIZONTAL)
avgspan.pack(side=tkinter.BOTTOM)
avgspan.set(min(30,L//30))
self.controlbox = master
self.PROCEED = True
self.rate = rate
self.avgspan = avgspan
self.controlBox = master
def __len__(self):
return int(self.radius*TAU)
def __call__(self):
global coordinates # might run faster with this unnecessary statement
L = len(self)
rate = self.rate.get
RATE = rate()
a = int(0.5+math.exp(interpolate(RATE,
(0,math.log(2000)),
(100,math.log(192000)))))
with subprocess.Popen(
'arecord --format=U8 --rate=%d'%(a), # --format=U8 byte, --rate=8000 Hz, --mmap could be faster
bufsize=L,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True) as arecord:
tk = self.tk
hf = self.hf
HFTally = len(hf)
hfn = 0
hftrig = self.hftrig
lf = self.lf
lftrig = self.lftrig
R = self.radius
read = arecord.stdout.read
coords = self.canvas.coords
itemconfig = self.canvas.itemconfig
avgspan = self.avgspan.get
scale = 1.0/256.0
arr = array.array
while self.PROCEED and (RATE == rate()):
data = arr('f',(scale*r for r in read(L)))
coords(lf,*coordinates(average(data,5,avgspan()),lftrig,R/2,R))
itemconfig(hf[(hfn+2)%HFTally],fill='#f55')
itemconfig(hf[(hfn+1)%HFTally],fill='#faa')
coords(hf[hfn],*coordinates(data,hftrig,R,R))
itemconfig(hf[hfn],fill='#f00')
hfn = (hfn + 1) % HFTally
# itemconfig(hf[hfn],fill='darkred')
tk.update()
return self.PROCEED
def main():
cg = CircleGraph()
while cg():
pass
if '__main__' == __name__:
main()
|

November 13th, 2012, 05:19 AM
|
|
Registered User
|
|
Join Date: Nov 2012
Posts: 6
Time spent in forums: 15 m 19 sec
Reputation Power: 0
|
|
|
Developer Shed Advertisers and Affiliates
| Thread Tools |
Search this Thread |
|
|
|
| Display Modes |
Rate This Thread |
Linear Mode
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
|
|