Closed valkyriesavage closed 9 years ago
This is a limitation of the underlying library we are using: You can select a number of channels to read, but it will always select channels 1...N; You can't select an arbitrary selection of channels such as 2, 5, and 7. Also note that on some platforms, selecting a non-power-of-two number of channels may fail due to a bug.
By default, all channels of the given sound device are selected. You can get a list of all devices using devices()
, and pass any of these to the Stream
constructor as input_device
or output_device
. Each device is a dict that has a field for input_channels
and output_channels
. If you lower these values before passing the dict to the Stream
constructor, your Stream will have fewer channels.
Some sound drivers choose to expose their channels in weird ways on some platforms. I have seen sound drivers that create sound devices in pairs of two channels, or provide different combinations in different sound devices. Maybe your sound card provides both a stereo device and a all-channels device.
Thanks!
Are you still interested in using only a subset of channels?
In case you are:
It is indeed not possible to make a channel selection (other than the first N channels) using the generic PortAudio API. However, PortAudio provides a few HostAPI-specific function where this can be done for certain HostAPIs, see http://portaudio.com/docs/v19-doxydocs/group__public__header.html. PySoundCard doesn't (yet?) support any of those, but if you want us to implement certain things, please comment on issue #16.
The platform-independent solution would be to activate a whole range of channels, and fill the ones that are not needed with zeros. This is a certain amount of useless work, but in most applications this will not be a problem.
I'm actually currently working on adding this feature to PySoundCard; if you are interested, you can check out my "playrec" branch: https://github.com/bastibe/PySoundCard/tree/playrec.
This provides a play()
function which accepts a mapping
argument. In this argument, you can specify a list of channels where the channels of the given array are played back.
There are also the functions rec()
and playrec()
, which take similar arguments.
If you have any suggestions for improvement, feel free to comment on issue #19 or contribute to the Wiki page: https://github.com/bastibe/PySoundCard/wiki/High-Level-API.
Thank you! I will definitely take a look at the wiki; I didn't expect to be doing so much audio processing, but here I am.
I actually have a related question: setting the input_channels variable doesn't seem to do "the right thing".
I tried that way, where I only get 2 channels from the source set to 18 channels (its default). I have also tried with 4 channels:
Where I also seem to get only 2 channels out. Is there something else I need to do other than what I've done there? If it helps, when I query the stream with s.input_channels, it does return 2 instead of what I set it to...
Oh, somehow it doesn't work if I feed it in for initialization, but if I initialize with that dictionary and then manually set s.input_channels = 4 it works alright...?
Hrm, actually...
All four of the channels I'm getting, in spite of the fact that I'm using 4 mics, are identical. And they have a strange quality: about half the time I get real data, and half the time I get 0s.
It should be input_device
, not inputDevice
.
Currently, the Stream
constructor takes arbitrary keyword arguments without checking them, this is why inputDevice
is accepted and ignored without raising an error.
This should be fixed once #43 is merged.
I discourage repeated calls to Stream.read()
, because there is no way to guarantee that (or check if) audio data is read without gaps in between.
It's much more reliable to use the callback API for recordings that are longer than a few blocks.
Of course the callback API is more complicated to use, that's why I wrote the convenience functions play()
, rec()
and playrec()
, which are currently in the above-mentioned "playrec" branch: https://github.com/bastibe/PySoundCard/tree/playrec.
I hope this will be available soon in an official release.
You should check this out; then your example will reduce to (and it will hopefully work!):
mydata = pysoundcard.rec(100 * CHUNK, samplerate=RATE, channels=CHANNELS)
The first argument is the number of samples you want to record.
BTW: you shouldn't specify a chunk size unless you have a reason to; if you don't specify a chunk size, the library uses appropriate chunking on its own.
Aha, most excellent. I had been using callbacks before, but was trying to get a MWE up with 4 channels to see how it worked. I've been specifying the block length so that I can do the analysis components of my project more easily (easier to compare things when I know all my FFT bins are the same).
Thanks so much, both.
Is it possible to select channel(s) on multi-channel audio devices when creating a stream? In particular, I have a 16 channel USB soundcard from which I need to stream each channel separately. I don't see options in Stream that support selecting which channel(s) it reads from.
(or even to select 3+ channels; it would be ok if I just had to use the first n channels)