refactor: enhance FIR baking process and simplify graph generation with biquad extraction
This commit is contained in:
31
apply.sh
31
apply.sh
@@ -33,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/" 2>/dev/null || true
|
||||
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; }
|
||||
@@ -53,7 +45,8 @@ 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 --------------------
|
||||
# --- 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"
|
||||
@@ -61,13 +54,25 @@ if [ -f "$OVERRIDE" ]; then
|
||||
|| 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"
|
||||
|
||||
|
||||
146
bake-graph.py
146
bake-graph.py
@@ -272,24 +272,67 @@ def apply_pink_noise_target_filter(samples, fs=48000, f_ref=1000.0):
|
||||
pink_samples = [ifft_vals[k].real / pad_len for k in range(N)]
|
||||
return pink_samples
|
||||
|
||||
def bake_driver_ir(src_wav, dst_wav, is_woofer=False, driver_gain=1.0):
|
||||
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)
|
||||
|
||||
# 2. True-Peak Inter-Sample Peak (ISP) Guarding (-0.5 dBFS ceiling)
|
||||
# 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(profile_dir=None):
|
||||
def generate_simple_graph_and_bake(profile_dir=None, input_graph_path=None):
|
||||
if not profile_dir:
|
||||
try:
|
||||
import detect_hardware
|
||||
@@ -300,9 +343,12 @@ def generate_simple_graph_and_bake(profile_dir=None):
|
||||
if not profile_dir or not os.path.exists(profile_dir):
|
||||
profile_dir = os.path.join(SCRIPT_DIR, "15_1")
|
||||
|
||||
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")
|
||||
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")
|
||||
|
||||
@@ -320,7 +366,7 @@ def generate_simple_graph_and_bake(profile_dir=None):
|
||||
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", ""):
|
||||
@@ -331,69 +377,96 @@ def generate_simple_graph_and_bake(profile_dir=None):
|
||||
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
|
||||
# 3. Build graph_simple.json dynamically from graph.json (omitting user_eq, equalizer, and whp* nodes)
|
||||
graph["node.description"] = "MacBook Pro 15,1 DSP Speakers (Baked FIR Crossovers & Latency Trimming)"
|
||||
new_nodes = []
|
||||
|
||||
for node in nodes:
|
||||
name = node.get("name", "")
|
||||
if name in ["whpL1", "whpL2", "whpR1", "whpR2"]:
|
||||
# Omit user_eq, equalizer (baked into FIRs), and whp* crossover nodes
|
||||
if name in ["user_eq", "equalizer", "whpL1", "whpL2", "whpR1", "whpR2"]:
|
||||
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)
|
||||
|
||||
# Re-wire links: filter out removed whp* crossover nodes
|
||||
# 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:
|
||||
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):
|
||||
continue
|
||||
new_links.append(link)
|
||||
|
||||
# Set graph inputs directly to user_eq (first node in processing chain)
|
||||
# Wire virtualbass -> loudness (stereo)
|
||||
new_links.append({"output": "virtualbass:out_l", "input": "loudness:in_l"})
|
||||
new_links.append({"output": "virtualbass:out_r", "input": "loudness:in_r"})
|
||||
|
||||
# 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"
|
||||
]
|
||||
|
||||
# Remove capture.volumes from filter.graph if present
|
||||
@@ -424,7 +497,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.")
|
||||
|
||||
|
||||
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.50,
|
||||
"ft_0": 5,
|
||||
"f_0": 70.0,
|
||||
"g_0": 1.00,
|
||||
"q_0": 0.7,
|
||||
"s_0": 0,
|
||||
"ft_1": 1,
|
||||
"f_1": 110.0,
|
||||
"g_1": 1.05,
|
||||
"q_1": 1.0,
|
||||
"ft_2": 1,
|
||||
"f_2": 315.0,
|
||||
"g_2": 1.03,
|
||||
"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.98,
|
||||
"q_5": 1.0,
|
||||
"ft_6": 3,
|
||||
"f_6": 10000.0,
|
||||
"g_6": 0.95,
|
||||
"q_6": 0.7,
|
||||
"ft_7": 3,
|
||||
"f_7": 16000.0,
|
||||
"g_7": 0.98,
|
||||
"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": 4
|
||||
}
|
||||
},
|
||||
{
|
||||
"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.0,
|
||||
"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": -2,
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user