Sing loud, sing proud, sing off-key — and then make it better.
MiccDrop is a cross-platform vocal practice app that turns any room into a karaoke booth. The Expo-powered mobile client pairs real-time pitch tracking with synced lyrics, while an Express/Supabase backend streams instrumentals, lyrics, and pitch guides pulled straight from the cloud. The result is a latency-friendly practice loop that lets singers pick a track, perform alongside the instrumental, visualize pitch accuracy, and review a score the moment the song ends.
- 🎤 Dual-auth onboarding – create an account with username/password or use Google Sign-In via
@react-native-google-signin/google-signin. - 🎧 Song discovery – browse Supabase-backed catalogs (Top Picks, Trending, Recents) and use live search via
@rneui/themedto jump into any track. - 🪄 Live lyric + pitch coach – track player fetches karaoke
.lrcfiles, renders them withreact-native-lyric, and overlays real-time pitch graphs driven by@siteed/expo-audio-stream+pitchy. - 🧠 Smart scoring – compares recorded notes against reference CSV pitch curves, penalizing semitone drift and surfacing a normalized score for every performance.
- 📊 Performance recap – post-song summary shows album art, metadata, and the computed score, with a quick path back to explore the catalog again.
- Sign in / create account – hits
/api/v1/signInDefault,/signInWithGoogle, or/createAccounton the server, which wraps Supabase Auth + bcrypt. - Pick a song –
/api/v1/getAllSongsreturns metadata (name, artist, Spotify art) used byapp/songSelector.tsx. - Perform –
trackPlayer.tsxfetches lyrics (/api/v1/getSongWithId), instrumental WAVs (/api/v1/getInstrumental), and pitch guides (/api/v1/getPitch). Live audio chunks are streamed, pitch-checked, and graphed. - Score + review –
scoring.tsxcompares the performance to the reference dataset andresults.tsxfetches display info via/api/v1/getSong.
- Organized under
app/with file-based routes for auth, tabbed navigation, and full-screen experiences (song selector, player, results). - Uses
expo-avfor playback,@siteed/expo-audio-streamfor microphone capture,pitchyfor detection, andreact-native-chart-kitfor the live pitch graph. - Shared UI helpers (gradient buttons, themed text) live in
components/, while hooks handle theming and timers.
server/server.jsexposes REST endpoints for auth, catalog access, and media delivery.- Supabase Database stores
users(credentials) andsongs(metadata + URLs). Bcrypt handles password hashing. - Supabase Storage buckets (
lyrics,instrumentals,pitches) hold karaoke assets. Bootstrapping helpers (linkLyricsToSongs, etc.) map bucket files to DB rows.
spotifyData.jsoncontains sample Spotify metadata used when seeding the catalog.- Lyrics, instrumental WAVs, and pitch CSVs are accessed on-demand through signed URLs rather than bundling large files into the client.
| Layer | Tools |
|---|---|
| UI / Navigation | Expo Router, React Native 0.76, Expo SDK 52, @expo/vector-icons, @rneui/themed |
| Audio / Analysis | expo-av, @siteed/expo-audio-stream, pitchy, react-native-lyric, react-native-chart-kit |
| Auth & Data | Express 4, Supabase JS client, bcrypt, Google Sign-In |
| Tooling | TypeScript, Jest + jest-expo, Expo CLI, Nodemon |
- Node.js ≥ 18 and npm (or Yarn 1.22)
- Xcode + iOS Simulator (macOS) and/or Android Studio/Emulator
- Expo CLI (
npx expo startworks without a global install) - Supabase project with the following resources:
userstable (id,username,email,password)songstable (spotify_id,song_name,artist,images,lyrics_url,instrumental_url,pitch_url)- Storage buckets:
lyrics,instrumentals,pitches
cd Miccdrop
npm installCreate a .env at the project root (loaded by both Expo and the Node server):
| Name | Used by | Description |
|---|---|---|
EXPO_PUBLIC_LOCALHOST |
Expo client | Hostname/IP for the Express server (use your LAN IP, e.g. 192.168.0.42) |
EXPO_PUBLIC_IOS_CLIENT_ID |
Expo client | iOS OAuth client ID for Google Sign-In |
supabaseUrl |
Server | Supabase project URL |
supabaseKEY |
Server | Supabase anon/public key (for user-facing queries) |
supabaseSERVICEKEY |
Server | Supabase service role key (needed to map storage objects) |
When running on a physical device,
EXPO_PUBLIC_LOCALHOSTmust be reachable over the network (nolocalhost).
cd Miccdrop
npx nodemon server/server.js # or: node server/server.jsThe server listens on port 3001 by default. Ensure your Supabase keys are loaded before starting.
# from Miccdrop/
npx expo start # launches the Metro bundler + QR code
npm run android # build & install on Android emulator/device
npm run ios # run on iOS simulator
npm run web # experimental web buildnpm test # runs Jest via jest-expo
npm run lint # Expo lint| Endpoint | Method | Description |
|---|---|---|
/api/v1/signInDefault |
POST | Username/password login (bcrypt-verified) |
/api/v1/signInWithGoogle |
POST | Google Sign-In fallback/creation |
/api/v1/createAccount |
POST | Registers a new user |
/api/v1/getAllSongs |
GET | Returns catalog metadata for the selector |
/api/v1/getSongWithId?id= |
GET | Streams the .lrc lyric file for a song |
/api/v1/getSong |
POST | Returns song name, artist, and artwork |
/api/v1/getInstrumental?id= |
POST | Streams the instrumental WAV |
/api/v1/getPitch?id= |
POST | Streams the reference pitch CSV |
All routes expect the Supabase URL/key env vars to be set and will respond with JSON (or the raw asset) plus standard HTTP status codes.
Miccdrop/
├── app/ # Expo Router routes (auth, tabs, track player, results)
├── assets/ # Logos, gradients, background art, audio placeholders
├── components/ # Shared UI + hooks (timer, controls, themed text)
├── constants/ # Color palette definitions
├── hooks/ # Color scheme + theme helpers
├── server/server.js # Express API + Supabase integration
├── types/ # Shared TypeScript interfaces (e.g., PitchData)
├── spotifyData.json # Sample Spotify metadata
└── scripts/ # Utility scripts (reset-project)
- Microphone audio is sampled at 16 kHz, chunked every 10 ms, and normalized to
Float32Arraybuffers. pitchycomputes frequency + clarity; valid ranges (C2–C6) update the live pitch graph viareact-native-chart-kit.- Reference CSVs (time, pitch, clarity) come from Supabase storage and feed the
PitchGraphoverlay plus the scoring function. app/scoring.tsxconverts both reference and recorded pitches into semitone offsets relative to A4 (440 Hz) and sums the squared difference, yielding a lower-is-better aggregate that is formatted for the results view.
| Command | Description |
|---|---|
npm run start |
Expo dev server (npx expo start) |
npm run android / ios / web |
Platform-specific Expo launches |
npm run reset-project |
Resets the Expo scaffold back to a blank app/ |
npm test |
Jest test runner |
npm run lint |
Expo lint |
- Wire up Supabase Auth tokens instead of manual fetch calls once security hardening is needed.
- Persist performance history per user (the profile page is currently mocked).
- Expand the scoring page to surface the pitch graph and lyric timeline for deeper feedback.
Happy singing! 🎶