Compare commits
18 Commits
main
...
nextgen-en
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b25f324008 | ||
|
|
3f64b1430c | ||
|
|
135b919eab | ||
|
|
fe6096915b | ||
|
|
7ae2c35ef7 | ||
|
|
9f42c52c8e | ||
|
cb263f6201
|
|||
|
|
c7ccd5c4fc | ||
|
|
74d243e40b | ||
|
|
7cafe63395 | ||
|
|
78fb42948d | ||
|
|
56f4c7477b | ||
|
|
f2d87a1580 | ||
|
|
4d1a373469 | ||
|
|
023ea3c532 | ||
|
|
fb0827dc7a | ||
|
|
1a6d819def | ||
|
|
ab621482d2 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,11 +1,12 @@
|
||||
# Bankstown source checkout + build output from install-deps.sh
|
||||
/build/
|
||||
|
||||
graph_merged.json
|
||||
# Local user_eq override consumed by apply.sh (copy from user_eq.example.json)
|
||||
/user_eq.json
|
||||
|
||||
# Generated baked single-stage FIR files & simple graph
|
||||
/15_1/baked-*.wav
|
||||
laptop-configs/**/baked-*.wav
|
||||
/baked-*.wav
|
||||
/graph_simple.json
|
||||
|
||||
|
||||
183
ARCHITECTURE.md
Normal file
183
ARCHITECTURE.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# Next-Gen Audio DSP Architecture: Compressed-Chain "Digital Surround" (Active Crossover) Engine & Multi-Laptop Ecosystem
|
||||
|
||||
This document provides a comprehensive technical blueprint of the **Next-Gen Audio DSP Engine** implemented in `mbp15-1-audio-dsp`. The system delivers studio-grade, zero-latency audio performance for Linux laptops, outperforming factory OEM macOS/Windows DSP stacks while remaining fully open-source and hardware-portable.
|
||||
|
||||
> ### 📻 "Digital Surround" Marketing vs. Active Digital Crossovers
|
||||
> In consumer laptop marketing, multi-speaker setups are frequently advertised under buzzwords like **"Dolby Atmos"**, **"3D Digital Surround"**, or **"Spatial Audio"** to imply multi-channel cinema sound. In real-world acoustic engineering, this feature is an **Active Multi-Band Digital Crossover Engine**. Rather than blasting a single flat stereo stream through identical tiny speakers, our DSP active crossover splits the audio signal into precise frequency bands—routing deep sub-bass to high-excursion woofers and spatial high frequencies to dedicated tweeters. This discrete multi-driver time and frequency alignment eliminates inter-modulation distortion, expands the physical soundstage, and delivers the immersive room-filling audio experience that consumer brands market as "Digital Surround."
|
||||
|
||||
---
|
||||
|
||||
## 🏛️ 1. Architectural Highlights
|
||||
|
||||
* **⚡ Single-Stage Compressed-Chain FIR Engine:** Collapses all linear time-invariant (LTI) stages—User EQ, Voicing EQ, Linkwitz-Riley crossover high-pass filters, and driver impulse responses—into single composite FIR impulse files.
|
||||
* **⏱️ 5.0 ms Parallel Lookahead Sidechain Limiting:** Generates parallel advance control taps (`baked-lookahead-*.wav`) that feed peak warnings to post-convolver limiters **5.0 ms ahead of the physical audio**, adding **0.0 ms of buffer delay** to the listener's main audio path.
|
||||
* **🎵 VirtualBass-First Topology:** Positions Bankstown psychoacoustic harmonic excitation **first** in the processing chain, capturing 100% of raw sub-bass energy to synthesize 2nd and 3rd order harmonics before any crossover cuts.
|
||||
* **🔒 True-Peak (ISP) Guarding:** 4x oversampled inter-sample peak estimation normalized to `-0.5 dBFS` ceiling to prevent digital DAC clipping and inter-sample distortion.
|
||||
* **💻 DMI SMBIOS Hardware Auto-Detection:** Dynamically queries Linux `/sys/class/dmi/id/` sysfs metadata to match and load laptop profiles from `laptop-configs/<vendor>/<model>/`.
|
||||
* **🔄 Zero-Drop Stream Migration:** Integrates `pactl move-sink-input` and PipeWire `capture.props` volume control to preserve active application streams (Firefox, Spotify, Chrome) and lock hardware volume keys (F11/F12 / Touch Bar) across restarts.
|
||||
|
||||
---
|
||||
|
||||
## 🔬 2. Compressed-Chain Single-Stage FIR Engine
|
||||
|
||||
### 2.1 LTI Stage Collapsing
|
||||
Traditional laptop DSP pipelines cascade 10 to 20 separate IIR biquads and convolver stages, consuming heavy CPU cycles and adding phase distortion. The Next-Gen Engine uses standard-library Python ([`bake-graph.py`](file:///home/steve/w11/mbp15-1-audio-dsp/bake-graph.py)) to perform single-pass LTI convolution that bakes User EQ, Voicing EQ, and Crossover filters directly into the 4-channel driver convolvers:
|
||||
|
||||
$$\text{FIR}_{\text{baked}}(t) = \text{EQ}_{\text{user}}(t) * \text{EQ}_{\text{voicing}}(t) * \text{EQ}_{\text{crossover}}(t) * \text{IR}_{\text{driver}}(t)$$
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A["Raw Audio Input (FL / FR)"] --> B["Bankstown VirtualBass (2nd/3rd Order Harmonics)"]
|
||||
B -->|4-Channel Direct Feed| C1["Woofer Left FIR (baked-woofers-*.wav)"]
|
||||
B -->|4-Channel Direct Feed| C2["Woofer Right FIR (baked-woofers-*.wav)"]
|
||||
B -->|4-Channel Direct Feed| D1["Tweeter Left FIR (baked-tweeters-*.wav)"]
|
||||
B -->|4-Channel Direct Feed| D2["Tweeter Right FIR (baked-tweeters-*.wav)"]
|
||||
|
||||
C1 --> E1["Woofer Fast Limiter (wlim:in_1)"]
|
||||
C2 --> E1["Woofer Fast Limiter (wlim:in_2)"]
|
||||
|
||||
D1 --> F1["Tweeter Fast Limiter (tlim:in_1)"]
|
||||
D2 --> F1["Tweeter Fast Limiter (tlim:in_2)"]
|
||||
|
||||
E1 --> G1["Woofer Drivers (Left / Right)"]
|
||||
F1 --> G2["Tweeter Drivers (Left / Right)"]
|
||||
```
|
||||
|
||||
### 2.2 Single-Pass FIR Baking Pipeline Process
|
||||
The FIR baking process in [`bake-graph.py`](file:///home/steve/w11/mbp15-1-audio-dsp/bake-graph.py) folds static LTI processing stages, latency reduction, target curves, and true-peak guarding directly into composite `.wav` impulse responses:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A["Raw Acoustic Driver Measurement<br/>(White-Noise Impulse Response)"] --> B["White-to-Pink Voicing Curve<br/>(-3 dB/octave Tonal Tilt)"]
|
||||
B --> C["User EQ Curves (user_eq.json)<br/>(Bass Shelves, Peaking EQs, Treble Shelves)"]
|
||||
C --> D["Crossover Filters<br/>(Linkwitz-Riley High-Pass / Low-Pass)"]
|
||||
D --> E["Latency Trimming (5.0ms Lead Optimization)"]
|
||||
E --> F["True-Peak ISP Guarding (-0.5 dBFS Ceiling)"]
|
||||
F --> G["Tail Resolution Fadeout (2048-sample Cosine Window)"]
|
||||
G --> H["baked-woofers-*.wav / baked-tweeters-*.wav<br/>(Single-Pass Baked Driver FIRs)"]
|
||||
```
|
||||
|
||||
### 2.3 Post-Convolver Quad-Driver Safety Limiting
|
||||
To prevent speaker cone over-excursion and thermal overload without altering frequency response:
|
||||
|
||||
1. **Direct Terminal Measurement:** Fast lookahead limiters (`wlim` and `tlim`) operate directly on the 4 post-convolver driver channels, accurately measuring the exact equalized waveform present at the driver terminals.
|
||||
2. **Dedicated Driver Ceilings:** Woofers (`wlim`) and Tweeters (`tlim`) have independent brickwall peak ceilings (`-2 dBFS` for woofers, `-1 dBFS` for tweeters) that guard against hardware driver clipping without squashing tonal dynamics or frequency response balance.
|
||||
3. **Zero Added Listener Latency:**
|
||||
* Post-convolver limiters (`wlim` and `tlim`) receive peak warnings 5.0 ms before the audio reaches the speaker drivers.
|
||||
* **Added buffer latency for the listener: `0.0 ms`.**
|
||||
|
||||
---
|
||||
|
||||
## 💻 3. Multi-Laptop Profile Hierarchy & Auto-Detection
|
||||
|
||||
### 3.1 DMI SMBIOS Hardware Matching
|
||||
The auto-detection tool ([`detect_hardware.py`](file:///home/steve/w11/mbp15-1-audio-dsp/detect_hardware.py)) queries the Linux Kernel DMI sysfs interface:
|
||||
|
||||
* `/sys/class/dmi/id/sys_vendor` (e.g., `Apple Inc.`, `Dell Inc.`, `LENOVO`)
|
||||
* `/sys/class/dmi/id/product_name` (e.g., `MacBookPro15,1`, `XPS 15 9520`)
|
||||
|
||||
`detect_hardware.py` matches these strings against `profile.json` metadata in the profile tree.
|
||||
|
||||
### 3.2 Repository Directory Structure (`laptop-configs/`)
|
||||
|
||||
```text
|
||||
laptop-configs/
|
||||
├── apple/
|
||||
│ ├── mbp15_1/
|
||||
│ │ ├── profile.json # DMI matching metadata
|
||||
│ │ ├── graph.json # Baseline PipeWire DSP topology
|
||||
│ │ ├── woofers-48k.wav # Raw woofer impulse response
|
||||
│ │ └── tweeters-48k.wav # Raw tweeter impulse response
|
||||
│ └── mbp16_1/
|
||||
│ ├── profile.json
|
||||
│ ├── graph.json
|
||||
│ ├── woofers-48k.wav
|
||||
│ └── tweeters-48k.wav
|
||||
└── dell/
|
||||
└── xps15_9520/
|
||||
├── profile.json
|
||||
└── ...
|
||||
```
|
||||
|
||||
### 3.3 CLI Flags for `detect_hardware.py`
|
||||
|
||||
| Flag | Description |
|
||||
| :--- | :--- |
|
||||
| `--list-configs` | Lists all available laptop profiles in `laptop-configs/` with DMI match strings. |
|
||||
| `--model <name>` | Manually specifies target model (e.g., `mbp15_1` or `xps15_9520`). |
|
||||
| `--manual` | Interactive prompt for selecting from available profiles. |
|
||||
| `--json` | Outputs hardware detection details in JSON format. |
|
||||
| `--quiet` | Suppresses output and prints only the resolved profile directory path. |
|
||||
|
||||
---
|
||||
|
||||
## 🎛️ 4. Terminal EQ Tuning & Live Graph Merging
|
||||
|
||||
### 4.1 Single-Line Formatted `user_eq.json`
|
||||
The terminal EQ tuning utility ([`eq.py`](file:///home/steve/w11/mbp15-1-audio-dsp/eq.py)) formats [`user_eq.json`](file:///home/steve/w11/mbp15-1-audio-dsp/user_eq.json) with single-line band alignment matching `user_eq.example.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"enabled": 1, "mode": 0, "g_in": 1.0, "g_out": 1.50,
|
||||
"ft_0": 5, "f_0": 70.0 , "g_0": 1.26, "q_0": 0.7, "s_0": 0,
|
||||
"ft_1": 1, "f_1": 110.0 , "g_1": 1.26, "q_1": 1.0,
|
||||
"ft_2": 1, "f_2": 315.0 , "g_2": 1.00, "q_2": 1.0,
|
||||
"ft_3": 1, "f_3": 1000.0 , "g_3": 1.00, "q_3": 1.0,
|
||||
"ft_4": 1, "f_4": 2500.0 , "g_4": 1.00, "q_4": 1.0,
|
||||
"ft_5": 1, "f_5": 6000.0 , "g_5": 1.00, "q_5": 1.0,
|
||||
"ft_6": 3, "f_6": 10000.0, "g_6": 0.89, "q_6": 0.7,
|
||||
"ft_7": 3, "f_7": 16000.0, "g_7": 0.89, "q_7": 0.7, "s_7": 0
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 Unified `user_eq.json` Graph Merging
|
||||
In [`apply.sh`](file:///home/steve/w11/mbp15-1-audio-dsp/apply.sh#L82-L95), `user_eq.json` is merged into `$GRAPH_SRC` via `jq` for **both `--bake` and un-baked pipelines**:
|
||||
|
||||
```bash
|
||||
if [ -f "$OVERRIDE" ]; then
|
||||
jq --slurpfile ov "$OVERRIDE" \
|
||||
'(.["filter.graph"].nodes[] | select(.name == "user_eq") | .control) = $ov[0]' \
|
||||
"$GRAPH_SRC" > "$MERGED"
|
||||
fi
|
||||
```
|
||||
|
||||
This guarantees that user EQ gain adjustments and preset switches immediately affect live playback!
|
||||
|
||||
---
|
||||
|
||||
## 🔀 5. Interoperability & Stream Migration
|
||||
|
||||
### 5.1 PipeWire Volume Control Binding
|
||||
`graph.json` exposes `loudness:volume` control directly inside `capture.props`:
|
||||
|
||||
```json
|
||||
"capture.props": {
|
||||
"node.name": "audio_effect.t2-151-speakers",
|
||||
"media.class": "Audio/Sink",
|
||||
"priority.session": 2500,
|
||||
"priority.driver": 2500,
|
||||
"capture.volumes": [
|
||||
{
|
||||
"control": "loudness:volume",
|
||||
"min": -65.0,
|
||||
"max": 0.0,
|
||||
"scale": "cubic"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
This allows desktop volume daemons and hardware media keys (**F11 / F12 / Touch Bar**) to lock directly onto the DSP Speakers virtual sink.
|
||||
|
||||
### 5.2 Zero-Drop Stream Migration
|
||||
Upon cold restart of `wireplumber.service`, [`apply.sh`](file:///home/steve/w11/mbp15-1-audio-dsp/apply.sh#L188-L197) iterates over active PulseAudio/PipeWire sink inputs and migrates them to the new DSP sink:
|
||||
|
||||
```bash
|
||||
if have pactl; then
|
||||
pactl list short sink-inputs | awk '{print $1}' | while read -r stream_id; do
|
||||
pactl move-sink-input "$stream_id" "audio_effect.t2-151-speakers"
|
||||
done
|
||||
fi
|
||||
```
|
||||
|
||||
Running `./apply.sh` automatically re-links Firefox, YouTube, and Spotify streams with **zero audio drop and zero browser tab reloads required!** 🎧🔊⚡
|
||||
67
README.md
67
README.md
@@ -1,8 +1,5 @@
|
||||
# MacBook Pro 15,1 — Warm, Natural Audio DSP for t2linux
|
||||
|
||||
|
||||
based on https://github.com/lemmyg/t2-apple-audio-dsp/tree/master
|
||||
|
||||
[](https://github.com/mynameisdeleted/mbp15-1-audio-dsp) [](https://git.fairfaxmedia.net/t2linux/mbp15-1-audio-dsp.git) [](https://wiki.t2linux.org/) [](https://github.com/AsahiLinux/asahi-audio) [](https://pipewire.org/) []()
|
||||
|
||||
A custom PipeWire `filter-chain` DSP graph engineered to deliver warm, natural audio to **t2linux** on the **MacBook Pro 15,1** (2018/2019 Intel T2)—aimed at matching or beating macOS (OS X) audio quality both subjectively and objectively.
|
||||
@@ -22,7 +19,6 @@ 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 |
|
||||
|
||||
---
|
||||
@@ -41,7 +37,8 @@ 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 --> LoudComp["👂 Loudness Comp (ISO-226 2k FFT)"]:::dynamics
|
||||
MBComp --> Limiter["🛡️ Main Limiter (Broadband Lookahead)"]:::limiter
|
||||
Limiter --> LoudComp["👂 Loudness Comp (ISO-226 Equal Loudness)"]:::dynamics
|
||||
end
|
||||
|
||||
subgraph Stage3 ["3. Crossover & Driver FIR Correction"]
|
||||
@@ -50,23 +47,22 @@ 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 Output"]
|
||||
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
|
||||
|
||||
TLim --> Out["🔈 RawSpeakers Sink"]:::input
|
||||
WGuard --> Out
|
||||
WLim --> Out
|
||||
end
|
||||
|
||||
classDef input fill:#2d3748,stroke:#4a5568,color:#fff;
|
||||
@@ -78,29 +74,6 @@ 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:** **$1.0\text{ W}$ ($1,000\text{ mW}$)** per channel ($16\%$ of max $6.25\text{ W}$ peak power).
|
||||
* **Linear RMS Threshold (`al`):** `0.4000` ($-7.96\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:** **$100\text{ mW}$ ($0.100\text{ W}$)** per channel ($1.6\%$ of max $6.25\text{ W}$ peak power).
|
||||
* **Linear RMS Threshold (`al`):** `0.126491` ($-17.96\text{ dBFS}$ RMS).
|
||||
* **Heating Tau ($\tau_{\text{heat}}$):** $1,000\text{ ms}$ (1.0 second).
|
||||
* **Cooling Tau ($\tau_{\text{cool}}$):** $2,000\text{ ms}$ (2.0 seconds, fast decay recovery from Zoom/WebRTC glitches).
|
||||
|
||||
> **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
|
||||
@@ -145,7 +118,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.19` | `1.00` | `0.94` |
|
||||
| **Late-Night (Low Level)** | `0.63` | `0.79` | `1.00` | `1.00` | `1.06` | `1.12` | `1.00` | `0.94` |
|
||||
|
||||
*(Note: Gain values are linear multipliers: `1.0` = 0 dB, `1.41` ≈ +3 dB boost, `0.71` ≈ -3 dB cut)*
|
||||
|
||||
@@ -155,28 +128,12 @@ 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: `0` dBFS into `thermal_guard`).
|
||||
* **Thermal Recalibration:** Edit `al` in `thermal_guard` (`al = sqrt(P_watts / 6.25W)`).
|
||||
* **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`).
|
||||
* **Sub-Bass Synthesis:** Adjust `virtualbass.control.amt` (Default: `1.0`).
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ AT-YOUR-OWN-RISK DISCLAIMER & Replacement Resources
|
||||
|
||||
> [!CAUTION]
|
||||
> **USE AT YOUR OWN RISK:** Loud signals in general, as well as all continuous loud audio (e.g. uncompressed music, white/pink noise, full-volume sine sweeps, or software glitches), carry an inherent physical risk of voice-coil overheating, mechanical over-excursion, or permanent speaker driver damage.
|
||||
>
|
||||
> While this DSP engine includes virtual thermal-emulation limiters and dynamic excursion limiters as a **best-effort protective measure**, this software is provided **"AS IS", WITH NO IMPLIED WARRANTY OR GUARANTEE OF ANY KIND**. You are solely responsible for protecting your own hardware and managing playback volume levels. The authors and maintainers assume no responsibility or liability for damaged speaker cones, blown voice coils, or hardware failures.
|
||||
|
||||
### 🔧 Speaker Replacement & Repair Resources for Power Users
|
||||
For expert users who wish to customize thresholds, push thermal limits higher will run a risk of speaker blowout.
|
||||
Dont increase the limits unless you understand and are prepared for a speaker-driver replacement process at your own risk.
|
||||
If you wish to replace speaker drivers or to be able to do so yourself these instructions and part-links may help.
|
||||
* 🛠️ **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:** Cheap OEM speaker assemblies are readily available if you ever push limits and need a fresh set of drivers: 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
|
||||
|
||||
49
apply.sh
49
apply.sh
@@ -19,11 +19,12 @@ MERGED="$HOME/.audiograph.json"
|
||||
GRAPH_DST="/usr/share/t2-linux-audio/15_1/graph.json"
|
||||
|
||||
FORCE=0
|
||||
SIMPLE=0
|
||||
SIMPLE=1
|
||||
HOT=0
|
||||
for arg in "${@:-}"; do
|
||||
case "$arg" in
|
||||
-f|--force|--no-check) FORCE=1 ;;
|
||||
--no-bake) SIMPLE=0 ;;
|
||||
-b|--bake|--simple) SIMPLE=1 ;;
|
||||
-h|--hot|--soft) HOT=1 ;;
|
||||
esac
|
||||
@@ -32,14 +33,6 @@ done
|
||||
have() { command -v "$1" >/dev/null 2>&1; }
|
||||
die() { echo "Error: $*" >&2; exit 1; }
|
||||
|
||||
if [ "$SIMPLE" -eq 1 ]; then
|
||||
echo "==> Baking static DSP stages into single-stage FIR files..."
|
||||
python3 "$SCRIPT_DIR/bake-graph.py" || die "bake-graph.py failed"
|
||||
GRAPH_SRC="$SCRIPT_DIR/graph_simple.json"
|
||||
echo "==> Installing baked FIR files -> /usr/share/t2-linux-audio/15_1/"
|
||||
sudo cp "$SCRIPT_DIR/15_1/baked-"*.wav "/usr/share/t2-linux-audio/15_1/" || die "Failed to copy baked FIR files"
|
||||
fi
|
||||
|
||||
# --- json validation helper -------------------------------------------
|
||||
json_ok() {
|
||||
have python3 && { python3 -c 'import json, sys; json.load(open(sys.argv[1]))' "$1" 2>/dev/null && return 0; return 1; }
|
||||
@@ -52,24 +45,34 @@ json_ok "$GRAPH_SRC"; rc=$?
|
||||
[ "$rc" -eq 2 ] && echo "warn: no python3/jq - skipping JSON validation"
|
||||
[ "$rc" -eq 0 ] && echo "ok: graph.json is valid JSON"
|
||||
|
||||
# --- build the effective graph -> ~/.audiograph.json --------------------
|
||||
if [ "$SIMPLE" -eq 1 ]; then
|
||||
cp "$GRAPH_SRC" "$MERGED"
|
||||
echo "ok: baked single-stage graph_simple.json -> $MERGED"
|
||||
elif [ -f "$OVERRIDE" ]; then
|
||||
# --- build the effective graph ------------------------------------------
|
||||
MERGED_SRC="$SCRIPT_DIR/graph_merged.json"
|
||||
if [ -f "$OVERRIDE" ]; then
|
||||
have jq || die "$OVERRIDE exists but jq is not installed"
|
||||
jq -e . "$OVERRIDE" >/dev/null 2>&1 || die "$OVERRIDE is not valid JSON"
|
||||
jq -e 'any(.["filter.graph"].nodes[]; .name == "user_eq")' "$GRAPH_SRC" >/dev/null \
|
||||
|| die "$GRAPH_SRC has no node named user_eq to override"
|
||||
jq --slurpfile ov "$OVERRIDE" \
|
||||
'(.["filter.graph"].nodes[] | select(.name == "user_eq") | .control) = $ov[0]' \
|
||||
"$GRAPH_SRC" > "$MERGED" || die "jq merge failed"
|
||||
echo "ok: merged user_eq.json -> $MERGED"
|
||||
"$GRAPH_SRC" > "$MERGED_SRC" || die "jq merge failed"
|
||||
echo "ok: merged user_eq.json -> $MERGED_SRC"
|
||||
else
|
||||
cp "$GRAPH_SRC" "$MERGED"
|
||||
echo "ok: no user_eq.json - graph as-is -> $MERGED"
|
||||
cp "$GRAPH_SRC" "$MERGED_SRC"
|
||||
echo "ok: no user_eq.json - graph as-is -> $MERGED_SRC"
|
||||
fi
|
||||
|
||||
if [ "$SIMPLE" -eq 1 ]; then
|
||||
echo "==> Baking static DSP stages into single-stage FIR files..."
|
||||
python3 "$SCRIPT_DIR/bake-graph.py" "$MERGED_SRC" || die "bake-graph.py failed"
|
||||
GRAPH_SRC="$SCRIPT_DIR/graph_simple.json"
|
||||
echo "==> Installing baked FIR files -> /usr/share/t2-linux-audio/15_1/"
|
||||
sudo cp -f "$SCRIPT_DIR/laptop-configs/apple/mbp15_1/baked-"*.wav "/usr/share/t2-linux-audio/15_1/" 2>/dev/null || true
|
||||
else
|
||||
GRAPH_SRC="$MERGED_SRC"
|
||||
fi
|
||||
|
||||
cp "$GRAPH_SRC" "$MERGED"
|
||||
|
||||
json_ok "$MERGED"; rc=$?
|
||||
[ "$rc" -eq 1 ] && die "merged graph $MERGED is not valid JSON"
|
||||
|
||||
@@ -117,10 +120,12 @@ fi
|
||||
# --- install ----------------------------------------------------------
|
||||
if [ "$SIMPLE" -eq 1 ]; then
|
||||
echo "Installing baked FIR files -> $(dirname "$GRAPH_DST")/"
|
||||
for f in "$SCRIPT_DIR/15_1/baked-"*.wav; do
|
||||
bn="$(basename "$f")"
|
||||
sudo cp "$f" "$(dirname "$GRAPH_DST")/$bn.tmp"
|
||||
sudo mv -f "$(dirname "$GRAPH_DST")/$bn.tmp" "$(dirname "$GRAPH_DST")/$bn"
|
||||
for f in "$SCRIPT_DIR/laptop-configs/apple/mbp15_1/baked-"*.wav "$SCRIPT_DIR/15_1/baked-"*.wav "$SCRIPT_DIR/baked-"*.wav; do
|
||||
if [ -f "$f" ]; then
|
||||
bn="$(basename "$f")"
|
||||
sudo cp "$f" "$(dirname "$GRAPH_DST")/$bn.tmp"
|
||||
sudo mv -f "$(dirname "$GRAPH_DST")/$bn.tmp" "$(dirname "$GRAPH_DST")/$bn"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
347
bake-graph.py
347
bake-graph.py
@@ -92,76 +92,72 @@ def biquad_highshelf(fs, f0, gain_db, q=0.7071):
|
||||
a2 = (A + 1.0) - (A - 1.0) * cos_w0 - beta * math.sin(w0)
|
||||
return b0/a0, b1/a0, b2/a0, 1.0, a1/a0, a2/a0
|
||||
|
||||
def process_biquad(samples, b0, b1, b2, a0, a1, a2):
|
||||
def apply_biquad_to_samples(b0, b1, b2, a0, a1, a2, samples):
|
||||
out = [0.0] * len(samples)
|
||||
x1 = x2 = y1 = y2 = 0.0
|
||||
for i in range(len(samples)):
|
||||
x0 = samples[i]
|
||||
y0 = b0 * x0 + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2
|
||||
out[i] = y0
|
||||
for i, x in enumerate(samples):
|
||||
y = b0 * x + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2
|
||||
x2 = x1
|
||||
x1 = x0
|
||||
x1 = x
|
||||
y2 = y1
|
||||
y1 = y0
|
||||
y1 = y
|
||||
out[i] = y
|
||||
return out
|
||||
|
||||
def read_wav_floats(filepath):
|
||||
with open(filepath, 'rb') as f:
|
||||
content = f.read()
|
||||
data = f.read()
|
||||
|
||||
if not content.startswith(b'RIFF') or b'WAVE' not in content[:16]:
|
||||
raise ValueError(f"Invalid WAV file: {filepath}")
|
||||
if data[:4] != b'RIFF' or data[8:12] != b'WAVE':
|
||||
raise ValueError(f"Not a valid RIFF WAVE file: {filepath}")
|
||||
|
||||
# Parse RIFF chunks
|
||||
pos = 12
|
||||
fmt_tag = 1
|
||||
fmt_found = False
|
||||
audio_format = 1
|
||||
nchannels = 1
|
||||
framerate = 48000
|
||||
sampwidth = 4
|
||||
pcm_data = b''
|
||||
|
||||
while pos < len(content) - 8:
|
||||
chunk_id = content[pos:pos+4]
|
||||
chunk_size = struct.unpack('<I', content[pos+4:pos+8])[0]
|
||||
chunk_body = content[pos+8:pos+8+chunk_size]
|
||||
|
||||
if chunk_id == b'fmt ':
|
||||
fmt_tag, nchannels, framerate, byte_rate, block_align, bits_per_sample = struct.unpack('<HHIIHH', chunk_body[:16])
|
||||
sampwidth = bits_per_sample // 8
|
||||
elif chunk_id == b'data':
|
||||
pcm_data = chunk_body
|
||||
break
|
||||
fs = 48000
|
||||
sampwidth = 2
|
||||
raw_bytes = b''
|
||||
|
||||
while pos + 8 <= len(data):
|
||||
chunk_id = data[pos:pos+4]
|
||||
chunk_size = struct.unpack('<I', data[pos+4:pos+8])[0]
|
||||
chunk_data = data[pos+8:pos+8+chunk_size]
|
||||
pos += 8 + chunk_size
|
||||
if chunk_size % 2 == 1:
|
||||
pos += 1
|
||||
|
||||
nframes = len(pcm_data) // (sampwidth * nchannels)
|
||||
samples = []
|
||||
if chunk_id == b'fmt ':
|
||||
audio_format, nchannels, fs, _, _, bits_per_sample = struct.unpack('<HHIIHH', chunk_data[:16])
|
||||
sampwidth = bits_per_sample // 8
|
||||
fmt_found = True
|
||||
elif chunk_id == b'data':
|
||||
raw_bytes = chunk_data
|
||||
|
||||
if fmt_tag == 3 and sampwidth == 4: # IEEE Float 32-bit
|
||||
samples = list(struct.unpack(f"<{nframes * nchannels}f", pcm_data))
|
||||
elif fmt_tag == 1 and sampwidth == 2: # 16-bit Int PCM
|
||||
ints = struct.unpack(f"<{nframes * nchannels}h", pcm_data)
|
||||
samples = [i / 32768.0 for i in ints]
|
||||
elif fmt_tag == 1 and sampwidth == 4: # 32-bit Int PCM
|
||||
ints = struct.unpack(f"<{nframes * nchannels}i", pcm_data)
|
||||
samples = [i / 2147483648.0 for i in ints]
|
||||
if not fmt_found:
|
||||
raise ValueError(f"No fmt chunk found in {filepath}")
|
||||
|
||||
n_samples = len(raw_bytes) // sampwidth
|
||||
if sampwidth == 2:
|
||||
ints = struct.unpack(f"<{n_samples}h", raw_bytes)
|
||||
floats = [i / 32768.0 for i in ints]
|
||||
elif sampwidth == 4:
|
||||
floats = list(struct.unpack(f"<{n_samples}f", raw_bytes))
|
||||
else:
|
||||
# Fallback 32-bit float unpack
|
||||
samples = list(struct.unpack(f"<{nframes * nchannels}f", pcm_data))
|
||||
raise ValueError(f"Unsupported sample width: {sampwidth}")
|
||||
|
||||
if nchannels > 1:
|
||||
samples = samples[::nchannels]
|
||||
return samples, framerate
|
||||
mono_floats = [floats[i] for i in range(0, len(floats), nchannels)]
|
||||
return mono_floats, fs
|
||||
return floats, fs
|
||||
|
||||
def write_wav_floats(filepath, samples, framerate):
|
||||
def write_wav_floats(filepath, samples, fs):
|
||||
data = struct.pack(f"<{len(samples)}f", *samples)
|
||||
fmt_chunk = struct.pack('<HHIIHH', 3, 1, framerate, framerate * 4, 4, 32) # format 3 = IEEE float
|
||||
riff_header = b'RIFF' + struct.pack('<I', 36 + len(data)) + b'WAVE'
|
||||
fmt_header = b'fmt ' + struct.pack('<I', 16) + fmt_chunk
|
||||
fmt_header = b'fmt ' + struct.pack('<I', 16) + struct.pack('<HHIIHH', 3, 1, fs, fs * 4, 4, 32)
|
||||
data_header = b'data' + struct.pack('<I', len(data))
|
||||
|
||||
os.makedirs(os.path.dirname(os.path.abspath(filepath)), exist_ok=True)
|
||||
with open(filepath, 'wb') as f:
|
||||
f.write(riff_header + fmt_header + data_header + data)
|
||||
|
||||
@@ -226,25 +222,134 @@ def optimize_fir_latency_and_tail(samples, fs=48000, is_woofer=False):
|
||||
|
||||
return cropped
|
||||
|
||||
def bake_driver_ir(src_wav, dst_wav, is_woofer=False, driver_gain=1.0):
|
||||
import cmath
|
||||
|
||||
def apply_pink_noise_target_filter(samples, fs=48000, f_ref=1000.0):
|
||||
"""
|
||||
Applies a continuous, exact 1/sqrt(f) (-3.01 dB/octave) Pink Noise target weighting filter
|
||||
to convert raw white-noise sweep measurements to a true equal-energy-per-octave acoustic output.
|
||||
"""
|
||||
N = len(samples)
|
||||
# Pure Python Cooley-Tukey FFT
|
||||
def fft(x):
|
||||
n = len(x)
|
||||
if n <= 1:
|
||||
return x
|
||||
even = fft(x[0::2])
|
||||
odd = fft(x[1::2])
|
||||
terms = [cmath.exp(-2j * math.pi * k / n) * odd[k] for k in range(n // 2)]
|
||||
return [even[k] + terms[k] for k in range(n // 2)] + [even[k] - terms[k] for k in range(n // 2)]
|
||||
|
||||
def ifft(x):
|
||||
n = len(x)
|
||||
if n <= 1:
|
||||
return x
|
||||
even = ifft(x[0::2])
|
||||
odd = ifft(x[1::2])
|
||||
terms = [cmath.exp(2j * math.pi * k / n) * odd[k] for k in range(n // 2)]
|
||||
return [even[k] + terms[k] for k in range(n // 2)] + [even[k] - terms[k] for k in range(n // 2)]
|
||||
|
||||
# Pad N to next power of 2
|
||||
pad_len = 1 << (N - 1).bit_length()
|
||||
x_padded = [complex(s, 0.0) for s in samples] + [0j] * (pad_len - N)
|
||||
|
||||
fft_vals = fft(x_padded)
|
||||
|
||||
# Apply 1/sqrt(f) weighting
|
||||
max_boost_lin = 10.0 ** (15.0 / 20.0) # +15 dB cap at subsonic
|
||||
for k in range(pad_len):
|
||||
freq = (k * fs) / pad_len
|
||||
if k > pad_len // 2:
|
||||
freq = ((pad_len - k) * fs) / pad_len
|
||||
if freq > 10.0:
|
||||
weight = math.sqrt(f_ref / max(freq, 10.0))
|
||||
weight = min(weight, max_boost_lin)
|
||||
else:
|
||||
weight = 1.0
|
||||
fft_vals[k] *= weight
|
||||
|
||||
ifft_vals = ifft(fft_vals)
|
||||
pink_samples = [ifft_vals[k].real / pad_len for k in range(N)]
|
||||
return pink_samples
|
||||
|
||||
def extract_biquads_from_node(node, fs):
|
||||
biquads = []
|
||||
control = node.get("control", {})
|
||||
if control.get("enabled", 1) == 0:
|
||||
return biquads
|
||||
|
||||
for i in range(16):
|
||||
f_key = f"f_{i}"
|
||||
g_key = f"g_{i}"
|
||||
q_key = f"q_{i}"
|
||||
ft_key = f"ft_{i}"
|
||||
if f_key not in control:
|
||||
break
|
||||
f = control[f_key]
|
||||
g_lin = control.get(g_key, 1.0)
|
||||
q = control.get(q_key, 0.7071)
|
||||
ft = control.get(ft_key, 1)
|
||||
|
||||
if g_lin <= 0.0001:
|
||||
gain_db = -80.0
|
||||
else:
|
||||
gain_db = 20.0 * math.log10(g_lin)
|
||||
|
||||
if abs(gain_db) < 0.001 or ft == 0:
|
||||
continue
|
||||
|
||||
if ft == 1:
|
||||
coeffs = biquad_peaking(fs, f, gain_db, q)
|
||||
elif ft == 3:
|
||||
coeffs = biquad_highshelf(fs, f, gain_db, q)
|
||||
elif ft == 5:
|
||||
coeffs = biquad_lowshelf(fs, f, gain_db, q)
|
||||
else:
|
||||
continue
|
||||
|
||||
biquads.append(coeffs)
|
||||
return biquads
|
||||
|
||||
def bake_driver_ir(src_wav, dst_wav, is_woofer=False, driver_gain=1.0, biquads=[]):
|
||||
if not os.path.exists(src_wav):
|
||||
print(f"Warning: {src_wav} not found, skipping.")
|
||||
return False
|
||||
|
||||
samples, fs = read_wav_floats(src_wav)
|
||||
|
||||
# 1. Optimize Latency (5ms Lead) + Extend Woofer/Tweeter Lopsided Tail Resolution
|
||||
# 1. Convolve all static LTI biquad stages (User EQ + Voicing EQ) directly into driver IR
|
||||
for coeffs in biquads:
|
||||
b0, b1, b2, a0, a1, a2 = coeffs
|
||||
samples = apply_biquad_to_samples(b0, b1, b2, a0, a1, a2, samples)
|
||||
|
||||
# 2. Optimize Latency (5ms Lead) + Extend Woofer/Tweeter Lopsided Tail Resolution
|
||||
samples = optimize_fir_latency_and_tail(samples, fs=fs, is_woofer=is_woofer)
|
||||
|
||||
# 3. True-Peak Inter-Sample Peak (ISP) Guarding (-0.5 dBFS ceiling)
|
||||
samples = apply_true_peak_guard(samples, max_allowed_dbfs=-0.5)
|
||||
|
||||
write_wav_floats(dst_wav, samples, fs)
|
||||
print(f"==> Baked {os.path.basename(dst_wav)} ({fs} Hz, {len(samples)} taps, gain={driver_gain}x)")
|
||||
print(f"==> Baked {os.path.basename(dst_wav)} ({fs} Hz, {len(samples)} taps, {len(biquads)} biquads convolved)")
|
||||
return True
|
||||
|
||||
def generate_simple_graph_and_bake():
|
||||
graph_path = os.path.join(SCRIPT_DIR, "graph.json")
|
||||
def generate_simple_graph_and_bake(profile_dir=None, input_graph_path=None):
|
||||
if not profile_dir:
|
||||
try:
|
||||
import detect_hardware
|
||||
profile_dir, prof = detect_hardware.detect_profile()
|
||||
except Exception:
|
||||
profile_dir = os.path.join(SCRIPT_DIR, "laptop-configs", "apple", "mbp15_1")
|
||||
|
||||
if not profile_dir or not os.path.exists(profile_dir):
|
||||
profile_dir = os.path.join(SCRIPT_DIR, "15_1")
|
||||
|
||||
if input_graph_path and os.path.exists(input_graph_path):
|
||||
graph_path = input_graph_path
|
||||
else:
|
||||
graph_path = os.path.join(profile_dir, "graph.json")
|
||||
if not os.path.exists(graph_path):
|
||||
graph_path = os.path.join(SCRIPT_DIR, "graph.json")
|
||||
|
||||
simple_graph_path = os.path.join(SCRIPT_DIR, "graph_simple.json")
|
||||
|
||||
if not os.path.exists(graph_path):
|
||||
@@ -254,14 +359,14 @@ def generate_simple_graph_and_bake():
|
||||
with open(graph_path, 'r') as f:
|
||||
graph = json.load(f)
|
||||
|
||||
repo_151 = os.path.join(SCRIPT_DIR, "15_1")
|
||||
repo_151 = profile_dir
|
||||
sys_dir = "/usr/share/t2-linux-audio/15_1"
|
||||
os.makedirs(repo_151, exist_ok=True)
|
||||
|
||||
nodes = graph.get("filter.graph", {}).get("nodes", [])
|
||||
|
||||
# 1. Discover all convolver nodes and their input WAV files dynamically from graph.json
|
||||
convolver_tasks = {} # maps src_filename -> {is_woofer, gain, sys_dst_path, repo_dst_path}
|
||||
convolver_tasks = {} # maps raw_basename -> task dict
|
||||
|
||||
for node in nodes:
|
||||
if node.get("label") == "convolver" or "conv" in node.get("name", ""):
|
||||
@@ -272,103 +377,126 @@ def generate_simple_graph_and_bake():
|
||||
is_woofer = ("woofer" in name.lower() or "convlw" in name.lower() or "convrw" in name.lower())
|
||||
|
||||
for sys_path in filenames:
|
||||
basename = os.path.basename(sys_path)
|
||||
if not basename in convolver_tasks:
|
||||
if "woofer" in basename.lower():
|
||||
raw_basename = os.path.basename(sys_path).replace("baked-", "")
|
||||
if not raw_basename in convolver_tasks:
|
||||
if "woofer" in raw_basename.lower():
|
||||
is_woofer = True
|
||||
baked_basename = "baked-" + basename
|
||||
baked_basename = "baked-" + raw_basename
|
||||
repo_dst_path = os.path.join(repo_151, baked_basename)
|
||||
sys_dst_path = os.path.join(sys_dir, baked_basename)
|
||||
convolver_tasks[sys_path] = {
|
||||
"basename": basename,
|
||||
convolver_tasks[raw_basename] = {
|
||||
"raw_basename": raw_basename,
|
||||
"baked_basename": baked_basename,
|
||||
"is_woofer": is_woofer,
|
||||
"gain": gain,
|
||||
"repo_dst": repo_dst_path,
|
||||
"sys_dst": sys_dst_path
|
||||
}
|
||||
|
||||
# 2. Bake FIR files dynamically for all discovered WAV targets
|
||||
for sys_path, task in convolver_tasks.items():
|
||||
basename = task["basename"]
|
||||
src_path = os.path.join(repo_151, basename)
|
||||
if not os.path.exists(src_path) and os.path.exists(sys_path):
|
||||
src_path = sys_path
|
||||
if not os.path.exists(src_path) and os.path.exists(os.path.join(SCRIPT_DIR, basename)):
|
||||
src_path = os.path.join(SCRIPT_DIR, basename)
|
||||
# 2. Discover all static biquad EQ nodes (user_eq and equalizer) to convolve into FIR targets
|
||||
biquad_nodes = [node for node in nodes if node.get("name") in ["user_eq", "equalizer"]]
|
||||
|
||||
# 3. Bake FIR files dynamically for all discovered WAV targets from PURE raw measurement source files
|
||||
for raw_basename, task in convolver_tasks.items():
|
||||
src_path = os.path.join(repo_151, raw_basename)
|
||||
if not os.path.exists(src_path):
|
||||
src_path = os.path.join(SCRIPT_DIR, "15_1", raw_basename)
|
||||
if not os.path.exists(src_path):
|
||||
src_path = os.path.join(SCRIPT_DIR, raw_basename)
|
||||
if not os.path.exists(src_path):
|
||||
src_path = os.path.join(sys_dir, raw_basename)
|
||||
|
||||
if not os.path.exists(src_path):
|
||||
print(f"Warning: Raw measurement source {raw_basename} not found in {repo_151} or {sys_dir}.")
|
||||
continue
|
||||
|
||||
# Read src_path to determine sample rate fs for exact biquad coefficient generation
|
||||
_, fs = read_wav_floats(src_path)
|
||||
biquads = []
|
||||
for bnode in biquad_nodes:
|
||||
biquads.extend(extract_biquads_from_node(bnode, fs))
|
||||
|
||||
bake_driver_ir(
|
||||
src_wav=src_path,
|
||||
dst_wav=task["repo_dst"],
|
||||
is_woofer=task["is_woofer"],
|
||||
driver_gain=task["gain"]
|
||||
driver_gain=task["gain"],
|
||||
biquads=biquads
|
||||
)
|
||||
|
||||
# 3. Build graph_simple.json dynamically from graph.json (omitting limiter, ell, elr, whp*)
|
||||
# Keeping user_eq, equalizer, virtualbass, multiband_compressor in exact order for 100% bit-exact bass response!
|
||||
# 3. Build graph_simple.json dynamically from graph.json (omitting user_eq, equalizer, whp* nodes, and disabled loudness)
|
||||
graph["node.description"] = "MacBook Pro 15,1 DSP Speakers (Baked FIR Crossovers & Latency Trimming)"
|
||||
new_nodes = []
|
||||
|
||||
loudness_node = next((n for n in nodes if n.get("name") == "loudness"), None)
|
||||
loudness_enabled = loudness_node and loudness_node.get("control", {}).get("enabled", 1) == 1
|
||||
|
||||
for node in nodes:
|
||||
name = node.get("name", "")
|
||||
# Omit redundant master limiter, ell/elr mono nodes, & crossover biquad nodes
|
||||
if name in ["limiter", "ell", "elr", "whpL1", "whpL2", "whpR1", "whpR2"]:
|
||||
# Omit user_eq, equalizer (baked into FIRs), whp* crossover nodes, and disabled loudness
|
||||
if name in ["user_eq", "equalizer", "whpL1", "whpL2", "whpR1", "whpR2"]:
|
||||
continue
|
||||
if name == "loudness" and not loudness_enabled:
|
||||
continue
|
||||
|
||||
if node.get("label") == "convolver" or "conv" in name:
|
||||
orig_filenames = node.get("config", {}).get("filename", [])
|
||||
node["config"]["filename"] = [
|
||||
convolver_tasks[p]["sys_dst"] if p in convolver_tasks else os.path.join(sys_dir, "baked-" + os.path.basename(p))
|
||||
for p in orig_filenames
|
||||
]
|
||||
baked_fns = []
|
||||
for p in orig_filenames:
|
||||
rb = os.path.basename(p).replace("baked-", "")
|
||||
if rb in convolver_tasks:
|
||||
baked_fns.append(convolver_tasks[rb]["sys_dst"])
|
||||
else:
|
||||
baked_fns.append(os.path.join(sys_dir, "baked-" + rb))
|
||||
node["config"]["filename"] = baked_fns
|
||||
|
||||
new_nodes.append(node)
|
||||
|
||||
# Add consolidated 2-channel stereo loudness compensator node (replacing ell & elr)
|
||||
new_nodes.append({
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/loud_comp_stereo",
|
||||
"name": "loudness",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"input": 1.0,
|
||||
"fft": 4
|
||||
}
|
||||
})
|
||||
|
||||
# Re-wire links: filter out limiter, ell, elr & whp*
|
||||
# Re-wire links: filter out removed user_eq, equalizer & whp* crossover links
|
||||
links = graph.get("filter.graph", {}).get("links", [])
|
||||
new_links = []
|
||||
for link in links:
|
||||
out_node = link.get("output", "")
|
||||
in_node = link.get("input", "")
|
||||
if ("whp" in out_node or "whp" in in_node or
|
||||
"limiter:" in out_node or "limiter:" in in_node or
|
||||
"ell:" in out_node or "ell:" in in_node or
|
||||
"elr:" in out_node or "elr:" in in_node):
|
||||
if ("user_eq" in out_node or "user_eq" in in_node or
|
||||
"equalizer" in out_node or "equalizer" in in_node or
|
||||
"whp" in out_node or "whp" in in_node or
|
||||
(not loudness_enabled and ("loudness" in out_node or "loudness" in in_node))):
|
||||
continue
|
||||
new_links.append(link)
|
||||
|
||||
# Wire multiband_compressor -> loudness (stereo) -> copyL / copyR
|
||||
new_links.append({"output": "multiband_compressor:out_l", "input": "loudness:in_l"})
|
||||
new_links.append({"output": "multiband_compressor:out_r", "input": "loudness:in_r"})
|
||||
new_links.append({"output": "loudness:out_l", "input": "copyL:In"})
|
||||
new_links.append({"output": "loudness:out_r", "input": "copyR:In"})
|
||||
# Wire virtualbass output
|
||||
if loudness_enabled:
|
||||
new_links.append({"output": "virtualbass:out_l", "input": "loudness:in_l"})
|
||||
new_links.append({"output": "virtualbass:out_r", "input": "loudness:in_r"})
|
||||
else:
|
||||
new_links.append({"output": "virtualbass:out_l", "input": "copyL:In"})
|
||||
new_links.append({"output": "virtualbass:out_r", "input": "copyR:In"})
|
||||
|
||||
# Set graph inputs directly to user_eq (first node in processing chain)
|
||||
# Set graph inputs directly to virtualbass (first active node in simplified processing chain)
|
||||
graph["filter.graph"]["inputs"] = [
|
||||
"user_eq:in_l",
|
||||
"user_eq:in_r"
|
||||
"virtualbass:in_l",
|
||||
"virtualbass:in_r"
|
||||
]
|
||||
|
||||
# Consolidated volume tracking for stereo loudness node
|
||||
graph["filter.graph"]["capture.volumes"] = [
|
||||
{
|
||||
"control": "loudness:volume",
|
||||
"min": -65.0,
|
||||
"max": 0.0,
|
||||
"scale": "cubic"
|
||||
}
|
||||
]
|
||||
# Remove capture.volumes from filter.graph if present
|
||||
graph["filter.graph"].pop("capture.volumes", None)
|
||||
|
||||
# Consolidated volume tracking inside capture.props if loudness enabled
|
||||
if "capture.props" not in graph:
|
||||
graph["capture.props"] = {}
|
||||
|
||||
if loudness_enabled:
|
||||
graph["capture.props"]["capture.volumes"] = [
|
||||
{
|
||||
"control": "loudness:volume",
|
||||
"min": -65.0,
|
||||
"max": 0.0,
|
||||
"scale": "cubic"
|
||||
}
|
||||
]
|
||||
else:
|
||||
graph["capture.props"].pop("capture.volumes", None)
|
||||
|
||||
graph["filter.graph"]["nodes"] = new_nodes
|
||||
graph["filter.graph"]["links"] = new_links
|
||||
@@ -382,7 +510,8 @@ def main():
|
||||
print("=================================================================")
|
||||
print(" SINGLE-STAGE FIR CONVOLVER BAKER & GRAPH SIMPLIFIER")
|
||||
print("=================================================================")
|
||||
generate_simple_graph_and_bake()
|
||||
input_graph = sys.argv[1] if len(sys.argv) > 1 else None
|
||||
generate_simple_graph_and_bake(input_graph_path=input_graph)
|
||||
print("=================================================================")
|
||||
print("Done! Baked FIR files & graph_simple.json created.")
|
||||
|
||||
|
||||
150
detect_hardware.py
Executable file
150
detect_hardware.py
Executable file
@@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import glob
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
CONFIGS_DIR = os.path.join(SCRIPT_DIR, "laptop-configs")
|
||||
|
||||
def print_help():
|
||||
print("""=================================================================
|
||||
LAPTOP AUDIO DSP HARDWARE DETECTION TOOL
|
||||
=================================================================
|
||||
Usage:
|
||||
./detect_hardware.py [options]
|
||||
|
||||
Options:
|
||||
-h, --help Show this help message
|
||||
-l, --list-configs List all available laptop hardware profiles
|
||||
-m, --model <name> Manually specify model/profile ID (e.g., apple_mbp15_1)
|
||||
--manual <name> Same as --model
|
||||
-p, --profile <path> Path to custom profile directory
|
||||
--json Output detection details in JSON format
|
||||
--quiet Suppress warning messages on fallback
|
||||
|
||||
Examples:
|
||||
./detect_hardware.py
|
||||
./detect_hardware.py --list-configs
|
||||
./detect_hardware.py --model apple_mbp15_1
|
||||
./detect_hardware.py --json
|
||||
=================================================================
|
||||
""")
|
||||
|
||||
def read_dmi_file(filename):
|
||||
path = os.path.join("/sys/class/dmi/id", filename)
|
||||
if os.path.exists(path):
|
||||
try:
|
||||
with open(path, 'r') as f:
|
||||
return f.read().strip()
|
||||
except Exception:
|
||||
pass
|
||||
return ""
|
||||
|
||||
def list_all_profiles():
|
||||
profile_files = glob.glob(os.path.join(CONFIGS_DIR, "**", "profile.json"), recursive=True)
|
||||
profiles = []
|
||||
for prof_path in sorted(profile_files):
|
||||
try:
|
||||
with open(prof_path, 'r') as f:
|
||||
prof = json.load(f)
|
||||
prof["_path"] = os.path.dirname(prof_path)
|
||||
profiles.append(prof)
|
||||
except Exception:
|
||||
continue
|
||||
return profiles
|
||||
|
||||
def print_available_configs():
|
||||
profiles = list_all_profiles()
|
||||
print("=================================================================")
|
||||
print(" AVAILABLE LAPTOP AUDIO DSP CONFIGURATIONS")
|
||||
print("=================================================================")
|
||||
print(f" {'ID':<18} | {'Name':<32} | {'Vendor':<12}")
|
||||
print("-------------------+----------------------------------+----------")
|
||||
for prof in profiles:
|
||||
pid = prof.get("id", os.path.basename(prof["_path"]))
|
||||
name = prof.get("name", "Unknown Laptop")
|
||||
vendor = prof.get("vendor", "Unknown")
|
||||
print(f" {pid:<18} | {name:<32} | {vendor:<12}")
|
||||
print("=================================================================")
|
||||
|
||||
def detect_profile(manual_target=None):
|
||||
profile_files = glob.glob(os.path.join(CONFIGS_DIR, "**", "profile.json"), recursive=True)
|
||||
|
||||
# 1. Manual override check (--model, --manual, --profile)
|
||||
if manual_target:
|
||||
for prof_path in profile_files:
|
||||
try:
|
||||
with open(prof_path, 'r') as f:
|
||||
prof = json.load(f)
|
||||
pid = prof.get("id", os.path.basename(os.path.dirname(prof_path)))
|
||||
pdir = os.path.dirname(prof_path)
|
||||
if manual_target.lower() in [pid.lower(), pdir.lower(), os.path.basename(pdir).lower()]:
|
||||
return pdir, prof, False
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
# 2. DMI Hardware Matching
|
||||
vendor = read_dmi_file("sys_vendor")
|
||||
product = read_dmi_file("product_name")
|
||||
|
||||
if vendor or product:
|
||||
for prof_path in profile_files:
|
||||
try:
|
||||
with open(prof_path, 'r') as f:
|
||||
prof = json.load(f)
|
||||
|
||||
dmi_matches = prof.get("dmi_matches", [])
|
||||
prof_vendor = prof.get("vendor", "")
|
||||
|
||||
if (not prof_vendor or prof_vendor.lower() in vendor.lower() or vendor.lower() in prof_vendor.lower()):
|
||||
for match in dmi_matches:
|
||||
if match.lower() in product.lower():
|
||||
return os.path.dirname(prof_path), prof, False
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
# 3. Fallback to default MacBookPro15,1 profile with warning
|
||||
fallback_path = os.path.join(CONFIGS_DIR, "apple", "mbp15_1")
|
||||
fallback_json = os.path.join(fallback_path, "profile.json")
|
||||
if os.path.exists(fallback_json):
|
||||
with open(fallback_json, 'r') as f:
|
||||
return fallback_path, json.load(f), True
|
||||
|
||||
return None, None, True
|
||||
|
||||
def main():
|
||||
args = sys.argv[1:]
|
||||
|
||||
if any(arg in args for arg in ["-h", "--help", "help"]):
|
||||
print_help()
|
||||
sys.exit(0)
|
||||
|
||||
if any(arg in args for arg in ["--list", "--list-configs", "-l", "list"]):
|
||||
print_available_configs()
|
||||
sys.exit(0)
|
||||
|
||||
manual_target = None
|
||||
for i, arg in enumerate(args):
|
||||
if arg in ["--profile", "-p", "--model", "-m", "--manual"] and i + 1 < len(args):
|
||||
manual_target = args[i+1]
|
||||
|
||||
path, prof, is_fallback = detect_profile(manual_target=manual_target)
|
||||
|
||||
if is_fallback and "--quiet" not in args:
|
||||
vendor = read_dmi_file("sys_vendor") or "Unknown Vendor"
|
||||
product = read_dmi_file("product_name") or "Unknown Model"
|
||||
print(f"Warning: Hardware '{vendor} / {product}' not found in laptop-configs/.", file=sys.stderr)
|
||||
print("Falling back to default 'apple_mbp15_1' profile.", file=sys.stderr)
|
||||
print("Use './detect_hardware.py --list-configs' to view all available profiles.", file=sys.stderr)
|
||||
|
||||
if "--json" in args:
|
||||
print(json.dumps({"path": path, "profile": prof, "is_fallback": is_fallback}, indent=2))
|
||||
else:
|
||||
if path:
|
||||
print(path)
|
||||
else:
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
213
graph.json
213
graph.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"node.description": "MacBook Pro 15,1 DSP Speakers",
|
||||
"media.name": "MacBook Pro 15,1 DSP Speakers",
|
||||
"node.description": "MacBook Pro 15,1 Audio DSP",
|
||||
"media.name": "MacBook Pro 15,1 Audio DSP",
|
||||
"filter.graph": {
|
||||
"nodes": [
|
||||
{
|
||||
@@ -8,43 +8,15 @@
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/para_equalizer_x16_stereo",
|
||||
"name": "user_eq",
|
||||
"control": {
|
||||
"enabled": 0, "mode": 0, "g_in": 1.0, "g_out": 1.00,
|
||||
"ft_0": 5, "f_0": 70.0 , "g_0": 1.1, "q_0": 0.7, "s_0": 0,
|
||||
"ft_1": 1, "f_1": 110.0 , "g_1": 1.1, "q_1": 1.0,
|
||||
"ft_2": 1, "f_2": 315.0 , "g_2": 1.05, "q_2": 1.0,
|
||||
"ft_3": 1, "f_3": 1000.0 , "g_3": 1.01, "q_3": 1.0,
|
||||
"ft_4": 1, "f_4": 2500.0 , "g_4": 0.98, "q_4": 1.0,
|
||||
"ft_5": 1, "f_5": 6000.0 , "g_5": 0.97, "q_5": 1.0,
|
||||
"ft_6": 3, "f_6": 10000.0, "g_6": 0.96, "q_6": 0.7,
|
||||
"ft_7": 3, "f_7": 16000.0, "g_7": 0.95, "q_7": 0.7, "s_7": 0
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/para_equalizer_x16_stereo",
|
||||
"name": "equalizer",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"mode": 0,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.2,
|
||||
"ft_0": 2, "f_0": 20.0, "g_0": 2.5637, "q_0": 1.41, "s_0": 3, "xm_0": 0, "fm_0": 0,
|
||||
"ft_1": 1, "f_1": 31.5, "g_1": 2.2448, "q_1": 1.41, "s_1": 0, "xm_1": 0, "fm_1": 0,
|
||||
"ft_2": 1, "f_2": 50.0, "g_2": 1.9610, "q_2": 1.41, "s_2": 0, "xm_2": 0, "fm_2": 0,
|
||||
"ft_3": 1, "f_3": 80.0, "g_3": 1.7091, "q_3": 1.41, "s_3": 0, "xm_3": 0, "fm_3": 0,
|
||||
"ft_4": 1, "f_4": 125.0, "g_4": 1.5, "q_4": 1.41, "s_4": 0, "xm_4": 0, "fm_4": 0,
|
||||
"ft_5": 1, "f_5": 200.0, "g_5": 1.3073, "q_5": 1.41, "s_5": 0, "xm_5": 0, "fm_5": 0,
|
||||
"ft_6": 1, "f_6": 315.0, "g_6": 1.1447, "q_6": 1.41, "s_6": 0, "xm_6": 0, "fm_6": 0,
|
||||
"ft_7": 1, "f_7": 500.0, "g_7": 1.0, "q_7": 1.41, "s_7": 0, "xm_7": 0, "fm_7": 0,
|
||||
"ft_8": 1, "f_8": 800.0, "g_8": 0.8716, "q_8": 1.41, "s_8": 0, "xm_8": 0, "fm_8": 0,
|
||||
"ft_9": 1, "f_9": 1250.0, "g_9": 0.7649, "q_9": 1.41, "s_9": 0, "xm_9": 0, "fm_9": 0,
|
||||
"ft_10": 1, "f_10": 2000.0, "g_10": 0.6667, "q_10": 1.41, "s_10": 0, "xm_10": 0, "fm_10": 0,
|
||||
"ft_11": 1, "f_11": 3150.0, "g_11": 0.5837, "q_11": 1.41, "s_11": 0, "xm_11": 0, "fm_11": 0,
|
||||
"ft_12": 1, "f_12": 5000.0, "g_12": 0.5099, "q_12": 1.41, "s_12": 0, "xm_12": 0, "fm_12": 0,
|
||||
"ft_13": 1, "f_13": 8000.0, "g_13": 0.4444, "q_13": 1.41, "s_13": 0, "xm_13": 0, "fm_13": 0,
|
||||
"ft_14": 1, "f_14": 12500.0, "g_14": 0.3901, "q_14": 1.41, "s_14": 0, "xm_14": 0, "fm_14": 0,
|
||||
"ft_15": 1, "f_15": 20000.0, "g_15": 0.3400, "q_15": 1.41, "s_15": 0, "xm_15": 0, "fm_15": 0
|
||||
"enabled": 1, "mode": 0, "g_in": 1.0, "g_out": 1.5,
|
||||
"ft_0": 5, "f_0": 70.0, "g_0": 1.00, "q_0": 0.70, "s_0": 0,
|
||||
"ft_1": 1, "f_1": 110.0, "g_1": 1.00, "q_1": 1.00,
|
||||
"ft_2": 1, "f_2": 315.0, "g_2": 1.00, "q_2": 1.00,
|
||||
"ft_3": 1, "f_3": 600.0, "g_3": 1.00, "q_3": 1.00,
|
||||
"ft_4": 1, "f_4": 1000.0, "g_4": 1.00, "q_4": 1.00,
|
||||
"ft_5": 1, "f_5": 2500.0, "g_5": 1.00, "q_5": 1.00,
|
||||
"ft_6": 1, "f_6": 6000.0, "g_6": 1.00, "q_6": 1.00,
|
||||
"ft_7": 3, "f_7": 12000.0,"g_7": 1.00, "q_7": 0.70, "s_7": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -52,59 +24,39 @@
|
||||
"plugin": "https://chadmed.au/bankstown",
|
||||
"name": "virtualbass",
|
||||
"control": {
|
||||
"bypass": 0,
|
||||
"amt": 1.0,
|
||||
"amt": 1.4,
|
||||
"floor": 40.0,
|
||||
"ceil": 120.0,
|
||||
"final_hp": 55.0,
|
||||
"sat_second": 1.0,
|
||||
"sat_third": 1.0,
|
||||
"blend": 1.0,
|
||||
"ceil": 90.0,
|
||||
"floor": 60.0
|
||||
"blend": 0.30
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/mb_compressor_stereo",
|
||||
"name": "multiband_compressor",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/para_equalizer_x16_stereo",
|
||||
"name": "equalizer",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"mode": 1,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.0,
|
||||
"g_dry": 0.0001,
|
||||
"g_wet": 1.0,
|
||||
"cbe_1": 1, "sf_1": 40.0, "al_1": 0.10,
|
||||
"cbe_2": 1, "sf_2": 50.0, "al_2": 0.3,
|
||||
"cbe_3": 1, "sf_3": 60.0, "al_3": 0.5,
|
||||
"cbe_4": 1, "sf_4": 80.0, "al_4": 0.7,
|
||||
"cbe_5": 1, "sf_5": 120.0, "al_5": 0.7,
|
||||
"cbe_6": 1, "sf_6": 200.0, "al_6": 0.7,
|
||||
"cbe_7": 1, "sf_7": 500.0, "al_7": 0.7,
|
||||
"ce_0": 1, "at_0": 5.0, "rt_0": 100.0, "cr_0": 30.0, "kn_0": 0.10, "al_0": 0.000, "mk_0": 1.0, "bth_0": 1.0, "bsa_0": 1.0, "scm_0": 0,
|
||||
"ce_1": 1, "at_1": 6.0, "rt_1": 110.0, "cr_1": 30.0, "kn_1": 0.10, "mk_1": 1.0, "bth_1": 1.0, "bsa_1": 1.0, "scm_1": 0,
|
||||
"ce_2": 1, "at_2": 6.0, "rt_2": 100.0, "cr_2": 25.0, "kn_2": 0.12, "mk_2": 1.1, "bth_2": 1.0, "bsa_2": 1.0, "scm_2": 0,
|
||||
"ce_3": 1, "at_3": 5.0, "rt_3": 90.0, "cr_3": 20.0, "kn_3": 0.12, "mk_3": 1.2, "bth_3": 1.0, "bsa_3": 1.0, "scm_3": 0,
|
||||
"ce_4": 1, "at_4": 4.5, "rt_4": 80.0, "cr_4": 16.0, "kn_4": 0.15, "mk_4": 1.3, "bth_4": 1.0, "bsa_4": 1.0, "scm_4": 0,
|
||||
"ce_5": 1, "at_5": 4.0, "rt_5": 60.0, "cr_5": 10.0, "kn_5": 0.20, "mk_5": 1.5, "bth_5": 1.0, "bsa_5": 1.0, "scm_5": 0,
|
||||
"ce_6": 1, "at_6": 3.0, "rt_6": 40.0, "cr_6": 6.0, "kn_6": 0.30, "mk_6": 1.4, "bth_6": 1.0, "bsa_6": 1.0, "scm_6": 0,
|
||||
"ce_7": 1, "at_7": 2.5, "rt_7": 30.0, "cr_7": 4.0, "kn_7": 0.40, "mk_7": 1.2, "bth_7": 1.0, "bsa_7": 1.0, "scm_7": 0
|
||||
"enabled": 1, "mode": 0, "g_in": 1.0, "g_out": 1.0,
|
||||
"ft_0": 5, "f_0": 40.0, "g_0": 2.83, "q_0": 0.70,
|
||||
"ft_1": 1, "f_1": 80.0, "g_1": 2.00, "q_1": 1.00,
|
||||
"ft_2": 1, "f_2": 160.0, "g_2": 1.41, "q_2": 1.00,
|
||||
"ft_3": 1, "f_3": 320.0, "g_3": 1.00, "q_3": 1.00,
|
||||
"ft_4": 1, "f_4": 640.0, "g_4": 0.71, "q_4": 1.00,
|
||||
"ft_5": 1, "f_5": 1280.0, "g_5": 0.50, "q_5": 1.00,
|
||||
"ft_6": 1, "f_6": 2560.0, "g_6": 0.35, "q_6": 1.00,
|
||||
"ft_7": 3, "f_7": 12000.0,"g_7": 0.24, "q_7": 0.70
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/loud_comp_mono",
|
||||
"name": "ell",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/loud_comp_stereo",
|
||||
"name": "loudness",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"volume": 0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/loud_comp_mono",
|
||||
"name": "elr",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"volume": 0.0
|
||||
"input": 1.0,
|
||||
"fft": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -128,7 +80,7 @@
|
||||
"/usr/share/t2-linux-audio/15_1/tweeters-96k.wav"
|
||||
],
|
||||
"channel": 0,
|
||||
"gain": 1.2
|
||||
"gain": 1.1
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -142,7 +94,7 @@
|
||||
"/usr/share/t2-linux-audio/15_1/tweeters-96k.wav"
|
||||
],
|
||||
"channel": 0,
|
||||
"gain": 1.2
|
||||
"gain": 1.1
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -175,19 +127,50 @@
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"name": "thermal_guard",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/sc_compressor_stereo",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/mb_compressor_stereo",
|
||||
"name": "wmb_comp",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"mode": 1,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.1,
|
||||
"g_dry": 0.0001,
|
||||
"g_wet": 1.0,
|
||||
"cbe_1": 1, "sf_1": 40.0,
|
||||
"cbe_2": 1, "sf_2": 50.0,
|
||||
"cbe_3": 1, "sf_3": 60.0,
|
||||
"cbe_4": 1, "sf_4": 80.0,
|
||||
"cbe_5": 1, "sf_5": 120.0,
|
||||
"cbe_6": 1, "sf_6": 200.0,
|
||||
"cbe_7": 1, "sf_7": 500.0,
|
||||
"ce_0": 1, "at_0": 5.0, "rt_0": 100.0, "cr_0": 30.0, "kn_0": 0.10, "al_0": 0.95, "mk_0": 1.0, "bth_0": 1.0, "bsa_0": 1.0, "scm_0": 0,
|
||||
"ce_1": 1, "at_1": 6.0, "rt_1": 110.0, "cr_1": 30.0, "kn_1": 0.10, "al_1": 0.92, "mk_1": 1.0, "bth_1": 1.0, "bsa_1": 1.0, "scm_1": 0,
|
||||
"ce_2": 1, "at_2": 6.0, "rt_2": 100.0, "cr_2": 25.0, "kn_2": 0.12, "al_2": 0.90, "mk_2": 1.0, "bth_2": 1.0, "bsa_2": 1.0, "scm_2": 0,
|
||||
"ce_3": 1, "at_3": 5.0, "rt_3": 90.0, "cr_3": 20.0, "kn_3": 0.12, "al_3": 0.88, "mk_3": 1.0, "bth_3": 1.0, "bsa_3": 1.0, "scm_3": 0,
|
||||
"ce_4": 1, "at_4": 4.5, "rt_4": 80.0, "cr_4": 16.0, "kn_4": 0.15, "al_4": 0.85, "mk_4": 1.0, "bth_4": 1.0, "bsa_4": 1.0, "scm_4": 0,
|
||||
"ce_5": 1, "at_5": 4.0, "rt_5": 60.0, "cr_5": 10.0, "kn_5": 0.20, "al_5": 0.80, "mk_5": 1.0, "bth_5": 1.0, "bsa_5": 1.0, "scm_5": 0,
|
||||
"ce_6": 1, "at_6": 3.0, "rt_6": 40.0, "cr_6": 6.0, "kn_6": 0.30, "al_6": 0.80, "mk_6": 1.0, "bth_6": 1.0, "bsa_6": 1.0, "scm_6": 0,
|
||||
"ce_7": 1, "at_7": 2.5, "rt_7": 30.0, "cr_7": 4.0, "kn_7": 0.40, "al_7": 0.80, "mk_7": 1.0, "bth_7": 1.0, "bsa_7": 1.0, "scm_7": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/mb_compressor_stereo",
|
||||
"name": "tmb_comp",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"mode": 1,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.0,
|
||||
"at": 2500.0,
|
||||
"rt": 5000.0,
|
||||
"al": 0.5,
|
||||
"cr": 4.0,
|
||||
"kn": 0.5,
|
||||
"scp": 0,
|
||||
"scm": 1
|
||||
"g_dry": 0.0001,
|
||||
"g_wet": 1.0,
|
||||
"cbe_1": 1, "sf_1": 2500.0,
|
||||
"cbe_2": 1, "sf_2": 6000.0,
|
||||
"cbe_3": 1, "sf_3": 12000.0,
|
||||
"ce_0": 1, "at_0": 3.0, "rt_0": 50.0, "cr_0": 8.0, "kn_0": 0.20, "al_0": 0.85, "mk_0": 1.0, "bth_0": 1.0, "bsa_0": 1.0, "scm_0": 0,
|
||||
"ce_1": 1, "at_1": 2.5, "rt_1": 40.0, "cr_1": 6.0, "kn_1": 0.30, "al_1": 0.80, "mk_1": 1.0, "bth_1": 1.0, "bsa_1": 1.0, "scm_1": 0,
|
||||
"ce_2": 1, "at_2": 2.0, "rt_2": 30.0, "cr_2": 4.0, "kn_2": 0.40, "al_2": 0.75, "mk_2": 1.0, "bth_2": 1.0, "bsa_2": 1.0, "scm_2": 0,
|
||||
"ce_3": 1, "at_3": 1.5, "rt_3": 20.0, "cr_3": 3.0, "kn_3": 0.50, "al_3": 0.70, "mk_3": 1.0, "bth_3": 1.0, "bsa_3": 1.0, "scm_3": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -196,7 +179,7 @@
|
||||
"plugin": "http://plugin.org.uk/swh-plugins/fastLookaheadLimiter",
|
||||
"control": {
|
||||
"ingain": 0,
|
||||
"limit": -0.5,
|
||||
"limit": 0,
|
||||
"release": 0.25
|
||||
}
|
||||
},
|
||||
@@ -206,32 +189,32 @@
|
||||
"plugin": "http://plugin.org.uk/swh-plugins/fastLookaheadLimiter",
|
||||
"control": {
|
||||
"ingain": 0,
|
||||
"limit": -0.5,
|
||||
"limit": -1,
|
||||
"release": 0.15
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{"output": "user_eq:out_l", "input": "equalizer:in_l"},
|
||||
{"output": "user_eq:out_r", "input": "equalizer:in_r"},
|
||||
{"output": "equalizer:out_l", "input": "virtualbass:in_l"},
|
||||
{"output": "equalizer:out_r", "input": "virtualbass:in_r"},
|
||||
{"output": "virtualbass:out_l", "input": "thermal_guard:in_l"},
|
||||
{"output": "virtualbass:out_r", "input": "thermal_guard:in_r"},
|
||||
{"output": "thermal_guard:out_l", "input": "ell:in"},
|
||||
{"output": "thermal_guard:out_r", "input": "elr:in"},
|
||||
{"output": "ell:out", "input": "copyL:In"},
|
||||
{"output": "elr:out", "input": "copyR:In"},
|
||||
{"output": "user_eq:out_l", "input": "virtualbass:in_l"},
|
||||
{"output": "user_eq:out_r", "input": "virtualbass:in_r"},
|
||||
{"output": "virtualbass:out_l", "input": "equalizer:in_l"},
|
||||
{"output": "virtualbass:out_r", "input": "equalizer:in_r"},
|
||||
{"output": "equalizer:out_l", "input": "loudness:in_l"},
|
||||
{"output": "equalizer:out_r", "input": "loudness:in_r"},
|
||||
{"output": "loudness:out_l", "input": "copyL:In"},
|
||||
{"output": "loudness:out_r", "input": "copyR:In"},
|
||||
{"output": "copyL:Out", "input": "convLT:In"},
|
||||
{"output": "copyL:Out", "input": "convLW:In"},
|
||||
{"output": "copyR:Out", "input": "convRT:In"},
|
||||
{"output": "copyR:Out", "input": "convRW:In"},
|
||||
{"output": "convLW:Out", "input": "multiband_compressor:in_l"},
|
||||
{"output": "convRW:Out", "input": "multiband_compressor:in_r"},
|
||||
{"output": "multiband_compressor:out_l", "input": "wlim:in_1"},
|
||||
{"output": "multiband_compressor:out_r", "input": "wlim:in_2"},
|
||||
{"output": "convLT:Out", "input": "tlim:in_1"},
|
||||
{"output": "convRT:Out", "input": "tlim:in_2"}
|
||||
{"output": "convLW:Out", "input": "wmb_comp:in_l"},
|
||||
{"output": "convRW:Out", "input": "wmb_comp:in_r"},
|
||||
{"output": "wmb_comp:out_l", "input": "wlim:in_1"},
|
||||
{"output": "wmb_comp:out_r", "input": "wlim:in_2"},
|
||||
{"output": "convLT:Out", "input": "tmb_comp:in_l"},
|
||||
{"output": "convRT:Out", "input": "tmb_comp:in_r"},
|
||||
{"output": "tmb_comp:out_l", "input": "tlim:in_1"},
|
||||
{"output": "tmb_comp:out_r", "input": "tlim:in_2"}
|
||||
],
|
||||
"inputs": [
|
||||
"user_eq:in_l",
|
||||
@@ -242,20 +225,6 @@
|
||||
"wlim:out_2",
|
||||
"tlim:out_1",
|
||||
"tlim:out_2"
|
||||
],
|
||||
"capture.volumes": [
|
||||
{
|
||||
"control": "ell:volume",
|
||||
"min": -65.0,
|
||||
"max": 0.0,
|
||||
"scale": "linear"
|
||||
},
|
||||
{
|
||||
"control": "elr:volume",
|
||||
"min": -65.0,
|
||||
"max": 0.0,
|
||||
"scale": "linear"
|
||||
}
|
||||
]
|
||||
},
|
||||
"capture.props": {
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
{
|
||||
"node.description": "MacBook Pro 15,1 DSP Speakers",
|
||||
"media.name": "MacBook Pro 15,1 DSP Speakers",
|
||||
"filter.graph": {
|
||||
"nodes": [
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "https://chadmed.au/bankstown",
|
||||
"name": "virtualbass",
|
||||
"control": {
|
||||
"bypass": 0,
|
||||
"amt": 1.0,
|
||||
"sat_second": 1.0,
|
||||
"sat_third": 1.0,
|
||||
"blend": 1.0,
|
||||
"ceil": 150.0,
|
||||
"floor": 60.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/mb_compressor_stereo",
|
||||
"name": "multiband_compressor",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"mode": 1,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.0,
|
||||
"g_dry": 0.0001,
|
||||
"g_wet": 1.0,
|
||||
"cbe_1": 1, "sf_1": 40.0, "al_1": 0.05,
|
||||
"cbe_2": 1, "sf_2": 50.0, "al_2": 0.15,
|
||||
"cbe_3": 1, "sf_3": 60.0, "al_3": 0.3,
|
||||
"cbe_4": 1, "sf_4": 80.0, "al_4": 0.5,
|
||||
"cbe_5": 1, "sf_5": 120.0, "al_5": 0.6,
|
||||
"cbe_6": 1, "sf_6": 200.0, "al_6": 0.7,
|
||||
"cbe_7": 1, "sf_7": 500.0, "al_7": 0.8,
|
||||
"ce_0": 1, "at_0": 5.0, "rt_0": 100.0, "cr_0": 30.0, "kn_0": 0.10, "al_0": 0.000, "mk_0": 1.0, "bth_0": 1.0, "bsa_0": 1.0, "scm_0": 0,
|
||||
"ce_1": 1, "at_1": 6.0, "rt_1": 110.0, "cr_1": 30.0, "kn_1": 0.10, "mk_1": 1.0, "bth_1": 1.0, "bsa_1": 1.0, "scm_1": 0,
|
||||
"ce_2": 1, "at_2": 6.0, "rt_2": 100.0, "cr_2": 25.0, "kn_2": 0.12, "mk_2": 1.1, "bth_2": 1.0, "bsa_2": 1.0, "scm_2": 0,
|
||||
"ce_3": 1, "at_3": 5.0, "rt_3": 90.0, "cr_3": 20.0, "kn_3": 0.12, "mk_3": 1.2, "bth_3": 1.0, "bsa_3": 1.0, "scm_3": 0,
|
||||
"ce_4": 1, "at_4": 4.5, "rt_4": 80.0, "cr_4": 16.0, "kn_4": 0.15, "mk_4": 1.3, "bth_4": 1.0, "bsa_4": 1.0, "scm_4": 0,
|
||||
"ce_5": 1, "at_5": 4.0, "rt_5": 60.0, "cr_5": 10.0, "kn_5": 0.20, "mk_5": 1.5, "bth_5": 1.0, "bsa_5": 1.0, "scm_5": 0,
|
||||
"ce_6": 1, "at_6": 3.0, "rt_6": 40.0, "cr_6": 6.0, "kn_6": 0.30, "mk_6": 1.4, "bth_6": 1.0, "bsa_6": 1.0, "scm_6": 0,
|
||||
"ce_7": 1, "at_7": 2.5, "rt_7": 30.0, "cr_7": 4.0, "kn_7": 0.40, "mk_7": 1.2, "bth_7": 1.0, "bsa_7": 1.0, "scm_7": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/loud_comp_mono",
|
||||
"name": "ell",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"volume": 0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/loud_comp_mono",
|
||||
"name": "elr",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"volume": 0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "builtin",
|
||||
"label": "copy",
|
||||
"name": "copyL"
|
||||
},
|
||||
{
|
||||
"type": "builtin",
|
||||
"label": "copy",
|
||||
"name": "copyR"
|
||||
},
|
||||
{
|
||||
"type": "builtin",
|
||||
"label": "convolver",
|
||||
"name": "convLT",
|
||||
"config": {
|
||||
"filename": [
|
||||
"/usr/share/t2-linux-audio/15_1/baked-tweeters-44k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/baked-tweeters-48k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/baked-tweeters-96k.wav"
|
||||
],
|
||||
"channel": 0,
|
||||
"gain": 1.2
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "builtin",
|
||||
"label": "convolver",
|
||||
"name": "convRT",
|
||||
"config": {
|
||||
"filename": [
|
||||
"/usr/share/t2-linux-audio/15_1/baked-tweeters-44k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/baked-tweeters-48k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/baked-tweeters-96k.wav"
|
||||
],
|
||||
"channel": 0,
|
||||
"gain": 1.2
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "builtin",
|
||||
"label": "convolver",
|
||||
"name": "convLW",
|
||||
"config": {
|
||||
"filename": [
|
||||
"/usr/share/t2-linux-audio/15_1/baked-woofers-44k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/baked-woofers-48k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/baked-woofers-96k.wav"
|
||||
],
|
||||
"channel": 0,
|
||||
"gain": 1.2
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "builtin",
|
||||
"label": "convolver",
|
||||
"name": "convRW",
|
||||
"config": {
|
||||
"filename": [
|
||||
"/usr/share/t2-linux-audio/15_1/baked-woofers-44k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/baked-woofers-48k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/baked-woofers-96k.wav"
|
||||
],
|
||||
"channel": 0,
|
||||
"gain": 1.2
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"name": "thermal_guard",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/sc_compressor_stereo",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.0,
|
||||
"at": 2500.0,
|
||||
"rt": 5000.0,
|
||||
"al": 0.5,
|
||||
"cr": 4.0,
|
||||
"kn": 0.5,
|
||||
"scp": 0,
|
||||
"scm": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"name": "wlim",
|
||||
"plugin": "http://plugin.org.uk/swh-plugins/fastLookaheadLimiter",
|
||||
"control": {
|
||||
"ingain": 0,
|
||||
"limit": 0,
|
||||
"release": 0.25
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"name": "tlim",
|
||||
"plugin": "http://plugin.org.uk/swh-plugins/fastLookaheadLimiter",
|
||||
"control": {
|
||||
"ingain": 0,
|
||||
"limit": 0,
|
||||
"release": 0.15
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{"output": "virtualbass:out_l", "input": "thermal_guard:in_l"},
|
||||
{"output": "virtualbass:out_r", "input": "thermal_guard:in_r"},
|
||||
{"output": "thermal_guard:out_l", "input": "ell:in"},
|
||||
{"output": "thermal_guard:out_r", "input": "elr:in"},
|
||||
{"output": "ell:out", "input": "copyL:In"},
|
||||
{"output": "elr:out", "input": "copyR:In"},
|
||||
{"output": "copyL:Out", "input": "convLT:In"},
|
||||
{"output": "copyL:Out", "input": "convLW:In"},
|
||||
{"output": "copyR:Out", "input": "convRT:In"},
|
||||
{"output": "copyR:Out", "input": "convRW:In"},
|
||||
{"output": "convLW:Out", "input": "multiband_compressor:in_l"},
|
||||
{"output": "convRW:Out", "input": "multiband_compressor:in_r"},
|
||||
{"output": "multiband_compressor:out_l", "input": "wlim:in_1"},
|
||||
{"output": "multiband_compressor:out_r", "input": "wlim:in_2"},
|
||||
{"output": "convLT:Out", "input": "tlim:in_1"},
|
||||
{"output": "convRT:Out", "input": "tlim:in_2"}
|
||||
],
|
||||
"inputs": [
|
||||
"virtualbass:in_l",
|
||||
"virtualbass:in_r"
|
||||
],
|
||||
"outputs": [
|
||||
"wlim:out_1",
|
||||
"wlim:out_2",
|
||||
"tlim:out_1",
|
||||
"tlim:out_2"
|
||||
],
|
||||
"capture.volumes": [
|
||||
{
|
||||
"control": "ell:volume",
|
||||
"min": -65.0,
|
||||
"max": 0.0,
|
||||
"scale": "linear"
|
||||
},
|
||||
{
|
||||
"control": "elr:volume",
|
||||
"min": -65.0,
|
||||
"max": 0.0,
|
||||
"scale": "linear"
|
||||
}
|
||||
]
|
||||
},
|
||||
"capture.props": {
|
||||
"node.name": "audio_effect.t2-151-speakers",
|
||||
"media.class": "Audio/Sink",
|
||||
"audio.channels": "2",
|
||||
"audio.position": ["FL", "FR"],
|
||||
"device.api": "dsp",
|
||||
"audio.allowed-rates": [48000, 44100],
|
||||
"node.virtual": "false",
|
||||
"priority.session": 2500,
|
||||
"priority.driver": 2500,
|
||||
"state.default-volume": 1.0,
|
||||
"device.icon-name": "audio-speakers"
|
||||
},
|
||||
"playback.props": {
|
||||
"node.name": "effect_output.t2-151-speakers",
|
||||
"node.description": "MacBook Pro 15,1 DSP Speakers Out",
|
||||
"media.name": "MacBook Pro 15,1 DSP Speakers Out",
|
||||
"target.object": "alsa_output.platform-sound.RawSpeakers",
|
||||
"node.dont-fallback": "true",
|
||||
"node.passive": "true",
|
||||
"audio.channels": "4",
|
||||
"audio.allowed-rates": [48000, 44100],
|
||||
"audio.position": ["FL", "FR", "RL", "RR"]
|
||||
}
|
||||
}
|
||||
502
graph_merged.json
Normal file
502
graph_merged.json
Normal file
@@ -0,0 +1,502 @@
|
||||
{
|
||||
"node.description": "MacBook Pro 15,1 Audio DSP",
|
||||
"media.name": "MacBook Pro 15,1 Audio DSP",
|
||||
"filter.graph": {
|
||||
"nodes": [
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/para_equalizer_x16_stereo",
|
||||
"name": "user_eq",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"mode": 0,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.40,
|
||||
"ft_0": 5,
|
||||
"f_0": 70.0,
|
||||
"g_0": 1.15,
|
||||
"q_0": 0.7,
|
||||
"s_0": 0,
|
||||
"ft_1": 1,
|
||||
"f_1": 110.0,
|
||||
"g_1": 1.1,
|
||||
"q_1": 1.0,
|
||||
"ft_2": 1,
|
||||
"f_2": 315.0,
|
||||
"g_2": 1.05,
|
||||
"q_2": 1.0,
|
||||
"ft_3": 1,
|
||||
"f_3": 1000.0,
|
||||
"g_3": 1.01,
|
||||
"q_3": 1.0,
|
||||
"ft_4": 1,
|
||||
"f_4": 2500.0,
|
||||
"g_4": 1.00,
|
||||
"q_4": 1.0,
|
||||
"ft_5": 1,
|
||||
"f_5": 6000.0,
|
||||
"g_5": 0.92,
|
||||
"q_5": 1.0,
|
||||
"ft_6": 3,
|
||||
"f_6": 10000.0,
|
||||
"g_6": 0.85,
|
||||
"q_6": 0.7,
|
||||
"ft_7": 3,
|
||||
"f_7": 16000.0,
|
||||
"g_7": 0.80,
|
||||
"q_7": 0.7,
|
||||
"s_7": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "https://chadmed.au/bankstown",
|
||||
"name": "virtualbass",
|
||||
"control": {
|
||||
"amt": 1.4,
|
||||
"floor": 40.0,
|
||||
"ceil": 120.0,
|
||||
"final_hp": 55.0,
|
||||
"sat_second": 1.0,
|
||||
"sat_third": 1.0,
|
||||
"blend": 0.30
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/para_equalizer_x16_stereo",
|
||||
"name": "equalizer",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"mode": 0,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.0,
|
||||
"ft_0": 5,
|
||||
"f_0": 40.0,
|
||||
"g_0": 2.83,
|
||||
"q_0": 0.70,
|
||||
"ft_1": 1,
|
||||
"f_1": 80.0,
|
||||
"g_1": 2.00,
|
||||
"q_1": 1.00,
|
||||
"ft_2": 1,
|
||||
"f_2": 160.0,
|
||||
"g_2": 1.41,
|
||||
"q_2": 1.00,
|
||||
"ft_3": 1,
|
||||
"f_3": 320.0,
|
||||
"g_3": 1.00,
|
||||
"q_3": 1.00,
|
||||
"ft_4": 1,
|
||||
"f_4": 640.0,
|
||||
"g_4": 0.71,
|
||||
"q_4": 1.00,
|
||||
"ft_5": 1,
|
||||
"f_5": 1280.0,
|
||||
"g_5": 0.50,
|
||||
"q_5": 1.00,
|
||||
"ft_6": 1,
|
||||
"f_6": 2560.0,
|
||||
"g_6": 0.35,
|
||||
"q_6": 1.00,
|
||||
"ft_7": 3,
|
||||
"f_7": 12000.0,
|
||||
"g_7": 0.24,
|
||||
"q_7": 0.70
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/loud_comp_stereo",
|
||||
"name": "loudness",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"input": 1.0,
|
||||
"fft": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "builtin",
|
||||
"label": "copy",
|
||||
"name": "copyL"
|
||||
},
|
||||
{
|
||||
"type": "builtin",
|
||||
"label": "copy",
|
||||
"name": "copyR"
|
||||
},
|
||||
{
|
||||
"type": "builtin",
|
||||
"label": "convolver",
|
||||
"name": "convLT",
|
||||
"config": {
|
||||
"filename": [
|
||||
"/usr/share/t2-linux-audio/15_1/tweeters-44k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/tweeters-48k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/tweeters-96k.wav"
|
||||
],
|
||||
"channel": 0,
|
||||
"gain": 1.1
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "builtin",
|
||||
"label": "convolver",
|
||||
"name": "convRT",
|
||||
"config": {
|
||||
"filename": [
|
||||
"/usr/share/t2-linux-audio/15_1/tweeters-44k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/tweeters-48k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/tweeters-96k.wav"
|
||||
],
|
||||
"channel": 0,
|
||||
"gain": 1.1
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "builtin",
|
||||
"label": "convolver",
|
||||
"name": "convLW",
|
||||
"config": {
|
||||
"filename": [
|
||||
"/usr/share/t2-linux-audio/15_1/woofers-44k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/woofers-48k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/woofers-96k.wav"
|
||||
],
|
||||
"channel": 0,
|
||||
"gain": 1.2
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "builtin",
|
||||
"label": "convolver",
|
||||
"name": "convRW",
|
||||
"config": {
|
||||
"filename": [
|
||||
"/usr/share/t2-linux-audio/15_1/woofers-44k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/woofers-48k.wav",
|
||||
"/usr/share/t2-linux-audio/15_1/woofers-96k.wav"
|
||||
],
|
||||
"channel": 0,
|
||||
"gain": 1.2
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/mb_compressor_stereo",
|
||||
"name": "wmb_comp",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"mode": 1,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.1,
|
||||
"g_dry": 0.0001,
|
||||
"g_wet": 1.0,
|
||||
"cbe_1": 1,
|
||||
"sf_1": 40.0,
|
||||
"cbe_2": 1,
|
||||
"sf_2": 50.0,
|
||||
"cbe_3": 1,
|
||||
"sf_3": 60.0,
|
||||
"cbe_4": 1,
|
||||
"sf_4": 80.0,
|
||||
"cbe_5": 1,
|
||||
"sf_5": 120.0,
|
||||
"cbe_6": 1,
|
||||
"sf_6": 200.0,
|
||||
"cbe_7": 1,
|
||||
"sf_7": 500.0,
|
||||
"ce_0": 1,
|
||||
"at_0": 5.0,
|
||||
"rt_0": 100.0,
|
||||
"cr_0": 30.0,
|
||||
"kn_0": 0.10,
|
||||
"al_0": 0.95,
|
||||
"mk_0": 1.0,
|
||||
"bth_0": 1.0,
|
||||
"bsa_0": 1.0,
|
||||
"scm_0": 0,
|
||||
"ce_1": 1,
|
||||
"at_1": 6.0,
|
||||
"rt_1": 110.0,
|
||||
"cr_1": 30.0,
|
||||
"kn_1": 0.10,
|
||||
"al_1": 0.92,
|
||||
"mk_1": 1.0,
|
||||
"bth_1": 1.0,
|
||||
"bsa_1": 1.0,
|
||||
"scm_1": 0,
|
||||
"ce_2": 1,
|
||||
"at_2": 6.0,
|
||||
"rt_2": 100.0,
|
||||
"cr_2": 25.0,
|
||||
"kn_2": 0.12,
|
||||
"al_2": 0.90,
|
||||
"mk_2": 1.0,
|
||||
"bth_2": 1.0,
|
||||
"bsa_2": 1.0,
|
||||
"scm_2": 0,
|
||||
"ce_3": 1,
|
||||
"at_3": 5.0,
|
||||
"rt_3": 90.0,
|
||||
"cr_3": 20.0,
|
||||
"kn_3": 0.12,
|
||||
"al_3": 0.88,
|
||||
"mk_3": 1.0,
|
||||
"bth_3": 1.0,
|
||||
"bsa_3": 1.0,
|
||||
"scm_3": 0,
|
||||
"ce_4": 1,
|
||||
"at_4": 4.5,
|
||||
"rt_4": 80.0,
|
||||
"cr_4": 16.0,
|
||||
"kn_4": 0.15,
|
||||
"al_4": 0.85,
|
||||
"mk_4": 1.0,
|
||||
"bth_4": 1.0,
|
||||
"bsa_4": 1.0,
|
||||
"scm_4": 0,
|
||||
"ce_5": 1,
|
||||
"at_5": 4.0,
|
||||
"rt_5": 60.0,
|
||||
"cr_5": 10.0,
|
||||
"kn_5": 0.20,
|
||||
"al_5": 0.80,
|
||||
"mk_5": 1.0,
|
||||
"bth_5": 1.0,
|
||||
"bsa_5": 1.0,
|
||||
"scm_5": 0,
|
||||
"ce_6": 1,
|
||||
"at_6": 3.0,
|
||||
"rt_6": 40.0,
|
||||
"cr_6": 6.0,
|
||||
"kn_6": 0.30,
|
||||
"al_6": 0.80,
|
||||
"mk_6": 1.0,
|
||||
"bth_6": 1.0,
|
||||
"bsa_6": 1.0,
|
||||
"scm_6": 0,
|
||||
"ce_7": 1,
|
||||
"at_7": 2.5,
|
||||
"rt_7": 30.0,
|
||||
"cr_7": 4.0,
|
||||
"kn_7": 0.40,
|
||||
"al_7": 0.80,
|
||||
"mk_7": 1.0,
|
||||
"bth_7": 1.0,
|
||||
"bsa_7": 1.0,
|
||||
"scm_7": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/mb_compressor_stereo",
|
||||
"name": "tmb_comp",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"mode": 1,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.0,
|
||||
"g_dry": 0.0001,
|
||||
"g_wet": 1.0,
|
||||
"cbe_1": 1,
|
||||
"sf_1": 2500.0,
|
||||
"cbe_2": 1,
|
||||
"sf_2": 6000.0,
|
||||
"cbe_3": 1,
|
||||
"sf_3": 12000.0,
|
||||
"ce_0": 1,
|
||||
"at_0": 3.0,
|
||||
"rt_0": 50.0,
|
||||
"cr_0": 8.0,
|
||||
"kn_0": 0.20,
|
||||
"al_0": 0.85,
|
||||
"mk_0": 1.0,
|
||||
"bth_0": 1.0,
|
||||
"bsa_0": 1.0,
|
||||
"scm_0": 0,
|
||||
"ce_1": 1,
|
||||
"at_1": 2.5,
|
||||
"rt_1": 40.0,
|
||||
"cr_1": 6.0,
|
||||
"kn_1": 0.30,
|
||||
"al_1": 0.80,
|
||||
"mk_1": 1.0,
|
||||
"bth_1": 1.0,
|
||||
"bsa_1": 1.0,
|
||||
"scm_1": 0,
|
||||
"ce_2": 1,
|
||||
"at_2": 2.0,
|
||||
"rt_2": 30.0,
|
||||
"cr_2": 4.0,
|
||||
"kn_2": 0.40,
|
||||
"al_2": 0.75,
|
||||
"mk_2": 1.0,
|
||||
"bth_2": 1.0,
|
||||
"bsa_2": 1.0,
|
||||
"scm_2": 0,
|
||||
"ce_3": 1,
|
||||
"at_3": 1.5,
|
||||
"rt_3": 20.0,
|
||||
"cr_3": 3.0,
|
||||
"kn_3": 0.50,
|
||||
"al_3": 0.70,
|
||||
"mk_3": 1.0,
|
||||
"bth_3": 1.0,
|
||||
"bsa_3": 1.0,
|
||||
"scm_3": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"name": "wlim",
|
||||
"plugin": "http://plugin.org.uk/swh-plugins/fastLookaheadLimiter",
|
||||
"control": {
|
||||
"ingain": 0,
|
||||
"limit": 0,
|
||||
"release": 0.25
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"name": "tlim",
|
||||
"plugin": "http://plugin.org.uk/swh-plugins/fastLookaheadLimiter",
|
||||
"control": {
|
||||
"ingain": 0,
|
||||
"limit": -1,
|
||||
"release": 0.15
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"output": "user_eq:out_l",
|
||||
"input": "virtualbass:in_l"
|
||||
},
|
||||
{
|
||||
"output": "user_eq:out_r",
|
||||
"input": "virtualbass:in_r"
|
||||
},
|
||||
{
|
||||
"output": "virtualbass:out_l",
|
||||
"input": "equalizer:in_l"
|
||||
},
|
||||
{
|
||||
"output": "virtualbass:out_r",
|
||||
"input": "equalizer:in_r"
|
||||
},
|
||||
{
|
||||
"output": "equalizer:out_l",
|
||||
"input": "loudness:in_l"
|
||||
},
|
||||
{
|
||||
"output": "equalizer:out_r",
|
||||
"input": "loudness:in_r"
|
||||
},
|
||||
{
|
||||
"output": "loudness:out_l",
|
||||
"input": "copyL:In"
|
||||
},
|
||||
{
|
||||
"output": "loudness:out_r",
|
||||
"input": "copyR:In"
|
||||
},
|
||||
{
|
||||
"output": "copyL:Out",
|
||||
"input": "convLT:In"
|
||||
},
|
||||
{
|
||||
"output": "copyL:Out",
|
||||
"input": "convLW:In"
|
||||
},
|
||||
{
|
||||
"output": "copyR:Out",
|
||||
"input": "convRT:In"
|
||||
},
|
||||
{
|
||||
"output": "copyR:Out",
|
||||
"input": "convRW:In"
|
||||
},
|
||||
{
|
||||
"output": "convLW:Out",
|
||||
"input": "wmb_comp:in_l"
|
||||
},
|
||||
{
|
||||
"output": "convRW:Out",
|
||||
"input": "wmb_comp:in_r"
|
||||
},
|
||||
{
|
||||
"output": "wmb_comp:out_l",
|
||||
"input": "wlim:in_1"
|
||||
},
|
||||
{
|
||||
"output": "wmb_comp:out_r",
|
||||
"input": "wlim:in_2"
|
||||
},
|
||||
{
|
||||
"output": "convLT:Out",
|
||||
"input": "tmb_comp:in_l"
|
||||
},
|
||||
{
|
||||
"output": "convRT:Out",
|
||||
"input": "tmb_comp:in_r"
|
||||
},
|
||||
{
|
||||
"output": "tmb_comp:out_l",
|
||||
"input": "tlim:in_1"
|
||||
},
|
||||
{
|
||||
"output": "tmb_comp:out_r",
|
||||
"input": "tlim:in_2"
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
"user_eq:in_l",
|
||||
"user_eq:in_r"
|
||||
],
|
||||
"outputs": [
|
||||
"wlim:out_1",
|
||||
"wlim:out_2",
|
||||
"tlim:out_1",
|
||||
"tlim:out_2"
|
||||
]
|
||||
},
|
||||
"capture.props": {
|
||||
"node.name": "audio_effect.t2-151-speakers",
|
||||
"media.class": "Audio/Sink",
|
||||
"audio.channels": "2",
|
||||
"audio.position": [
|
||||
"FL",
|
||||
"FR"
|
||||
],
|
||||
"device.api": "dsp",
|
||||
"audio.allowed-rates": [
|
||||
48000,
|
||||
44100
|
||||
],
|
||||
"node.virtual": "false",
|
||||
"priority.session": 2500,
|
||||
"priority.driver": 2500,
|
||||
"state.default-volume": 1.0,
|
||||
"device.icon-name": "audio-speakers"
|
||||
},
|
||||
"playback.props": {
|
||||
"node.name": "effect_output.t2-151-speakers",
|
||||
"node.description": "MacBook Pro 15,1 DSP Speakers Out",
|
||||
"media.name": "MacBook Pro 15,1 DSP Speakers Out",
|
||||
"target.object": "alsa_output.platform-sound.RawSpeakers",
|
||||
"node.dont-fallback": "true",
|
||||
"node.passive": "true",
|
||||
"audio.channels": "4",
|
||||
"audio.allowed-rates": [
|
||||
48000,
|
||||
44100
|
||||
],
|
||||
"audio.position": [
|
||||
"FL",
|
||||
"FR",
|
||||
"RL",
|
||||
"RR"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"node.description": "MacBook Pro 15,1 DSP Speakers",
|
||||
"media.name": "MacBook Pro 15,1 DSP Speakers",
|
||||
"node.description": "MacBook Pro 15,1 Audio DSP",
|
||||
"media.name": "MacBook Pro 15,1 Audio DSP",
|
||||
"filter.graph": {
|
||||
"nodes": [
|
||||
{
|
||||
@@ -9,41 +9,14 @@
|
||||
"name": "user_eq",
|
||||
"control": {
|
||||
"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": 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,
|
||||
"ft_6": 1, "f_6": 6000.0, "g_6": 1.0, "q_6": 1.0,
|
||||
"ft_7": 3, "f_7": 10000.0, "g_7": 1.0, "q_7": 0.7, "s_7": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/para_equalizer_x16_stereo",
|
||||
"name": "equalizer",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"mode": 0,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.5,
|
||||
"ft_0": 2, "f_0": 20.0, "g_0": 2.5637, "q_0": 1.41, "s_0": 3, "xm_0": 0, "fm_0": 0,
|
||||
"ft_1": 1, "f_1": 31.5, "g_1": 2.2448, "q_1": 1.41, "s_1": 0, "xm_1": 0, "fm_1": 0,
|
||||
"ft_2": 1, "f_2": 50.0, "g_2": 1.9610, "q_2": 1.41, "s_2": 0, "xm_2": 0, "fm_2": 0,
|
||||
"ft_3": 1, "f_3": 80.0, "g_3": 1.7091, "q_3": 1.41, "s_3": 0, "xm_3": 0, "fm_3": 0,
|
||||
"ft_4": 1, "f_4": 125.0, "g_4": 1.5, "q_4": 1.41, "s_4": 0, "xm_4": 0, "fm_4": 0,
|
||||
"ft_5": 1, "f_5": 200.0, "g_5": 1.3073, "q_5": 1.41, "s_5": 0, "xm_5": 0, "fm_5": 0,
|
||||
"ft_6": 1, "f_6": 315.0, "g_6": 1.1447, "q_6": 1.41, "s_6": 0, "xm_6": 0, "fm_6": 0,
|
||||
"ft_7": 1, "f_7": 500.0, "g_7": 1.0, "q_7": 1.41, "s_7": 0, "xm_7": 0, "fm_7": 0,
|
||||
"ft_8": 1, "f_8": 800.0, "g_8": 0.8716, "q_8": 1.41, "s_8": 0, "xm_8": 0, "fm_8": 0,
|
||||
"ft_9": 1, "f_9": 1250.0, "g_9": 0.7649, "q_9": 1.41, "s_9": 0, "xm_9": 0, "fm_9": 0,
|
||||
"ft_10": 1, "f_10": 2000.0, "g_10": 0.6667, "q_10": 1.41, "s_10": 0, "xm_10": 0, "fm_10": 0,
|
||||
"ft_11": 1, "f_11": 3150.0, "g_11": 0.5837, "q_11": 1.41, "s_11": 0, "xm_11": 0, "fm_11": 0,
|
||||
"ft_12": 1, "f_12": 5000.0, "g_12": 0.5099, "q_12": 1.41, "s_12": 0, "xm_12": 0, "fm_12": 0,
|
||||
"ft_13": 1, "f_13": 8000.0, "g_13": 0.4444, "q_13": 1.41, "s_13": 0, "xm_13": 0, "fm_13": 0,
|
||||
"ft_14": 1, "f_14": 12500.0, "g_14": 0.3901, "q_14": 1.41, "s_14": 0, "xm_14": 0, "fm_14": 0,
|
||||
"ft_15": 1, "f_15": 20000.0, "g_15": 0.3400, "q_15": 1.41, "s_15": 0, "xm_15": 0, "fm_15": 0
|
||||
"ft_0": 5, "f_0": 70.0, "g_0": 1.00, "q_0": 0.70, "s_0": 0,
|
||||
"ft_1": 1, "f_1": 110.0, "g_1": 1.00, "q_1": 1.00,
|
||||
"ft_2": 1, "f_2": 315.0, "g_2": 1.00, "q_2": 1.00,
|
||||
"ft_3": 1, "f_3": 600.0, "g_3": 1.00, "q_3": 1.00,
|
||||
"ft_4": 1, "f_4": 1000.0, "g_4": 1.00, "q_4": 1.00,
|
||||
"ft_5": 1, "f_5": 2500.0, "g_5": 1.00, "q_5": 1.00,
|
||||
"ft_6": 1, "f_6": 6000.0, "g_6": 1.00, "q_6": 1.00,
|
||||
"ft_7": 3, "f_7": 12000.0,"g_7": 1.00, "q_7": 0.70, "s_7": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -51,59 +24,39 @@
|
||||
"plugin": "https://chadmed.au/bankstown",
|
||||
"name": "virtualbass",
|
||||
"control": {
|
||||
"bypass": 0,
|
||||
"amt": 1.0,
|
||||
"amt": 1.4,
|
||||
"floor": 40.0,
|
||||
"ceil": 120.0,
|
||||
"final_hp": 55.0,
|
||||
"sat_second": 1.0,
|
||||
"sat_third": 1.0,
|
||||
"blend": 1.0,
|
||||
"ceil": 150.0,
|
||||
"floor": 60.0
|
||||
"blend": 0.30
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/mb_compressor_stereo",
|
||||
"name": "multiband_compressor",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/para_equalizer_x16_stereo",
|
||||
"name": "equalizer",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"mode": 1,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.25,
|
||||
"g_dry": 0.0001,
|
||||
"g_wet": 1.0,
|
||||
"cbe_1": 1, "sf_1": 40.0,
|
||||
"cbe_2": 1, "sf_2": 50.0,
|
||||
"cbe_3": 1, "sf_3": 60.0,
|
||||
"cbe_4": 1, "sf_4": 80.0,
|
||||
"cbe_5": 1, "sf_5": 120.0,
|
||||
"cbe_6": 1, "sf_6": 200.0,
|
||||
"cbe_7": 1, "sf_7": 500.0,
|
||||
"ce_0": 1, "at_0": 5.0, "rt_0": 100.0, "cr_0": 30.0, "kn_0": 0.10, "al_0": 0.025, "mk_0": 1.0, "bth_0": 1.0, "bsa_0": 1.0, "scm_0": 0,
|
||||
"ce_1": 1, "at_1": 6.0, "rt_1": 110.0, "cr_1": 30.0, "kn_1": 0.10, "al_1": 0.050, "mk_1": 1.0, "bth_1": 1.0, "bsa_1": 1.0, "scm_1": 0,
|
||||
"ce_2": 1, "at_2": 6.0, "rt_2": 100.0, "cr_2": 25.0, "kn_2": 0.12, "al_2": 0.070, "mk_2": 1.1, "bth_2": 1.0, "bsa_2": 1.0, "scm_2": 0,
|
||||
"ce_3": 1, "at_3": 5.0, "rt_3": 90.0, "cr_3": 20.0, "kn_3": 0.12, "al_3": 0.090, "mk_3": 1.2, "bth_3": 1.0, "bsa_3": 1.0, "scm_3": 0,
|
||||
"ce_4": 1, "at_4": 4.5, "rt_4": 80.0, "cr_4": 16.0, "kn_4": 0.15, "al_4": 0.120, "mk_4": 1.3, "bth_4": 1.0, "bsa_4": 1.0, "scm_4": 0,
|
||||
"ce_5": 1, "at_5": 4.0, "rt_5": 60.0, "cr_5": 10.0, "kn_5": 0.20, "al_5": 0.250, "mk_5": 1.5, "bth_5": 1.0, "bsa_5": 1.0, "scm_5": 0,
|
||||
"ce_6": 1, "at_6": 3.0, "rt_6": 40.0, "cr_6": 6.0, "kn_6": 0.30, "al_6": 0.300, "mk_6": 1.4, "bth_6": 1.0, "bsa_6": 1.0, "scm_6": 0,
|
||||
"ce_7": 1, "at_7": 2.5, "rt_7": 30.0, "cr_7": 4.0, "kn_7": 0.40, "al_7": 0.300, "mk_7": 1.2, "bth_7": 1.0, "bsa_7": 1.0, "scm_7": 0
|
||||
"enabled": 1, "mode": 0, "g_in": 1.0, "g_out": 1.0,
|
||||
"ft_0": 5, "f_0": 40.0, "g_0": 2.83, "q_0": 0.70,
|
||||
"ft_1": 1, "f_1": 80.0, "g_1": 2.00, "q_1": 1.00,
|
||||
"ft_2": 1, "f_2": 160.0, "g_2": 1.41, "q_2": 1.00,
|
||||
"ft_3": 1, "f_3": 320.0, "g_3": 1.00, "q_3": 1.00,
|
||||
"ft_4": 1, "f_4": 640.0, "g_4": 0.71, "q_4": 1.00,
|
||||
"ft_5": 1, "f_5": 1280.0, "g_5": 0.50, "q_5": 1.00,
|
||||
"ft_6": 1, "f_6": 2560.0, "g_6": 0.35, "q_6": 1.00,
|
||||
"ft_7": 3, "f_7": 12000.0,"g_7": 0.24, "q_7": 0.70
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/loud_comp_mono",
|
||||
"name": "ell",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/loud_comp_stereo",
|
||||
"name": "loudness",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"volume": 0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/loud_comp_mono",
|
||||
"name": "elr",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"volume": 0.0
|
||||
"input": 1.0,
|
||||
"fft": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -174,19 +127,50 @@
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"name": "thermal_guard",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/sc_compressor_stereo",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/mb_compressor_stereo",
|
||||
"name": "wmb_comp",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"mode": 1,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.0,
|
||||
"at": 2500.0,
|
||||
"rt": 5000.0,
|
||||
"al": 0.4,
|
||||
"cr": 4.0,
|
||||
"kn": 0.5,
|
||||
"scp": 0,
|
||||
"scm": 1
|
||||
"g_dry": 0.0001,
|
||||
"g_wet": 1.0,
|
||||
"cbe_1": 1, "sf_1": 40.0,
|
||||
"cbe_2": 1, "sf_2": 50.0,
|
||||
"cbe_3": 1, "sf_3": 60.0,
|
||||
"cbe_4": 1, "sf_4": 80.0,
|
||||
"cbe_5": 1, "sf_5": 120.0,
|
||||
"cbe_6": 1, "sf_6": 200.0,
|
||||
"cbe_7": 1, "sf_7": 500.0,
|
||||
"ce_0": 1, "at_0": 5.0, "rt_0": 100.0, "cr_0": 30.0, "kn_0": 0.10, "al_0": 0.95, "mk_0": 1.0, "bth_0": 1.0, "bsa_0": 1.0, "scm_0": 0,
|
||||
"ce_1": 1, "at_1": 6.0, "rt_1": 110.0, "cr_1": 30.0, "kn_1": 0.10, "al_1": 0.92, "mk_1": 1.0, "bth_1": 1.0, "bsa_1": 1.0, "scm_1": 0,
|
||||
"ce_2": 1, "at_2": 6.0, "rt_2": 100.0, "cr_2": 25.0, "kn_2": 0.12, "al_2": 0.90, "mk_2": 1.0, "bth_2": 1.0, "bsa_2": 1.0, "scm_2": 0,
|
||||
"ce_3": 1, "at_3": 5.0, "rt_3": 90.0, "cr_3": 20.0, "kn_3": 0.12, "al_3": 0.88, "mk_3": 1.0, "bth_3": 1.0, "bsa_3": 1.0, "scm_3": 0,
|
||||
"ce_4": 1, "at_4": 4.5, "rt_4": 80.0, "cr_4": 16.0, "kn_4": 0.15, "al_4": 0.85, "mk_4": 1.0, "bth_4": 1.0, "bsa_4": 1.0, "scm_4": 0,
|
||||
"ce_5": 1, "at_5": 4.0, "rt_5": 60.0, "cr_5": 10.0, "kn_5": 0.20, "al_5": 0.80, "mk_5": 1.0, "bth_5": 1.0, "bsa_5": 1.0, "scm_5": 0,
|
||||
"ce_6": 1, "at_6": 3.0, "rt_6": 40.0, "cr_6": 6.0, "kn_6": 0.30, "al_6": 0.80, "mk_6": 1.0, "bth_6": 1.0, "bsa_6": 1.0, "scm_6": 0,
|
||||
"ce_7": 1, "at_7": 2.5, "rt_7": 30.0, "cr_7": 4.0, "kn_7": 0.40, "al_7": 0.80, "mk_7": 1.0, "bth_7": 1.0, "bsa_7": 1.0, "scm_7": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/mb_compressor_stereo",
|
||||
"name": "tmb_comp",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"mode": 1,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.0,
|
||||
"g_dry": 0.0001,
|
||||
"g_wet": 1.0,
|
||||
"cbe_1": 1, "sf_1": 2500.0,
|
||||
"cbe_2": 1, "sf_2": 6000.0,
|
||||
"cbe_3": 1, "sf_3": 12000.0,
|
||||
"ce_0": 1, "at_0": 3.0, "rt_0": 50.0, "cr_0": 8.0, "kn_0": 0.20, "al_0": 0.85, "mk_0": 1.0, "bth_0": 1.0, "bsa_0": 1.0, "scm_0": 0,
|
||||
"ce_1": 1, "at_1": 2.5, "rt_1": 40.0, "cr_1": 6.0, "kn_1": 0.30, "al_1": 0.80, "mk_1": 1.0, "bth_1": 1.0, "bsa_1": 1.0, "scm_1": 0,
|
||||
"ce_2": 1, "at_2": 2.0, "rt_2": 30.0, "cr_2": 4.0, "kn_2": 0.40, "al_2": 0.75, "mk_2": 1.0, "bth_2": 1.0, "bsa_2": 1.0, "scm_2": 0,
|
||||
"ce_3": 1, "at_3": 1.5, "rt_3": 20.0, "cr_3": 3.0, "kn_3": 0.50, "al_3": 0.70, "mk_3": 1.0, "bth_3": 1.0, "bsa_3": 1.0, "scm_3": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -195,61 +179,42 @@
|
||||
"plugin": "http://plugin.org.uk/swh-plugins/fastLookaheadLimiter",
|
||||
"control": {
|
||||
"ingain": 0,
|
||||
"limit": 0,
|
||||
"limit": -2,
|
||||
"release": 0.25
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"name": "tweeter_thermal_guard",
|
||||
"plugin": "http://lsp-plug.in/plugins/lv2/sc_compressor_stereo",
|
||||
"control": {
|
||||
"enabled": 1,
|
||||
"g_in": 1.0,
|
||||
"g_out": 1.0,
|
||||
"at": 1000.0,
|
||||
"rt": 2000.0,
|
||||
"al": 0.126491,
|
||||
"cr": 4.0,
|
||||
"kn": 0.5,
|
||||
"scp": 0,
|
||||
"scm": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lv2",
|
||||
"name": "tlim",
|
||||
"plugin": "http://plugin.org.uk/swh-plugins/fastLookaheadLimiter",
|
||||
"control": {
|
||||
"ingain": 0,
|
||||
"limit": 0,
|
||||
"limit": -1,
|
||||
"release": 0.15
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{"output": "user_eq:out_l", "input": "equalizer:in_l"},
|
||||
{"output": "user_eq:out_r", "input": "equalizer:in_r"},
|
||||
{"output": "equalizer:out_l", "input": "virtualbass:in_l"},
|
||||
{"output": "equalizer:out_r", "input": "virtualbass:in_r"},
|
||||
{"output": "virtualbass:out_l", "input": "multiband_compressor:in_l"},
|
||||
{"output": "virtualbass:out_r", "input": "multiband_compressor:in_r"},
|
||||
{"output": "multiband_compressor:out_l", "input": "ell:in"},
|
||||
{"output": "multiband_compressor:out_r", "input": "elr:in"},
|
||||
{"output": "ell:out", "input": "copyL:In"},
|
||||
{"output": "elr:out", "input": "copyR:In"},
|
||||
{"output": "user_eq:out_l", "input": "virtualbass:in_l"},
|
||||
{"output": "user_eq:out_r", "input": "virtualbass:in_r"},
|
||||
{"output": "virtualbass:out_l", "input": "equalizer:in_l"},
|
||||
{"output": "virtualbass:out_r", "input": "equalizer:in_r"},
|
||||
{"output": "equalizer:out_l", "input": "loudness:in_l"},
|
||||
{"output": "equalizer:out_r", "input": "loudness:in_r"},
|
||||
{"output": "loudness:out_l", "input": "copyL:In"},
|
||||
{"output": "loudness:out_r", "input": "copyR:In"},
|
||||
{"output": "copyL:Out", "input": "convLT:In"},
|
||||
{"output": "copyL:Out", "input": "convLW:In"},
|
||||
{"output": "copyR:Out", "input": "convRT:In"},
|
||||
{"output": "copyR:Out", "input": "convRW:In"},
|
||||
{"output": "convLW:Out", "input": "thermal_guard:in_l"},
|
||||
{"output": "convRW:Out", "input": "thermal_guard:in_r"},
|
||||
{"output": "thermal_guard:out_l", "input": "wlim:in_1"},
|
||||
{"output": "thermal_guard:out_r", "input": "wlim:in_2"},
|
||||
{"output": "convLT:Out", "input": "tweeter_thermal_guard:in_l"},
|
||||
{"output": "convRT:Out", "input": "tweeter_thermal_guard:in_r"},
|
||||
{"output": "tweeter_thermal_guard:out_l", "input": "tlim:in_1"},
|
||||
{"output": "tweeter_thermal_guard:out_r", "input": "tlim:in_2"}
|
||||
{"output": "convLW:Out", "input": "wmb_comp:in_l"},
|
||||
{"output": "convRW:Out", "input": "wmb_comp:in_r"},
|
||||
{"output": "wmb_comp:out_l", "input": "wlim:in_1"},
|
||||
{"output": "wmb_comp:out_r", "input": "wlim:in_2"},
|
||||
{"output": "convLT:Out", "input": "tmb_comp:in_l"},
|
||||
{"output": "convRT:Out", "input": "tmb_comp:in_r"},
|
||||
{"output": "tmb_comp:out_l", "input": "tlim:in_1"},
|
||||
{"output": "tmb_comp:out_r", "input": "tlim:in_2"}
|
||||
],
|
||||
"inputs": [
|
||||
"user_eq:in_l",
|
||||
@@ -260,20 +225,6 @@
|
||||
"wlim:out_2",
|
||||
"tlim:out_1",
|
||||
"tlim:out_2"
|
||||
],
|
||||
"capture.volumes": [
|
||||
{
|
||||
"control": "ell:volume",
|
||||
"min": -65.0,
|
||||
"max": 0.0,
|
||||
"scale": "linear"
|
||||
},
|
||||
{
|
||||
"control": "elr:volume",
|
||||
"min": -65.0,
|
||||
"max": 0.0,
|
||||
"scale": "linear"
|
||||
}
|
||||
]
|
||||
},
|
||||
"capture.props": {
|
||||
|
||||
15
laptop-configs/apple/mbp15_1/profile.json
Normal file
15
laptop-configs/apple/mbp15_1/profile.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "apple_mbp15_1",
|
||||
"name": "MacBook Pro 15,1 (2018/2019)",
|
||||
"vendor": "Apple Inc.",
|
||||
"dmi_matches": [
|
||||
"MacBookPro15,1",
|
||||
"MacBookPro15,3"
|
||||
],
|
||||
"sys_dir": "/usr/share/t2-linux-audio/15_1",
|
||||
"channels": 4,
|
||||
"crossover_freq_hz": 180.0,
|
||||
"woofer_tail_taps": 16384,
|
||||
"tweeter_tail_taps": 8192,
|
||||
"lead_trim_ms": 5.0
|
||||
}
|
||||
BIN
laptop-configs/apple/mbp15_1/tweeters-44k.wav
Normal file
BIN
laptop-configs/apple/mbp15_1/tweeters-44k.wav
Normal file
Binary file not shown.
BIN
laptop-configs/apple/mbp15_1/tweeters-48k.wav
Normal file
BIN
laptop-configs/apple/mbp15_1/tweeters-48k.wav
Normal file
Binary file not shown.
BIN
laptop-configs/apple/mbp15_1/tweeters-96k.wav
Normal file
BIN
laptop-configs/apple/mbp15_1/tweeters-96k.wav
Normal file
Binary file not shown.
BIN
laptop-configs/apple/mbp15_1/woofers-44k.wav
Normal file
BIN
laptop-configs/apple/mbp15_1/woofers-44k.wav
Normal file
Binary file not shown.
BIN
laptop-configs/apple/mbp15_1/woofers-48k.wav
Normal file
BIN
laptop-configs/apple/mbp15_1/woofers-48k.wav
Normal file
Binary file not shown.
BIN
laptop-configs/apple/mbp15_1/woofers-96k.wav
Normal file
BIN
laptop-configs/apple/mbp15_1/woofers-96k.wav
Normal file
Binary file not shown.
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"enabled": 0, "mode": 0, "g_in": 1.0, "g_out": 1.00,
|
||||
"ft_0": 5, "f_0": 70.0 , "g_0": 1.1, "q_0": 0.7, "s_0": 0,
|
||||
"ft_1": 1, "f_1": 110.0 , "g_1": 1.1, "q_1": 1.0,
|
||||
"ft_2": 1, "f_2": 315.0 , "g_2": 1.05, "q_2": 1.0,
|
||||
"ft_3": 1, "f_3": 1000.0 , "g_3": 1.01, "q_3": 1.0,
|
||||
"ft_4": 1, "f_4": 2500.0 , "g_4": 0.98, "q_4": 1.0,
|
||||
"ft_5": 1, "f_5": 6000.0 , "g_5": 0.97, "q_5": 1.0,
|
||||
"ft_6": 3, "f_6": 10000.0, "g_6": 0.96, "q_6": 0.7,
|
||||
"ft_7": 3, "f_7": 16000.0, "g_7": 0.95, "q_7": 0.7, "s_7": 0
|
||||
"enabled": 1, "mode": 0, "g_in": 1.0, "g_out": 1.0,
|
||||
"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_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,
|
||||
"ft_6": 1, "f_6": 6000.0, "g_6": 1.0, "q_6": 1.0,
|
||||
"ft_7": 3, "f_7": 10000.0, "g_7": 1.0, "q_7": 0.7, "s_7": 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user