bastibe/PySoundCard

demo not working

Closed this issue · 10 comments

I'm trying to play around with the pysoundcard demos in the readme.md. """Play an audio file.""" works fine, but I can't get """Loop back five seconds of audio data.""" to work. I tried several block lengths (16 to 1024). I get 5 seconds of:

/Library/Frameworks/Python.framework/Versions/7.3/lib/python2.7/site-packages/pysoundcard.py:592: RuntimeWarning: 689725.9183: Input overflowed
  self._handle_error(err)
/Library/Frameworks/Python.framework/Versions/7.3/lib/python2.7/site-packages/pysoundcard.py:592: RuntimeWarning: 689725.9190: Input overflowed
  self._handle_error(err)
...

Any ideas? I'm using python 2.7.3 32-bit, on Mac 10.9

This seems like a low-level PortAudio problem, you probably have to change some settings (e.g. latency).

What kind of sound card do you have?
Did you try any other software that uses PortAudio (e.g. Audacity)?

Could you please post the list of devices that PortAudio finds on your computer (use the devices() function)?

Thanks -- not sure how to set PortAudio settings through pysoundcard (I only see non-relevant google results).

I have the default soundcard that comes with MacBook Pro (2012). Audacity works well enough, as does pyo (digital sound processing package).

I have:

>>> d = devices()
>>> d.next()
{'struct_version': 2, 
'input_channels': 2, 
'default_high_output_latency': 0.1, 
'default_low_output_latency': 0.01, 
'default_sample_rate': 44100.0, 
'output_latency': 0.01, 
'name': u'Built-in Microph', 
'interleaved_data': True, 
'default_high_input_latency': 0.012154195011337868, 
'device_index': 0, 
'sample_format': <type 'numpy.float32'>, 
'default_low_input_latency': 0.00199546485260771, 
'host_api_index': 0, 
'input_latency': 0.00199546485260771, 
'output_channels': 0}
>>> d.next()
{'struct_version': 2, 
'input_channels': 0, 
'default_high_output_latency': 0.01671201814058957, 
'default_low_output_latency': 0.00655328798185941, 
'default_sample_rate': 44100.0, 
'output_latency': 0.00655328798185941, 
'name': u'Built-in Output', 
'interleaved_data': True, 
'default_high_input_latency': 0.1, 
'device_index': 1, 
'sample_format': <type 'numpy.float32'>, 
'default_low_input_latency': 0.01, 
'host_api_index': 0, 
'input_latency': 0.01, 
'output_channels': 2}

possibly of relevance -- looks like it might be using Core Audio?

>>> default_api()
{'struct_version': 1, 'name': u'Core Audio', 'api_idx': 0, 'type': 5L, 'default_output_device_index': 1, 'device_count': 2, 'default_input_device_index': 0}

and for completeness:

>>> pa_version()
(1899, u'PortAudio V19-devel (built Oct  4 2013 14:52:56)')

I guess using Core Audio is normal on Mac, right?

Are the two devices you listed the only ones?

Are those the ones you're using with Audacity?
Can you do playback and recording simultaneously in Audacity?

Can you do simultaneous playback and recording in pyo?

Did you build PortAudio yourself?
They have an example program called paex_read_write_wire which you should also try.
The source code is in examples/paex_read_write_wire.c.

Yes, core audio is typical / normal on mac. And yes, those are the only two devices; another .next() raises a StopIteration. I used those two with Audacity and pyo.

Recording in Audacity works, but the recording stops if I start playing a sound in another Audacity project window. (I don't tell recording to stop. It continues when I switch to the other project window, and only stops when I start playing something in that other window.)

I can play and record at the same time in pyo.

I did not build PortAudio myself (as far as I am aware!). I downloaded and tried building it now to find paex_read_write_wire, but the build did not go through.

Based on the error message ("RuntimeWarning: 689725.9190: Input overflowed"), I am wondering if the number of bytes per samples is off somehow on my machine, leading to the overflow.

Here's a minimal example for me to get that error:

from pysoundcard import Stream
block_length = 512
s = Stream(sample_rate=44100, block_length=block_length)
s.start()
s.read(block_length)

Interestingly a longer block length will succeed (at least for one read; it fails if I try multiple times in a loop like the example):

from pysoundcard import Stream
block_length = 1024
s = Stream(sample_rate=44100, block_length=block_length)
s.start()
s.read(block_length)

I think I'm finally starting to understand what's the problem here!

Just to make sure: You are talking about the example that's mentioned in the section "Read/Write Mode", right?

Did you try the loop back example from the section "Callback Mode"?

Does it also produce overflow warnings?

Yes, I was trying the loop example from the section "Read/Write Mode".

The example from the section "Callback Mode" runs for me without errors of any kind. I am not sure what it is supposed to sound like, but I do hear a high-pitch, and it seems like if I tap some keys to make a sound, this triggers auditory feedback.

OK, I think now I get it. I'm sorry that I asked for so many details which are in the end quite irrelevant.

Simply put, the read() and write() methods are not really meant for this use case. I think we should remove the example from the README file because it's misleading (see #26).

For any non-trivial use case, especially if it involves synchronous recording and playback, the callback API should be used.

I'm currently working on some high-level wrappers around the callback API that will hopefully make it much easier to use (#19).

The example from the section "Callback Mode" runs for me without errors of any kind. I am not sure what it is supposed to sound like, but I do hear a high-pitch, and it seems like if I tap some keys to make a sound, this triggers auditory feedback.

You are supposed to get on the output whatever reaches the input (but with a certain delay, a.k.a. latency).
If, as in your case, you have a (i guess built-in) microphone and loudspeakers, you hear the sounds you're making (e.g. hitting the keyboard) plus an ugly acoustic feedback (like in every single movie where somebody grabs a microphone to make an announcement). The pitch of the feedback depends on the distance between the microphone and the loudspeakers and on the latency of the system.
If you want to avoid the feedback, you should try the example using headphones.

Cool, all sounds good. The callback mode looks great -- I want to do things like voice-onset recording and voice-offset detection.

If you only need recording you can try to use the blocking read() method, but I think on the long run you're better off using the callback mode.

If you have any ideas for high-level functions that would help for your use case, please comment on #19.

Please close this issue if it's resolved from your point of view.