In this lab, you will learn the basics of Processing, a programming language that we will be working with for the next few labs, to create sound-responsive animations of faces. An example of some of these types of animations can be seen below.
Pretty cool, huh? While learning to program can involve a lot of technical details, this lab will also focus on a different aspect of Computer Science: creavity. By the end of this lab, all of you will have created a cool animation!
Download the processing language here by following the directions for your operating system below. (Here are some other online instructions as well.)
For the next few labs, we will be using the Processing language to draw pictures and create animations. Writing programs to draw pictures is useful because we can create several copies of a picture or manipulate a picture (to create animations, for example) easily.
In this first lab, you will be drawing a face, and creating an animation like in the examples at the top of this page.
To keep things simple, you will only use rectangles, ovals, triangles and straight lines to draw your face. While this might seem limiting, you can still create incredible pictures with a few basic shapes and some imagination. We have included descriptions of a couple basic commands to get you started and a few links to extra resources. Feel free to experiment and play!
Once you've opened the Processing application, you can immediately beginning typing your code in the current window. Be sure you save regularly. When you save, all files associated with the project get saved in a single folder. Note that the project won't work if they are not all in the same folder.
In general, when we want the computer to do something, we need to give the computer a command. Most commands in Processing will look like such.
A command will start with the name of the command (always one word) followed by a pair of parentheses ( ) then followed by a semi-colon ; .commandName(extra information);
These rules must be followed exactly, otherwise the computer might complain or produce unexpected behavior. Computers will do exactly what you tell them to do. You'll soon realize that computers are very dumb and have a hard time interpreting what you really meant.
Occasionally, we want to write annotate our code in a more human-friendly language. These annotations are called comments. If we just go ahead and mix English sentences with code, the computer is going to try to interpret our annotation as a command and produce a lot of errors. We want the computer to ignore our notes, and this is done be prefixing all annotations with //.
// All of this text will be ignored, even if happens to be code.
To specify the positions of our shapes in Processing, we use a coordinate system (having an x axis and a y axis.) Like you've seen in your math classes, the x values represent a horizontal location and y values represent a vertical location. Unlike what is taught in your math classes, the origin (0, 0) is the top-left corner of your canvas, instead of the center. By convention, an x-value of 0 is the left edge of your canvas and increases in value as you move right across the screen. A y-value of 0 is the top edge of your canvas and increases positively as you move down the screen. For example, the point (0, 100) will be directly below (0, 50). This might take a little time to get used to, but this allows you to always be working with positive numbers.
To draw a rectangle, we use the rect command which requires four pieces of extra information describing the location and the dimensions of the rectangle. Without these pieces of information, the computer isn't going to know what to do if you simply say "Hey Computer! Draw me a rectangle!"
rect(x, y, width, height);
x - The x coordinate of the top-left-hand corner of your rectangle.
y - The y coordinate of the top-left-hand corner of your rectangle.
width - The width of the rectangle in pixels.
height - The height of the rectangle in pixels.
In order to draw a round shape, we might be tempted to have a circle command. But we want to have a more general command that allows us to draw ovals with unequal width and height if we so choose, like the rect command. To draw an oval or circle, we use the ellipse command which also requires four pieces of extra information.
x - The x coordinate of the center of your ellipse.ellipse(x, y, width, height);
Here are some extra references including commands for additional shapes and changing colors:
Tutorials that may be helpful:
Humans are naturally drawn to faces and will try to interpret drawings as faces if possible. For the first part of this lab, you will draw a face using the basic geometric shapes described above. (If you're really ambition, you may use other commands referenced on the Processing website, but this is optional.) There are no specific requirements for the kind of face you create. This is an opportunity to get creative! Your only restriction is your own imagination. Eventually, you will animate the face change based on surrounding volume levels.
Here are sources of inspiration for interesting, geometric faces:
A series of commands will be executed in order from top to bottom. That means if I type
The square will be drawn on top of the circle such that the circle will not be visible. If I swap the order of these two commands, the circle will now be drawn on top. You can use this to your advantage to overlap shapes or create the illusion that two shapes have been placed next to each other without having to do any complicated calculations.ellipse(50, 50, 100, 100);
rect(0, 0, 100, 100);
Now that you have finished creating your face, you will animate the face to change based on surrounding sound volume levels, as seen in the video in the overview.
So far, we have been drawing in "static mode" (our faces have not been moving.) In order to animate our faces we need to switch to "active mode." To do this, we will add these two pieces of code:
This creates two new, custom commands, setup and draw, which you will fill with the code you have written in Step 1.void setup() { // setup code here... } void draw() { // drawing code here... }
The setup command is executed exactly once at the beginning of your program. You should put any code that you do not want to be animated here. For example, if your head will not change or move with volume, you can place that part of your face code inside setup. The size of your window will most likely be placed here.
The draw command is executed 60 times a second. Any code that you do want to be animated should be placed here. For example if I put rect(50, 50, 100, 100) inside the draw command, this will draw a 100x100 square at (50, 50) 60 times in a second. This particular example is not very useful, however, because the square's location and dimensions never change and therefore will still look static. In the next section, we will show you how to get these values to change.
There is one more subtle problem with this example. The suggested code will draw squares on top of each other, such that after one second, we've layered 60 squares. What if the squares were not drawn in the same place, but instead changed location over time. Let's say the first time draw is executed, we tell the computer to draw at (50, 50), then the second time we tell the computer to draw at (51, 50) then at (52, 50) then (53, 50) etc. such that the rectangle appears to move to the right. What will happen is that the square will just grow in width over time. This is because after we draw the square the first time, we draw the second square on top, and the third square on top of that, creating the illusion that the original shape is getting fatter. So, how to we fix this problem, if we wanted the old squares to disappear? When we want a shape to appear to have changed, we need to erase the old shape. This means each time in draw, we need to clear the screen before drawing again. We can do so by using the background command and painting the background to the current color.
Let's take a closer look at the provided code. the float volume = getVolume(); command captures the surrounding volume as a real (decimal point) number. This number is then given the label volume, so you can use the word volume in your face code in place of any number to substitute the current volume level captured. This label is called a variable, similar to a variable you would use in a mathematical equation. In programming, any time we need to remember a value to use in multiple places, we store these values in variables. Because this volume command is inside of draw(), the surrounding volume is captured 60 times a second causing the volume variable to constantly change.
Experiment with volume by substituting volume for one of the values in your face code. For example, replace the x-value of your eye with volume to see it move side to side or the width value of your head to watch it stretch. To display the value of the current volume, add this code inside the draw command.
text(volume, 5, 5);
Sometimes just substituting volume for another value gives less than desirable results. If you replace a dimension with volume, your shape might become too big or small at times. If you replace a location value, you probably noticed that the shape is too far left or too high. How can we modify volume to address this problem? Below are two strategies that can be used, either in combination or separately.
When there is no surrounding noises, our volume variable will be close to 0. If we simply replace a value with volume, our shape may have a width or height of 0, or be placed on the x or y axis. To remedy this, you can shift volume by adding a number to it. For example, the code rect(volume + 100, 100, 50, 50) will produce a rectangle which will be located at x-value 100 in silence and will move to the right as sound increases.
Bring your laptop to class on October 10 ready to demo your project. We will all walk around the room and check out what people did.