Creating the interactive elements

Source class

A class for creating the individual sound sources.

  1. Create the Source class file.

  2. Import the required classes.

    package com.nokia.mid.mansion;
    
    import javax.microedition.lcdui.Graphics;
    import javax.microedition.media.*;
    import javax.microedition.media.control.*;
    import java.io.InputStream;
    import java.io.IOException;
    import javax.microedition.amms.control.audio3d.LocationControl;
    import javax.microedition.amms.*;
    
    import java.util.Random;
    import javax.microedition.lcdui.Canvas;
    
    
  3. Set Source to implement Runnable. Define the objects, constants and variables used by the application. 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 acoustical space.

    For more information, see LocationControl and SoundSource3D in the AMMS API specification.

    /**
     * Sound source with graphics, too
     */
    public class Source implements Runnable {
        final static int BALL_RADIUS = 5;
        final static int BALL_DIAM = BALL_RADIUS*2;
        private int x = 0, y = 0; //sound source's location
        private Player p;
        private VolumeControl volC;
        private LocationControl locC;
        private SoundSource3D ss3D;
    
        /** keeps the mover thread active until true*/
        protected boolean closed = false;
    
        // needed for collision detection in random movements:
        House house = null; 
        Canvas canvas = null; // for repaint after movement
    
        static Random random = new Random();
        private static int yellow = 0xcccc00;
    
    
  4. Create the constructor.

        public Source(int x, int y, String fileName, House house, Canvas canvas) {
    		this.x=x;
    		this.y=y;
    		this.house = house;
    		this.canvas = canvas;
    	
    		InputStream is = getClass().getResourceAsStream(fileName);
    		if (is == null)
    			System.out.println("MIDlet: error creating InputStream of" + fileName);
    		try {
    			System.out.println("MIDlet: Creating Player " + fileName);
    			p = Manager.createPlayer(is, "audio/X-wav");	  
    			if (p == null)
    				System.out.println("error creating Player of" + fileName);
    			p.realize();
    			p.setLoopCount(-1); //indefinetely
    			System.out.println("MIDlet: realized: " + fileName);
    		} catch (IOException e) {
    			System.out.println(e);
    		} catch (MediaException e) {
    			System.out.println(e);
    		}
    		volC=(VolumeControl)p.getControl("VolumeControl");
    		if (volC!=null) {
    			System.out.println("MIDlet: got VolumeControl");
    			int v = volC.setLevel(100);
    			System.out.println("MIDlet: set Volume to "+v);
    		}
    	       
    

    The GlobalManager handles the creation of SoundSource3Ds. The method createSoundSource3D 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.

    For more information, see GlobalManager, createSoundSource3D, addPlayer, setCartesian, and removePlayer in the AMMS API specification.

    		try {
    			ss3D = GlobalManager.createSoundSource3D();        
    			if (ss3D != null) {
    		        System.out.println("MIDlet: got a new SS3D");
    		        ss3D.addPlayer(p);
    		        System.out.println("MIDlet: Player added to a SS3D");
    		        locC=(LocationControl)ss3D.getControl("javax.microedition.amms.control.audio3d.LocationControl");
    		        if (locC != null) {
    		        	System.out.println("MIDlet: got LocationControl from a SS3D");
    		        	locC.setCartesian(x, 0, y);
    		        } else {
    		        	System.out.println("LocationControl not available for " + fileName);
    		        	ss3D.removePlayer(p);
    		        }
    		        p.prefetch();
    			}
    	    } catch (MediaException e) {
    	    	System.out.println(e);
    	    }	
        }
    
    
  5. Create a method to close players.

        /**
         * Deinits players
         */
        protected void destroy() {
    		closed = true;
    		if(p != null) { 
    		    p.close();
    		}
        }
    
    
  6. Create methods for starting and stopping the running of the application.

        public final void start() {
        	try {
        		p.start();
        	} catch (MediaException e) {
    		    System.out.println(e);
    		} catch (IllegalStateException ise) {
    			    //synchronization problems with close.
    		}
       }
    
        public final void stop() {
        	if(p.getState() == Player.STARTED) {
        		Thread t = new Thread () {
        			public void run() {
        				try {
        					p.stop();
        				} catch (MediaException e) {
        					System.out.println(e);
        				} catch (IllegalStateException ise) {
        					//synchronization problems with close.
        				}
        			}
        		};
    	    t.start();
        	}
        }
    
    
  7. Create a method for setting locations on the Canvas.

        public final void setLocation(int x, int y) {
    		this.x=x;
    		this.y=y;
    		if (locC != null) { 
    			locC.setCartesian(x, 0, y);
    		} 
        }
    
    
  8. Create the methods for getting the x and y coordinates.

        public final int getX() {
        	return x;
        }
        
        final int getY() { 
        	return y;
        }
    
    
  9. Create the method that runs the application.

        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) {}
    		}
        }
    
    
  10. Create a method for drawing the visible sound source to a given Graphics object.

        /**
         * Draws the sound source to given Graphics.
         * @param dx x translation in millipixels
         * @param dy y translation in millipixels
         * @param rot rotation in deci-angles
         */
        public void draw(Graphics g, int dx, int dy, int rot) {
    		int newX = Trig.transXS(x-dx, y-dy, rot) ;//+g.getClipWidth()/2;
    		int newY = Trig.transYS(x-dx, y-dy, rot) ;//+g.getClipHeight()/2;
    		drawFace(g, newX, newY);   
        }
    
    
  11. Create a method for drawing the "smiley face" to the moving sounds source.

        /**
         * Draws a face to given graphics
         */
        void drawFace(Graphics g, int x, int y) { 
    		// Draw ball:
    		g.setColor(yellow);
    		g.fillArc(x-BALL_RADIUS, y-BALL_RADIUS, BALL_DIAM, BALL_DIAM, 0, 360);
    		// Draw eyes:
    		g.setColor(0);
    		g.fillArc(x-2, y-2, 2, 2, 0, 360);
    		g.fillArc(x+2, y-2, 2, 2, 0, 360);
    		// mouth:
    		g.drawArc(x-BALL_RADIUS+1, y-BALL_RADIUS+1, BALL_DIAM-3, BALL_DIAM-3, 200, 140);
        }
    }
    

Walker class

A class that creates the walker, with which the user can explore the mansion.

  1. Create the Walker class file.

  2. Import the required classes.

    package com.nokia.mid.mansion;
    
    import javax.microedition.media.*;
    import javax.microedition.amms.Spectator;
    import javax.microedition.amms.GlobalManager;
    import javax.microedition.amms.control.audio3d.OrientationControl;
    import javax.microedition.amms.control.audio3d.LocationControl;
    import javax.microedition.amms.control.audioeffect.ReverbControl;
    
    
  3. Create the Walker class and define the objects, constants and variables used by the application and create the constructor. The Spectator class represents the listener in the virtual acoustical space. OrientationControl is an interface for manipulating the virtual orientation of an object in the virtual acoustical space. ReverbControl is an interface for manipulating the settings of an audio effect called reverb.

    For more information, see Spectator, OrientationControl, and ReverbControl in the AMMS API specification.

    /**
     * Spectator functionality.
     *
     */
    public class Walker {
        private static final int STEP = 200; //step size in mm
        private Spectator spectator;
        private LocationControl specLocC; // locC of spectator
        private OrientationControl specOriC; // OriC of spectator
        private ReverbControl reverb;
        private String revName = "none";
        private int specX = 1000, specY = 6000; // spectator location
        private int specRot = 0; // spectator rotation
        // for checking the needs for a reverb settings updates:
        private int prevRoom = -999; 
    
        public Walker (){
        	initSpectator();
        }
    
    
  4. Create a method for initializing a Spectator and fetching controls for it.

    The getSpectator method gets the Spectator, which represents the listener in the virtual acoustical space. The getControl method obtains the object that implements the specified Control interface.

    For more information, see getSpectator and getControl in the AMMS API specification.

        /**
         * 	Init spectator and get controls for it.
         */
        private void initSpectator() {   
    	    try {
    	    	spectator = GlobalManager.getSpectator();
    	    } catch (MediaException me) {
    	    	System.out.println(me);
    	    }
        
    	    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.");
    	    }
          
    

    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/disables a given effect and the isEnabled method returns true if the effect is enabled and false otherwise.

    For more information, see setOrientation, setPreset,setEnabled, and isEnabled in the AMMS API specification.

    	    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);
          }
        }
      }//initSpectator()
    
    
  5. Create the methods used for rotating and moving the "walker" around the mansion.

        public void rotateLeft() {
    		// rotate spectator left 
    		specRot = specRot - 1;
    		if (specRot == -1)
    		    specRot = 35;
    		updateSpecRot(specRot);
        }
    
        public void rotateRight() {
    		// rotate spectator right
    		specRot = (specRot + 1)%36;
    		updateSpecRot(specRot);
        }
        
        public void moveForward(House house) {
    		int newSpecX = specX + Trig.transX(0, STEP, specRot);
    		int newSpecY = specY + Trig.transY(0, STEP, specRot);
    		updateSpecLoc(newSpecX, newSpecY, house);
        }
    
        public void moveBackward(House house) {
    		int newSpecX = specX + Trig.transX(0, -STEP, specRot);
    		int newSpecY = specY + Trig.transY(0, -STEP, specRot);	
    		updateSpecLoc(newSpecX, newSpecY, house);
        }
    
        public int getX() {
        	return specX;
        }
    
        public int getY() {
        	return specY;
        }
    
        public int getRot() {
        	return specRot;
        }
    
        private void updateSpecRot(int newRot) {
    		newRot += 18;
    		if(specOriC != null) specOriC.setOrientation(newRot*10, 0, 0);
        }
    
    
  6. Create a method that updates the "walker's" location, provided the that 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, House house) {
        	if (house.isInside(newX, newY)) {
    		    specX = newX;
    		    specY = newY;
    		    if(specLocC != null)
    			specLocC.setCartesian(newX, 0, newY);
    		    
    		    // update reverb settings if necessary
    		    int currentRoom = house.inWhichRoom(specX);
    		    if (currentRoom != prevRoom) {
    				prevRoom = currentRoom;
    			    if(reverb != null) {
    					reverb.setPreset(House.presetName(currentRoom));
    					revName = House.presetName(currentRoom);
    					System.out.println("New reverb: " + House.presetName(currentRoom));
    			    }
    		    }
        	}
        }
    
    
  7. Create a method for forcing a reverb change, no matter what room the "walker" is in.

        /**
         * Forces the Reverb of Spectator independently of the room.
         */
        protected void forceReverb(int index) {
    	    revName = House.presetNameByIndex(index);
    	    reverb.setPreset(revName);
    	    System.out.println("Manually forced reverb: " + House.presetNameByIndex(index));
        }
    
    
  8. Create a method for fetching the current reverb preset's name.

        /**
         * Gets the current reverb preset's name.
         */
        protected String getRevName() {
        	return revName;
        }
    }