feat: add dual woofer (500mW) & tweeter (75mW) virtual thermal guards and document in README with disclaimer
This commit is contained in:
60
README.md
60
README.md
@@ -22,6 +22,7 @@ Upstream graphs (`asahi-audio` / `t2-apple-audio-dsp`) target a measurement-flat
|
||||
| 💥 **Distortion at High Volume** | Post-FIR driver limiters (`wlim` @ -2dB, `tlim` @ -1dB) | Crystal clean output at 100% volume with zero amp clipping |
|
||||
| 🔊 **Woofer Over-Excursion** | 60 Hz high-pass + 8-band multiband compressor | Woofers don't bottom out or rattle on heavy bass beats |
|
||||
| 🔇 **No Deep Sub-Bass** | Psychoacoustic sub-bass (`virtualbass` via Bankstown) | Extended perceived low-end without physical cone strain |
|
||||
| 🛡️ **Voice-Coil Overheating** | Dual Woofer & Tweeter Virtual Thermal Guards | Continuous white noise automatically attenuated to 500mW / 75mW |
|
||||
| 🎚️ **Fixed / Rigid EQ** | Isolated 8-band `user_eq` preference node | Custom tone presets that survive git updates |
|
||||
|
||||
---
|
||||
@@ -40,8 +41,7 @@ flowchart TD
|
||||
subgraph Stage2 ["2. Dynamics & Headroom Management"]
|
||||
EQ --> VB["🔊 Virtual Bass (Bankstown Sub-Harmonics)"]:::dynamics
|
||||
VB --> MBComp["📊 Multiband Compressor (8-Band LSP)"]:::dynamics
|
||||
MBComp --> Limiter["🛡️ Main Limiter (Broadband Lookahead)"]:::limiter
|
||||
Limiter --> LoudComp["👂 Loudness Comp (ISO-226 Equal Loudness)"]:::dynamics
|
||||
MBComp --> LoudComp["👂 Loudness Comp (ISO-226 2k FFT)"]:::dynamics
|
||||
end
|
||||
|
||||
subgraph Stage3 ["3. Crossover & Driver FIR Correction"]
|
||||
@@ -50,22 +50,23 @@ flowchart TD
|
||||
subgraph Tweeters ["Tweeter Channels"]
|
||||
Copy --> ConvLT["🔊 Tweeter L FIR (convLT)"]:::fir
|
||||
Copy --> ConvRT["🔊 Tweeter R FIR (convRT)"]:::fir
|
||||
ConvLT --> TGuard["🛡️ Tweeter Thermal Guard (75mW / 1.0s Tau)"]:::limiter
|
||||
ConvRT --> TGuard
|
||||
TGuard --> TLim["🛡️ Tweeter Limiter (-1 dB Ceiling)"]:::limiter
|
||||
end
|
||||
|
||||
subgraph Woofers ["Woofer Channels"]
|
||||
Copy --> ConvLW["🔊 Woofer L FIR (convLW)"]:::fir
|
||||
Copy --> ConvRW["🔊 Woofer R FIR (convRW)"]:::fir
|
||||
ConvLW --> WLim["🛡️ Woofer Limiter (-2 dB Ceiling)"]:::limiter
|
||||
ConvRW --> WLim
|
||||
WLim --> WGuard["🛡️ Woofer Thermal Guard (500mW / 2.5s Tau)"]:::limiter
|
||||
end
|
||||
end
|
||||
|
||||
subgraph Stage4 ["4. Driver Safety Backstops & Output"]
|
||||
ConvLT --> TLim["🛡️ Tweeter Limiter (-1 dB Ceiling)"]:::limiter
|
||||
ConvRT --> TLim
|
||||
ConvLW --> WLim["🛡️ Woofer Limiter (-2 dB Ceiling)"]:::limiter
|
||||
ConvRW --> WLim
|
||||
|
||||
subgraph Stage4 ["4. Driver Output"]
|
||||
TLim --> Out["🔈 RawSpeakers Sink"]:::input
|
||||
WLim --> Out
|
||||
WGuard --> Out
|
||||
end
|
||||
|
||||
classDef input fill:#2d3748,stroke:#4a5568,color:#fff;
|
||||
@@ -77,6 +78,29 @@ flowchart TD
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Dual-Driver Virtual Thermal Guards & Power Caps
|
||||
|
||||
Because Linux cannot access the T2 hardware current-sensing ADCs, we implement a **Virtual Voice-Coil Thermal Model** that models continuous electrical power dissipation ($P = V_{\text{rms}}^2 / R_{\text{vc}}$) and exponential cooling into the air gap:
|
||||
|
||||
$$C_{\text{th}} \frac{d\Delta T(t)}{dt} = \frac{V_{\text{rms}}^2(t)}{R_{\text{vc}}} - \frac{\Delta T(t)}{R_{\text{th}}}$$
|
||||
|
||||
### Thermal Guard Configurations
|
||||
|
||||
* **Woofer Thermal Guard (`thermal_guard` @ Post-`wlim`):**
|
||||
* **Continuous Power Cap:** **$500\text{ mW}$ ($0.50\text{ W}$)** per channel ($8\%$ of max $6.25\text{ W}$ peak power).
|
||||
* **Linear RMS Threshold (`al`):** `0.282843` ($-10.97\text{ dBFS}$ RMS).
|
||||
* **Heating Tau ($\tau_{\text{heat}}$):** $2,500\text{ ms}$ (2.5 seconds).
|
||||
* **Cooling Tau ($\tau_{\text{cool}}$):** $5,000\text{ ms}$ (5.0 seconds).
|
||||
* **Tweeter Thermal Guard (`tweeter_thermal_guard` @ Pre-`tlim`):**
|
||||
* **Continuous Power Cap:** **$75\text{ mW}$ ($0.075\text{ W}$)** per channel ($1.2\%$ of max $6.25\text{ W}$ peak power).
|
||||
* **Linear RMS Threshold (`al`):** `0.109545` ($-19.21\text{ dBFS}$ RMS).
|
||||
* **Heating Tau ($\tau_{\text{heat}}$):** $1,000\text{ ms}$ (1.0 second, faster heating for smaller coil mass).
|
||||
* **Cooling Tau ($\tau_{\text{cool}}$):** $2,500\text{ ms}$ (2.5 seconds).
|
||||
|
||||
> **Acoustic Result:** Dynamic music (Blues, Classical, Rock) has high crest factor ($12\text{ dB} - 18\text{ dB}$) and operates at $0\text{ dB}$ gain reduction with full peak dynamics. Continuous high-power signals (full-volume white noise or sine sweeps) are automatically attenuated to harmless power levels after ~2 seconds.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### 1. Install Dependencies
|
||||
@@ -121,7 +145,7 @@ Customize tone settings without touching calibrated internal DSP nodes. `user_eq
|
||||
| **Electronic / Hip-Hop** | `1.26` | `1.19` | `1.00` | `0.94` | `1.00` | `1.00` | `1.06` | `1.00` |
|
||||
| **Movie (Dialogue Focus)**| `0.84` | `0.94` | `1.00` | `1.06` | `1.19` | `1.19` | `1.06` | `1.00` |
|
||||
| **Movie (Action / Bass)** | `1.41` | `1.12` | `1.00` | `1.00` | `1.00` | `1.06` | `1.12` | `1.12` |
|
||||
| **Late-Night (Low Level)** | `0.63` | `0.79` | `1.00` | `1.00` | `1.06` | `1.12` | `1.00` | `0.94` |
|
||||
| **Late-Night (Low Level)** | `0.63` | `0.79` | `1.00` | `1.00` | `1.06` | `1.19` | `1.00` | `0.94` |
|
||||
|
||||
*(Note: Gain values are linear multipliers: `1.0` = 0 dB, `1.41` ≈ +3 dB boost, `0.71` ≈ -3 dB cut)*
|
||||
|
||||
@@ -131,12 +155,24 @@ Customize tone settings without touching calibrated internal DSP nodes. `user_eq
|
||||
|
||||
If your specific physical unit requires custom acoustic tuning:
|
||||
|
||||
* **Woofer Ceiling:** Edit `wlim.control.limit` in `graph.json` (Default: `-2` dB. Lower to `-3` / `-4` dB for stricter mechanical protection).
|
||||
* **Bass Drive:** Adjust `equalizer.control` (`g_1` through `g_5`).
|
||||
* **Woofer Ceiling:** Edit `wlim.control.limit` in `graph.json` (Default: `0` dBFS into `thermal_guard`).
|
||||
* **Thermal Recalibration:** Edit `al` in `thermal_guard` (`al = sqrt(P_watts / 6.25W)`).
|
||||
* **Sub-Bass Synthesis:** Adjust `virtualbass.control.amt` (Default: `1.0`).
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ AT-YOUR-OWN-RISK DISCLAIMER & Replacement Resources
|
||||
|
||||
> [!CAUTION]
|
||||
> **USE AT YOUR OWN RISK:** This DSP engine processes micro-speakers with active equal-energy voicing curves and sub-bass synthesis. While dual virtual thermal guards ($500\text{ mW}$ woofers / $75\text{ mW}$ tweeters), excursion protection, and peak limiters are enabled by default to safeguard hardware, **modifying threshold limits, disabling protection nodes, or playing continuous full-volume synthetic square waves is done entirely at your own risk**. The authors and maintainers assume no responsibility or liability for damaged speaker cones, blown voice coils, or hardware failures.
|
||||
|
||||
### 🔧 Speaker Replacement & Repair Resources
|
||||
If you choose to push hardware limits or need to replace aged factory speakers:
|
||||
* 🛠️ **iFixit Repair Guide:** [MacBook Pro 15" Touch Bar 2018 Speaker Replacement - iFixit](https://www.ifixit.com/Guide/MacBook+Pro+15-Inch+Touch+Bar+2018+Right+Speaker+Replacement/122784)
|
||||
* 🛒 **Replacement Speaker Modules:** Search for MacBook Pro 15,1 / 15,2 (A1990 2018/2019) Left & Right Speaker Assemblies on [iFixit Parts](https://www.ifixit.com/Parts/MacBook_Pro_15%22_Touch_Bar) or [eBay A1990 Speakers](https://www.ebay.com/sch/i.html?_nkw=macbook+pro+a1990+speakers).
|
||||
|
||||
---
|
||||
|
||||
## 📚 Documentation & Repository Links
|
||||
|
||||
### 🔗 Repositories & Mirrors
|
||||
|
||||
77
graph.json
77
graph.json
@@ -11,7 +11,7 @@
|
||||
"enabled": 1, "mode": 0, "g_in": 1.0, "g_out": 1.5,
|
||||
"ft_0": 5, "f_0": 70.0, "g_0": 1.0, "q_0": 0.7, "s_0": 0,
|
||||
"ft_1": 1, "f_1": 110.0, "g_1": 1.0, "q_1": 1.0,
|
||||
"ft_2": 1, "f_2": 220.0, "g_2": 1.0, "q_2": 1.0,
|
||||
"ft_2": 1, "f_2": 220.0, "g_2": 0.95, "q_2": 1.0,
|
||||
"ft_3": 1, "f_3": 450.0, "g_3": 1.0, "q_3": 1.0,
|
||||
"ft_4": 1, "f_4": 1000.0, "g_4": 1.0, "q_4": 1.0,
|
||||
"ft_5": 1, "f_5": 2500.0, "g_5": 1.0, "q_5": 1.0,
|
||||
@@ -101,8 +101,7 @@
|
||||
"name": "ell",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"input": 1.0,
|
||||
"fft": 4
|
||||
"volume": 0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -111,8 +110,7 @@
|
||||
"name": "elr",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"input": 1.0,
|
||||
"fft": 4
|
||||
"volume": 0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -136,7 +134,7 @@
|
||||
"/usr/share/t2-linux-audio/15_1/tweeters-96k.wav"
|
||||
],
|
||||
"channel": 0,
|
||||
"gain": 1.2
|
||||
"gain": 1.1
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -150,7 +148,7 @@
|
||||
"/usr/share/t2-linux-audio/15_1/tweeters-96k.wav"
|
||||
],
|
||||
"channel": 0,
|
||||
"gain": 1.2
|
||||
"gain": 1.1
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -191,6 +189,52 @@
|
||||
"release": 0.25
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"name": "thermal_guard",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/sc_compressor_stereo",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"mode": 1,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.0,
|
||||
"at": 2500.0,
|
||||
"rt": 5000.0,
|
||||
"al": 0.282843,
|
||||
"cr": 4.0,
|
||||
"kn": 0.5,
|
||||
"scp": 1,
|
||||
"scm": 1,
|
||||
"__comment_thermal__": "VIRTUAL VOICE-COIL WOOFER THERMAL GUARD (500mW Rating)",
|
||||
"__comment_power__": "P_peak = V_peak^2 / R_vc = 5.0^2 / 4.0 = 6.25W Peak per Channel",
|
||||
"__comment_threshold__": "Linear RMS Threshold: al = sqrt(P_continuous / P_peak) = sqrt(0.50W / 6.25W) = sqrt(0.08) = 0.282843 (-10.97 dBFS)",
|
||||
"__comment_timing__": "Thermal Integration (at): 2500ms (2.5s heating tau), Thermal Cooling (rt): 5000ms (5.0s exponential decay into air gap)",
|
||||
"__comment_instructions__": "TO RECALIBRATE: Set al = sqrt(P_target_watts / 6.25W). Set at = tau_heat_ms, rt = tau_cool_ms."
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"name": "tweeter_thermal_guard",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/sc_compressor_stereo",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"mode": 1,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.0,
|
||||
"at": 1000.0,
|
||||
"rt": 2500.0,
|
||||
"al": 0.109545,
|
||||
"cr": 4.0,
|
||||
"kn": 0.5,
|
||||
"scp": 1,
|
||||
"scm": 1,
|
||||
"__comment_thermal__": "ULTRA-SAFE VIRTUAL VOICE-COIL TWEETER THERMAL GUARD (75mW Rating)",
|
||||
"__comment_power__": "P_peak = V_peak^2 / R_vc = 5.0^2 / 4.0 = 6.25W Peak per Channel",
|
||||
"__comment_threshold__": "Linear RMS Threshold: al = sqrt(P_continuous / P_peak) = sqrt(0.075W / 6.25W) = sqrt(0.012) = 0.109545 (-19.21 dBFS)",
|
||||
"__comment_timing__": "Thermal Integration (at): 1000ms (1.0s heating tau), Thermal Cooling (rt): 2500ms (2.5s exponential decay into air gap)",
|
||||
"__comment_instructions__": "TO RECALIBRATE: Set al = sqrt(P_target_watts / 6.25W). Set at = tau_heat_ms, rt = tau_cool_ms."
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"name": "tlim",
|
||||
@@ -219,16 +263,24 @@
|
||||
{"output": "copyR:Out", "input": "convRW:In"},
|
||||
{"output": "convLW:Out", "input": "wlim:in_1"},
|
||||
{"output": "convRW:Out", "input": "wlim:in_2"},
|
||||
{"output": "convLT:Out", "input": "tlim:in_1"},
|
||||
{"output": "convRT:Out", "input": "tlim:in_2"}
|
||||
{"output": "wlim:out_1", "input": "thermal_guard:in_l"},
|
||||
{"output": "wlim:out_2", "input": "thermal_guard:in_r"},
|
||||
{"output": "wlim:out_1", "input": "thermal_guard:sc_l"},
|
||||
{"output": "wlim:out_2", "input": "thermal_guard:sc_r"},
|
||||
{"output": "convLT:Out", "input": "tweeter_thermal_guard:in_l"},
|
||||
{"output": "convRT:Out", "input": "tweeter_thermal_guard:in_r"},
|
||||
{"output": "convLT:Out", "input": "tweeter_thermal_guard:sc_l"},
|
||||
{"output": "convRT:Out", "input": "tweeter_thermal_guard:sc_r"},
|
||||
{"output": "tweeter_thermal_guard:out_l", "input": "tlim:in_1"},
|
||||
{"output": "tweeter_thermal_guard:out_r", "input": "tlim:in_2"}
|
||||
],
|
||||
"inputs": [
|
||||
"user_eq:in_l",
|
||||
"user_eq:in_r"
|
||||
],
|
||||
"outputs": [
|
||||
"wlim:out_1",
|
||||
"wlim:out_2",
|
||||
"thermal_guard:out_l",
|
||||
"thermal_guard:out_r",
|
||||
"tlim:out_1",
|
||||
"tlim:out_2"
|
||||
],
|
||||
@@ -255,7 +307,8 @@
|
||||
"device.api": "dsp",
|
||||
"audio.allowed-rates": [48000, 44100],
|
||||
"node.virtual": "false",
|
||||
"priority.session": 1500,
|
||||
"priority.session": 2500,
|
||||
"priority.driver": 2500,
|
||||
"state.default-volume": 1.0,
|
||||
"device.icon-name": "audio-speakers"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user