The tricky thing about getting kids interested in programming is finding a project they can tackle that is exciting and doesn’t require a large commitment on their part. I have a 13-year-old son who is very fond of his EVO 4G. As summer draws to a close, I decided I’d write a short tutorial he could try on one of the increasingly frequent afternoons he calls or texts me at work to announce that he is bored.
I pondered a bit on exactly what kind of tutorial to write; while geeks like me might enjoy implementing a simple algorithm to spit out a Fibonacci sequence, inflicting such an exercise on a child might be considered torture in some states. Kids love smartphones because of the multimedia capabilities, so I knew I’d have to exploit those capabilities if I wanted to interest my son.
The answer came to me riding in the car, when for the 40th time I considered ripping the EVO from my son’s hands and pitching it out the window so I didn’t have to hear one more electronically simulated bodily function. It was sound board of course. One of those annoying programs in the marketplace that allows you to press a button and rewards you for doing so by playing a wave file.
I don’t think for one minute the Google marketplace needs another sound board. I am, however, for anything that gets young people using their brains and interested in engineering. Android is a great platform for getting started with programming. The tools are free. Thanks to the emulator, you don’t even have to own an Android phone. And for a one-time fee of $25 you can even make your application available in the Android Market for all your friends and family to download.
The source code for a very simple sound board follows. Or if you wish to download the entire project you can do so here. Have fun!
Step one: Create a new Android project for SDK 1.6 or higher.
Step two: Add a new layout for a list view in your \layout folder.
MAIN.XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffff">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
android:textColor="#000000"
android:background="#ffffff"
android:textStyle="bold"
android:textSize="14sp"/>
<ListView
android:id="@+id/android:list"
android:background="#ffffff"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:dividerHeight="1dip"/>
</LinearLayout>
Step three: You’ll also need a list view row layout in the same folder.
LIST_ROW.XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip"
android:background="#ffffff">
<TableLayout
android:layout_width="fill_parent"
android:layout_weight="1"
android:layout_height="fill_parent"
android:stretchColumns="*"
android:background="#ffffff">
<TableRow>
<ImageView
android:id="@+id/icon"
android:padding="2dip"
android:background="#ffffff"/>
<TextView
android:id="@+id/description"
android:padding="2dip"
android:textSize="12sp"
android:textColor="#000000"
android:singleLine="true"
android:background="#ffffff"/>
</TableRow>
</TableLayout>
</LinearLayout>
Step four: For this simple sample, my sound board consists of only three sounds. Each one is an animal sound, and so I needed a wave file for each, as well as an image. I placed the three image files in the \drawable folder. The digital sounds need to go in the \raw folder. If your project doesn’t already have a \raw folder, you can just create one under the \res folder.
Gotcha! While the documentation for Android multimedia development says it supports WAV files directly, in my experience this support varies greatly between devices and even versions of the operating system. I highly recommend converting you WAV files to OGG files. If you aren’t familiar with OGG files, there are plenty of free applications available that save WAV files as OGG files. Just Google it.
Step five: Now we need a simple container class to hold our sound objects.
Sound.java
package com.authorwjf;
public class Sound {
private String mDescription = "";
private int mSoundResourceId = -1;
private int mIconResourceId = -1;
public void setDescription(String description) { mDescription = description; }
public String getDescription() { return mDescription; }
public void setSoundResourceId(int id) { mSoundResourceId = id; }
public int getSoundResourceId() { return mSoundResourceId; }
public void setIconResourceId(int id) { mIconResourceId = id; }
public int getIconResourceId() { return mIconResourceId; }
}
Step six: A custom adapter for our list view.
SoundAdapter.java
package com.authorwjf;
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class SoundAdapter extends ArrayAdapter<Sound>{
private ArrayList<Sound> items;
private Context c = null;
public SoundAdapter(Context context, int textViewResourceId, ArrayList<Sound> items) {
super(context, textViewResourceId, items);
this.items = items;
this.c = context;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.list_row, null);
}
Sound s = items.get(position);
if (s != null) {
TextView description = (TextView) v.findViewById(R.id.description);
if (description != null) {
description.setText(s.getDescription());
}
ImageView icon = (ImageView) v.findViewById(R.id.icon);
icon.setImageResource(s.getIconResourceId());
}
return v;
}
}
Step seven: And last but not least our Main.
Main.java
package com.authorwjf;
import java.util.ArrayList;
import android.app.ListActivity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
public class Main extends ListActivity {
private ArrayList<Sound> mSounds = null;
private SoundAdapter mAdapter = null;
static MediaPlayer mMediaPlayer = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//create a simple list
mSounds = new ArrayList<Sound>();
Sound s = new Sound();
s.setDescription("Elephant");
s.setIconResourceId(R.drawable.elephant);
s.setSoundResourceId(R.raw.elephant);
mSounds.add(s);
s = new Sound();
s.setDescription("Rooster");
s.setIconResourceId(R.drawable.rooster);
s.setSoundResourceId(R.raw.rooster);
mSounds.add(s);
s = new Sound();
s.setDescription("Kitten");
s.setIconResourceId(R.drawable.kitten);
s.setSoundResourceId(R.raw.kitten);
mSounds.add(s);
mAdapter = new SoundAdapter(this, R.layout.list_row, mSounds);
setListAdapter(mAdapter);
}
@Override
public void onListItemClick(ListView parent, View v, int position, long id){
Sound s = (Sound) mSounds.get(position);
MediaPlayer mp = MediaPlayer.create(this, s.getSoundResourceId());
mp.start();
}
}
Gotcha! The Android platform actually supports two mechanisms for playing sounds: SoundPool and MediaPlayer. I chose the latter in this instance because in my opinion it is more straightforward. However, it has more overhead and not all the flexibility you get with SoundPool. If you are planning to create a sound board for more than just your own gratification, I recommend reading up on both Android multimedia libraries and choose the one that best meets your needs.