diff --git a/Software/Sigmastudio/Sigmastudio.zip b/Software/Sigmastudio/Sigmastudio.zip new file mode 100644 index 0000000..ed30de4 Binary files /dev/null and b/Software/Sigmastudio/Sigmastudio.zip differ diff --git a/Software/Sigmastudio/sigmastudiofinale.png b/Software/Sigmastudio/sigmastudiofinale.png new file mode 100644 index 0000000..7fb3158 Binary files /dev/null and b/Software/Sigmastudio/sigmastudiofinale.png differ diff --git a/Software/docs/adau1701-sigmastudio-analysis.md b/Software/docs/adau1701-sigmastudio-analysis.md index 4b13b47..27ba412 100644 --- a/Software/docs/adau1701-sigmastudio-analysis.md +++ b/Software/docs/adau1701-sigmastudio-analysis.md @@ -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) │ - ▼ - ┌──────────────────┐ - │ Multiple1 (L/R) │ - │ = MASTER VOLUME │ - │ (addr 42, 43) │ - └──────────────────┘ - │ - ┌────────────┴────────────┐ - ▼ ▼ - ┌───────────────┐ ┌───────────────┐ - │ Limiter1 (L) │ │ Limiter2 (R) │ - │ (addr 44-58) │ │ (addr 59-73) │ - └───────────────┘ └───────────────┘ - │ │ - ▼ ▼ - Output1 Output2 - (→ BT1035 I2S, L) (→ BT1035 I2S, R) +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) ─────────────────────────────────────────────────┤ + ▼ + ┌──────────────────┐ + │ 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) + │ + ┌──────────┴──────────┐ + ▼ ▼ + 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 nome→indirizzo (74 celle) | — | ✅ | -| `/api/dsp/param` | PUT | `{"name":"...","value":}` | 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":}` | 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 | diff --git a/Software/docs/app-cursor-brief-2026-08-25.md b/Software/docs/app-cursor-brief-2026-08-25.md new file mode 100644 index 0000000..93150bf --- /dev/null +++ b/Software/docs/app-cursor-brief-2026-08-25.md @@ -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. diff --git a/Software/docs/manual/ch-sigmastudio.tex b/Software/docs/manual/ch-sigmastudio.tex index 0b040ba..270a1bf 100644 --- a/Software/docs/manual/ch-sigmastudio.tex +++ b/Software/docs/manual/ch-sigmastudio.tex @@ -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. diff --git a/Software/docs/manual/sigmastudiofinale.png b/Software/docs/manual/sigmastudiofinale.png new file mode 100644 index 0000000..7fb3158 Binary files /dev/null and b/Software/docs/manual/sigmastudiofinale.png differ