Rewamp is the successor to Modizer, a demoscene and retrogaming oriented music player that was limited to iOS devices.
It is multiplatform, with a focus on MacOS/iOS/Android as primary targets and Linux/Windows as secondary ones.
Development of Rewamp involves AI usage, mostly as an accelerator to develop the UI part and some of the backend features. Several playback engines customization are reusing the work I've done previously for Modizer.
- 1248 file extensions, 45 decoding engines — Amiga MOD, C64 SID, NSF, SPC, GBS, PSF, VGM, SNDH, ZX Spectrum AY, PC-98, X68000, game streams (Wwise, FSB…). Real chip emulation, not renderings: a 6502 runs the NSF driver, a 68000 runs the Amiga replayers.
- Subsongs are first-class. A
.nsf,.gbs,.sidor.sndhexpands into its tracks, named with what the file itself carries — NSFe track labels, HVSC's STIL, the UADE song database — rather than numbers. - Seven visualizers: stereo oscilloscope, per-voice oscilloscope, spectrum, live notation, a piano keyboard, the tracker's own pattern grid, and Milkdrop presets through projectM. All GPU-rendered, and fed with what you are hearing.
- Per-voice control: mute or solo a single chip channel while it plays, and watch each one's waveform and note.
- Playback speed from 0.2× to 3×. Most engines change the tempo and keep the pitch — the speed-up happens in the song's own sequencer or in the emulated machine, not in the audio stream; the others resample.
- Gapless playback, with an optional crossfade.
- System media controls everywhere: Now Playing on iOS and macOS, the media notification on Android, MPRIS on Linux, the media overlay and media keys on Windows.
- Queue with shuffle and repeat, playlists, favourites, listening statistics, and a library that survives a reinstall.
- Optional online catalogue — browse and stream a large preservation archive with artwork, demoscene productions and per-subsong lengths. Local playback needs no server at all.
- Plays archives (zip/7z/rar/lha) in place, follows an M3U found inside one, and takes files dropped on the window or opened from the file manager.
- 18 languages.
| Platform | Minimum | Status |
|---|---|---|
| iOS | 15.0 | Primary target — beta on TestFlight |
| Android | 8.0 (API 26) | Primary target — beta on the Play internal track |
| macOS | 13.0 (Ventura) | Primary target — beta as a notarized DMG |
| Linux | glibc 2.35 (Ubuntu 22.04, Debian 12) | Released as an AppImage, x86_64 and aarch64 — see Releases |
| Windows | 10, x64 | Released as a portable zip — see Releases |
Android ships 64-bit only (arm64-v8a, x86_64). A 32-bit build links and
runs but silently loses the formats whose codec goes through
FFmpeg, and only
32-bit-only devices — pre-2018, low end — would ever have received it.
These floors come from what the engine needs, not from taste: API 26 is where
AAudio arrives on Android, and the Apple versions are what the GLES visualizer
stack and the Flutter toolchain require. The Linux floor is the glibc of the
container the AppImage is built in (see .github/workflows/appimage.yml).
The AppImage needs fusermount3 and /dev/fuse, present on any modern
desktop — not libfuse2, its runtime is statically linked. If mounting
fails anyway: ./Rewamp-*.AppImage --appimage-extract && ./squashfs-root/AppRun
(--appimage-extract-run does not exist in this runtime). Audio goes through
PulseAudio/PipeWire: libpulse0 must be installed, or everything runs and
nothing plays. On an X11 session the visualizers use a CPU read-back path,
slower than the Wayland one but complete.
The Windows zip needs no installer: unpack it anywhere and run rewamp.exe
(the Visual C++ runtime travels with it). It is not code-signed yet, so
SmartScreen warns on the first launch. Every engine is built, and the
visualizers and projectM run on a bundled ANGLE
over OpenGL. Demoscene production videos are not available there yet: the
embedded web view has no Windows implementation.
Flutter for the UI, C/C++ for everything that makes sound, joined by FFI. miniaudio drives the output device.
- A decoder is a plugin. Each engine exposes one vtable —
probe / open / read / seek / length / close— and the registry picks a winner per file by scoring extension and header, so a format recognised by its magic beats one merely claimed by a generic suffix. The core itself knows no formats. - Decoding never runs in the audio callback. A dedicated producer thread, in the realtime scheduling band, keeps a ring buffer filled; the callback only pops and copies. Audio is immune to UI load by construction rather than by politeness.
- Oscilloscope data is timestamped, not sampled. Chip cores write per-voice samples as a side effect of decoding, keyed by absolute frame; the visualizers read at the consumer position. That is what keeps the picture matching the sound under a two-second look-ahead.
- Visualizers are native GL (GLES 3.0) shared across platforms:
ANGLE over
Metal on macOS/iOS behind a Flutter
texture, a
SurfaceViewon Android, an EGLImage shared with GTK on Linux (a CPU read-back path under X11), and our own ANGLE build on Windows. - The engine is built twice from one source set — CocoaPods podspecs on Apple, CMake for Android, Linux and Windows. Keeping the two in step is a standing constraint of the project.
- Library, playlists and history live in a local SQLite database. The online catalogue is a set of HTTPS RPCs, and the app is fully usable without it.
Flutter 3.41 or newer (Dart 3; the Linux CI builds with 3.47.5, the Windows CI with 3.47.6). Then, per platform: Xcode for macOS/iOS, the Android SDK + NDK for Android, Visual Studio 2022 or newer with the Desktop development with C++ workload for Windows (CMake and Ninja come with it), and on Linux:
sudo apt install clang cmake ninja-build pkg-config \
libgtk-3-dev libegl1-mesa-dev libgles2-mesa-dev \
libasound2-dev libsecret-1-dev libbz2-dev \
libavcodec-dev libavformat-dev libavutil-dev libswresample-dev
sudo apt install libpulse0 # runtime, see belowTwo of these hide their absence. The FFmpeg -dev packages: without them the
build succeeds and vgmstream silently loses every format whose codec goes
through FFmpeg (Vorbis, Opus, AAC, ATRAC3, WMA, XMA…) — CMake picks the
system FFmpeg up through pkg-config, or a prebuilt one through
REWAMP_FFMPEG_DIR. And libpulse0 at runtime: no -dev package pulls
it in and miniaudio only dlopens it, so without it everything compiles, the
app starts, and nothing plays. On Ubuntu 22.04 the stock clang is 14 and is
not enough: install clang-15 (in the distribution's repositories) and select
it with update-alternatives, as the CI does.
git clone --recurse-submodules https://github.com/yoyofr/rewamp-app.git
cd rewamp-appOn Windows, switch Git to LF first — git config --global core.autocrlf false, before cloning. With Git for Windows' default (true) the patch
files of step 2 are checked out with CRLF line endings and
sync_vgmstream.sh fails with a conflict, which looks like a stale patch and
is not.
Three decoders are git submodules pinned to genuine upstream commits
(libopenmpt,
vgmstream,
libvgm). If you already cloned
without them:
git submodule update --init --recursive.
The submodules point at unmodified upstream. Rewamp's changes to them live
in packages/rewamp_audio/patches/ and are applied as working-tree changes:
cd packages/rewamp_audio
./scripts/sync_libopenmpt.sh
./scripts/sync_vgmstream.sh
./scripts/sync_libvgm.sh(On Windows, run them from Git Bash.) A later git submodule update resets
the submodules to upstream and erases the patches: run the three scripts
again after it.
Skipping this compiles fine and misbehaves quietly — no Wwise Vorbis in vgmstream, XM modules with a broken 16-bit tempo, missing per-voice capture in libvgm. The other vendored engines are committed already patched; only these three need the step.
./setup.sh # regenerates the Runner glue, leaves hand-written code aloneApple and Windows. None of these are committed (they are large binaries). On Apple each release script checks for them, because the failure otherwise surfaces as an unrelated link error:
cd packages/rewamp_audio
./scripts/build_angle_macos.sh # or build_angle_ios.sh — offscreen GLES for the visualizers
./scripts/build_libopenmpt_macos.sh # or _ios.sh
./scripts/build_vgmstream_macos.sh # or _ios.shRebuild the libopenmpt/vgmstream ones after any patch change: a plain
flutter build links the previous .a and will not see it.
On Windows, once per checkout, from a PowerShell prompt (both go through the vcpkg that ships with Visual Studio — nothing to install, network required):
powershell -File packages/rewamp_audio/scripts/build_angle_windows.ps1 # GLES for the visualizers
powershell -File packages/rewamp_audio/scripts/build_ffmpeg_windows.ps1 # minimal FFmpeg for vgmstreamWithout them the CMake configuration stops on purpose; set
REWAMP_WINDOWS_VIZ=0 or REWAMP_ALLOW_NO_FFMPEG=1 to build without the
visualizers or without FFmpeg. One more Windows trap: a plugin fetches
CppWinRT through NuGet, and a %APPDATA%\NuGet\NuGet.Config that declares
no package source fails with primarySources while blaming the package — add
https://api.nuget.org/v3/index.json as a source.
Android and Linux build every decoder from source through CMake — nothing to prebuild.
cd app
flutter pub get
cd macos && pod install && cd .. # Apple only, and AFTER pub get
flutter run -d macos # or: -d ios, -d android, -d linux, -d windowsThe manual pod install is required on Apple: the Podfile reads the ephemeral
xcconfig that flutter pub get generates. flutter clean wipes it, so run
flutter pub get again before the next pod install.
The catalogue, artwork and account features talk to a server. A build made
here defaults to the project's own instance, https://api.rewamp.app, which is
what the published binaries are built against. Point a build at your own server
instead:
flutter run --dart-define=REWAMP_API_URL=https://your-instanceThat server is run for the published app, not as a public API: treat it as something that may rate-limit, change shape or require an authenticated client without notice. A fork meant for other people should host its own.
Local playback of your own files needs no server at all — the catalogue is entirely optional.
Every decoder is on by default and gated by a flag; set one to 0 to leave it
out:
REWAMP_WITH_OPENMPT=0 flutter build macosThe environment variable works the same way for the CMake builds (Android,
Linux, Windows); a -D on the CMake command line takes precedence.
The prebuilt ffmpeg-kit slices for Android are not redistributed here.
Without them vgmstream builds without FFmpeg and loses the formats whose codec
goes through it; everything else is unaffected. Drop your own under
packages/rewamp_audio/third_party/ffmpeg-kit/android-{arm64,x86_64}/ffmpeg/,
or point CMake at a build with REWAMP_FFMPEG_DIR (environment or -D). On
Linux the system FFmpeg is found through pkg-config instead, and the
AppImage carries its own minimal build (scripts/appimage/build_ffmpeg_minimal.sh).
On Windows, build_ffmpeg_windows.ps1 (step 4) builds it.
Lines of code (cloc, comments and blank lines excluded), Rewamp's own code
apart from the engines and libraries it bundles. Recomputed at every snapshot.
[ LANGUAGES BREAKDOWN — lines of code ]
Rewamp Bundled Total
C 10,715 1,820,271 1,830,986
C/C++ Header 2,100 1,347,667 1,349,767
C++ 22,221 994,836 1,017,057
Dart 87,440 0 87,440
Assembly 0 36,627 36,627
Objective-C++ 767 3,044 3,811
GLSL 362 989 1,351
Swift 777 0 777
Kotlin 672 0 672
Objective-C 26 0 26
Others 8,911 262,355 271,266
TOTAL 133,991 4,465,789 4,599,780
Rewamp is GPL-3.0-or-later. The app's own code could be more permissive, but the binary statically links GPL-3 decoders (ZXTune, sc68, vio2sf), so the whole is GPL-3.
Every bundled engine and library keeps its own licence and authors — see THIRD-PARTY-NOTICES.md, generated from the same list the app shows under Settings → About.
Some licences ask for a visible credit; those appear in the app itself: SunVox (© Alexander Zolotov · WarmPlace.ru), the UADE song database (CC BY-NC-SA), Milkwave's transition patterns (BSD-3), and Jan Mróz's spectrum shader (CC BY 3.0).
UnRAR is included for solid RAR/RSN
archives under its own licence: its source
"may be used in any software to handle RAR archives without limitations free of
charge, but cannot be used to develop RAR (WinRAR) compatible archiver and to
re-create RAR compression algorithm, which is proprietary" — full text in
packages/rewamp_audio/third_party/unrar/license.txt.