Document DigiRadioFinale DSP revision, archive SigmaStudio source

Adds the new SigmaStudio project export (Sigmastudio.zip, source
screenshot) alongside the existing project archives in Sigmastudio/,
rewrites docs/adau1701-sigmastudio-analysis.md for the 224-parameter
program (exclusive source mux replacing the old mixer, Bass Boost1/
SPhat1 dedicated blocks, unimplemented VU-meter readback), adds the
DigiRadioFinale figure/table to the manual, and adds a brief for the
iOS app side (active_source API shape, enhancement semantics change)
to hand to Cursor.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-25 21:52:17 +02:00
co-authored by Claude Sonnet 5
parent 75cb147f09
commit b55f2dac9d
6 changed files with 317 additions and 143 deletions
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

+132 -134
View File
@@ -6,188 +6,186 @@ con il driver firmware (`components/drivers/adau1701/`) e le API HTTP
(`components/net/src/SetupWebServer.cpp`). Ogni valore di indirizzo/registro citato è
letto direttamente dai file di export SigmaStudio, non inventato.
**Root cause del bug "volume/mixer/EQ non si salvano mai" trovato e risolto in questa
sessione (2026-08-24): vedi §7.** Tutto il resto del documento descrive l'architettura
del programma DSP com'è oggi, dopo il fix.
**Questo documento descrive la revisione "DigiRadioFinale" (2026-08-25)**, che
sostituisce il programma DSP precedente (74 parametri, mixer additivo) con uno
molto più ricco (224 parametri) basato su un **selettore di sorgente esclusivo**
invece di un mixer. §5 raccoglie anche i bug storici della revisione precedente,
per riferimento.
---
## 1. Catena del segnale (da `DigiRadio_NetList.xml`)
```
┌─────────────┐
Si4684 (I2S) ──L──▶ │ Gain Si4674 │──▶
──R──▶ │ (addr 3,4) │──▶
└─────────────┘ │
│ ┌──────────────┐ ┌──────────────┐
ESP32 (I2S) ──L──▶ ┌─────────────┐ ├──▶│ St Mixer1 │──▶│ Param EQ1 │──
──R──▶ │ Gain ESP32 │──▶┤ │ ST0/ST1/ST2 │ │ 6 bande │ │
│ (addr 5,6) │──▶┘ │ (addr 9-11) │ │ (addr 12-41) │ │
└─────────────┘ └──────────────┘ └──────────────┘ │
Beep1 (interno) ──▶ Single1 ──▶ SSplitter1 ──▶ (ST2, ingresso mixer) │
(addr 0-2) (addr 7) (addr 8) │
Input1 (Si4684 L/R, ESP32 L/R) ──┬─▶ DCB1 (L radio) ─┐
├─▶ DCB2 (R radio) ─┼─▶ Compressor1 ─▶ 1×RTA1 (L) ─
├─▶ DCB4 (L esp32) ─┤ (stereo RMS) 1×RTA2 (R) ─
└─▶ DCB3 (R esp32) ─┘ 1×RTA3 (L) ─┤ (readback,
1×RTA4 (R) ─┤ ingresso)
Beep1 ─▶ S Splitter1 (mono→stereo) ─────────────────────────────────────────────────
┌──────────────────┐
│ Multiple1 (L/R)
│ = MASTER VOLUME
│ (addr 42, 43)
│ MX1 (mux)
│ select = DC1
│ 0=Radio 1=BT
│ 2=Beep (raw int!) │
└──────────────────┘
┌────────────┴────────────┐
Param EQ1 (6 bande, addr 59-88)
SPhat1 (Spatializer, addr 89-140)
Gen Filter1 (Voice Clarifier,
addr 141-145 — non tarato)
Multiple1 (Master Volume,
addr 146-147)
Bass Boost1 (Dynamic Bass Boost,
addr 148-187)
┌──────────┴──────────┐
▼ ▼
┌───────────────┐ ┌───────────────┐
│ Limiter1 (L) │ Limiter2 (R)
│ (addr 44-58) │ │ (addr 59-73) │
└───────────────┘ └───────────────┘
1×RTA1_2 (readback) 1×RTA2_2 (readback)
▼ ▼
Limiter1 (L) Limiter2 (R)
addr 209-223 addr 194-208
│ │
▼ ▼
Output1 Output2
(→ BT1035 I2S, L) (→ BT1035 I2S, R)
```
Punto architetturale importante, spesso fonte di confusione: **ogni sorgente ha DUE
livelli di gain in cascata**, non uno solo:
**Cambio architetturale rispetto alla revisione precedente**: non esiste più un
mixer che combina Si4684 + ESP32 + Beep simultaneamente. `MX1` è un **selettore
esclusivo**: passa UNA SOLA delle tre coppie stereo alla volta, scelta scrivendo
`DC1` (indirizzo 3). Non esistono più gain pre-mixer per sorgente (`SI4674`/`ESP32`
sono spariti) — il livello si controlla solo con Master Volume ed EQ, a valle
della selezione.
1. **Gain pre-mixer** (`SI4674`/`SI4674_1` addr 3/4, `ESP32`/`ESP32_1` addr 5/6) — un
gain indipendente per canale L e R, applicato PRIMA che il segnale entri nel mixer.
2. **Gain del mixer** (`STMIXER1_ST0_VOLUME`/`ST1_VOLUME` addr 9/10) — un SOLO gain per
l'intera coppia stereo di quella sorgente, applicato AL mixer.
Se uno dei due è a -96dB (muto) e l'altro è aperto, il risultato finale è comunque
muto — impostare solo uno dei due senza sapere dell'altro è la causa più comune di
"ho cambiato il volume ma non sento niente".
**Scoperta empirica cruciale (2026-08-25)**: `DC1` è dichiarato
`SIGMASTUDIOTYPE_FIXPOINT` nell'export compilato (che farebbe pensare al formato
5.23 usato da tutte le altre celle), ma **MX1 legge invece un intero a 32 bit
grezzo**. Scrivere `0x00800000` (= 1.0 in 5.23) non cambia la sorgente; scrivere
`0x00000001` sì. Confermato dal vivo: 0=Radio, 1=Bluetooth(ESP32), 2=Beep. Vedi
`adau1701::paramSourceIndex()` e `Adau1701Driver::selectSource()`.
---
## 2. Mappa completa dei registri Parameter RAM (74 indirizzi, 0-73)
## 2. Mappa completa dei registri Parameter RAM (224 indirizzi, 0-223)
| Indirizzo | Nome SigmaStudio | Funzione | Gruppo |
| Indirizzi | Blocco | Funzione | Controllo runtime |
|---|---|---|---|
| 0 | `BEEP1_ENABLE` | Abilita generatore toni interno | Diagnostica |
| 1 | `BEEP1_KICK` | Trigger del generatore toni | Diagnostica |
| 2 | `BEEP1_BEEP_FREQ` | Frequenza del tono (fissa, mai cambiata a runtime) | Diagnostica |
| 3 | `SI4674` | Gain pre-mixer Si4684, canale L | Mixer |
| 4 | `SI4674_1` | Gain pre-mixer Si4684, canale R | Mixer |
| 5 | `ESP32` | Gain pre-mixer streaming ESP32, canale L | Mixer |
| 6 | `ESP32_1` | Gain pre-mixer streaming ESP32, canale R | Mixer |
| 7 | `SINGLE1` | Gain del tono Beep prima dello splitter | Diagnostica |
| 8 | `SSPLITTER1` | Splitter mono→stereo per il tono Beep | Diagnostica |
| 9 | `STMIXER1_ST0_VOLUME` | Gain mixer, leg Si4684 (stereo, un solo controllo) | Mixer |
| 10 | `STMIXER1_ST1_VOLUME` | Gain mixer, leg ESP32 (stereo, un solo controllo) | Mixer |
| 11 | `STMIXER1_ST2_VOLUME` | Gain mixer, leg Beep — **mai esposto da nessuna API curata**, fisso a 1.0 (unity) di fabbrica | Mixer (non controllato) |
| 12-16 | `PARAMEQ1_ST0_*` (B0,B1,B2,A0,A1) | Banda EQ 0 — **filtro passa-alto fisso, mai scritto da `applyEq()`** | EQ (banda bloccata) |
| 17-21 | `PARAMEQ1_ST1_*` | Banda EQ 1 (default 100 Hz) | EQ |
| 22-26 | `PARAMEQ1_ST2_*` | Banda EQ 2 (default 400 Hz) | EQ |
| 27-31 | `PARAMEQ1_ST3_*` | Banda EQ 3 (default 1000 Hz) | EQ |
| 32-36 | `PARAMEQ1_ST4_*` | Banda EQ 4 (default 3000 Hz) | EQ |
| 37-41 | `PARAMEQ1_ST5_*` | Banda EQ 5 (default 8000 Hz) | EQ |
| 42 | `MULTIPLE1` | **Volume master**, canale L | Master |
| 43 | `MULTIPLE1_1` | **Volume master**, canale R | Master |
| 44-58 | `LIMITER1_*` | Limiter canale L (soglia a indirizzo 55) | Limiter |
| 59-73 | `LIMITER2_*` | Limiter canale R (soglia a indirizzo 70) | Limiter |
| 0-2 | `BEEP1_*` | Tono di test interno | `setBeepEnabled()` (live-only) |
| 3 | `DC1` | Selettore sorgente per MX1 — **intero grezzo**, non 5.23 | `selectSource()` |
| 4-7 | `DCB1-4_POLE` | DC blocker, uno per canale (radio L/R, esp32 L/R) | Fisso (compilato) |
| 8 | `SSPLITTER1` | Fan-out mono→stereo per Beep | Fisso |
| 9-46 | `COMPRESSOR1_*` | Compressore RMS stereo (curva a 34 punti) su radio L/R | Fisso |
| 47-58 | `1XRTA3,4,1,2` | 4 VU-meter in ingresso (radio L/R, esp32 L/R) | Lettura via indirizzo speciale 2074 — **meccanismo non ancora implementato in firmware** |
| 59-88 | `PARAMEQ1_ST0..5_*` | EQ parametrico, 6 bande × 5 coefficienti (B0,B1,B2,A0,A1) | `setEqBand()`/`applyEq()` |
| 89-140 | `SPHAT1_*` | Spatializer (SuperPhat) — solo `SPREAD1`/`SPREAD2` (139,140) sono la manopola di intensità; il resto (filtro crossover, tabella compander) è tarato in SigmaStudio | `setStereoSpreadLevel()` — scala SPREAD1/2 proporzionalmente (0=nessuno spread aggiunto, 100=pieno) |
| 141-145 | `GENFILTER1_ST0_*` | Voice Clarifier — **ancora piatto/identità** in questo export (b0=1, resto 0), non tarato | Non ancora implementato |
| 146-147 | `MULTIPLE1`, `MULTIPLE1_1` | Master Volume L/R | `setMasterVolume()` |
| 148-187 | `BASSBOOST1_*` | Dynamic Bass Boost — `BASSFREQUENCY`/`TIMECONSTANT` fissi; filtro crossover (B0,B1,B2,A1,A2) e tabella compander a 33 punti (`TABLE0-32`) sono la parte "intensità" | `setBassBoostLevel()` — scala filtro+tabella verso l'identità/unità (0=bypass piatto, 100=pieno compilato) |
| 188-193 | `1XRTA2_2,1_2` | 2 VU-meter in uscita (post Bass Boost, pre limiter) | Stesso meccanismo di lettura non ancora implementato |
| 194-208 | `LIMITER2_*` | Limiter canale R (soglia indirizzo 205) | Fisso |
| 209-223 | `LIMITER1_*` | Limiter canale L (soglia indirizzo 220) | Fisso |
Le 6 bande EQ condividono gli **stessi coefficienti per L e R** (il cell "Parametric
EQ - Double Precision" è stereo ma con un solo set di coefficienti per banda) — non
esiste un controllo EQ separato per canale.
Formato dati: fixed-point **5.23** (28 bit significativi, non 32 — un errore di
decodifica di questo formato durante l'indagine del 23/08 aveva fatto sembrare
instabile un filtro che in realtà era corretto; vedi `core::floatToFixpoint823()` /
sign-extend da bit 27 in `Adau1701Driver.cpp`).
Formato dati: fixed-point **5.23** per quasi tutte le celle (28 bit significativi,
sign-extend da bit 27 — vedi `core::floatToFixpoint823()`), **eccetto `DC1`** che è
un intero grezzo a 32 bit (vedi sopra).
---
## 3. Registri di controllo (Core Control block, 0x800-0x827)
## 3. API HTTP e corrispondenza con i registri
| Indirizzo | Nome | Uso nel nostro firmware |
|---|---|---|
| 0x81C | Core Control Register | Scritto una sola volta al boot dal replay del programma compilato |
| 0x81E | Serial Output Control | Compilato, mai modificato a runtime |
| 0x81F | Serial Input Control (bit IBP/ILP) | **Storia**: un override IBP=1 qui era stato introdotto il 16/08 insieme a un fix non correlato di Si4684, mai validato da solo, e causa del fruscio multi-giorno risolto oggi (24/08). Rimosso — ora resta al default compilato (0x00) |
| 0x820/0x821 | MP Config 0/1 | Compilato, mai toccato |
| 0x822 | Analog Power-Down | Compilato, mai toccato |
| 0x826 | Analog Interface Register 2 | Contiene i bit IBIAS_ADJ/VREF_TRIM di trim analogico interno, mai toccati; è un registro diverso da quello dove viveva l'override IBP (0x81F) |
---
## 4. API HTTP e corrispondenza con i registri — tutte testate dal vivo il 24/08
| Endpoint | Metodo | Corpo | Registri toccati | Persistenza NVS | Testato |
| Endpoint | Metodo | Corpo | Cosa tocca | Persistenza | Testato dal vivo |
|---|---|---|---|---|---|
| `/api/audio/profile` | GET | — | legge tutto | | ✅ |
| `/api/audio/profile` | PUT | mixer + master + eq[6] + enhancements | 3,4,5,6,9,10,12-41,42,43 | ✅ | ✅ (round-trip completo dopo riavvio) |
| `/api/audio/reset` | POST | — | ripristina `AudioProfile::factoryDefault()` (mixer: **entrambe** le sorgenti aperte a 0dB, non radio-first) | ✅ | ✅ |
| `/api/audio/stereo-enhance` | POST | `{"level":0-100}` | bande EQ 3,4,5 (sovrascrive) | ✅ | ✅ |
| `/api/audio/bass-enhance` | POST | `{"level":0-100}` | bande EQ 1,2 (sovrascrive) | ✅ | ✅ |
| `/api/audio/beep` | POST | `{"enabled":true/false}` | 0 (`BEEP1_ENABLE`), 1 (`BEEP1_KICK`) | ❌ (live-only, come da design) | ✅ |
| `/api/dsp/params` | GET | — | elenco statico nomeindirizzo (74 celle) | — | ✅ |
| `/api/dsp/param` | PUT | `{"name":"...","value":<float>}` | qualunque cella per nome, incluse quelle **non** raggiungibili dalle API curate (es. `STMIXER1_ST2_VOLUME`) | ❌ (live-only, "escape hatch" come SigmaStudio Remote Connection) | ✅ (scritto e ripristinato `STMIXER1_ST2_VOLUME`) |
| `/api/tuner/xtal-calibrate` | POST | `{"ibias","ctun","xtal_freq_hz"}` | Si4684 POWER_UP (non ADAU1701) | ✅ (dal fix di stasera) | ✅ |
| `/api/audio/profile` | GET/PUT | `active_source`, `master`, `eq[6]`, `enhancements` | `DC1`, EQ 59-88, Master 146-147, Bass Boost/Spatializer via enhancements | | ✅ |
| `/api/audio/reset` | POST | — | `AudioProfile::factoryDefault()` (Radio, EQ piatto, enhancements 0) | ✅ | — |
| `/api/audio/stereo-enhance` | POST | `{"level":0-100}` | `SPHAT1_SPREAD1/2` (scala proporzionale) | ✅ | ✅ (effetto soggettivo/sottile) |
| `/api/audio/bass-enhance` | POST | `{"level":0-100}` | `BASSBOOST1_*` filtro+tabella (scala verso identità) | ✅ | ✅ (confermato su radio, non su tono fisso — l'algoritmo è dinamico, reagisce a contenuto con dinamica reale) |
| `/api/audio/beep` | POST | `{"enabled":true/false}` | `BEEP1_ENABLE/KICK` | ❌ (live-only, per design) | ✅ |
| `/api/dsp/params` | GET | — | elenco statico nome→indirizzo (230 celle, incluse le 6 speciali readback) | — | ✅ |
| `/api/dsp/param` | PUT | `{"name":"...","value":<float>}` | qualunque cella per nome — **eccetto `DC1`, che qui va scritto già come intero puro, non tramite `selectSource()`** | ❌ (live-only) | ✅ (sweep completo di 223/224 celle scrivibili, 0 errori) |
### Campo `"locked"` per banda EQ (aggiunto oggi)
`active_source` accetta `"radio"`, `"bluetooth"`, `"beep"`. Il vecchio campo
`"mixer"` (con `si4684_left_db`/`esp32_left_db`/`mix_left_db` ecc.) **non esiste
più** — non ha più senso dato che non c'è più un mixer da bilanciare.
`GET/PUT /api/audio/profile` ora include `"locked":true/false` per ciascuna delle 6
bande in `eq[]`:
- banda 0: **sempre `true`** — è il passa-alto fisso, qualsiasi valore scritto è
cosmetico, non ha mai effetto udibile (`Adau1701Driver::applyEq()` la salta
esplicitamente).
- bande 1,2: `true` quando `bass_level > 0` — l'enhancement le sovrascrive con valori
calcolati da formula, un edit manuale in quel momento non è udibile.
- bande 3,4,5: `true` quando `stereo_level > 0`, stesso motivo.
Prima di questo fix il comportamento era identico (le bande erano già sovrascritte),
ma l'API non lo segnalava — sembrava che "il salvataggio non facesse nulla" quando in
realtà stava facendo esattamente quello che il DSP prevede, solo senza dirlo.
Il campo `"locked"` per banda EQ (introdotto il 24/08 quando bass/stereo enhance
sovrascrivevano le bande EQ) **ora è sempre `false` tranne la banda 0** (passa-alto
fisso): bass/stereo enhance non toccano più l'EQ, guidano direttamente Bass
Boost1/SPhat1.
---
## 5. Bug trovati e stato
## 4. VU-meter (readback) — non ancora implementato
Le 6 celle `1×RTA*` sono veri VU-meter (level detector) posizionati in 4 punti
d'ingresso e 2 punti d'uscita. Il loro valore letto NON sta al normale indirizzo
Parameter RAM di ciascuna — condividono tutte l'indirizzo speciale **2074**, con
un codice di selezione diverso per ciascuna (`VALUES_1XRTA1` = 0x0376, ecc., tipo
`SIGMASTUDIOTYPE_SPECIAL`/`SIGMASTUDIOTYPE_10_14`). Questo è il meccanismo di
"Data Capture" dell'ADAU1701 (registro indiretto), diverso dal semplice
read/safeload usato ovunque altrove in questo firmware. **Va ancora reverse-
engineerato e implementato** — non è stato inventato né testato in questa sessione.
---
## 5. Bug trovati e stato (cronologia)
| # | Sintomo | Causa reale | Stato |
|---|---|---|---|
| 1 | Mixer/volume/EQ salvati non sopravvivono MAI a un riavvio | **NVS inizializzato DOPO** `AudioService::loadAndApply()` in `app_main()` — ogni lettura falliva con `ESP_ERR_NVS_NOT_INITIALIZED` (0x1101), silenziosamente, da sempre | ✅ risolto oggi — riordinato boot in `main.cpp`, verificato dal vivo |
| 2 | Anche dopo il fix #1, mixer e master tornavano comunque al preset "radio" a ogni riavvio | `HardwareBootstrap::boot()` chiamava `applyRadioFirstMix()` **incondizionatamente** dopo il caricamento, sovrascrivendo qualunque valore appena ripristinato da NVS | ✅ risolto oggi — ora condizionale, si applica solo se non c'è un profilo salvato |
| 3 | Modificare la banda EQ 0 (20 Hz) via web UI/app non ha mai effetto udibile | È il filtro passa-alto fisso del programma compilato, `applyEq()` la salta di proposito | ✅ ora segnalato via `"locked":true`, non più silenzioso |
| 4 | Attivare bass/stereo enhancement sembra "cancellare" le modifiche manuali dell'EQ sulle bande coinvolte | `core::applyEnhancementsToEq()` sovrascrive bande 1-2 (bass) e 3-5 (stereo) con valori a formula quando il livello è > 0 | ✅ ora segnalato via `"locked":true` sulle bande coinvolte; il comportamento DSP resta invariato (per design) |
| 5 | Il leg Beep del mixer (`STMIXER1_ST2_VOLUME`, indirizzo 11) non è mai regolabile dalle API curate | Nessun bug — è un ingresso diagnostico interno, mai stato nei piani esporlo. Raggiungibile comunque via `/api/dsp/param` se serve per debug | Non è un bug, solo documentato |
| 6 | Fruscio persistente su radio e streaming (multi-giorno) | Override IBP=1 su `SerialInputRegister` (0x81F), introdotto l'8/16 agosto insieme a un fix non correlato, mai validato da solo — condiviso da tutti gli ingressi seriali del chip | ✅ risolto ieri (24/08, prima parte della sessione) — vedi `docs/si4684-rf-investigation-report.md` |
| 1 | Mixer/volume/EQ salvati non sopravvivono MAI a un riavvio (revisione precedente) | NVS inizializzato dopo `AudioService::loadAndApply()` in `app_main()` | ✅ risolto 2026-08-24 |
| 2 | Mixer e master tornavano al preset "radio" a ogni riavvio anche dopo il fix #1 | `HardwareBootstrap::boot()` chiamava `applyRadioFirstMix()` incondizionatamente | ✅ risolto 2026-08-24 |
| 3 | Qualsiasi modifica EQ/enhancement diversa da zero → silenzio totale (anche sul tono di test) | Segno mancante in `core::designPeakingEq()`: i coefficienti di retroazione RBJ (sottrattivi) venivano scritti tali e quali nei registri A0/A1 dell'ADAU1701 (additivi) — retroazione positiva invece che negativa, il filtro divergeva su un valore costante (DC, inaudibile) | ✅ risolto 2026-08-25 — vedi `components/core/src/BiquadDesign.cpp`, test di stabilità in `biquad_design_test.cpp` |
| 4 | Bridge TCP SigmaStudio (porta 8086): `accept()` in loop infinito su EBADF da ogni boot | `SigmaStudioTcpServer::stop()` cancellava incondizionatamente il singleton del socket attivo, anche quando chiamato sull'oggetto move-from (ogni boot ne crea uno) | ✅ risolto 2026-08-25 |
| 5 | Nuovo netlist DigiRadioFinale: nessun mixer, solo `MX1` a selezione esclusiva | Non è un bug — cambio di design intenzionale, confermato dall'utente | Documentato, non un bug |
| 6 | Scrivere `DC1` in formato 5.23 (es. 1.0 = 0x00800000) non cambia la sorgente selezionata | `MX1` legge `DC1` come intero grezzo, non fixpoint, nonostante `TYPE_DC1` compilato dica `SIGMASTUDIOTYPE_FIXPOINT` | ✅ risolto 2026-08-25 — confermato dal vivo (0/1/2 → Radio/BT/Beep) |
| 7 | Fruscio persistente su radio e streaming (multi-giorno, revisione precedente) | Override IBP=1 su `SerialInputRegister` (0x81F), mai validato in isolamento | ✅ risolto 2026-08-24 |
---
## 6. Come testare manualmente (comandi usati stasera)
## 6. Come testare manualmente
```bash
# Stato attuale
curl http://192.168.1.62/api/audio/profile
# Scrivi un pattern distintivo (mixer + master + 5 bande EQ)
# Cambia sorgente
curl -X PUT http://192.168.1.62/api/audio/profile -d '{
"mixer": {"si4684_left_db": 0, "si4684_right_db": 0,
"esp32_left_db": -96, "esp32_right_db": -96,
"mix_left_db": 0, "mix_right_db": -96},
"master": {"left_db": -4, "right_db": -4},
"active_source": "bluetooth",
"master": {"left_db": 0, "right_db": 0},
"eq": [
{"gain_db": 0, "center_hz": 20, "q": 1.414},
{"gain_db": 5, "center_hz": 100, "q": 1},
{"gain_db": -3, "center_hz": 400, "q": 1.2},
{"gain_db": 2, "center_hz": 1000, "q": 1},
{"gain_db": -1, "center_hz": 3000, "q": 1},
{"gain_db": 4, "center_hz": 8000, "q": 1}
{"gain_db": 0, "center_hz": 100, "q": 1},
{"gain_db": 0, "center_hz": 400, "q": 1},
{"gain_db": 0, "center_hz": 1000, "q": 1},
{"gain_db": 0, "center_hz": 3000, "q": 1},
{"gain_db": 0, "center_hz": 8000, "q": 1}
],
"enhancements": {"stereo_level": 0, "bass_level": 0}
}'
# Riavvia la scheda (fisicamente, o via reset seriale) e rileggi:
curl http://192.168.1.62/api/audio/profile
# → deve mostrare ESATTAMENTE gli stessi valori scritti sopra
# Bass Boost / Spatializer
curl -X POST http://192.168.1.62/api/audio/bass-enhance -d '{"level":100}'
curl -X POST http://192.168.1.62/api/audio/stereo-enhance -d '{"level":100}'
```
Per leggere/scrivere una singola cella arbitraria (debug avanzato, non persistente):
Per leggere/scrivere una singola cella arbitraria (debug avanzato, non
persistente — **non usare per `DC1`**, che ha una semantica intero-grezzo
diversa da tutte le altre celle):
```bash
curl http://192.168.1.62/api/dsp/params # elenco nome→indirizzo
curl -X PUT http://192.168.1.62/api/dsp/param -d '{"name":"STMIXER1_ST2_VOLUME","value":1.0}'
curl http://192.168.1.62/api/dsp/params # elenco nome→indirizzo (230 celle)
curl -X PUT http://192.168.1.62/api/dsp/param -d '{"name":"SPHAT1_SPREAD1","value":0.0629}'
```
---
@@ -196,12 +194,12 @@ curl -X PUT http://192.168.1.62/api/dsp/param -d '{"name":"STMIXER1_ST2_VOLUME",
| File | Contenuto |
|---|---|
| `Firmware/ADAU1701-Firmware/DigiRadio_IC_1_PARAM.h` | Sorgente di verità per tutti gli indirizzi Parameter RAM |
| `Firmware/ADAU1701-Firmware/DigiRadio_IC_1_PARAM.h` | Sorgente di verità per tutti gli indirizzi Parameter RAM (export DigiRadioFinale) |
| `Firmware/ADAU1701-Firmware/DigiRadio_NetList.xml` | Topologia del segnale (chi è collegato a chi) |
| `components/drivers/adau1701/include/adau1701/Adau1701ParamTable.hpp` | Tabella nome→indirizzo generata da PARAM.h, usata da `/api/dsp/param` |
| `components/drivers/adau1701/include/adau1701/Adau1701ParamMap.hpp` | Funzioni helper indirizzo-per-banda-EQ e indirizzo-per-sorgente-mixer |
| `components/drivers/adau1701/src/Adau1701Driver.cpp` | Implementazione `applyMixer`/`applyEq`/`setMasterVolume`/`setBeepEnabled` |
| `components/services/audio/src/AudioService.cpp` | `loadAndApply()`, `applyRadioFirstMix()`, enhancement plumbing |
| `components/core/src/EnhancementsDesign.cpp` | Formula di sovrascrittura EQ per bass/stereo enhancement |
| `main/main.cpp` | Ordine di boot (`app_main()`) — sede del fix root-cause di oggi |
| `main/hardware_bootstrap.cpp` | `HardwareBootstrap::boot()` — sede del secondo fix (radio-first condizionale) |
| `components/core/include/core/ActiveSource.hpp` | Enum Radio/Bluetooth/Beep + nota sulla semantica intero-grezzo di DC1 |
| `components/drivers/adau1701/include/adau1701/Adau1701ParamTable.hpp` | Tabella nome→indirizzo generata da PARAM.h (230 celle) |
| `components/drivers/adau1701/include/adau1701/Adau1701ParamMap.hpp` | `paramAddrEqBandBase()`, `paramSourceIndex()` |
| `components/drivers/adau1701/src/Adau1701Driver.cpp` | `selectSource()`, `applyEq()`, `setMasterVolume()`, `setBassBoostLevel()`, `setStereoSpreadLevel()`, `setBeepEnabled()` |
| `components/core/src/BiquadDesign.cpp` | `designPeakingEq()` — fix del segno A0/A1 (2026-08-25) |
| `components/services/audio/src/AudioService.cpp` | `loadAndApply()`, `applyRadioFirstMix()`, `selectSource()`, enhancement plumbing |
| `docs/manual/ch-sigmastudio.tex` §"Next revision: DigiRadioFinale" | Diagramma e tabella indirizzi per il manuale PDF |
@@ -0,0 +1,118 @@
# Brief per Cursor — allineamento app iOS al nuovo firmware DSP (DigiRadioFinale)
Il firmware ADAU1701 è stato sostituito con un programma DSP molto più ricco
(224 parametri contro 74 prima). Questo documento descrive **cosa è cambiato
lato API HTTP** e **quali controlli nuovi puoi costruire in app**, più qualche
indicazione di UX. I dettagli implementativi Swift (struttura file, ViewModels
esistenti, tab bar) restano una tua scelta — qui do solo il contratto dati e
gli obiettivi funzionali.
Dispositivo di test: `http://192.168.1.62` (mDNS `digiradio-CC4DB4.local`).
---
## 1. Breaking change: `mixer` → `active_source`
**Prima**: `GET/PUT /api/audio/profile` aveva un oggetto `"mixer"` con guadagni
indipendenti per Si4684, ESP32 e i due leg del mixer — permetteva di
"mescolare" radio e Bluetooth insieme.
**Ora**: il firmware non ha più un mixer. C'è un **selettore di sorgente
esclusivo** — si ascolta una sorgente alla volta, come su un vero stereo.
```json
{
"active_source": "radio",
"master": {"left_db": 0, "right_db": 0},
"eq": [ ... 6 bande, invariato ... ],
"enhancements": {"stereo_level": 0, "bass_level": 0}
}
```
`active_source` accetta esattamente `"radio"`, `"bluetooth"`, `"beep"`.
`"beep"` è il tono di test interno (usato per diagnostica firmware, probabilmente
da nascondere in UI di produzione o mettere in una sezione "Diagnostica").
**Azione richiesta**: sostituire ogni UI che oggi mostra due slider indipendenti
(volume radio / volume BT) con un **selettore a scelta singola** (segmented
control o lista) tra Radio e Bluetooth. Non esiste più un modo per sentirli
mescolati.
---
## 2. `enhancements` ora pilota algoritmi DSP reali, non più un trucco EQ
**Prima**: `bass_level`/`stereo_level` sovrascrivevano silenziosamente alcune
bande dell'equalizzatore manuale (da cui il campo `"locked"` per banda, per
segnalarlo).
**Ora**: pilotano due blocchi DSP dedicati e indipendenti dall'EQ:
- `bass_level` (0-100) → **Bass Boost1**, un vero algoritmo ADI di "Dynamic
Bass Boost" (filtro crossover + compander dinamico). Effetto udibile solo su
contenuto reale con dinamica (radio, streaming) — su un tono fisso costante
non si sente quasi nulla, è normale (l'algoritmo reagisce a variazioni di
livello nel tempo).
- `stereo_level` (0-100) → **SPhat1** ("SuperPhat" Spatializer/stereo widener),
un secondo algoritmo ADI dedicato.
Il campo `"locked"` per banda EQ **ora è sempre `false`** tranne la banda 0
(passa-alto fisso, sempre `true`, invariato da prima). Puoi quindi rimuovere
qualunque logica "banda grigia perché l'enhancement l'ha sovrascritta" —
l'EQ manuale ora è sempre indipendente dagli enhancement.
**Azione richiesta**: nessun cambio di forma dati per `enhancements` (stessi
due slider 0-100 di prima), ma puoi rimuovere la UI "banda bloccata" per le
bande 1-5 (resta solo per la banda 0, che era già così).
---
## 3. Non ancora disponibile lato firmware (in arrivo)
- **VU-meter / readback dei livelli** (in ingresso e in uscita) — il firmware
ha 6 sensori di livello nel DSP ma il meccanismo di lettura (un registro
indiretto dell'ADAU1701) non è ancora implementato. Non costruire ancora una
UI che dipende da dati di livello in tempo reale dal firmware — se vuoi una
sezione "grafica" ora, usa un placeholder o un'animazione generica non
agganciata a dati reali, finché non arriva l'endpoint.
- **Voice Clarifier** — la cella DSP dedicata (`Gen Filter1`) esiste nella
catena del segnale ma non è ancora tarata (passa tutto invariato). Nessuna
API la pilota ancora. Non esporre ancora questo controllo in UI, o mettilo
disabilitato/"prossimamente".
- **Mute in uscita** (pre-Output1/Output2) — non presente in questo export del
firmware. Se serve, va aggiunto lato SigmaStudio prima di poter esporlo via API.
Ti avviso appena questi sono pronti lato firmware con l'endpoint esatto.
---
## 4. Riepilogo controlli disponibili ORA (tutti testati dal vivo sul dispositivo)
| Controllo | Endpoint | Corpo |
|---|---|---|
| Sorgente attiva | `PUT /api/audio/profile` (campo `active_source`) | `"radio"` \| `"bluetooth"` \| `"beep"` |
| Master volume | `PUT /api/audio/profile` (campo `master`) | `{"left_db":..,"right_db":..}`, range tipico -96..+12 dB |
| Equalizzatore (6 bande) | `PUT /api/audio/profile` (campo `eq`) | invariato: `gain_db`, `center_hz`, `q` per banda; banda 0 sempre inerte |
| Bass Boost | `POST /api/audio/bass-enhance` | `{"level":0-100}` |
| Stereo Spread | `POST /api/audio/stereo-enhance` | `{"level":0-100}` |
| Tono di test (diagnostica) | `POST /api/audio/beep` | `{"enabled":true/false}` — richiede anche `active_source:"beep"` per essere udibile |
| Lettura stato completo | `GET /api/audio/profile` | risposta con tutti i campi sopra |
---
## 5. Indicazioni di stile (dalla richiesta dell'utente)
- Stile Apple/HIG nativo: niente slider/bottoni "grezzi" o accozzaglia in
un'unica schermata. Raggruppa per tab/sezione logica (es. "Ascolto" per
sorgente+volume, "Suono" per EQ+Bass Boost+Stereo Spread, "Bluetooth" per
pairing, "Diagnostica" per tono di test/dettagli tecnici).
- Preferisci componenti nativi SwiftUI (`Picker` segmented per la sorgente,
`Slider` con `.tint()` per i livelli, liste con `Form`/`List` in stile
Impostazioni) piuttosto che controlli custom pesanti.
- La sezione "grafica" (visualizzazione carina) può oggi mostrare solo dati
già disponibili (EQ come curva, o un'animazione leggera legata allo stato
sorgente/tono) — non agganciarla a VU-meter reali finché non sono pronti
(punto 3).
- Dato che non esiste più il mix simultaneo radio+BT, il cambio sorgente è
un'azione "netta" (come cambiare stazione) — vale la pena un feedback visivo
chiaro (es. breve transizione/fade nell'interfaccia, non nell'audio: il
cambio DSP è istantaneo) quando l'utente lo seleziona.
+58
View File
@@ -287,3 +287,61 @@ communication channel to a chip --- either the classic USBi/ICP dongle, or
DigiRadio's own TCP:8086 SigmaStudio bridge (Section~\ref{sec:adau1701-sigmastudio-tcp})
when connecting live to a running board.
\end{drnote}
\section{Next revision: DigiRadioFinale}
\label{sec:ss-digiradiofinale}
\begin{drcaution}[Not yet integrated into firmware]
This section documents a SigmaStudio export (\texttt{DigiRadioFinale}) captured
2026-08-25 that is not yet the program the firmware replays at boot. It expands
the parameter RAM from 74 to 224 words with several new dedicated blocks,
replacing two of the EQ-overlay workarounds in
Section~\ref{sec:ss-enhancements} with real ADI algorithm modules. Driver,
safeload API, and this manual's runtime tables will be updated once the
program is finalised.
\end{drcaution}
\begin{figure}[htbp]
\centering
\includegraphics[width=\linewidth]{sigmastudiofinale.png}
\caption{DigiRadioFinale signal chain: per-channel DC blockers and RMS
compressor, four input-side level meters, the 6-leg Param EQ, the
SuperPhat spatializer, an unconfigured general filter, master volume,
the Dynamic Bass Boost algorithm, two output-side level meters, and the
L/R limiters.}
\label{fig:ss-digiradiofinale}
\end{figure}
\begin{table}[htbp]
\centering
\small
\begin{tabular}{@{}L{2.6cm}L{2.2cm}L{7.6cm}@{}}
\drhead Addresses & Block & Role \\
\midrule
0--2 & Beep1 & test tone (unchanged) \\
3 & DC1 & input trim \\
4--7 & DCB1--4 & DC blocker, one per channel \\
8 & S Splitter1 & control fan-out (unchanged) \\
9--46 & Compressor1 & RMS compander, 34-point curve \\
47--58 & 1×RTA3,4,1,2 & 4 input-side level meters (readback) \\
59--88 & Param EQ1 & 6 stereo legs (ST0--ST5) $\times$ 5 coefficients \\
89--140 & SPhat1 & SuperPhat spatializer (dedicated algorithm,
replaces the stereo-enhance EQ overlay) \\
141--145& Gen Filter1 & general 2nd-order filter, currently flat/bypassed
--- reserved, not yet configured (candidate slot
for Voice Clarifier) \\
146--147& Multiple1 & master volume L/R (unchanged) \\
148--187& Bass Boost1 & Dynamic Bass Boost algorithm (dedicated,
replaces the bass-enhance EQ overlay) \\
188--193& 1×RTA2\_2,1\_2 & 2 output-side level meters (readback) \\
194--223& Limiter2, Limiter1 & unchanged \\
\bottomrule
\end{tabular}
\caption{DigiRadioFinale parameter RAM map, by address.}
\label{tab:ss-digiradiofinale-map}
\end{table}
No dedicated mute cell exists yet in this export, and Gen Filter1 (the
Voice Clarifier candidate) is still an identity filter (b0=1, all other
coefficients zero). Both are pending further SigmaStudio work before this
program replaces the one described earlier in this chapter.
Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB