Building Retro Audio System with piCorePlayer and Raspberry Pi 4

Mladen Dragicevic
9 min readApr 9, 2022

--

Some time ago, I was visiting a small local record fair in the center of Zagreb when I’ve noticed a guy selling some old fashioned radios. He was in business of restoring mostly vintage valve radios. I was actually looking for something similar as a casing for a streaming server I was planning to build. Anyway, I’ve managed to get my hands on a broken piece he had, so I’ve started to build on this project.

Now, the radio itself was not working, but had most of the parts (although in a very bad condition). Also, it was big. Way bigger than I wanted to build at first, but it was best I could find so I was determined to salvage as much as possible and to utilize the size in some manner.

It was missing the back panel and the buttons at the front were in a bad condition. So, I’ve stripped the interior from the original parts as they were not working and I did not need them. I’ve also removed the speakers since idea was to use Bluetooth connection to connect to external speakers. After this, I’ve disassembled the front glass panel and the original buttons. Now I could clean the interior of the radio and the front glass panel where names of old radio stations are printed. I’ve also restored the buttons to their original condition as best as possible (filling broken plastic parts and repainting them). I did not want to repaint the wood or clean more on the fiber parts as I wanted that old grungy look for it.

Front panel after restauration

The Interiors

Ok, now that I’ve had all the important parts of the casing in place, I could focus on the interior hardware. My intention was to connect the streaming server using the Bluetooth connection, so I could position the radio in a different part of the living room and reutilize the speakers I have for the TV. This also implied that a Wi-Fi connection is needed to connect the radio to the router. The speakers under the TV did not have a Bluetooth receiver, so I’ve bought Logitech Bluetooth Audio Receiver. There are also other options available and they are fairly cheap, so this is a good solution if your speaker system is older. However, be aware of the distance between the source and the receiver as Bluetooth can be sensitive to obstacles and interference (I’ve learned this the harder way).

I already had a Raspberry Pi 4 model B (with 4GB RAM) lying around, so I opted to use that. To be honest, this was probably an overkill for a project like this - an older or cheaper model could probably be used with the same outcome.

The good thing with this model of Raspberry Pi is that it has integrated Wi-Fi and Bluetooth chip. Also, Wi-Fi can operate on 5GHz so in theory it won’t interfere with the Bluetooth chip. The bad thing is that onboard Bluetooth is very limited in range and in practice if you don’t have the receiver very near, you will have audio stutter and interference. I’ve lost a couple of days trying to figure out why sometimes randomly I have such a bad stutter and blamed it on the Linux (because Bluetooth and Linux is a special kind of voodoo). But in the end, with the help of the good folks that are developing piCorePlayer, I’ve managed to pinpoint that indeed problem is in the hardware and an external Bluetooth dongle is needed.

That being said, I think there is a special place in hell for those manufacturers that use cheap knockoff copies of chips in their dongles. First one I bought had what it turned out to be not an original Cambridge Silicon Radio chip, so I’ve tried to patch the kernel on multiple tries to make it work without a success (the damn thing just would not connect whatever I did, although lsusb command listed it as a CSR device…). I’ve also lost a couple of days on this (and quite some nerves). So just be careful with this, as I could not find good info online which dongle works well on Linux while it was also available in my local retail store to buy. In the end, I’ve managed to get it working with TP-Link UB400 out of the box. Anyway, takeaway lesson from this is that Linux and Bluetooth can be a nightmare, you have been warned!

Honey, I Shrunk the Electronics

The Cosmetics

Actually, those were the main parts needed for this thing to work, but it was missing something. Remember how I said this thing was huge? So it will not be on a shelf, but rather placed in a room somewhere as a display piece…

This is why I wanted to make it a bit more interesting and since I had extra room inside the radio, I’ve decided to place some LED light strips. When the radio is turned on, LED strips would glow through the front glass panel illuminating radio stations names. Actually, for my first iteration I’ve used some yellow LED diodes I’ve soldered on, but they were just too weak for this glass panel. I wanted it to be more visible, hence the LED strips.

I needed external power for the LED strips and a relay to switch them on/off using the Raspberry GPIO based on the playing status of the streaming server. I wanted to have only one power cord from the radio, so I’ve placed an extension cord inside in order to have both adapters (from Raspberry and LED strips) plugged in without the need to cut their cords.

Relay is getting signal on the GPIO17 (board pin 11) here, of course other GPIOs are also possible to use. I’ve used 3.3V relay connected as normally open. You can also use 5V relay which is much easier to find, but additional modifications to the wiring could be needed.

LED strips are between the metal part and front glass panel

The Brain

Now that hardware part was solved, it was time to focus on the software part. There is this great project that Paul, Steen, Ralphy and Greg are developing called piCorePlayer. I have to say that also community and their response to the community is one of the best I’ve seen online. I’ve installed what is called option number 3: complete music system with integrated player and server (Squeezelite and LMS).

But what is piCorePlayer? I’ll put a quote from their webpage here as I think it explains it quite well:

pCP is a highly specialized audio system. By installing extra software packages and hardware additional features can be added.

piCorePlayer is built on a very small Linux distro which is only about 12 MB, known as piCore Linux. It boots very fast and it is running entirely in RAM, it doesn’t write to the SD-card unless you want to save a new setting. Therefore, pCP is very robust and you can simply pull the power without any risk of corruption of your SD card.

There are numerous plugins available online, depending on which services and customizations you need. Also, material skin for SlimServer really makes whole Logitech Media Server look beautiful both on mobile phone and on the computer as it has responsive design. Setup is fairly easy, I’ve just followed the documentation available online.

LMS using material skin

One thing that was not so easy to do was getting the LED strip to work based on the status of the player (whether it is paused or playing). For this to work I had to get a bit creative and managed to figure it out when I’ve stumbled on a plugin that looked like it is not officially supported anymore, but was still working. Plugin is called SBNetIO developed by Guenther Roll. Unfortunately, I could not find his code repo anymore as it seems deleted, but luckily plugin is still available on forked git projects. The plugin forwards LMS (formerly known as Squeezebox Server) events to a listening server by means of network communication. On server side these messages can be translated to arbitrary actions. Thus, in combination with a server the plugin offers a mechanism to run remote commands. So, to use the plugin you will need to setup another server — on its own, the plugin is pretty useless.

I’ve written a very simple Python script which starts a simple TCP server that based on the received signal starts or stops the LED strip lights (by activating/deactivating pin board number 11/GPIO17 in this case):

#!/usr/bin/python3import asyncio
import RPi.GPIO as GPIO
GPIO_SWITCH = 11async def handle_command(reader, writer):data = await reader.read(100)
message = data.decode()
addr = writer.get_extra_info('peername')
if message == 'upali\n':
GPIO.output(11, False)
elif message == 'ugasi\n':
GPIO.output(11, True)
else:
print('unknown command')
writer.write(data)
await writer.drain()
writer.close()
async def main():
server = await asyncio.start_server(
handle_command, '127.0.0.1', 8888)
async with server:
await server.serve_forever()
if __name__ == "__main__":#Initial GPIO-setup
GPIO.setwarnings(False)
GPIO.cleanup()

# to use Raspberry Pi board pin numbers
GPIO.setmode(GPIO.BOARD)
GPIO.setup(GPIO_SWITCH, GPIO.OUT)

asyncio.run(main())

The server is running in this example on 127.0.0.1:8888. I’ve added user defined commands to the piCorePlayer startup procedure so this server starts on boot (it is under Tweaks on the settings panel, make sure to have Beta mode enabled):

Running Python script at startup

Now I needed to configure SBNetIO plugin to send the appropriate commands. If you check the plugin list, settings for this plugin is missing (I guess due to some sort of more recent incompatibility), but you can still access the settings by manually navigating to the correct address (I’m using material skin):

<addres:port>/material/settings/server/plugins/SBNetIO/settings/basic.html

Entering data here will create modifications to the preferences file located at <mounted_folder>/slimserver/prefs/plugin/SBNetIO.prefs (here is my preferences file after the settings input):

---
_client:e4:5f:01:2a:8d:95:
_version: 0
_client:ec:81:93:9b:88:03:
PowerOffOnPause: 1
Zone1Active: 1
Zone1Auto: 1
Zone1Name: Ledice
Zone2Active: 0
Zone2Auto: 0
Zone2Name: Zone 2
Zone3Active: 0
Zone3Auto: 0
Zone3Name: Zone 3
_ts_PowerOffOnPause: 1646814137
_ts_Zone1Active: 1646814137
_ts_Zone1Auto: 1646825789
_ts_Zone1Name: 1646825789
_ts_Zone2Active: 1646814137
_ts_Zone2Auto: 1646823450
_ts_Zone2Name: 1646814137
_ts_Zone3Active: 1646814137
_ts_Zone3Auto: 1646823450
_ts_Zone3Name: 1646814137
_ts_delayOff: 1646826919
_ts_delayOn: 1646814137
_ts_msgOff1: 1646825789
_ts_msgOn1: 1646825789
_ts_pref_Enabled: 1646823450
_ts_srvAddress: 1646823663
_ts_srvAddress1: 1646825789
_version: 0
delayOff: '0'
delayOn: '0'
msgOff1: ugasi
msgOn1: upali
pref_Enabled: 1
srvAddress: 127.0.0.1:8888
srvAddress1: 127.0.0.1:8888
_version: 0

So basically plugin is sending msgOff1 for turning off command and msgOn1 for turning on command on the specified address and port (127.0.0.1:8888), while server written in Python is running on this port and accepting defined commands… Final product?

Let there be light…

I still need to add back cover to the radio case, but overall I’m very happy how this project turned out. Audio quality is great, stutter is gone and whole thing looks quite nice :)

I would like to say thanks once more to the good people developing piCorePlayer as well people contributing with nice plugins and whole community. I’ve mostly focused in this blog post on the whole idea and how to setup things that were more or less unique to this project, but without the piCorePlayer this project would be much, much more complicated.

Thank you for reading this and I hope maybe it will inspire others with more ideas. If you like what you read let me know and hit follow to keep up to date with my future projects. Cheers!

--

--

Mladen Dragicevic

Love creativity and techy stuff… especially the combination of those.