Sometime in July 2021 I thought it'd be kinda cool to have an actual lofi beats radio. Somewhere between this decade and the last I stopped listening to so much music, and I kinda blame streaming services for it.

When you had to load your own music onto a player it meant you had a collection, and that was something you curated. You had a mood, you'd pop that in your player, and you'd listen to it. Sure you can do that with radio-style play on Spotify or whatever, and you get the mood, but now it's all all been algorithmised instead of curated. There's plenty to be said for serendipitous discovery but that's not what I'm on about.

With a pretty much infinite selection of music at your fingertips now, nothing feels special any more. It's not yours, and to me it has an effect of mentally cheapening it. I like looking at my shelf of CDs, or my own local list of albums that I've ripped or bought. I don't really care about endless recommendations of similar things I might like, or what's hot this week.

Anyway that's just me, and sometimes I do just want to let the algorithm do its thing. I also want it to be a dedicated appliance because fiddling with a phone to change the volume or pause the music is distracting, and bluetooth sucks while we're on the topic. I want a box, the box plays music, and the box has a volume control. There's this old thing called a radio that did that quite well. I want that radio to play lofi hip hop radio - beats to relax/study to and I want it to just work with minimal fuss.

I started with the Pirate Audio amp for RPi, it's a DAC and amplifier and screen and buttons, all in one. It's gonna be small, which is great. That was $41 over at Core Electronics, and a basic speaker was another $6. I already have the RPi Zero W lying around from previous tinkering, which is lucky because they're in somewhat short supply.

I tried using Mopidy music server but it turned out to be way too heavyweight. It can integrate with a dozen different things but I only want one. The Pi Zero really doesn't have enough grunt, so we need to go back to basics. What's the simplest thing I can do? Play the youtube stream, ditch the video, and pump that out some speakers. It doesn't really get any simpler than that. One of the great things about Linux is that you can do stuff like that from the command line.

I think I could replicate the build again, it goes something like this:

  • Start with RPi OS buster Lite (based on Debian 10.10)
  • Configure wifi, enable SSH, get your SSH key on there, update all packages, install tools like vim, git, lsof, and whatever else you might need for diagnosing problems when stuff doesn't work
  • Install Python packages for gpio and spi: apt install -y python3-rpi.gpio python3-spidev python3-pip
  • Enable SPI (raspi-config nonint do_spi 0) and setup the audio hat in /boot/config.txt according to instructions
  • Disable as many unneeded components as possible to trim down the system and make it boot quicker. Stuff like: bluetooth, daily apt-upgrades, modemmanager, avahi daemon, dhcpcd
  • Write a simple script to play the muzak, and run it as a systemd unit so it starts on boot. The script runs mpv with a playlist of youtube URLs, and it repeats the list on infinite loop. I think I was able to tell it to discard the video stream, and pump the audio out the I2S soundcard (the Pirate Radio hat).
  • Write a little frontend script to drive the SPI display and GPIO buttons. It controls mpv via its JSON-RPC socket, and draws images and UI elements to the little screen. This script is also run as a systemd unit so it starts at boot.

With a whole lot of fiddling and playing with the screen, it works rather nicely. Drawing bitmaps to the display is quite slow, and putting a realtime clock on the screen causes it to flicker badly, but I'm probably just doing it horribly (like trying to draw the whole screen 30 times a second from a 24-bit colour image). I think it should be possible to only update a small portion of the screen, which would be much faster, but I don't know what I'm doing.

Four physical buttons is enough for Vol+, Vol-, Next Track, and... I forget what the fourth one is. Also you can trigger a shutdown by holding a button for three seconds.

When you initiate a shutdown the script shows this Disconnected image, which stays there because the display buffer is static, I think it's pretty elegant.

Honestly the startup time is not impressive. The OS boots plenty quickly, but connecting to the stream and starting to play music takes a really long time. I think it's because the Pi Zero CPU really doesn't have enough grunt for playing youtube, but I'm probably doing it wrong as well. As a stopgap I decided that it can boot into playing a local MP3 (Never Gonna Give You Up), which tells the user that the device is up and running. Then when you hit Next Track (or wait for Mr Astley to finish) it'll grind its way into playing some lofi beats, live from youtube.

One final optimisation is to make the system read-only. It'd suck if your lofi radio falls over one day because your SD card got corrupted, but thankfully it's pretty easy to make a Linux system read-only so there's no chance of corruption happening (unless you interrupt it during boot, I guess).

Using this guide as a basis:

apt purge triggerhappy
systemctl disable console-setup
apt purge logrotate

apt install busybox-syslogd
apt purge rsyslog

systemctl stop dphys-swapfile.service
apt purge dphys-swapfile

apt autoremove -y

And uhhh, yeah I think that's it. The biggest change here is replacing the default syslog daemon, and getting rid of the swapfile. After this you mark your filesystems as readonly in fstab and cross your fingers.

Some day I'll put this into a neat little box, and maybe chuck another speaker on there. Put in a little USB battery pack to function as a UPS, then it'll be a proper little radio.

Back To Top