Another Pi-Based Audio Streamer

My first Raspberry Pi streamer project has been in service for a few years now, so I felt it was time to build another one. Multiple players in different rooms can be synchronized with each other (or play different music from your library or live streams). Like the first, it is based on piCorePlayer. This time, however, I decided to use a much smaller touchscreen. Recently Osoyoo, a Canada-based company began offering a series of Pi-compatible touchscreens that use the DSI interface. They are less expensive than the "official" Pi touchscreen and come in different sizes. I decided to try a 3.5" screen for this project and then mated it with a Pi 3B+. While people have gotten other screens to work, this is usually problematic and not well supported by the piCorePlayer team. So it was nice to find a DSI screen that "just works" out of the box.

I then did some investigating to see what to use for a DAC. Allo had not yet released its new Boss 2, which supposedly will be a better DAC than the Boss 1, so I started looking at USB DACs. I almost bought a $99 Schiit Modi 3+, which is based on an AKM chip, thinking I would remove the board from the enclosure. But then stumbled across the Khadas Tone 1 DAC, based on the ESS ES9038Q2M chip. It also incorporates the XMOS XU208-128-QF48 chip which for USB interfaces, is about as good as you can do. I have trepidations about USB interfaces since they are noisy and prone to jitter. What I liked about the Boss design is that it was a master clock provider to the I2S Pi bus, with onboard low-jitter clocks. The downside for the Boss is that it uses the TI PCM5122 DAC chip, which while not bad, is not quite in the same league as the AKM and ESS chips. It has higher noise and distortion figures than either.

Here is the tiny 3.5" Osoyoo touchscreen connected to the Pi with the supplied DSI cable.

Here is the flip side. The display gets its power through the DSI interface, eliminating the need for a separate +5 Volt connection

Here is the display with the Pi mounted on the back. After burning a micro-SD card with the piCorePlayer software and booting up the player, it was able to connect to the LMS server running on my other player over WiFi. A headphone was connected to the Pi's onboard audio out to verify everything was working.

The touchscreen is very small, so is not particularly practical for controlling the player, but is good for display purposes. I also tested this RF remote, which works fine for navigating the player screens, selecting tracks, etc. Next step will be to connect the Tone 1 board and hook it up to my main listening system.

Here is the Tone 1. It appears to be a well-designed board and has RCA outputs, USB C input (also for power), and a S/PDIF connector. In the "generic" version, this can only be an input. In the "VIM" version Khadas sells, for use with their SBCs, it can be either input or output when running Volumio software, which is interesting. I will be using the USB port for input only. An intriguing feature is that has an onboard connector for multi-channel sound output (up to 8 channels total) and an OLED display, but that is for another day.

The Tone 1 is spec'ed to decode PCM up to 384KHz at 32-bit resolution (yeah, right) and DSD up to DSD256. After some further checking, I found this review of the Tone 1 board on Audio Science Review, a well-respected website with comparisons of many DACs.

This chart is from audiosciencereview.com showing the relative position of the Tone 1 DAC (in red) in terms of measurement quality versus other DACs. Some of these DACs are in the $1000+ range, so for an $89 board, it is pretty impressive. Here is the full-size chart. THD+Noise was measured at 0.00033%, an astonishingly low figure. This is only slightly worse than the Benchmark DAC3, for example, which sells for $2,200 (in a case, of course). Measurements are not everything, but this approaches the limits of what is measurable, so the only thing left to worry about is listening! Another nice thing about the board is that it is well documented, even schematics.

Here is the Tone 1 temporarily connected to a USB port on the Pi. The RCA outputs are feeding my Yamaha passive preamp, McCormack DNA .5 amp, and Matin Logan panels. Sounds great and worked right out of the box after setting piCorePlayer to use USB for audio and turning off the built-in Pi audio output. This setup is powered by a 5 Volt 3 amp wall wart, so is not optimal for a high-quality setup, but OK for testing.

The sound out of the Khadas is VERY good. I noticed an immediate difference in detail vs. my older player. It sounds especially nice with my class A amp.

Here is the Modushop chassis I decided to use.  This is the "Galaxy" 2U chassis with a 10mm thick aluminum front panel. The dimensions are 230 x 188 mm external. The back panel will require some metalwork on my part. I hope my drill press is up to the task. I also finally broke down and ordered a Dremel look-alike set to cut rectangular openings. 

I designed a front panel using Front Panel Designer for the player which will look like this (front view). The round recess is to allow for a knob attached to a rotary encoder. I sent the file along with an order for a Modushop chassis from the DIY Audio Store.

Here is the back of the panel. The recess will allow the display to be mounted slightly recessed from the front surface. I specified a 7mm depth for the recess (10mm thick aluminum panel, leaving 3mm for the bezel). I got some plastic screen retainers (as in window screens) to mount the display from the back. There are 4 blind-tapped M3 holes to screw these into.

I decided that the new player should have a linear 5 Volt supply for the Pi and the Tone 1. Since I already had PCBs from my preamp project, this was a no-brainer. I just had to re-order components from the BOM I already had for Mouser. I did upgrade the 3-terminal regulator to an LM1084 5 amp version, which should have plenty of headroom for the pi, display, and DAC.

Linear supplies are always better than SMPS or wall-warts (which are usually SMPS anyway) and will keep noise to a minimum. It would be ideal to use separate supplies for the Pi and the DAC, but this would require some customization to the Tone 1, since by default it gets its power from the USB interface. Khadas has actually documented how to do this, but I was opting for simplicity. (Is perfect the enemy of good? Haha).

Since I wanted to have a rotary encoder on the front panel for this project to make it easier to navigate the interface, I did some research into what others have done. This turned out to be trickier than I expected and does not work out of the box. One of the long-standing members at the Slimdevices Forum, "pippin", (who also happens to be the author of iPeng, the iOS remote control software for piCorePlayer and LMS) had created a utility to allow for an encoder to perform control functions. Eventually, this utility got added to the piCorePlayer extension repository. After figuring out how to wire an encoder to the GPIO interface for the Pi, I found a forum entry explaining how to create a script to set up these functions. The script looks like this: 

#!/bin/sh

# start pigpiod daemon

pigpiod

# give the daemon a moment to start up before issuing the sbpd command

sleep 1

# load uinput module, then set the permission to group writable, so you don't need to run sbpd with root permissions

sudo modprobe uinput

sudo chmod g+w /dev/uinput

# issue the sbpd command

# This command will cause encoder to move selection right or left; Press=Enter; long press=down

sbpd e,20,21,KEY:KEY_LEFT-KEY_RIGHT,4  b,26,KEY:KEY_ENTER,4,0,KEY:KEY_DOWN,500

In order for the script to execute, the permissions on it need to be changed in the tc home directory in piCorePlayer:

chmod 755 sbpd-script.sh

The last line of the script describes the action taken by the system when the encoder is activated. In my case, I chose to have it navigate the jivelite UI by moving the item selection left or right depending on the direction of rotation, and when the encoder knob is depressed, acting like "enter" on a keyboard. A long press will simulate down navigation to allow selecting items in a list. The details of the sbpd parameters are listed here. The script is named sbpd-script.sh and is placed in the home directory for the default user tc. The numbers 20, 21, and 26 correspond to the GPIO pins on the Pi. The wiring for the encoder is as follows:

SW to GPIO26 (physical pin 37)

DT to GPIO20 (physical pin 38)

CLK to GPIO21 (physical pin 40)

+ to 3V3 (physical pin 1)

GND to Ground (physical pin 6)



The choice of pins is somewhat arbitrary. Since I am not using a Pi "hat" they are pretty much wide open. 

In order for the script to run, two extensions need to be added to piCorePlayer: pigpio.tcz and pcp-sbdp.tcz. These are available in the piCorePlayer extensions repository. The script is started at boot time by adding this entry in the user commands section of the "tweaks" page in the piCorePlayer web UI:

/home/tc/sbpd-script.sh

Here are typical rotary encoders. These are very cheap and can be easily interfaced with a Raspberry Pi GPIO header. In addition to producing pulses as the shaft is rotated when the shaft is pressed, a switch closure is sensed. This particular version has a small PCB with pins for easy connection to the Pi GPIO connector with some DuPont jumpers.

While waiting for my customized chassis from Modushop in Italy (stuck in a FedEx warehouse at Charles DeGaulle Airport in Paris for FIVE DAYS), I did some more reading on the Tone 1 and ESS ES9038Q2M chip implementations in general. It seems that some commercial DACs with this chip exhibit a weird "hump" in the IM (Intermodulation Distortion) measurements vs. levels. ESS does not publish details, and if you want information from them, you need to sign a non-disclosure agreement, which is weird in itself. It turns out the original designer on the Tone 1 went off to start his own company building DACs (SONCOZ) using the same chip. He was disturbed about the hump, despite the fact that no one seems to have been able to confirm its effect on listening to music. So in late 2019, he published this article in Audio Science Review about how to fix it. Turns out he needed to change values in the I/V converter stage after the D/A chip. In other words, it was not possible to fix it by changing the settings inside the chip. Apparently, Khadas has not implemented this in the Tone 1 to date, so I am stuck with the hump. Modifying the board would be difficult since several resistors and caps have to be changed and they are all SMD devices.

Despite that fact, I decided it would be interesting to fiddle with the parameters inside the chip (mainly the filters), so I ordered some ESS controller boards from Ian Jin (aka iancanada in the DIY Audio Forums). He had built several projects around the ESS chip and wanted a way to control it so he built a board based on an STM32 ARM processor, complete with a tiny OLED display and rotary encoder for setting various ESS chip parameters. Since it will be too late to put the OLED display on the front panel of my case (additional CNC milling required), I will either place it on the rear panel or leave it inside the box.


CNC machined front panel received from Modushop Italy. Perfectly done as usual. Here is the Osoyoo touch panel held in place "blind" in the back of the panel by plastic window screen clips. On the left is an encoder. I guess I could have designed in an additional encoder (maybe for volume) since there is plenty of real estate.

Power supply issues arose when I started bench testing. The onboard rectifier diodes got too hot when I loaded the supply up to about 2.5 Amps with a test load, so I removed them and added a bridge rectifier which I mounted on the side of the chassis. Also, the heatsink for the 5 Volt regulator gets a little too hot for my liking, so I ordered a bigger one. As it turns out, the total load on the supply is only about 1.5 Amps when the player is idle (but with the display on). The unfiltered DC runs about 8.5 Volts, so the regulator has about 5 Watts dissipation ((8.5-5.1)*1.5). Since the old heatsink has about a 10-degree C rise per Watt, that means the regulator is running about 50 C above ambient (inside the box). The new heatsink indeed allows the regulator to run a lot cooler (the new heatsink is specified at about 5 degrees C/Watt), so the regulator should be more reliable. I made the classic mistake of taking power supply design for granted and should have run through some basic calculations ahead of time.

Here is the interior. The Pi is mounted on the left chassis side panel. Power to the Pi is fed directly to the GPIO pins and not the USB connector. The DAC is as far away from the transformer as I could get it. There is plenty of room left, so I may add a headphone amp at some point.

The back of the unit - drilling the 1/2" holes for the Tone 1 RCA jacks was a challenge. The aluminum back is quite thick ~ 1/8 inch. I added a Wifi dongle (since the Pi's built-in WiFi won't work in a metal box) and an RF remote dongle. Also a USB flash drive for the LMS library.

Completed unit being tested. The nice aluminum knob came from Amazon. Everything seems to work OK, including the RF remote. Sound is excellent.

I have not yet added iancanada's ESS controller - I will do that at a later date since I wanted to get the player up and running.

There is plenty of room in the chassis for more stuff - I am thinking of adding a headphone amp. I need to figure out if I can build one which only needs 5 Volt power, or perhaps add another linear supply. If the box turns into a (mostly) headphone device, I would want to add a volume control. iancanda's controller apparently can serve as a hardware volume control, since it manipulates the internal registers inside the ESS chip. Theoretically, the ESS design allows for bit-perfect volume control, as opposed to just throwing away bits in an ALSA software mixer running inside the piCorePlayer, so should be preferable.

One thing I ran into is the backlight brightness could not be adjusted with the piCorePlayer settings. It complains that the display is not the "official" Pi display and won't change it. Osoyoo has some hints in their user manual, but they do not work with this version of linux. It turns out that this was fixed simply by updating the Jivelite software, which I had neglected to do after flashing my SD card with the latest piCorePlayer software. For some reason, the piCorePlayer team keeps the Jivelight updates separate from the main software updates, so I missed it. Problem solved.

Some screenshots of the player in action:

The Album View - sort of like a jukebox. The front panel dial or the remote can be used to scroll through the albums. Also, iPeng on an iOS device works great.

Playlists view - you can create or play saved playlists. The LMS server actually stores the playlist data and persists it on its local storage.

Now Playing View. When in this view, different views of the current album art/song info can be displayed by touching the screen.

Simulated VU Meter View - there are a few variations of the VU meter. Mostly eye candy but useful for seeing relative levels of the source.

2023 Streaming Update

I was gently reminded by a family member that while my older collection of ripped CDs played on this box sounded nice, they were old and somewhat limited in terms of artists and genres. So I decided to try Qoboz. I installed the LMS plugin and signed up for a trial. They have an extensive catalog of Hirez recordings and I have been enjoying listening to some albums not in my collection. I have noticed some occasional stutters which could be network congestion on their end (or mine). I think the WiFi dongle I have on this box is only 2.4 GHz, although that should be sufficient. It could also be that the Pi 3B+ is getting bound up, but I doubt that. I can check using an SSH top command during a stream.

Anyway, streaming sounds good and I particularly enjoyed listening to the Crosby, Stills, and Nash demo album. David Crosby's solo acoustic rendition of Almost Cut My Hair is spectacular!