Sound Playback in Processing for Android

I added sound playback to the Processing app that I’m currently porting to Android. On the desktop, I used the Minim sound library, which is not supported on Android (although there is some discussion about alternatives and a possible port). All I really need from a sound library is a way to play several .ogg (or .mp3 or .wav) files simultaneously and asynchronously, query their playback durations, maybe set the playback volume of individual sounds, and stop playing sounds at any time.

The android.media.MediaPlayer class is just fine for that.

In general, a sound can be played using the following code:

snd = new MediaPlayer();
snd.setDataSource(path_or_url_of_sound_to_play);
snd.prepare();
snd.start()

My own app is a game that contains only a handful of .ogg files. I keep a HashMap of the MediaPlayer instances for all sounds in the game, with prepare() already called on them. Then I simply call start() whenever an event triggers the sound in the game.

I store all sounds in the assets/ sub-folder of the project, so that they are automatically included in the app package. However, this does not mean that these files will exist in the current working directory when the app is run.

Loading the files as if they existed in the current working directory does not work:

snd = new MediaPlayer();
snd.setDataSource("./Sounds/win.ogg");
snd.prepare();  // <- raises an exception because the file does not exist

This results in an error similar to this:

PlayerDriver: Command PLAYER_SET_DATA_SOURCE completed with an error
or info PVMFErrNotSupported
MediaPlayer: error (1, -4)
SoundTest: Error! java.io.IOException: Prepare failed.: status=0×1
at android.media.MediaPlayer.prepare(Native Method)

In Processing, you can normally use the createInput() method to open a file in the assets folder. This method returns an InputStream, but there is no way to initialize a MediaPlayer from an InputStream.

I did try to use the dataPath() method of the sketch to retrieve the absolute path to the file, but as we’ll see, this doesn’t work either:

snd = new MediaPlayer();
snd.setDataSource(theSketch.dataPath("Sounds/win.ogg"));
snd.prepare();  // <- raises an exception because the file does not exist

The dataPath() method returns a path like “/data/data/org.realmike.myapp/files/data/Sounds/win.ogg”, but no such file exists. All files in the assets/ sub-folder are actually inside the .apk (which I suppose is some kind of .jar file). They do not exist as separate files in the filesystem.

So, to load sound files stored in the assets folder, you should retrieve the AssetManager instance from the sketch and initialize the MediaPlayer with a file descriptor:

snd = new MediaPlayer();
AssetManager assets = theSketch.getAssets();
AssetFileDescriptor fd = assets.openFd("Sounds/win.ogg");
snd.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
snd.prepare();

Make sure to pass fd.getStartOffset() and fd.getLength() to setDataSource(). The file descriptor returned by fd.getFileDescriptor() refers to the entire app package. Without the offset and the length, the MediaPlayer will try to interpret the .apk file as a sound file—and fail.

There is a different way to load sounds: As described in the Android Dev Guide, you can also store sounds in the res/raw/ folder of the project and use MediaPlayer.create() to load them:

MediaPlayer mp = MediaPlayer.create(context, R.raw.sound_file_1);
mp.start();

As far as I can tell, this approach requires you to hard-code the integer constants that refer to the sounds (“R.raw.sound_file_1″) in the source code*. As these constants are auto-generated during the build, I did not find a way to store these constants in a data file that my app could read, so that I could associate in-game events with sounds at runtime.

*) I don’t know enough about Java introspection to turn a string such as “sound_file_1″ into the corresponding constant from R.raw.

Portions of this page are reproduced from work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License.

1 comment to Sound Playback in Processing for Android

  • Thank you for this, I can’t believe it so tricky to get audio playback to work.
    I had it all written using Minim which worked great in Processing but isn’t available to run on the Android phone.

    Thanks again, you’ve saved me!

Leave a Reply

  

  

  

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Ads