HQPTuner: an improved configuration interface for HQPlayer Embedded

Hello everyone!

I’m very very pleased announce that I’ve improved the entire HQPlayer Embedded configuration interface! I call my project HQPTuner:

I’ve always been frustrated by HQPlayer Embedded’s stock web UI: it’s so full of awesome UX potential that remains entirely untapped. One of the most powerful hifi programs ever made and its configuration interface is ugly, flat, boring, scattered, and frustrating (sorry Jussi!).

HQPTuner is an alternative, attractive, informative, and (for a genuine nerd like me) honestly kind of fun interface. I wanted something that even newbies could use without needing to cross-reference the manual, and I wanted to bring more of HQPlayer’s awesome power within easy reach for power users.

For those interested in the nitty-gritty, it’s a small Python backend with a JavaScript/CSS frontend.

Features I’ve shipped so far:

  • Filter narrowing: this is the flagship right here.

    • Only show filters matching a certain quality, genre, focus, and/or phase

    • Optionally show only apodizing (and/or half apodizing) filters for the 1x dropdowns

    • Note this has already paid dividends and helped me discover new filters that I really like.

  • Full matrix pipeline support with REW-style click-and-drag adjustments on the response plot.

  • Flagship #2: full Headphone Auto EQ profile integration. Over 8,800 headphone EQ profiles. Type in your headphones (+ pads), hit apply, restart the daemon, done. Or, load your own profile from REW.

  • Flagship #3: Automated crossfeed compensation. To my knowledge, this is the first time this feature has shipped outside of a full-on DSP solution (e.g. Jan Meier’s work, CanOpener; in both cases they own the full DSP chain)… that is, the first time it’s being applied to someone else’s DSP chain.

  • Surface all manual knowledge where it belongs: every single feature and filter comes with its manual description printed right below it. This can be turned off entirely (well, converted to hover tips anyway) or left on only for filters/shapers.

  • Idiot proofing: Irrelevant features are hidden or grayed out. PCM output mode? SDM features collapse, or gray out with stated reasons. Running DSD512? Modulators that only work at DSD1024 are unselectable and tell you why so you don’t have to guess why there’s no output.

  • No more ‘applying settings reverts to [default]’. I’ve re-written the entire preset feature to work around the daemon’s desire to revert to default, so the settings you send are the settings you get back every time. My presets sync with the daemon so that they’re available on the stock UI too.

  • Friendly output rates. No more breaking out the calculator to remember what Hz to set for DSD256. Just choose, e.g., “8x” for PCM or “DSD256” for SDM.

  • A live log tail allows you to keep tabs on the process and helps debugging efforts.

  • Crossfeed, Loudness, and Matrix EQ contain live plots that show effects as you adjust them. Matrix EQ plot peaks contain REW-style click-and-drag functionality.

  • Live volume control.

  • Adjustable accent color between amber, phosphor green, and every-web-UI-ever blue. Or, input your own hex code.

  • Ships in Docker.

Features I’m not including:

  • Media playback or library management (that’s what Roon is for)

  • Convolution engine

  • Desktop support (sorry! if you want to see this, let Jussi know)

Furthermore, to enable “friendly output rates”, I’ve forced the Auto-rate family setting on (can’t be toggled with HQPTuner) and taken away the ability to select uncommon output rates. “8x” for PCM is the equivalent of setting 48k x 8 = 384000 Hz; DSD256 is the equivalent of setting 48k x 256 = 12288000 Hz (you can disable the 48k DSD option if your DAC doesn’t support those rates). This should cover the vast majority of use cases, however, if you’re one of those weirdos who listens at random rates or caps your output at 32kHz multiples, HQPTuner may not be for you.

And now, the money shots :smiley:

Caveat Emptor

This is fresh off the presses and still in beta. I’ve rooted out as many bugs and as much weirdness as I can find, but my actual use case only touches so much of the program. For example, I don’t use any ALSA backends, I’m network only. Expect issues. Bug reports, suggestions, and general feedback welcome.

Last but not least, I’ll make a dedicated thread if this gets enough traction and/or makes it out of beta lol

EDIT: major bug! Depending on your system’s startup sequence, the HQPTuner container may try to mount the default /tmp log location before it ever exists. This results in /tmp/hqplayerd.log being created as a folder… then the HQPTuner container fails to start. Big ol’ footgun.

The fix, for now, is:

rmdir /tmp/hqplayerd.log
sudo systemctl restart hqplayerd
sudo docker restart hqptuner

Working on a real fix.

12 Likes

Working great here, much appreciate the effort!

1 Like

Haha, “working great” is quite generous given the glaring error at the top of your screenshot, so thank you very much! :smiley:

I’m working on fixing the bug when the output buffer is simply reporting 0 instead. I’m seeing that now with my speakers output as well.

It’ll be a hot minute before a fix gets pushed to the master repo, since I’ve also added a “structural” crossfeed alternative to the built-in Bauer implementation. Sounds absolutely awesome once your head size is dialed in, super spacious. But its interaction with existing pipelines and/or loading an EQ profile on top of the crossfeed pipelines are complicated enough to be buggy in ways that are difficult to track down with normal usage.

For example, the warning in the screenshot above… well, they WERE routed straight through until I engaged that feature!

Thanks again and stay tuned for improvements :slight_smile:

1 Like

This is a fantastic project! It worked perfectly in my environment as well.

If I could make one request, I think it would be great to consolidate the settings that don’t require a reboot into a single tab. Something like adding the Matrix profile changes to the Embedded Web UI’s “Main” tab would look even better. It would also be awesome to have the Playback Filter added in Ver 6 included here as well (I noticed “Junk Filter” in the code, so perhaps it’s already on your roadmap).

Thanks a lot!

1 Like

Thanks!!

As for gathering the live settings together, I’m on the fence. The layout I have now I think works really well, even if it does split the two live features—matrix profiles and volume control. And I suspect that the majority of people are using a set volume and/or optimal ISO, in which case the matrix profiles are the only real live features and those are on the same page.

Or maybe there are other live settings you’re referring to that I’m forgetting about?

I’ve added the junk filter for release in the next version, it will be called “High-frequency filter” in HQPTuner. I need to try that out for myself! There’s an album that I adore (Marked for Death by Emma Ruth Rundle) but it’s fake 24/96, and yet that fake still somehow sounds better than the Redbook version.

I’ve managed to integrated the Speakers page, so once that ships there will be a switch at the top of the DSP page that allows you to toggle between headphones mode (adds headphone auto EQ lib + crossfeed cards) and speakers mode (adds levels/delays plus a diagram). Of course you don’t have to use either… but imvho you’re missing out if you’re listening to headphones without crossfeed :slight_smile: be sure to try the “Structural” crossfeed that I just shipped, too! once your head size is dialed in, it sounds much more natural.

Unfortunately, switching between the speakers and headphones cards, the app gets very very confused about which settings to restore, which settings have been changed, and how to adjust the pipelines accordingly… it’ll probably be later this weekend before all of that is shippable.

In the meantime, you can set everything else through HQPTuner and then turn the junk filter on via the stock UI. Or just rawdog the dev version and deal with the bugginess :zany_face: they only occur doing things that most people would never do anyway, like switching between Headphones and Speakers with an EQ profile already applied.

1 Like

Hello everyone!

I am very pleased to announce the beta release of my (imvho dramatically) improved configuration interface for HQPlayer: HQPTuner.

Inspiration

I have often said that HQPlayer is one of the best deals in all of high-end digital audio, with two caveats:

  1. You may go broke trying to afford CPUs and GPUs to feed it the power it craves.
  2. The UX is just bad, at least for Embedded (I’ve barely used Desktop so I won’t comment there). Sorry, Jussi!

Everything under the hood of HQPlayer is pure awesome power, but the UI with which you interact with that power will confound, baffle, and frustrate even experienced audiophiles. Worse, it turns people away from the HQP community. I know at least two intelligent audiophiles who just won’t use HQPlayer because they feel it’s just too complicated; they literally don’t think they’re smart enough to operate HQPlayer. They’re wrong, of course, but I also can’t in good conscience tell someone “no, it’s easy” and then send them marching towards the stock UI. They’ll nope out in two minutes.

The point is that configuring HQPlayer is only as difficult as the UI makes it. Right now, that’s genuinely reasonably difficult. The UI is disorganized, opaque, and if you want to know what a feature does, you have to Ctrl+F through a PDF or separate help page with everything listed out rote.

Hell, I decided to give this project its own thread because I highly suspect that there’s at least one person out there who’s avoided HQPlayer Embedded because of the stock UI. If that’s you, I hope you see this, give HQPTuner a try, and change your mind.

Anyway… it’s not just that the UI is bad enough to drive users away, but that it’s so full of potential. Real, actual, good UX potential that I could see perfectly clearly, but that would never be acted on unless I did it myself.

So I just f’ing did it. I’ve re-written the entire† configuration UI surface to be more attractive, informative, and useful.

Features

Let’s start with the flagships:

  1. Filter narrowing via five drop-downs (genre, focus, quality, phase, length). Only show apodizing filters for 1x content by default and/or half-apodizing filters. Rather than sorting through a list of 50+ filters with the PDF open in another window, you’re down to a handful of relevant filters with a few clicks.
  2. Headphone Auto EQ integration: Over 8,800 headphone correction profiles directly in the UI. Type in your headphones, select and apply the EQ curve, restart daemon. Done.
  3. Structural crossfeed: I am a huge fan of crossfeed, but Bauer doesn’t do it for me. So I wrote a structural crossfeed implementation with proper delays/HRTF and everything that loads in a few clicks. Measure your head’s circumference, input the value, tune the rest to taste. And for those of you who do like it Bauer-style, I’ve included crossfeed treble compensation—the first case I’m aware of of crossfeed compensation being applied to someone else’s DSP chain (Meier and CanOpener both own their entire DSP chains).

Other features I’ve included:

  • SURFACE
  • THE
  • FREAKING
  • MANUAL’S
  • KNOWLEDGE: Every feature comes accompanied by its manual explanation verbatim, right there. No PDF, no separate tab for a Help page, no Ctrl+F. These can optionally converted to hover tips for those who prefer a cleaner, less cluttered interface.
  • Idiot proofing: Irrelevant features collapse or gray out with stated reasons. Don’t waste time trying to figure out which Integrator is best if you’re only ever running PCM; with HQPTuner, it’s hidden under a collapsed card so it won’t even cross your mind. Running DSD512? Modulators that only work at 1024x are unselectable and tell you why so you don’t end up wondering why AHM7EC8B doesn’t output anything.
  • Friendly output rates: no more breaking out the calculator or memorizing raw sample rate Hz. For PCM, select 1x, 2x, 4x, 8x, 16x, or 32x; for SDM, select DSD64 - DSD2048.
  • Hardware acceleration settings: Those settings you normally have to write to hqplayerd.xml to enforce? HQPTuner has them in the UI, with full descriptions right there, so you can easily play around.
  • Better organized: HQPTuner has five tabs: Output, Volume, Resampling, DSP, and System. I’ve scrapped a lot of the original organizational system for my own so things are where you might expect them to be.
  • The settings you send to the daemon with HQPTuner are the settings you get back every time, even if it means two consecutive restarts*.* I’ve re-written the entire profile saving system around the daemon’s desire to constantly revert to [default] (but my profiles still sync to the stock UI).
  • Adjustable accent color between amber, phosphor green, and every-web-UI-ever blue. Or roll your own with a hex code.
  • Live log tail
  • Dockerized

…and more.

†Features that are not included/planned:

  • Media and library management (use Roo… oh, right, forgot where I was for a second :sweat_smile: )
  • Convolution engine (use Matrix DSP)

To enable “friendly” output rates, I’ve also forced “auto rate family” on, PCM sample/SDM bit rates to “auto”, and taken away the ability to set 32kHz-multiple rate caps. If you’re one of those weirdos… sorry. And if your DAC doesn’t support 48kHz DSD multiples, that feature toggle is maintained.

Now for the money shots :smiley:

Fig 1. Filter narrowing in effect. Showing 1x filters matching “genre: rock”, “quality: 5/5”, and “long” or “extra long” which are also apodizing.

Fig 2. Output tab. Changes (e.g. high-frequency filter) are highlighted in the selected accent color. Irrelevant settings (ALSA backend, DAC bits) are collapsed and grayed respectively.

Fig 3. DSP tab showing structural crossfeed + headphone EQ + REW-style interactive response plot.

Caveat Emptor

This is a beta release. Expect and report bugs, weirdness, or other quirks through Github, DM, or in this thread. I don’t want bug reports for HQPTuner going into the main Embedded thread.

Back up your HQPlayer presets and configs before using HQPTuner, or use new presets that don’t overwrite the originals. I’d feel really bad if this f’ed anyone’s settings up, but at least now you’ve been warned.

I only use so many of HQPlayer’s features, e.g., I’ve never used an ALSA backend, so I have several blind spots when testing. It’s going to take more than a few other people’s use cases to suss out the weirdness and quirks.

Last but not least, unfortunately for now, HQPTuner is exclusive to HQPlayer Embedded and not available for the Desktop version. This is due to… well, the nitty gritty doesn’t matter, but you can always email Jussi and tell him you’d like to have HQPTuner capacity with the Desktop app!


Ok, my spiel is done. Enjoy and please let me know what you think! I wholeheartedly welcome and all feedback, suggestions, criticisms, etc.

4 Likes

For me personally, I change the oversampling filter settings just as frequently as the matrix profiles. I’d highly appreciate it if you could consider adding this to the live settings. Also, it would be amazing if there were a bookmark feature for frequently used filters.

​Of course, I know I’m not the only one using hqptuner, so please do take other users’ feedback into account as well.

​Thanks for the amazingly fast updates—keep up the great work!

1 Like

The new version is going to fly hopefully by the end of the night.

A heads up: for the newer versions, the log is retrieved from HTTP rather than by parsing directly due to a bug caused by the default /tmp location. Remove the log line from compose.yaml going forward.

Many, many fixes and additions… but the big ones are:

  • Junk filter added (“High-frequency filter”)
  • Filters, modulators, dither, etc. now properly apply live rather than restarting the daemon
  • Addition of the Speakers feature (delays/levels per channel)

I’d also really be interested in hearing what people think about another feature I’ve thought up: EQ Assistant

Basically, you’d enter an OpenAI token into the compose file which would reveal an EQ Assistant card at the bottom of the DSP tab. Never appears otherwise. This card would give you a chatbot well-versed in translating qualitative descriptions of sound into actionable EQ changes.

I’ve done this myself, using Claude Opus to drive HQPTuner via CLI. The short version is that the Auteur Classics profile available in the Headphone Auto EQ library was super clear, but all treble. It took Claude and I about 15 rounds to sort everything out, but the result is a remarkably good sound.

Even if you’re an AI hater or skeptic, hear me out. This is exactly the kind of tasks LLMs excel at: constrained, focused, and data-rich. Any LLM worth two assholes should contain a massive corpus of sound engineering principles, but the larger the model more abstract and less precise you can be with your descriptions.

I’m an audiophile, not a sound engineer, so I describe the things I hear qualitatively. I can make educated guesses, but when it comes to complaints like “guitars are present and balanced but big fuzzy guitars don’t bloom and sound oversized like they should”… I have no idea where “fuzzy guitar bloom” lives. But Claude either knew what I was talking about every time, or asked clarifying questions/helped me figure out the change needed.

An excerpt:

“Guitar fundamentals were present and level - hence ‘there and balanced’ - but the body beneath them was missing, so the sound never bloomed or read oversized. A notch, not a shortfall of bass. Notch at 125-160 Hz (125 Hz +0.02, 160 Hz -0.08) sitting between the sub-bass (63 Hz +2.51) and the earlier 190 Hz fill. OOMPH band 80-160 averaged only +0.61. Solution: fill 125-160 Hz body notch; best oomph-per-mud ratio.”

Honestly? I’d have never guessed that what was missing was that low. I’d have kept poking the higher low mids into mud and then attempting to claw them back until I had a profile I couldn’t stand.

This would be a major, major feature that would be a massive pain to develop, but if people think it might be of some use, I’d be down to take a crack at it.

In the meantime, if you’re curious, just point Claude at HQPTuner, give it a copy of hqplayerd-readme.txt, have it research sound engineering principles and terminology for a few turns, then describe your complaint as clearly and thoroughly as you can manage. You might be surprised. (And then also send me the transcript for training materials :D)

2 Likes

Having an issue saving profiles. Using Edge, make my changes, apply, save as new, give it a name, save, hard refresh, and never shows up. Is my workflow incorrect?

Thanks

Good catch! Working on a fix now, should ship soon.

EDIT: try now! It was a focus issue, something really stupid that I should have caught before.

Solved, I think. Permissions issue on my end.

Moved to same VM, same issue, can’t seem to save any presets and restarted hqplayerd manually. May be it’s my workflow?

Same issue, let me move HQPTuner to same VM as hqplayerd, will follow-up.

Before you go through debugging this issue, here is my setup, I run hqplayerd on an ubuntu VM via unRAID. HQPTuner runs in docker on unRAID, two different IPs, same subnet. I read this from your github:

HQPTuner applies “restart”-category changes by restarting the hqplayerd daemon — but your hqplayerd is remote (on the Ubuntu VM at .76), and HQPTuner running in a container on Unraid has no way to restart a systemd service on another machine. Its own docs say “same-host installation recommended” for exactly this reason. So those 4 restart changes get stuck “staged,” they can’t commit, and that jams up Apply & Save. Combine that with the 6.0.4 /backup bug

I was going to move HQPTuner to the same VM?

Thanks
```

I don’t think moving it to the same host is going to fix it. HQPTuner never hits systemd, it lacks permissions to do that. Every daemon restart goes through the official API.

The reference to “same host installation recommended” is stale and needs excised from the docs; that was for when the log fetching was based on having the actual file mounted inside the container. Now that it fetches the logs over HTTP, there’s no need to have it on the same host.

Can you DM me the HQPTuner logs and let me know of the stock web UI shows a named profile active? Or, if you’ve solved it, let me know what the fix was!

Yes, the permissions and moving to same hosts did not address the issue. I was finally able to save a new preset, but when I go back in and make changes under Volume Tab and click apply and save changes, stale, see picture. Also, I manually restarted hqplayerd, same issue.

…and this:
✗ Config not applied: daemon returned an unusable /backup (known 6.0.4 bug after a profile load/save); refusing to build a restore from a stale cached archive — restart hqplayerd, then retry

From Claude FWIW:
That error is the real culprit behind everything tonight — and now it’s naming itself. This is the HQPlayer 6.0.4 /backup bug: after you load or save a profile, the daemon’s /backup endpoint hands back a stale/unusable archive, and HQPTuner (correctly) refuses to apply config without a good restore point. Since you’ve been saving and loading presets, you keep re-triggering it. It’s not your setup, not permissions, not the container — it’s a daemon bug.

Let me check whether there’s a newer HQPlayer Embedded that fixes it, since updating the daemon would end this permanently.

In the meantime, switch your Docker over to :beta and see if the bug is fixed there. If not, it should at least fail with an informative reason (and print something useful to the logs as well).

I should have worked around the /backup bug, but it may be manifesting in different ways that I didn’t anticipate. Will keep digging.

^ Just a brief explanation: HQPTuner has its own preset saving/loading system that works around the daemon’s entirely. It’s not just the /backup bug but that the daemon constantly wants to revert to [default]. Actually, I work with that lol. Each preset is a file that HQPTuner keeps independently (/state/presets) (and also syncs to HQPlayer’s own preset store) with active.json indicating which is currently live. That becomes the source of truth. The daemon shouldn’t see a profile being loaded, only changes to [default].

No dice, made some changes and tried to save as a new preset.

4 staged✗ Config not applied: absent from this snapshot0 live · 4 restartSave current settings as a new preset:SaveCancelDiscardApplyApply & SaveSave as New…

WIll do and follow-up.

Thanks

I think I’ve cracked it.

HQPlayer only writes the parts of its configuration file it has had a reason to write, it never fills the rest back in. If you’d never set up loudness, or never switched matrix processing on, your file simply had no loudness or matrix section in it. HQPTuner could edit what was there but couldn’t add what wasn’t.

Try :beta again.

Same problem, recreated container and made some changes from volume tab, hit apply and save. Using the tag :beta, here is my compose for reference:

guyp@ubuntu-hqp:~$ cat compose.yaml
services:
hqptuner:
image: Package hqptuner · GitHub
container_name: hqptuner
restart: unless-stopped
ports:

  • “8090:8090” # UI at http://192.168.60.76:8090
    extra_hosts:
  • “host.docker.internal:host-gateway” # reach hqplayerd on this same VM
    env_file:
  • /home/guyp/hqptuner/.env # username / password live here
    environment:
    HQPTUNER_HQP_HOST: host.docker.internal
    HQPTUNER_HQP_CONTROL_PORT: “4321”
    HQPTUNER_HQP_HTTP_PORT: “8088”
    HQPTUNER_LISTEN_HOST: 0.0.0.0
    HQPTUNER_LISTEN_PORT: “8090”

HQPTUNER_HQP_HOME: /var/lib/hqplayer/home

volumes:

  • /home/guyp/hqptuner/state:/state
  • /tmp/hqplayerd.log:/tmp/hqplayerd.log:ro # live log tail (same-host)

- /var/lib/hqplayer/home:/var/lib/hqplayer/home # for convolution uploads

labels:
net.unraid.docker.icon: “/home/guyp/hqptuner/hqptuner-icon.png”

Damn… I can’t reproduce this for the lfie of me. DM me the profile you’re trying to save to when you get a chance. There’s something in there that’s not in my fresh profiles that’s causing the bug.

PS you should remove the /tmp/hqplayerd.log file from the volume mounts. the container now gets its logs directly over HTTP. /tmp/hqplayerd.log can cause HQPTuner to crash on startup if Docker comes up before hqplayerd.

PPS be sure it’s a fresh pull, that error text appears to only match an older version without the above fix

I removed all presets, restarted hqpleyrd, updated hqptuner stack, removed volume mapping for logs, and was able to create a new preset w/ volume and loudness settings with one exception. When I set the volume to -35 and apply and save, reverts back to -3, does not stick.

Also If I select default from top right I see this:

Also, using :beta

Great work on this, looking forward to this maturing. Let me know if you need anything else.

Thanks

1 Like