Dino Fizzotti

Engineer, maker, hacker, thinker, funner.

Feb 5, 2020 - 11 minute read - Comments - Software Go Raspberry Pi

Diskplayer: Using 3.5" floppy disks to play albums on Spotify

Diskplayer

Diskplayer is an audio device which uses physical media to play streaming music with 3.5” floppy disks and Spotify. You can find a GitHub repo with code here: https://github.com/dinofizz/diskplayer and a video showing playback and record activity here: https://youtu.be/1usBGe_ZiGc

History

Spotify is amazing. With a few taps on my phone I can access all the music I love to listen to, both old and new. Spotify makes it really easy to find something to play and to switch from a track on one album to another.

Some of my top tracks on Spotify from 2019 Some of my top tracks on Spotify from 2019

I first started buying music of my own in 1997. I think the first CD in my collection was Robert Miles’ Dreamland. My collection grew gradually, and by the time I bought my last CD in 2012 (Phantogram's Nightlife EP, purchased after a live show) I had a decent number of albums.

The first and last CDs I bought The first and last CDs I bought

Notice that in the previous paragraph I used the phrase “music of my own”. My CD collection was distinctly mine. Mine to listen to on my stereo CD player in my bedroom or on my Sony Discman. Mine to lend out to friends. Mine to take care of and mine to neglect. It's hard to view the vast infinite catalogue of music available on Spotify as being mine - it's Spotify who is doing the honour of lending me the music, one stream of bytes at a time.

The listening experience was also very different with CDs than it is with using Spotify on my iPhone. Music albums were something I saved for and I can recall the excitement and anticipation I had after purchasing a CD. Since it couldn't be listened to immediately, the wait from the music store to my bedroom seemed endless. What a ceremony it was, once I finally made it home. I would rip off the protective plastic wrapper, open the case, stretch my thumb and middle finger over the diameter of the CD, press my index finder in the middle of the case to release the disc, insert it into my personal stereo CD player and press play. With the first few notes flowing from the speakers, I would carefully slide out the cover which was usually a small booklet of glossy and slightly stiff paper, and sometimes a pull-out poster. Whilst I lay on my bed listening, I would admire the cover and read every square millimetre of the insert: music lyrics, production acknowledgements, political statements. Spotify does deliver some of these components, however it's presented to you not by the artist, but in a very Spotify-framed experience.

I like to listen to entire albums from beginning to end. Part of this is because I felt this is what the artist must have intended when creating the track list. However swapping out CDs and changing from a track on one album to another was a really disruptive experience - even with the Sanyo 5 CD changer stereo I had in my later teenage years.

Of course many of the points made above are the same reasons for the recent resurgence in popularity of vinyl records. People enjoy feeling connected to their music. Their music. One property of vinyl records which I like is that moving backwards and forwards within a track, or even from one track to another, is not directly supported by the medium or most players. The single physical groove which spirals from the outer rim to the centre encourages the listener to experience an album from beginning to end. I will not comment on whether or not vinyl records sound better than CDs ;)

So if you haven't guessed by now, I miss this experience. Diskplayer is a project I created which combines the nostalgia of physical media with some of the practicalities of on-line streaming music - and a retro twist: I'm using 3.5” floppy disks to play albums on Spotify.

Diskplayer

Diskplayer

Features

  • Physical media with album art: picking an album to listen to requires flipping through a collection of disks, identified by album covers
  • A purposefully limited playback experience: there is no track skipping or scrubbing - the album starts playing once the disk is inserted, and stops either when the album has finished playing or the disk is ejected
  • Unlimited catalogue: album availability is that which is found on Spotify
  • Ability to “record” Spotify albums to new media using a web UI
  • Improved audio quality using an external digital-to-analogue converter

See a video of Diskplayer in action here:

3.5” Floppy Disks

My original idea was to use RFID tags on random vinyl records to identify Spotify albums as they were placed on a record player. I developed this concept on and off for a few years, and had bits of working hardware and software in various stages, but after a few years I grew to like the idea of reducing the project complexity (in size and moving parts). In 2017 I was off sick for a few days and ended up binge watching a bunch of Techmoan, LGR and The 8-Bit Guy videos, which seeded in me the idea of using floppy disks. This meant I could remove the RFID tags and reader, and read and write Spotify URIs directly to the disks! Much simpler, and the hardware did not need any construction. A simple USB floppy disk drive and a Raspberry Pi would do the trick.

As the hardware and the floppy disk case are all matte black I thought I would use colour floppy disks with a black shutter to brighten the project up a bit. I found all my disks on eBay, with an average price of around £1 per disk.

Floppy disks
Disks

For the album art I used Ben Dodson's iTunes Artwork Finder to source the images. I used GIMP to add a colour-matched border around the sides of the square album covers to match the dimensions of a rectangular floppy disk label. I used a local print shop to print sheets of 6 images on A4 sticker sheet, which I then cut with a craft knife and applied to the disks.

Diskplayer Hardware

USB disk drive, Raspberry Pi and floppy disk holder

Diskplayer consists of the following hardware:

I purchased a generic USB floppy disk drive from Amazon, and the choice of a RPi 2 was simply because that's what I had at the time. As the RPi 2 does not come with on-board WiFi, I am using an Edimax WiFi adapter. While the Raspberry Pi does come with a 3.5mm audio out interface, the sound is created using the Broadcom SoC's PWM lines and filter circuits. As I was aiming for a “hi-fidelity” experience (yes I know I'm playing lossy compressed streaming audio) I opted to add the HiFiBerry DAC board. It sounds great :)

Raspberry Pi 2 Model B Raspberry Pi 2 Model B
Raspberry Pi showing HiFiBerry DAC Raspberry Pi showing HiFiBerry DAC
USB Floppy Disk drive USB Floppy Disk drive

Diskplayer Software

The following software components are running on the Raspberry Pi:

  • Spotifyd
  • A combination of a UDEV rule and a script to detect floppy disk media changes
  • The actual diskplayer player and recorder applications

Spotifyd

First, some history…

My first iteration used Mopidy as a local music server, in conjunction with the Mopidy-Spotify extension. However at some point in last few years, Spotify deprecated the libspotify libary used by the extension, resulting in a loss of functionality:

Mopidy-Spotify is dependent on pyspotify, a wrapper for Spotify's libspotify C library. libspotify was deprecated in 2015 with no replacement. It is unmaintained, functionally limited, and also now unavailable from the Spotify developer site. Where possible we are moving to use Spotify's Web API instead. However, native playback is still only possible using libspotify and there is no official way for us to provide some Spotify features.

- https://github.com/mopidy/mopidy-spotify#status

Solution

In searching for a replacement for Mopidy I came across Spotifyd:

An open source Spotify client running as a UNIX daemon.

Spotifyd in turn makes use of librespot which is essentially an open source alternative to libspotify written in Rust. It looks like the people behind librespot have reverse engineered the Spotify Connect protocol.

Setting up Spotifyd on my Raspberry Pi originally involved compiling the project from the source code, but it looks like ARM binaries are now available from the releases page: https://github.com/Spotifyd/spotifyd/releases

The configuration is very simple, a single file located at /etc/spotifyd.conf and then the installation of a systemd unit file so that it can be run as a service after boot. This is all well documented in the project README: https://github.com/Spotifyd/spotifyd

Note: you will need a Spotify premium account for Spotifyd to work

Detecting Floppy Disk Media Changes

udev rule

To detect when floppy disks are inserted or ejected I make use of a custom udev rule. Udev is the “device manager” used by linux, and it features the capability to write “rules” which perform actions when specific conditions are met. To learn more about udev please check out the links in the resources section of this post.

I created a rule at /etc/udev/rules.d/100-floppy-change.rules with the following content:

ACTION=="change", ATTRS{idVendor}=="03ee", ATTRS{idProduct}=="6901", ENV{DISK_MEDIA_CHANGE}=="1", RUN+="/home/pi/media_change.sh $env{DEVNAME}"

This rule waits for the CHANGE events on a specific device, and then executes a shell script media_change.sh with an argument of the device name (i.e. /dev/sda).

I obtained the specific vendor and product attributes for my USB floppy disk device by running lsusb:

$ lsusb
Bus 001 Device 005: ID 03ee:6901 Mitsumi SmartDisk FDD

media_change.sh

I am using the shell script below to act on floppy disk change events. The script checks if the device is listed as part of the attached block devices (lsblk). If it is, this means that a new disk has been inserted. The disk is mounted to a fixed location on the filesystem, the Spotifyd service is started, and the contents of diskplayer.contents file in the mounted folder are used as an argument to the diskplayer player application. The device is then unmounted from the filesystem.

If there is no device listed in the output from lsblk then we assume that a floppy disk was removed. The script then invokes the diskplayer player application with a pause command, and stops the Spotifyd service.

See below the current contents of the script. I am writing a very basic log file out to mount.log:

#!/usr/bin/env bash
exec >> /home/pi/mount.log 2>&1
export LC_ALL=en_GB.utf-8
export LANG=en_GB.utf-8

echo "$(date) Start."
echo "$(date) Media change detected on device $1"

device=${1##*/}

lsblk | grep $device

if [ $? -eq 0 ]; then
    echo "$(date) Device exists on machine."
    echo "$(date) Mounting device $1 to /media/floppy."
    /usr/bin/systemd-mount $1 /media/floppy
    systemctl start spotifyd.service
    cd /opt
    /opt/player --path /media/floppy/diskplayer.contents
    /usr/bin/systemd-mount --umount /media/floppy
else
    echo "$(date) Device does not exist on machine."
    cd /opt
    /opt/player --pause
    systemctl stop spotifyd.service
fi
echo "$(date) End."

See below an example of activity from the mount.log file:

Sat 25 Jan 14:38:00 GMT 2020 Start.
Sat 25 Jan 14:38:00 GMT 2020 Media change detected on device /dev/sda
sda           8:0    1  1.4M  0 disk 
Sat 25 Jan 14:38:00 GMT 2020 Device exists on machine.
Sat 25 Jan 14:38:00 GMT 2020 Mounting device /dev/sda to /media/floppy.
Started unit media-floppy.mount for mount point: /media/floppy
Stopped unit media-floppy.mount for mount point: /media/floppy
Sat 25 Jan 14:38:05 GMT 2020 End.
Sat 25 Jan 14:49:29 GMT 2020 Start.
Sat 25 Jan 14:49:29 GMT 2020 Media change detected on device /dev/sda
Sat 25 Jan 14:49:29 GMT 2020 Device does not exist on machine.
Sat 25 Jan 14:49:30 GMT 2020 End.

The actual contents of the file diskplayer.contents is the Spotify URI for a specific album, e.g. spotify:album:3oyu7chRauu88JYPYfFB55.

Diskplayer

GitHub: https://github.com/dinofizz/diskplayer

Diskplayer is essentially a Spotify client, written in Go, built around zmb3's existing Spotify Web API wrapper.

This was the first project I had attempted in Go - in fact I chose Go specifically so that I could use this project as an excuse to learn a little about the language.

There are two components of diskplayer. The “player” binary and the “recorder” binary. The player binary can be used to obtain a new long-lived Spotify client authentication token, as well as accepting Spotify URI or a path to a file containing a Spotify URI which it will attempt to play. Playback occurs on an existing Spotify playback device, which is specified in a configuration file. Basic usage of the player binary:

$ ./player                                                                                                                                                                                     *[master] 
Usage of ./player:
  -auth
        Retrieve a new Spotify OAuth2 token.
  -path string
        Path to file containing Spotify URI to play.
  -pause
        Pause Spotify playback.
  -uri string
        Spotify URI of album/playlist to play.

So then an actual play command would look something like this:

$ ./player -uri spotify:album:3oyu7chRauu88JYPYfFB55

The recorder binary runs as an HTTP server, and exposes a simple UI which can be used to record a Spotify URI to a chosen location:

Displayer recorder web UI

I have more detailed build and usage instructions at the project's Github page.

Conclusion

Starting a project is easy, I've done it hundreds of times. Finishing a project is a much rarer occurence! My initial entry in my notebook for the idea of using a physical format to represent digital media dates to 2013. I'm really happy with how it has turned out 7 years later. I learnt many things along the way (some things which never made it at all into the final solution). And now I have a really awesome way to listen to music.

This project is dedicated in memory of Indie, a truly magnificent cat who would sit on my lap purring loudly whilst I worked on this project.

Raspberry Pi 3 and mitmproxy