# Dell XPS 14 / XPS 16 (2026) speaker tuning.
#
# Biquad chain fitted to the measured response of the xps-audio-linux EasyEffects
# profile under a dense pink-weighted multitone of 104 bin-aligned tones,
# followed by a lookahead limiter. Measures 1.24 dB RMS against that reference
# (0.97 dB weighted over the fit's own error metric).
#
# Fitted and measured on the XPS 14 (SKU 0DB9); the XPS 16 (0DBA) is covered on
# report that the same profile suits it. See tuning.conf.
#
# Q below 200 Hz is capped at 1.8 on purpose. A closer magnitude fit is possible
# with high-Q sections, but the reference produces its narrow bass features by
# convolution, and reproducing them with high-Q biquads swung group delay 31 ms
# across 63-80 Hz, which smears bass transients. The cap costs 0.33 dB and
# halves the swing.
#
# This is a plain filter-chain sink rather than a WirePlumber smart filter. A
# smart filter is the better shape -- it would leave the real device as the
# default output instead of adding a second one -- but on PipeWire 1.6.8 /
# WirePlumber 0.5.15 this graph loads and links correctly as a smart filter and
# then passes audio through unprocessed: its controls are present and
# mpv -> filter -> sink links are made, yet the filter's input monitor and the
# speaker sink's monitor measure identically. Revisit when that is understood.
#
# Channels are wired explicitly because the limiter is a stereo plugin; a mono
# graph is duplicated per channel and would limit each side independently,
# shifting the stereo image on bass transients.

context.modules = [
  { name = libpipewire-module-filter-chain
    args = {
      node.description = "Laptop Speakers"
      media.name       = "Laptop Speakers"

      filter.graph = {
        nodes = [
          { type = builtin name = s0_l      label = bq_highpass  control = { "Freq" = 60.9 "Q" = 1.0 } }
          { type = builtin name = s1_l      label = bq_highpass  control = { "Freq" = 60.9 "Q" = 1.0 } }
          { type = builtin name = s2_l      label = bq_peaking   control = { "Freq" = 83.4 "Q" = 1.8 "Gain" = -8.0 } }
          { type = builtin name = s3_l      label = bq_peaking   control = { "Freq" = 100.4 "Q" = 1.59 "Gain" = 7.47 } }
          { type = builtin name = s4_l      label = bq_peaking   control = { "Freq" = 250.5 "Q" = 2.966 "Gain" = -4.7 } }
          { type = builtin name = s5_l      label = bq_peaking   control = { "Freq" = 419.8 "Q" = 3.0 "Gain" = -5.83 } }
          { type = builtin name = s6_l      label = bq_peaking   control = { "Freq" = 631.3 "Q" = 2.515 "Gain" = -10.33 } }
          { type = builtin name = s7_l      label = bq_peaking   control = { "Freq" = 894.4 "Q" = 4.0 "Gain" = -2.42 } }
          { type = builtin name = s8_l      label = bq_peaking   control = { "Freq" = 1355.7 "Q" = 2.884 "Gain" = 6.92 } }
          { type = builtin name = s9_l      label = bq_peaking   control = { "Freq" = 1707.2 "Q" = 1.311 "Gain" = -6.54 } }
          { type = builtin name = s10_l     label = bq_peaking   control = { "Freq" = 3100.0 "Q" = 0.5 "Gain" = -10.09 } }
          { type = builtin name = s11_l     label = bq_peaking   control = { "Freq" = 3200.0 "Q" = 1.048 "Gain" = 3.09 } }
          { type = builtin name = s12_l     label = bq_highshelf control = { "Freq" = 6015.2 "Q" = 1.5 "Gain" = -1.34 } }

          { type = builtin name = s0_r      label = bq_highpass  control = { "Freq" = 60.9 "Q" = 1.0 } }
          { type = builtin name = s1_r      label = bq_highpass  control = { "Freq" = 60.9 "Q" = 1.0 } }
          { type = builtin name = s2_r      label = bq_peaking   control = { "Freq" = 83.4 "Q" = 1.8 "Gain" = -8.0 } }
          { type = builtin name = s3_r      label = bq_peaking   control = { "Freq" = 100.4 "Q" = 1.59 "Gain" = 7.47 } }
          { type = builtin name = s4_r      label = bq_peaking   control = { "Freq" = 250.5 "Q" = 2.966 "Gain" = -4.7 } }
          { type = builtin name = s5_r      label = bq_peaking   control = { "Freq" = 419.8 "Q" = 3.0 "Gain" = -5.83 } }
          { type = builtin name = s6_r      label = bq_peaking   control = { "Freq" = 631.3 "Q" = 2.515 "Gain" = -10.33 } }
          { type = builtin name = s7_r      label = bq_peaking   control = { "Freq" = 894.4 "Q" = 4.0 "Gain" = -2.42 } }
          { type = builtin name = s8_r      label = bq_peaking   control = { "Freq" = 1355.7 "Q" = 2.884 "Gain" = 6.92 } }
          { type = builtin name = s9_r      label = bq_peaking   control = { "Freq" = 1707.2 "Q" = 1.311 "Gain" = -6.54 } }
          { type = builtin name = s10_r     label = bq_peaking   control = { "Freq" = 3100.0 "Q" = 0.5 "Gain" = -10.09 } }
          { type = builtin name = s11_r     label = bq_peaking   control = { "Freq" = 3200.0 "Q" = 1.048 "Gain" = 3.09 } }
          { type = builtin name = s12_r     label = bq_highshelf control = { "Freq" = 6015.2 "Q" = 1.5 "Gain" = -1.34 } }
          { type   = lv2
            name   = limiter
            plugin = "http://lsp-plug.in/plugins/lv2/limiter_stereo"
            control = {
              # Both default to enabled: "alr" regulates level toward the
              # threshold and "boost" normalises the threshold up to full
              # scale. A fixed tuning must switch them off or its tone drifts
              # with programme level.
              "alr"   = 0
              "boost" = 0
              "g_in"  = 0.5456
              "th"    = 0.891
            }
          }
        ]

        links = [
          { output = "s0_l:Out" input = "s1_l:In" }
          { output = "s1_l:Out" input = "s2_l:In" }
          { output = "s2_l:Out" input = "s3_l:In" }
          { output = "s3_l:Out" input = "s4_l:In" }
          { output = "s4_l:Out" input = "s5_l:In" }
          { output = "s5_l:Out" input = "s6_l:In" }
          { output = "s6_l:Out" input = "s7_l:In" }
          { output = "s7_l:Out" input = "s8_l:In" }
          { output = "s8_l:Out" input = "s9_l:In" }
          { output = "s9_l:Out" input = "s10_l:In" }
          { output = "s10_l:Out" input = "s11_l:In" }
          { output = "s11_l:Out" input = "s12_l:In" }
          { output = "s12_l:Out" input = "limiter:in_l" }
          { output = "s0_r:Out" input = "s1_r:In" }
          { output = "s1_r:Out" input = "s2_r:In" }
          { output = "s2_r:Out" input = "s3_r:In" }
          { output = "s3_r:Out" input = "s4_r:In" }
          { output = "s4_r:Out" input = "s5_r:In" }
          { output = "s5_r:Out" input = "s6_r:In" }
          { output = "s6_r:Out" input = "s7_r:In" }
          { output = "s7_r:Out" input = "s8_r:In" }
          { output = "s8_r:Out" input = "s9_r:In" }
          { output = "s9_r:Out" input = "s10_r:In" }
          { output = "s10_r:Out" input = "s11_r:In" }
          { output = "s11_r:Out" input = "s12_r:In" }
          { output = "s12_r:Out" input = "limiter:in_r" }
        ]

        inputs  = [ "s0_l:In" "s0_r:In" ]
        outputs = [ "limiter:out_l" "limiter:out_r" ]
      }

      audio.channels = 2
      audio.position = [ FL FR ]

      capture.props = {
        node.name   = "omarchy_speaker_tuning"
        media.class = Audio/Sink
      }
      playback.props = {
        node.name     = "omarchy_speaker_tuning_output"
        node.passive  = true
        target.object = "@SPEAKER_SINK@"
        # This stream is the filter's output and is a movable sink input like any
        # other, so anything that reroutes "all streams" to a newly selected
        # output would drag the processing along with it -- onto headphones, or
        # into the tuning's own sink, which is a cycle. Pin it.
        node.dont-move = true
        # If the speaker sink is not present yet -- the tuning host can start
        # before the device is discovered -- WirePlumber would otherwise link this
        # output to whatever default exists, quietly tuning the wrong device while
        # the tuning sink still looks healthy. Wait for the named target instead.
        # Both are needed: without linger, WirePlumber destroys the node rather
        # than waiting (see its scripts/linking/find-defined-target.lua).
        node.dont-fallback = true
        node.linger = true
      }
    }
  }
]
