Using any audio source with HQPlayer - Spotify, Amazon, Apple Music, YouTube Music, Deezer, Soundcloud [2023]

No, the changes only apply to this particular functionality.

1 Like

… and what about Embedded 4, will it work with new NAA versions?

Yes, it will work with any NAA 4.x at least. It just cannot use all the features of newer ones.

But still you benefit from newer NAA OS / HQPlayer OS (when used as NAA) in form of updated DAC driver support.

Can you give an overview of how this UAC2 works. I can’t wrap my head around it yet. I have embedded 5.3.1 on Ubuntu Server installed with your latest kernel.

So does that mean auto rate switching will now work with something like minidsp mchstreamer connected to NAA?

Should work with any USB (UAC2) audio source.

It makes HQPlayer (directly or through NAA) look like a USB connected DAC. This requires that the device running the HQPlayer Embedded or NAA instance has needed hardware capabilities to become a USB device (instead of host; normal desktop/laptop computers lack this).

2 Likes

Well done to all involved. This has been pretty exciting watching this evolve.

Maybe not great for Roon?

1 Like

Now the new Desktop release is also out.

For example if one boots up latest HQPlayer OS on UP Gateway with the USB OTG set to Device mode, in HQPlayer Desktop select “hqplayer:USB Audio (DWC3)” as input device. Connect your source device with USB → microB cable to the UP Gateway USB 3 OTG port.

If you use RPi4 with HQPlayer OS, before bootin up with new image, edit the config.txt first and on the last lines swap the ‘#’ prefix so that the dwc2 host mode line has ‘#’ (commented out) and the dwc2 peripheral mode line has ‘#’ removed. In HQPlayer instead select “hqplayer:USB Audio (RPi4)” as input device. Connect your source device with USB → type-C cable to the RPi4 Type-C port. Since the RPi4 can draw quite a bit of power, you may have best results if you can use type-C → type-C cable for connecting. You will need to use at least USB3 → type-C cable on USB3 port to supply enough current.

In HQPlayer Desktop, for source URI line (above playback queue display) enter “audio:default/0/2” and hit enter. Now it should appear on the playback queue. Then just start playback. Now the NAA should appear as a USB DAC on the source device. When you start playing something, HQPlayer time should start proceeding and you should hear what ever you play on the source device. I’ve tested mostly with my old iPad Pro through the Apple’s Lightning to USB3 adapter dongle which also allows simultaneous charging of iPad.

3 Likes

I don’t think it has impact on this, since you can use Roon as source just like before. But the feature is useful if you’d like to use something like Apple Music, Amazon Music or Spotify as source. So it widens the range of potential sources, especially streaming ones.

1 Like

Thanks for this.

Will get to testing - after I measure SMSL DO300EX (4499EX) which just arrived today :smile:

1 Like

So, I could connect one of my Android DAPs playing Tidal or local music through an OTG cable to the NAA Up Gateway and tunnel through my Mac running HQPlayer hooked to a DAC? It’s almost like a Roon source, right? Except you can do Spotify Apple and Amazon?

I can only speak for myself, but this pathway with Apple Music seems a better option than Roon and Tidal/Qobuz, which is my current source.

With my current hardware, and infrastructure, it’s what I’ve been waiting for, for the past year tbh.

I’ve got the previous version of HQPlayer desktop, but maybe the new version for my new Holo Red, arriving soon? Would the embedded be better suited to the Holo, as it’s a NAA?

Hi Jussi,

Thank you so much for your work on UAC2 Gadget support. This end of the week, I finally had time to play with it; overall I’m excited with, but i still have to figure out a few issues:

  • there is a small playback hickup when input rate jumps between samplerate families - 1 second gap at the start of the track (1s sound → 1s no sound → sound)
    note: in my Proof-of-Concept setup of CamillaDSP + gaudio_ctl (executing a python script to reconfigure CamillaDSP’s samplerates on the fly) around 2 weeks ago, i don’t remember a similar issue; but i will retest to be sure
  • ocasionally, when samplerate changes, audio is garbled and i can only fix it if by playing a 44100 track; not sure yet if this is a Capture Side issue or it has somthing to do with my Topping D50s DAC; but i’m more inclined to blame USB Gadget for it; i also had this issue while testing CamillaDSP
  • when using networkaudiod/NAA as UAC2 input, auto rate switcing doesn’t work for me (networkaudiod doesn’t report rate changes in its logs, and hqplayerd is not notified about it either); i tested using networkaudiod running on same RPi as hqplayerd - hqplayerd.xml config entry below; naa-start-uac-gadget.sh script is not executed, so i had to run it manually

<input address="HQPlayer" ipv6="1" name="USB Audio (RPi4)" device="hw:CARD=UAC2Gadget,DEV=0" samplerate="0" channels="2" format="pcm" period_time="100" type="network"/>

My test setup was:

  • (input) iPhone 8 (running VOX.app music player) connected to RPi 4, running your HQPlayer Emebedded 5.3.1 image
  • (output) Topping D50s connected to RPi4, running RoPieeee with NAA 4.5.0
  • mode: pcm; filters: poly-sinc-gauss-long (1x), poly-sinc-gauses-hires-lp; dither: LNS15; max samplerate 768000, dac-bits 32 but (i should probably limit it to 24 with my DAC); any base rate enabled

Improvement suggestion for naa-start-uac-gadget.sh & hqplayer-start-uac-gadget.sh scripts:

  • setting p_chmask to 0, disables Playback device; i don’t think we care about playback in this scenario anyway
  • because i don’t think we can have more than one UDC, we could use “ls /sys/class/udc > …/UDC” instead of passing it as a command line argument

Yes, this is normal, in particular with first rate change, as the DSP pipeline with all the algorithms will need to be reinitialized. And if you you have auto rate / adaptive rate then the DAC needs to be restarted with a different rate as well.

Did you have all the same DSP there, such as upsampling? And same I/O path?

I have not encountered such on my testing. But I got few stops when using iPad and Apple Music as source when iOS was changing output rate quickly back and forth multiple times like 48k → 44.1k → 48k → 44.1k and one of the changes happened between rate change notification and restarting the gadget input at new rate.

This is the issue… You are pointing to the gadget device and not to the virtual input device…

This is what I have:

<input address="hqplayer" channel_offset="0" device="USB Audio (RPi4)"
 format="auto" ipv6="1" pack_sdm="1" period_time="0" samplerate="0"
 short_buffer="0" type="network6"/>

Thus the networkaudiod doesn’t have the necessary configuration for the input. Add the “name” item to make it named, above works also with HQPlayer Desktop, but there it is selectable straight.

Yes, makes sense…

Not 100% sure about the hardware possibilities, I wanted to play safe with the few tested cases.
But that may be good idea in future when the test coverage over different hardware is a bit wider.

I can imagine some newer Atom hardware and maybe ARM SoC’s having more than one. Of course I could modify the NAA / hqplayerd config to cover that case as well by default.

This is the issue I had with previous couple years UAC2 input.

I made an Apple Music playlist with these exact family rate changes just to test this

Will test soon and report back

thank you so much for sharing the hqlayerd.xml config entry - i missed completely that i should use a virtual input device (if capture is done on NAA); now every thing works fine (USB Gadget configured automatically, auto rate switching …)

Not as complex as HQPlayer - in my testing, CamillaDSP was configured to (Synchronous) resample to 705600 / 768000 with a -3 dB gain to avoid clipping. Capture & playback on same RPi4; other than the fact that I had my DAC connected to the RPi instead of the (RoPieee as) NAA, the HW setup was identical to what I used to test UAC2 input with HQPlayer Emebeded 5.3.1 Image.

Everything was glued together (arround CamillaDSP & pyCamillaDSP v2.0) with gaudio_ctl & a modified set_samplerate.py script by stemag on ASR forum (updated for pyCamillaDSP v2.0 and to change both capture & playback samplerates based on capture samplerate); pyCamillaDSP & gaudio_ctl compiled / installed from source

Click to see camilladsp / gaudio_ctl commands used
/usr/local/bin/camilladsp -p 1234 -w
/usr/local/bin/gaudi_ctl -y "/usr/local/bin/set_samplerate.py {R}"
Click to see CamillaDSP config file
title: "CamillaDSP Stereo with 16x Resample"
description: "UAC2 Gadget Capture with resampling and -3dB gain"

devices:
  samplerate: 705600
  chunksize: 4096
  queuelimit: 4
  silence_threshold: -60
  silence_timeout: 3
  target_level: 500
  adjust_period: 10
  enable_rate_adjust: false
  resampler:
    type: Synchronous
  capture_samplerate: 44100
  stop_on_rate_change: false
  rate_measure_interval: 1
  volume_ramp_time: 400.0
  capture:
    type: Alsa
    channels: 2
    device: hw:UAC2Gadget
    format: S32LE
  playback:
    type: Alsa
    channels: 2
    device: hw:D50s
    format: S32LE

mixers:
  stereo:
    description: "Stereo Mixer (-3dB gain)"
    channels:
      in: 2
      out: 2
    mapping:
      - dest: 0
        mute : false
        sources:
          - channel: 0
            gain: -3
            inverted: false
            scale: dB
      - dest: 1
        mute : false
        sources:
          - channel: 1
            gain: -3
            inverted: false
            scale: dB

pipeline:
  - type: Mixer
    name: stereo
Click to see modified set_samplerate.py script
#!/usr/bin/python3

# This script must be launched at each sample rate change
# (a gaudio_ctl daemon will do the trick).
# To this end, it updates the samplerate parameter of the current configuration
# according to the sample rate of the signal being captured. Then it
# sends the updated parameter to camilladsp via a websocket.
# If camilladsp has not a current valid configuration, a standard
# configuration is loaded from file.
# Note 1: camilladsp must be launched in wait mode.
# Note 2: the parameter samplerate in the standard configuration is not relevant,
#             as it will be changed right after the file is loaded anyway.
#
# This script derives from the work of @audiofun on ASR forum.

import camilladsp
import sys

cdsp = camilladsp.CamillaClient("127.0.0.1", 1234)

msg = ""

try:
    cdsp.connect()
    capturerate = int(sys.argv[1])

    config = cdsp.config.active()

    if config is None:
        config = cdsp.config.read_and_parse_file("/usr/local/etc/camilladsp-active.yml")

    if 705600 % capturerate == 0:
        rate = 705600
    else:
        rate = 768000
    
    config['devices']['samplerate'] = rate
    config['devices']['capture_samplerate'] = capturerate
    
    cdsp.config.set_active(config)
    msg = "Capture Sample Rate {} & Playback Sample Rate {} successfully set".format(capturerate, rate)

except ConnectionRefusedError as e:
    msg = "Can't connect to CamillaDSP, is it running? Error:" + str(e)
    retry = True

except camilladsp.CamillaError as e:
    msg = "CamillaDSP replied with error:" + str(e)
    retry = True

except IOError as e:
    msg = "Websocket is not connected:" + str(e)
    retry = True

finally:
    print(msg)
    cdsp.disconnect()

2 Likes

for a moment i thought i “discovered” why during playback i hear a short glitch (music is audible for ~1 sec, abruptly/discompfortably stops for ~1 sec, and resumes perfectly) at the begining of a track if input samplerate jumps between rate families.

note: with short_buffer enabled (in engine section), the glitch is less discomfortable / i don’t even notice it sometimes

+ 2023/12/26 10:35:30 ALSA input engine running...
  2023/12/26 10:35:30 enter streaming mode
  2023/12/26 10:39:18 ALSA input rate change detected: 192000 -> 176400
  2023/12/26 10:39:18 ALSA input rate change detected: 192000 -> 176400
  2023/12/26 10:39:18 leave streaming mode
- 2023/12/26 10:39:18 stop
- 2023/12/26 10:39:18 ALSA input engine stopping...
- 2023/12/26 10:39:19 ALSA input engine stop request...
- 2023/12/26 10:39:19 ALSA input engine stopped
+ 2023/12/26 10:39:22 start 176400/32/2 [pcm]
  2023/12/26 10:39:22 ALSA input set channels: 2 (2)
# 2023/12/26 10:39:22 start: clAudioEngine::SetSampleRate(): requested rate not available
? 2023/12/26 10:39:22 starting audio failed, attempting to reinitialize...
  2023/12/26 10:39:22 ALSA input attempting to uninitialize...
- 2023/12/26 10:39:22 ALSA input backend uninitialized
  2023/12/26 10:39:22 ALSA input attempting to initialize...
[ . . . ]
+ 2023/12/26 10:39:22 ALSA input backend initialized
  2023/12/26 10:39:22 ALSA input set sampling rate: 176400 (176400)
  2023/12/26 10:39:22 ALSA input set channels: 2 (2)
  2023/12/26 10:39:22 ALSA input set sampling rate: 176400 (176400)
+ 2023/12/26 10:39:22 ALSA input engine starting...


but networkaudiod generates similar logs for all samplerate transitions, so i discovered nothing;
the only things i find odd are:

  • that “ALSA input rate change detected” is reported twice
  • and that when input engine is started with the new samplerate, clAudioEngine::SetSampleRate fails and we need to re-initialize the backend; maybe we should re-initialize input backend every time a samplerate change is detected (at least for UAC2Gadget)

Yeah, RPi4 is very slow for running HQPlayer. And especially any arbitrary precision calculations become really slow. But it is usable for some really basic playback scenarios, like doing up to 192k PCM output. But I wouldn’t really use RPi4 for doing any serious DSP.

Probably RPi5 is better for the DSP part, but I haven’t got time to do any testing on it yet.

This is normal with for example 6.1 and newer kernels. 5.15 and older kernels was better. ALSA changed things so that changing sample rate is now much bigger operation than before. The code still supports the earlier way as well that was quicker.

So ALSA kind of followed the path Microsoft took in WASAPI in Windows 8. And recently Apple has taken similar path with CoreAudio as well, but only on Intel CPUs (probably more of bug there, maybe they just don’t bother to test on Intel hardware carefully).

1 Like

This line is in your hqplayerd.xml file right?

And input address=“hqplayer” refers to the NAA name?

So I would change “hqplayer” to whatever the NAA name is? Otherwise I have two different “hqplayer” machines clashing?

Currently testing with RPi4 running latest HQP OS image but hqplayerd is disabled on HQP OS on the Pi4.