Cinder-PortAudio: PortAudio as an alternative audio backend

Hi all,

I’d like to announce that we have made public cinderblock and new audio backend for ci::audio that wraps PortAudio:

The main motivation for adding PortAudio as a possible backend is to gain support for Windows / Steinberg ASIO drivers, which have a long a much longer history with audio interface vendors over the native Windows WASAPI drivers. Moreover, we have an upcoming project that uses Dante equipment, which only supports ASIO on Windows. As such, we’ve only tested this so far on Windows, but PortAudio supports many other OSes and backends and enabling those would mostly be a matter of setting up the project configuration.

Using Cinder-PortAudio is straightforward: once the cinderblock is setup in your project, you make one call before any other audio calls:


audio::ContextPortAudio::setAsMaster();

There is also a basic sample and TinderBox template included in the repo.

Why isn’t Cinder-PortAudio included in core? The main reason is that when originally writing ci::audio, we chose to use platform specific APIs directly to minimize thirdparty code and remove the extra layers between the user’s application and whatever OS specific audio backend exists. That said, portaudio supports almost all popular OSes and backends out there, so it can be a nice solution if cinder core doesn’t yet provide support for one of those, for example if you need JACK support in linux or ASIO on windows.

Furthermore, while enabling ASIO is straightforward, you still need to personally agree to Steinberg’s licensing agreement and install the sdk into the right location, so we can’t use ASIO as an audio backend by default. For more directions on how to set up ASIO, please see this section of the readme.

Lastly, I also want to send a big thanks to Rare Volume, who helped to fund this development with the aim of providing it to the larger Cinder community.

cheers,
Rich Eakin

11 Likes

Thanks again for this work Rich - ASIO support in particular is really key for Cinder, and has come up in project work for us quite a bit lately in the context of compatibility with Dante networks in particular.

Looking forward to using this.

Where were you 2 years ago? :wink:

Thanks for the hard work, PortAudio seems to cover a lot of bases, which is especially helpful for those of us who suck at audio programming, namely myself.

Cheers,

A.

@lithium hey I mentioned then that if it were my project then I would take the portaudio route and that’s what I did. :smile:

@petros recently added support for CMake, so now this should be usable on all Posix systems. Thanks Petros! If anyone can test and report back issues or success we’d be grateful.

cheers,
Rich

This is great! Cinder audio wasonly recognizing 2 channels instead of 4 on my multichannel device. It was also running an odd amount of 480 framesPerBlock. Port Audio fixed multichannel functionality on my device and is now only 128 framesPerBlock, lowering my latency. Thanks!
I had to enable in and out in the findDevicebyName function. Does this have something to do with duplexIO?

//DEVICE
//console() << audio::Device::printDevicesToString() << endl;
auto EIEDev = audio::ContextPortAudio::master()->deviceManager()->findDeviceByName("Akai EIE Pro ASIO Driver", true, true);//audio::ContextPortAudio::master()->deviceManager()->getDefaultOutput();
//INPUT
auto inNode = audio::ContextPortAudio::master()->createInputDeviceNode(EIEDev, ci::audio::Node::Format().channels(EIEDev->getNumInputChannels()));
//Output
ctx->setOutput(ctx->createOutputDeviceNode(EIEDev, audio::Node::Format().channels(EIEDev->getNumOutputChannels())));

@Malfunkn Glad to hear it’s working for you. A Couple comments:

‘odd amount of 480 framesPerBlock’ - a little while ago I lifted the restriction of requiring power of two block sizes, as there wasn’t really any reason for it other than tradition. Windows WASAPI drivers ask for a default buffer of 10 milliseconds in whatever samplerate you have set, which is where the 480 comes from (if your samplerate is 48K).

About your code - it’s a bit of an odd design and I’d like to change it in the future when time permits, but you don’t actually need to use the audio::DeviceManager directly. You can instead use:

auto EIEDev == audio::Device::findDeviceByName( "Akai EIE Pro ASIO Driver" );

Or if you need separate input / output devices, you can use Device::findInputByName() and audio::Device::findOutputByName() instead. Does that answer your question?

Cheers,
Rich

@rich.e Hey mate, I’ve finally had a need to try this (ASIO has reared its ugly head again). All the installation and everything went perfectly, but the audio coming in from my test microphone is updating super slowly, I’m sorry i don’t know the correct audio terminology, but the rate the audio updates looks as though my app is running at 5fps instead of 60, if that helps paint the equivalent picture.

Is this a known limitation by any chance, or anything you’ve run into? I’m still at the point in the project where if i really put my foot down I can have ASIO (and thus portaudio) removed, but I just wanted to make sure i’m not doing anything dumb / fixable first.

*Edit it doesn’t seem to be limited to microphone input, just a GenSineNode produces the same result.

*Edit 2. Found it. The Cmake WASAPI check was looking for MSVS instead of MSVC, so WASAPI wasn’t available as a host api. This still means the wmme and/or wdkms are super slow for some reason, but since i’ll only be dealing with WASAPI and ASIO that’ll have to be a problem for another day. Sorry for the noise.

Ta,

A