https://github.com/aleatropy/Flast
A bit-perfect FLAC player for Android. 131 KB installed, no network access, no ads, no accounts, no library scraping, no settings you have to understand before it plays music.
It does one thing: decode a FLAC file and hand the samples to your USB DAC without touching a single bit on the way. It tells you, on screen, whether it actually managed that — and when it didn't, why not.
MUSIC PLAYLISTS CONFIG
──────────────────────────────────────────
ALL TRACKS │ ALBUMS
──────────────────────────────────────────
01. Come On, Come On.flac
02. White Wedding (Pt. 1).flac
03. Hot In The City (Single Version).flac
...
If you don't know what CPU your phone has, take flast-1.0.0-universal.apk.
It works on every Android phone and tablet and costs you about 180 KB more.
There are three different CPU architectures in the Android world, not just "64-bit and 32-bit" — the split is also ARM vs Intel. Phones and tablets are ARM; emulators and a few Chromebooks are Intel.
| File | Which CPU | Which devices |
|---|---|---|
flast-1.0.0-universal.apk |
all three, bundled | anything — pick this if unsure. 300,015 B |
flast-1.0.0-arm64-v8a.apk |
64-bit ARM | almost every phone/tablet since ~2017. 120,722 B |
flast-1.0.0-armeabi-v7a.apk |
32-bit ARM | older and budget phones. Untested — see below. 102,092 B |
flast-1.0.0-x86_64.apk |
64-bit Intel/AMD | Android emulators, some Chromebooks, a few old Intel tablets. 119,623 B |
The universal APK is not a clever binary that runs everywhere. It is a bundle containing all three, and your device picks the one it needs and ignores the other two. That is why it is roughly the size of the three added together. It costs about 179 KB of extra storage and zero extra RAM — Android never loads the copies your CPU cannot run. If you are not certain what is inside your phone, take it; you cannot choose wrong.
- Download the APK from the Releases page.
- Open it. Android will ask you to allow installing from this source — that prompt is normal for any app not from the Play Store.
- Open Flast. It asks for permission to read audio files. Allow it, or the music list stays empty.
- That's it. It scans your storage in the background and the list fills in.
The 32-bit ARM build compiles cleanly and passes every static check, but no one has ever executed it. The development phone is 64-bit only, so there was no way to test it here. It is published because a 32-bit user having something to try is better than nothing — but you are the first person to run that binary, and it may not work. Please report what happens either way.
The arm64-v8a, x86_64 and universal builds are unaffected by this. arm64-v8a is the one that has actually been tested.
Requires Android 8.0 (API 26) or newer. See TRANSPARENCY.md for why that floor exists and why it can't go lower.
Every release is signed with the same key. You can check that an APK really came from this project:
apksigner verify --print-certs flast-1.0.0-universal.apk
The SHA-256 of the signing certificate must be:
743e01c075419ade8c953b83f720e4bdadc9fb8310cbae0ef7b3e2ccc22d084d
If it differs, someone else built that APK. Don't install it.
Read this before deciding whether this app is for you. It is the most important thing on this page.
Flast asks Android for the most direct audio path that exists — AAudio in
EXCLUSIVE mode with an MMAP buffer, which bypasses the system mixer
entirely. When it gets that, the exact bytes in your FLAC file reach your DAC
with no resampling, no mixing, and no volume scaling.
Whether it gets that is not up to this app. It is up to your phone.
Every Android manufacturer writes their own audio HAL, and whether it grants exclusive mode varies by phone model, by chipset, and sometimes by which system audio effects you have switched on. There is no public list of which devices work. Nobody — not us, not Google — can tell you in advance whether yours will.
So Flast does the only honest thing available: it tells you, live, on the player screen.
| What you see | What it means |
|---|---|
BIT-PERFECT: YES |
Exclusive mode granted, MMAP confirmed, and the stream format carries every bit of your file. The audio is untouched. |
BIT-PERFECT: PARTIAL |
Exclusive mode works, but Android's software volume is below maximum and is scaling the samples. Raise the volume to max, or use a DAC with its own volume control. |
BIT-PERFECT: NO |
Something in the chain rules it out — see below. |
The indicator is re-checked continuously, not decided once when the track
started. If something takes the exclusive audio path away mid-track, it
changes to NO while you watch.
Tap the indicator and it tells you exactly which of those applies and why.
NO is not a bug. It means one of:
- your phone's HAL refused exclusive mode (the most common reason);
- you're on Bluetooth, which re-encodes audio by definition and can never be bit-perfect in any app;
- you're on the phone's own speaker or headphone jack rather than a USB DAC;
- the file is deeper than the stream format the device would grant;
- the file's channels or sample rate had to be converted. A 5.1 file
folded down to a stereo DAC is not the file's samples any more, and neither
is 44.1 kHz resampled to 48 kHz. Any up-mix, down-mix or resample means
NO, however good the rest of the chain is.
Flast still plays in all of those cases. It falls back to Android's shared audio path and keeps working — it just refuses to claim something it didn't achieve.
On some Samsung/Exynos devices, MMAP mode combined with factory audio
enhancements (Dolby Atmos and similar) has been reported to produce complete
silence rather than degraded audio. If Flast shows BIT-PERFECT: YES but you
hear nothing, turn off audio enhancements in your system sound settings before
assuming the app is broken.
- Plays FLAC. Nothing else — no MP3, no Ogg, no WAV.
- Scans all your storage, internal and SD card, for
.flacfiles. It does not require a folder called "Music". - Browses by track or by album folder. Multi-disc sets (
Disc 1,CD 2, …) collapse into the one album they belong to. - Playlists, stored as plain text files you can read and edit yourself.
- Play / pause / next / previous. Long-press a track to add it to a playlist.
- Keeps playing in the background with a notification.
- Two themes (black or white) and four font sizes.
Each of these is a decision, not a missing feature:
- No equalizer, no DSP, no "enhancements". Every processing stage is a chance to break bit-perfect. If you want EQ, this is not your app — and that's fine, Poweramp and Neutron are good at it.
- No internet access. The app holds no
INTERNETpermission at all. You can verify that inAndroidManifest.xml— there is nothing to trust us about. - No album art, no artist/album tags. Tracks are shown by filename and grouped by folder. See TRANSPARENCY.md.
- No software volume control inside the app. Attenuating digitally would silently break the thing the app exists for.
- No crossfade and no seek bar. Nor true gapless: the gap between two tracks of an album is about 10 ms, not zero. Sample-exact gapless would mean decoding the next track into the same buffer before the current one ends, and the accounting that requires — which track does the sample now leaving the buffer belong to? — is not worth the risk to a player whose entire job is not corrupting the samples. A listener can still hear the seam on an album written to run continuously, and how large it is depends on your storage speed and your device's audio HAL, so it may well be bigger on your phone than the figure measured below. If you need a genuinely seamless album, this is not the player for it, and saying otherwise would be a lie.
- No accounts, no telemetry, no analytics, no crash reporting.
| Permission | Why |
|---|---|
READ_MEDIA_AUDIO (Android 13+)READ_EXTERNAL_STORAGE (Android 8–12) |
To find and read your FLAC files. Without it the library is empty. |
FOREGROUND_SERVICEFOREGROUND_SERVICE_MEDIA_PLAYBACK |
So music keeps playing when you leave the app. Android requires a foreground service for this. |
POST_NOTIFICATIONS (Android 13+) |
The foreground service must show a notification. Android requires the permission to display it. |
That is the complete list. No internet, no location, no contacts, no "all files access".
From a Galaxy A55 (Android 16) with a 658-track library on an SD card and an XMOS USB DAC. These are measurements, not estimates:
| APK | 120,722 B (arm64) · 102,092 B (armeabi-v7a) · 300,015 B (universal) |
| Installed on device | 131 KB |
| Scan cache for 658 tracks | 30,045 B |
| RAM in use | ~15–20 MB |
| CPU, 44.1 kHz/16-bit bit-perfect | 18.9% of one core (≈2.4% of an 8-core phone) |
| CPU, 96 kHz/24-bit bit-perfect | 19.96% of one core |
| CPU, same file in non-bit-perfect SHARED mode | 8.80% of one core |
| Library scan | 658 files across 2 volumes in 254 ms |
| Silence between two tracks of an album | 7–10 ms — device-dependent, see above |
Roughly 14 of those 19 CPU points are Android's own low-latency MMAP audio path, not FLAC decoding — decoding is about 4%.
Bit-perfect costs battery, and here is the measurement rather than a hand-wave. Same build, same 96/24 file, only the audio mode forced:
| CPU | Wakeups | |
|---|---|---|
| SHARED (not bit-perfect) | 8.80% of a core | 151/s |
| EXCLUSIVE (bit-perfect) | 19.96% of a core | 578/s |
2.3× the CPU and 3.8× the wakeups. That is the real price of an untouched signal path, and it is not something the app can optimise away — the exclusive path is required to be low-latency, which means waking hundreds of times a second by design. See TRANSPARENCY.md.
We can't test every device, so COMPATIBILITY.md is
community-maintained. If you try Flast, please add a line — a NO report is
just as useful as a YES.
Needs JDK 17, the Android SDK, and NDK 27.0.12077973.
git clone https://github.com/aleatropy/Flast.git
cd flast
./gradlew assembleRelease
Unsigned APKs land in app/build/outputs/apk/release/. To sign them, copy
keystore/keystore.properties.example to keystore/keystore.properties and
fill in your own key — the project's release key is not in this repository and
never will be.
There is a host test suite for the parts where a bug would be silent — the
storage scanner, the renderer, and the lock-free audio ring buffer. It needs
only gcc and python3, no SDK and no device:
./tools/tests/run.sh
It compiles the shipped source (two suites extract their functions verbatim
from ui_main.c and flac_stream.c at runtime) and runs it under
AddressSanitizer, UndefinedBehaviorSanitizer and ThreadSanitizer.
See CONTRIBUTING.md before opening a pull request — this project rejects features on purpose, and it's only fair to say so up front.
Flast is GPL-3.0-or-later. See LICENSE.
In short: you may use, study, modify and redistribute it, and anything you distribute that is built from this code must also be free software under the same terms.
It bundles libFLAC 1.4.3 (decoder only), which is BSD-3-Clause from the
Xiph.Org Foundation — see
COPYING.Xiph. That
licence is compatible with the GPL, and libFLAC's copyright notices are
retained in this repository as it requires.
The embedded bitmap font is an 8×16 monospace glyph set generated at build
preparation time from a terminal font; see
ui_font_spleen8x16.c.