Using hamlib to poll frequency data with Max/MSP

This Max patch connects to a radio transceiver and reads the frequency data using hamlib. Hamlib provides a common API for amateur radio devices. The hamllib server runs in the background using TCP/IP. This patch uses Jeremy Bernstein’s shell object. and the Sadam Library of externals, installed with the Max package manager.


hamlibtcptest1.maxpat : select radio, starts rigcltd dameon, poll frequency via tcp/ip : shell script to run rigctld


Max: Jeremy Bernstein’s shell external, and the sadam library from Max package manager.

hamlib can be installed using homebrew


There is some latency when using the Elecraft K4. Need to look into the internal CAT settings.

Also, look into communication latency of TCP/IP and associated libraries.

I’m exploring a version of this that uses node.js instead of the shell external and tcp/ip library in Max. Initial problem is that the rigctld daemon stays active after Max is closed and needs to get killed manually.

Websdr as a remote receiver with Max/MSP and Elecraft K4

Remote receiver project using Websdr as a remote alternative to a local receiver.

Demonstration of a Max/MSP program that connects an amateur radio transceiver to Websdr – transmitting locally from Maine (USA) while receiving remotely using a radio in the Netherlands. The Max program reads the frequency from a Elecraft K4 transceiver, to control the Websdr sites. It also loads the remote receivers, controls audio routing, mode, filter, and waterfall display settings. An iPad, running touchOSC, acts a a control panel. Up to 4 remote receivers operate at the same time. Websdr is a remarkable system, developed by PA3FWM at It lets you control remote receivers worldwide, from your Web browser.


  • Max/MSP
  • Websdr
  • TouchOSC
  • Elecraft K4 transceiver with antenna system
  • Skookumlogger (logging software)

Max Patches:

websdrjweb7.maxpat : main control program. Contains [jweb] objects for launching websdr instances. Also code for injecting javascript to control parameters like frequency, filter, and volume. This patch acts as an intermediary between TouchOSC, WebSDR, and allows external MIDI control as well as getting frequency input from CAT controlled radios like the Elecraft K4.

websdrCATaudio.maxpat : handles serial port interaction for the K4. Also reads audio stream from either the K4 receiver (via USB) or the websdr receiver (via Blackhole.)  I created an aggregate audio device called K4sdr to allow Max to read both devices at the same time. Audio switching and levels are handled using a Korg nanoControl2. For example to switch between the audio streams or listen to both.

Optional: arduino-ptt-detect2.maxpat : reads serial data from an Arduino, connected to the amplifier keying line, to determine whether the radio is in transmit mode, so we can switch back to the local audio stream to eliminate latency of hearing your signal via websdr. See subsequent post about this setup…


websdrCW3.touchOSC : controls all 4 websdr channels, ie,., volume, mute, filter, CW offset, filtershift, – Also handles window management, loading js code, zoom in/out websdr and selecting channel waterfall views or Max code views.

CW Offset

websdr doesn’t have a control for CW pitch offset. To sync the frequency of the K4, the websdr is run in LSB mode with a frequency offset equal to the CW pitch setting in the transceiver. eg., 450 Hz. This works for most of the websdr sites, but unfortunately some of the sdr’s are off-frequency. You can usually compensate by adjusting the CWfreqOffset for that channel (in Max or TouchOSC).

Setting the offset also requires shifting the filter so it is centered over the actual signal.


This is currently a work in progress, not available on Github. Local files are in max teaching examples folder.

X API update

Attempts to use the X API (formerly Twitter) for projects with Max/MSP have been disappointing at best. Most of the API is behind a paywall now.  The cost is $5000 per month. to implement streaming API used in projects like this:

The free tier only allows basic tweeting and user lookup. Search is not available.

I was able to find only one node example that actually worked in the free tier. By “Coding with Ado”. The code requests a token from X, and then you enter a timestamped pin number to continue. Making it worthless for programs and bots.

A local copy of the source code for this is in tkzic/nodetweet3/index.js

Other options

Another option with X, is to use a service like Socialdata.

There service sits in the middle to handle X API calls. You are charged by the number of calls. It doesn’t offer streaming either, but you can simulate it by calling a search every few seconds.

Other social media options

There are API’s for other social sites like facebook, instagram, tiktok, etc.,

Hamlib C programming example on Mac OS

Hamlib provides a standardized computer interface for amateur radios.

I was able to get it to run in a C program on Mac OS Ventura.


Install Hamlib using homebrew. ie,., brew install hamlib.

Download this sample C test code – testrig.c – from or

Change the SERIAL_PORT constant to the actual port name. Change the baud rate.

Lookup the hamlib code for your radio.

For example, for the Elecraft K3, the code is 2043.

compile using this command:

gcc testrig.c -I /opt/homebrew/include -L /opt/homebrew/lib -l hamlib -o testrig

Type this to run the program:

./testrig 2043

Assuming 2043 is the rig number. If all is working, the program will set a bunch of stuff on your radio, changing frequency, mode, etc.,

Local files: tkzic/chatgpt/radio/ctest.c

notes: link to instructions for compiling hamlib manually:

Using Web Serial API for Radio CAT interface

Work in progress…

An html example that sends and receives CAT commands with an Elecraft K4 connected to the serial port of the machine running the web browser.

The file was built using examples from this article by Francois Beaufort. It’s an excellent resource for Web Serial.

The html file for this project is here:

But it won’t run from that server. It only runs locally.


Download the index.html file from the link above. start a local web server, eg., “npx http-server” and enter the server address into a Chrome browser.

When you press connect, the browser will prompt you to select a serial port for the radio.  On my computer the K4 serial ports appear something like: cu2.usbserial-21100. There are 2 ports. Select either one.

Then press read. If you spin the dial on the K4, and it is autoinfo mode, you should see CAT commands in the read window.

enter a CAT command in the write window and press the write button. It is preloaded with “fa7;” which sets frequency to 7 MHz.

Press the disconnect button to end your session.

local files tkzic/webusb/serial2/index.html



Sonification of Mass Ave buses, from Nubian to Harvard.

Updated for Max8 and Catalina

This patch requests data from MBTA API to get the current location of buses – using the Max js object. Latitude and Longitude data is mapped to oscillator pitch. Data is polled every 10 seconds, but it seems like the results might be more interesting to poll at a slower rate, because the updates don’t seem that frequent. And buses tend to stop a lot.

Original project link from 2014:

MBTA developer website:

This project uses version 3 of the API. There are quality issues with the realtime data. For example, there are bus stops not associated with the route. The direction_id and stop_sequence data from the buses is often wrong. Also, buses that are not in service are not removed from the vehicle list or indicated as such.

The patch uses a [multislider] object to graph the position of the buses along the route – but due to the data problems described above, the positions don’t always reflect the current latitude/longitude coordinates or the bus stop name.


folder: mbta


  • mbta.maxpat
  • mbta.js
  • poly-oscillator.maxpat

You will need  to replace the API key in the message object at the top of the patch with your own key. Or you can probably just remove it. The key distributed with the patch is fake. You can request your own developer API key from MBTA. It’s free.

  • Open mbta.maxpat
  • Open the Max console window so you can see what’s happening with the data
  • click on the yellow [getstops] message to get the current bus stop data
  • Toggle the metro (at the top of the patch) to start polling
  • Turn on the audio (click speaker icon) and turn up the gain

Note: there will be more buses running during rush hours in Boston.  Try experimenting with the polling rate and ramp length in the poly-oscillator patch. Also, you can experiment with the pitch range.

Python3 tcp client for Max

Using OSC from [udpsend]

I needed a better way to send radio frequency data from Max to a rigcltd daemon (via tcp). This is the method of tuning SDR devices hosted by CubicSDR.

From the max8radio folder run:

The input is OSC frequency data, on port 8001, in the form: /F 7001000

(This would be for 7.001 MHz)

An OSC server in the python program listens for these messages and then reformats and sends them to a running rigctld daemon running in the background on port 4532

rigctld -m 1 4532 &

The frequency message going to rigctld would be in the format: F+ 7001000


Updating Max/MSP internet sensor projects

Notes for updating from Max6 to Max8 in Mac OS Catalina

In general, 32 bit code will not work

Link to internetsensors project:


1. mxj object

Need to update, but the Oracle link leads to a dead end message. Go to the Oracle download link but instead of pressing the green download button, <ctrl> click and save the link as described in the instructions from intrepidOlivia in this link

2. aka.objects

I have used, and aka.speech – among others. These objects no longer work. Replace with Jeremy Bernstein’s shell object:

NOTE: There’s a problem with [shell] – it rejects input that is converted to a symbol using [tosymbol].

This can be fixed by using from symbol – or just eliminating [tosymbol] – it make affect the stderr-stdout redirection token, ie., “>” and other special characters but for now [shell] does not accept symbol input

aka.speech can be replaced using the “say” command in the shell.  more details to follow about voice parameters.

‘say’ has similar params to aka.speech, eg., voice name and rate. There are voices for specific languages. This feature could be used, for example, to match the language from a Tweet to an appropriate voice

3. Twitter streaming API

I revised the php code for the Twitter streaming project, to use the coordinates of a corner of the city polygon bounding box. That seems to be more reliable than the geo coordinates which are absent from most Tweets.

There is a new API in the works – but its difficult to decipher the Twitter API docs because they have so many products and the documentation is obtuse.

Also it would be interesting to extract the “language” field and use it to select which voice to use in the speech synthesizer. Or even have an english translation option.

4. Echonest API

Echonest was absorbed into Spotify. The API is gone. But the Spotify API does have some of the feature detection and analysis code. But it doesn’t allow you to submit your own audio clips. There are also some efforts to preserve some of the Echonest stuff like the blog by Paul Lamere, and the remix code. Here are a few links I found to get started.

Spotify API (features)

Echonest blog:

Amen – algorithmic remix project:

5. Google speech to text

Several issues:

  • Replacing [] with [shell] – instead of using [tosymbol], this workaround seems to help

  • Now have rewritten all of the recording code, and shell interactions with Google.
  • Still need to work on voice options for the ‘say’ command (text to speech)
  • pandorabots API problems turned out that the URL needed to be https instead of http

6. twitter curl project

Looks like is gone. Maybe purchased by google? Anyway – this project is toast

7. Twitter via Ruby

Got this working again.

8. Bird calls from

This patch has been completely re-written. The old API was obsolete. This version uses [dict] and [maxurl] to format and execute the initial query. Then it uses [jit.uldl] to download the mp3 file with the bird-call audio.  Interesting that [maxurl] would not download the file using the “download” URL. It only worked with a URL containing the actual file name.

9. ping

Needed to reinstall ruby gems using xcrun (see above)

seems to be a problem with mashape:

Could not resolve host: (Patron::HostResolutionError)

[mashape was acquired by – so will need to refactor the code in the ruby server.]