ALSA LADSPA Plugin Chain For FM Transmission

From Nearline Storage
Jump to navigation Jump to search

I found a great tool for enhancing audio for FM transmission and adding RDS text to the signal, Stereo Tool. It's free to use the basic features but it costs $600+ to unlock all of the FM-related features if you want to use them. In the free version they have a beep tone that goes off every few seconds when you are using unlicensed features.

Turns out that it is possible to do similar enhancements using the LADSPA plugins in ALSA. As an example, here's the /etc/asound.conf that I use with my radio station Linux server, a Raspberry Pi using a cheap Behringer U-Control UCA 202 digital/analog converter. (Note the use of the hw:1,0 device for output, which corresponds to the USB DAC device.)

With this config you would direct output to the "radio" device to use the LAPDSPA plugin chain, .i.e., "aplay -D radio some.wav"

# Make USB DAC the default device
pcm.!default {
    type hw
    card 1
}
ctl.!default {
    type hw
    card 1
}

# LADSPA plugin chain for radio station processing
pcm.radio {
    type plug
    slave.pcm "ladspa"
    hint {
        show on
        description "in -> equal -> declip -> compressor -> limiter -> dmix -> out"
    }
}

#  LADSPA plugins:
#    "listplugins" to see the list of installed plugins
#    "analyseplugin <filename>" to see plugin controls
#    Use "ardour2" to experiment with plugin settings
pcm.ladspa {
    type ladspa
    slave.pcm dmixplug
    path "/usr/lib/ladspa"
    plugins {
        0 {
            # Equalizer - FM curve (approx, should cut at 19kHz, not 16)
            label Eq
            input {
                # 31 Hz, -48 to 24, default -30
                # 63 Hz, -48 to 24, default 0
                # 125 Hz, -48 to 24, default 0
                # 250 Hz, -48 to 24, default 0
                # 500 Hz, -48 to 24, default 0
                # 1 kHz, -48 to 24, default 0
                # 2 kHz, -48 to 24, default 0
                # 4 kHz, -48 to 24, default 0
                # 8 kHz, -48 to 24, default 0
                # 16 kHz, -48 to 24, default 0
                controls [ -30 0 0 0 0 0 0 0 0 -30 ]
            }
        }
        1 {
            # Expander - remove low-level noise/hiss
            label se4
            input {
                # RMS/peak, 0 to 1, default 0
                # Attack time (ms), 1.5 to 400, default 101.125
                # Release time (ms), 2 to 800, default 401
                # Threshold level (dB), -30 to 0, default 0
                # Ratio (1:n), 1 to 20, default 1
                # Knee radius (dB), 1 to 10, default 3.25
                # Attenuation (dB), -24 to 0, default 0
                controls [ 1 101.125 401 -26 10 3.25 0 ]
            }
        }
        2 {
            # Compressor
            label sc4
            input {
                # RMS/peak, 0 to 1, default 0
                # Attack time (ms), 1.5 to 400, default 101.125
                # Release time (ms), 2 to 800, default 401
                # Threshold level (dB), -30 to 0, default 0
                # Ratio (1:n), 1 to 20, default 1
                # Knee radius (dB), 1 to 10, default 3.25
                # Makeup gain (dB), 0 to 24, default 0
                controls [ 0.9 101.125 401 -10 2 3.25 0 ]
            }
        }
        3 {
            # Limiter
            label fastLookaheadLimiter
            input {
                # Input gain (dB), -20 to 20, default 0
                # Limit (dB), -20 to 0, default 0
                # Release time (s), 0.01 to 2, default 0.5075
                controls [ 10 0 0.8 ]
            }
        }
    }
}

# Rate converter set up, dmixplug acts as intermediary between LADSPA plugin 
# and dmix, which cannot connect directly
pcm.dmixplug {
    type plug
    slave.pcm dmixer
}
pcm.dmixer {
    type asym
    playback.pcm {
        # See plugin:dmix at http://www.alsa-project.org/alsa-doc/alsa-lib/pcm_plugins.html
        type dmix
        ipc_key 5678291
        ipc_key_add_uid true
        slave {
            pcm "hw:1,0"
            format S16_LE
            rate 44100
            channels 2
            buffer_size 5000000
        }
    }
    capture.pcm {
        type null
    }
}