teaching machines

The Monodrone, Part III

June 13, 2019 by . Filed under electronics, music, public.

This post is part of a series of notes and exercises for a summer camp on making musical instruments with Arduino and Pure Data.

There’s something wrong with our monodrone. It plays a lot of notes at the same time! Why does this happen? To find out, hit the close 1 message back in Pure Data to release the serial port. Replace write with println and upload your sketch. Open the Serial Monitor and check the output.

So, why do we get some many overlapping notes? Because of the loop function in our Arduino sketch. It runs continuously, asking the button about its state continuously and sending a 0 or 1 across the serial port continuously. While a button is held down, it will send 1, 1, 1, 1, 1, 1, 1, 1, 1… Our Pure Data patch generates a note for each of these 1s, and that’s why we hear the rapid-fire sound that we do.

We can fix this by only printing a 0 or 1 only when the button changes. To detect a change, we must keep a history of what the button’s state used to be. Let’s add this variable outside our two functions:

int old_button = LOW;

void setup() {
  ...
}

void loop() {
  ...
}

When we declare a variable outside the functions, it has a lifetime that exceeds the functions. If we declared it inside a function, that variable would disappear once the function finished executing. Since old_button has to maintain a history of what happened in the past, we can’t let it disappear. Computer scientists call the lifetime of a variable its scope. Variable old_button has a wide scope.

LOW is another name for 0 and better describes electrical voltage. (Similarly, HIGH is another name for 1.) To remember what the button was a moment ago, we hang on to the current reading as the very last step of loop:

int old_button = LOW;

void setup() {
  ...
}

void loop() {
  int button = digitalRead(7);
  Serial.println(button);
  old_button = button;
}

The next time loop runs, old_button will tell us what the button used to be. To detect a change, then, we ask if button and old_button are different. In C++, we can ask that question with the != (not equals) operator.

To run some code when the two values are different, we embed the code in a conditional statement, which has this form:

if (button != old_button) {
  // code to run when the values are not equal
}

Add a conditional statement like this to loop. Move the last two lines (the print and the old_button assignment) inside its curly braces. Test your new program. Do you see messages in the Serial Monitor only when the button is pressed or released?

Once that’s working, switch println back to write. Test it with Pure Data. You should no longer hear the echoes. It should sound decent, but boring. That’s the monodrone being itself.

Challenges

After you get your monodrone working, answer the following questions on a piece of scratch paper.

  1. Encode a secret message in Morse code. What is that message as dots and dashes? Emit it using your monodrone.
  2. What happens when you use the == (equals) operator instead of !=? Imagine you are the Arduino and think about the state of the variables as the program runs. Reason out loud and on paper.