Programming Pitch Bending in Trombone Champ


In the newest version of “Trombone Champ,” we implemented new code to handle pitch bending that works really well. For some reason, it took us a while to figure this out, so we thought it might be helpful to document our solution!

If you have experience with music theory or working with sound, you will probably read this and think “Wtf! You moron! This is all common sense!” Well, maybe you’re right! But when I googled this stuff years back, I wasn’t able to find any helpful documentation. The only thing I was able to find were various people attempting to solve the same problem. Interestingly, it turns out the math to handle pitch bending is very simple.

(If all you care about is the code, you can skip right to the end.)

To begin: if you’re thinking of building a musical display like the one in Trombone Champ, your first instinct will probably be to display the whole notes in a major scale. Something like this:

Makes sense, and this is what the very first mockups of Trombone Champ looked like. Here’s the very first mockup of Trombone Champ’s user interface: you can see that all of the note lines are evenly-spaced like the above diagram:

However, there’s a big problem here: it assumes that the tones in a major scale are spaced evenly. Take a look at a piano:

Even though the whole notes are spaced evenly on a piano, there are black keys distributed unevenly between them. When you go from C to D, you’re moving two semitones: from C, to C#, and then to D. But when you move from E to F, you’re only moving one semitone.

Most western music uses what’s called an “equal-tempered chromatic scale,” where an octave is divided into twelve equal semitones. So, technically, if we’re going to lay all of the notes out in a linear fashion like in Trombone Champ, the black and white keys should be equally-spaced. So, looking at the keys of a piano is slightly misleading in this case.

(This also goes to show how well-designed the piano keyboard is… it handles the various intervals in a way that’s immediately easy to understand.)

Anyways, if we want to display all of the notes on a flat plane like “Trombone Champ,” we can visualize it as 12 equal semitones:

And then, to simplify, we can just delete the sharps and flats:

This is how the note lines are distributed in Trombone Champ. Everything is spaced based on 12 equal semitones.

It may seem weird that the lines aren’t distributed equally, but nobody’s complained so far! Also, the fact that the game allows you to slide smoothly between notes makes this somewhat necessary: we want x number of pixels to equal x pitch change. If the whole notes in the above diagram were spaced equally, some of the gaps would require more pitch bending than others. This would be a huge pain to program, and it would also feel kind of weird: if the user moved the mouse at a steady rate, the pitch would sometimes bend twice as quickly.

Anyways, using the center as a baseline, this is how we need to adjust the pitch of a note as it bends:

In Unity (the game engine the game is made in), each AudioSource has a “pitch” value which you can simply adjust up and down. This is the value we adjust in the game. Most audio software has a similar “pitch” value that acts the same.

Looking at the above image, you can see that this isn’t a simple linear function: you’re doubling as you go up (from 1 to 2), and halving as you go down (from 1 to 0.5). So, we can’t use simple linear math.

This is because, in real life, pitch is a logarithmic function rather than a linear one. Pitches aren’t distributed evenly, which is kind of annoying when you consider that we’re using what’s literally called an “equal-tempered chromatic scale.” You can see an example of this in on a guitar neck: the frets get closer and closer together as you move up the neck.

In older versions of Trombone Champ, we used a bunch of magic numbers to nudge the values in the right direction, but was done mostly by guesswork. I wasn’t fully aware of the “real” math behind pitch, and tried to make it sound good “by ear.”

The result sounded OK most of the time, but some pitch bends would be quite out of tune. You can hear some of the minor issues here:

Anyways, the newest version of the game fixes the problem by using the “Real Math” behind tones. If you do a lot of research, you can find pages like this one, which document the actual values of the tones in a scale: Twelfth root of two (Wikipedia)

As it turns out, each semitone is 21/12 apart from each other. You can see this represented in the “Multiplier” column of the table here (from the above Wikipedia link):

There’s a lot going on in this table, but if you look at the “Coefficient” column, you’ll see that it goes from 1 (no pitch change) to 2 (doubled pitch, one octave up). And, you’ll see that all of the tones in between also have their values listed out.

One potential way to fix the pitch bend problem is to move all of the lines around so that they’re spaced unevenly, like the lines on a guitar fretboard, using the numbers in the “Coefficient” column as a guide. If you do this, you should theoretically be able to use a simple linear slide, and all of the lines representing the notes should perfectly correspond to the correct tones.

We’d originally considered implementing this fix in Trombone Champ, but decided against it, as it would lead to a weird distribution of lines that might not make much sense to the user. It’s also bad for gameplay to have these note lines distributed in this way, because high notes would be very close to each other while lower notes would be spaced apart much more. So, lower notes would be more difficult from a gameplay perspective, since they’d require more movement.

Luckily it turns out it’s not so difficult to solve this “the right way:” keeping the lines where they are (spaced evenly, according to equal semitones) and using math to make the pitch correct.

Our goal is basically to write a function that results in the values of the “Coefficient” column: so, for example, if you start with A and then bend it up to D#, the resulting pitch change will be exactly 1.414213. And the “multiplier” column reveals how to do this: you need to multiply the pitches by 2x/12, where x is the number of semitones you want to move.

Personally, I find fractional exponents difficult to understand, especially in this weird case where all of the denominators are 12. It helps to simplify all of these fractions. If you convert the fractions to simplified values, it’s dramatically easier to understand:

So, ignore everything else and look at the exponents above (in red). They simply go from 0 (representing zero pitch bending) to 1 (representing one octave of pitch bending upwards) or -1 (representing one octave of pitch bending downwards). And the math works:

  • 2 to the power of zero (zero pitch bending) equals 1, which makes sense because multiplying a pitch by 1 doesn’t change it at all.
  • 2 to the power of 1 (pitch bending up 1 octave) equals 2, which makes sense because you’re doubling a pitch when you go upwards an octave.
  • 2 to the power of -1 (pitch bending down 1 octave) equals 0.5, which makes sense because you’re halving the pitch of a note when you go down an octave.

Suddenly it seems really simple! We just use 2x, and then all we need to do is change x and it should work like magic!

In the newest version of Trombone Champ, all of the old pitch bending code has been replaced with the code above. It’s a fraction the size of the previous code and works much, much better!

Pitch bends still can still sound very slightly off-tune, but I attribute that the sample we’re bending (a sloppy trombone toot which starts off slightly flat) rather than the code.

Anyways, hope this helps someone out there! Now you’re free to make your very own ripoff of Trombone Champ, or some other tool, or whatever. Have fun!

Holy Wow Studios