Internet Radio, Radio Recorder, and MP3 Player With Smartphone Control.
by FlyingDrMike in Circuits > Raspberry Pi
6849 Views, 47 Favorites, 0 Comments
Internet Radio, Radio Recorder, and MP3 Player With Smartphone Control.
My objective here was to be able to listen to the 8am news over breakfast – without having to up at 8am. Hence the inclusion of the recording function. I have been enjoying the news every day for several months now, when I am ready to listen to it, and with just a couple of clicks. This project builds on my earlier Internet Radio/Music player project but is described here from scratch as I also improved my software installation process and used a digital audio board with simpler connections. The system can record any daily program, and could be easily modified for other radio recording requirements. The amplifier and speaker could be any of a large number of systems. In my case I had an old JBL Radial docking station doing nothing and so used the electronics in a bespoke enclosure that could be fitted under a kitchen cabinet. The sound quality is brilliant.
No physical controls are needed as it uses a web interface and smartphone control. It can also be linked into a home automation system as the control software is Node-Red that makes it easy to link network devices.
All the software is free. The recording function uses a program called Steamripper.
Steps:
- Connect hardware
- Initial Pi setup
- Install additional software
- Software Configuration
- Node-Red control
- JBL Dock Reassembly
Demonstration:
22/3/2021
From today the BBC has brought its internet streaming inhouse and is not making its internet radio urls available to the public. Hence the links in the stations.m3u file to BBC stations no longer work. I have contacted the BBC asking them to remove this restrictive change. Others, especially those who the BBC is mandated to serve, might consider doing the same.
However a visit to http://www.radiofeeds.co.uk might prove worthwhile.
Supplies
Hardware:
- Pi Zero
- PCM5102 audio board
- Wifi dongle plus OTG cable to connect
- Amplifier (JBL dock in this case)
Software:
- Raspbian Buster
- Node-Red
- MPC/MPD
- Streamripper
This project could use a Pi Zero W. However a Pi Zero plus Wi-Fi dongle is similar/lower cost and has more flexibility for aerial placement and better reception.
Connect Hardware
I decided to use a different digital audio board to my earlier HQ Audio project, still a PCM5102A. This is because this one is easier to wire up. A number of connections (settings) can be set via solder bridges on the board. The one I got had the default settings already set and I only had to bridge the link to set SCK to ground.
First solder the PCM5102 board links. There is one on the top side to link SCK to ground. We need the board to use its own clock and it will only do this is there is none on the SCK input. Then, if needed, close 3 of the four links on the bottom of the board to ‘L’ (1, 2, 4) – for FLT (normal filter), DMP (De-emphasis off) and FMT (format I2C). Link ‘3’ to ‘H’ - XMT (software mute off).
There are 5 leads to connect to the Pi. However if the amplifier is being driven from the same power supply (common ground) it is better to connect the ground on the PCM5102 board to the ground on the amplifier input in order to eliminate noise on the ground wiring. The connections are:
Board | Connect to | Pi | Function |
VCC | 5v | pin 2 or 4 | Power |
GND | GND | pin 6 or 14 | Ground |
LCK | GPIO19 | pin 35 | data word clock |
DIN | GPIO21 | pin 40 | data |
BCK | GPIO18 | pin 12 | data bit clock |
The amplifier choice is very much a personal preference. Most can be connected via a 3.5mm phono lead. I used a JBL On Stage dock during the development and then disassembled a JBL Radial dock for the final system.
I have included my approach in the last step.
Initial Pi Setup
The setup process runs the Pi remotely throughout – also called headless mode. This avoids the need to connect a keyboard/Mouse/screen.
Start by downloading the latest version on Raspbian from https://www.raspberrypi.org/downloads/. I used the lite version to avoid a load of stuff that will not be used here. Burn this onto a micro SD card using Etcher from https://www.balena.io/etcher/.
In order to run headless we need to add two files to ‘boot’ before putting the card into the Pi. The first is a blank file called SSH. This tells the Pi to enable SSH from start-up. The second file is needed to give the Wi-Fi details so the Pi can connect. This latter file is called wpa_supplicant.conf and is of the form:
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
network={
ssid="YOUR_NETWORK_NAME"
psk="YOUR_PASSWORD"
key_mgmt=WPA-PSK
}
Edit the YOUR_NETWORK_NAME and YOUR_PASSWORD and save to the ‘Boot’ part of the SD card as wpa_supplicant.conf
Plug the SD card into the Pi and power up. Wait a minute and then log onto your Wi-Fi router and look for the connected devices, and for device name raspberry pi. Note the IP address, typically of the form 192.168.0.xx.
Now we can log on. Use Putty from https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.htm. Enter the IP address and set port to 22. Now click ‘open’ and you should have the equivalent of the Pi terminal screen. Log on as ‘pi’ with password ‘raspberry’. Note that the text entry can be copied from here and pasted into Putty (right mouse click). This saves a load of time!
First revise the password and other settings via:
sudo raspi-config
(copy text then right click in Putty to paste)
First change the password
I then change the network name (optional)
Under localisation set the WiFi country.
Then right arrow twice and click 'Finish', and 'Yes' to reboot. This will lose the Putty connection. Rather than close this, wait a minute for the Pi to restart and the right click the Putty task bar and select ‘Restart Session’. Now log in using ‘pi’ and the new password.
Next update by entering:
sudo apt-get -y update
Then upgrade entering:
sudo apt-get -y upgrade
This can take a while.
We now have the initial Pi setup complete.
Install Additional Software
We need three packages: StreamRipper , MPD (music player), and Node-Red.
Stream ripper is the easiest. Enter into Putty:
sudo apt-get -y install streamripper
Now to MPD:
sudo apt-get -y install mpd mpc
‘mpc’ is Music Player Client that is needed both for test and to setup playlists.
We next need to setup directories for the music and playlists.
First I added a 'Music' directory in the home/pi folder. Then I added a ‘playlists’ directory and a ‘Record’ directory in the home/pi/Music folder. I used a FTP program - FileZilla (free) to do this remotely. This is also useful later to upload the radio playlist and music files. To use FileZilla enter the Pi IP address in Host, then username (pi) and password, and Port 22 and then click ‘Quickconnect’.
The playlists folder needs its permissions changing to save playlists. So using Putty enter:
chmod a+w /home/pi/Music/playlists
We need to tell mpd where to look for music and playlists. So, via Putty:
sudo nano /etc/mpd.conf
change the music directory line to read:
music_directory "/home/pi/Music"
and the playlist line to read:
playlist_directory "/home/pi/Music/playlists"
Save and exit (^X, Y, Enter).
Lastly load Node-Red. I have moved to a simpler and more reliable method to load Node-Red – following the approach at https://nodered.org/docs/hardware/raspberrypi . This uses a script and will install or upgrade Node-Red – so the approach is the same working from the full or lite versions of Raspbian Stretch. So enter:
bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)
Enter Y when prompted (twice).
This script also loads files needed to enable autostart of Node-Red.
At this point we have our Pi updated and loaded with the key software for this project.
Software Configuration
There is a bit of work to do here but we will take it in stages, testing as we go.
Audio setup
First we need to disable the on-board sound by editing alsa-blacklist.conf:
sudo nano /etc/modprobe.d/alsa-blacklist.conf
add:
blacklist snd_bcm2835
Save and exit (^X, Y, enter).
Now, to set the IO for the sound card, edit config.txt:
sudo nano /boot/config.txt
Add:
dtoverlay=hifiberry-dac
Remove or comment (#) the line:
dtparam=audio=on
Leave the line:
#dtparam=i2s=on
commented out.
Save and exit (^X, Y, enter).
Next add some alsa (sound) configuration:
sudo nano /etc/asound.conf
Paste the text below:
pcm.!default {
type hw
card 0
}
ctl.!default {
type hw
card 0
}
Save and exit (^X, Y, enter).
It is no harm to do a reboot. So:
sudo reboot
Restart the Putty session after a minute or so.
Test if everything is OK:
aplay -l
This should return:
**** List of PLAYBACK Hardware Devices ****
card 0: sndrpihifiberry [snd_rpi_hifiberry_dac], device 0: HifiBerry DAC HiFi pcm5102a-hifi-0 []
Subdevices: 1/1
Subdevice #0: subdevice #0
If you have an amplifier you can connect via a phono lead and test it via: speaker-test -D -c -twav So:
speaker-test -D default -c 2 -twav
This is a continuous test saying ‘front left’ and ‘front right’ alternately from the appropriate speakers.
Enter ^C to stop.
There are two options for volume control – software and hardware. At least one is needed. Here I plan to link to the up and down volume controls on the JBL dock and hence do not need the software option. For the software option see: High Quality Music Player and Internet radio
Also refer to the Instructable above for details on loading music and setting up playlists.
Internet Radio
For this we need a playlist of the stations. The playlist is simply a list of the station URLs, one per line. The URLs can be found by searching on ‘Internet Radio URLs’. I also checked these out on my Windows PC using VLC media player (Media>Open Network Stream). Notepad++ (free download) is a great editor to use as it includes line numbers. My playlist is attached and can be used as a starting point.
I saved the playlist (on my PC) as stations.m3u . I then used FileZilla to put a copy into the playlist folder on the Pi. See a copy of stations.m3u attached.
We can now test mpd. First we must reboot so mpd reads the playlists. So, via Putty:
sudo reboot
Then restart the Putty session and load the playlist via:
mpc clear
mpc load stations
The 'clear' instruction clears the ‘queue’/removes any previously loaded playlists.
Then play:
mpc play 1
‘play 1’plays the station in line 1 of station.m3u. Note that later we will be sending commands directly to MPD and it uses 0 for the first line. You should now hear your radio station (BBC Radio 1 if using my list).
mpc stop
stops the player.
Radio recording
The basic operation of Streamripper is the command:
streamripper ‘radio url’
This will record music tracks as individual mp3 files in the default directory.
There are a load of switches that can be used to tailor its behaviour. For a full list enter:
streamripper
In this case we want a single file for the duration of the news, called news.mp3 and placed in our Music/Record directory.
The url for BBC radio 1 is:
<a href="http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio1_mf_p"> http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radi...</a>
Say we want to record 5 minutes (300secs)
The command becomes:
streamripper <a href="http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio1_mf_p"> http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radi...</a> -a news.mp3 -d /home/pi/Music/Record -s -l 300
Run the above (enter into Putty) and when complete check a news.mp3 file has been created (look via FileZilla).
Also delete the ‘incomplete’ folder and the news.cue file.
MPD only works with playlists. So we need a playlist to play a single .mp3. So first get mpc to update its file of music:
mpc update
The playlist needs to be cleared before adding the contents of the Record folder:
mpc clear
mpc ls Record | mpc add
Then the playlist is saved by:
mpc save Record
Now test via:
mpc clear
mpc load Record
mpc play
This is a good test but we need to add some file management. Plus it is simpler to get Streamripper to send its output to a folder outside the Music directory and then copy the news.mp3 file over when the recording is done. Fortunately Node-Red can do all this for us. So use FileZilla to add a directory called ‘ripper’ to /home/pi/.
The next step pulls everything together using Node-Red.
Downloads
Node-Red Control
Node-Red is a great system and is supported by many programmers who have created nodes that can be added to deliver additional functionality. Here we will be adding nodes to help us with time, mpd, file management and user interface.
First we need to get Node-Red to start when the Pi starts. Enter via Putty:
sudo systemctl enable nodered.service
If you ever need to disable this enter:
sudo systemctl disable nodered.service
Now restart the Pi with:
sudo shutdown -r now
Node_Red is accessed via its web page on the Pi at ‘Pi IP address’:1880 . Enter this into a PC browser after the Pi has restarted.
The additional nodes are loaded via ’Manage Palette’ found via the ‘three horizontal lines’ icon top right. Select the install tab and enter ‘moment’. Look for ‘node-red-contrib-moment’ and click install. Next search for mpd and install ‘node-red-contrib-mpd’. Then search for ‘node-red-contrib-fs-ops’ and install. Lastly search for ‘dashboard’ and install ‘node-red-dashboard’.
So now all the pieces of the jigsaw are available – but were to start? Fortunately you can copy and paste my flows and you will be running – and then modify to your needs. Open NRrecord.txt in Notepad or equivalent. Select the contents and copy. Back in Node-Red select the ‘three horizontal lines’ icon top right, then 'Import' then 'Clipboard'. Now paste the flows and click 'Import'. The flows will appear. Then click the Deploy button (top right) to activate.
Note I have included a nice feature to hide the radio and music controls when they are not needed. This however only works properly with a single user interacting with Node-Red. If you want more than one user (which is fine) this needs to be disabled by deleting the wires from ShowHideRadio and ShowHideMusic to the Changetab node.
Also the Add Playlist node will need editing to match your playlists. For details see: High Quality Music Player and Internet radio
For interest the way I approached the development was to start with listing the system inputs, outputs and the functionality between them. One set of nodes is needed to manage the recording and update the news.mp3 file in the Music directory. Another, initially much simpler one, was needed to do the playback. The final option for the latter was to incorporate this into my Internet Radio and Music player interface.
For the recording the inputs are:
· Radio station
· Start time
· Duration
Outputs are:
· Command to run StreamRipper
· File management to update the news.mp3 file and delete old files and the ones not needed
I started with an inject node to send the Streamripper command entered earlier into an exec node and looked for the debug outputs – hoping there would be something useful sent at the end that could trigger the file updates. Got a 'code:0' at the end. Good.
Next I repeated the test but sending the files to the ‘ripper’ folder created earlier.
Then I moved to the user interface adding text and slider nodes from dashboard for the time and duration, and a drop-down box for the stations. For each of these we need the data stored so it can be assembled when needed to generate the instruction to drive Streamripper. This is done using flow.set(name, variable) instructions in a function node.
For the timing I used an inject node set to output every minute. This happens close to 0 seconds so we can be pretty close to the pips when recording the news. The timestamp is in UCT format and ignores timezone and the clocks changing for summer/winter time. This is where the moment node helps as it both deals with daylight saving and coverts the time to an object format that is easy to process. A function node can then compare the saved time to the actual time and then assemble and send the command to run Streamripper.
Lastly we have the file management that is kicked off by the code:0 output from completion of the exec command. This uses a couple of the fs-ops nodes. Initially I only set the delete node to delete the news.cue file. However I found that after a period of operation additional news files appeared, possibly from powering the system off while the recording is taking place. To address this I added a node to read all files in the directory. This also adds the ‘incomplete’ directory that cannot be deleted until it is empty. It seemed easier to leave this as the files there are overwritten. So a function mode was needed to remove this directory from the array before sending the array to the delete node.
The play system just sends the same 3 commands used earlier to test to the MPD node. I found a short delay was needed to ensure these were handled in the correct order.
While doing the development I was reflecting on the comment:
“Hardware eventually fails. Software eventually works.” So true!
Now connect an amplifier, log onto the user interface at ‘Pi IP address’:1880/ui and have a play.
Downloads
JBL Dock Reassembly
I had an old JBL Radial dock that was not being used and hence thought I would move the internals over to a new enclosure that would fit my revised purpose. This dock has tactile switches for volume up/down and would be easy to drive from the Pi (if connected to ground - confirmed OK later). Node-Red can drive the Pi GPIO pins. I could also keep the switches in case I wanted manual control later.
The JBL Radial does not come apart easily! However it helps when one is planning to discard the enclosure. The metal grilles are held in place with hot-melt glue so a hot air gun – preferable a lower power type (e.g. for applying heatshrink film) - helps. A hot air soldering gun might work. With the screens removed the screws that hold the main halves together are easily accessible. Then there is a load more hot-melt glue to soften to get into the base to extract the input circuit board and volume control switches. Eventually one can separate the electronics and make sure all still works. I left the speakers in place for as much as possible as the very strong magnets soon pull something you don’t want into the cones.
Next came the question of power supplies. The dock is 24v and the Pi 5v. One option was two supplies and use the Pi to turn the dock off when not in use (via a mains isolated switch). The alternative is to use a single 24v supply plus DC-DC converter to give 5v and use a MOSFET or similar to turn off the dock.
The system would be off more than on and the idle current of the 24v supply around double the 5v supply. Hence the idle current would less using two supplies and turning off the 24v supply when the system is not being used. Logic driven mains switches are available on ebay – but beware the one I got does not have the track separation distances for ‘double isolation’. Hence only use these if you understand the requirements for safe use.
If you're running the Raspberry Pi without a screen there's no need to power the display circuitry, and you can save a little power (25ma) by running /usr/bin/tvservice -o (-p to re-enable). Add the line to /etc/rc.local to disable HDMI on boot.
I made the enclosure from 9mm MDF board. I wanted to minimise the height for the under-cabinet location. This led me to mounting the woofer downwards plus making rebates in the top and bottom panels. I used a hole saw to make the holes for the smaller speakers and cut the woofer hole with a coping saw. I then made rebates for the speakers using a router carefully by hand.
I made speaker grilles from 3mm MDF. After epoxying screws in place I sprayed these black and then covered in speaker cloth.
See below the completed internals:
The plan is to finish the case in vinyl but we plan to change the kitchen units and hence will select the vinyl to match.