Chill out to some Lo-Fi beats with this Raspberry-Pi powered speaker! It can stream music directly from YouTube playlists. A tone knob on the front allows you to fade between two equaliser presets, while a button is used to pause and skip tracks.
I based the visual design of the speaker on La Wood Television (New Zealand) Ltd's “Lara” radio.
Please note that I don't know the first thing about speaker enclosure design, so don't expect the sound quality to be world class. Consider it to be a lo-fi aesthetic :). In particular you shouldn't expect thumping bass out of this thing.
I modelled this in Fusion 360, then added the wood texture to the model in Blender using Carvature.
Print the speaker enclosure (Body, Cover and Lid) in Wood PLA (I used Kiwi3D Cherry PLA) at 0.2mm layer height, 2 perimeters, 13% rectilinear infill.
Don't print these three simultaneously, because you'll end up with lots of stringing connecting the different parts.
Be sure to enable the brim when printing the Cover and Lid, since they're pretty tall and skinny and could fall over otherwise.
This is how my print looked straight off the printer:
Just a wee bit of stringing, I probably should have dried my filament out more!
To clean this up, pull out the worst of it out with your hands, then use a craft knife to cut out the strings that are bridging the holes in the enclosure, especially around the USB ports. I hit what was left on the inside with the briefest of blasts from a keychain butane torch, which causes them to vaporise or shrivel up, and be easily rubbed off the surface. The outside surface will be sanded anyway, so don't worry about those so much.
Sand all the outside surfaces ALONG the wood grain lines (horizontally), using 80 grit sandpaper. Take care not to sand across the grain (vertically). This removes the stringing and any other bumps and unevenness. Any scratches added by the sandpaper will just enhance the wood grain effect.
Here's what mine looked like after cleanup and sanding, you can see how the sandpaper has only really knocked down the highest spots, which is good, we don't want to remove all the wood texture!
The Lid and Cover pieces need to be treated the same way. Note that when sanding the Cover, the bars that run across it are a little fragile. When you're sanding in-between the bars, pinch the one you're sanding between your thumb and forefinger to hold it in place and stop it from being deflected too much by the sandpaper.
Finally, paint on your wood stain with any old paintbrush (I used a 1-inch synthetic cheapie) and allow it to dry according to your stain's directions. Adding additional coats will darken the stain, if you like. You don't need to stain the inside of the enclosure.
Screw four M2.5x10mm screws into the four screwholes on the bottom side of the Lid, but don't screw them in quite all the way (leave a couple of mm). The top of the screwhead should protrude at least 6mm from the surface. There is some room for adjustment here so that the screws can easily slip into the keyholes in the top of the Body piece, and the Lid can slide forwards to lock itself in place. This is what that looks like in cross-section:
The front panel is two pieces, the Outline, which forms a black border around the piece, and the Body. To slice this, load the Front Panel.stl, then right click it and click Add Part > Load, then select the Front Panel - Outline.stl. Use the Place on Face tool to put outline ring face-down on the printbed, like so:
Set layer height to 0.2mm.
On your Printer Settings tab, bump the number of extruders up to 2. On the Custom GCode page of that tab, set the Tool Change G-code to M600. On the Print Settings tab, go to the Multiple Extruders page and untick “Wipe Tower > Enable”.
I set my Bottom Fill Pattern on the Infill page to Hilbert Curve to give my front panel a fancy look.
On the Advanced page, set Elephant Foot Compensation to 0, since this otherwise trims off the outer edge of the frame.
On the Plater tab, right click the Outline STL and assign it to Extruder 2.
When you print this model, the printer will pause at the start of the print for you to load the filament for the main body of the front panel, I used Silver PLA. It'll print the silver parts, then it'll pause and have you switch over to the Black PLA to print the outline. Finally, it'll have you switch one final time back to Silver to complete the print.
You can answer the prompt on the printer (was filament change successful?) with “no” to have the printer do an extra purge for you between colours, which is useful for getting rid of the last remnants of the black filament.
You can supply your own knobs, or print the ones that I've included at 0.2mm layer height (but getting them to fit well on the shaft is a bit tricky).
These are multi-colour prints just like the Front Panel. This time I've used this technique to print the main body in black, and inset a silver top on the top of the knob, with the top infill pattern set to Concentric.
Install "Raspberry Pi OS Lite" on your MicroSD card (not the “Desktop” or “Full” version), using the Raspberry Pi Imager:
https://www.raspberrypi.com/software/
Use the Advanced Settings button in that tool to set the hostname, configure your WiFi connection settings, enable SSH access, and set the password for your “pi” account.
Put that card into your Pi and boot it up. Note that it's fine to boot the Pi connected to the X400 now without connecting anything else yet, but don't connect power to the Pi by USB if you're doing that (the X400 doesn't tolerate being backfed power).
Connect to the Pi by SSH using the credentials you entered (eg “ssh [email protected]”), and run these commands to install the pre-requisites and my lofipi-mpv package:
sudo apt install --no-install-recommends nodejs libasound2-plugin-equal pigpio mpv youtube-dl
wget https://github.com/thenickdude/lofipi-mpv/releases/download/v1.1.0-0/lofipi-mpv_1.1.0-0.bullseye0_armhf.deb
sudo dpkg -i lofipi-mpv_1.1.0-0.bullseye0_armhf.deb
We now need to configure the Pi to send audio to the X400, equalise it, and downmix it to mono.
Edit /boot/config.txt (e.g. with sudo nano /boot/config.txt
) and add these lines to the bottom:
[all]
# Output to X400 audio hat, disable HDMI audio
hdmi_ignore_edid_audio=1
dtoverlay=iqaudio-dacplus,unmute_amp
Further up in that file, find these lines:
# Enable audio (loads snd_bcm2835)
dtparam=audio=on
And comment out the dtparam line by adding a # in front like so to disable the onboard Pi headphone port:
# Enable audio (loads snd_bcm2835)
# dtparam=audio=on
Add a new alsa config file (sudo nano /etc/asound.conf
) with this content:
# Card 0 is: vc4hdmi [vc4-hdmi]
# Card 1 is the one we want to use the X400: IQaudIODAC [IQaudIODAC]
defaults.pcm.card 1
defaults.ctl.card 1
pcm.!default {
type plug;
# Downmix to mono:
ttable {
0.0 0.5 # in-channel 0, out-channel 0, 50% volume
1.0 0.5 # in-channel 1, out-channel 0, 50% volume
}
slave.pcm plugequal;
}
pcm.plugequal {
type equal;
channels 1;
slave.pcm "plughw:1,0";
}
ctl.equal {
type equal;
channels 1;
}
Now reboot your pi to check it all went well and the system still boots (sudo reboot
).
For more diagnostics, you can run “aplay -l” (that's a lowercase letter ‘L’) to check that IQaudIODAC appears as card 1:
$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: vc4hdmi [vc4-hdmi], device 0: MAI PCM i2s-hifi-0 [MAI PCM i2s-hifi-0]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 1: IQaudIODAC [IQaudIODAC], device 0: IQaudIO DAC HiFi pcm512x-hifi-0 [IQaudIO DAC HiFi pcm512x-hifi-0]
Subdevices: 1/1
Subdevice #0: subdevice #0
And if you have the speaker hooked up already you can test playback like so:
$ sudo service stop lofipi-mpv
$ aplay /usr/share/sounds/alsa/Front_Center.wav
Finally you can shut down the Pi:
$ sudo shutdown -h now
De-solder the volume potentiometer from the X400 so that you can relocate it to the front panel of the enclosure. I covered up some nearby SMD components with some tape to make sure I didn't accidentally remove them, then I added a little lead solder to the existing solder on the pins, and used a manual solder-sucker to clear the solder:
Connect the potentiometer back to where it was connected on the PCB using some short wires, or maybe add a connector to the PCB if you have one (I didn't), the pin spacing is 0.2". Take care not to swap the order of the wires, because otherwise turning the pot counter-clockwise will increase the volume instead of decreasing it (I nearly blew my socks off!)
Unplug the “mute” jumper on the X400 (this will mute the amp until the OS enables it, which avoids a big thump sound upon poweron).
Wire up the second “tone” potentiometer, pushbutton, and Noctua fan with the other electronic components as shown in this diagram (full size):
Please mind the orientation of the electrolytic capacitor, the negative stripe must be connected to the GND pin.
Only one side of the tone pot and the centre (wiper) pin will be used, one pin will be unused.
The pinout of the GPIO connector on the X400 is documented here, it differs a little from the one directly on the Pi:
https://wiki.geekworm.com/X400_V3.0
The colour-codes of the wires of the Noctua fan are listed here:
https://noctua.at/en/what-pin-configuration-do-noctua-products-use
I used a crimping tool to make one 5-pin Dupont-style connector for the pins on the left side of the GPIO connector (one position unpopulated), and I cut off the Noctua's included connector and made one 3-pin connector for it on the pins on the right side. The RPM wire on the fan is not needed.
On the NPN transistor the Emitter connects to Ground, the Collector to the PWM signal wire of the fan, and the Base connects via the resistor to the GPIO pin on the X400/Pi. This transistor protects the Pi against the 5V pull-up inside the fan (since the Pi's GPIOs are only 3.3V-tolerant).
Add the Front Panel printed part to the front of the enclosure, it will be secured in place by the nuts of the potentiometers and the button.
Insert the two potentiometers and the pushbutton into the front panel from behind and secure them with their included nuts (if yours didn't come with nuts, I've included a printable version which you can print at 0.1mm layer height).
For the potentiometers, have their contacts pointing directly upwards, which should align them so that their anti-twist lug slips into the slot in the face. You may need to trim the contact pins for clearance with the speaker (I trimmed them flush).
Plug the X400 tophat onto the Raspberry Pi using the standoffs and screws that are included with it, but only add screws in from the top. Screw two speaker wires into the Left speaker terminals on the X400 (those are the two terminals closest to the edge of the board, they're labelled on the back side of the PCB) while you still have good access to them.
Slip the Pi into its final resting place atop the standoffs at the bottom of the enclosure, and screw it in from underneath using the M2.5x14mm screws. Take care not to snap off the microSD card against the tone potentiometer (they can easily collide).
Screw in the Noctua fan using M2.5x14mm screws from the outside of the enclosure and M2.5 hex nuts on the other side. Orientation is not critical, but I like mine with the label facing outwards so that the fan acts as an exhaust fan. I only managed to reach the two topmost mounting screwholes, and left the bottom two unpopulated, lol, there is probably a better mounting design possible here.
Now you can plug in the front panel and fan connectors to the Pi, and solder the speaker wires to the terminals of the speaker. Drop the speaker into the front panel from the front (I oriented it with the terminals facing to the side so they were more out of the way) and secure it from the front with the M3x6mm button-head screws. These screws just screw directly into the plastic and cut their own threads. If you end up stripping out these holes, you can replace these screws with longer ones and add M3 hex nuts on the inside instead.
Finally, slide the Cover downwards from the top of the case. If you can't push it down easily, there is probably crud stuck in the channels in the body, chisel, cut or sand that out. In future if you want to remove this cover, be sure to push it upwards from the base instead of pulling it from the top, or you will break it.
Lofipi starts streaming music from YouTube (by default, from this playlist) as soon as it finishes booting. For your first powerup, be sure to turn the volume knob down to a reasonable level!
You can press the button to pause and resume the music. Hold down the button for 400ms to skip to the next track.
You can change which playlist or video will be played by editing the config file (sudo nano /etc/lofipi-mpv.conf
). This file starts out empty, but these are the default settings that will be applied:
https://github.com/thenickdude/lofipi-mpv/blob/master/default.conf
You can override any one of those by adding lines to your lofipi-mpv.conf, for example:
fan_speed=0.25
play_url=https://www.youtube.com/watch?v=dQw4w9WgXcQ
On your first powerup, Lofipi needs to learn the range of your tone knob, so sweep it from full-left to full-right. After that the tone knob should behave normally.
My original design for this speaker was for it to be fully offline, and play infinite lo-fi hiphop thanks to the algorithmically-generated beats of Dylan Turner's lofigenerator.com. This is great because you don't even need wifi, you just plug in power and it starts playing.
This website is too slow to run on the Pi 3B+, it takes about 3 minutes to render 1 minute of audio. But it only takes advantage of a single core. So I ported his algorithm to run in Node.js instead, where I can use Node's worker threads to render 4 songs in parallel on the Pi's 4 cores. This allows the Pi to render faster than realtime, and so after an initial loading period it can stream music continuously. And it caches tracks on disk so that on the next powerup it can begin playing immediately without having to wait for a song to generate.
I added the fan to the lofipi specifically to support this usecase, because when all 4 cores are maxed out the Pi hits 80 degrees and throttles quickly, while the amplifier and Pi PCBs also heat up to alarming temperatures via conduction (even the USB ports get hot). 50% fanspeed is enough to keep the CPU temperature down to a cool 60 degrees under this workload. Under a single-core workload (like lofipi-mpv) the fan is not really needed, and 25% fan is already more than necessary.
I got this working wonderfully. However lofigenerator.com is not open source, so I can't redistribute my version of that project.
I am sharing the patches I made to various projects to get that working on the Pi, though:
The author hasn't provided the model origin yet.