Electrophone Definition: any of a class of musical instruments (such as a synthesizer or electric organ) whose sound is generated electronically.
The basic idea is to create a musical instrument from the computer. When the user touches a button
I suppose this is the second iteration of this very simple program. The first was a pygame experiment when my oldest daughter was still very young. She played it on my crummy HP laptop and looked adorable wearing headphones. I mapped every key on the keyboard to a sound or color change. In some cases whole regions of the keyboard played the same sound. In other cases a single key had to be struck. This meant that mashing the keyboard (as very small children are prone to) would produce a result, but there were also "hidden" things to search for for.
I put this second version together using the kivy library. Actual coding time was probably only a day or two. But I spent a lot more time getting the sound samples just right and then building the android APK. This version was designed for a touch screen so there is no keyboard support. That would make a good next phase though.
Initially I tried using some free samples downloaded from the University of Iowa. But I found many of these to be too quiet, and sustained too long. I tried using Audacity and sox to cut, fade, and amplify the samples. But generally this process increased the noise floor and I just wasn't happy with the result. In the end I decided these samples just weren't going to work.
My second approach was much better. I found that I could make a scale in rosegarden, choose an instrument (lower left) and then export to midi file. Then I used fluidsynth to make a .wav (
fluidsynth -F out.wav /usr/share/sounds/sf2/FluidR3_GM.sf2 input.mid) and load it into Audacity to cut up the notes in separate .ogg files.
sox is a pretty cool command line multitool for audio. For example:
sox -v AMP% trim START END fade IN LEN OUT INFILE OUTFILE
Part of my trouble was I wanted to be able to play all the notes very close together by running my finger across the "keys". Triggering all the samples in a short amount of time tended to create constructive interference and clipping which sounded horrible. I researched general approaches to this kind of mixing but came up dry. In the end I simply made my samples pretty short and quiet and set a minimum time between starting sample playback.
Building an APK
Python is my programming language of choice. I have a lot of experience using it to solve a variety of problems, so I'm quite a bit more productive in it than other languages. Java in particular seems like I get bogged down in the infrastructure so fast that it quits being fun. Since more of programming is for fun. Learning the native Java development environment for Android was a non-starter.
Kivy was wonderful to program in. I has cross platform libraries for almost everything you'd want to do on a phone or tablet and native support on Linux and Windows makes development and testing a breeze. Kivy suggests using buildozer, which is itself a wrapper for p4a for deploying to android. Building a debug apk file and testing it was easy enough.
$ buildozer init $ buildozer -v android debug $ buildozer serve
buildozer is a very clever idea. It looks for all the python modules you used, runs them through cython to generate C code, then compiles that with the android NDK, links the generated libraries into a skeleton Android project and builds it.
Unfortunately given the amount of time I spent trying to build a production apk that google would accept. I might have been better off learning android native development.
First problem was signing the package. Kivy has instructions. Installing the android studio gives access to keytool, which creates the needed certificates. buildozer can sign the package if you tell it where the certs are, which you do by setting certain environmental variables. I created the below script.
1 2 3 4 5 6
#!/bin/bash export P4A_RELEASE_KEYSTORE=/path/to/keystore export P4A_RELEASE_KEYSTORE_PASSWD=[pass] export P4A_RELEASE_KEYALIAS_PASSWD=[pass] export P4A_RELEASE_KEYALIAS=[alias] buildozer -v android release --use-sdk-wrapper
The next problem is that if you target a newer version of the android SDK, which Google requires you to do or it will reject your apk file, buildozer fails to download it. It looks to me like Google's links have changed, or something. I downloaded the SDK and NDK manually using sdkmanager. You use the buildozer.spec file to tell it where to look for the NDK and SDK and which to versions to use.
# (str) Android NDK directory (if empty, it will be automatically downloaded.) android.ndk_path = /home/brian/Android/android-ndk-r17c # (str) Android SDK directory (if empty, it will be automatically downloaded.) android.sdk_path = /home/brian/Android/Sdk # (int) Android API to use android.api = 28 # (int) Minimum API required android.minapi = 21 # (int) Android SDK version to use android.sdk = 28 # (str) Android NDK version to use android.ndk = 17c # (str) python-for-android branch to use, defaults to stable p4a.branch = master
There is a bug in cython and/or p4a that results in errors when buildozer tries to compile kivy. The fix here was to set
p4a.branch = master in buildozer.spec and use a specific version of cython.
pip install -U --force-reinstall Cython==0.25.2
Yes this was getting ridiculous. I get the feeling nobody is putting real production level effort into using kivy/buyildozer. Makes me pretty nervous.
The last hurdle was truly the most mystifying. For a while kivy seemed to target version 19 of the SDK no matter what I did. If I cleared .buildozer and rebuilt I'd get a strange gradle error. Finally based on something I read in a google group I tried:
- using SDK=19 NDK=17c
- buildozer android debug
- rm -rf .buildozer/android/platform/build/dists
- change SDK=28, min SDK=21
- buildozer android debug
At the finally got me an apk file that google wouldn't reject.
The google play console itself is a giant UIX trainwreck. I was extremely confused and while I've found the magic sequence of things you have to do, they are still things that make no sense to me.
I had to first create a "track" and upload an apk. Once that was done the "publish" button was greyed out with no indication why. I googled to discover I needed to setup the store front settings on the left menu first. Doing that allowed me to publish. I was trying to do an internal test track but the opt-in link wouldn't appear. It says it will appear when you publish. But I had already clicked a button labeled "Publish". The only indication that I was waiting for something was in small font under the app name in the drop down which said "Pending publishing". No indication that I should wait for google to review and accept it. Had to search around again to learn that was what was happening.
This was all a learning experience. The app is on the play store. You should try it. I've posted it for free as I don't think anyone would be willing to pay for yet another "turn your phone into a toy for your kids" app. I hope this one is a little different in that it sort of makes it a real instrument and without ads.