DEV Community

Cover image for Building AceGuitar: A Flutter App for Guitar Enthusiasts | Part 1
PeterTheSalmon
PeterTheSalmon

Posted on

Building AceGuitar: A Flutter App for Guitar Enthusiasts | Part 1

As I was searching for an arrangement of Tarrey Town the other day (went with this one, for anyone interested), I realized that finding guitar music isn’t a great experience – especially on mobile. It involves scouring various sites, dodging paywalls, and a multitude of other painful steps.

Most of this comes down to one website: Ultimate Guitar. Ultimate Guitar has a near monopoly on guitar tabs, and – well, I’m not a huge fan. And while I have plenty to complain about regarding their website, I’ll focus on the app for now.

At first glance, it doesn’t look too bad – but go any deeper and the problems start to arise. Open the tuner and – wow, straight from 2012. Want to add a filter? Oops, forgot to add text descriptions to that enum. How about this chord library – ah.

Ultimate Guitar

Ignoring the questionable design decisions, though, the tab-finding experience isn’t great either – most popular songs have an inaccessible “official” version, which leads to my biggest problem with Ultimate Guitar: their relentless quest to have you subscribe to the pro version.

Now, I have no problem with software subscriptions – it costs money to maintain, moderate, and improve applications. But when the price of a single month is over thirty dollars I struggle to see the value proposition. I could have Netflix, Prime Video, and Spotify for $30 – and the first two actually create original content! Ultimate guitar is almost completely user-submitted music, which makes the price tag even more outrageous.

$8/month is 75% off??

I hope that communicates just some of the frustration I have with Ultimate Guitar – though many of these complaints apply to other apps and websites as well. Pricey subscriptions and poor designs are the most common offenders, but a laggy experience isn’t hard to find either.

So that’s where AceGuitar comes in – my attempt at an all-inclusive, modern, beautiful guitar app build with the framework that makes projects like these possible: Flutter.

AceGuitar will include everything a guitar app should have: a tuner, metronome, backing tracks, recordings, and, of course, tabs and sheet music. It’s designed to be as helpful as possible, without the annoyances of other guitar programs. This article is the first of many that will go through my process of developing AceGuitar.

The first big question was design: how should the app look? (Aside: yes, I know starting with a look in mind isn’t always the best idea. But, in this case, I had ideas in mind already so it seemed worthwhile to record them.) Material design is deeply integrated into Flutter, but it can look a bit generic and plain. There are packages like GetWidget and Libadwaita that offer their own UI components, but none of them felt quite right for this project. What I settled on was Material 3, but with some changes to better fit the clean-but-fun vibe I wanted to convey. I reduced the default corner radii, added some more depth, and customized the font and icons with Work Sans and Ionicons.

I planned to make the app truly cross-platform, with mobile, desktop, and web apps. But, almost immediately, problems arose. Flutter web still just isn’t great: the initial loading time is painfully slow, many packages and functionalities aren’t available, and the use experience doesn’t feel nearly as smooth as Flutter on mobile. The desktop apps had their own issues: the biggest was that the Material design widgets just don’t work as well on bigger screens, which gives the impression that you’re using a scaled-up mobile app instead of something designed for desktop. Considering the effort it would take to get around these issues and the fact that the mobile apps would still be the primary focus, I decided to reduce the scope of the project to just Android and iOS.

I went with Riverpod for state management, as I find it has a good balance of power and simplicity and doesn’t require too much boilerplate. Deep links are a future feature, so I chose AutoRoute for routing and navigation. The backend is powered by Firebase for storage with Firestore as well as Google authentication. In terms of structure, I went feature-first: each section of the app has a folder with the route, page, components, and any Providers or utilities.

Feature-first folder structure

I did make the slightly unconventional decision of naming files and folders with UpperCamelCase instead of snake_case – I just find it easier to read, particularly as the file names and the classes contained within are often identical.

With all that out of the way, the first two features have been focused on individual experiences rather than the sharing of music. First, the tuner. It turns out that extracting pitch from a phone microphone is quite difficult – a few articles (namely this one and this one) proved helpful, but a big part of the process was just trial and error.

I used flutter_audio_capture and pitch_detector_dart to capture and analyze audio data, and pitchupdart was a solid starting point for returning an accurate note.

The biggest problem while developing the tuner was that frequencies from the low E string – meant to be 82hz – can easily be interpreted as double that, which throws off the tuning algorithm. See my very poor graph:

Image description

The way I got around this issue is a bit questionable – here’s the function for analyzing pitch:

Image description

Here’s the essential overview:

  1. If the pitch is less than 96, we can confidently say that the E string is being played. We also update the _lowEValue for use later on0
  2. Here’s where that graph comes in: if the pitch is close to double the existing _lowEValue, we can assume that it is just a misinterpretation and still return E
  3. Otherwise, just return another note

There is a flaw in this logic, though – the D string, with a frequency of 147 Hz, is uncomfortable close to doulbe our _lowEValue, which could lead to further tuning errors. At this point, though, it’s the best I could come up with.

With all that said, here’s a gif of the tuner at work (apologies for the low quality – had to make this a gif).

Image description

I am fairly happy with the design, but functionality will have to be improved in a future update.

The other feature I’ve developed is the metronome, which feels much more complete. One issue was playing beats at regular intervals – the Timer class from dart:async isn’t consistent enough to play the sounds evenly, so I used a workaround by capturing a Ticker from a StatefulWidget.

This enabled very precise timing for the metronome. Implementing different time signatures was trivial, though custom time signatures are something for a future update.

Image description

So that’s AceGuitar so far – most of it is unimplemented, but the structure is in place for what I hope will become a ubiquitous platform for guitar players of all skill levels. If you have feedback, suggestions, or the like, leave a comment! This is my first attempt at blog-writing and I’d love to hear what you think. (You can also check out my posts on my website) 🐟

Oldest comments (0)