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 Hanson

A 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 Disqus

Project 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.