Skip to content

Latest commit

 

History

History
44 lines (24 loc) · 5.35 KB

File metadata and controls

44 lines (24 loc) · 5.35 KB

Melodair

Inspiration

Singing is one of the only health interventions people already do for fun — in the car, in the shower, at karaoke, badly and happily. It's tied to sharper memory, and it's used in dementia care because a song can outlast almost every other memory. It's also doing something very physical: it trains the same long, controlled exhale that pulmonary rehab is built around, from COPD to long-COVID breathlessness.

Every karaoke app grades the wrong thing, though. They score pitch — how close you got to the note — and ignore what's actually doing the work underneath: your breath. Pitch is decoration. Breath is the muscle.

We flipped it: what if the score was the breath?

What it does

Melodair is a sing-along app where the thing you're actually scored on is breath control, not vocal accuracy.

You pick a song, sing along, and hold the sustained note at the end of each line — the moment songs already ask you to hold anyway. Under the hood that's a Maximum Phonation Time test, dressed up as something you'd actually want to do.

After each session you get:

  • A Breath Score (0–100): half how close your longest hold came to your personal baseline, half how steady your breath was across the phrases you attempted. No hidden weighting.
  • The Ridge: a real-time visualization of your exhale, drawn as receding mountain terrain rather than a waveform or level meter — so it reads as a landscape, never a pass/fail signal.
  • A Sigil: a small generative seal drawn deterministically from that session's own numbers. Same input, same seal, forever — the image is the data, not a decoration of it.
  • A running sense of whether you're getting steadier session to session, plus a flock of companion birds that evolve as your streak of strong sessions grows.

It's built for anyone working on breath control — a singer doing warmups, someone managing a lung condition like COPD, or anyone who just wants their breath capacity as a number that moves.

Promising, not prescribed: this is breath practice, not a medical device. The "why this helps" framing is grounded in a 2025 SINFONIA randomized controlled trial (101 people with COPD or interstitial lung disease, 12 weeks of group singing, measurable quality-of-life gains) and a 2017 Cochrane review that rates the overall evidence low-to-very-low. Both the in-app card and the AI coach read from the same source file, so neither can say something more confident than the other.

How we built it

Melodair is a single Flutter/Dart codebase (iOS + Android), layered so the dependency arrow only points inward — presentation → domain ← data — with the scoring engine and sigil generator depending on nothing but dart:math.

Audio pipeline. The record package streams raw PCM off the mic at 48kHz; a pure-Dart frame builder turns that into ~60Hz frames, calibrating a noise floor per room (75th percentile of a half-second of silence) and applying onset/release hysteresis — 12dB above the floor to start a phrase, 250ms of quiet to end one — so a wobble in a note is never mistaken for running out of breath. Echo cancellation, noise suppression, and automatic gain control are switched off deliberately: AGC would flatten the very amplitude decay the app is trying to measure. just_audio plays the backing track through one shared audio_session (configured once at startup for simultaneous playback and capture), so accompaniment never tears down the mic mid-session.

Scoring. The Breath Score is pure Dart with no Flutter or plugin imports, so the same take always produces the same score and the logic could move server-side unchanged. It's deliberately a one-sentence formula: 50% how close the longest hold came to a personal baseline (from a maximum-phonation-time calibration), 50% mean steadiness (pitch and amplitude jitter) across attempted phrases.

The Ridge. A custom-painted terrain, not a waveform: the same amplitude envelope is rendered at several smoothing levels as receding depth planes, with Catmull-Rom smoothing and a centered moving average, so a live 60Hz mic feed and a stored 10Hz take render through the exact same code path.

Sigils. A deterministic generative seal (seeded PRNG) built from exactly six take parameters — longest hold sets size, decay slope sets line weight, steadiness sets edge quality, phrase count sets ring count, the song's motif sets hue, and a personal record adds one gold mark.

State & architecture. flutter_bloc Cubits, one per feature, provided at the route rather than the app root — so leaving the sing screen is what releases the microphone. go_router for navigation. Constructor-based dependency injection from a single composition root, no service locator, no globals. shared_preferences stands in for a backend during the demo, with every repository behind a build flag that swaps mocks for a real HTTP client.

AI coach. An optional GPT-4o-mini call turns a take's real numbers into a short, warm reflection — and fails soft to a local templated sentence if no API key is configured, so the feature is pure upside. It's fed the same research citations that back the in-app "why this helps" card, so the two can never contradict each other.

Testing. flutter_test against deterministic, hand-synthesized audio fixtures (steady, ragged, fading, and short holds), so the scoring and calibration logic can be verified without a live microphone.