Peppymeter (peppyalsa) VU Meters with Roon?

I finally had a chance to revisit this and want to say thanks to @ipeverywhere (and everyone else) for continuing to tinker around with this. With snd-aloop and alsaloop everything is working in my Pi streamer when I group the loopback device with the standard endpoint in Roon. Very cool.

I’ll post my full walkthrough later where I’ve distilled all of the above (plus a few other tweaks to PeppyMeter configs) to get everything working as a complete streamer + VU meters, but first I’m going to test building a basic Volumio streamer running RoonBridge and nothing but the VU meters which may be easier in the long run.

One problem I can’t figure out with the manual approach, though: My Pi streamers are all configured to run at 1024x768 but there are no Peppy Meter skins that fit that resolution, and I can’t figure out how to tell python3 to run at full screen. Anyone have any suggestions on running Peppy Meter at full screen with standard Pi resolutions?

1 Like

Two updates:

  • I gave Volumio a try and I have to say I’m liking their distro more and more as a Roon endpoint. There’s a newer tool called ‘volroon’ which is available as a plugin w/in Volumio that uses a web extension to display Now Playing and basic playback functions. No Now Playing support was a huge blocker for me and Volumio, glad to see it. BUT, no luck getting PeppyMeter to work with a Roon stream. I tried hacking around with asound.conf but couldn’t get it to work, which is a shame b/c it’s slick as a Volumio screensaver. I’m going to request Roon support b/c it’s a much more elegant solution than the manual implementation below.

  • I was able to fix the full screen issue and cobble together a super quick runbook for getting this up and running on a 3.5 TFT. It’s not 100% yet – autostart with peppymeter and alsaloop isn’t working, and there are still a few bumps that aren’t fully solid (see below), but it’s a great first PoC.

Quick walkthrough on getting this running on a standard Pi w/ screen:

  • Get the endpoint up and running with RoonBridge and your screen however you’d like. Once that’s working…
    • You’ll need to force your screen resolution to match one of the pre-scaled resolutions like 800x480 to use “large” meters
  • Install peppyalsa:
    • git clone GitHub - project-owner/peppyalsa
    • cd peppyalsa/
    • sudo apt-get install build-essential autoconf automake libtool libasound2-dev libfftw3-dev
    • aclocal && libtoolize
    • autoconf && automake --add-missing
    • ./configure && make
    • sudo make install
  • Make fifo
    • mkfifo ~/myfifo
  • Load snd-module
    • sudo modprobe snd-aloop (to load it now)
    • sudo echo ‘snd-aloop’ >> /etc/modules (to persist it after a reboot)
  • Run alsaloop
    • alsaloop -d -C “hw:Loopback,0,0” -P “peppyalsa” -l 1500 -b &
  • Grab PeppyMeter (you’ll need python3 if you don’t have it installed)
    • git clone GitHub - project-owner/PeppyMeter: PeppyMeter Repository
    • cd PeppyMeter
    • edit config.txt to choose “large” (assuming you set that resolution from above) and to choose your meters (or just leave it random for now to get started)
    • export DISPLAY=:0 && cd /home/pi/PeppyMeter/ && python3 /home/pi/PeppyMeter/ > /dev/null 2>&1 & (remove the background and redirects to /dev/null to test and see full output if you have issues)
  • In Roon, enable the Loopback PCM device now available for your Pi RoonBridge endpoint
  • Group the standard Alsa RoonBridge endpoint with the new Loopback PCM and you should be in business.

I’ve been running with this setup all day, rotating between a few different meters, and generally all is good, but I have had two issues with the above:

  • I had to set the latency (-l in alsaloop) really high to avoid buffer underrun issues. No idea why; everything in my env is connected over ethernet so it’s not a network issue. It does make the Peppy needles a bit less responsive.
  • After listening in this setup for a while, maybe ~30 minutes, the audio will become distorted, starting gradually and sounding mechanically until it becomes really robot-y and distorted. Ungrouping and regrouping in Roon fixes it. It may be something that I can correct in the loopback Roon settings, haven’t played around yet. Or maybe increasing the buffer?
1 Like

@rcrawley umfortunately I can’t be of any help on the resolution thing, but as a photographer I’m pretty handy in photoshop and might be able to adjust a couple of the backgrounds to fit the needed resolution for you.

If you need any help testing your instructions please feel free to DM me.

Thanks @312Elements! I think we were posting at the same time. :slight_smile: Forcing my Pi screen to a resolution that matched the “large” resolution for Peppy has worked for now, but thanks for the offer! My next step is to work out why launching Peppy via autostart isn’t working, but once that’s done and I have bootable VU Meters I may take you up on on that offer.

Also found this archive of different sized meters:

…and a few different options and resolutions embedded in this long thread:

1 Like

Fixed this issue (at least so far after a normal work day of streaming) by setting the resync delay on the alsaloop device in Roon to 500ms. Not really sure what this does but so far, so good.

I was also able to solve the load on boot issue by loading alsaloop in crontab:

$ crontab -e
@reboot /usr/bin/alsaloop -C hw:Loopback,0,0 -P peppyalsa -l 2000 -b > /tmp/alsaloop.log 2>&1 &

I had to jack the latency all the way up to 2000 to keep it stable, and am redirecting stdout and stderr to a temp log to debug future latency issues.

…an wrote a small script to load PeppyMeter:


export DISPLAY=:0 
cd /home/pi/PeppyMeter
python3 ./ > /tmp/peppymeter.log 2>&1 &

…that I call from ~/.config/lxsession/LXDE-pi/autostart:


And that did it. I now have a 3.5 TFT streamer running RoonBridge, out via USB to a Schiit stack with PeppyMeter working on boot. Now onto building a more permanent one with a wide screen LCD for the main streaming room. Thanks again for all the notes in this thread!


Nice job!

Would you mind checking CPU load just for me to compare with my dynamic-range-metering-bridge?
Thanks a lot for considering!

Load is high, floating around 35 for user processes while streaming. Biggest offenders are mutter and Xorg. Makes me wonder if you can run pygame without X (something like fbi for displaying pictures w/o X). A quick search looks like it should be possible…

@rcrawley I’m out of town for a long weekend but will give this a go upon returning. If you happen to get to eventually start from scratch on a new unit at some point would you be willing to do a starting from scratch tutorial of sorts? If I happen to get to it first, I’ll document the process as well and credit you. I just don’t think there’s a clearly document d start to finish tutorial for this procedure and I think it’s very much needed.

@312Elements Thanks for looking at it. And I’d be happy to build a more complete walkthrough, see below. I run a few different Pi endpoints around the house, most of them are running Ropieee with the official 7" Pi screen and HifiBerry HATs, so nothing really different or special there. For my tinkering streamers, I alternate between these types:

  • RoonBridge running a simple kiosk display showing Roon’s Display (connecting to port 9330 on Roon), with a flip clock screensaver
  • RoonBridge running Roon Extensions and the Web Controller, a nice aftermarket interface that allows me to start/stop the music from the streamer (something I can’t do with Roon display), with a flip clock screensaver
  • Volumio, just for testing every few months to see how it’s going with Roon support. I really like Volumio and would probably swap out to Volumio on all of my Pi Roon endpoints so the fam could walk up to any and change the music/source to anything they’d like. I could do this today with volroon but I have a few small issues here and there when testing it so I don’t think it’s 100% stable yet. And of course getting Peppy support for Roon as I mentioned above. :slight_smile:

Here’s my straightforward walkthrough of the 2nd option, RoonBridge using Web Controller and a 3.5 TFT screen with USB out to a stand-alone DAC (like the Schiit Modi). It’s the most involved so if you want to use Roon’s Display instead just skip all of the steps I’ve listed as [OPT] below and change the Chrome Kiosk URL to the one that’s published in Roon’s Display settings. Hope this helps, feel free to ping me with any questions or issues, and always open to doing things more simply or different for ease and stability.

* install and update buster (raspberryPiOS 32b)
* `sudo raspi-config` to expand local storage, set timezone, and set audio to USB
* install/config screen:
  * git clone (docs, (MHS3528)
  * sudo ./MHS35-show 180
* Calibrate screen (and install unclutter while you're there)
  * apt install xinput-calibrator unclutter
  * export DISPLAY=:0 && xinput_calibrator
* install ALSA (if not installed) 
* install Roon bridge - wget
  * chmod 755 ./ && ./
* [OPT] install docker - wget -O
* [OPT] install Roon extensions - wget
* [OPT] In Roon, install extension snapshots (extensions -> system -> snapshots)
* [OPT] In Roon, install web controller (snapshots -> web/controll -> web control), then start it
* Test chromium-browser: 
  * export DISPLAY=:0 && chromium-browser --noerrdialogs --start-fullscreen --start-maximized --disable-infobars --homepage http://localhost:8080
    * Or swap out --homepage URL for Roons Display address
* add to ~/.config/lxsession/LXDE-pi/autostart to run at boot
  @unclutter -idle 0.5 -root &
  @lxpanel --profile LXDE-pi
  @pcmanfm --desktop --profile LXDE-pi
  @xset -dpms
  @chromium-browser --kiosk --no-first-run --fast --fast-start --noerrdialogs --start-fullscreen --start-maximized --disable-infobars --homepage http://localhost:8080&
* install x11-apps: sudo apt install x11-apps
  * apt install xscreensaver xscreensaver-data-extra xscreensaver-gl-extra
* install flip clock: 
  * sudo apt-get install build-essential libsdl1.2-dev libsdl-ttf2.0-dev libsdl-gfx1.2-dev libx11-dev
  * git clone
  * cd gluqlo && make && sudo make install && sudo cp gluqlo /usr/local/bin
* Add screensaver to ~/.config/systemd/user/xscreensaver.service
  ExecStart=/usr/bin/xscreensaver -nosplash
* systemctl —user enable screensaver
* Add gluqlo to local xscreensaver by adding this block at the end of the `programs:` section, removing -w and -h if you don't need to run a custom size)
  * -				gluqlo -root -ampm -w 800 -h 480	    \n\
* Run `xscreensaver` to disable everything except gluqlo
  * You'll need to ssh into the streamer with port forwarding enabled and
    using a local X server like XQuartz, or do it manually via local config
* [OPT] install shairport - apt install shairport-sync
  * edit /etc/shairport[?].conf to select correct audio device and set name
    * alsa = {output_device = "hw:1"}

Once everything is working with Roon to stream to the endpoint and display one of the options via the screen, you can pick up my two posts above to swap out chromium-browser with PeppyMeter if you’d like. My next test is to replace gluqlo with PeppyMeter and run it as the screensaver with the Web Controller, assuming you can run pygame via xscreensaver, TBD.

I’ve been running with this setup for a few weeks and generally everything is working really well. I have bumped into two minor issues, though, and would love to see if anyone has seen this?

  1. After running for a full day-ish (maybe after two days) of grouping the alsasound endpoint with the Cambridge, Roon starts to interpret pause as “Next Track”. This happens in both the Roon client as well as using the pause button directly on the Cambrdige. When I press Pause on either it just goes to the next track, and the following is displayed in logs (vumeters-lo-1 is the alsasound loopback):
04/08 17:19:50 Trace: [vumeters-lo-1] [Lossless, 16/44 MQA TIDAL FLAC => 24/44] [1% buf] [PLAYING @ 4:44/4:46] This Twilight Garden - The Cure
04/08 17:19:50 Debug: [raat/tcpaudiosource] connecting to
04/08 17:19:50 Debug: [raat/tcpaudiosource] connected
04/08 17:19:50 Warn: [raat/tcpaudiosource] send failed: Broken pipe
04/08 17:19:50 Warn: [raat/tcpaudiosource] disconnecting + retrying
04/08 17:19:50 Debug: [raat/tcpaudiosource] disconnecting

I haven’t narrowed it down to only happening when it’s playing Tidal, or maybe MQA, that’s as far as I’ve gotten.

  1. When I group the Cambridge with the alsaloop endpoint, the Cambridge will start reporting a lot of clipping which it never does when not grouped with this endpoint or when grouped with other endpoints in the house:

Screen Shot 2023-04-09 at 9.42.28 AM

Full signal path for the Cambridge when clipped:

I’ve enabled headroom and experimented down to 6 with the same result. Is there another setting in the alsaloop endpoint that could be causing this? Interestingly I always have headroom set at 4 for the Cambridge, but when I group it with the alsaloop endpoint I can audibly here the volume of the Cambridge going up, like Roon is interpreting a different headroom for the Cambridge when it’s solo and then when it’s grouped.

Let’s see your parametric EQ resulting curve!

TLDR, how do you handle different sample rates/bit depths for the vu meters zone?

Volume leveling settings need to be set every time you ungroup/regroup zones, so that’ll explain you hearing volume changes, maybe?

I’m not sure how to find/show a resulting EQ graph?

Good catch on volume leveling; I have it set to Auto for the Cambridge and not enabled for alsaloop. Once I enabled it for alsaloop and for the grouping the volume issue went away. Thanks for the pointer!

I don’t have max sampling rates or max bits per sample option for the alsaloop device. Both the Cambridge and the Cambridge+alsaloop groupings are set to allow 192kHz.

The white curve in my example is the resulting EQ curve.

Ah, didn’t realize there was a resulting EQ.

According to the graph it seems you’d need at least -5dB of headroom, but you could also use the slider to the right of the graph to pull it down to stay below 0dB, instead.
You should at least effect less clipping occurrences when decreasing gain, so just keep on reducing it to remedy and keep observing…

Good luck!

I had an urge to use PeppyMeter for cool VU meters but also (importantly) to show the metadata for the current playing track, whether this is from internet radio, spotify or roonbridge.

I bought a Waveshare widescreen 7.9" display and mounted it in a metal box that sits on top of my kitchen radio (an old valve radio) which houses the Pi and AMP2 so it’s not “proper hifi”.

I swapped out DietPi for Volumio on my Rasberry Pi as thought this would be the easiest way to get this all working whereupon I discovered that Peppymeter doesn’t display metadata for Roonbridge…

I did start investigating the guidance in this thread but for my use case, it all looked a bit complex and (I was thinking) might result in metadata for roon but not for the other sources. So (as an experiment), I enabled shairport in volumio so I can stream to the Pi via Airplay from Roon and lo, the metadata displays perfectly!

For my limited sonic requirements, this was a quick and easy way to get Peppymeter working with Roon.

Using AirPlay and Volumio+Peppy via Roon is a great tip, thanks for sharing! Can you group AirPlay endpoints in Roon with RAAT endpoints?

I’ve reached out on this thread asking for Volumio+Peppy support for Roon as a source and it sounds like it’s not on anyone’s roadmap:

That’s not possible, unfortunately…

Just a quick update here: I’ve been relatively stable and running on my PeppyMeter build for a few weeks and generally everything is great. I’ve noticed that when grouping the loopback device with my primary Roon zone in the same room, alsasound seems to be a bit less stable when applying volume leveling, it just stops receiving or sending data on occasion but doesn’t report anything in logs. Not an issue that a quick reboot of the Peppy Pi won’t fix. So overall I’m really pleased with the results, and wanted to say thanks again to this community for the help and feedback on getting this in place.

But never satisfied, I saw these just came out and immediately started thinking about options to run one per channel. :smiley:

Anyone get this working with moode audio?

I followed this guide and everything works except the needle never moves. I tried grouping with both Loopbacks that appear in Roon.