Initial commit: InTono — app KMP per l'apprendimento musicale

App Kotlin Multiplatform (Android/iOS/Desktop) con Compose Multiplatform:
controllo intonazione (YIN), pratica guidata, metronomo, ear training,
sfide, scansione spartiti via AI, spartiti bundled e pentagramma con
glifi tipografici, travature, battute e spaziatura proporzionale.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
lucianoandClaude Fable 5 committed 2026-07-22 10:06:59 +02:00
commit 21ad969b10
245 files changed
+28963

No files matched your search

@@ -0,0 +1,71 @@
# Design: rendering avanzato del pentagramma (InTono)
Data: 2026-07-22 — Approccio approvato: **disegno raffinato su Canvas** (nessun font musicale embedded).
## Obiettivo
Migliorare la resa delle note sul pentagramma nelle viste Compose condivise con quattro upgrade approvati dall'utente:
1. **Glifi raffinati** — teste "a pera" (`Path`), code curve riempite, ♯/♭ ben proporzionati, chiave a piena opacità e dimensione maggiore.
2. **Travature (beam)** — crome/semicrome consecutive nello stesso beat unite da parallelogrammi inclinati.
3. **Battute** — stanghette e cifre del tempo (es. 4/4) dopo la chiave.
4. **Spaziatura proporzionale** — larghezza orizzontale ∝ √(durata in quarti).
Non-obiettivi: font SMuFL/Bravura (rimandabile senza rework: la geometria resta valida), pause, legature di portamento, chiavi miste nello stesso rigo, gambi condivisi tra righi.
## Architettura
### 1. `StaffLayout` (esteso) — geometria pura, `commonMain`, testabile
- `quarterUnits(duration: NoteDuration): Double` — WHOLE=4, HALF=2, QUARTER=1, EIGHTH=0.5, SIXTEENTH=0.25, THIRTY_SECOND=0.125.
- `beamGroups(notes: List<MusicalNote>, beats: Int, beatType: Int): List<IntRange>` — gruppi di indici di note beamabili (durata ≤ EIGHTH) consecutive che iniziano nello stesso beat; gruppi di 1 elemento esclusi (tengono la coda). Il confine di beat spezza il gruppo.
- `measurePositions(notes: List<MusicalNote>, beats: Int, beatType: Int): List<Int>` — indici *dopo* i quali cade una stanghetta (accumulo di quarti ≥ capacità battuta; best effort quando le durate non riempiono esattamente la battuta: la stanghetta cade al superamento, mai eccezioni).
- `spacingWeights(notes: List<MusicalNote>): List<Float>` — pesi orizzontali `sqrt(quarterUnits)`, normalizzati dal chiamante sull'ampiezza disponibile.
- `stemUp(relPos: Int): Boolean` (regola esistente `relPos < 4`); per un beam group la direzione è quella della maggioranza delle note del gruppo.
### 2. `StaffRenderer` (nuovo file, `ui/components`) — estensioni `DrawScope`
Primitive di disegno usate da tutte le viste:
- `drawNoteHeadPath` — testa a pera via `Path` (quadratiche, come il mockup approvato), piena per ≤ QUARTER, contorno per WHOLE/HALF; rotazione implicita nella forma.
- `drawCurvedFlag` — coda a goccia riempita (`Path` cubica), 1–3 code per croma/semicroma/biscroma, specchiata per gambo in giù.
- `drawBeam` — parallelogramma tra due estremità di gambo, spessore ~0.5·lineSpacing, pendenza limitata (±0.5·lineSpacing per nota); doppia barra per semicrome.
- `drawSharpGlyph` / `drawFlatGlyph` — esistenti, raffinati (proporzioni del mockup).
- `drawBarline`, `drawTimeSignature(beats, beatType)` — stanghetta sottile a tutta altezza rigo; cifre con `TextMeasurer` (bold, serif di sistema).
- `drawClef` — glifo Unicode esistente ma a piena opacità/colore nota e dimensione maggiore.
Le funzioni esistenti in `NoteRenderer.kt` (drawNoteHead/drawNoteStem/drawNoteFlags) vengono sostituite dalle nuove primitive; il file viene aggiornato o assorbito da StaffRenderer.
### 3. Modello e parser
- `NoteSequence` guadagna `beats: Int = 4`, `beatType: Int = 4`.
- `MusicXmlParser` estrae la prima occorrenza di `<time><beats>N</beats><beat-type>M</beat-type></time>` nella prima parte; assente → 4/4.
- Inserimento manuale, scale, esercizi, scansione AI: default 4/4.
### 4. Applicazione per vista
| Vista | Glifi | Travature | Battute+Tempo | Spaziatura |
|---|---|---|---|---|
| StaffFullView | ✅ | ✅ | ✅ | ✅ (per rigo) |
| StaffContextView | ✅ | ✅ | ✅ (se nella finestra) | ✅ |
| StaffPreview | ✅ | ✅ | — | ✅ |
| StaffView (nota singola) | ✅ | — | — | — |
L'evidenziazione (nota corrente oro, suonate sbiadite) resta identica. In StaffFullView il wrapping per riga passa da "N note fisse" a "capienza per pesi", con le battute che preferibilmente non si spezzano a fine riga quando possibile (best effort: si spezza sul confine di battuta più vicino che sta nella riga; se una battuta è più larga della riga, si spezza comunque).
## Gestione errori
- Sequenze senza time signature → 4/4.
- Durate che non riempiono la battuta (anacrusi, parser lossy) → stanghetta al superamento della soglia; nessuna eccezione.
- Beam group con note su registri lontani → pendenza della travatura clampata.
- Sequenze vuote → nessun disegno (comportamento attuale).
## Test
- **TDD (commonTest)**: `quarterUnits` per tutte le durate; `beamGroups` (coppie di crome, croma singola, confine di beat in 4/4 e 6/8, misto crome/semicrome, interruzione su nota lunga); `measurePositions` (4/4 esatto, 3/4, durate eccedenti, sequenza vuota); `spacingWeights` (monotonia, rapporto √); parser `<time>` (presente, assente, 6/8).
- **Verifica visiva**: lancio dell'app desktop e ispezione di Esercizi/Spartiti/Pratica (screenshot).
## Rischi
- La resa estetica di path disegnati a mano richiede iterazione visiva: prevista una passata di tuning dopo la prima implementazione, con l'app desktop come banco di prova.
- StaffFullView cambia il layout di wrapping: verificare l'auto-scroll alla riga corrente (già esistente) con le nuove larghezze.