Saturday, December 21, 2013
Updated the Tuning Fork Android App
After about a year and a half I finally updated the tuning fork android app.
This app started as a high quality signal generator for electronics. I learned how to create precise high quality sine waves from the audio player. In order to make something out of my efforts, I published it as a musical instrument tuning program.
Users had been complaining that the sliders I used to set pitch and note were finicky, and they were right. Also my Java skills are 10X what they were when I wrote it, so I wanted to fix some things.
Since I have a new PC since I did the original Android work, I had to resurrect my Android/Eclipse setup, my keystore, and get adb usb connection working with my current Samsung phone (a whole post unto itself) as well get the drivers working with my old droids.
I converted the sliders to buttons to increment and decrement the tone and pitch. I'm pretty happy with that. If you want to change the pitch by a lot, it gets a little tedious pushing the button. But for reasonable changes it is good and you can easily change it to whatever value you want.
I added some common pitch and tone combos that musicians use as presets on a drop down menu.
Finally I added a save favorite button that allows you to remember a setting and recall it. Android has the ability through SharedPreferences to save a small amount of data without requiring any user permissions. I didn't want to make this simple app ask for any permissions from the user.
I also added a real help screen, not just a toast and fixed the menus to navigate back and forth logically. onBackPressed() takes you back to the main screen, pressing it again stops the app.
I published the app at that point, version 1.3, just to make sure my keystore and google acount process still worked. I didn't want to spend forever on this and find I couldn't update the app.
After that I tackled an annoying issue that was even more obvious when the app was changing notes via the buttons. Each note change often resulted in a click, then a warble, and then the new tone would play perfectly.
I first thought the audio player wasn't starting and stopping smoothly, but I ruled that out. Then I realized I was doing non thread safe updating of the tone array. When the app is going to play a tone, it calculates the sine waveform and sets the length of the buffer to exactly the correct repeat so there is no glitch. That was fundamental to the original design, to play a continuous frequency accurate tone without glitches. The audio player runs in a child thread (activity) so that it doesn't block the UI. However when the tone changed, the sound array had to be recalculated by the main thread. Often the audio thread, while looping, would pick up the array half way through that process. The result was a click and warble.
First I tried synchronizing the tone array variable, and various methods of synchronizing a function wrapped around updating this variable to prevent it being read by the player thread while it was being written. This was a disaster. Problem is, the way synchronization works, is it blocks a thread until the desired variable is not busy. The end result was the user UI thread was being blocked by the looping audio thread, which never gave the UI a chance to update the array. While this seems solvable it led to a lot of bad behavior by the app.
Finally I realized I should move the array updating functions into the audio thread. The block of code that calculates the sine wave array is in the audio loop, but only conditionally runs when the desired note is changed. Only the desired note and pitch is passed from the main to the audio thread. This is much better because all the calculating and array filling which took time is not on the thread boundary. Only a simple variable pass is needed.
The result is version 1.4, which smoothly changes notes when the buttons are pressed. Hooray! Enjoy.
Posted by siliconfish at 10:45 AM