This post is part of a series of notes and exercises for a summer camp on making musical instruments with Arduino and Pure Data.
The last step of our arpeggiator gives the musician the ability to control the tempo or timing of the notes. We’ll use our last potentiometer for this. Its reading will be used to set the delay between notes. This delay needs to be set in both the Arduino sketch and the Pure Data patch.
notewait, right after you write the note’s ID, read the value from
A2 and assign it to a
short variable named
duration. We’ll use this number directly as the number of milliseconds that each note plays.
Recall that the analog pins report a number in the range [0, 1023]. We need two bytes to hold numbers in this range, and
shorts are two bytes wide—on Arduino, at least. Adjust your call to
delay to use this
We must also send the duration out along the serial port so that Pure Data knows when to stop playing the note. But there’s a hitch. The
comport object can only receive bytes, and
duration is a two-byte quantity. We are going to need to do some bit twiddling.
Consider the number 1023. In binary, it has this form:
Let’s separate the bytes so they are easier to see:
Maybe we could just send the number in pieces like this? Yes, that’s what we’ll do.
The byte on the left is called the high-order byte. It holds the digits of the most magnitude. The byte on the right is called the low-order byte. The Arduino functions
lowByte will separate
duration into its two parts. Use them and write the high-order byte to the serial port. Then write the low-order byte.
That takes care of the Arduino side of things. Our message size is now 3 bytes. On to Pure Data!
The third inlet of
makenote expects the duration. To get the duration, we need to gather up the three bytes of each message sent in by the Arduino. The last two bytes must be reconstituted back into a two-byte quantity. There are a couple of operators we can use to achieve this. Suppose the high-order byte is 00000011, and the low-order byte is 11111111.
00000011 <- high 11111111 <- low
We can put these bytes back together with this set of operations:
(high << 8) | low. The
<< is called the left-shift operator. The
<< 8 tells
high to move left 8 bits, shifting it into its correct place and padding the lesser digits with zeroes. That leaves us with this situation:
00000011 00000000 <- high << 8 11111111 <- low
| is called a bitwise or. It looks at each pair of corresponding bits in the two numbers. If at least one of the bits is 1, the output bit is 1. Given these two numbers,
| gives us this result:
That’s our two-byte quantity!
Accomplish these operations in Pure Data in the following way:
unpack float float floatobject.
repackinto the inlet of
unpackinto the first inlet of
unpack—the high-order byte—into the first inlet of
<< 8into the left inlet of
unpack—the low-order byte—into the second inlet of
|into the inlet of the number box.
There. Now you should be able to set the tempo and hear your arpeggiator speed up and slow down when you crank the third potentiometer!
After you get your arpeggiator working, answer the following questions on a piece of scratch paper.
lowByteto extract the bytes of the duration. There are other ways to tease apart the bytes. Investigate the bitwise operations of C++. What bitwise operations could we have used?