Merge pull request 'feat: add user_eq override functionality and update documentation' (#3) from loudness-tracked-tilt into main
Reviewed-on: #3
This commit was merged in pull request #3.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,5 @@
|
||||
# Bankstown source checkout + build output from install-deps.sh
|
||||
/build/
|
||||
|
||||
# Local user_eq override consumed by apply.sh (copy from user_eq.example.json)
|
||||
/user_eq.json
|
||||
|
||||
35
INSTALL.md
35
INSTALL.md
@@ -147,16 +147,19 @@ If you have your own recalibrated FIRs, drop them at that path (or edit the six
|
||||
./apply.sh
|
||||
```
|
||||
|
||||
`apply.sh` preflights before touching anything:
|
||||
`apply.sh`:
|
||||
|
||||
1. validates `graph.json` is well-formed JSON (`python3` or `jq`)
|
||||
2. checks the `/usr/share/t2-linux-audio/15_1/` dir exists (§1)
|
||||
3. checks every FIR `.wav` **referenced by the graph** is present (§4)
|
||||
4. checks every LV2 plugin URI **the graph loads** resolves in `lv2ls` (§3)
|
||||
2. **builds the effective graph** → `~/.audiograph.json`: if `user_eq.json`
|
||||
exists next to the script, its contents replace the `user_eq` node's
|
||||
`control` block (`jq`); otherwise it's a straight copy of `graph.json` (§7)
|
||||
3. checks `/usr/share/t2-linux-audio/15_1/` exists (§1)
|
||||
4. checks every FIR `.wav` **referenced by the graph** is present (§4)
|
||||
5. checks every LV2 plugin URI **the graph loads** resolves in `lv2ls` (§3)
|
||||
|
||||
then `sudo cp`s the graph into place, restarts WirePlumber, and confirms the
|
||||
sink came up. Steps 3–4 read the paths/URIs straight out of `graph.json`, so
|
||||
they stay correct if you edit it.
|
||||
then `sudo cp`s `~/.audiograph.json` into place, restarts WirePlumber, and
|
||||
confirms the sink came up. Steps 4–5 read the paths/URIs straight out of the
|
||||
merged graph, so they stay correct if you edit either file.
|
||||
|
||||
Pass `-f` to skip the preflight (JSON validation still runs):
|
||||
|
||||
@@ -186,11 +189,19 @@ pw-top # look for the filter-chain node, check for XRUN
|
||||
|
||||
## 7. Pick a sound profile
|
||||
|
||||
`user_eq` is the first node in the graph and the only block meant for
|
||||
hand-editing — an 8-band tone control that defaults flat (= the reference
|
||||
voicing). Paste one of the preset rows from
|
||||
[README.md § User preference EQ](README.md#user-preference-eq) into its `control`
|
||||
block and re-run `./apply.sh`.
|
||||
`user_eq` is the first node in the graph — an 8-band tone control that defaults
|
||||
flat (= the reference voicing). To change it without touching the committed
|
||||
`graph.json`:
|
||||
|
||||
```sh
|
||||
cp user_eq.example.json user_eq.json # git-ignored
|
||||
$EDITOR user_eq.json # set the g_* values
|
||||
./apply.sh # merges it into ~/.audiograph.json and installs
|
||||
```
|
||||
|
||||
`jq` must be installed for this path. Delete `user_eq.json` to return to the
|
||||
default. Preset values (Rock, Classical, Movie–dialogue, …) are in
|
||||
[README.md § User preference EQ](README.md#user-preference-eq).
|
||||
|
||||
---
|
||||
|
||||
|
||||
20
README.md
20
README.md
@@ -205,9 +205,23 @@ compressed if pushed hard.
|
||||
| 6 | 6 kHz | bell | detail / sibilance |
|
||||
| 7 | 10 kHz | high shelf | air |
|
||||
|
||||
Edit the `g_*` values in the `user_eq` `control` block. **Linear, not dB**
|
||||
(`+3 dB ≈ 1.41`, `−3 dB ≈ 0.71`). Keep each between `0.5` (−6 dB) and `2.0`
|
||||
(+6 dB). Run `./apply.sh` after.
|
||||
Values are **linear, not dB** (`+3 dB ≈ 1.41`, `−3 dB ≈ 0.71`). Keep each `g_*`
|
||||
between `0.5` (−6 dB) and `2.0` (+6 dB).
|
||||
|
||||
Two ways to set it, both followed by `./apply.sh`:
|
||||
|
||||
- **Override file (recommended, survives `git pull`).** Copy the template and
|
||||
edit it:
|
||||
```sh
|
||||
cp user_eq.example.json user_eq.json
|
||||
$EDITOR user_eq.json
|
||||
```
|
||||
`user_eq.json` is git-ignored. When present, `apply.sh` splices its contents
|
||||
into the `user_eq` node's `control` block with `jq`, writes the result to
|
||||
`~/.audiograph.json`, and installs that. Delete `user_eq.json` to go back to
|
||||
the committed default.
|
||||
- **Edit `graph.json` directly** — change the `g_*` in the `user_eq` `control`
|
||||
block. Simple, but a `git pull` will conflict.
|
||||
|
||||
### Presets — the 8 `g_*` values, `g_0`…`g_7`
|
||||
|
||||
|
||||
66
apply.sh
66
apply.sh
@@ -1,14 +1,21 @@
|
||||
#!/bin/bash
|
||||
# Apply the MacBook Pro 15,1 audio DSP graph:
|
||||
# validate JSON, preflight the prerequisites, install, reload WirePlumber.
|
||||
# build the effective graph, preflight the prerequisites, install, reload.
|
||||
#
|
||||
# ./apply.sh full checks
|
||||
# ./apply.sh -f skip the preflight checks (still validates JSON)
|
||||
# ./apply.sh validate + preflight + build + install + reload
|
||||
# ./apply.sh -f skip the preflight checks (JSON validation still runs)
|
||||
#
|
||||
# If user_eq.json exists next to this script, its contents replace the
|
||||
# "user_eq" node's control block (requires jq) - copy user_eq.example.json to
|
||||
# user_eq.json and edit. The merged graph is written to ~/.audiograph.json and
|
||||
# that file is what gets installed.
|
||||
|
||||
set -u
|
||||
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
|
||||
GRAPH_SRC="$SCRIPT_DIR/graph.json"
|
||||
OVERRIDE="$SCRIPT_DIR/user_eq.json"
|
||||
MERGED="$HOME/.audiograph.json"
|
||||
GRAPH_DST="/usr/share/t2-linux-audio/15_1/graph.json"
|
||||
|
||||
FORCE=0
|
||||
@@ -17,38 +24,55 @@ case "${1:-}" in -f|--force|--no-check) FORCE=1 ;; esac
|
||||
have() { command -v "$1" >/dev/null 2>&1; }
|
||||
die() { echo "Error: $*" >&2; exit 1; }
|
||||
|
||||
# 0 = valid, 1 = invalid, 2 = no validator available
|
||||
json_ok() {
|
||||
if have python3; then python3 -m json.tool "$1" >/dev/null 2>&1
|
||||
elif have jq; then jq -e . "$1" >/dev/null 2>&1
|
||||
else return 2; fi
|
||||
}
|
||||
|
||||
[ -f "$GRAPH_SRC" ] || die "$GRAPH_SRC not found"
|
||||
|
||||
# 1. valid JSON -----------------------------------------------------------
|
||||
if have python3; then
|
||||
python3 -m json.tool "$GRAPH_SRC" >/dev/null || die "graph.json is not valid JSON"
|
||||
echo "ok: graph.json is valid JSON"
|
||||
elif have jq; then
|
||||
jq -e . "$GRAPH_SRC" >/dev/null || die "graph.json is not valid JSON"
|
||||
echo "ok: graph.json is valid JSON"
|
||||
json_ok "$GRAPH_SRC"; rc=$?
|
||||
[ "$rc" -eq 1 ] && die "graph.json is not valid JSON"
|
||||
[ "$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 [ -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.json 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"
|
||||
else
|
||||
echo "warn: no python3/jq - skipping JSON validation"
|
||||
cp "$GRAPH_SRC" "$MERGED"
|
||||
echo "ok: no user_eq.json - graph.json as-is -> $MERGED"
|
||||
fi
|
||||
|
||||
json_ok "$MERGED"; rc=$?
|
||||
[ "$rc" -eq 1 ] && die "merged graph $MERGED is not valid JSON"
|
||||
|
||||
# --- preflight (against the merged graph) ------------------------------
|
||||
if [ "$FORCE" -eq 0 ]; then
|
||||
# 2. t2 speaker-DSP package present --------------------------------
|
||||
[ -d "$(dirname "$GRAPH_DST")" ] || die \
|
||||
"$(dirname "$GRAPH_DST") is missing - install the t2 speaker-DSP package first (INSTALL.md section 1)"
|
||||
|
||||
# 3. FIR files referenced by the graph exist ----------------------
|
||||
miss=0
|
||||
while IFS= read -r w; do
|
||||
[ -f "$w" ] || { echo " missing FIR: $w"; miss=1; }
|
||||
done < <(grep -oE '/[^" ]+\.wav' "$GRAPH_SRC" | sort -u)
|
||||
done < <(grep -oE '/[^" ]+\.wav' "$MERGED" | sort -u)
|
||||
[ "$miss" -eq 0 ] && echo "ok: FIR .wav files present" \
|
||||
|| die "FIR files missing - INSTALL.md section 4"
|
||||
|
||||
# 4. every LV2 plugin URI the graph loads resolves ---------------
|
||||
if have lv2ls; then
|
||||
miss=0
|
||||
while IFS= read -r u; do
|
||||
lv2ls | grep -qxF "$u" || { echo " missing plugin: $u"; miss=1; }
|
||||
done < <(grep '"plugin"' "$GRAPH_SRC" | grep -oE 'https?://[^"]+' | sort -u)
|
||||
done < <(grep '"plugin"' "$MERGED" | grep -oE 'https?://[^"]+' | sort -u)
|
||||
[ "$miss" -eq 0 ] && echo "ok: all LV2 plugins resolve" \
|
||||
|| die "LV2 plugins missing - run ./install-deps.sh (INSTALL.md section 3)"
|
||||
else
|
||||
@@ -56,18 +80,18 @@ if [ "$FORCE" -eq 0 ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# 5. install ------------------------------------------------------------
|
||||
echo "Copying graph.json -> $GRAPH_DST"
|
||||
sudo cp "$GRAPH_SRC" "$GRAPH_DST"
|
||||
# --- install ----------------------------------------------------------
|
||||
echo "Installing $MERGED -> $GRAPH_DST"
|
||||
sudo cp "$MERGED" "$GRAPH_DST"
|
||||
|
||||
echo "Restarting WirePlumber"
|
||||
systemctl --user restart wireplumber
|
||||
|
||||
# 6. confirm ----------------------------------------------------------
|
||||
# --- confirm --------------------------------------------------------
|
||||
sleep 1
|
||||
if have wpctl && wpctl status 2>/dev/null | grep -qi "DSP Speakers"; then
|
||||
echo "Done - 'MacBook Pro 15,1 DSP Speakers' sink is up."
|
||||
else
|
||||
echo "Done - graph copied, WirePlumber restarted."
|
||||
echo "Done - graph installed, WirePlumber restarted."
|
||||
echo "If no 'DSP Speakers' sink shows: journalctl --user -u wireplumber -b -e"
|
||||
fi
|
||||
|
||||
@@ -46,6 +46,13 @@ lv2_have http://plugin.org.uk/swh-plugins/fastLookaheadLimiter && need_swh=0
|
||||
pkgs=()
|
||||
[ "$need_lsp" -eq 1 ] && pkgs+=(lsp-plugins)
|
||||
[ "$need_swh" -eq 1 ] && pkgs+=(swh-plugins)
|
||||
have jq || pkgs+=(jq) # apply.sh needs jq for the user_eq override
|
||||
if ! have lv2ls; then
|
||||
case "$PM" in
|
||||
apt) pkgs+=(lilv-utils) ;;
|
||||
dnf|zypper|pacman) pkgs+=(lilv) ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ "${#pkgs[@]}" -gt 0 ]; then
|
||||
if [ -z "$PM" ]; then
|
||||
|
||||
11
user_eq.example.json
Normal file
11
user_eq.example.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"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