Reimagining the Spirit Box: Part II
Fifty-seven words uttered in eight hours with nobody home: the first published baseline for a spirit box, and the math behind the three that mirrored my day.
Updated October 2026. The first version of this guide only worked some of the time. On a Pi Zero W the Bluetooth chip comes up late during boot, and the Raspberry Pi OS would sometimes skip starting Bluetooth entirely, causing the speaker not to connect. These updated steps fix the problem and speaker will now connect regardless of which device is powered on first.
This guide will walk you through setting up a sophisticated multi-layer audio signal generator that runs as a service on your Raspberry Pi and outputs sound to a Bluetooth speaker. The system includes four main components: an audio generator script, a connection service, a player service, and a systemd configuration to automatically run at startup. Once it's set up, power on the Pi and the speaker in any order and the audio will start on its own.
The setup consists of:
Before starting, you'll need:
You'll also need to install some packages:
sudo apt-get update
sudo apt-get install -y bluez bluez-alsa-utils alsa-utils python3-numpy python3-scipy
The Python libraries come from apt rather than pip. Bookworm blocks sudo pip3 install for system-wide packages.
Download the project files: [LINK]
The download is a zip file (uap_dogwhistle.zip) that contains:
uap3-generator.py - The audio generator scriptdogwhistle-link - The connection service scriptdogwhistle-player - The player service scriptdogwhistle-link.service and dogwhistle-player.service - The systemd service filesdogwhistle - The settings file (speaker address, audio file location, volume)main.conf (see Step 2)install.sh - Does all of Step 2 for youCopy the zip file to your Pi's home directory. From your computer (replace pi@raspberrypi.local with your Pi's username and address):
scp uap_dogwhistle.zip pi@raspberrypi.local:~
Then on the Pi, unzip it and open the folder:
unzip uap_dogwhistle.zip
cd ~/uap_dogwhistle
The quick way is to run the installer, which does everything in this step:
sudo bash install.sh
The services start right away, but they won't connect to anything until you pair your speaker (Step 3) and add its address (Step 4). If you run the installer again later, it keeps your existing settings file.
If you'd rather do it by hand, here's what it does.
If you followed the earlier version of this guide, turn off the old service:
sudo systemctl disable --now uap3-player.service
Turn off PipeWire. Raspberry Pi OS ships two Bluetooth audio systems, and if both are running they fight over the speaker. This setup uses BlueALSA only:
sudo systemctl --global mask pipewire.socket pipewire-pulse.socket pipewire.service pipewire-pulse.service wireplumber.service filter-chain.service
Move the scripts to /usr/local/bin and make them executable:
sudo install -m 755 pi/usr/local/bin/dogwhistle-link /usr/local/bin/
sudo install -m 755 pi/usr/local/bin/dogwhistle-player /usr/local/bin/
Move the service files to the systemd directory:
sudo install -m 644 pi/etc/systemd/system/dogwhistle-link.service /etc/systemd/system/
sudo install -m 644 pi/etc/systemd/system/dogwhistle-player.service /etc/systemd/system/
Install the Bluetooth fixes. The first override is the important one: it stops Raspberry Pi OS from skipping Bluetooth when the chip is slow to appear at boot. The second sets BlueALSA to send audio only, at a fixed 65% volume. main.conf makes the Pi respond faster when the speaker tries to reconnect:
sudo install -D -m 644 pi/etc/systemd/system/bluetooth.service.d/override.conf /etc/systemd/system/bluetooth.service.d/override.conf
sudo install -D -m 644 pi/etc/systemd/system/bluealsa.service.d/override.conf /etc/systemd/system/bluealsa.service.d/override.conf
sudo install -m 644 pi/etc/bluetooth/main.conf /etc/bluetooth/main.conf
Install the settings file and create the folder for the audio:
sudo install -m 644 pi/etc/default/dogwhistle /etc/default/dogwhistle
sudo mkdir -p /opt/uap-dogwhistle
Before the services will work, you need to pair your Bluetooth speaker. Put the speaker in pairing mode first.
Start Bluetooth control:
bluetoothctl
If it just says Waiting to connect to bluetoothd..., Bluetooth was skipped at boot (the bug this guide fixes). Exit with Ctrl+C, run sudo systemctl restart bluetooth, and try again.
Scan for devices:
scan on
When your speaker shows up, stop scanning:
scan off
Pair with your speaker (replace XX:XX:XX:XX:XX:XX with your speaker's MAC address):
pair XX:XX:XX:XX:XX:XX
Trust your speaker so it automatically connects:
trust XX:XX:XX:XX:XX:XX
Exit Bluetooth control:
exit
You don't need to connect here. The connection service handles that from now on.
Put your speaker's MAC address in the settings file:
sudo nano /etc/default/dogwhistle
SPEAKER_MAC=XX:XX:XX:XX:XX:XX
AUDIO_FILE=/opt/uap-dogwhistle/uap3_output.wav
VOLUME=65
The player runs as the user pi. If your username is different, change the User= line:
sudo nano /etc/systemd/system/dogwhistle-player.service
Run the audio generator script to create the WAV file (this may take some time on a Raspberry Pi):
cd /opt/uap-dogwhistle
sudo python3 ~/uap_dogwhistle/audio/uap3-generator.py
This will generate a 1-hour WAV file (uap3_output.wav, about 317 MB) in /opt/uap-dogwhistle.
Reload the systemd daemon to recognize the new services:
sudo systemctl daemon-reload
Enable the services to start automatically on boot:
sudo systemctl enable bluetooth bluealsa dogwhistle-link dogwhistle-player
Start (or restart) the services so they pick up your settings:
sudo systemctl restart bluetooth bluealsa
sudo systemctl restart dogwhistle-link dogwhistle-player
Check that the services are running:
systemctl status dogwhistle-link dogwhistle-player
View the logs to ensure everything is working, then turn on your speaker:
sudo journalctl -fu dogwhistle-link -u dogwhistle-player
You should see something like this:
speaker not connected: trying to connect
connected, audio ready
speaker ready: playing uap3_output.wav from the start
page-timeout in the log just means the speaker is off or out of range. The Pi keeps trying.
If you encounter issues:
Check that Bluetooth is running:
systemctl status bluetooth
Verify Bluetooth connection:
bluetoothctl info XX:XX:XX:XX:XX:XX
View detailed logs:
sudo journalctl -u dogwhistle-link -u dogwhistle-player -n 50
Test audio playback manually (stop the player first, and start it again when you're done):
sudo systemctl stop dogwhistle-player
aplay -D bluealsa:DEV=XX:XX:XX:XX:XX:XX,PROFILE=a2dp /opt/uap-dogwhistle/uap3_output.wav
sudo systemctl start dogwhistle-player
Check service status:
sudo systemctl status dogwhistle-link dogwhistle-player
If it's running on a battery, check for low voltage (throttled=0x0 means everything is fine):
vcgencmd get_throttled
If the speaker connects to your phone instead of the Pi, disconnect the phone. The speaker reconnects to whatever it was last connected to.
The generated audio contains six distinct layers:
To customize the audio parameters, you can modify the frequency values, amplitudes, or other parameters in the uap3-generator.py script. After making changes, regenerate the WAV file in /opt/uap-dogwhistle and restart the player:
sudo systemctl restart dogwhistle-player
The Pi sends the audio at a fixed 65% volume, and you set the loudness on the speaker itself. To change the Pi's level, edit VOLUME in /etc/default/dogwhistle and restart the player.