Nov 032010

I have been working on a little application which requires mixing of a number of audio tracks. It should be multi-screen and run on PC’s as well as Android devices.
Ideally I would like it to be able to mix at least some 12 tracks, but making that happen on Android is proving to be very difficult. There are a few ways to do the calculations, and the benefits of different techniques varies depending on the machine running the code.

In a previous post I showed some code for a audio mixer made with Pixel Bender.
It works great on my PC, drastically reducing the CPU load compared to simply using ByteArray.readFloat and ByteArray.writeFloat.
Unfortunately it does not provide the same performance gains when I run the application on Android, either in the Flash Player or as an AIR app. In fact it does slightly worse that simply mixing in AS. I’m not sure why that is, but I guess it has something to do with threading.

So I have been thinking of possible solutions to squeeze out a few more tracks on Android. My first idea was that since there is no need for stereo audio, there could be some way to do the mixing in mono. But since Sound.extract will only produce a stereo output and one needs to write to in stereo it does not seem possible to reduce CPU strain much that way. When mixing in pure AS it removes the need for multiplying every second sample with the volume value, but that is pretty much it. You still need to increment the pointer when reading the audio data on every second sample, which seems to be about as taxing as reading an extra float that one does not use. And of course one needs to write twice to the So any gains is very marginal. If Sound.extract had a flag to extract audio as mono it might have been possible to make a noticeable increase in track count by mixing in mono.
Also, Pixel Bender does not support single channel inputs and outputs, so I could not figure out a way to make a shader for mono mixing that reduces CPU load.

Another option I considered was using fast memory solutions such as Azoth or Apparat. It turns out to be a no-go since it requires the ByteArray to be little endian, and is big endian. Having to flip the bits for each sample would surely turn out to negate any benefits of the faster memory access.

Also Vector is faster than ByteArray, and I have seen claims that on Android it’s even faster than Alchemy memory. But since Sound.extract returns a ByteArray there is nothing to be gained by using a Vector for straight mixing since the samples are only accessed once.

So no matter what I try I seem to be hitting a dead end. The best track count I get on Android is still using basic mixing in AS, and on the PC Pixel Bender performs a lot better. So currently I have decided to keep two different engines in the application and switch between them depending on the device used.
Of course, if anyone can think of a solution I have not explored or are aware of any errors in my conclusions, your input would be greatly appreciated.


Switch to our mobile site