Ben Eggett
Writing Music with Ruby: A Subtle Introduction to Music Theory

Writing Music with Ruby: A Subtle Introduction to Music Theory

by Ben Eggett

In his presentation, "Writing Music with Ruby: A Subtle Introduction to Music Theory," Ben Eggett explores how music theory can be understood and applied through programming in Ruby. He begins by expressing gratitude to his supporters and sharing his background in both programming and music. Ben notes that many individuals find music theory challenging due to poor instructional approaches, which he likens to bad programming documentation.

He emphasizes the importance of understanding sound waves, starting with the concept of the A note at 440 Hertz, and introduces the basics of notes, frequencies, and audio sampling. Key points covered in the talk include:
- Understanding Audio: Ben explains sound as vibrations measured in Hertz, how they convert into electrical signals, and the concept of pure tone.
- Generating Sounds with Ruby: He demonstrates how to create sine waves and notes using Ruby code, explaining essential concepts such as sample rates and wave files.
- Musical Intervals and Scales: Ben discusses octaves, semitones, tones, and introduces both chromatic and major scales, illustrating how these can be generated via coding.
- Modes and Chords: The talk covers modes as variations of scales and how to build chords through stacking thirds.
- Chord Progressions: He illustrates how chord progressions work using a common sequence recognized in many pop songs.
- Creating Music: Throughout the presentation, he provides real-time coding demonstrations, resulting in various musical outputs, including a stochastic song that varies each time it is played.

Ben concludes by encouraging attendees to engage with creative coding as a means to better understand music theory, mentioning that his code is available on GitHub for others to use and adapt. His focus remains on experimentation and enjoying the creative process over perfection. The session serves not only as a coding tutorial but also as an introduction to the principles of music making through programming.

00:00:08.960 Hello, everyone.
00:00:23.600 I'm Ben Eggett, and the very first thing I want to do is thank all of you who have supported me—my co-workers, colleagues, Ruby friends, previous students, and the local community. Thank you, Mike, for selecting this talk; I'm really excited to give it. At least one person in the room is excited.
00:00:35.600 I want to give a special thanks to my wife, Lily, who is here up front. Thank you, Lily; you've been an incredible support for me. I know it’s not always easy to be the spouse of a programmer.
00:00:54.160 A little bit about me: I was born and raised here in Salt Lake City. I've moved around a bit but ultimately found my way back. This is my family: my wife, Lily, is from Peru and is one of the most social and awesome people I’ve ever met. My daughter, Kenneth, is halfway from Peru and is the cutest girl I’ve ever met! She also likes eating rice, tofu, and sushi, but don’t tell her mom.
00:01:14.000 My hobbies include skiing, longboarding, playing guitar, and, of course, music. I’ve lived in several different places, and I currently work in access development for a fantastic employer. If you’re interested in what we do, please talk to me afterward.
00:01:39.439 I’m the organizer for the downtown Ruby user group meetup. For those of you who are unaware, we have weekly hack nights on Wednesdays at the coffee shop just two blocks up the road. We also have monthly meetups at a local company a half block away from here. If you're not downtown, there are five other chapters nearby, so check it out at utahrubi.org—we have an awesome community!
00:01:56.880 Okay, so do I have any musicians in the house? I can’t actually see half of you, but I’m curious if anyone knows any music theory. When I was in high school, I took a course called AP Music Theory. I had been playing guitar since I was 11, had played in bands, and done concerts since middle school. I thought this course would be a great way to add some depth to my music knowledge.
00:02:29.360 The course was taught by the band teacher, and it started out quite interesting. We learned about the relationships between notes, scales, and chords, and concepts like the circle of fifths. We were instructed to compose music by writing sheet music from scratch, and we were graded on our ability to play the sheet music on a piano in front of the class. I had never played piano before, which made it a bit challenging.
00:02:54.239 The class progressed in this direction, focusing on writing melodies with accompanying chords in various styles, like classical, jazz, blues, etc. The AP test came, which was divided into three parts: it assessed our theoretical knowledge, our ability to handwrite sheet music, and included a vocal test to see if we could sing along with the theory. I failed quite hard; I received a score of two on the test. Just so you know, a three is considered passing and a five is the maximum that can earn you more college credit.
00:03:35.280 Interestingly, I aced the theoretical part, but I had never claimed to be a vocalist or a sheet music expert. Given that I had never played piano before that class, I was pretty bummed. I thought I was a decent musician for a 17-year-old, at least a good guitar player, but I was abruptly corrected. Maybe I was just dumb, or it’s possible that the material was taught in a way that I couldn't really understand.
00:04:07.120 I think there are some serious problems with learning music theory. As a programmer, I like to use this analogy: the documentation is often bad. When looking at a beautiful song, I’m sure I could spend half a day figuring it out on a piano, but it can feel like someone is trolling me with poor documentation.
00:04:25.440 I exaggerated a little bit, but enough said—the API is worse! This illustration of the circle of fifths, a fundamental piece of music theory, was daunting when I first saw it. Once I understood it, I found it actually quite simple. On the other hand, no one here has ever said their code was very simple once they wrapped their heads around it. Documentation doesn't foster learning; in fact, it often feels like a huge barrier.
00:05:10.400 If this had been my first introduction to programming, I probably would have fallen into a very different career path. However, I must admit that now this kind of stuff really fascinates me. I started searching for some Ruby projects that could interface with assembly language and stumbled upon a little gem. I’m glad to see at least one other person in the room shares this interest.
00:05:41.759 Now, to quote Ryan Davis, 'All code is a little bit of a lie.' In fact, Ryan, I just want to say thank you. In my mind, you exemplify this principle. You're one of those giants in my book, and I appreciate what you’ve done.
00:06:16.720 Are you sure you don’t know music theory? Okay, what is music, really? In this talk, I’m going to show you how to start with nothing but a Ruby interpreter to generate sine waves, notes, scales, modes, chords, arpeggios, and songs in a comprehensible manner, even for those who have never touched an instrument before.
00:06:50.240 I hope to offer an interesting perspective for those who are already well-versed in music theory. Just a warning: I don’t claim to be an expert, remember—I failed that AP test. So, I ask for your help in person, not on the internet.
00:07:01.599 The remainder of my talk will bounce back and forth between slides, music, and code.
00:07:07.599 Let’s talk about notes. I first want to start off by discussing 440 Hertz. Who here knows what this is and what it has to do with music? Okay, so 440 Hertz represents 440 cycles per second, and it’s an ISO standard established in 1975.
00:07:21.280 It is an A note. Let me show you what this sounds like.
00:07:50.560 Live coding is my favorite thing; it never goes wrong, right? But let’s see if I can demonstrate this.
00:08:02.080 So in order to understand music, we must really understand sound waves. Audio is essentially vibration—typically, we’re discussing vibrations in the air, approximately 20 Hertz to 20,000 Hertz, which makes up the human audible range. This means the air is moving back and forth roughly between 20 and 20,000 times per second. The lower the frequency, the lower the pitch, and the higher the frequency, the higher the pitch.
00:08:36.800 If you measure that vibration and convert it into an electrical signal—let's say using a microphone or line-in—you’ll receive an electrical signal with voltage variations in some waveform. This is pure tone, a hypothetical construct of pure music that’s computer-generated. We create sine waves that fluctuate between one volt and negative one volt. If you hooked up an oscilloscope or voltmeter, you’d see this displayed visually.
00:09:37.200 When we hook our voltmeter to a computer and instruct it to read like 440, we want to set a reasonable sample rate for a CD, which is like 44,100 times per second. You could also add another channel for stereo sound. This is essentially how music is recorded at the sound engineering level.
00:10:10.000 To build notes, we’re going to touch on some music and some math, using Ruby. I won’t focus heavily on the math, but it’ll be included for context. So, audio consists of sine waves; if you don’t grasp this concept instantly, don’t worry—you're not alone!
00:10:45.200 In our examples, we’ll be writing a WAV file in mono format PCM. A few key terms: frequency refers to the number of cycles per second and sample rate is the number of frames per second. In this context, we’ll be writing a wave format, so a frame is basically a 16-bit floating-point number ranging from negative one to positive one. To build a note, we’ll need to create an array of samples for a one-second-long note at our given sample rate.
00:11:56.480 We can calculate the duration; for our one-second-long note, that means we’ll utilize 22,050 frames at the sample rate. Next, we’ll figure out the cycles per frame. Essentially, the fraction of a cycle per frame equals the frequency divided by the sample rate. With these calculations and the understanding of the math involved, here’s what our code could look like.
00:12:50.640 I’ve object-oriented this to simplify building a DSL around it, but it didn’t start out that way—it began as scripting primarily using hashes. The concept is to define a frequency, a duration, and to perform our three calculations from earlier.
00:13:07.760 With that, we utilize our favorite Ruby module, Enumerable, to compile all these samples by mapping them together in the code. Essentially, we’re taking the sample and applying the sine function to a phase, which increments each time we loop through by our sine wave cycle, represented as 2π radians.
00:13:54.000 Here’s a demo of what that looks like. So this demonstrates the samples we’re generating, about 22,050 samples that fluctuate from one to negative one. When we graph it, it visually presents one cycle, specifically for the A note at 440 hertz.
00:14:27.440 Now let's discuss writing a file. You can create a WAV file using the Ruby standard library; it isn’t overly complicated, but that’s not the focus of today’s topic. I once wrote a simple version of it and stumbled across this WAV file gem. This gem is a native Ruby implementation that doesn’t wrap any C libraries; it’s super straightforward, running under a thousand lines of code, including plenty of comments.
00:14:56.720 It also supports various formats—like jumping from mono to stereo—so we define an output class that looks similar to this. I’ll speed through this part; we set the parameters for writing our WAV file and include this module in different code parts. With that done, we can play our notes.
00:15:43.520 Cool! So, we write it to a WAV file. If you look at it, it stores it as a note.wav, and I’m using afplay, which is an Apple command-line tool for playback.
00:16:11.200 As we learned yesterday from both Paul and Michael, the power of programming really lies in our ability to abstract concepts. The first abstraction I want to discuss is octaves. An octave is simply double the frequency; for instance, the next note would be 880 hertz and the previous one would be 220 hertz.
00:16:50.559 The slides I have for this topic might look a bit silly, so if they succeed, be sure to clap hard, but if they don’t, clap even harder! Now, if we wanted to create an octave, we would just double the frequency. Conversely, if we wanted to drop an octave, we’d go down to 220 hertz. If we proceed to play those in order, we could explore three sets of octaves.
00:17:29.360 This leads us to a practical application: we can encapsulate this into an octave class, adding a couple of extra features, like the capability to set the direction and specify the number of octaves. Essentially, we take that starting note and loop through it, doubling the frequency if we’re ascending or halving it if we’re descending, resulting in a simple way to generate the appropriate samples.
00:18:16.560 Now, we can apply this to create sound sequences, which are quite fun. Next, let’s discuss tones and semitones. A semitone is the smallest interval in Western music—it's one fret on the guitar or the adjacent note on a piano. A tone consists of two semitones, and there are twelve semitones in an octave.
00:19:04.280 The mathematical side of this explains that moving up 12 semitones results in the equation r to the power of 12 equals 2. The 12th root of 2 is approximately 1.059. This allows us to create a systematic way to generate notes. When we set something up with the 12th root of 2, we can calculate frequencies for each of those notes.
00:19:43.120 To illustrate, I’ll create a note set at 220 hertz and reduce the duration to play it out a bit quicker. By incrementally adjusting the frequency using the 12th root of 2, we’re now traversing up the chromatic scale, which plays every note across the range.
00:20:37.040 Scales are next. The simplest scale is a chromatic scale. Most common scales have seven notes; a scale is defined as all the notes played in order. The chromatic scale encompasses all those notes, though it may not sound very musical yet. We also have the major scale, the most commonly used scale, which includes seven specific notes arranged in a pattern that typically sounds happy. The minor scale follows a tone-semitone pattern, creating a sound that is often perceived as sad.
00:21:20.400 Let’s talk about modes. How many here understand modes? A few less hands went down in the audience, which is good! Just know that there are seven modes, similar to the seven notes in a scale. Modes are essentially rotations of the major scale. If we look at the pattern for each mode, we can see how they can fit into the broader context of what we’re discussing.
00:22:09.560 These interval sequences can be rotated through using Ruby’s rotate method. I’ve created a little modes module that uses this rotation method to facilitate music composition. The bottom of the module simply includes alias methods for easier access.
00:22:49.520 Let’s set up a quick demo of that to illustrate how it works. There we go! You can see the names of our second modes and pull these same elements together using the various modes.
00:23:31.120 Now, back to scales. Scales are simply iterations of a mode from a starting point, and we can utilize the twelfth root of two that we just discussed to look up a mode. I’ve built a small DSL that lets us input the desired mode and retrieves the necessary frequency.
00:24:32.960 We can map it out using the major mode, for example. We saw how it plays out nicely! You can easily produce sound with all that.
00:25:19.680 Now, let’s discuss intervals and specifically thirds. Thirds can be major or minor; a major interval consists of two to three semitones, while minors stretch to four semitones. To visualize this, we just need to map a scale and select a note. Remember that moving sequentially through intervals forms arpeggios.
00:26:06.720 To demonstrate, if we have a scale, we can define a third and proceed. So, that’s a third! Interesting, right?
00:26:39.360 Now let’s discuss chords. Single notes are easy, but to form a chord, we need to combine thirds, effectively melting down and clamping the values to fit within a wave format. The code to do this is somewhat similar—we take the third and flatten the values, grouping them together while ensuring we set a ceiling on them.
00:27:12.120 Let me show you what a chord sounds like. Here’s a chord, and this is what it sounds like. A bit too perfect, right? The character of music often arises from instruments not reproducing perfectly rounded sine waves—computers, on the other hand, excel at being perfect, which influences how we perceive music.
00:27:56.160 Now, let’s quickly touch on chord scales. You can derive different chords from a scale that will automatically be major or minor, based on its pattern or mode. Each mode generates a specific chord when we stack thirds. I have a small module prepared to facilitate this for the scale.
00:28:39.680 Next up, chord progressions. These are variations of the aforementioned chord scales that we can play in a specific order. A common progression is the I-V-vi-IV progression. It’s essentially a sequence of chords played in a specific arrangement.
00:29:26.920 Let me give you a quick demo of that. We have our scale, and we can produce the chords. Now, let’s play the fifth or even the sixth, and then back to four—this is that chord progression I mentioned earlier.
00:30:00.720 This familiar progression is common in countless pop songs; if you hear it, it's a straightforward recipe for some catchy music.
00:30:33.920 Let’s conclude with some songs. I’ll start with an example using arpeggios, traditionally the notes played in order—this section is about harmonizing that with a chord progression.
00:31:20.000 The beauty of the extraction process is creating a code DSL we can program our musical compositions with. This code is refined into just six lines for the song.
00:32:16.480 Let me show you one more simple song featuring a melody. It’s straightforward; we define a melody and navigate through the same structures we’ve discussed. If you recognize this song, we’re instantly friends.
00:32:54.400 This is an introduction to the distortion phenomenon, created by chopping the sine wave at certain breakpoints—this clipping yields unique textures.
00:33:03.840 I think I could start an indie electric band!
00:33:06.240 As a final piece, here’s a more complex song. This one is stochastic—meaning it writes itself a little differently every time.
00:33:14.720 Just enhancing this first song, we see variability every time.
00:33:19.120 You can rotate this melody or even shuffle it, which results in it playing differently each time. I propose it could be the new MountainWest RubyConf theme song.
00:33:51.760 I want to emphasize that there’s so much you can accomplish with this format.
00:34:02.720 Now I must admit this is not the most polished music library—it was never intended to be. It serves as a creative coding experiment.
00:34:43.280 It’s designed to help you learn Ruby and grasp music theory more effectively than I did during my lengthy AP course.
00:35:07.840 While the code is not perfect and could greatly benefit from refactoring, it’s flexible. The DSL isn’t complete, but that’s okay—it serves its purpose.
00:35:25.760 I want to express my gratitude to Jameis Buck—creative coding is all about experimentation and enjoying the process.
00:35:44.240 I’ve uploaded this code to GitHub. Feel free to use it, play with it, and modify it as you see fit. There’s no pride in ownership here; it's about the fun of creative coding.
00:36:00.960 Thank you, everyone. Let's continue crafting beautiful music together!