Tag: software defined radio

rtlsdr, Pd, linux


Today was able to get the rtlsdr~ object running in Pd on Ubuntu 14.04 on a Macbook pro.

Audio quality seems rough. The only driver I could get to work was Alsa at 44.1KHz – may be able to get help with this from Pd community.

Ended up using 64bit libraries for librtlsdr and libusb-1.0 . In fact, needed to using the shared (.so) libraries, not the static ones (.a) due to a weird linker error. Its possible that it happened due to mixing shared and static and I might try again using both static for these 2 libs.

See notes from previous post about issues with USB capture, and non-root user in Linux – there are 2 flags on the cmake for rtlsdr that might help resolve both of these, but I wasn’t having any luck and needed to use the method described in previous post.

The source code for linux version is in the /usr/lib/pd-extended/extra/rtlsdr~ folder – and the test pd file is in ~/pd/rtlSDR-block.pd, along with some abstractions.

There is also a makefile to build a local version of rtl_fm (rtl_fm3.c) in ~/rtl-sdr-new/rtl-sdr/rtl-fm3/

This makefile mixes the static and shared libs with no problem… hmm…?


Need to package this stuff up and send it to pdsdr github with source for Max/Pd on mac and Pd on linux. + instructions… etc.,

Would like to try running on r-pi – but will need to adapt the test patch to receive Osc messages because there is no gui on r-pi

Also I am some skeptical about running at low sample rates for audio – we’ll see…

another note

Just thinking, that even if I am not able to run rtlsdr~ on r-pi that we could adapt rtl_fm so it receives control input from Pd using Osc and work that way…


rtlsdr – Ubuntu installation

Notes for Ubuntu 14.04 LTS

Basic install:

1. use instructions at http://sdr.osmocom.org/trac/wiki/rtl-sdr

You will also need to install the following dependencies:

  • git
  • cmake
  • make
  • libusb-1.0
  • sox (optional)

Two issues:

  • rtlsdr device gets captured by OS, preventing application access
  • Standard installation process doesn’t allow non-root users to use a device

To prevent OS from capturing device…

Set up a blacklist file as explained in this post:


As the message suggests, there are two solutions.  The quickest is to
simply unload the driver:

sudo rmmod dvb_usb_rtl28xxu rtl2832

Not sure whether “rtl2832” on the end there is required or not, but it
can’t hurt.  This is only a temporary solution, as the driver will be
loaded again the next time you unplug and replug the USB device, so
you’ll have to run the command again.

If this works, and you don’t want to use the device for TV reception,
you can stop the module from ever being loaded, solving the problem
permanently.  The exact method depends on your Linux distribution, but
for me (running Arch Linux) I create a file in /etc/modprobe.d with
a .conf extension (I called it “no-rtl.conf”) with these contents:

blacklist dvb_usb_rtl28xxu
blacklist rtl2832
blacklist rtl2830

Again not sure whether it’s necessary to blacklist all three of these
or just the first, but I was erring on the side of caution and chose to
list everything to do with the Realtek DVB device.

Once you have created this blacklist file, you may need to unload the
driver one last time if it was already running – the blacklist
prevents it from loading but doesn’t do anything if it’s already

To allow non-root users to use the device…

Set up a udev rule as explained in this post:


Next, you need to add some udev rules to make the dongle available for the non-root users. First you want to find the vendor id and product id for your dongle.

The way I did this was to run:


The last line was the Realtek dongle:
Bus 001 Device 008: ID 0bda:2838 Realtek Semiconductor Corp.

The important parts are “0bda” (the vendor id) and “2838” (the product id).

Create a new file as root named /etc/udev/rules.d/20.rtlsdr.rules that contains the following line:

SUBSYSTEM==”usb”, ATTRS{idVendor}==”0bda”, ATTRS{idProduct}==”2838″, GROUP=”adm”, MODE=”0666″, SYMLINK+=”rtl_sdr”

With the vendor and product ids for your particular dongle. This should make the dongle accessible to any user in the adm group. and add a /dev/rtl_sdr symlink when the dongle is attached.

It’s probably a good idea to unplug the dongle, restart udev (sudo restart udev) and re-plug in the dongle at this point.




rtl-sdr: Pd, Max and Mac

Notes on compiling rtl_sdr in Mac OS – writing Max and Pd Externals.


update 3/31/2014

Today I got the Pd external running – using essentially same source code as Max. There is occasional weirdness going on with audio clicks when starting/stopping the radio, but other than that it seems fine and it runs. wooHOO. More to follow…


update 3/28/2014

Now have set up a skeleton for Pd, called rtlfmz~ (inside the Pd application bundle) which does absolutely nothing but compiles all of the project files and calls a function in rtl_fm.  Next step will be to port the actual Max external code and do the conversion.

updates 3/38/2014 before working on Pd version

There is now a fairly solid max external (rtlfmz~) using a recent version for rtl_fm. Also there is a simple Makefile that compiles local version of rtl_fm3.c in:


There are very minor changes to rtl_fm.c (for includes) and also a local version of librtlsdr.a (librtlsdr32.a) that is 32 bit.

The current state of the Max external does both pre-demodulated and raw IQ output, but you can only run one copy  of the object due to excess use of global variables and my uncertainty over how to run multiple devices, threading, etc.,  – but we’ll go with it an try porting to Pd now.

update 2/27 – converted to using new version of rtl_fm

I had been using an older version of rtl_fm –

renamed external to rtlfmz~ and now using new version as (rtl_fm3.c) in the project

In addition to recopying the librtlsdr.a – I also recopied all of the include files and added two new files

convenience.c convenience.h

There is a different method of threading and reading which I haven’t looked at yet, but it is now doing what it did before inside Max, which is read FM for a few seconds and write audio data to a file

plan: Set up a circular buffer accessible to the output thread and to the max perform function. – then see if we can get it to run for a few seconds.

The main thing to think about is how to let the processing happen in another thread while returning control to max. Then there really should be a way to interrupt processing from max.

There needs to be a max instance variable that tells whether the radio is running or not. Then, when its time to stop – you just do all the cleanup stuff that is at the end of the rtl_fm main() function.


update 2/18/2014 – Max external

Now have rtl_fm function within the plussztz~ external

It detects, opens device, demodulates about 30 seconds of FM, and writes audio at 44.1kHz. to a file /tmp/radio.bin – which can be played by the play command

Changes to code included:

  • removing exit calls
  • changing printf to post()
  • removing signal interrupt handling
remaining to do:
  • Need a way to get the device to read in the background – so its not blocking the Max thread
  • Need a way to stop/restrart the device – because if we aren’t, the continual sync_reads will waste a lot of cpu cycles.

update 2/15/2014 – Max external

Have now successfully  compiled a test external in Max 6.1.4 – name is plussztz~ and it includes the rtl_fm code.  Made 2 changes so far:

  • in build settings, set architectures to i386
  • in rtl_fm2, changed <include> libusb.h to “include” libusb.h

original post

Today I was able to write a simple makefile to compile the rtl_fm app using the libusb and librtlsdr dynamic libraries.

Pd requires i386 architecture for externals (i386) so I then compiled the app using static libraries and the i386 architecture.

libusb-1.0 already had a 32 bit version in /usr/local/lib/libusb32-1.0.a (note that this version also requires compiling these frameworks:

-framework foundation -framework iokit

For librtlsdr, I rebuilt, using cmake with the following flags:


But did not install the result. See this link for details on building with cmake: http://sdr.osmocom.org/trac/wiki/rtl-sdr

This produced a 32 bit static version of librtlsdr.a that could be used for building the app.

See this Stack Overflow post for more on cmake and architectures: http://stackoverflow.com/questions/5334095/cmake-multiarchitecture-compilation

local files:

currently local version of this test is in: tkzic/rtl-sdr-tz/rtl_fm2/

The default makefile builds the 32 bit architecture.


  • try to move the makefile into Xcode
  • try compiling rtl_sdr or rtl_fm as a simple max object – the fm app might be better to start with since it gives an audio signal output.
  • then try in pd




converting IQ audio files using sox

To get information about a file:

# sox --i 10meter96.wav

Input File : '10meter96.wav'
Channels : 2
Sample Rate : 96000
Precision : 16-bit
Duration : 00:00:16.50 = 1584387 samples ~ 1237.8 CDDA sectors
File Size : 6.34M
Bit Rate : 3.07M
Sample Encoding: 16-bit Signed Integer PCM


To convert the sample rate:

# sox 10meter96.wav -r 44100 10meter44.wav

More useful hints about sox by Selvaganeshan at “The Geek Stuff”


Here are the commands that worked to get the raw IQ data from rtl_sdr into Max

rtl_sdr -f 94900000 -s 1024000 -g 50 iq.raw

To convert the above to 96k 16bit wav format

sox -e unsigned-integer -r 1024k -t raw -b 8 -c 2 iq.raw -r 96k -b 16 iq.wav

Note: I could not get the above conversion to work with device sampling rates below 1024k. Didn’t try anything higher.



Notes on rtl-sdr source code – first impressions

I did a quick read of source code (rtl-fm.c) today.

Basically it opens an input stream of IQ samples from the rtl-sdr device, demodulates filters, and outputs audio.

Other than usual madness with threads and locking – the code is fairly straightforward. Not well commented – but clear enough that we could extract the input streaming and frequency (device) control to make a Max external. One question would be whether or not to do the downsampling in the external, or in Max?

Rough estimate would be this project would involve about 1-2 weeks of analysis and hacking. Possibly less – but there is a learning curve – and a heuristic stuff which is required to work with the hardware.

Fortunately it actually works in MacOS and Windows – and there are plenty of other examples to compare it to. But this is not a casual evening project.