Multitrax is a Flutter + self-hosted Supabase MVP for async multitrack recording and collaboration.
The core loop is intentionally simple:
- sync latest song state,
- record or redo locally,
- submit a take,
- render a new mix,
- export when ready.
An async song session is a repeated workflow where every submission can trigger a new render, then collaborators sync and continue.
flowchart TD
syncLatest[SyncLatestState] --> recordTake[RecordTake]
recordTake --> redoOrSubmit[RedoOrSubmit]
redoOrSubmit -->|Redo| recordTake
redoOrSubmit -->|Submit| uploadTake[UploadTake]
uploadTake --> enqueueRender[EnqueueRenderJob]
enqueueRender --> workerRender[WorkerRenderMix]
workerRender --> mixReady[MixReady]
mixReady --> syncLatest
mixReady --> optionalExport[OptionalExportMP3orWAV]
-
Start local Supabase:
npx supabase start
-
Run migration smoke checks:
./scripts/test_supabase_migration.sh
-
Run the Flutter app (development flavor):
cd apps/multitrax_app flutter pub get flutter run --flavor development -t lib/main_development.dart \ --dart-define=SUPABASE_URL=http://127.0.0.1:54321 \ --dart-define=SUPABASE_ANON_KEY=<supabase-anon-key>
-
Start the audio worker (from repo root):
docker build -t multitrax-audio-worker services/audio_worker docker run --rm \ -e DATABASE_URL="postgresql://postgres:[email protected]:54322/postgres" \ -e SUPABASE_URL="http://host.docker.internal:54321" \ -e SUPABASE_SERVICE_ROLE_KEY="<supabase-service-role-key>" \ -e POLL_INTERVAL_SECONDS=3 \ -e RECONNECT_BACKOFF_SECONDS=3 \ -e LOCK_TIMEOUT_SECONDS=120 \ -e MAX_JOB_ATTEMPTS=3 \ multitrax-audio-worker
Song: collaboration unit with 16 fixed track slots.Take: immutable uploaded audio for one track slot.MixVersion: rendered guide mix from current selected takes.RenderJob: worker task to produce a new mix.ExportJob: worker task to generate MP3/WAV from current mix.SubmissionId: idempotency key for robust take submission.PlaybackModule: track playback, waveform, scrub, and play-all behavior.
flowchart LR
flutterApp[FlutterApp] --> supabaseApi[SupabaseAuthAndPostgres]
flutterApp --> supabaseStorage[SupabaseStorage]
flutterApp --> renderJobs[RenderJobsTable]
renderJobs --> audioWorker[AudioWorkerFFmpeg]
audioWorker --> supabaseStorage
audioWorker --> mixVersions[MixVersionsTable]
flutterApp --> exportJobs[ExportJobsTable]
exportJobs --> audioWorker
- Flutter app composition and providers live under
apps/multitrax_app/lib/app. - Supabase client, repositories, cache stores, and services are wired at app startup.
SongDetailCubitowns sync, recording, submit, retry, and export-request transitions.- Sync + submit operations are network-safe and designed for eventual consistency.
- Supabase tables model songs, members, slots, takes, mixes, render jobs, and export jobs.
- RLS policies enforce owner/editor/listener permissions per song.
- RPC
submit_take_and_enqueue_renderkeeps submission + render enqueue atomic.
- Python worker polls
render_jobsandexport_jobs. - FFmpeg mixes selected takes and generates MP3/WAV exports.
- Worker reclaims stale jobs and marks exhausted retries as failed.
- Dedicated playback module in
apps/multitrax_app/lib/playback. - Per-track playback, play-all selection, waveform visualization, and scrub controls.
- Session-local play-all track inclusion avoids heavy in-flight player churn.
- Upload retry/backoff with persistent queue.
- Idempotent submission keys to prevent duplicate writes.
- Test coverage for cubits, repository behavior, navigation, and playback interactions.
apps/multitrax_appFlutter app (iOS/Android/macOS)supabaselocal stack config, migrations, and seed dataservices/audio_workerDockerized FFmpeg worker servicescriptsmigration smoke test and local helper scriptsdocsarchitecture and implementation notes
App runtime:
SUPABASE_URLSUPABASE_ANON_KEY
Worker runtime:
DATABASE_URLSUPABASE_URLSUPABASE_SERVICE_ROLE_KEYPOLL_INTERVAL_SECONDSRECONNECT_BACKOFF_SECONDSLOCK_TIMEOUT_SECONDSMAX_JOB_ATTEMPTS
Flutter checks:
cd apps/multitrax_app
flutter analyze
flutter testWorker smoke test:
cd ../..
python3 -m unittest services/audio_worker/tests/test_ffmpeg_pipeline.pyUseful Flutter run targets:
# iOS simulator/device
flutter run --flavor development -t lib/main_development.dart -d ios \
--dart-define=SUPABASE_URL=http://127.0.0.1:54321 \
--dart-define=SUPABASE_ANON_KEY=<supabase-anon-key>
# macOS
flutter run --flavor development -t lib/main_development.dart -d macos \
--dart-define=SUPABASE_URL=http://127.0.0.1:54321 \
--dart-define=SUPABASE_ANON_KEY=<supabase-anon-key>- Collaboration is async-only for this MVP.
- Exports require a rendered current mix to exist.
- Songs use 16 fixed track slots.
- Play-all timing is near-simultaneous, not sample-accurate DAW sync.
- License: MIT
- Author: Jeff Higham
- Repository: https://github.com/jeffhigham-f3/multitrax
