Fun with AudioTrack

I mentioned the class AudioTrack a couple of times already. Let’s see how it works.

AudioTrack is available since Android 1.5 (API level 3) and offers an extremely simple way to send PCM data directly to the device’s audio hardware. You can use it in two modes: static and streaming. I will only look at the streaming mode here. Streaming mode means that you permanentley write new PCM data to the hardware, the framework will queue it in a buffer and play it back for you. AudioTrack supports various sampling rates and 2 PCM encodings, 8-bit and signed 16-bit PCM. An AudioTrack instance can either be in mono or stereo mode. Here’s a small class that can be used similar to the AudioDevice class of the onset detection tutorial:

Pretty simple eh? Now let’s start with the constructor. The first thing we do is to get the minimum buffer size for the AudioTrack instance we are going to create. This is achieved by a call to AudioTrack.getMinBufferSize(), passing in the sampling rate, wheter we are mono or stereo and the PCM encoding, in this case 16-bit signed. This buffer size is used by the AudioTrack internally for a buffer it stores all the samples in we’ll write to it. If the buffer is full it is flushed to the audio hardware. Now, in the next line we instantiate an AudioTrack. The first parameter dictates which audio stream our samples are going to be written to. There’s a couple of audio streams in the Android system, we’ll almost always want to use AudioManager.STREAM_MUSIC here. For the other stream types refer to the documentation. The next three parameters say what sampling rate we want to have, wheter we want the track to be mono or stereo and which PCM encoding we want to use. As with the AudioDevice class from the onset detection tutorial we use 44100Hz, mono, 16-bit signed PCM. The last parameter says wheter this AudioTrack is static or a streaming one, we want it to be a streaming one. All that’s left is to call and we are ready to write samples to the audio hardware.

All the code in the onset detection tutorial worked with PCM data encoded as floats in the range [-1,1]. We want to emulate this here so i wrote a little method called AndroidAudioDevice.writeSamples( ) which takes a float array of mono float PCM samples and writes it to the hardware. For this the float samples have to be converted to 16-bit signed PCM which is done in the AudioDevice.fillBuffer() method, no rocket science here. Once we have the converted PCM we simply write it to the AudioTrack via AudioTrack.write() which takes a short array (our PCM samples), an offset into the array and the number of samples to use from the offset on. Extremely simple, even more than the equivalent Java Sound class SourceDataLine.

Now there’s a couple of interesting things about AudioTrack. First off, if you don’t write to it constantly it will pause itself to not hog any further system resources. Upon the next write it will start playback again introducing a wake up lag. Another not so nice thing is that due to the internal buffer of AudioTrack which has to be filled up completely before it is send to the hardware there’s noticeable lag between the time you write your first samples and when you hear them being played back. The minimum buffer size i get on my Milestone for the configuration is 8192, sadly the documentation doesn’t tell wheter that’s bytes or samples. If it’s bytes we divide that by two and then by the sampling frequency to get the total lag introduced by the internal buffer: 8192 / 2 / 44100 = 0,092 seconds, so nearly 100ms. That’s noticeable. In case the minimum buffer size is in samples it get’s even worse. The lag will be 200ms in that case. So that’S what you have to expect when using this class. Writting a software mixer based on AudioTrack is possible as long as you don’t need low latency. Synthesizing sounds each time the screen is touched for example is a bad idea as the lag is more than noticeable. Another property of AudioTrack is that the AudioTrack.write() method blocks. If you want to use it in a game you should do all your audio mixing in a seperate thread.

Still, the class is pretty niffty and it makes it easy to port all the examples from the onset detection tutorial to Android. I tested it with the WaveDecoder class and it worked like a charm, not eating up to much system resources while doing its thing. Here’s the sine wave generator sample ported to android:

You can also try to use the decoders included in the tutorial framework, however, the pure Java MP3 decoder will be to slow. Only the WaveDecoder works acceptably. When i’m done porting all decoders to C++ i might put out a small Android audio library so you can benefit from that a bit. Now go out and play 🙂

And now something completely different…

I was out for a beer tonight with a couple of friends and Stefanie. While talking about strange cultural differences i remembered something a friend of mine showed me a year ago. Thanks to almighty google i was able to find it with the simple query “plastic breast vending machine”. Here’s the awesome result:

The japanese are strange people indeed.

No programming news today, i started porting all the audio analysis code to C++ so i can use it on Android. Will report any progress here soon and maybe put out a little demo.

Newton Statistics, February

Well, here it is, my second stats report for Newton. Between this and the last one i released two updates, one fixing some issues and the other one adding 4 new levels. Here’s the current downloads and installs data:

I’m currently at 46% install base, a bit above 6000 installs. That’s probably not bad and the Abduction blog shows similar figures for the lite version of Abduction (albeit a lot more downloads). What’s interesting is that the install base starts to shrink slowly over time and is not compensated by new downloads. This shrinking sets in a week after a new release with daily loses of 30 installs. I could of course put out weekly updates as many others do just to push Newton back to the top of the “Just In” list but i think that’s a shitty practice as long as i don’t have to offer any fixes or new content.

Speaking of new content, we now have 20 new levels for the full release. Yes, we are working slowly, i’m sorry. I guess the initial goal of 80 new levels can’t be reached in reasonable time so we’ll stop at around 40-50 and hope that the in-game editor and level sharing will make up for some of the missing levels. The full version of Newton will probably cost 1.49€ which is hopefully a reasonable price.