Mixing MIDI, Tone, and Sampled Audio using MMAPI

By Vikram Goyal

Mobile Media API (MMAPI) is a protocol- and format-agnostic API for playing and manipulating multimedia content in mobile devices. It is a diverse API and handles several different types of media seamlessly, depending upon device capabilities. In this tech tip, you will learn how to mix and play multiple media content at the same time.

Understanding the issues of mixing in MMAPI

On the face of it, mixing sounds in a mobile applications is a desirable attribute to have, especially for multimedia-rich applications like games. MMAPI provides you the ability to mix different media, but there are pitfalls. The following sections describe some of these issues.

Device fragmentation

MMAPI implementations that return a value of true for supports.mixing system property should, in theory, be able to do the following.

  • Support the playing of at least two tones simultaneously,
  • Use Manager.playTone() when another player instance is playing back audio, and
  • Support the playback of at least two instances of audio players.

In practice, not all MMAPI implementations follow these guidelines. This is due to device fragmentation. You should consult the design guidelines supplied by the device manufacturer to find out the capabilities of the device that you are working with.

Multiple player instances

With multiple player instances active in an application, there is a danger of too many resources being taken up to service these instances. When a player instance is in a prefetched/realized state, it will become a memory liability if kept around for a long time, especially because player instances in this state can request exclusive access to system resources, like the audio hardware. Thus, even if your device's MMAPI implementation allows for more than 2 player instances to be active at any time, it is prudent to keep this number low.

MIDI, tones, and sampled audio

As I said earlier, what can be mixed depends on your device's MMAPI implementation. Generally, most implementations will allow you to mix one instance of sampled audio and one instance of either a simple tone or MIDI sound, or both.

Putting together the code

Mixing sounds is a common feature in games where a background sound plays throughout the game, while various user or application events generate their own short lived sounds. In the following example, I will use a basic sampled audio as a background score, while various events during the game play will be mixed using MIDI and Tone control. The example is created and run using Netbeans 6.5. Make sure that MMAPI is selected as an optional API while creating this application, as MIDIControl is not part of the basic MIDP 2.0 MMAPI package.

When you run this code (supplied as a Netbeans project), you will be able to mix a MIDI sound and a system-generated tone with the continuous background music. This is tested in Sun Wireless Toolkit 2.2 supplied with Netbeans. If you run this in other toolkits, or better still, on an actual device, you will need to make sure that MIDIControl is supported.

Resources


EXAMPLE SOURCE CODE

/\*
 \* TechnicalTipMIDlet.java
 \*
 \*/

import javax.microedition.media.\*;
import javax.microedition.lcdui.\*;
import javax.microedition.midlet.\*;
import javax.microedition.media.control.MIDIControl;

/\*
 \* TechnicalTipMIDlet mixes audio, MIDI and tone
 \* @author  Vikram Goyal
 \*/
public class TechnicalTipMIDlet extends MIDlet implements CommandListener {

  // define variables

  // the players for background music and MIDI
  private Player backgroundMusic = null;
  private Player aPlayer = null;

  // the MIDIControl extracted from aPlayer
  private MIDIControl mControl = null;

  // display items, the display
  private Display display = null;

  // and an alert
  private Alert alert = null;

  // commands to exit, for aCommand (MIDI) and bCommand (tone)
  private Command exitCommand = null;
  private Command aCommand = null;
  private Command bCommand = null;

  public TechnicalTipMIDlet() {

    // initialize the display
    display = Display.getDisplay(this);

    // a message for the user
    alert = new Alert("Message");
    alert.setString("Press A to play a tone, Press B to play a MIDI");
    alert.setTimeout(Alert.FOREVER);

    // create commands
    exitCommand = new Command("Exit", Command.EXIT, 1);
    aCommand = new Command("A", Command.ITEM, 1);
    bCommand = new Command("B", Command.ITEM, 1);

    // add to alert
    alert.addCommand(exitCommand);
    alert.addCommand(aCommand);
    alert.addCommand(bCommand);

    // set this class as command listener
    alert.setCommandListener(this);

    // and initialize the player instances
    initialize();
  }

  private void initialize() {

    // create and prefetch player instances
    try {

      // for the background music, load a simple wav file and put it on
      // infinite loop
      backgroundMusic =
        Manager.createPlayer(
          getClass().getResourceAsStream("music.wav"), "audio/x-wav");
      backgroundMusic.prefetch();
      backgroundMusic.setLoopCount(-1);

      // create the MIDI player, prefetch
      aPlayer = Manager.createPlayer(Manager.MIDI_DEVICE_LOCATOR);
      aPlayer.prefetch();

      // and extract the MIDIControl
      mControl =
        (MIDIControl)aPlayer.getControl(
          "javax.microedition.media.control.MIDIControl");

    } catch(Exception ex) {
      handleError(ex);
    }
  }

  public void commandAction(Command cmd, Displayable disp) {

    // handle the exit command
    if(cmd == exitCommand) {
      destroyApp(true);
      notifyDestroyed();
      return;
    }

    try {

      // if it's the aCommand
      if(cmd == aCommand) {

        // play a short MIDI event
        mControl.shortMidiEvent(MIDIControl.NOTE_ON | 11, 60, 100);
      }

      if(cmd == bCommand) {

        // if bCommand, use the Manager class to play a simple tone
        Manager.playTone(61, 1000, 100);
      }
    } catch(Exception ex) {
      handleError(ex);
    }
  }

  public void startApp() {

    try {

      // start the background music if it was created successfully
      if(backgroundMusic != null) backgroundMusic.start();
      else handleError(new Exception("Error with background player"));
    } catch(Exception ex) { handleError(ex); }

    display.setCurrent(alert);
  }

  public void pauseApp() {
  }

  public void destroyApp(boolean unconditional) {

    try {

      // close players
      if(backgroundMusic != null) {
        backgroundMusic.close();
        backgroundMusic = null;
      }

      if(aPlayer != null) {
        aPlayer.close();
        aPlayer = null;
      }

    } catch(Exception e) {
      handleError(e);
    }

  }

  // handles errors
  private void handleError(Exception ex) {
    alert.setTitle("Error");
    alert.setString(ex.getMessage());
    display.setCurrent(alert);
    ex.printStackTrace();
  }
}

Vikram Goyal is the author of Pro Java ME MMAPI, published by Apress. This book explains how to add audio, video and other multimedia capabilities to a Java-enabled phone. Vikram is also the author of the Jakarta Commons Online Bookshelf and helps manage a free craft projects website.

Comments:

Thanks for the source code but it ain't working 4 me.Why are the errors in lines 8 and 9

Posted by Amara aAlfred Amara on January 28, 2009 at 06:05 PM PST #

Amara aAlfred Amara -
The errors on lines 7 and 8 are because "import" was shown as "Import" (note the capitalization).

Posted by guest on February 03, 2009 at 10:01 AM PST #

Thanks, I fixed the incorrect capitalization in the code.

Posted by Christine Dorffi on February 03, 2009 at 10:16 AM PST #

error in line 8 and 9. thank you.

Posted by manish kumar on February 03, 2009 at 08:45 PM PST #

Comment error fixed, thanks.

Posted by Christine Dorffi on February 04, 2009 at 12:15 AM PST #

Hi
thanks for these information

i'am try to play tow music file wav and mp3
put it giv me:
javax.microedition.media.MediaException: Failed to realize Player: Malformed wave media: no FMT and/or Data.

please tell me if i can run these type or not and if there is another way to run it.

cheers;

Posted by zakarea on February 15, 2009 at 02:30 AM PST #

Hi Zakarea,

The error that you have got looks like an issue with the MMAPI implementation of your device. What is your device implementation?

Can you play a single wave file or an MP3 file without trying to play them together?

Vikram

Posted by Vikram Goyal on February 15, 2009 at 01:07 PM PST #

This code works I was able to test it out on a Motorola RaZR phone, so far so good. I am experimenting with game programming with the MotoDevStudio Eclipse IDE. This code is good for introducing a \*.wav file for the opening of a videogame splash page.

One question whats the line of code I should enable in order to display a \*.png image file while the \*.wav file plays in the background.

-Thanks

Posted by Ramon V Saldana on March 11, 2009 at 06:33 AM PDT #

Hi Ramon,

Displaying an image while playing a media file would be more involved than changing a few lines of code, but not too hard. To display an image, you will need to use the Image class in the javax.microedition.lcdui package, and you could use the code above to play a media file at the same time.

Cheers,
Vikram

Posted by Vikram Goyal on March 11, 2009 at 09:03 AM PDT #

hi, i am new to using netbeans. can u guide me to some examples on how to create mobile applications, especially on manipulating a database.
thnx

Posted by Nisreen on October 02, 2009 at 08:41 PM PDT #

Platform type: CLDC/MIDP.
Emulator Platform: Sun Java(TM) Wireless Toolkit 2.5.2 for CLDC.

Getting this when compile/run:

Running in the identified_third_party security domain
java.lang.IllegalArgumentException
at javax.microedition.media.Manager.createPlayer(Manager.java:726)
at TechnicalTipMIDlet.initialize(TechnicalTipMIDlet.java:71)
at TechnicalTipMIDlet.<init>(TechnicalTipMIDlet.java:61)
at java.lang.Class.runCustomCode(+0)
at com.sun.midp.midlet.MIDletState.createMIDlet(+34)
at com.sun.midp.midlet.Selector.run(Selector.java:150)
java.lang.Exception: Error with background player

I am total newbie with Java Mobile technology, when you find time, can you clarify this?

Martin Berger

Posted by Martin Berger on October 04, 2009 at 11:19 PM PDT #

Nisreen, I suggest these tutorials/introductions:
- http://www.netbeans.org/kb/docs/javame/quickstart.html
- http://www.netbeans.org/kb/trails/mobility.html
- http://developers.sun.com/mobility/reference/index.jsp

Posted by Christine Dorffi on October 05, 2009 at 03:39 AM PDT #

Martin,

I can't recreate your error. Could you make sure that you have all the media files in the right place?

Vikram

Posted by Vikram Goyal on October 06, 2009 at 08:40 PM PDT #

Martin, I tested this code out in 2 different IDE’s. First, MOTODEV Studio for Java ME and Netbeans IDE 6.7.

It doesn’t appear to be a flaw with Vikram’s Goyals code there might be a configuration issue on your end with the way your complier is setup. Make sure you have the latest JDK and that you are using Netbeans 6.7.

Make sure you select Java ME to begin the project in Netbeans. Then select Mobile Applications. Where it says Project Name type in TechnicalTipMIDlet. Deselect the box that is checked Create HelloMIDlet. If you follow the Netbeans 6.7 walk through it’s a basic 4 step process. One more issue if you are using Windows Vista run Netbeans 6.7 as Administrator.

I would also suggest,since you are new to Java ME programming/Netbeans environment that you play around with your compiler for a little bit. Also, read the documentation Christine posted in order to become better acquainted with the netbeans compiler.

-Good luck

rvsaldana@gmail.com

Posted by Ramon V Saldana on October 06, 2009 at 11:51 PM PDT #

Vikram & Ramon:

I resolved that by installing Sun Wireless Toolkit 2.2 and running with it.
Also this time i used "Open project" option.

Previously i tried it with Sun Wireless Toolkit 2.5.2, i though it will work.
So if you want to recreate error, you can try NetBeans 6.7 + Sun Wireless Toolkit 2.5.2 and import project as Mobile Projects with Existing MIDP Sources.

Thanks for your trouble and time.

Martin Berger

Posted by Martin Berger on October 07, 2009 at 04:06 AM PDT #

Nice information on MMAPI... I have bookmarked this post... let me know more info on this...

Posted by mary on March 07, 2010 at 02:55 PM PST #

Thanks netbeans.
Saya adalah pengguna netbeans yang masih baru, saya sangat kagum dengan netbeans, terlebih perkembangan dunia aplikasi mobile.
tapi ada sedikit kesulitan, bagaimana cara menghitung waktu mundur saat music running. thanks,
please replay to my email.

Posted by ukungzulfah on April 27, 2010 at 03:28 AM PDT #

hiii
guys m new to netbeans n wanna develop a mobile music player.
please can any one send me the example code for it???

Posted by Hemang on August 16, 2010 at 08:05 PM PDT #

It is hard to find many of the newer cellphones using Java ME on them. I think most developers have switched to Google Android. Currently, I am reading this book called ProAndroid 2 by Sayed Hashim,Satya Komatineni, Dave MacLean, seems like a very interesting read. At this time I am not even sure of what the future of Java ME will be ? There are some reports that Java ME is dead and will be replaced by Java FX. I have no idea at this time.

-Good Luck

Posted by Ramon V Saldana on August 16, 2010 at 10:16 PM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Tips for developers who use Java technologies (Java SE, Java ME, JavaFX) for mobile and embedded devices.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today