A few months ago I needed a simple soundboard for a live session. I wanted to trigger audio clips from a Bluetooth/External keyboard connected to my Android phone - just press a key, hear the sound, instantly.
Every app I found was either subscription-based, required an account, or didn't support physical keyboards at all. So I built CTunes.
What CTunes does
CTunes maps keyboard keys (A-Z and 0-9) to audio files on your device. Tap the on-screen button or press the physical key — the sound plays immediately.
That's the whole pitch. 36 keys. Any audio file. Zero lag.
Try it
I'd love feedback — especially from anyone who uses soundboards for live performance, streaming, or teaching. What features would make this more useful for your workflow?
Core features
- Key mapping — pick any audio file from your device and assign it to a key
- Dual input — works with on-screen taps and physical Bluetooth keyboards
- 18-color palette — each key gets a unique color so you can read the board at a glance
- Import / Export — your entire layout serialises to a single JSON file
-
Persistent storage — mappings survive reboots and reinstalls via SQLite +
takePersistableUriPermission() - Free — ad-supported, no subscription, no sign-in, works fully offline
The tech stack
CTunes is a native Android app written in Java (yes, Java — not Kotlin). Here's how the main pieces fit together:
Architecture
- Single-module project, Activities only
- No Fragments, no Navigation component
- SQLite via a hand-rolled
SQLiteOpenHelper -
SharedPreferencesfor UI settings (grid size, column count, keyboard visibility)
Audio playback
java
// A new MediaPlayer is created per keypress
// The previous one is released first to avoid leaks
if (currentPlayer != null) {
currentPlayer.release();
}
MediaPlayer mp = MediaPlayer.create(this, uri);
if (mp != null) {
mp.setOnCompletionListener(MediaPlayer::release);
mp.start();
currentPlayer = mp;
}
Top comments (4)
Nice project! The single-activity architecture keeps things clean. I play guitar and I could see using something like this to trigger backing tracks or metronome clicks during practice without fumbling around on screen.
Curious - does it support looping an audio file? Like if I wanted a drum loop running continuously while I play over it. Also, how does it handle longer files (30s+)? Creating a new MediaPlayer per keypress makes total sense for short samples but wondering about the memory behavior with bigger files.
Hi @jakemoreno_dev
I’ve actually just pushed an update that adds looping support 🎉
So you can now run a drum loop or backing track continuously while playing over it.
Google Play
Hi @jakemoreno_dev
Thanks for the kind words and the great use case - backing tracks and metronome clicks during practice is exactly the kind of thing this was built for!
To answer your questions :
Looping - not supported yet, but it's on the roadmap and coming in the next update. The plan is toggle behaviour so pressing the key again stops it instead of restarting.
Longer files - the app only keeps one audio track alive at a time, so pressing any key interrupts whatever is currently playing. For a 30s backing track that means an abrupt cut if you accidentally tap another key. That's a known limitation I plan to address soon.
Multiple sounds - I've been thinking about supporting up to 5 simultaneous sounds, but there are a few edge cases to get right first:
what happens when you hit a 6th sound, whether a looping backing track should stay running while you trigger one-shots on top, what pressing the same key twice should do, and making sure everything cleans up properly when a call comes in or you switch apps.
Once those decisions are made the implementation is straightforward, but I want to get the behaviour right before shipping it.
Hi Anoop, Sweet project!
I actually play in a band and I was looking for a simple interface to use my phone as a sample triggering mechanism to add a little bit of fun on stage.
Currently I'm working on doing some samples for us to be able to cover "Faint" by Linkin Park but there are a few issues with how it works for me.
I have a very short synth stab sound I want to play multiple times really fast (you can hear it in the song at about 1:27) but when I tap multiple times in succession I notice that the sounds do not feel like they play instantly. Between a tap and sound coming out is a delay of around 3-400ms. This happens both when my phone is connected via USB as well as just playing directly through the speaker. It's not a huge deal for longer song intro samples but it causes an issue for tight sounds that I want to play multiple times.
Additionally the stab has a reverb / delay trail that I want to keep but tapping it a second time cancels the first playback. I know you are probably addressing this with what you mentioned about multiple sounds but wanted to bring it up again.
Lastly, a small bug is that the stop music and loop buttons are covered by the android navigation buttons on my phone so they are quite difficult to press.
I'll be keeping an eye on this project, nice work so far