Published using Google Docs
Processing Mini-Project Tutorials: Sound Waves
Updated automatically every 5 minutes

Sound Waves

Clicking on the screen results in a sound playing and a colourful circular wave emanating from the click location.

Example (requires Java plugin): http://gailcarmichael.com/processing/workshop/SoundWaves/

Concepts used: coordinates, colours, mouse interaction, objects, lists, shapes, sounds

Step-by-Step

Here’s a general overview of what we’re doing in this project:

Setting Up A Circle Class

Let’s begin our project by breaking the problem down a bit.  Let’s say for now that we only want one circle on the screen at a time (if the user clicks again before the circle is done, we forget about the old circle and start a new one).  We’ll also say that one circle will be the same colour no matter where it is on the screen.

There are a number of things we need to know about our circle.  We have to keep track of where it is on the screen, how big it is at a given moment in time, and what colour it is.  Because we have multiple bits of data to keep track of, it would be worth making a Circle class to store it all in one object.

(If you need to review how objects work, have a look at our slides from this morning, or read this more in-depth tutorial. Remember a class is like a blueprint, and the object is the model we create.)

Create a new tab in your project by clicking the right arrow at the top right of the editor, and choosing “New Tab.”  Name that tab Circle.

In the new tab, create your new class that will define what a circle can be like:

class Circle

{

  // we’ll put variables in here

}

Add the Circle class code above to the Circle tab.

We need to add a few variables to our class.  Remember that variables we declare here will be associated with each individual object we create; that is, there will be a whole new set of these variables each time we make a new circle.

Here are the variables we need to add:

Add the variables in the above list to the Circle class (list them under the first curly brace).

That should do it for now.  Go back to the main tab (the one with the same name as your project) to get ready for the next step.

Creating a New Circle

In this step, we’ll test out our Circle class and make it grow each frame (we’ll just do it at the beginning of the program for now, and make changes later so that circles are created when we click the mouse).

Let’s start adding some variables at the top of the main tab of our project.  We need to keep track of what radius a circle should start with, how much the radius show grow by each frame, and how big the radius should grow before we’re done with it.  We should put all this together at the top so we can use the numbers more than once, but only have to change them in one place if we don’t like them.

// Variables

int initCircleRadius = 5; // start size

int maxCircleRadius = 250; // max size

int deltaCircleRadius = 5; // how much to grow the radius each frame

Add the above code at the top of the file in the main tab (the main tab has the same name as your project).

We also need a variable to store a circle object, so go ahead and declare a new variable of type Circle in the same place.

Add a new variable of type Circle under the variables that are already there. Call it myCircle.

Now that we have a variable to store our Circle in, we have to actually create a new object using the class definition we made earlier.  We can do this in the setup() method, since we only need to do it once when the program starts.

Add an empty setup() method below the variables in the main tab.  Review the Photo Painting tutorial if you aren’t sure how to do this.

You can create a new circle like this:

myCircle = new Circle();

In the setup() method, create a new Circle and save it in the myCircle variable.

Now that we’ve created a circle, we should probably fill in some details about its colour, etc.  For example, we should set its radius to be the starting radius we defined earlier:

myCircle.radius = initCircleRadius;

Assign reasonable values to all the variables in the Circle object.

Drawing the Circle

To test that what we’ve done so far works, let’s draw our circle on the screen.  We need to write a draw() method, and inside that, draw our circle.  If you need to review how the draw() method works, check out the relevant Processing reference page.

Go ahead and create a draw() method, and inside it, start by making the background a solid white (it’s good to start each frame with a blank canvas).

Add an empty draw() method below the setup() method.  Inside the draw() method, set the background to be solid white.

We’ll draw an ellipse (since a circle is really just an ellipse with equal radii).  Use your circle object’s variables to draw the appropriate ellipse (that is, don’t use arbitrary numbers, but get the values stored inside your object).  I made my circle have a thicker-than-default stroke (i.e. outline) with the colour stored in my object, and no fill.

Using the Circle object’s variables (x,y coordinates, radius, and color), draw an ellipse as the next line in the draw() method.

Run and test the program to make sure the circle appears the way you intended it to.

Growing the Circle Each Frame

Next up, we want to make our circle get a bit bigger for each frame of the program’s animation so it looks like it’s growing.

The draw() method is already called each frame, so let’s take advantage of that.  After displaying the circle to the screen, we can simply add to its radius so that it will appear bigger the next frame when it’s drawn again.

Add deltaCircleRadius to myCircle’s radius after you draw the ellipse in the draw() method.

Run the program to see whether your circle grows.

Did it work? Good! But you may have noticed one little problem -- the circle just keeps on growing until it’s off the screen.  We actually want it to stop before that.  Use the maxCircleRadius you defined earlier to check the radius every time draw() is called.  If the radius is bigger than the max, don’t draw the ellipse.

Add an if-statement to the draw() method.  Your if-statement will check whether the circle’s current radius is less than maxCircleRadius.

Move the code that adds to the circle’s radius inside the if-statement so it only happens when the radius isn’t too big.

Run and test the program to make sure everything’s working.

Putting the Circle Where the Mouse is Clicked

Now let’s change our program so that the circle appears only when the mouse is clicked, and is centered on the location of the click.

To do this, we need a mouseClicked() method.  Check out the reference page.

Add an empty mouseClicked() method under the draw() method.

In mouseClicked(), we want to create a new circle.  This will replace the circle creation we did in setup(), since we don’t want a circle at the beginning of the program anymore.

Move all of the circle creation and variable assignment code from setup() to mouseClicked().

Run the program and make sure that the circle only appears when the mouse is clicked.

Once that’s working, you can change the location of the circle to be where the mouse was clicked.  The cursor location at any given time is stored in Processing’s special predefined variables mouseX and mouseY.

Inside the mouseClicked() method, mouseX and mouseY to the x,y coordinate variables of your circle object.

Run and test your program to make sure the circles are appearing where you click the mouse.

Setting the Color According to Mouse Click Location

In the example, you may notice that the circles are not all the same colour.  I did this by using the mouse location to calculate a colour.  Let’s add this feature to our project.

If you set your window size to be 500x500 in the setup() method...

size(500,500);

...then you know that your mouse coordinates can’t be bigger than 500 in either direction.

Set the size of the window to be 500x500 in the setup() method.

We also know that the three components in a colour can be between 0 and 255, and 255 is half of 500 (you can learn more about colour in Processing here).  Based on that, here’s one way we can select a colour based on the mouse coordinates:

color c = color(mouseX / 2.0, mouseY / 2.0, 200);

I chose 200 for the blue component arbitrarily - you can experiment with any sort of numbers you’d like.

Use the code above to get a colour based on mouse coordinates, and save that colour to your circle object’s color variable in the mouseClicked() method.

Supporting Multiple Circles

We’re almost there! The last bit of functionality is the ability to have multiple circles on the screen.  That is, when we click to add a new circle, we don’t want the old ones to disappear until they’ve already reached their maximum radius.

How is this possible with just one circle variable? Should we add more circle variables somehow?

To solve this problem, we’ll make use of lists.  We can maintain a list of all the circles that are still growing on the screen. Then, at each frame of the program, we can remove from the list any circles that have reached the maximum radius.  When drawing our circles, we’ll draw anything that’s still in the list.

Have a look at the reference page for ArrayList, Processing’s built in list type.

Make a new list at the top of our project in our variables area using the following code.

ArrayList<Circle> circleList = new ArrayList();

(Notice my use of <Circle> in the example code above -- it’s not strictly necessary, but it will make using your list a lot easier because Processing will know what kind of object is stored in the list.  Ask a TA if you want to know more about this.)

In mouseClicked(), add the circle object you create to the list using the ArrayList’s add() method (see reference below).  (You can also remove the myCircle variable as well, though it won’t hurt anything to leave it.)

(Use the reference page to help you use ArrayLists.)

Finally, in the draw() method, you will use a for loop to look at each circle in the list.  You’ll need the size() and get() methods from the ArrayList to accomplish this.

Add a for loop that starts at lap 0 and goes until one less than the size() of the circleList.

(Wondering why you loop until one less than the size of the list? It’s because the indexes start at zero instead of 1, so the last index is actually one less than the size.)

Inside the for loop, use the ArrayList get() method to get the Circle object whose index is the current lap number.

Also inside the for loop, draw the current circle object you got from the ArrayList in the same way you drew the myCircle variable, including the if-statement.

Inside the draw() method, remove the code that drew the myCircle object.

If you run the program now, you’ll notice that the circles stop growing when they’ve reached their maximum size, but they don’t disappear.  That’s because they’re still in the list, so they are still being drawn, even if their radius isn’t being changed anymore.  To fix that, we need to go through our list and remove the circles we don’t want to draw anymore.

The only hitch is that we can’t go through the list forwards like we did with the previous for loop.  This is because as we remove items from the list, it gets smaller.  The number of laps through the loop was based on the list’s size, which is now changing.  By the time we get to the end, the circle that was there might be totally gone!

It turns out that we can get around this problem just by going through the list backwards.  Tha is, we can start on the last lap and work our way down to lap 0.  That way, even if we remove something from the end of the list, the first item will still be there.

Create a for loop that goes from lap “one less than the size of the circle list” down to lap 0.

Inside the for loop, use the ArrayList get() method to get the Circle object whose index is the current lap number.

Also inside the for loop, use an if-statement to check whether the current circle has a radius BIGGER than the maximum.  If it does, then remove the circle from the list with the remove() method.

As usual, run and test your program and see if clicking around the circle works as expected!

Before the last step, take a moment to think about how having a Circle class was useful once we moved to having multiple circles.  Run it by a TA to see if you’ve got the right idea.  (Not sure how to approach this challenge? Think about how you’d write the code if you DIDN’T have a Circle class.)

Adding Sound

Our very last item is to add sound to the project.  I’m going to give you a bit of challenge here and get you to figure this one out on your own.

Don’t worry, I’m not going to hang you out to dry!

There is an example file that comes with Processing that shows you exactly what you need to do.

Open Files > Examples... from the menu.

This is a really great place to go when you want to get ideas on how to accomplish something in Processing.

Look for Minim Audio under Libraries.

Minim is the library that allows Processing projects to use sound.  We want to do what the LoadSnippet project is doing.

Open the LoadSnippet project and look at the code.  Use it as a reference to open your own sound file in the Sound Waves project.

(If you need a sound file, feel free to download the same one I used in the example.)  Don’t forget to add the sound file to the project using the Sketch > Add File... menu item.

Rewind and play your sound at the beginning of the mouseClicked() method.

You’re all done - great job!!

Extensions

Want an extra challenge? Try writing code to accomplish any of the following:


Tutorial by Gail Carmichael, www.gailcarmichael.com