Aerotwist - Guitar Tuner
) | \ /| |\___ \ | |<br>(____ /\___ >__| \____/|__| \/\_/ |__/____ > |__|<br>\/ \/ \/
Giant ascii art embedded in every page of your site is how you<br>show other people that YOU CARE. And I do. I really, really do.
But if you're looking at the source of this page, that means I won the game.<br>Not sure what the game is, but I feel like I won it.
See Guitar Tuner
Overview and Highlights #
Guitar Tuner, despite its cryptic name, is a web app that helps you tune a guitar. I'm sure you, like me, are shocked at this revelation.
Here's some of the things it has:
Web Components . It's the perfect time to give Web Components a run out. In this case I had the idea that I could have three components: one to handle the audio input and analysis; one for the dial; and one for the instructions (tune up, down, etc).
Service Worker for offline . Sure, why not? It's effectively a single page app, and that means adding on Service Worker support should be super simple. Plus offline support is the sport of winners.
Web Manifest . On the off-chance someone wants to add the app to their homescreen, it seems like it would be good to provide a nice icon, short name, and set up some preferences for how the app should behave. Yay manifests!
ES6 classes, fat arrow functions, and Promises . I gave these a run out recently, and I got hooked. I'm not going back to ES5 unless you drag me, so they're in here, too. But I also used them with the Polymer / Web Componenty bits this time around, which was fun.
Open source . You can get the code and have a look around!
If you're not a guitarist, or you don't have a guitar to hand, you can always check out the video below where I show it in use. Unfortunately it does involve seeing me play the guitar, for which I can only apologise, but hopefully I at least get points for trying.
Big fat caveats #
Nothing quite like couching a thing you've built in a load of just-in-case-it-doesn't-work caveats. So with that in mind...
I have assumed a standard-tuned, 6-string guitar . If nothing else I don't have a 12-string to hand, and generally they're way less common, and I'm nothing if not a majority panderer when it comes to tuners. You can always submit a patch if you would like to. It may already work, I just don't know.
The tuning is done through the device's microphone . It's probably going to be (well, it will be) less accurate than a chromatic tuner that uses the vibrations on the guitar's neck to provide frequency information. But in a pinch it could be handy.
Mobile Safari isn't supported, nor is Internet Explorer . This is because they don't support getUserMedia, and I can't do much to work around it. If the browser can't listen, it can't help me tune a guitar. Edge will support getUserMedia, though, so that's good news!
Alright, caveats out of the way, let's talk details!
Polymer #
I recently wrote a post about how you can lazy-load and progressively enhance your pages with Polymer. Guitar Tuner uses that exact approach (because I figured it out while I was building the app), and that means I have the Web Components goodies, but the app should be super fast to load. In fact, on WebPageTest the Speed Index for a cable connection is ~450 , and on 3G it's ~2800 , which I'm very happy about.
It is a small app, mind. The whole thing weighs in at 40.1KB including Polymer (but excluding the 12KB Web Components polyfills), so if it had been slow to load I think I'd have found that more than a little depressing.
You can read the other post if you want the super gory details, but the quick version here is that I'm loading all three of my web components individually, and as each one arrives it upgrades the element it manages. In order to prevent FOUC, I inline some styles in the head of the app's index.html that make it look like this:
The placeholder styles make the app look like this. They're inlined to the page and removed when the elements upgrade.
When each elements upgrades it removes the placeholder styling. That means the app gets to something that looks “visually complete” much sooner than waiting for the elements to upgrade first.
When each elements upgrades it removes the placeholder styling. That means the app gets to something that looks "visually complete" much sooner than waiting for the elements to upgrade first.
The elements all race to get Polymer, and, because of the way HTML Imports work and because Polymer is always requested with the same URL, we only request it once. Once loaded, all three components will be able to use it.
Web Components #
The app contains three Web Components:
. This is responsible for requesting microphone access through getUserMedia, and will pop up a toast if there are errors. It also uses the Page Visibility API to toggle microphone access so if you hide the app, then microphone access is disabled, and re-enabled once you switch back to the app. It also figures out what the dominant frequency is in the audio and...