Recursion

Rhythmic Recursion

Rhythmic Recursion

by Celeen Rusk

The video "Rhythmic Recursion" presented by Celeen Rusk at RubyConf 2016 explores the intersection of music and computer science, specifically focusing on the concept of recursion within minimalist music. Celeen discusses her background in music and software engineering, illustrating how both fields share abstract representations and compositional processes.

In the talk, the following key points are addressed:

  • Introduction to Recursion: Celeen defines recursion as self-reference, connecting it with computer science and music composition. She emphasizes the idea of processes being vital in both areas.
  • Minimalism in Music: Celeen introduces a piece by Steve Reich, published in 1973, which exemplifies minimalist music. The simplicity of its notation makes it accessible for analysis and transformation into code.
  • Breaking Down the Music: The discussion includes a detailed examination of the musical score, highlighting the repetitive structures and rhythmic patterns present in the piece.
  • Representation in Code: The speaker demonstrates how to represent the rhythmic patterns in Ruby code using arrays, where 1 indicates a note and 0 indicates a rest. This simplification allows for effective programming representation of the music.
  • Understanding Recursive Patterns: Celeen emphasizes that the second part of the music involves a recursive pattern. She illustrates how shifts in notes can be defined and implemented through a recursive function in programming.
  • Technical Demonstration: The talk culminates in a demonstration of how to code the two parts of the music using Sonic Pi, showcasing the function of playing multiple rhythms concurrently.
  • Audience Engagement: Celeen interacts with the audience, asking for definitions, sharing personal anecdotes related to music, and addressing questions about sound presentation in code.

The primary takeaway is the interconnectedness of music and programming, revealing how analytical skills and creativity in one field can enhance understanding and capability in the other. Celeen Rusk invites further exploration of the topics covered and provides resources for viewers interested in coding and music integration.

00:00:15.070 Hi, my name is Celeen, and I have a degree in music. I'm really glad that was your response to that joke. In retrospect, it's kind of a joke in poor taste, but I keep trying it anyway. So, as I mentioned, my name is Celeen, and I'm a software engineer at a company called Braintree in Chicago. I’m putting my information up here now in case you want to write it down. If you have any questions, feel free to reach out; I love making new friends. Also, I appreciate feedback—these forums are really great for that. I'll post this information again at the end of the talk.
00:01:06.409 This talk is kind of about computer science. How many people in the audience have heard of the 'Structure and Interpretation of Computer Programs'? Yes? Cool! Has anyone watched the video lectures posted on the MIT OpenCourseWare version of it? That's a bit of a crapshoot; I watched half of the first one and haven't really picked it back up again. Hopefully, some of you can relate to that experience. There’s a gentleman named Harold Abelson who gives those lectures. It looks like it’s from the 80s; it’s fantastic, and I love many of the things he says in it.
00:01:28.310 He mentions, "Welcome to this class on computer science," except that’s not really a good name for it because it’s not really science and it’s not really about computers. He likens it to the study of geometry, which was initially developed by the ancient Egyptians. The name comes from 'Gaia,' which means earth, and 'Metron,' which means to measure. Geometry was developed as a way of surveying land. Much like the ancient Egyptians, we’re developing rudimentary fundamentals of geometry. This evolution allowed us to talk precisely about declarative knowledge—a way to express what is true.
00:02:06.440 Mr. Abelson believes that centuries from now, people will look back at 20th-century primitives and think, "Oh yeah, those folks were fiddling around with these gadgets called computers, but really they were developing a formalized process—a formalized way to talk about intuitions about processes." I really like that. I’ve heard it said elsewhere that computer science is the study of processes, and I think if that’s true, then programming is the application of that study, or at least one application of it.
00:02:36.570 As I mentioned, I have a degree in music, and I’ve noticed many musicians transitioning into tech. How many people in the audience today dabble in music or know a bit about it? Cool! Is there anyone who feels they don’t know anything about music? Awesome! I’m glad there are both types of people here because I hope this talk will be clear to everyone. I’m approaching things from the code perspective.
00:03:09.140 Another idea I want to mention before we get started is that I attended Strange Loop this year, where a gentleman named Chris Ford talked about ethnomusicology and African polyrhythms. I really enjoyed how he connected these concepts with programming. He mentioned that both music and programming use an abstract form of representation to communicate ideas about processes. There’s also a lot of composition and analysis in both fields. This is likely true for many other fields as well, but I noticed it in music because I’ve studied it for most of my life.
00:03:41.820 What we’re going to do today in this talk is look at a piece of music by Steve Reich, published in 1973. It falls under an era of academic music called minimalism. You can see from this page why it’s called minimalism, especially if you have any background in music. Many classical music pieces take up an entire book, while this piece takes up just half a page. Its appearance is very minimalistic.
00:04:09.290 We’re going to deconstruct the traditional musical representation seen here, analyze the process, and then we’ll recompose it using Ruby code. We’ll also use Sonic Pi to assist in that process, but I won’t focus too much on that tool; we can discuss it afterward if you’d like. I’m really excited—let’s get going! When we start breaking down this piece, the first thing to note is that there are five stanzas. Each stanza has two parts, which are indicated in the top left-hand corner with 'clap one' and 'clap two.' This means there are two performers in the piece, and the instrument is clapping, which is not very common in academic music.
00:04:50.340 Each stanza comprises two lines, representing two parts. Next, I want to point out that formal music has a structure called a bar or measure. Each of these broader stanzas contains three bars, delineated by vertical bars between each group of notes. This is a cool observation.
00:05:16.319 I also want to draw your attention to the top of the page where we see some instructions. The first part indicates tempo, saying 'equals 160 180,' which we won’t worry about too much for now. Below that, it instructs to repeat each bar 12 times. Typically, when reading music, a colon indicates to repeat from where you see the first colon facing right. In this score, Steve Reich gives us very specific instructions: do not repeat the way you normally would; repeat twelve times instead. However, for the sake of this talk, we are going to repeat it four times because I think twelve is too many.
00:05:39.810 One more thing to note before we move on is that the top part has the same pattern of notes in every measure throughout the entire piece. This could be considered the boring part of the piece, but it is also really important because it provides a structure against which the changing part works. Let’s take a closer look at the first measure where both parts are the same and break down some of the representations we see here.
00:06:04.080 Despite how this looks, it may seem like there are lots of different notes, but don't be fooled—this musical notation can be a bit weird. All these notes represent the same rhythmic value. The small markings between the notes, called rests, also represent the same rhythmic value. This consistency is remarkable because these are the only notes and rests in the entire piece. Coupled with the fact that it’s a rhythmic piece, it makes this very easy to represent in code, as we only need to care about the order in which the rhythmic values appear.
00:06:36.920 I want to play this rhythmic pattern for you, as it is the main theme of the piece, and you will hear it persistently. It sounds like this: (demonstrates rhythm). I’m going to repeat that while emphasizing the rests with my hands. I like to think of rests in music as white space from a coding perspective.
00:07:11.030 Additionally, I have a mnemonic for this rhythm because I found it helps to remember rhythms and melodies. I was a big choir nerd in college, and my choir would go on tour every winter break. Being music nerds, we sat at the back of the bus one year trying to learn how to play this piece of clapping music, which only requires a couple of people’s hands and familiarity with the process. We created lyrics to remember it, which I’ll share with you now: ‘There is no pooping on the bus!’ This should make it easy to remember the thematic rhythm.
00:07:50.629 The beauty of this simple representation is that it can be represented in a very simplistic manner in Ruby code using arrays. I’ve chosen to represent the first part with one array and the second part with another array. I’ve used 1 to represent the spaces where there is a note or clap, and 0 for the spaces where there isn’t. This parallelism is effective.
00:08:22.650 Looking at the rest of the score past the first measure, you may have noticed that the second part changes throughout the piece, and spoiler alert: it follows a recursive pattern. Before we proceed with breaking down the notes and processes, let’s define our terms. Does anyone in the audience want to volunteer a definition of recursion?
00:09:02.470 Yes! It’s often described as self-reference, and I like that definition. There are numerous definitions, and the one I found defines recursion more specifically for computers than what you just provided, which is quite common. I also found a definition that pertains to mathematics, emphasizing recursion generated by repeating a particular operation. Beyond computers and mathematics, examples like two mirrors facing each other might be considered recursive, reflecting each other across. I prefer this definition because it's broad and helps us build a bridge between fields by analyzing similar processes.
00:09:45.080 Upon examining the rest of the score, we know that the second part derives from a recursive process. To pinpoint that repeated operation, let’s take a closer look at the second measure. We've established that the first part is unchanged, so we know what it was in the measure prior. We can now focus on the second part to identify the specific change.
00:10:12.990 Does anyone want to share what this repeated operation is? Yes! The whole pattern shifts back, and the first note is placed at the end of the bar. Well said! This process continues until the end of the piece, and we can represent these notes and rhythms in code quite easily. Using 1s to represent a clap and 0s to signify a rest works well here.
00:10:37.620 As we visualize how this operation occurs repeatedly throughout the piece, we can trace it through the last measure in the fifth stanza, when they return to the same pattern again. Now, we’re at the point where we can discuss how to recompose this process. I believe we have a solid understanding of what the process is overall; how do we represent it in code? We have two performers who need representation, what they are playing on the page, and how to execute their parts. We need to represent this with the tools we already know.
00:11:23.850 I’ve taken the liberty of establishing a few components already, such as the two parts. It’s worth mentioning that Sonic Pi is a domain-specific language over Ruby, and it has its quirks. I haven’t defined this code in a class as you might typically do in object-oriented Ruby; instead, I’m using instance variables. I have assigned two distinct voices—one high-pitched percussive voice and another mid-pitched percussive voice—just to add some texture and variety.
00:12:00.580 By using these different pitches, it can be a little easier to differentiate between parts since both come from the same speakers. Admittedly, it might not help as much, but it does provide at least a slight distinction. I’ve already established the baseline part that remains constant, which I call our baseline, while the other is the rotating part.
00:12:37.440 Now, let’s redefine some of the essential terms for anyone who might not be familiar with music. A measure or bar groups notes together. The repetition of measures is what I’ll call a section—remember when we read to repeat each measure 12 times? We’re repeating it four times, as a reminder, and I couldn't think of a better term.
00:13:01.180 I’ve defined a couple of brief methods to start with: play note and play rest. They’re straightforward since each is of the same rhythmic value and not especially distinguished. Other helpful methods could enhance our progress here, and I propose we tell the computer how to play a measure, how to play a section, and then how to play both parts in unison.
00:13:22.500 Typically, if two humans were clapping this piece, it would be two separate brains performing a singular process together. A computer can somewhat fulfill a similar role. We need to inform it how to play two parts at once. For this, we’ll take the two arguments: the notes we want to play and the voice we want to use.
00:13:49.400 For each value in this pattern, if it’s a 1, we play the note with the designated voice; if it’s a 0, we play the rest. This can be demonstrated with the following sound (demonstrates the rhythm). Now that we know how to play the measure, there are various ways to implement this for playing a section.
00:14:08.320 I did it this way for certain reasons. If it were inside a class, you would likely want to extract the number into a constant, but this is how it turned out, and it works. It still produces coherent sounds and feels very fun. It sounds like this (demonstrates). Does that make sense so far?
00:14:44.990 Finally, we know how to instruct the computer to play both parts simultaneously. We will do this a section at a time; that aligns with the structure of the process. In Sonic Pi, the way to accomplish this is by wrapping one play section call in a thread, allowing the other to play concurrently.
00:15:09.230 I think that’s neat; essentially, you can dictate how separate processing proceeds. Here’s what that sounds like (demonstrates the mixed parts). To provide context, I will remind you of the difference: this is one part (demonstrates), and this is two parts (demonstrates). As you can hear, it's a bit louder, and it becomes more apparent when they play different things.
00:15:24.700 Now it's time for the collision—thank you! I’m obviously very excited about this section! Let’s continue defining our terms, focusing on recursion which we've been diligent about defining already. In my estimation, recursion is usually broken down into three elements: the part where the function calls itself, the kick or base case that tells the function to exit after a certain repeating point, and the part that changes something to reach the base case.
00:16:04.920 This concept is best illustrated with classic examples such as the factorial problem. The function multiplying two numbers changes one number by subtracting one each time it repeats. Now, let's tackle the pivotal part: we’ll write the play recursive method. We pass in a section to play recursively, calling the method within itself.
00:16:42.780 What do we pass into the repeated call? Does anyone want to share? Right! The last measure aligns again. We know we’re done when both parts synchronize. Steve Reich called this piece—and many others like it—phase music for this reason: you begin with one thing, and over time, it moves through a phase until it stops.
00:17:18.260 Now, what is the change we want to pass into the recursive call? Yes! It’s the rotating part. We also need to inform the system of the action we want to take; what is that?
00:17:55.050 Exactly! We instruct the section to play. When it’s not done, we’ll simply continue playing it with the rotated part. So, let’s combine all of these elements. Technically, we could utilize the method we just crafted by passing it a rotated baseline, but a challenge arises.
00:18:22.309 Has anyone recognized what the problem may be? Yes! The initial section to play will virtually be unchanged. It won't exit immediately because we’re using the rotated baseline. So, we will play the section first as it is and then traverse into the recursive bit when it’s the same.
00:18:46.920 You could make this recursive method differently so that the kick appears at the top, thus skipping the replaying when the two parts match. But you’d have to organize the play sections at the bottom, which isn't a major issue—strategy is comparatively consistent.
00:19:14.619 We will hear it all simultaneously since the way it’s arranged creates a pleasant feeling in the end. Before we listen to it, I want to go through some thank-yous and links. I have a link to Sonic Pi because it’s a great DSL for those interested in exploring.
00:19:40.900 I also have the complete code on my GitHub along with a PDF of my slides. I’m using Deckset, and that markdown is there as well if anyone is interested. In case you want to reference the composer and piece again, thank you to John Downey and Josh Larson for their mentorship throughout this process, and thanks to Dev Bootcamp for initially inspiring this talk about music and programming.
00:20:09.389 Lastly, I want to thank Sam Aaron and everyone who’s contributed to Sonic Pi. I genuinely appreciate it. Now, I’ll transfer Sonic Pi into the viewer. I’ll adjust the size a bit—there we go. I’ve also written a logging method that will display when the base case is achieved and visualize each part during its first play, illustrating how rotation occurs. Let’s do this!
00:21:06.390 (Demonstration.) Thank you! Does anyone have any questions? That's an excellent question! Can you play the bassline from one speaker and the rotating part from another? I'd love to explore that option. However, we had some issues with the line out on the computer, and the sounds you heard were amplified via a microphone next to the speaker. I’ll definitely consider this feedback for my next presentation.
00:29:29.840 What editor am I using to write the code? That’s built into Sonic Pi. It was designed for Raspberry Pi, but there’s also an OSX version. I’m not a substantial fan of the Sonic Pi editor, especially since I've adapted to other editors like Sublime. As a result, I became mildly frustrated with having to copy and paste using the mouse, which slowed down my development. Nonetheless, it’s nice not having to create the sound system from scratch.
00:30:09.890 Thanks once again for attending!