Sound Player

There are several ways to play audio on Android. One of the basic capabilities is to simply playback audio files that are saved with a Sketch. The below example uses a class called SoundPlayer (code below) to play an audio file (“beep.ogg“) that has been placed into the Sketch’s data folder.

SoundPlayer beepSound;
SoundPlayer otherSound;

void setup() {
  beepSound = new SoundPlayer(this,"beep.ogg");
  //otherSound = new SoundPlayer(this,"other.wav");
}

void draw() {
  
}

void mousePressed() {
  beepSound.play();
}
class SoundPlayer extends Object  implements android.media.MediaPlayer.OnCompletionListener {
  
  android.media.MediaPlayer mediaPlayer;
  android.content.res.AssetFileDescriptor assetFileDescriptor;
  processing.core.PApplet theSketch;
  
  boolean ready = false;
  
  public SoundPlayer(PApplet _theSketch, String audioFile) {
    theSketch = _theSketch;
    
    try {
      assetFileDescriptor = theSketch.getAssets().openFd(audioFile);
      
      mediaPlayer = new android.media.MediaPlayer();
      mediaPlayer.setDataSource(assetFileDescriptor.getFileDescriptor(),assetFileDescriptor.getStartOffset(), assetFileDescriptor.getLength());
      mediaPlayer.setOnCompletionListener(this);
      mediaPlayer.prepare();
      ready = true;
    } catch (Exception e) {
      println(e); 
    }
  }
  
  public void play() {
    if (ready) {
      try {
        mediaPlayer.start();
        ready = false;
        println("playSound");
      } catch (Exception e) {
        println(e); 
      }
    }
  }
  
  public void onCompletion(android.media.MediaPlayer mp) { 
    try {
      println("Trying to prepare");
      mediaPlayer.stop();
      mediaPlayer.prepare();
      ready = true;
    }
    catch (Exception e) {
      println(e); 
    }
  }  
}  

The SoundPlayer class uses the built-in MediaPlayer class which is the base class for video playback as well. We’ll dig deeper into the MediaPlayer in future classes.

Lots and Lots of Things

Arrays

Arrays are a convient way to handle multiple items of the same data type (integers, objects or anything else).

This is a representation of an int array containing 9 elements:

------------------------------------------
| 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256 |
------------------------------------------

The code to create this array might be something like the following:

int[] myArray = {1,2,4,8,16,32,64,128,256};

or it could be done using a for loop

int[] myArray = new int[9];
for (int i = 0; i < myArray.length; i++)
{
	myArray[i] = pow(2,i);
}

nameOfArray.length gives you the number of elements in the array.

nameOfArray[indexNumber] gives you the individual element of the array at a given index number. Remember, index numbers start at 0 so the first index of the array is 0 and the last one in our array is 8.

pow(base, exponent) is a built-in processing function for the math expression of power. 2 to the power of 2 is 4 (in other words squared). 2 power of 3 is 8 (in other words, 2 cubed). Anyh base to the power of exponent is the base multiplied by itself the exponent number of times. 2 to the power of 4 is 2 x 2 x 2 x 2 or 16.

For Loops, as you can see above, are great for dealing with arrays. Start at 0 and go to the length of the array to perform the same operation on each element in the array.

Arrays and Objects

If we develop a Ball Class such as follows:

// The name of our class
class Ball
{
  // our Class variables.  
  int wWidth;
  int wHeight;
  int bSize;
  
  int x, y;
  int xDirection, yDirection;
  
  // Constructor.  This gets called when we create a "new Ball"
  Ball(int windowWidth, int windowHeight, int ballSize)
  {
    wWidth = windowWidth;
    wHeight = windowHeight;
    bSize = ballSize;
    x = 1;
    y = 1;
    xDirection = 1;
    yDirection = 1;
  }

  Ball(int windowWidth, int windowHeight, int ballSize, int xPosition, int yPosition, int xDir, int yDir) 
  {
    this(windowWidth, windowHeight, ballSize);
    x = xPosition;
    y = yPosition;
    xDirection = xDir;
    yDirection = yDir;
  }
  
  // Our method to determine current position of the ball.
  void compute()
  {
    if (x < wWidth && x > 0)
    {
      // Move along x axis
      x += xDirection;
    }
    else
    {
      // Change direction, from positive to negative and vice versa
      xDirection = xDirection * -1;
      x += xDirection;
    }
    
    if (y < wHeight && y > 0)
    {
      y += yDirection;    
    }
    else
    {
      yDirection = yDirection * -1;
      y += yDirection;
    }
  }
  
  // This actually displays our ball, it gets called in the main draw function
  void display()
  {
    compute();  // first we run the computation
    ellipseMode(CENTER);
    ellipse(x,y,bSize,bSize);   
  }

}

And decide that we want multiple Ball's, we can use an "array" of Ball objects like so:

Ball[] ourBalls;  // Declare array of Ball objects called ourBalls
int numBalls = 50;  // An integer to hold the number of Ball objects we are going to create

void setup()
{
  size(500,500);
  ourBalls = new Ball[numBalls];  // Initalize the array, passing in the brackets the number of Ball objects
  for (int i = 0; i < ourBalls.length; i++)  // Use our nifty for loop, starting at 0 and going to the number of objects in the array.  Incrementing i by 1 each time.
  {
	// Using the overloaded constructor
	// Ball(int windowWidth, int windowHeight, int ballSize, int xPosition, int yPosition, int xDirection, int yDirection)
	// Picking some values just to see what happens    
	// Create a Ball object for each element in the array.
	ourBalls[i] = new Ball(width, height, i+10, i+1, i-1, i, 1 - i);
  }
}

void draw()
{
  background(0);
  // Use another for loop to tell each of the Ball objects to display
  for (int i = 0; i < ourBalls.length; i++)
  {
	ourBalls[i].display();
  }
}  

Classes and Objects

Java and therefore Processing is an Object Orientated Language. This means that Java makes it easy to use objects in your code.

An Object is a datatype just like a variable with a couple of differences. Objects can hold multiple pieces of data and can hold methods to manipulate that data.

A Class is the blueprint for an Object. It is the code that represents the data and methods that are contained within.

I like to think of the following example when thinking about Classes and Objects.
We are all people, human people. That is a class. The class states that we have hair, eyes, ears, are capabile of walking and so on.

Our human class, would contain variables that hold the color of our eyes, hair, how fast we walk and so on. It would also contain methods for walking, talking, eating and everything else that we do.

In order to create a person (object), we would use the human (class) as a blueprint and fill in the values particular to the person we are creating.

In (some form of) English:

Define Human Class
	Human Has A Hair Color, Eye Color and Shoe Size.
	Human Can Walk and Run.
Create New Human
	This Human has Green Hair, Orange Eyes and wears a size 10 shoe.

In Processing we would open a new Tab and type the following:

// Give our class a name and tell Processing it is a class.
class Human
{
	// Variables for our individual humans.
	int hairColor;  // Shade of gray for simplicity sake
	int eyeColor;        
	int shoeSize;
	
	// Constructor, what we use to create a NEW human object: a person
	// A special type of method.
	Human(int theHairColor, int theEyeColor, int theShoeSize)
	{
		hairColor = theHairColor;
		eyeColor = theEyeColor;
		shoeSize = theShoeSize;
	}
	
	// our walk function for humans, returns distance walked, takes in number of steps
	int walk(int numSteps)
	{
		int distance = numSteps * shoeSize;
		return distance;
	}
	
	// our run funtion for humans, returns distance walked, takes in number of steps
	int run(int numSteps)
	{
		int distance = walk(numSteps) * 2;
		return distance;
	}
}

In order to create a human in our main program we would do the following:
You will notice that you call methods of the class/object using “.” method name on the actual object.

Human shawn;  // Declare the variable shawn to be an object of type Human

void setup()
{
	shawn = new Human(30,129,12); // Create the new human, run the constructor
	int distanceWalked = shawn.walk(10); // Have shawn walk, get the distance walked
	println("Shawn Walked: " + distanceWalked);
	int distanceRan = shawn.run(10); // Have shawn run
	println("Shawn Walked: " + distanceRan);
}

Using Objects makes it very easy to create multiple versions of the same thing, each with it’s own variables.

We can add a new Human called dan to illustrate:

Human shawn;  // Declare the variable shawn to be an object of type Human
Human dan;

void setup()
{
	shawn = new Human(30,129,12); // Create the new human, run the constructor
	dan = new Human(80,90,9);
	
	int distanceWalked = shawn.walk(10); // Have shawn walk, get the distance walked
	int dDistanceWalked = dan.walk(10);
	println("Shawn Walked: " + distanceWalked + " and Dan walked: " + dDistanceWalked);
	
	int distanceRan = shawn.run(10); // Have shawn run
	println("Shawn Walked: " + distanceRan);
}

Let’s go through another example:

// The name of our class
class Ball
{

  // our Class variables.  
  int wWidth;
  int wHeight;
  int bSize;
  
  int x, y;
  int xDirection, yDirection;
  
  // Constructor.  This gets called when we create a "new Ball"
  Ball(int windowWidth, int windowHeight, int ballSize)
  {
	wWidth = windowWidth;
	wHeight = windowHeight;
	bSize = ballSize;
	x = 1;
	y = 1;
	xDirection = 1;
	yDirection = 1;
  }
  
  // This is an Overloaded constructor
  Ball(int windowWidth, int windowHeight, int ballSize, int xPosition, int yPosition)
  {
	this(windowWidth, windowHeight, ballSize);
	x = xPosition;
	y = yPosition;
  }
  
  // Our method to determine current position of the ball.
  void compute()
  {
	if (x < wWidth && x > 0)
	{
	  // Move along x axis
	  x += xDirection;
	}
	else
	{
	  // Change direction, from positive to negative and vice versa
	  xDirection = xDirection * -1;
	  x += xDirection;
	}
	
	if (y < wHeight && y > 0)
	{
	  y += yDirection;    
	}
	else
	{
	  yDirection = yDirection * -1;
	  y += yDirection;
	}
  }
  
  // This actually displays our ball, it gets called in the main draw function
  void display()
  {
	compute();  // first we run the computation
	ellipseMode(CENTER);
	ellipse(x,y,bSize,bSize);   
  }

}

Here is what would be in the main Processing program:

Ball aBall, anotherBall;

void setup()
{
  size(500,500);
  aBall = new Ball(width,height,100);  // Call the constructor of Ball to create a new Ball
  anotherBall = new Ball(width,height,5,100,2); // Same..
}

void draw()
{
  background(255);
  aBall.display();  // Call the display function/method on the aBall object.
  anotherBall.display(); // Call it on the anotherBall object.
}               

Modularity

Built-In Methods

These methods get called automatically (they are callbacks) by Processing. You override them and implement them yourself.

mouseDragged(): Called when the screen is pressed and finger moved. Will happen repeatedly as the finger is dragged on the screen.

mousePressed(): Gets called when the screen is pressed.

mouseReleased(): Gets called when the screen which has been pressed is released.

keyPressed(): Gets called when a key is pressed. May happen multiple times in a row with one key press.

keyReleased(): Gets called when a key is released.

Test it out:

void setup()
{
}

void draw()
{
}

void mouseDragged() 
{
  println("mouseDragged");
}

void mousePressed() 
{
  println("mousePressed");
}

void mouseMoved() {
  // Doesn't work, no mouse moved in Processing for Android
  println("mouseMoved");
}

void mouseReleased() {
  println("mouseReleased");
}

void keyPressed() {
  println("keyPressed");
}

void keyReleased() {
  println("keyReleased");
}

Mouse Released Example:

void mouseReleased()
{
  fill(255, 127, 0);
  ellipse(mouseX, mouseY, 10, 10);
}

Drawing Example:

int x, y;

void setup()
{
  size(500, 500);
  background(255);
}

void draw()
{
  // Empty!
}

void mouseDragged() 
{
  line(x, y, mouseX, mouseY);
  x = mouseX;
  y = mouseY;
  println("mouseDragged");
}

void mousePressed() 
{
  x = mouseX;
  y = mouseY;
  println("mousePressed");
}

Creating our own methods

We can create our own methods that we can call elsewhere in your code. There are many advantages to writing methods rather than putting everything in the setup() or draw() methods.

Reuse: Writing a function for a commonly used set of commands that you can call over and over again. For instance, you have a complex shape that you use throughout your code. Rather than cutting and pasting those instructions everywhere you can write them once and call it over and over again.
Encapsulation: Putting functionality in a method and thereby seperating it from the rest of the code helps in understanding the program. It also makes making changes to that code much easier.

Methods comprise of the following parts:
Return Type: This is the type of data (or variable) that the method returns. So far we have only seen the built-in methods which return nothing and therefore use the type: void. Any of the other data types are acceptable as well.
Name: This is simply the name of the method. You will call or execute the method using this. An example is setup.
Arguments: You can pass data into a method through the use of arguments. These are specified as variables of a certain type (your choosing) that the method can then make use of. These variables are local to the method.
Code Block: These are the instructions or code that the method will execute when called.

Here is an example:

// return type, function name, arguments, including types
int ourCoolMethod(int someInt, int someOtherInt)
{
  // Declare a variable
  int aThridInt;
  
  // Do something valuable
  aThridInt = someInt * someOtherInt;
  aThridInt++;
  
  // Return something (an integeter in our case as it must match the return type)
  return aThridInt;
}

We would run this method somewhere else in our code such as:

void setup() {        
  int myResult = ourCoolMethod(10, 2);
  print(myResult);

  int a = 10;
  int b = 3;
  int c = ourCoolMethod(a, b);
  print(c);
}

// return type, function name, arguments, including types
int ourCoolMethod(int someInt, int someOtherInt)
{
  // Declare a variable
  int aThridInt;
  
  // Do something valuable
  aThridInt = someInt * someOtherInt;
  aThridInt++;
  
  // Return something (an integeter in our case as it must match the return type)
  return aThridInt;
}

Crazy Example:

int acounter = 0;

void setup()
{
  size(400,400);
  background(255);
}

void draw()
{
  fill(acounter%255);
  if (acounter%2 == 0)
  {
    drawLessCrazyShape(acounter%width,acounter%height,60);
  }
  else
  {
    drawCrazyShape(width-(acounter%width),height-(acounter%height));
  }
  acounter++;
}

void mousePressed()
{
    fill(mouseX,0,mouseY);
    drawCrazyShape(mouseX, mouseY);
}

void mouseDragged()
{
   fill(255,0,0);
   drawLessCrazyShape(mouseX,mouseY,50);
}

void drawCrazyShape(int x, int y)
{
  beginShape(POLYGON); 
    vertex(x, y); 
    x = x/(y+1)*2;
    vertex(x, y);
    y++;
    x--; 
    vertex(x, y); 
    y = x/(y+1)*2;
    vertex(x, y);
    x -= 30; 
    vertex(x, y); 
    vertex(y*2, x); 
  endShape();
}

void drawLessCrazyShape(int one, int two, int size)
{
  beginShape(POLYGON); 
    
    vertex(one, two); 
    
    one -= size;
    two += size;
    vertex(one, two);
    
    one -= size;
    two -= size;
    vertex(one, two); 

    one += size;
    two -= size;
    vertex(one, two);

    one -= size;
    two += size;
    vertex(one, two); 
    
  endShape();
}