Use rtl_fm and redsea to listen radio stations with RDS data...


Use rtl_fm and redsea to listen radio stations with RDS data...

This is more of a proof of concept, that you can use rtl_fm and redsea programs, to read RDS data and also listen the audio! I don't think, that many people will prefer this way to listen to radio stations :)

So, first install rtl_fm, by installing the package rtl-sdr. In Debian/Ubuntu systems use this command: sudo apt install rtl-sdr.

Then you have to install redsea, which is a command line program to parse RDS data, from rtl_fm data. Go to its Github repo and follow the instructions: https://github.com/windytan/redsea

Now you can use the script below to listen to your favorite radio station and also read any RDS text, at the same time, on the terminal!

You can and must configure the rtl_fm command line in the script, to match your system setup, as any RTLSDR device is different and needs different parameters, specially the PPM value.

And a small preview, nothing much...

rds

Da script...

#!/bin/bash

#title           :  rds.sh 
#description     :  Listen to radio and read RDS data, with rtl_fm and redsea
#author          :  xqtr // cp737.net
#date            :  2025/11/04
#version         :  1.0
#usage           :  sdr.sh <freq> // sdr.sh 103.5
#notes           :  Install rtl_dm and redsea // https://github.com/windytan/redsea

# Initialize variables
last_prog_type=""
last_partial_radiotext=""
last_partial_ps=""

if [ "$#" -ne 1 ]; then
    echo ""
    echo "Usage:"
    echo "  rds.sh <freq>"
    echo ""
    echo "Example:"
    echo "  rds.sh 103.5"
    echo ""
    exit 1
fi

clear

echo -e "\033[4;1H\033[2KPress Ctrl+C to stop"

# Use tee to split the rtl_fm output to both audio player and redsea
# Redirect rtl_fm stderr to /dev/null to hide startup messages
rtl_fm -M fm -l 0 -A std -p 0 -s 171k -g 20 -F 9 -f "$1"M 2>/dev/null | tee >(
    # Audio playback branch
    aplay -r 171k -f S16_LE -t raw -c 1 2>/dev/null || \
    play -r 171k -t raw -e signed-integer -b 16 -c 1 - 2>/dev/null
) >(
    # RDS decoding branch  
    redsea -r 171k -p | while IFS= read -r line; do
        [ -z "$line" ] && continue

        if ! echo "$line" | jq -e . >/dev/null 2>&1; then
            continue
        fi

        prog_type=$(echo "$line" | jq -r '.prog_type // empty')
        partial_radiotext=$(echo "$line" | jq -r '.partial_radiotext // empty')
        partial_ps=$(echo "$line" | jq -r '.partial_ps // empty')

        if [ -n "$prog_type" ]; then
            last_prog_type="$prog_type"
        fi

        if [ -n "$partial_radiotext" ]; then
            last_partial_radiotext="$partial_radiotext"
        fi

        if [ -n "$partial_ps" ]; then
            last_partial_ps="$partial_ps"
        fi

        output="\033[1;1H\033[2K"
        if [ -n "$last_prog_type" ]; then
            output="${output}: $last_prog_type"
        fi

        output="${output}\033[2;1H\033[2K"
        if [ -n "$last_partial_radiotext" ]; then
            output="${output}: $last_partial_radiotext"
        fi

        output="${output}\033[3;1H\033[2K"
        if [ -n "$last_partial_ps" ]; then
            output="${output}: $last_partial_ps"
        fi

        echo -e "$output"
    done
) >/dev/null

# Wait for background processes
wait

Add a comment

Previous Next