The Golang Challenges are a series of monthly Go challenges organized by JoshSoftware Pvt. Ltd. I always read about the challenges but never participated. The October Golang Challenge (aka the 7th challenge) was released. With my background in Android, I was really intrigued to see how easy / hard it would be so I decided to jump into the rabbit hole. This post details that journey including design decisions (a layer system to easily add visual objects), gotchas (screen orientation problems), other interesting parts (generating sound).

Layer System

When I finished my first version of the piano, it was very basic. But the code was complex with tons of if-statements. I thought to myself, if I wanted to add any more interactive parts (like a dialog box) I need to somehow reduce the complexity to make adding them sustainable. That’s where the layer system comes into play.

The layer system idea stemmed from Photoshop. You have independent layers and a layer manger coordinates inter-layer events. Each layer just implements handling the events independently. For example, having a layer of only white piano keys and another layer of only black piano keys.

Every layer has a basic interface to implement.

For simple events like painting, the layers should be painted from the first layer upwards. In this case, this ordering would make sure that the white keys didn’t paint over the black keys.

For touch events, the layer system allows us to regulate how many layers the touch event will reach before terminating the touch event. If we detect that a black key is touched, we terminate the event, and the lower layers don’t get to handle the event. One additional case for this challenge was sliding gesture. Essentially, at a given point, we might slide from key to key. That means we could be moving from one layer (e.g. white keys) to another layer (e.g. black keys). We need to tell the remaining layers to not do anything but disable itself.

The disable and skip cases for touch events can be seen here:

 

Screen Orientation

At the time I started, I saw this issue regarding gomobile not respecting the orientation to stay in specified in the AndroidManifest.xml. This would cause the app to rotate whenever the phone was rotated and the app would get compressed when in portrait mode.

 

My temporary solution was to detect when in portrait mode vs landscape mode.

Once I detected what orientation, I would draw the components in `landscape mode` or `90 degrees rotated in portrait mode`. This would always draw the components in landscape mode and keep the layout usable.

 

Luckily, this issue has been fixed with a CL from Daniel Skinner. You can now use the AndroidManifest.xml and specify which orientation to lock into and avoid this workaround

 

Audio

Generating audio reminded me of engineering school. Things like Nyquist Sample Frequency, Sine Waves, etc all came rushing back. For the exact piano note frequencies, this wikipedia page helped out.

In Go, the note sound data is stored in []byte. This means that the possible values range between 0-255. But a sine wave range ranges between -1 and 1. This means after creating the sine wave data, it had to be scaled and shifted to fit the 0 – 255 range.

 

Wrap-Up

This project was really fun to tackle. I wish I could have added new layers like a dialog box. However, I ran out of time. It’s funny because the layer system took more time than expected and it was originally for helping me to add more objects. I originally tried mobile with Go back in 1.4 and it was such a pain to setup. Now, there’s a gomobile tool to get everything together. It’s great to see how quickly things have improved.

The project itself is named Amadeus. The name is the middle name of Mozart. My code can be found here.