The Magic Radio

This was first published on linkedin back in 2018 - but I've rehosted it here for organizational purposes and made some slight edits. You can always see the original at Putting the Magic back in a 1950's Radio | LinkedIn

This is Skipper Albert AWOL, the Voice of the Jungle, broadcasting on the DBC to all points unknown.

As someone who's visited theme parks quite regularly over my life, I've become quite familiar with the experience of waiting in highly-themed queues with looping soundtracks overlaid behind the murmurs of impatient crowds. And as with many individuals who have had a parks-injected childhood, I have become nostalgic for several of the more iconic tracks and loops. It's quite easy to pull them up online, simply googling "Jungle Cruise WDW loop" pulls up an hour long track ready for playback.

But for me, that wasn't quite authentic enough.

The Inception

While waiting in line for the Jungle Cruise at the beginning of the summer, one of my close friends and I began discussing the audio loop played overhead. Immediately, we came to the conclusion that a radio which could tune to various Disney Parks ambient loops would be a worthwhile investment of time and resources for our last summer project before college. Once I returned home that evening, I began prototyping to decide if this was something I could really do.

Prototyping / Proof of Concept

I had been in the possession of an early Raspberry Pi B+ for quite a while, but without a project to put it to work it simply languished in storage. So, first things first, I set up the raspberry pi with a light distribution of Raspbian, set up an SSH connection, installed a Wifi dongle, and began to test. With the SSH/Wifi connection, development was made easy through the SSH File System extension for Visual Studio Code and the PuTTY client for Windows, which allowed me to write all the code I needed from the comfort of my desktop. I began preparing the individual technical portions of the project one-by-one, all written in Python.

Recent reports of giant pythons have been greatly exaggerated. These reptiles cannot digest children weighing over 60 pounds in a single bite. The largest child they can consume at any one time would have to weigh less than 45 pounds.

1. Auto Playback

This one was simple. As I had gone with Python, the biggest recommendation was to use PyGame. Since using an entire game engine would be absolutley overkill for this project, I decided to only use the mixer object. This left me with one issue - all tracks had to have the exact same frequency / sampling rate. I ultimately decided on 48.0kHz, and would just re-encode all audio I wished to use through software tools like ffmpeg and/or avconv.

2. Physical Controls

When you imagine a radio from the 1930s, you imagine dials and sliders. All analog inputs. This was something I hoped to emulate with the radio. To accomplish this, I began experimenting with some potentiometers I had lying around from my first breadboarding kit. The Raspberry Pi, however, cannot read analog signals natively. However, an Arduino Uno (also from the breadboarding kit) can read analog signals. More importantly, using PySerial I can read the data that the Arduino sends over the serial/USB cable. Now I had something that could spit out data representing the position of both dials (volume and tuning.) A third prototype script joined the volume dial and the audio playback mechanics to create a very fancy looped mp3 player.

Retrospectively, an Analog-to-digital conversion chip could've done what I needed for a fraction of the cost. However, it would've taken more time than I wanted during the development process to wrap my brain around that.

3. Tuning

This is the effect / mechanic which ties the whole radio together. Any old mp3 player can shuffle music, play playlists, and adjust volume, but none (that I know of) simulate static with an analog tuning dial, as well as focusing into/out of a station while panning through the spectrum. In my research of modernized radios, I found a project which did a similar effect, but it used internet radios and other tech I really didn't feel like introducing into the MagicRadio. In their blog post, they document a diagram of their tuning spectrum. Inspired by that, I planned out my own.

Ignoring my crude handwriting, you can view how each station would be represented. The volume of the station would rise exponentially the closer you got to the center, settle flat, then fall in the same pattern as the rise but mirrored vertically. I used an exponential curve for the tuning shape to better present the effect of tuning into a station. Finally, a looping static sound effect would literally fill in the remaining volume, i.e. if the station is at 10% volume the effect would have 90% volume.

To represent this information in software, I store two pieces of data, the volume and the audio file playing, in a list 1,024 items long (the full range of the potentiometer). Once setup is completed, the program can simply read the value from the list and tune between different "stations." At this point, they're simple looping mp3 files. Unfortunately, this brought up an effect which had completely slipped my mind until this point: Persistence.

When listening to a radio station in real life, the music playback is already in progress. It is, as far as you can observe, permanent. It'll continue forever after you turn the radio off, or change stations, or anything like that. Tuning out then tuning back in sometime later means that that station has continued to play back music, and it might be at a different point in the song - or a different song entirely - than it was before.

The tuning system on here did not have that, and was jarring. It was implemented easily enough - begin playback on the audio file with a 'lead' in seconds. The lead is calculated by finding the current time since Epoch and subtracting from it a predetermined theoretical "start" point (in this, represented as MRGlobals.clockTime). If it was longer than the duration of the track, I'd go through and take the remainder of the lead divided by the duration. This would just give me the remaining time as if it had looped back on itself.

While doing this, I encountered another issue. When jumping ahead in time on a song, it'd take a while to actually start playback. So much so that it would sound like it was completely frozen. This was caused by my use of mp3 files - PyGame had to decode and decompress the audio file up to that point. The further ahead it was the longer it took. This was simply solved by switching to the ogg-vorbis format, one which doesn't use any compression.

The Quest for a Case

I had two options for a body:

  1. Convert a classic radio, gutting most of it to make space for the new parts
  2. Build a new body from scratch, attempting to make it look as authentic as possible.

I had no skill of any kind in woodworking at the beginning of the project, so I was heavily leaning towards the first option. I'm a bit of a nostalgic, so gutting anything older than me is a bit heartbreaking, but it was ultimately a much smarter option. I found a broken and battered radio at a flea market, which was given it for free thanks to its derelict state

This beautiful guy is a Silvertone 225, manufactured by Sears, Roebuck & Co. Originally equippable with a battery, I found him burnt out, cut, and missing the back panel in its entirety.

The Teardown

The radio housed the majority of its electronics in a metal drawer, fixed into the frame with two metal strips on the back and the dial wheels on the front. Removing this granted me a view of electronics which would never be shipped in a domestic product today.

 

It was amazing seeing this product, completely manufactured by human hands over half a century ago, but it was most definitely broken. Tubes burnt, wires snipped, just a mess. Not to mention various debris scattered through the circuitry.

It was a bit of a shame to strip it down.

 

Another unfortunate part of the construction was discovered somewhere around this stage: Many parts had been riveted into the metal frame.

A few hours with a drill solved that.

Crisp and clean, I could finally investigate what was onboard and how I could use it.

The Volume Dial

With my prototypes, I had been using potentiometers with an arduino. Turns out potentiometers haven't changed much in 70 years. A set of alligator clips later and now the radio is using the original volume knob.

As an added bonus, the original potentiometer also included a switch - turning the volume all the way down shuts down the radio. This was an easy (and worthwhile) addition. By disabling the audio output when the switch is in the "off" position, any extra noise is completely eliminated.

The Speaker

The prototypes had all been powered through an Amazon Basics speaker, connected through the 3.5mm jack. Theoretically I could keep using this, but a more professional solution came through the Adafruit I2S 3W Stereo Speaker Bonnet. Using the speakers that kit recommends produces a tinny, unpleasant noise. Curious, I poked the + and - of one channel and clipped that to the original radio speaker. Wonderful, crisp clear audio came out of the speaker, so I quickly ditched the plastic test speakers for this.

At some point, I began to notice an annoying hiss present in the speaker and a drastic amount of electrical noise in the analog input signals. A series of experiments provided me the source of this noise - the speaker was mounted via metal directly to the metal sheet the potentiometer was connected to - the electric ground of the device. Insulating the speaker mount removed the majority of electrical noise - both aural and input-wise.

It was at this point I posted a recording on twitter of the prototype software working with a prototype hardware assembly inside the original case

The Tuner

The radio used a string and wheel to display to the user what station they were tuned into - quite an elegant solution that still mechanically held up today. Not to mention, the actual tuning circuitry relied upon interlacing metal plates, changing the impedence of the circuit to tune the frequency it received. Very clever.

Unfortunately, this made it difficult to use in my project.

My original plan to use a potentiometer for tuning would have to use some adjustment. Here were my problems:

  1. The dial the user interacts with rotates several times more than the 270° potentiometers I had. If I wanted to just replace the main dial I'd either have to setup some weird gearing thing or just abandon the analog display entirely
  2. The big wheel (which rotates ~180°) was quite solidly attached. I could take a drill to it, but that is quite messy. And I'd still have a gearing issue.

I came up with a solution - I'd mount the potentiometer below the big wheel, attached to the same frame that holds that one up. Using a band, I'd convert the rotation of the big wheel to a new small wheel sized just right so that a 180° rotation of the big wheel would rotate the small wheel 270° over the same arc length (string / band length). I threw together the parts in Fusion 360, and ended up with something like this:

This first iteration, printed by a friend of mine, didn't turn out all that successful.

Turns out, when modeling the small wheel, I had forgotten to add the height of the walls to my original sketch of the circle. When inset, this resulted in the surface on which the belt rested on being a tad too small - about 30° of potentiometer rotation were lost. It also turns out rubber bands don't work great in this application - it kept slipping and stretching, causing the tuning to have latency and unpredictable behavior.

That last problem was solved by mirroring the solution the original engineers found.

I used floss (a pretty tensile strong string, not to mention abundant) and wrapped it around the big wheel mirroring the exact tensioning system they have in the original. I even used a piece of a pen spring to eliminate any slack. It's not spectacularly pretty, but it works well enough.

I had another small wheel 3D printed from Shapeways, this time the proper diameter, and its installation fixed the rotation issues I was having.

Now that all the mechanics of the device were working, it was time to get started on the software side.

A New Architecture

The original test software had several issues

  • Each station would be "fixed," or looping indefinitely as a single track
  • I could not control the position of each station in the tuning spectrum
  • It had no logging. If it was to run headless, as I planned, I would need to be able to find out why an error occurred through logs.
  • The code was very disorganized. All in one file, all without classes, just not great.

So, I built a new program from the ground up. Still using Python and all the modules I had mentioned before, I developed a system with these goals in mind:

  1. Stations could have individual behaviors, defined in a "stations.json" file
  2. Stations would be in the order I defined. This allowed me to build a "thematic gradient." Basically, stations around each other sound similar. My stations close to the left side sound more spacey & futuristic (Epcot, Wolf 359, etc) ranging to Big Band (DHS Entrance Loop, Jungle Cruise WDW and DLR, Fallout Radio Stations) and ending up back in a mystical theme (Animal Kingdom, Orbiting Human Circus, Classical Music) on the right side.
  3. The system would be easily expandable. If I wanted to add a new station it would be as simple as dropping in the music and adding it to the file. If I wanted to add in new behavior types I just needed to add a class.
  4. The system would give feedback to the user even when loading - The static sound effect playing would change volume with the volume knob while music was loading in the background, and play a "warmed up" sound effect once music was loaded. This let users know it hadn't crashed while loading, and the "warmed up" effect allowed the user to know it was ready even when tuned into static.

Over a few weeks, I put together the entire system. Now it has run for weeks without crashes, errors, anything. I published the code to github here, with a lot more technical details on the software and the power of the end-user. It describes the different station types, their various behaviors, and even some steps to get it running identical to how it runs on my radio.

I'm quite proud of the documentation, both in the Readme and the source code itself.

Now I had a functional radio, but it was still quite ugly. Shedding false leather, sitting uneven, and missing a back, it needed some TLC. Jumping right into materials and techniques I hadn't used before, I tried my best.

Fit and Finish

It was clear I needed to apply a new skin to the radio. Even really well done sealant wouldn't be great at preventing the shedding the current skin was doing, and it would still be quite ugly. So, I stripped the old material off and began investigating new materials.

A test-fitting with this material I found locally didn't look particularly great. Far too matte for my liking, the material just didn't fit the aesthetic the existing parts provided. Off to amazon I went, and I found some nice metallic false leather. While that shipped, I solidified the original joints of the wood frame with wood glue and Propel (to hold it in place)

With Mod Podge and Patience, I slowly reassembled the radio over a few days. The real challenge came with the side straps - the original radio had straps stretching from the feet to the handle, sewn down the perimeter, creating a nice border. This landed me in the possession of a sewing machine - something I'd never operated before, but I quickly fell in love with. Four tries later, I ended up with the final product I desired. A few trips to my local Lowes gave me the remaining hardware to complete the attachment with the handles and feet.

All that was left at this point was a back panel and detailing.

The back panel was cut using a jigsaw, sanded down to fit snug, stained for protection and color, and mounted using a single hinge and some magnets on the sides. Finally, I added a pull tab created from the same material as the body, attached with beautiful brass fittings.

Detailing included work on the inside to insulate, color coordinate, and reinforce the wiring connections, as well as a little something extra on the outside printed again using Shapeways.