Intro to dsd
Today we’re going to use dsd
to decode DMR messages using a rtl-sdr dongle. The main point of this guide is to run everything on Mac OS, as there’re plenty of alternatives for Windows and Linux. I couldn’t really find a proper guide on how to set up everything on OSX, so here it is.
What is DMR?
Before we start, what exactly is DMR? Here’s a quote from an amazing online resource about it:
DMR stands for Digital Mobile Radio and uses the Motorola TRBO protocol for communications. Like other digital modes such as D-Star, C4FM and APCO P25, the TRBO protocol converts your voice into a digital form and sends it out via RF (with other bits of information included) and allows you to communicate to other DMR radios and also DMR repeaters, which are networked together around the world via the internet.
How to find one in the wild
You can generally find DMR signals on the following frequencies (EU):
- 441.0000 MHz
- 446.5000 MHz
- 446.0750 MHz
- 433.4500 MHz
- 145.7900 MHz
- 145.5100 MHz
Source: https://www.onesdr.com/dmr-frequency-list/
When scanning these frequencies it’s important to distinguish DMR signals from other digital and encrypted traffic. Here’s an audio example that I recorded of a DMR signal:
Decoding DMRs on MacOS
Now that you have your signal – what can we do to synthesise speech out of these digital signals. The answer – DSD. Let’s set it up
DSD setup
Go ahead and clone/download this repo: https://github.com/szechyjs/dsd. Jared has done an amazing job of creating this port, which works wonderfully under Unix systems.
Before proceeding with the setup, ensure that you’ve installed the pre-requisites. Link: https://github.com/szechyjs/dsd/wiki/Installation#dependency-installation-on-osx
At the time of writing they are listed as:
brew install git cmake libsndfile itpp portaudio
brew install --HEAD mbelib
Once you have the repo cloned follow the instructions he has provided here: https://github.com/szechyjs/dsd/wiki/Installation
Or TL;DR:
cd dsd
mkdir build && cd build
cmake .. && make
sudo make install
Once you’ve done that you should have access to the dsd
executable in your terminal. The help output is visualised below:

As you can see both dsd
and mbelib
are listed at the top with their versions, so we’re good to go.
DSD useful commands
I’ve included several flags here that are super useful.
dsd -h
– shows the complete help listing (the image above is trimmed)dsd -i pa:1 -o pa:2
– example startup with audio input on device #1 and output on device #2dsd -a
– show all audio devices. You should pick the ids for the above command from here
Audio routing
DSD works by audio ingression from a given source. You have several options on how you can set this up. I’ll go through a couple that I’ve tested and are working at the time of writing.
rtl_fm
If you have a compatible dongle you can use the rtl-sdr
lib package to pipe audio. Here’s some more info on that
- Wiki: https://osmocom.org/projects/rtl-sdr/wiki
- Source code: https://gitea.osmocom.org/sdr/rtl-sdr.git
I won’t go into setup instructions for this, follow the Readme. It’s a basic make-install chain.
Once you have that installed, check what rtl_
executables you have available:

The one we need to get dsd
running is rtl_fm
. Feel free to explore what the others do, each of them is amazing.
You can test the setup by running:
rtl_fm -f 155862500 -p 49 -s 48000 -g 25 -M fm test.txt
The output should be:

This command tells rtl_fm
to tune into 155.862 Mhz in FM mode with 48k sample rate, and to output to a test.txt file.
We’ll look into piping into dsd
and decoding in a bit
Alternative – VB Cable
VB Cable is a fairly old piece of software that links the output of a given service to the input of another. Figuratively creating a “cable” connection between the two. The setup on OSX is super simple, just follow the instructions here: https://vb-audio.com/Cable/
Once you have it installed, open the VBCable control panel and you’ll see this UI:

As you can see the link is operational and is awaiting input.
Now just use any sdr software to output to the VBCable. Examples:
SDR++

GQRX

Starting DSD with the audio pipe
No matter how you’ve decided to pipe audio into dsd
it’s time to actually set up the workflow. I’ll begin with the VBCable solutions as they are easier to setup and debug.
The VBCable way
Run dsd -a
to find the appropriate audio input and output devices. We’re looking for VBCable here for the input and your speakers/headphones as the output. Example:


You can see that the VBCable is on id 3 and my speakers are on id 1.
Running dsd
is as simple as:
dsd -i pa:3 -o pa:1 -v99
The in and out flags are clear, just make sure you prefix them with pa:xxx
. The -v
flag increases the verbosity of the output messages, the default is 0 (this is optional).
You should now see an output like this:

Now simply start your SDR software, make sure to pipe the audio out to the VBCable and start looking for those DMR signals.
The rtl_fm way
In certain ways starting up dsd
with the rtl_fm
util is easier. Here’s the command:
rtl_fm -f 1681187500 -p 49 -s 48000 -g 25 -M fm | dsd -i - -o pa:1 -v99
It’s the same rtl_fm
startup command as before, but we’re now piping the output to dsd
directly. When using -i -
it tells dsd
to use the piped in data as the input. The rest of it is straight forward – -o pa:1
is the output device and -v99
increases the verbosity of the output messages.

Decoding signals
Now that everything is up and running how do you actually decode signals? Well dsd
does this automatically. When you find an appropriate signal you’ll see a stream of messages in the output. If the signal is strong enough you’ll also hear voices.
Example of a partial decode in GQRX:
Example of a partial decode in SDR++:
Why do I say partial? You can see the percentage of invalid packets is rather high in both cases. Some invalid packets are okay, but 60-70% is too much. The dsd
service does recognise the signal as DMR and tries to decode it, even receiving data headers, but it’s missing too many frames.
You can do several things to try to fix this like:
- The signal is too weak, move the antenna, adjust the length (diapole), increase gain, add filters
- Try to switch over to WFM and play around with the bandwidth
- Use NFW but adjust the bandwidth to one of: 12500, 7000, 4000
Once I get a clear voice recording, I’ll update this guide.
As an example, here’s a video of when everything goes right.
The video is NOT mine!
Happy decoding!