Skip to content

Repository files navigation

RubberRing icon RubberRing

An Android tool for practicing song parts. Pick an audio file, mark a start/stop region on its waveform, and play it back in a seamless, gapless loop — slowed down without changing pitch, and snapped to an editable beat grid. Chain loops into practice arrangements to drill transitions.

Early-stage release — expect rough edges. Feedback and bug reports welcome via Issues.

Screenshots

RubberRing library home and the loop editor with chord lane

Features

  • Import-and-own library — picked files are copied into app-private storage, so loops survive the original being moved or deleted. The library doubles as the home screen, with recents and custom, renameable track titles.
  • Waveform loop editing — drag start/end handles to mark a section; it decodes to PCM and loops via AudioTrack loop points, so the boundary wraps with zero audible gap or click.
  • Editable beat grid — a dependency-free estimator finds BPM and a downbeat, and handles snap to the grid. Refine it by hand at any time: tap the tempo, nudge ±1 BPM, or halve/double it.
  • Pitch-preserving speed — slow down or speed up from 0.5× to 1.5× with a WSOLA time-stretch that keeps the original pitch.
  • Saved loops — capture a region + grid per track, up to ten of them, and drag the chips into the order you practise them.
  • Practice arrangements — chain saved loops into an ordered sequence, each repeated a set number of times and optionally looping the whole set — for drilling A–B–A transitions.
  • English and German — picked in Settings or followed from the device, stored as Android's own per-app language. Chords can optionally use German note names (H and B).
  • Opens audio shared from other apps — via the share sheet or "Open with".
  • Session comforts — System/Light/Dark themes with a theme-aware waveform, follow-playhead auto-scroll, keep-screen-on, library backup & restore, an in-app quick-help sheet, and a short "what's new" note on the first launch after an update. Preferences persist across launches.

Tech stack

  • Language: Kotlin (Java 17 target)
  • UI: Jetpack Compose (Canvas for the waveform, grid, and handles)
  • Build: Android Gradle Plugin 9.2.1 + Gradle 9.5.1 (via wrapper)
  • SDK: minSdk 26 · compile/targetSdk 36
  • Decode: MediaExtractor + MediaCodec → PCM
  • Playback: low-level AudioTrack with sample-accurate loop points
  • Beat detection & time-stretch: custom (WSOLA), no native/NDK or GPL dependencies
  • Async: Kotlin Coroutines + Flow

Building

Requires a JDK (17+) and the Android SDK. Point the build at your SDK by creating a local.properties file in the project root (this file is git-ignored):

sdk.dir=/path/to/Android/Sdk

Then build a debug APK:

./gradlew assembleDebug

The APK lands at app/build/outputs/apk/debug/app-debug.apk; sideload it to a device to run it.

Project layout

app/src/main/java/de/singular/looper/
  MainActivity.kt        Compose entry point
  LooperViewModel.kt     app state, orchestrates decode / detect / play
  audio/
    AudioDecoder.kt      file URI -> PCM + metadata
    LoopPlayer.kt        AudioTrack wrapper: loop points, play/pause/seek
    BeatDetector.kt      tempo + downbeat estimation
    TimeStretch.kt       pitch-preserving WSOLA speed change
    DecodedAudio.kt / WaveformData.kt   PCM + envelope models
  library/
    LibraryRepository.kt import-and-own storage + metadata index
    LibraryTrack.kt / SavedLoop.kt / ArrangementStep.kt
  ui/
    LoopWaveform.kt      waveform + grid + handle rendering

Support

If Rubber Ring is useful to you, you can support its development on Ko-fi. Thank you!

License

GPL-3.0-only — version 3 of the GNU General Public License, and not "or any later version". The full text is in LICENSE, the copyright notice in COPYRIGHT.

Artwork and name

The wordmark and the ring icon are licensed separately, under CC BY 4.0. COPYRIGHT lists the files.

The name is not licensed by either grant — give a fork its own.

Disclaimer(s)

  1. This app is built around my own musical style, particularly the chords and tempi I use. While looping will work regardless of the imported audio, chord and beat detection may not work perfectly for Prog-Polka-Fusion in 7/8.

  2. This project was developed with the assistance of Claude under my direction and functional review. The code has been analysed with Codacy (detekt).

Codacy Badge

Releases

Packages

Contributors

Languages