Penlets.com provides resources for users and developers of the Pulse smart pen from LiveScribe.
Subscribe: RSS Feed - Developers Group
Tutorial
Introduction to Playing Sounds
Tutorial by Robert HansonA fundamental rule of building a user interface is to provide immediate feedback to the user to indicate that something happened, or needs to happen. When writing a penlet, assuming the user is writing something with the pen, it may be best to indicate what is going on with sounds instead of relying on the display. This could be as simple as a "beep", or perhaps a voice that says "draw nine vertical lines", as the Pulse demo apps do. In this tutorial you will learn how to load audio clips onto your pen, and learn how to play them.
The first step (of course) is to create some audio clips. The clips must be stored in either WAV or AAC. If you have a choice you may want to use WAV as it is an uncompressed and lossless format, while AAC is compressed with some loss of audio quality. On the other hand, if your audio clips are very long, AAC may be preferable so that you don't eat up too much of the storage space on the pen.
Editor's Audio Tool Pick: Audacity If you don't already have a favorite audio recording and editing tool, you may want to try out Audacity. Audacity is free, open-source, and most important of all is powerful enough for most editing needs.
Recommended Audio Format Settings Livescribe
recommends the following audio settings when you create you audio clips.
Failure to follow the recommendation could result in no audio playback.
- Uncompressed PCM
- Audio Sample Rate: 16 kHz
- Stereo or Mono
- Audio Sample Size: 16-bit (recommended)
You will need place your finished audio clips under the
/res
directory of your project. Although you can just drop your clips in
this directory it may be beneficial to create a subdirectory under
/res
that is used just for your clips. For this tutorial I created a
directory
/res/audio
, and placed my clips there.
For my specific audio project I decided to write a penlet that plays
the sounds of guitar strings. The first stroke plays the first
string, the second stroke plays the second, and so on, repeating the
series after the sixth string. My audio clips are named
string1.wav
through
string6.wav
.
Now that we have some clips, playing them is very simple. Because it is not complex, I have decided to show you the entire sample application below, following that I will point out the important lines.
package com.penlets.audio;
import com.livescribe.afp.PageInstance;
import com.livescribe.display.Display;
import com.livescribe.event.StrokeListener;
import com.livescribe.penlet.Penlet;
import com.livescribe.penlet.PenletStateChangeException;
import com.livescribe.penlet.Region;
import com.livescribe.ui.MediaPlayer;
import com.livescribe.ui.ScrollLabel;
public class AudioDemo extends Penlet implements StrokeListener
{
private Display display;
private ScrollLabel label;
private MediaPlayer mediaPlayer;
private int currentSound = 1;
private int maxSound = 6;
public boolean canProcessOpenPaperEvents ()
{
return true;
}
/* ***********************************************
* Abstract methods of Penlet.
*********************************************** */
public void initApp () throws PenletStateChangeException
{
display = context.getDisplay();
label = new ScrollLabel();
mediaPlayer = MediaPlayer.newInstance(this);
}
public void activateApp (int reason, Object[] args)
{
label.draw("Draw lines to play sounds", true);
display.setCurrent(label);
context.addStrokeListener(this);
}
public void deactivateApp (int reason) {
context.removeStrokeListener(this);
}
public void destroyApp () throws PenletStateChangeException { }
/* ***********************************************
* StrokeListener interface methods.
*********************************************** */
public void strokeCreated (long startTime, Region region, PageInstance pageInstance)
{
mediaPlayer.play("/audio/string"
+ currentSound + ".wav", false);
currentSound++;
if (currentSound > maxSound) {
currentSound = 1;
}
}
}
Lines 26-48 implement the abstract
Penlet
methods, which are used to implement the initialization and
destruction of our penlet. The
initApp()
is the first point of interest. On line 34 we create a new
MediaPlayer
instance. You could create this elsewhere, but by creating it in
initApp()
we will reuse the same instance if the penlet is executed multiple
times. When we call
MediaPlayer.newInstance(this)
, notice that we passed our penlet as an argument. This reference to
our penlet allows the MediaPlayer to distinguish between out audio
clips and clips belonging to another penlet. This also means that you
can't share clips across penlets.
Also of note is line 41 where we add our penlet as a
StrokeListener
. This isn't specific to playing audio clips, but for this specific
penlet it allows us to capture stroke events and play sounds when
they occur. Along these same lines,
lines 21-24 return a
true
value for
canProcessOpenPaperEvents
, otherwise storke events would not be passed to our penlet.
Lines 50-63 are where we handle the stroke event and play the
sound. Besides the small piece of logic that iterates the counter,
the one line that plays the actual clip is line 56 where we call
mediaPlayer.play()
. The
play()
takes two arguments. The first is the path to the sound clip. The
path begins with a slash, indicating our projects
/res
directory, followed by the path to the file from there. So specifying
"/audio/string1.wav"
will play the clip in our project located at
/res/audio/string1.wav
. The second argument is boolean value indicating if you want the
clip to wait for any currently playing clips to complete. We pass
false
for this, which will play the specified clip immediately, cutting off
any clip currently playing.
There is more to
MediaPlayer
than we have shown here, but this should get you started with the
basics and allow you to experiment further.
Happy coding!
Comments (View) blog comments powered by DisqusProject Information
Tested for use with: JaveOne-SDK
New Tutorials
Using a Shared Library
Learn how to create a library of utils that you can
share between projects.
Capturing Drawn Shapes
Learn how to capture shapes drawn by the pen and determine relationships.
Penlets 101
Never written a penlet before? Then start here with Penlets 101!
Creating a Custom Vocabulary
Learn how to create a custom vocabulary for your ICR applications.
Using Properties Files
J2ME lacks a Properties class. In this tutorial we roll our own,
along with split and chomp functions.