Outline

In this week’s lab you will:

  • use javascript objects to represent the elements of your sketch, and arrays to store all the elements
  • use nested iteration (loops) to compare all possible pairs of these elements (and do things when certain conditions are met)
  • create a work of interactive sound-art using the p5.sound library we talked about in the week 6 lecture

Pre-lab checklist

Before you attend your lab session, make sure:

  • you’ve completed lab 6
  • you’ve watched the week 4 lecture on functions and how to “loop over an array”

Introduction

In this lab, we’re going to be making an interface for generative music. We’ll be taking inspiration from an iPhone app called Bloom by Brian Eno and Peter Chilvers. Don’t worry if you’re not familiar with it, the concept is really simple (as you’ll see in the next section). Again, what you’re doing in this lab is figuring out what things (objects) exist in the world, writing functions to do stuff to those things, and then finally applying those functions to all the things in the world using a loop.

Part 1: arrays

Before we start working on our Bloom clone, let’s do a quick bit of revision—this time on arrays, since it’s been a while since they were covered in week 4. It’s okay to skip this section if you’re already comfortable with arrays.

An array is a different type of variable, just like a string ("hello"), a number (1.0), a boolean (true), or an object. Except, the value it stores is a list of other values. The syntax for arrays looks like:

var arrayOfNumbers = [100, 24, -2, 18, 106, 42, 1, 8];
var arrayOfStrings = ["hello", "darkness","my", "old", "friend"];
var arrayOfBooleans = [true, false, true, true, false];

Everything in between the [ and matching ] makes up the elements of the array. An element is an item inside the list that is an array.

Each element has a position in the array, we call this the index. The first element has an index of 0, the second has an index of 1, etc.

We can access the elements inside an array using an “indexing” syntax.

let groceryList = ["potato", "panko", "capsicum"];

groceryList[0] = "sweet potato"; // change "potato" to "sweet potato"

This indexing syntax uses [ and ] again, but this time it’s following the name of the variable and contains the previously mentioned index of the element you’d like to access.

Can you complete the following if statement? Make it so that it checks if the third score in the array (42) is greater than 50 (ie. it passed).

It’s also common to want to add elements to an array, we do this with the push function.

var items = ["keyboard", "mouse", "monitor"];
items.push("headphones");

// items is now ["keyboard", "mouse", "monitor", "headphones"]

Can you fill in the blank so that the following code adds “jeff” to the array?

Part 2: a single bloomer

Find a partner in your labs Teams channel! If someone has advertised themselves but not found a partner, reply to their comment and a tutor will set up a meeting for you to collaborate in. If no-one is currently advertising, make a message advertising yourself. There isn’t going to be much actual pair-work today, but it’ll still be nice to have someone to bounce ideas off of while you’re working!

Fork and then clone the lab 7 template repo, open it in VSCode and start the live server as usual. In addition, you’ll need to add the p5.Sound library to your sketch just like in part 4 of the week 6 lab, and un-comment the lab-sound.js script tag in your index.html which contains the rest of the helper code for this lab (remember, un-commenting in HTML means to remove the <!-- and --> before and after the <script> tag respectively..

This is a hard lab. Send a message to your tutor if you get stuck.

For this sketch, we’re going to use the same code pattern as the week 6 lab—except to have multiple bloomers on the screen, we’ll use an array to hold our objects. For a review on objects see last weeks lab content, for a review on arrays see the start of this weeks lab.

That means we will describe our bloomers as an array of JavaScript objects. Ask your neighbour or your tutor if you can’t remember how these work.

A bloomer is an circular entity which:

  1. when it’s born, it grows (in size) from nothing
  2. when it reaches maturity, it “blooms” and plays a sound
  3. after reaching maturity, it stops growing.

Think back to the week 6 lab (wow, such a long time ago!), where we thought about what fields a pokemon might have. Send a message to the Teams chat with some ideas for what properties you will need for your bloomer object.

Once you’ve cloned the template, at the top of your sketch.js there will be variable declaration for bloomers (initialised as an empty array). This is where you’ll store the bloomer objects in your sketch “world”.

var bloomers = [];

In the setup function use the .push() method to add a single bloomer object to the array.

function setup() {
  // ...
  bloomers.push({ /* your bloomer object goes in here - make sure it's got the right properties */ })
}

Part 3: drawing the bloomers

In the draw() function your will find that there’s a for loop which calls two functions inside the loop: drawBloomer() and updateBloomer(b). Remember that this is a common pattern for just calling one (or more) functions on each element of the bloomers array (one at a time). So, for now, this code is just like calling drawBloomer on the object we pushed to the array in the last step.

Scroll to the drawBloomer(b) function in the sketch.js file and write some code which draws the bloomer object as an ellipse. Remember that you can use the dot syntax to get a property from an object.

I know we’ve harped on about it a lot in labs & lectures, but it’s really important to understand what’s going on here. Conceptually it’s quite simple:

  1. there’s an array of bloomer objects (the array variable is called bloomers)
  2. you’re writing a function which takes a single bloomer object as a parameter (drawBloomer(b))
  3. when you call drawBloomer(b) function inside the for loop, that’s how you draw (or do whatever) to all the bloomers in the array

Don’t get confused and try to make your drawBloomer(b) function draw all the bloomers—it only has to draw one. Breaking the problem down like this is super helpful, especially as the things you want to do to each “thing” in the world become more complex.

You should now be able to see your bloomer in the browser. After that’s working properly (ask your tutor or lab neighbour if you get stuck) lets update your drawBloomer(b) function so that it changes the colour of the bloomer if it has bloomed (reached maturity). That sounds like a job for an conditional statement, don’t you think?

Add an if statement to the drawBloomer function which draws the bloomer with a different colour if the bloomer’s hasBloomed property is true.

Part 4: updating the bloomers

The second function you need to define is updateBloomer(b). This is where you should modify any parameters in your bloomer objects.

First up, you want to make your bloomer grow.

Send a message to the your labs Microsoft Teams channel—how many different ways could you represent this notion of “growth” in a p5 sketch?

In the updateBloomer function, write some code which modifies the bloomer to make it “grow”.

Next, you need to add a condition to make your bloomer “bloom”. You can just use its size for now and make it more fun a bit later.

Write an if statement in the updateBloomer function which checks if the bloomer has not already bloomed and (&&) if it is larger than 250. If both of these are true, set the bloomer’s hasBloomed value to true and call the playBoop() function.

The template repo sets up all the necessary infrastructure for playing sounds in the lab-sound.js file. Feel free to look at it if you’re interested in seeing how it works—but don’t worry about understanding it today, just calling the playBoop() function will be enough.

Save your code, and check now that your bloomer grows and then plays a sound as the colour changes.

Part 5: all the bloomers!

To make this interactive, we just need to let the user create more bloomers. We can do this by using the .push() method again.

In the mouseReleased() function, make another call to .push() which adds a new bloomer to the bloomers array, but this time set it’s position to mouseX and mouseY.

Save your code and check if you can add a new bloomer by clicking on the screen. This should also grow, change colour and make a sound without you doing any additional work! Hooray for well-planned code!

Part 6: break it down!

For this week’s break it down, let’s have a look at what other effects can be achieved with the bloomers code.

In your pair, open up a cocoding session on p5live. Copy and paste the code below in so you can work on it together — try and make it your own, be creative!

Summary

Congratulations! In this lab you:

  • built a simple interface for making generative music
  • used best-practice techniques for managing the data in your sketch

Remember to commit your code and push it back up to Gitlab, and log out of the lab computer.

If you want to dive deeper into generating music with p5 read and edit the lab-sound.js file. The template is setup to use the p5.TriOsc() object so why not start by changing that to another oscillator. As always you can learn all about these in the p5 reference.

Updated:    11 Jan 2021 / Responsible Officer:    Head of School / Page Contact:    Charles Martin