audio: add eq parser
This commit is contained in:
parent
35c8ebb56a
commit
e865cd7c8f
1 changed files with 188 additions and 2 deletions
|
|
@ -4,12 +4,193 @@
|
|||
lib,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.xyno.desktop.audio;
|
||||
json = pkgs.formats.json { };
|
||||
toFloat = builtins.fromJSON;
|
||||
readFilterTxt =
|
||||
text:
|
||||
let
|
||||
lines = splitString "\n" text;
|
||||
consumeLine =
|
||||
line:
|
||||
let
|
||||
parts = splitString " " line;
|
||||
content = foldl (
|
||||
props: str:
|
||||
if props.lastNode == "Filter" then
|
||||
props
|
||||
// {
|
||||
nr = toInt (removeSuffix ":" str);
|
||||
lastNode = str;
|
||||
}
|
||||
else if props.lastNode == "Preamp:" then
|
||||
props
|
||||
// {
|
||||
nr = 0;
|
||||
gain = toFloat str;
|
||||
label = "HSC";
|
||||
lastNode = str;
|
||||
freq = 0;
|
||||
q = 1.0;
|
||||
}
|
||||
else if props.lastNode == "ON" then
|
||||
props
|
||||
// {
|
||||
label = str;
|
||||
lastNode = str;
|
||||
}
|
||||
else if props.lastNode == "Fc" then
|
||||
props
|
||||
// {
|
||||
freq = toInt str;
|
||||
lastNode = str;
|
||||
}
|
||||
else if props.lastNode == "Gain" then
|
||||
props
|
||||
// {
|
||||
gain = toFloat str;
|
||||
lastNode = str;
|
||||
}
|
||||
else if props.lastNode == "Q" then
|
||||
props
|
||||
// {
|
||||
q = toFloat str;
|
||||
lastNode = str;
|
||||
}
|
||||
else
|
||||
|
||||
props // { lastNode = str; }
|
||||
) { lastNode = null; } parts;
|
||||
in
|
||||
content;
|
||||
in
|
||||
filter (x: x ? nr) (map consumeLine lines);
|
||||
genFilterGraph = filters: {
|
||||
nodes = (
|
||||
map (filter: {
|
||||
type = "builtin";
|
||||
name = "eq_band_${toString (filter.nr + 1)}";
|
||||
label =
|
||||
if filter.label == "HSC" then
|
||||
"bq_highshelf"
|
||||
else if filter.label == "LSC" then
|
||||
"bq_lowshelf"
|
||||
else
|
||||
"bq_peaking";
|
||||
control = {
|
||||
Freq = filter.freq;
|
||||
Q = filter.q;
|
||||
Gain = filter.gain;
|
||||
};
|
||||
|
||||
}) filters
|
||||
);
|
||||
links = map (x: {
|
||||
output = "eq_band_${toString x}:Out";
|
||||
input = "eq_band_${toString (x + 1)}:In";
|
||||
}) (range 1 ((builtins.length filters) - 1));
|
||||
};
|
||||
genfilterChain =
|
||||
cfg':
|
||||
json.generate "filter-chain.json" (
|
||||
recursiveUpdate {
|
||||
"node.description" = cfg'.displayName;
|
||||
"media.name" = cfg'.displayName;
|
||||
"filter.graph" = genFilterGraph (readFilterTxt cfg'.filterText);
|
||||
"audio.channels" = 2;
|
||||
"audio.position" = [
|
||||
"FL"
|
||||
"FR"
|
||||
];
|
||||
"capture.props" = {
|
||||
"node.name" = "effect_input.${cfg'.internalName}";
|
||||
"media.class" = "Audio/Sink";
|
||||
};
|
||||
"playback.props" = {
|
||||
"node.name" = "effect_output.${cfg'.internalName}";
|
||||
"node.passive" = true;
|
||||
"target.object" = cfg'.hwAddr;
|
||||
};
|
||||
} cfg'.extraConfig
|
||||
);
|
||||
eqPkg =
|
||||
cfg':
|
||||
(pkgs.writeTextDir "share/wireplumber/wireplumber.conf.d/99-${cfg'.internalName}.conf" ''
|
||||
node.software-dsp.rules = [
|
||||
{
|
||||
matches = [{ node.name = "${cfg'.hwAddr}" }]
|
||||
actions = {
|
||||
create-filter = {
|
||||
filter-path = "${genfilterChain cfg'}"
|
||||
hide-parent = ${boolToString cfg'.hideParent}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
wireplumber.profiles = {
|
||||
main = { node.software-dsp = "required" }
|
||||
}
|
||||
'')
|
||||
// {
|
||||
passthru.requiredLv2Packages = with pkgs; [
|
||||
lsp-plugins
|
||||
bankstown-lv2
|
||||
];
|
||||
|
||||
};
|
||||
|
||||
eqSubmodule =
|
||||
{ name, ... }:
|
||||
{
|
||||
options = {
|
||||
internalName = mkOption {
|
||||
type = types.str;
|
||||
default = name;
|
||||
internal = true;
|
||||
};
|
||||
displayName = mkOption { type = types.str; };
|
||||
hwAddr = mkOption { type = types.str; };
|
||||
filterText = mkOption { type = types.str; };
|
||||
hideParent = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
extraConfig = mkOption {
|
||||
type = types.attrsOf types.anything;
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
options.xyno.desktop.audio.enable = lib.mkEnableOption "enable pipewire and stuff";
|
||||
config = lib.mkIf cfg.enable {
|
||||
options.xyno.desktop.audio.enable = mkEnableOption "enable pipewire and stuff";
|
||||
options.xyno.desktop.audio.eq = mkOption {
|
||||
type = types.attrsOf (types.submodule eqSubmodule);
|
||||
default = { };
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
xyno.desktop.audio.eq.se215 = {
|
||||
displayName = "Shure SE215";
|
||||
hwAddr = "alsa_output.usb-Synaptics_CX31993_384Khz_HIFI_AUDIO-00.analog-stereo";
|
||||
extraConfig."capture.props"."device.icon-name" = "audio-headphones";
|
||||
filterText = ''
|
||||
Preamp: -5.7 dB
|
||||
Filter 1: ON LSC Fc 105 Hz Gain 0.3 dB Q 0.70
|
||||
Filter 2: ON PK Fc 174 Hz Gain -4.6 dB Q 0.68
|
||||
Filter 3: ON PK Fc 811 Hz Gain 3.1 dB Q 1.42
|
||||
Filter 4: ON PK Fc 3430 Hz Gain 3.8 dB Q 4.37
|
||||
Filter 5: ON PK Fc 6943 Hz Gain 5.4 dB Q 2.76
|
||||
Filter 6: ON HSC Fc 10000 Hz Gain 3.8 dB Q 0.70
|
||||
Filter 7: ON PK Fc 5725 Hz Gain 8.1 dB Q 1.13
|
||||
Filter 8: ON PK Fc 5056 Hz Gain -10.9 dB Q 2.93
|
||||
Filter 9: ON PK Fc 7269 Hz Gain -6.3 dB Q 3.47
|
||||
Filter 10: ON PK Fc 2278 Hz Gain -2.1 dB Q 2.94
|
||||
'';
|
||||
};
|
||||
services.pipewire = {
|
||||
enable = true;
|
||||
# raopOpenFirewall = true; # airplay
|
||||
|
|
@ -20,7 +201,9 @@ in
|
|||
"default.clock.allowed-rates" = [
|
||||
"44100"
|
||||
"48000"
|
||||
"88200"
|
||||
"96000"
|
||||
"176400"
|
||||
"192000"
|
||||
];
|
||||
};
|
||||
|
|
@ -44,6 +227,9 @@ in
|
|||
];
|
||||
};
|
||||
};
|
||||
wireplumber.extraConfig."98-bluetooth"."wireplumber.settings"."bluetooth.autoswitch-to-headset-profile" =
|
||||
false;
|
||||
wireplumber.configPackages = mapAttrsToList (n: v: eqPkg v) cfg.eq;
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue