Urf Tunes is a procedural music generator that uses your League of Legends Champion Mastery levels to generate a song unique to your data.
We're KirkBerkley and RndmInternetMan, two League of Legends players on the NA server. We created Urf Tunes for the Riot Games API Challenge 2016.
There are a few ways we use the Champion Mastery data to alter the song. First, we use pseudorandom number generators to determine things like the form of the song, the chord progressions, the pitches of the notes, the drum patterns, and so forth. We don't want the songs to be random, though - we want them to be deterministic, so your song never changes (until you level up a champion). That's why we use the Mastery levels from different groups of champions as the seeds for these pseudorandom number generators. By seeding the pseudorandom number generator with consistent data, the same "random" numbers are produced for the same Champion Mastery data, which means you get the same song every time.
Second, we look at the total levels of some groups of champions to determine which type of introduction your song gets.
Third, the sound of the primary melody instruments is created by directly using Champion Mastery levels; we'll get into this a bit more in a later question, as it's really fundamental to the project.
If you're interested in knowing what parts of the song are affected by a particular champion, you can search for the champion's name in our code; we intentionally use champion names to index into the champion mastery data to make it easier to do this.
Not quite. We're not just playing random notes in a random order and hoping for the best. We use the numbers to move through Markov chains to choose the structure of the song, rhythms for the drums, pitches and durations of the melody notes, etc. In short, Markov chains are a sort of "map;" for every possible state you could be in, it defines which states you can go to next, and what the probability of moving to each of those states is. The values the pseudorandom number generator gives us define how we move through the "map." Setting up the Markov chains to produce something that sounds good can be tricky, and is certainly more difficult than just using random numbers directly. We spent a lot of time fine-tuning our Markov chains to make sure they generate sweet beats.
Another cool thing is that we use multiple Markov chains and a differently seeded pseudorandom number generator for each one, so leveling up a single champion results in changing only one aspect of the song. This gives a similar, but still noticeably different, song, which gives a nice sense of progression as you level up champions. Another advantage of using this system is that everyone, no matter how much or how little they've played League, has an interesting song.
So far, we've talked about how we use the Champion Mastery levels in ways that aren't really reversible: you can't tell what Champion Mastery level you have on a particular champion just by listening to the song. However, we also use the Champion Mastery levels to generate some special waveforms for the melody instruments. Basically, this means that the sound of the melody itself contains the mastery data - those bars you see in the visualizer are actually champion mastery levels (except the bars on the far left - those are low-frequency instruments like the bass).
Without going into too much detail, combining harmonics (integer multiples) of the frequency of the note can be used to create complex sounds. This happens in real-life instruments, and it's why, say, a trumpet sounds different than a piano. With a computer, we can set which harmonics we want to use, and how powerful we want those harmonics to be, allowing us to create a variety of sounds. For each of the five melody instruments used in the song (outside of the introduction), we use your Champion Mastery levels on 26 champions; each champion affects one of the first 26 harmonics, and the higher the Champion Mastery level, the more powerful the harmonic will be in the sound.
Obviously, determining the Champion Mastery levels from those sounds isn't something a typical human could do (and we doubt even an atypical human could do it). So how is it reversible? Enter the Fast Fourier transform. Basically, the Fast Fourier transform takes the sound wave and extracts the powers of the harmonics from the sound. We take this data and display it in the visualizer. You might notice that some patterns in the visualizer correspond to particular instruments. As we mentioned before, the bass and bass drum are pretty skewed towards the left side, and the snare drum is at equal height across the entire visualizer (this is because it's basically just white noise). The spikes you see are your Champion Mastery levels. We also show the Champion Mastery levels using the champion icons below the visualizer so you can easily identify which champions are used in the current instrument. The images are dimmed for lower Champion Mastery levels to make it easier to pick up on which champions correspond to which visualizer spikes.
When the API Challenge was announced, we thought about the number of different possible sets of Champion Mastery levels there are. Each champion can have six different levels (including level 0) and there are 130 champions, which gives 6130 possibilities. That's a bit more than 1.44 x 10101. Since there are so many possibilities, it's extremely unlikely that any two League of Legends players have the same Champion Mastery data (except for players with only a few total levels). This makes your Champion Mastery levels a sort of "fingerprint" - something that's unique to you. We thought it would be interesting to present that "fingerprint" in a unique way, and the most unique way we thought of was music.
When we entered into the API Challenge last year, we went into it with a clear idea of what we were aiming for, and how to accomplish it. For Urf Tunes, however, we had none of that. Before this project, we knew nothing about procedural music generation and little about how sound worked, we didn't know what tools and libraries were available, and we only had a vague idea of what the end result would look like. Basically, the biggest challenge was overcoming the uncertainty of how to teach a computer how music works. We're glad (in hindsight) that we chose to go with this project in spite of the uncertainty - we learned a lot in only a couple of weeks, and we managed to make some music that doesn't sound completely awful!
The most important tool we used was the Web Audio API. This is how we make all of the sound that you hear and the visualization that you see. It's really well documented, it's easy to use, and it's built-in to your browser already! Unfortunately, as we found out, it doesn't have complete support in all browsers. The only browsers we found that fully supported everything we used were Chrome and Opera.
For the recording, we used WebAudioRecorder.js by GitHub user higuma. It's built specifically for use with the Web Audio API, and it was really easy to use.
We used seedrandom.js for generating pseudorandom numbers. We used this library because the built-in Math.random() function can't be seeded. As we explained earlier, it's very important that we seed our pesudorandom numbers.
For creating the website, we also used jQuery and Bootstrap.
Though not a development tool or library, we found this music theory website really helpful. It lets you look through chord progressions in popular songs and see how frequently they're used. That data translated really well into rules for our Markov chains.
There's a lot that could be done to add more variation to the generated music. For example, all of our songs have the same kind of "feel" to them, they're all in the same key, and they all have the same time signature (4/4). We decided to keep these things the same across all of the songs to simplify our music generation algorithms, but they're restrictions we wish we had time to remove. We would love to add more variation between the songs, but that would require us to teach the computer (and ourselves) a LOT more about music theory, and that's a bit too much for two weeks.
We also had some ideas for features we wish we could've added to the site. For example, it would be cool to have a playlist feature so you could enter a bunch of Summoner names and have their songs play one after another. It would also be nice to be able to download the song immediately instead of waiting for the whole song to finish playing.
You have to wait until the end of the song before you can download it. We're actually building the song dynamically as it plays in your web browser - that means the song isn't fully written until it finishes playing.
Urf Tunes works best in Google Chrome. Although we tried, we couldn't get everything working in every browser. In particular, the sound quality in FireFox is, in our experience, much worse than in Chrome.
We do! You should check out: