J2ME: problems with sound

October 8th, 2010

Recently I am trying to write a J2ME game for Nokia S60 5th edition and Symbian^3 devices, but I face a strange problem with sound: if we have a graphics thread working hard redrawing the screen, then playing sound completely slows it down. This is unexpected because if there is no graphics thread, playing sound in very same way uses about 2-3% of CPU in my Nokia N97.

I wrote a simple J2ME app to ilustrate the problem. Its source can be downloaded from here: SoundTest.tar.gz . Here’s the Java source:


class SoundMIDlet:

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class SoundMIDlet extends MIDlet
{
private SoundCanvas mCanvas = null;

public void startApp()
{
mCanvas = new SoundCanvas();
Display.getDisplay(this).setCurrent(mCanvas);
}

public void pauseApp() { }
public void destroyApp(boolean uncond) { }
}

class SoundCanvas:

import javax.microedition.lcdui.*;

public class SoundCanvas extends Canvas implements Runnable
{
private Thread mSoundThrd= null;
private PlayerPool pool;

private int height,width;
private long time=10;
private int angle=0;

public SoundCanvas()
{
this.setFullScreenMode(true);
pool = new PlayerPool(50);

mSoundThrd = new Thread(this);
mSoundThrd.start();

height = getHeight();
width = getWidth();
}

protected void pointerPressed (int x, int y)
{
pool.playSound();
}

public void paint(Graphics g)
{
double radians, x, y;
int len = width/2 - 10;

g.setColor(0,0,0);
g.fillRect(0, 0, width, height );

for( int i=0; i<=255; i++) { g.setColor(i,i,i); if( ++angle >=360 ) angle-=360;
radians = (double)(angle*Math.PI) / 180;
x = len*Math.sin(radians);
y = len*Math.cos(radians);

g.drawLine( width/2, width/2, width/2+(int)x, width/2 +(int)y);
}

g.drawString( "FPS:"+(1000/time), width/2, height -100, Graphics.TOP|Graphics.HCENTER );
}

public void run()
{
long tmptime;

while(true)
{
tmptime = System.currentTimeMillis();

repaint();
serviceRepaints();

try { Thread.sleep(20); }
catch(InterruptedException ex) {}

time = System.currentTimeMillis() - tmptime;
}
}
}

class PlayerPool:

import java.io.InputStream;

import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.control.VolumeControl;

public class PlayerPool
{
protected Player player;

public PlayerPool(int volume)
{
try
{
InputStream is =getClass().getResourceAsStream("laser.wav");
player = Manager.createPlayer(is, "audio/wav");
player.realize();
player.prefetch();
VolumeControl vol = (VolumeControl)player.getControl("VolumeControl");
vol.setLevel(volume);
}
catch(Exception ex) { }
}

public void playSound()
{
try
{
if (player != null)
{
if (player.getState() == Player.UNREALIZED)
{
player.prefetch();
player.realize();
}

int state = player.getState();

if (state != Player.CLOSED)
{
if( state!= Player.STARTED ) player.start();
else player.setMediaTime(0);
}
}
}
catch (MediaException e) { }
}
}

Leave a Reply