For information about the design and functionality of the MIDlet, see section Design.
For information about the key aspects of implementing the MIDlet, see:
The GlobalManager
handles the creation
of SoundSource3Ds
. LocationControl
is an interface for manipulating the virtual location of an object
(in this case a SoundSource3D
) in the virtual acoustic
space. SoundSource3D
represents a sound source in
a virtual acoustic space.
A Source
object is
a container for a 3D sound source:
public Source(int x, int y, String fileName, House house, Canvas canvas, int color) { this.x = x; this.y = y; this.house = house; this.canvas = canvas; this.color = color; InputStream is = getClass().getResourceAsStream(fileName); if (is == null) { throw new IllegalArgumentException("error creating InputStream of" + fileName); } try { player = Manager.createPlayer(is, "audio/X-wav"); if (player == null) { throw new IllegalArgumentException("error creating Player of" + fileName); } player.realize(); player.setLoopCount(-1); //indefinetely } catch (IOException e) { System.out.println(e); } catch (MediaException e) { System.out.println(e); } volC = (VolumeControl) player.getControl("VolumeControl"); if (volC != null) { volC.setLevel(100); } try { ss3D = GlobalManager.createSoundSource3D(); if (ss3D != null) { ss3D.addPlayer(player); locC = (LocationControl) ss3D.getControl("javax.microedition.amms.control.audio3d.LocationControl"); if (locC != null) { locC.setCartesian(x, 0, y); } else { //LocationControl not available ss3D.removePlayer(player); } player.prefetch(); } } catch (MediaException e) { System.out.println(e); } }
The createSoundSource3D
method in the GlobalManager
creates a SoundSource3D
.
The addPlayer
method adds a Player
to the module. The setCartesian
method moves the object to the
new location, and the removePlayer
method removes a Player
or all channels of a Player
from the module.
The following are methods for starting and stopping the player:
public final void start() { try { player.start(); } catch (MediaException e) { System.out.println(e); } catch (IllegalStateException ise) { //synchronization problems with close. } } public final void stop() { if (player.getState() == Player.STARTED) { Thread t = new Thread() { public void run() { try { player.stop(); } catch (MediaException e) { System.out.println(e); } catch (IllegalStateException ise) { //synchronization problems with close. } } }; t.start(); } }
The following method closes the player:
protected void destroy() { closed = true; if (player != null) { player.close(); } }
The following method sets the location:
public final void setLocation(int x, int y) { this.x = x; this.y = y; if (locC != null) { locC.setCartesian(x, 0, y); } }
The Source
class implements the Runnable
interface to update the position randomly:
public void run() { int tempX = 0; int tempY = 0; while (!closed) { tempX = x + (random.nextInt() & 256) - 128; tempY = y + (random.nextInt() & 256) - 128; if (house.isInside(tempX, tempY)) { setLocation(tempX, tempY); canvas.repaint(); } try { Thread.sleep(250); } catch (InterruptedException e) { } } }
The Spectator
class represents the listener in
the virtual acoustic space. OrientationControl
is
an interface for manipulating the virtual orientation of an object
in the virtual acoustic space. ReverbControl
is an
interface for manipulating the settings of an audio effect called
reverb.
A Walker
object is a container for
the spectator:
public Walker(House house) { try { spectator = GlobalManager.getSpectator(); } catch (MediaException me) { System.out.println(iae); } } this.house = house; changeReverbToTheCurrentRoomPreset(); } if (spectator != null) { if ((specLocC = (LocationControl) spectator.getControl("javax.microedition.amms.control.audio3d.LocationControl")) != null) { specLocC.setCartesian(specX, 0, specY); } else { System.out.println("Spectator couldn't get LocationControl."); } if ((specOriC = (OrientationControl) spectator.getControl("javax.microedition.amms.control.audio3d.OrientationControl")) != null) { specOriC.setOrientation(specRot * 10, 0, 0); } else { System.out.println("Spectator couldn't get OrientationControl."); } try { if ((reverb = (ReverbControl) GlobalManager.getControl("javax.microedition.amms.control.audioeffect.ReverbControl")) != null) { try { reverb.setPreset("mountains"); } catch (IllegalArgumentException iae) { System.out.println(iae); } reverb.setEnabled(true); if (!(reverb.isEnabled())) { System.out.println("MIDlet: enabling reverb failed."); } } else { System.out.println("Spectator couldn't get Reverb."); } } catch (IllegalArgumentException iae) { System.out.println(iae); } } }
The getSpectator
method retrieves the Spectator
. The getControl
method obtains the object that
implements the specified Control
interface. The setOrientation
method turns the object to
the new orientation. The setPreset
method sets the effect according
to the given preset. The setEnabled
method enables or disables a given
effect, and the isEnabled
method returns true if the effect
is enabled and false otherwise.
The following method updates the Walker's orientation:
private void updateSpecRot(int newRot) { newRot += 18; if (specOriC != null) { specOriC.setOrientation(newRot * 10, 0, 0); } }
The following method updates the Walker's location, provided the space is free and not a wall:
/** * Updates location if collision to the wall doesn't prevent. Updates * possible new reverb settings as well, if the spy moves to a new room. */ private void updateSpecLoc(int newX, int newY) { if (house.isInside(newX, newY)) { specX = newX; specY = newY; if (specLocC != null) { specLocC.setCartesian(newX, 0, newY); } changeReverbToTheCurrentRoomPreset(); } } /** * Forces the Reverb of Spectator independently of the room. */ protected void changeReverbTo(int index) { revIndex = index; if (reverb != null) { reverb.setPreset(getCurrentReverbName()); } } /** * Forces the Reverb of Spectator to the current room preset. */ private void changeReverbToTheCurrentRoomPreset() { // update reverb settings if necessary int currentRoom = house.inWhichRoom(specX); if (currentRoom != prevRoom) { prevRoom = currentRoom; changeReverbTo(House.presetIndexByRoom(currentRoom)); } }