Probably one of the most important aspects of my PiCar radio project is the audio system. Not that I am an audiophile of any sort, but what’s the point in a radio that you can’t hear.
My Jeep JK has reasonable factory audio; I say reasonable, because I at the least I can hear the radio when the windows are open and my LS engine is cranking out torque.
It came with acceptable front and back speakers, tweeters and a subwoofer. (I removed the subwoofer early on for more trunk space). Replacing the stock radio necessitates that I keep some amount of parity with the stock system. This is before any consideration of upgrading the audio components.
That said, it clear that an important engineering goal for the PiCar project is to be able to drive multiple speakers. It would be nice also to take input from auxiliary devices like an iPhone or Sat radio.
Raspberry Pi Audio
Most Pi users are aware of its built in 3.5mm audio jack, but did you know that the Pi can easily be expanded to accept external audio devices and sound cards. This is made possible by the Advanced Linux Sound Architecture (ALSA) framework that ships with the Raspberry Pi OS. ALSA is a impressibly versatile system. It consists series of APIs that provide:
Ability to add sound cards.
Control which sound cards are selected
Control the mixing of sound
A common sound input and output API
And not that it is relevant to my project, but ALSA also has support for MIDI, sequencers and audio timing.
PiCar uses the ALSA api for sound output, but also to provide the features you would expect in a car radio: Control of volume, left-right balance and front-rear speaker fading. PiCar also uses ALSA to take input from an auxiliary jack.
The downside of ALSA is that the documentation is not great, but the good news is that lots of people recognize this are there are lots of helpful articles on the net as well as StackExchange Linux forums.
Pulse Code Modulation
Programming ALSA will require you to to have some familiarity with what Pulse-code modulation (PCM) is. Simply put, it is one of the most popular methods that computer use to modulate and demodulate sound to and from bits. Sound is encoded with a Digital to Analog converter (DAC) by taking a sample every so often. Depending on the level of resolution, DACs can have anywhere from 8 to 24 bits of precision. The intervals when you take the sample is called the sample rate. for example music on CDs are take at rate of 44,100 samples per second.
The PCM data is sometimes recorded on a file. One of the popular file formats for encoding PCM data is the .wav file. But in PiCar the PCM data comes from our Software Defined Radio (SDR) in realtime. It can also come from the AUX jack or an external source like an iPhone.
The conversion from bits to sound and back is typically done by a sound card. Quality can vary widely depending on which card you use.
Sound Cards
There are a huge variety of sound card that will work with ALSA. The built in sound hardware on the Raspberry Pi was only really designed to make beeps and minimal sound effects and has a number of problems related to popping and performance.
So if you are doing anything interesting yo will probably have to look into an external sound card. They come in two flavors: add-on boards and USB devices.
Here are a few that I have experimented with:
The Waveshare WM8960 Hi-Fi Sound Card. This is a really nice board for about $18 that plugs into your GPIO connector and communicates over GPIO using both I2S as well as I2C. It provides two speaker channels as and a built in set of MEMS microphones and It does require the installation of a driver, but Waveshare gives you good step by step instructions. WaveShare gives you the source code to the driver as well as the schematic and a user manual. The board also comes with a pair of mini-speakers, which was a nice touch.
I would have used the Waveshare card, but my application was already using the GPIO ports. I also needed more than two channels. and the built in microphones would be useless in the radio enclosure.
I decided to try an USB sound card. One of the really nice ones was the Signstek HiFi USB DAC. This device worked right out the box, and had awesome audio quality as well as solid packaging.
I didn’t experience any slowdown doing audio out of USB, but again this only had two channels and no audio in for the AUX jack. I considered using two of the devices and attempt to configure ALSA to mirror the channels, but people wiser than me suggested I would be better digging up a 4 channel card.
This lead me to the the VAlinks USB Card 6 Channel card. It included 6 channels, front/center/rear and a center/subwoofer option. What made this device especially attractive was that it include a LINE-IN as well as a microphone port. This made easy work of hooking up the AUX jack hardware. All for about $20.
The device worked with ALSA without installing any driver extra drivers. ALSA recognized it as a StarTech ICUSBAUDIO7D
card. I ultimately chose this card for the PiCar project.
I came across a few posts that helped with playing stereo on these multi port devices,
One thing to note about all of these cards, none of them really can drive automotive speakers. For that you need an amplifier of some sort. This was also true of the factory Jeep radio, which used an external amp. But this is not a hard problem to solve. You could choose to pickup a aftermarket automotive amplifier from someplace like Crutchfield.
At the very least you could pickup a cheap automotive the Wingoneer XH-M180 50Wx4 TDA7850 (Yes, I know the photo on Amazon is wrong)
ALSA Utilities
ALSA provides a number of utilities and the source code that make testing and configuring these devices a bit easier. I often use the alsamixer and amixer utility to select and adjust the sound cards. The speaker-test utility is also indispensable and worth spending some time with.
ALSA devices can also be configured to do a number of amazing things. The first thing you will probably need to do is setup ALSA so it picks your device as the preferred output.
Sound programming
There are a huge variety of APIs available for adding sound to your linux application. I found this post to be quite helpful. I chose to go use the ALSA API directly in my C++ code.
The API’s I ended up using fell into two categories: the PCM (digital audio) interface and the simple mixer interface .
You use the The PCM interface for sound I/O functions. These Programming ALSA looks a lot like Linux I/O you need to make an call to snd_pcm_open to open the sound device, and you setup the parameters like sound format, rate and number of channels using snd_pcm_set_params.
Once setup you can use the functions like snd_pcm_writei and snd_pcm_readi to so sound I/O. These functions are defined in the alsa/asoundlib.h
include file. These API’s work in blocks of data buffers called frames and periods. I recommend this article from linux journal to get your head around how to code ALSA I/O.
Volume and Balance
If you want adjust the volume of fool with mixing setting you use functions from alsa/mixer.h
include file. For example to adjust the output volume make calls to snd_mixer_selem_set_playback_volume and snd_mixer_selem_get_playback_volume.
ALSA doesn’t have any specific API for Left/Right and Front/Rear balance adjustment. You can however independently set the volume controls for any of the channels.
The solution to this was to calculate the speaker balance in code myself and setup the channel volumes as appropriate.
There is a little bit of magic involved in deciding if you are adjusting the volume in a linear manner or in logarithmically. You might wonder what is the fuss here. There is a lot of science to this. I found this post from Dr Lex very helpful.
By the way, I highly recommend you refresh you understanding of how decibels (dB) works. I really liked this video from Michael Ossmann.
My code is in a bit of flux, but most of PiCar’s sound I/O is implemented in the AudioOutput and AudioLineInput class. I will probably make some more improvements to handle replacing sound cards without having to update the code.
And there you have it. I have presented you some [sic] sound advice how you can use Raspberry Pi’s sound features. Have fun and be sure too make lots of noise.