BEAGLEBONE BLACK: NAVIGATING THE AUDIO MAZE
It is almost ironic that the quest for a “perfect audio appliance” which led us to the “simpler”, low power (the BBB consumes less than 5W) and light-weight world of embedded Linux, has also led us to the incredibly complex world of Linux audio.
Because of its long evolution, long list of requirements from both sound professionals and consumers, and open development environment, many audio subsystems have flourished, each having their own set of unique features, duplicating features from each other, providing interfaces to as many applications (even legacy applications) as possible and attempting to interfaces to each other.
Here is a depiction of Linux audio (circa 2008) [link]:
According to TuxRadar [link],
There’s a problem with the state of Linux audio, and it’s not that it doesn’t always work. The issue is that it’s overcomplicated. This soon becomes evident if you sit down with a piece of paper and try to draw the relationships between the technologies involved with taking audio from a music file to your speakers: the diagram soon turns into a plate of knotted spaghetti. This is a failure because there’s nothing intrinsically more complicated about audio than any other technology. It enters your Linux box at one point and leaves at another.
To and audio application, Linux audio provides several audio subsystems through which audio can be channeled: ALSA, PulseAudio, Jackd, OSS and others. An application can use anyone of these subsystems and in fact they do in order to provide wide appeal and compatibility.
Here is a very simplified and high diagram describing the different audio subsystems and their relationship [link]:
And application can literally take any route through the different components in order to arrive at the hardware. An application can use Alsa, routed through Jack and back to Alsa; or it can use PulseAudio to OSS or Alsa all the way. Audio applications such as MPD can use either ALSA, PureAudio or OSS in order to appeal to a wider audience and provide compatibility to new, old and in-between versions and flavors of Linux.
FOCUS ON ALSA
In our quest for bit-perfect audio, A reasonable approach to simplify the audio path is by minimizing the number of components through which the audio stream can possibly travel.
A practical way to do this is to direct the application to use a single audio subsystem. In our case, restricting to ALSA looks like a good option since it is already included in the Debian BBB release. (At least PulseAudio and Jack are are installed when installing MPD)
This site [link] also has a good overview of the different sound subsystems in Linux. A graphical description of ALSA is as follows:
The key message here is that ALSA looks like a “simple” interface between an audio application and the hardware and that there is a Mixer (Sound Mixing) outside the Kernel that CAN can potentially be bypassed. And indeed it can be bypassed:
A sound developer who wishes to output sound in their application can take any of the following routes with ALSA:
- Output using ALSA API directly to ALSA’s Kernel API (when sound mixing is disabled)
- Output using ALSA API to sound mixer, which outputs to ALSA’s Kernel API (when sound mixing is enabled)
- Output using OSS version 3 API directly to ALSA’s Kernel API
- Output using a wrapper API which outputs using any of the above 3 methods
A further simplification is to restrict the use of ALSA through the ALSA API (a more modern API) and avoid using the OSS v3 API (Legacy API). This may not be an issue as modern applications do not have a need to use the older OSS v3 interface.
MPD (MUSIC PLAYER DAEMON)
Since Volumio and RuneAudio are using MPD, It is a good idea to select MPD and figure out how it works. MPD simply runs in the background playing music from its playlist. Client programs communicate with MPD to manipulate playback, the playlist, and the database. [link]
Configuring MPD to use ALSA
The mpd configuration file is at /etc/mpd.conf. (The default configuration for mpd -as installed for debian, uses ALSA.)
The MPD documentation [link] indicates that it is capable of outputting to 15 plugins (ALSA, PulseAudio, OSS, etc). The configuration file allow the selection of the output plugin. Here is the example for selecting ALSA as the output of MPD:
To configure an audio output manually, add an audio_output
block to mpd.conf
:
audio_output { type "alsa" name "my ALSA device" device "hw:0" }
Further, the configuration allows us to disable and bypass any mixing/resampling of the audio data. I’ve highlighted in red the important parameters.
The following table lists the audio_output
options valid for all plugins:
Additional ALSA specific fields can be added according to this table (ALSA uses libasound)
Setting | Description |
---|---|
device NAME |
Sets the device which should be used. This can be any valid ALSA device name. The default value is “default”, which makes libasound choose a device. It is recommended to use a “hw” or “plughw” device, because otherwise, libasound automatically enables “dmix”, which has major disadvantages (fixed sample rate, poor resampler, …).Note: the default device can be set in the ALSA configuration file. The default device can be set to “hw” type and thus bypassing “dmix” the ALSA mixer. |
use_mmap yes|no |
If set to yes , then libasound will try to use memory mapped I/O. Here is an example using this parameter [link]: “yes” # Minor speed improvement, should work with all modern cards |
buffer_time US |
Sets the device’s buffer time in microseconds. Don’t change unless you know what you’re doing. Note: etc/mpd.conf states: MPD Internal Buffering: ****** This setting adjusts the size of internal decoded audio buffering. Changing this may have undesired effects. Don’t change this if you don’t know what you are doing: audio_buffer_size “2048”. ******This setting controls the percentage of the buffer which is filled before beginning to play. Increasing this reduces the chance of audio file skipping at the cost of increased time prior to audio playback: buffer_before_play “10%” |
period_time US |
Sets the device’s period time in microseconds. Don’t change unless you really know what you’re doing. |
auto_resample yes|no |
If set to no , then libasound will not attempt to resample, handing the responsibility over to MPD. It is recommended to let MPD resample (with libsamplerate), because ALSA is quite poor at doing so. |
auto_channels yes|no |
If set to no , then libasound will not attempt to convert between different channel numbers. |
auto_format yes|no |
If set to no , then libasound will not attempt to convert between different sample formats (16 bit, 24 bit, floating point, …). |
dsd_usb yes|no |
If set to yes , then DSD over USB according to the proposed standard by dCS and others is enabled. This wraps DSD samples in fake 24 bit PCM, and is understood by some DSD capable products, but may be harmful to other hardware. Therefore, the default is no and you can enable the option at your own risk. |
Thus in the MPD configuration we can:
- Specify ALSA as output plugin
- Specify that no mixer should be used in audio output plugin
- Specify that no volume adjustment be applied
- Further disable “dmix” the ALSA mixer (#2 may do the same thing. But you never know…)
- Further disable resampling in the output (dmix?)
- Optionally enable DSD over USB
Here is a guide on setting up MPD that will illustrate some of the parameters discussed above [link].
Configuring sample rate converter in MPD
Now that we’ve taken cared of the output plugin configuration, we need to ensure that other MPD plugins do not do sample rater conversion and/or mixing.
MPD can use one of the following sample rate converter:
- Internal (built in into MPD, low overhead, low quality)
- Sox (provided by libsoxr [link])
- Secret Rabbit Code (provided by libsamplerate [link])
Both libsoxr and libsamplerate can be compiled into MPD so they may be already available in the MPD package. After installing the package mpd in Debian/BBB further request for libsamplerate and libsoxr fails to locate these libraries, likely indicating that these have already been compiled into mpd (I am using “mpd” and “MPD” interchangeably).
SRC (libsamplerate) provides a small set of converters to allow quality to be traded off against computation cost. The current best converter provides a signal-to-noise ratio of 145dB with -3dB passband extending from DC to 96% of the theoretical best bandwidth for a given pair of input and output sample rates. [link] -The MPD documentation lists 97 db SNR [link]. Not sure how the two figures are related.
The MPD documentation says:
The setting samplerate_converter
controls how MPD shall resample music.
If MPD has been compiled with libsamplerate support, this setting specifies the sample rate converter to use. Possible values can be found in the mpd.conf man page or the libsamplerate documentation. By default, this is setting is disabled.
Possible values:
Value | Description |
---|---|
“internal “ |
The internal resampler. Low CPU usage, but very poor quality. |
“soxr very high “ |
Use libsoxr with “Very High Quality” setting. |
“soxr high ” or “soxr “ |
Use libsoxr with “High Quality” setting. |
“soxr medium “ |
Use libsoxr with “Medium Quality” setting. |
“soxr low “ |
Use libsoxr with “Low Quality” setting. |
“soxr quick “ |
Use libsoxr with “Quick” setting. |
“Best Sinc Interpolator ” or “0 “ |
libsamplerate: Band limited sinc interpolation, best quality, 97dB SNR, 96% BW. |
“Medium Sinc Interpolator ” or “1 “ |
libsamplerate: Band limited sinc interpolation, medium quality, 97dB SNR, 90% BW. |
“Fastest Sinc Interpolator ” or “2 “ |
libsamplerate: Band limited sinc interpolation, fastest, 97dB SNR, 80% BW. |
“ZOH Sinc Interpolator ” or “3 “ |
libsamplerate: Zero order hold interpolator, very fast, very poor quality with audible distortions. |
“Linear Interpolator ” or “4 “ |
libsamplerate: Linear interpolator, very fast, poor quality. |
It appears that there is no “off” setting, so that MPD will always attempt to resample audio in order to match the capabilities of the downstream components. There doesn’t seem to be a way to remove all the resamplers even by removing libsamplerate and libsoxr because there is always the internal resampler of MPD. In the case of the mpd package for debian, it is likely that libsamplerate and libsoxr have been compiled with mpd, so removal is not possible.
It is also reasonable to assume that if the “samplerate_converter” setting is not used in the config file (the default condition), a default sample rate conversion method would be applied.
We already have a way to disable “dmix” in ALSA which defaults to 48KHz, so there is no need for MPD to resample to 48KHz to meet the requirements of dmix. The only remaining sample rate requirement is the capability of the hardware. It is therefore reasonable to assume that if the hardware is capable to supporting the sample rate of the audio file, then no resampling would be performed.
CONFIGURING ALSA
According to these sites [link]. [link]
There are 3 configurations files that are read every time an ALSA device is opened:
- Default configuration file (comes with ALSA and should not be changed): /usr/share/alsa/alsa.conf
- System wide configuration file (optional): /etc/asound.conf
- User configuration file (optional, residing in the users home directory): $HOME/.asoundrc
There is no need to write a configuration file since the default is always present. However, for our purpose we want to ensure that the data is sent to device without any mixing or resampling by ALSA
Recall from the ALSA-specific settings above:
It is recommended to use a “hw” or “plughw” device, because otherwise, libasound
automatically enables “dmix”
Type=hw
Thus we wish to define a “hw” device. For our purpose we create a /etc/asound.conf file with the following entry:
pcm.!default { type hw card 0 }
The exclamation sign causes the previous definition of pcm.default to be overridden (so we don’t have to worry about the default configuration file /usr/share/alsa/alsa.conf).”card 0″ is the audio device we wish to use. It could be “card 1” or other. See below to determine what to use. “type hw” is used as recommended.
If sample rate conversion is needed, we can use the “plug” type
Type=plug
Use the following entry in /etc/asound.conf
pcm.!default { type plug slave.pcm { type hw card 0 } }
EXPLORING THE AUDIO COMPONENTS IN DEBIAN/BBB (KNOWN TO ALSA)
I used this guide [link] to explore and identify the different ALSA components in the Debian distribution for BBB
The presence of /proc/asound directory indicates that ALSA is present:
The file /proc/asound/cards tells you which sound cards are present in the system. Here is BBB without any external devices. It says there is a native sound device.
The file /proc/asound/devices tells you the features of the cards. The native sound device is an audio playback device.
The file /proc/asound/pcm gives us more detail on the “digital audio playback” (PCM). Here we find that the audio device is provided by the HDMI interface.
The simplest say to identify which cards are installed in the system is to use “aplay -l” [link]. This gives the same info as /proc/asound/cards and /proc/asound/pcm
Further information on the device capabilities can be obtained from the file /proc/asound/card0/pcm0p/sub0/hw_params. It requires that a track is being played. Notice we use “card0” because the card has been identified as “card0”
alsacap
alsacap serves to list the sampling rates, number of channels and sample formats supported by installed sound cards and their ALSA drivers. This helps to find out which parameters do not require resampling (something to be avoided) and to troubleshoot ALSA problems [link]
However, the tool is only available as source so it needs to be compiled. Here is a sample output from here [link]
$ alsacap *** Scanning for playback devices *** Card 0, ID `SB', name `HDA ATI SB' Device 0, ID `VT1818S Analog', name `VT1818S Analog', 1 subdevices (1 available) 2..8 channels, sampling rate 44100..192000 Hz Sample formats: S16_LE, S32_LE Subdevice 0, name `subdevice #0' Device 1, ID `VT1818S Digital', name `VT1818S Digital', 1 subdevices (1 available) 2 channels, sampling rate 44100..192000 Hz Sample formats: S16_LE, S32_LE Subdevice 0, name `subdevice #0'
ADDING A USB AUDIO DEVICE
Unlike a PC, a reboot is required for the system to detect the presence of a USB audio device.
After connecting a TI PCM270x-based device (USB 1.1)
After connecting DIYINHK XMOS-based device (USB 2.0)
After connecting AMANERO board (USB2.0)
As can be seen, these cards are all automatically recognized by BBB.
ENABLING I2S OUTPUT
diyaudio’s MIERO has developed a driver to enable I2S output in the BBB [link].
It requires that the HDMI output be disabled (since it shares the same lines with Audio I2S). In my installation, the line to disable HDMI is already there as a comment, so I just had to un-comment it and reboot.
With HDMI disabled (and no other device in the USB port) -no sound cards detected:
Here are the instructions (copied from the site) to download and install the I2S driver for BBB/Debian. You can just copy each line and paste it in the PuTTY windows (paste by clicking the right mouse button.
download and extract driver wget http://bbb.ieero.com/botic_driver_v3.tar.gz tar xvzf botic_driver_v3.tar.gz install driver (assumes official BBB Debian release) cp -av botic_driver/firmware /lib/ cp -av botic_driver/modules.bbbdebian/* /lib/modules/ update module dependencies depmod -a load driver (Needed after every boot) echo BB-BONE-BOTIC1 > /sys/devices/bone_capemgr.*/slots There are 3 configurations for the driver BB-BONE-BOTIC1 - this is for BBB without cape - onboard clock (48fs rates only) BB-BONE-BOTIC2 - onboard clock (48fs rates) - external clock (44k1fs rates) - external clock switch on UART1_TXD (pin configurable via DT) BB-BONE-BOTIC3 - external clock (48fs rates) - external clock (44k1fs rates) - external clock switch on UART1_TXD (pin configurable via DT)
aplay -l shows the following
The I2S pins are the following:
TESTING WITH APLAY
Rather than testing with MPD which might invoke its resampler by default, we will use aplay (alsa player) which does not have a resampler of its own. It is a lightweight player for alsa.
I compiled a collection of tracks from 44KHz to 384KHz
Type=hw: bypassing the mixer
The entry in /etc/asound.conf is as follows:
pcm.!default { type hw card 0 }
Using this configuration requires that the source file matches both the bit depth and sample rate supported by the hardware. For example, if using the BOTIC driver (which enables I2S output) which is set as 32bit device, you cannot play 16bit nor 24bit files. The error message indicates that only “S32_LE” (Signed 32 bit Little Endian) is supported:
Type=plug, enabling the ALSA mixer
The entry in /etc/asound.conf is as follows:
pcm.!default { type plug slave.pcm { type hw card 0 } }
The result is that “dmix”, the alsa mixer is invoked. With a reputation of being bad, hopefully it does fine with bit-stuffing (e.g., converting 16 bit to 32 bit by appending zeros)
Testing the BOTIC driver we obtain the following results:
Playing a 44.1KHz file. We expect conversion to 48KHz because the native I2S in BBB only supports 48KHz and its family of sample rates. And indeed, this is what we find. The first screen shows playing the 44K file; the second screen shows the contents of /proc/asound/card0/pcm0p/sub0/hw_params showing that it is outputting 32-bit 48KHz. Thus we see dmix in action, doing sample rate convertion
Playing a 192KHz. We expect no sample rate conversion as this is natively supported by the BBB, but dmix will convert from 24 bit to 32 bit. Indeed, this is what we find. The first screen shows playing the 192K file; the second screen shows the contents of /proc/asound/card0/pcm0p/sub0/hw_params showing that it is outputting 32-bit 192KHz. We hope that dmix is just bit-stuffing…
If playing 176KHz, ALSA resamples to 192KHz.
REFERENCES
- Automating the mpd configuration process for bit-perfect audio: [link]
- Must read: bit-perfect audio in Linux: [link]
- An example configuration for MPD and ALSA [link]
Leave a comment Cancel reply
Recent Posts
- 10-Year old SMPS design still an excellent performer
- New Review and In-Depth Analysis of Hypex UCD-180HG
- Alpair 12p In Cabinets
- Firmware v 0.99
- Soekris DAC: Modding VRef
- R2R DAC Benchmark Filters (for now)
- dam 1021 R2R More Mods…
- Digital Filters for Soekris R-2R DAC
- Soekris dam 1021 R-2R DAC ILLUSTRATED GUIDE
- BBB DAC DEVELOPMENTS
- dam1021 R-2R DAC MODs
- Soekris dam1021 Build
- Raspberry Pi 2
- The Soekris R-2R DAC: Technical Details
- INSIDE MARANTZ AV RECEIVER
Latest Comments
Arduino
Theory
- Choosing and Using Bypass Caps
- Complete List of Linear Tech Application Notes
- Decoupling, Bypassing, Layout
- FIR Filter Tutorial
- Grounding Data Converters
- Intro to FIR Digital Filters
- Intuitive Guide to Principles of Communications
- Rakon Jitter Whitepaper
- Reduce EMI, RFI
- Successful PCB grounding with mixed-signal chips
- The Scientist and Engineer's Guide to Digital Signal Processing
- Tutorials and other Resources
- USB Power
Tools for DIYaudio
- % to dB Calculator
- Audio Equipment Database
- Best Solder
- Circuit simulation
- Generate DSD128 and DSD256
- Hex<->Binary<->Decimal Converter
- IC Manufacturer's LOGOs
- Inductor markings
- Inside Audio Equipment
- Jitter Calculator
- LOTs of Calculators
- Schematics
- Service Manuals
- SMD Codebook
- SMD Marking Code Search
- SMD Markings
- Tantalum Capacitor Markings
Excellent thanks, although I do start to wonder if it’s really worth it, everything seems so fragmented and possibly a step backwards, at least at this stage.
I share your feelings. At a point it was frustrating looking at the overwhelming amount of information all over the place. But once I was able to have a bit of understanding and then finally capable of enabling and disabling the low level mixer (dmix), it was worth the learning experience.
I do believe that collectively, this would result in a step forward. At the minimum it is an order of magnitude cheaper than a computer 🙂
People seems to be a bit impatient in getting this to work. I hope it will take a while. It would be more fun 🙂
Thanks for this! Do you know if there has been any considerable changes since 2014?
I can wait, by the time I finish the things I’m building for my sister this will be a commercial product :). I resisted the urge to jump in so at this stage I’m just watching and learning. Unfortunately I don’t have the patients & stamina to do the research you do.
Another fantastic post! This syncs up perfectly with I’ve been trying to do with my Beaglebone https://twitter.com/foundatron/status/429279220603166720
Curious. Have you seen or used mpd-configure? https://github.com/ronalde/mpd-configure It’s a great commandline tool for configuring mpd. If nothing else, going through ronalde’s code really helped me understand how and what needs to be configured in alsa and mpd.
Thanks for the tip. I haven’t come across this reference. There is so much information out there….
This is very good info. Especially the articles from “la cocina…”
Thanks to the author for writing this elaborate page and to all for the compliments regarding my articles and scripts.
I would like to point interested readers at the major improvements I made to the https://github.com/ronalde/mpd-configure/blob/master/mpd-configure script in the last few days.
I also created a new script https://github.com/ronalde/mpd-configure/blob/master/tests/detect-alsa-output-capabilities.sh which serves as a more or less portable and modern replacement for `caps.c`. Since today, the detection and selection mechanisms of this new script are now incorporated into `mpd-configure`.
See the accompanying article at http://lacocina.nl/detect-alsa-output-capabilities for some background and sample outputs.
Kind regards,
Ronald
Certainly deserved.
Hi, I thought I let you I recently made quit a few enhancements to both scripts.
Besides the encoding formats, alsa-capabilities is now able to show the sample rates an audio interface supports. Run it directly from the web using:
bash <(wget -q -O – "http://lacocina.nl/alsa-capabilities"😉 -s
mpd-configure now supports command line switches. The following example creates a valid /etc/mpd.conf (while backing up the original) configured to use the first available USB DAC without any questions asked:
CONF_MPD_MUSICDIR="/srv/media/music" CONF_MPD_HOMEDIR="/var/lib/mpd" \
bash mpd-configure -l u -n -o "/etc/mpd.conf"
Regards,
Ronald
Unfortunately, my post was automatically ‘enhanced’, replacing the last doublequote and single closing bracket by a blinking smiley: “)
vitamin c serum for face
nawigacje samochodowe sklep
conmanai dgrasdd
france inverse