Recently I announced Sound of Summer, a catalog of past summers with respect to music. This was my first Rails app and takes advantage of both the Rdio and Echo Nest APIs. I got more comfortable with git, AJAX, and JSON but I still feel like a fraud around the words array, object, and constructor. I know people are interested in how this project came to nascence but since I’m not clear as to what part of the process is of particular interest, I’ll just tell the whole story.
Abstract
Many songs in my iTunes library are tagged by season, so I imported an iTunes-generated CSV file into a database. Selecting a year brings up a list of songs and locations for that year via AJAX. Certain songs are available on Rdio, so when you select a song, a search query is sent to the Echo Nest API and returns a JSON object that includes the Rdio key for the track, which is then passed to the Rdio Web Playback API which ultimately plays the song. I’ll explain why I took that detour momentarily. Another feature is the opportunity to tweet what you were listening to during that season of your life.
Working with Rails
I have had absolutely no Ruby or Rails experience before working on this project, but I’ve worked with CakePHP, an MVC framework which was modeled after Rails, so I immediately felt comfortable. Also, Ruby is hilarious. You can Google “thin unicorn cucumber faker sinatra tux” and all the results returned are related to Ruby. That said, it was easy, as a neophyte, to accomplish what I needed to between the excellent documentation, the prolific community, and the focused and accessible RailsCasts. I would advise anyone curious about Rails or Ruby to jump right in, given the breadth of resources available.
Responsive Navigation
Sound of Summer is responsive. Linearizing the content for narrow viewports was straightforward, but the timeline took a little bit of creativity. For narrow viewports, I flipped its orientation - it’s the same markup for both - and rather than adjust the height and opacity properties for each year based on the song count which was stored in a data attribute, I adjusted the width and opacity. I also used the conditional content technique to truncate the number of characters in the year label for certain widths.
Rainbow Road
One aesthetic aspect of the project that I’m proud of is the gradient effect on each playlist, which I’m going to release as a jQuery plugin. Essentially, I loop through each list item with respect to i, apply the css property of background-color in rgba to each item, and pass i into the loop, in addition to some constants to influence the chromatic values that I used my imagination to come up with. As i increments, each item in the loop has an incremented value of i, a different rgba value, and different color properties. The most primitive example is on dribbble, but it’s been improved:
function rainbowRoad(container) {
$(container).find('a').each(function(i) {
var self = $(this),
r = Math.round(20+i),
g = Math.round(i * 2.25),
b = Math.round((10+i) * 2),
a = (.1+(i*.01));
self.css({'backgroundColor': 'rgba('+ r +','+ g +','+ b +','+ a +')'});
});
}
Rdio API
The documentation for the Rdio API is impressively well-written and thorough. The Web Services API support is extensive, with libraries for Python, Ruby, C#, Java and PHP, et al. The Web Playback API is just as well supported. I believe its ease of use is all due to the hard work of Ian McKellar, who really impressed me with his dedication to improving the API and making it more accessible to developers. Personally, I felt that the support group, to which he is a dedicated contributor, was a necessary companion to the API documentation, and I treated it as supplemental reading.
Echo Nest API
Echo Nest really took me by surprise. As a service, they gather a lot of interesting data on all music objects - tracks, albums, artists. I was astounded at the quality of data available for each track, and I was only scratching the surface of this rich and cavernous platform. Each song returned from Echo Nest had data on intrinsic musical properties like pitch, key, time signature, speechiness, danceability, a property called ‘hotttness’ and tempo which is ultimately what I used for this project. Where else do you find all that data about one song in one place? It’s like you think you know everything about your favorite song, but there are all these aspects that you can’t possibly know - how can you divine such deep analysis just by listening? This is definitely the coolest data I have ever come across in my entire life, and I’ve synthesized porphyrin.
Feel my Heartbeat
When a song is selected, there’s a pulsing heart indicator - an icon font in a pseudo element - that lets you know it’s playing. (Well, it pulses as long as you’re using a browser that supports css3 2d animations). The support for applying transformations to pseudo elements is limited, but you can position it absolutely and animate the parent element. The heart pulses to the beat of the music by controlling the interval of the animation from the tempo of the song.
It’s hard to tell the story of the heartbeat without telling the story of the Echo Nest API, which is impossible to tell without talking about the Rdio API. While the Echo Nest API turned out to be a vehicle for one of my favorite design elements, it was initially a compromise, as I was unable to query the Rdio API from client-side techniques alone. The Rdio API needs to sign every call it makes, and that requires a server side component - this is well-documented. Echo Nest, an Rdio partner, has a much simpler API: pass in your api key, make an AJAX request, get an object back. This object included the Rdio key for playback and the tempo of the track. Tempo is evaluated in the units of beats per minute, or the amount of times the heart should beat per minute per song, also known as frequency. But we need the duration of our animation, or the period. If you remember your 11th grade trigonometry as well as I do, you would look this up on Google and see that the frequency is 1/period, which means that the period is 1/frequency.
I defined a period two ways depending on the tempo to account for the visual busyness of a single heartbeat consisting of two visual transformations, the heart enlarging and the heart contracting. For the majority of cases, I set the period to bpm/120. This shortens the period, but since we’re dividing 1/period, our duration will be longer (if you weren’t terrified of fractions in 5th grade or learned about limits in calculus, you’d remember that the bigger the denominator, the smaller the result (e.g. 1/1 > 1/10 > 1/100 > 1/1000). The converse is also true. For songs over 140 bpm, which correlates to a vivace tempo, I felt a little visual busyness was warranted. I increased the the period to bpm/60, thereby decreasing the interval, and accelerating the animation so the heart will beat twice as fast for songs with vivace tempos and above.
var bpm = (song.audio_summary.tempo),
heartBeat = function(){ $('.indicator').css({
'-webkit-animation-duration': 1/period+'s',
'-moz-animation-duration': 1/period+'s',
'animation-duration': 1/period+'s'
});
}
if (bpm > 140) { //vivace
var period = (song.audio_summary.tempo/60);
heartBeat();
} else {
period = (song.audio_summary.tempo/120);
heartBeat();
}
Conclusion
It was very rewarding to explore technologies and techniques that I didn’t know at the outset of this project. I took great pleasure in developing the details, like writing hilariously named functions like TriggaPane() which sounds like the name of a rapper. But the most addictive aspect was overcoming obstacles that I’d deemed as being beyond my expertise. There were entire weekends spent typing the same commands in the terminal, entire evenings spent refreshing the browser without accomplishing anything. But all it takes is one right thing to move forward, whether it’s modifying one line of code, or approaching your problem from a different point of view.
Another aspect of Sound of Summer that I found fulfilling is the respect I showed front end web development. Too often, front-end gets bullied into mediocrity by markup generated by robots, CMS or framework constraints, time or budget limitations, or just the attitude that front end is easy or not worth crafting as carefully as you would visual design or back-end architecture. But I got to ignore all that and take pride in my work, and believe that it matters to the web at large, because it matters to me.