Multichannel PyAudio with ASIO Support

Question:

I’m attempting to interface to a PreSonus AudioBox 1818VSL with PyAudio on Win7, but am having some trouble recording more than 2 channels (stereo) at a time. The PreSonus driver creates many stereo input audio devices (ex. stereo channels 1&2, 3&4, etc.) and an 18 input channel ASIO device. I can record from any of the stereo devices without issue. To minimize latency and record from > 2 channels, I’m trying to use the ASIO device.

I’ve been using a build of PyAudio from http://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio, which has compiled support for ASIO, DS, WMME, WASAPI, WDMKS.

Calls to pyaudio_handle.is_format_supported() show the ASIO device supports 8 to 32-bit data at 44.1, 48, and 96 kHz.

Below is the dictionary returned by pa.get_device_info_by_index(32)

{'defaultHighInputLatency': 0.046439909297052155,
'defaultHighOutputLatency': 0.046439909297052155,
'defaultLowInputLatency': 0.046439909297052155,
'defaultLowOutputLatency': 0.046439909297052155,
'defaultSampleRate': 44100.0,
'hostApi': 2L,
'index': 32,
'maxInputChannels': 18L,
'maxOutputChannels': 18L,
'name': u'AudioBox ASIO Driver',
'structVersion': 2L}

Below is the code that I have been using to create the PyAudio input stream. The callback function simply pushes the data into a list and returns pyaudio.paContinue until I get the amount of samples I want, then it returns pyaudio.paComplete.

pyaudio_handle = pyaudio.PyAudio()
stream = pyaudio_handle.open(
    format=pyaudio.get_format_from_width(2,unsigned=False),
    channels=4,
    rate=48000,
    input=True,
    frames_per_buffer=256,
    input_device_index=32,
    stream_callback=pyaudio_stream_callback,
)

Attempting to initialize the ASIO driver at rates faster than 44.1 kHz cause PyAudio to hang and not return. Initializing at 44.1 kHz produces the following error: IOError: [Errno Unanticipated host error] -9999.

Any help that you can provide resolving this error would be helpful. I would even settle for proof that ASIO works with > 2 channels in PyAudio when running on Win7. Thanks.

Asked By: Fitzy

||

Answers:

I was able to record 8 channel audio (M-audio M-Track Eight) using the ASIO driver at 96 kHZ.

From

p = pyaudio.PyAudio()
p.get_device_info_by_index(4) 

I found that ‘index’: 4 was the ASIO driver:

{'defaultLowInputLatency': 0.005804988662131519, 
 'defaultHighOutputLatency': 0.09287981859410431, 
 'defaultLowOutputLatency': 0.005804988662131519,
 'defaultSampleRate': 44100.0, 
 'maxInputChannels': 8, 
 'maxOutputChannels': 8,
 'structVersion': 2, 
 'name': 'M-Audio M-Track Eight ASIO', 
 'index': 4, 
 'hostApi': 2,
 'defaultHighInputLatency': 0.09287981859410431}

So I started with the sample code on PyAudio but switched from wave to scipy.io.wavfile to write the multichannel .wav file since wave only supports stereo.

import pyaudio
import wave
import numpy as np
from scipy.io import wavefile

CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 8
RATE = 96000
RECORD_SECONDS = 10
WAVE_OUTPUT_FILENAME = "output.wav"

p = pyaudio.PyAudio()

stream = p.open(format=FORMAT,
                channels=CHANNELS,
                rate=RATE,
                input=True,
                input_device_index=4,
                frames_per_buffer=CHUNK
                )

print("* recording")

frames = []

for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
    data = stream.read(CHUNK)
    frames.append(data)

print("* done recording")

stream.stop_stream()
stream.close()
p.terminate()


#Not really sure what b'' means in BYTE STRING but numpy needs it 
#just like wave did...
framesAll = b''.join(frames)

#Use numpy to format data and reshape.  
#PyAudio output from stream.read() is interlaced.
result = np.fromstring(framesAll, dtype=np.int16)
chunk_length = len(result) / CHANNELS
result = np.reshape(result, (chunk_length, CHANNELS))

#Write multi-channel .wav file with SciPy
wavfile.write(WAVE_OUTPUT_FILENAME,RATE,result)

Viola! 96 kHz, 16-bit, 8 channel .wav file!

Oh, details

  • Win7 64bit
  • M-Audio Eight 64 bit Windows Driver 1.0.11
  • Python 3.4.2 32 bit
  • PyAudio 0.2.8 for Win7 from
    here
  • numpy-1.9.2
  • scipy-0.15.1-win32-superpack-python3.4
Answered By: Lucas

Unfortunately, I wasn’t able to record more than two tracks with the build of PyAudio from http://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio. Also I found the same problem at https://stackoverflow.com/a/17734495/9314452 written by @Laughingrice.

So I compiled portaudio with Microsoft Visual Studio (free version) according to

http://portaudio.com/docs/v19-doxydocs/compile_windows_asio_msvc.html
http://portaudio.com/docs/v19-doxydocs/compile_windows.html

Note that we have to download ASIO SDK library from https://www.steinberg.net/developers for ASIO support.

Then I also built pyaudio with the portaudio_x64.dll (compiled with MSVC) like:

python setup.py build_ext -I .portaudioinclude -L .portaudiomybuildRelease -l portaudio_x86
python setup.py install

When I met an error message:

>>> import pyaudio
Could not import the PyAudio C module '_portaudio'.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:UserssubfAppDataLocalProgramsPythonPython310Libsite-packagesPyAudio-0.2.12-py3.10-win-amd64.eggpyaudio.py", line 116, in <module>
    import _portaudio as pa
ImportError: DLL load failed while importing _portaudio: DLL load failed

I solved the problem by coping the portaudio DLL to the directory of pyaudio library directly:

copy portaudio_x64.dll C:UsersmyidAppDataLocalProgramsPythonPython310Libsite-packagesPyAudio-0.2.12-py3.10-win-amd64.egg

I succeeded in recording more than two channels with pyaudio.

And I made separate wav files because the wave file format has 2 GB limitation.

wavfile.write( "channel_01.wav", RATE, result[:,0] )
wavfile.write( "channel_02.wav", RATE, result[:,1] )
wavfile.write( "channel_03.wav", RATE, result[:,2] )
wavfile.write( "channel_04.wav", RATE, result[:,3] )
wavfile.write( "channel_05.wav", RATE, result[:,4] )
wavfile.write( "channel_06.wav", RATE, result[:,5] )
wavfile.write( "channel_07.wav", RATE, result[:,6] )
...

Now I am trying to record automatically (by nnCron freeware) multi-track with pyaudio from beringer X32 at every worship service in a church.

Answered By: Gwang-Jin
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.