DEV Community

Cover image for I built a free Android soundboard that works with a External keyboard
anoop p
anoop p

Posted on • Originally published at anooptube.in

I built a free Android soundboard that works with a External keyboard

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
  • SharedPreferences for 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;
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)