Boodler is an open-source soundscape tool written in C and Python. It is able to generate a never-ending, never-repeating stream of sound based on soundscape code, written in Python.
A while back, I ported Boodler to the iPhone. It also works fine on the iPad. However, it does not have a UI, so if you want to use it, you’d better be able to use a terminal.
The easiest way to install Boodler for iPhone is through my Cydia repository. This will install a pre-built Boodler with all the dependencies. If you want to compile from scratch, read on. And make sure you have an on-iPhone development environment set up.
As always, feel free to contact me if something doesn’t work out.
The easiest way to compile Boodler on the iPhone is with a patch. First, though, you’ll need to get the dependencies and the sources.
iphone:~ mobile$ sudo apt-get install python setuptools
iphone:~ mobile$ wget http://boodler.org/dl/Boodler-2.0.3.tar.gz
iphone:~ mobile$ wget http://gammalevel.com/forever/Boodler-2.0.2-iPhone.patch
Now, we’ll unpack the sources and apply the patch:
iphone:~ mobile$ tar xzvf Boodler-2.0.3.tar.gz
iphone:~ mobile$ cd Boodler-2.0.3
iphone:~/Boodler-2.0.3 mobile$ patch -p1 < ../Boodler-2.0.2-iPhone.patch
Finally, we’ll build, sign, and install our copy of Boodler.
iphone:~/Boodler-2.0.3 mobile$ python setup.py build
iphone:~/Boodler-2.0.3 mobile$ ldid -S build/lib.darwin-10.5-arm-2.5/boodle/cboodle_osxaq.dylib
iphone:~/Boodler-2.0.3 mobile$ sudo python setup.py install
(You may get a complaint about a missing AudioToolbox framework. If
you do, copy it over from the official SDK, like we did during the
environment setup. It should be in
“(SDK)/System/Library/Frameworks/AudioToolbox.framework
“. Be sure to
merge them, though: don’t overwrite files, just copy the missing
ones from inside the framework.)
To test your freshly-installed Boodler, run this command:
iphone:~/Boodler-2.0.3 mobile$ boodler.py --testsound
If nothing plays, check your volume levels. If it still doesn’t work, but there’s no error, something weird is going on. Feel free to contact me with questions.
If you hear something, congratulations! Boodler now works exactly as
it does on the desktop! However, you should only use Boodler as
mobile
; it complains loudly when you use it as root
. For more
information on how to use Boodler, refer to the Boodler
documentation.
This method is exactly like the one used above, but instead of applying a patch, we’ll be editing files manually. This section is more for my reference in the future: it shows what I did, where, and why.
setup.cfg
First, we need to edit setup.cfg
so that it uses the OS X AudioQueue
driver by default:
[build_scripts]
default_driver=osxaq
Also, we need to specify what drivers we want, and which we don’t. We
don’t really want to compile anything but the osxaq
driver. Also, we
should enable integer math instead of floating-point math.
The most important point here is disabling the macosx
driver. Without disabling it, it will try to compile, and it will
fail, always.
[build_ext]
with-drivers=osxaq
without-drivers=stdout,file,lame,vorbis,shout,macosx
intmath=1
(Note: I have since learned the iPhone is completely capable of fast floating-point math, but it needs to be out of “Thumb” mode. I’ll have to investigate this further when I have time.)
setup.py
I used to have a modification for setup.py
, but if you copy over the
development framework from the official SDK, you don’t need it
anymore. Go figure.
src/cboodle/audev-osxaq.c
These mods are not really needed, and they’re a bit of a hack. They keep Boodler running even when the device is locked, though, so it’s nice to have.
At the top, near the other CoreAudio/AudioToolbox includes, add these:
#include <AudioToolbox/AudioServices.h>
#include <CoreFoundation/CoreFoundation.h>
We need a thread with a run loop, so that AudioServices can tell us when a call is coming in, or we need to be quiet. Add a new global pthread with the other global variables:
static pthread_t cfthread;
Now we need an AudioServices callback, to tell us when we need to shut
up. Right below the playCallback
function prototype, add this:
void interruptionListenerCallback(void* user, UInt32 intState)
{
if (intState == 1) // begin interrupt
{
AudioQueuePause(aqueue);
bailing = TRUE;
running = FALSE;
audev_close_device();
exit(0); // a hack, to please AudioServices
}
}
Now we need a function to run in our thread, to set up AudioServices and our callback, then to run the Run Loop:
void* cfthread_main(void* arg)
{
AudioSessionInitialize(CFRunLoopGetCurrent(), NULL, interruptionListenerCallback, NULL);
UInt32 sessionCategory = 'medi'; // media player, stays on when locked
AudioSessionSetProperty('acat', sizeof(UInt32), &sessionCategory);
AudioSessionSetActive(1);
CFRunLoopRun();
return NULL;
}
Finally, we need to actually start our thread. In audev_init_device
,
right before the block where all the properties of formataq
are set,
put this line:
pthread_create(&cfthread, NULL, cfthread_main, NULL);