mirror of
https://github.com/NixOS/nixos-hardware
synced 2024-11-22 19:09:42 +01:00
framework: Add hardware.framework.laptop13.audioEnhancement
option
Co-authored-by: Jörg Thalheim <Mic92@users.noreply.github.com>
This commit is contained in:
parent
c2c275fbb2
commit
672ac2ac86
5 changed files with 394 additions and 5 deletions
|
@ -7,4 +7,6 @@
|
||||||
# Requires at least 5.16 for working wi-fi and bluetooth.
|
# Requires at least 5.16 for working wi-fi and bluetooth.
|
||||||
# https://community.frame.work/t/using-the-ax210-with-linux-on-the-framework-laptop/1844/89
|
# https://community.frame.work/t/using-the-ax210-with-linux-on-the-framework-laptop/1844/89
|
||||||
boot.kernelPackages = lib.mkIf (lib.versionOlder pkgs.linux.version "5.16") (lib.mkDefault pkgs.linuxPackages_latest);
|
boot.kernelPackages = lib.mkIf (lib.versionOlder pkgs.linux.version "5.16") (lib.mkDefault pkgs.linuxPackages_latest);
|
||||||
|
|
||||||
|
hardware.framework.laptop13.audioEnhancement.rawDeviceName = lib.mkDefault "alsa_output.pci-0000_00_1f.3.analog-stereo";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
../common
|
../common
|
||||||
|
@ -8,17 +8,19 @@
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
{
|
{
|
||||||
hardware.intelgpu.loadInInitrd = lib.versionOlder config.boot.kernelPackages.kernel.version "6.2";
|
hardware.intelgpu.loadInInitrd = lib.versionOlder config.boot.kernelPackages.kernel.version "6.2";
|
||||||
|
# same as 13th gen framework 13-inch
|
||||||
|
hardware.framework.laptop13.audioEnhancement.rawDeviceName = lib.mkDefault "alsa_output.pci-0000_00_1f.3.analog-stereo";
|
||||||
}
|
}
|
||||||
# https://community.frame.work/t/tracking-hard-freezing-on-fedora-36-with-the-new-12th-gen-system/20675/391
|
# https://community.frame.work/t/tracking-hard-freezing-on-fedora-36-with-the-new-12th-gen-system/20675/391
|
||||||
(lib.mkIf (lib.versionOlder config.boot.kernelPackages.kernel.version "6.2") {
|
(lib.mkIf (lib.versionOlder config.boot.kernelPackages.kernel.version "6.2") {
|
||||||
boot.kernelParams = [
|
boot.kernelParams = [
|
||||||
# Workaround iGPU hangs
|
# Workaround iGPU hangs
|
||||||
# https://discourse.nixos.org/t/intel-12th-gen-igpu-freezes/21768/4
|
# https://discourse.nixos.org/t/intel-12th-gen-igpu-freezes/21768/4
|
||||||
"i915.enable_psr=1"
|
"i915.enable_psr=1"
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
(lib.mkIf (lib.versionOlder config.boot.kernelPackages.kernel.version "6.8") {
|
(lib.mkIf (lib.versionOlder config.boot.kernelPackages.kernel.version "6.8") {
|
||||||
boot.blacklistedKernelModules = [
|
boot.blacklistedKernelModules = [
|
||||||
# This enables the brightness and airplane mode keys to work
|
# This enables the brightness and airplane mode keys to work
|
||||||
# https://community.frame.work/t/12th-gen-not-sending-xf86monbrightnessup-down/20605/11
|
# https://community.frame.work/t/12th-gen-not-sending-xf86monbrightnessup-down/20605/11
|
||||||
"hid-sensor-hub"
|
"hid-sensor-hub"
|
||||||
|
@ -27,7 +29,7 @@
|
||||||
(lib.mkIf (config.hardware.framework.enableKmod == false) "cros_ec_lpcs")
|
(lib.mkIf (config.hardware.framework.enableKmod == false) "cros_ec_lpcs")
|
||||||
];
|
];
|
||||||
|
|
||||||
boot.kernelParams = [
|
boot.kernelParams = [
|
||||||
# For Power consumption
|
# For Power consumption
|
||||||
# https://kvark.github.io/linux/framework/2021/10/17/framework-nixos.html
|
# https://kvark.github.io/linux/framework/2021/10/17/framework-nixos.html
|
||||||
# Update 04/2024: Combined with acpi_osi from framework-intel it increases the idle power-usage in my test (SebTM)
|
# Update 04/2024: Combined with acpi_osi from framework-intel it increases the idle power-usage in my test (SebTM)
|
||||||
|
|
|
@ -32,5 +32,7 @@ in
|
||||||
# https://community.frame.work/t/tracking-framework-amd-ryzen-7040-series-lid-wakeup-behavior-feedback/39128/45
|
# https://community.frame.work/t/tracking-framework-amd-ryzen-7040-series-lid-wakeup-behavior-feedback/39128/45
|
||||||
ACTION=="add", SUBSYSTEM=="serio", DRIVERS=="atkbd", ATTR{power/wakeup}="disabled"
|
ACTION=="add", SUBSYSTEM=="serio", DRIVERS=="atkbd", ATTR{power/wakeup}="disabled"
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
hardware.framework.laptop13.audioEnhancement.rawDeviceName = lib.mkDefault "alsa_output.pci-0000_c1_00.6.analog-stereo";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
382
framework/13-inch/common/audio.nix
Normal file
382
framework/13-inch/common/audio.nix
Normal file
|
@ -0,0 +1,382 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.hardware.framework.laptop13.audioEnhancement;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
hardware.framework.laptop13.audioEnhancement = {
|
||||||
|
enable = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Create a new audio device called "Framework Speakers",
|
||||||
|
which applies sound tuning before sending the audio out to the speakers.
|
||||||
|
This option requires PipeWire and WirePlumber.
|
||||||
|
|
||||||
|
The filter chain includes the following:
|
||||||
|
- Pyschoacoustic bass enhancement
|
||||||
|
- Loudness compensation
|
||||||
|
- Equalizer
|
||||||
|
- Slight compression
|
||||||
|
|
||||||
|
This option has been optimised for the Framework Laptop 13 AMD 7040 series, but should work on all models.
|
||||||
|
|
||||||
|
Before applying, ensure the speakers are set to 100%,
|
||||||
|
because the volumes compound and the raw speaker device will be hidden by default.
|
||||||
|
|
||||||
|
You might also need to re-select the default output device.
|
||||||
|
|
||||||
|
In some cases, the added bass will vibrate the keyboard cable leading to a rattling sound,
|
||||||
|
a piece of foam can be used to mitigate this.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
hideRawDevice = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Hide the raw speaker device.
|
||||||
|
This option is enabled by default, because keeping the raw speaker device can lead to volume conflicts.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
rawDeviceName = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
example = "alsa_output.pci-0000_c1_00.6.analog-stereo";
|
||||||
|
description = ''
|
||||||
|
The name of the raw speaker device. This will vary by device.
|
||||||
|
You can get this by running `pw-dump | grep -C 20 pci-0000`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable (let
|
||||||
|
outputName = cfg.rawDeviceName;
|
||||||
|
prettyName = "Framework Speakers";
|
||||||
|
|
||||||
|
# These are pre-made decibel to linear value conversions, since Nix doesn't have pow().
|
||||||
|
# Use the formula `10 ** (db / 20)` to calculate.
|
||||||
|
db = {
|
||||||
|
"-18.1" = 0.1244514611771385;
|
||||||
|
"-5.48" = 0.5321082592667942;
|
||||||
|
"-4.76" = 0.5780960474057181;
|
||||||
|
"8.1" = 2.5409727055493048;
|
||||||
|
"-36" = 1.5848931924611134e-2;
|
||||||
|
};
|
||||||
|
|
||||||
|
json = pkgs.formats.json { };
|
||||||
|
|
||||||
|
# The filter chain, heavily inspired by the asahi-audio project: https://github.com/AsahiLinux/asahi-audio
|
||||||
|
filter-chain = json.generate "filter-chain.json" {
|
||||||
|
"node.description" = prettyName;
|
||||||
|
"media.name" = prettyName;
|
||||||
|
"filter.graph" = {
|
||||||
|
nodes = [
|
||||||
|
# Psychoacoustic bass extension,
|
||||||
|
# it creates harmonics of the missing bass to fool our ears into hearing it.
|
||||||
|
{
|
||||||
|
type = "lv2";
|
||||||
|
plugin = "https://chadmed.au/bankstown";
|
||||||
|
name = "bassex";
|
||||||
|
control = {
|
||||||
|
bypass = 0;
|
||||||
|
amt = 1.2;
|
||||||
|
sat_second = 1.3;
|
||||||
|
sat_third = 2.5;
|
||||||
|
blend = 1.0;
|
||||||
|
ceil = 200.0;
|
||||||
|
floor = 20.0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
# Loudness compensation,
|
||||||
|
# it ensures that the sound profile stays consistent across different volumes.
|
||||||
|
{
|
||||||
|
type = "lv2";
|
||||||
|
plugin = "http://lsp-plug.in/plugins/lv2/loud_comp_stereo";
|
||||||
|
name = "el";
|
||||||
|
control = {
|
||||||
|
enabled = 1;
|
||||||
|
input = 1.0;
|
||||||
|
fft = 4;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
# 8-band equalizer,
|
||||||
|
# it tries to lessen frequencies where the laptop might resonate,
|
||||||
|
# and tries to make the frequency curve more pleasing;
|
||||||
|
# this is the "Lappy McTopface" profile (https://github.com/ceiphr/ee-framework-presets)
|
||||||
|
# further tuned for the Framework Laptop 13 AMD 7040 series
|
||||||
|
# and might need some tuning on other models.
|
||||||
|
{
|
||||||
|
type = "lv2";
|
||||||
|
plugin = "http://lsp-plug.in/plugins/lv2/para_equalizer_x8_lr";
|
||||||
|
name = "fw13eq";
|
||||||
|
control = {
|
||||||
|
mode = 0;
|
||||||
|
react = 0.2;
|
||||||
|
zoom = db."-36";
|
||||||
|
|
||||||
|
fl_0 = 101.0;
|
||||||
|
fml_0 = 0;
|
||||||
|
ftl_0 = 5;
|
||||||
|
gl_0 = db."-18.1";
|
||||||
|
huel_0 = 0.0;
|
||||||
|
ql_0 = 4.36;
|
||||||
|
sl_0 = 0;
|
||||||
|
wl_0 = 4.0;
|
||||||
|
|
||||||
|
fl_1 = 451.0;
|
||||||
|
fml_1 = 0;
|
||||||
|
ftl_1 = 1;
|
||||||
|
gl_1 = db."-5.48";
|
||||||
|
huel_1 = 3.125e-2;
|
||||||
|
ql_1 = 2.46;
|
||||||
|
sl_1 = 0;
|
||||||
|
wl_1 = 4.0;
|
||||||
|
|
||||||
|
fl_2 = 918.0;
|
||||||
|
fml_2 = 0;
|
||||||
|
ftl_2 = 1;
|
||||||
|
gl_2 = db."-4.76";
|
||||||
|
huel_2 = 6.25e-2;
|
||||||
|
ql_2 = 2.44;
|
||||||
|
sl_2 = 0;
|
||||||
|
wl_2 = 4.0;
|
||||||
|
|
||||||
|
fl_3 = 9700.0;
|
||||||
|
fml_3 = 0;
|
||||||
|
ftl_3 = 1;
|
||||||
|
gl_3 = db."8.1";
|
||||||
|
huel_3 = 9.375e-2;
|
||||||
|
ql_3 = 2.0;
|
||||||
|
sl_3 = 0;
|
||||||
|
wl_3 = 4.0;
|
||||||
|
|
||||||
|
fr_0 = 101.0;
|
||||||
|
fmr_0 = 0;
|
||||||
|
ftr_0 = 5;
|
||||||
|
gr_0 = db."-18.1";
|
||||||
|
huer_0 = 0.0;
|
||||||
|
qr_0 = 4.36;
|
||||||
|
sr_0 = 0;
|
||||||
|
wr_0 = 4.0;
|
||||||
|
|
||||||
|
fr_1 = 451.0;
|
||||||
|
fmr_1 = 0;
|
||||||
|
ftr_1 = 1;
|
||||||
|
gr_1 = db."-5.48";
|
||||||
|
huer_1 = 3.125e-2;
|
||||||
|
qr_1 = 2.46;
|
||||||
|
sr_1 = 0;
|
||||||
|
wr_1 = 4.0;
|
||||||
|
|
||||||
|
fr_2 = 918.0;
|
||||||
|
fmr_2 = 0;
|
||||||
|
ftr_2 = 1;
|
||||||
|
gr_2 = db."-4.76";
|
||||||
|
huer_2 = 6.25e-2;
|
||||||
|
qr_2 = 2.44;
|
||||||
|
sr_2 = 0;
|
||||||
|
wr_2 = 4.0;
|
||||||
|
|
||||||
|
fr_3 = 9700.0;
|
||||||
|
fmr_3 = 0;
|
||||||
|
ftr_3 = 1;
|
||||||
|
gr_3 = db."8.1";
|
||||||
|
huer_3 = 9.375e-2;
|
||||||
|
qr_3 = 2.0;
|
||||||
|
sr_3 = 0;
|
||||||
|
wr_3 = 4.0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
# Compressors. The settings were taken from the asahi-audio project.
|
||||||
|
{
|
||||||
|
type = "lv2";
|
||||||
|
plugin = "http://lsp-plug.in/plugins/lv2/mb_compressor_stereo";
|
||||||
|
name = "woofer_bp";
|
||||||
|
control = {
|
||||||
|
mode = 0;
|
||||||
|
ce_0 = 1;
|
||||||
|
sla_0 = 5.0;
|
||||||
|
cr_0 = 1.75;
|
||||||
|
al_0 = 0.725;
|
||||||
|
at_0 = 1.0;
|
||||||
|
rt_0 = 100;
|
||||||
|
kn_0 = 0.125;
|
||||||
|
cbe_1 = 1;
|
||||||
|
sf_1 = 200.0;
|
||||||
|
ce_1 = 0;
|
||||||
|
cbe_2 = 0;
|
||||||
|
ce_2 = 0;
|
||||||
|
cbe_3 = 0;
|
||||||
|
ce_3 = 0;
|
||||||
|
cbe_4 = 0;
|
||||||
|
ce_4 = 0;
|
||||||
|
cbe_5 = 0;
|
||||||
|
ce_5 = 0;
|
||||||
|
cbe_6 = 0;
|
||||||
|
ce_6 = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type = "lv2";
|
||||||
|
plugin = "http://lsp-plug.in/plugins/lv2/compressor_stereo";
|
||||||
|
name = "woofer_lim";
|
||||||
|
control = {
|
||||||
|
sla = 5.0;
|
||||||
|
al = 1.0;
|
||||||
|
at = 1.0;
|
||||||
|
rt = 100.0;
|
||||||
|
cr = 15.0;
|
||||||
|
kn = 0.5;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# Now, we're chaining together the modules instantiated above.
|
||||||
|
links = [
|
||||||
|
{
|
||||||
|
output = "bassex:out_l";
|
||||||
|
input = "el:in_l";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
output = "bassex:out_r";
|
||||||
|
input = "el:in_r";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
output = "el:out_l";
|
||||||
|
input = "fw13eq:in_l";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
output = "el:out_r";
|
||||||
|
input = "fw13eq:in_r";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
output = "fw13eq:out_l";
|
||||||
|
input = "woofer_bp:in_l";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
output = "fw13eq:out_r";
|
||||||
|
input = "woofer_bp:in_r";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
output = "woofer_bp:out_l";
|
||||||
|
input = "woofer_lim:in_l";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
output = "woofer_bp:out_r";
|
||||||
|
input = "woofer_lim:in_r";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
inputs = [
|
||||||
|
"bassex:in_l"
|
||||||
|
"bassex:in_r"
|
||||||
|
];
|
||||||
|
outputs = [
|
||||||
|
"woofer_lim:out_l"
|
||||||
|
"woofer_lim:out_r"
|
||||||
|
];
|
||||||
|
|
||||||
|
# This makes pipewire's volume control actually control the loudness comp module
|
||||||
|
"capture.volumes" = [
|
||||||
|
{
|
||||||
|
control = "el:volume";
|
||||||
|
min = -47.5;
|
||||||
|
max = 0.0;
|
||||||
|
scale = "cubic";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
"capture.props" = {
|
||||||
|
"node.name" = "audio_effect.laptop-convolver";
|
||||||
|
"media.class" = "Audio/Sink";
|
||||||
|
"audio.channels" = "2";
|
||||||
|
"audio.position" = [
|
||||||
|
"FL"
|
||||||
|
"FR"
|
||||||
|
];
|
||||||
|
"audio.allowed-rates" = [
|
||||||
|
44100
|
||||||
|
48000
|
||||||
|
88200
|
||||||
|
96000
|
||||||
|
176400
|
||||||
|
192000
|
||||||
|
];
|
||||||
|
"device.api" = "dsp";
|
||||||
|
"node.virtual" = "false";
|
||||||
|
|
||||||
|
# Lower seems to mean "more preferred",
|
||||||
|
# bluetooth devices seem to be ~1000, speakers seem to be ~2000
|
||||||
|
# since this is between the two, bluetooth devices take over when they connect,
|
||||||
|
# and hand over to this instead of the speakers when they disconnect.
|
||||||
|
"priority.session" = 1500;
|
||||||
|
"priority.driver" = 1500;
|
||||||
|
"state.default-volume" = 0.343;
|
||||||
|
"device.icon-name" = "audio-card-analog-pci";
|
||||||
|
};
|
||||||
|
"playback.props" = {
|
||||||
|
"node.name" = "audio_effect.laptop-convolver";
|
||||||
|
"target.object" = outputName;
|
||||||
|
"node.passive" = "true";
|
||||||
|
"audio.channels" = "2";
|
||||||
|
"audio.allowed-rates" = [
|
||||||
|
44100
|
||||||
|
48000
|
||||||
|
88200
|
||||||
|
96000
|
||||||
|
176400
|
||||||
|
192000
|
||||||
|
];
|
||||||
|
"audio.position" = [
|
||||||
|
"FL"
|
||||||
|
"FR"
|
||||||
|
];
|
||||||
|
"device.icon-name" = "audio-card-analog-pci";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
configPackage =
|
||||||
|
(pkgs.writeTextDir "share/wireplumber/wireplumber.conf.d/99-laptop.conf" ''
|
||||||
|
monitor.alsa.rules = [
|
||||||
|
{
|
||||||
|
matches = [{ node.name = "${outputName}" }]
|
||||||
|
actions = {
|
||||||
|
update-props = {
|
||||||
|
audio.allowed-rates = [44100, 48000, 88200, 96000, 176400, 192000]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
node.software-dsp.rules = [
|
||||||
|
{
|
||||||
|
matches = [{ node.name = "${outputName}" }]
|
||||||
|
actions = {
|
||||||
|
create-filter = {
|
||||||
|
filter-path = "${filter-chain}"
|
||||||
|
hide-parent = ${lib.boolToString cfg.hideRawDevice}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
wireplumber.profiles = {
|
||||||
|
main = { node.software-dsp = "required" }
|
||||||
|
}
|
||||||
|
'')
|
||||||
|
// {
|
||||||
|
passthru.requiredLv2Packages = with pkgs; [
|
||||||
|
lsp-plugins
|
||||||
|
bankstown-lv2
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
services.pipewire.wireplumber.configPackages = [ configPackage ];
|
||||||
|
|
||||||
|
# Pipewire is needed for this.
|
||||||
|
services.pipewire.enable = lib.mkDefault true;
|
||||||
|
});
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
../../bluetooth.nix
|
../../bluetooth.nix
|
||||||
../../kmod.nix
|
../../kmod.nix
|
||||||
../../framework-tool.nix
|
../../framework-tool.nix
|
||||||
|
./audio.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
# Fix TRRS headphones missing a mic
|
# Fix TRRS headphones missing a mic
|
||||||
|
|
Loading…
Reference in a new issue