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:

py3rigctl2.py

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

 

Max8radio project

New version of software define radio for Max/MSP  (in progress)

github repository: https://github.com/tkzic/max8radio

Notes

goals and strategy

The new approach will be to remove most of the device handling code from Max. Instead providing device interfaces from existing device libraries, like soapy-sdr, hamlib, gnu-radio, etc., The Max portion of the project will read IQ files, perform DSP, and other magic.

The first platform will be Max8 in Mac OS Catalina

projects

Max + CubicSDR + hamlib

See working prototype below. This setup uses CubicSDR as a device driver to send IQ data into Max’s input audio stream. CubicSDR supports many devices via soapySDR. It supports networked rig control via Hamlib.

Advantages of this system: It works now. It runs in Windows. It runs over the a local network. The software is managed and distributed by somebody else.

Disadvantages: Its not an elegant solution – ie., not self contained within Max. It requires installation and setup of CubicSDr. The software is managed and distributed by somebody else – so it could stop working at any time.

rx_tools + hamlib

rx_tools is an update of some of the rtl tools, like rtl_fm. It includes soapySDR device support. If hamlib is added to rx_tools, then you could do the same networked frequency control, and IQ streaming as CubicSDR – using rigctld. Without the overhead of running CubicSDR. The downside it that it’s yet another program to maintain and distribute.

Next step: look at source code for rx_tools and estimate scope of hamlib intergration.

openwebrx and websdr API

openwebrx  https://www.openwebrx.de/

Websdr  http://websdr.org/

These sites provide access to SDR devices connected to web servers. Although they don’t stream IQ data, it would be interesting to build a Max front end to the APIS.

background information

See previous posts:

External programs required

  • hamlib (macports)
  • cubicSDR (see link above)
  • netcat (nc) (built into Mac OS terminal)

notes on rigctld commands

Best results using one letter commands with single quotes:

echo 'F 7023000' | nc -w 1 localhost 4532

Prepend ‘+’ for more feedback, like this:

% echo '+F 7023000' | nc -w 1 localhost 4532
set_freq: 7023000
RPRT 0

Latest prototypes

Links to latest working projects (from newest to oldest)

 

First Max test project

This is an update of the test done with CubicSDR and RTLSDR as described here: https://reactivemusic.net/?p=19802

CubicSDR is great but eventually the goal is to pare down the interface between the SDR device and Max. Something like a command line IQ filter would be ideal:  https://github.com/xmikos/simplesoapy

Hardware and system setup

This test uses an Airspy Discovery HF+, but any device supported in CubicSDR should work – that’s the point of this exercise.

Using BlackHole from Existential Audio https://existential.audio/blackhole/

as an alternative to Soundflower to route the IQ (audio stream) data from CubicSDR to Max. You could also use a cable to connect output of one audio device to input of another, etc.,

Signal path:

Antenna -> Airspy -> CubicSDR -> rigctld -> Max

CubicSDR settings

  • Plug in Airspy device before launching CubicSDR, so it will be discovered on the setup screen
  • On the main display, click just to the right of the mode buttons to bring up a drop down menu of audio devices
  • select I/Q mode
  • select the audio device, or “BlackHole 2ch”, that you will use to route audio to Max
  • click on any of the frequency digits, press space, and enter in the same frequency as the Center Frequency (e.g., 7000000)
  • click the ‘V’ to the left of the frequency digits, to select ‘delta lock mode’. This causes the frequency and center frequency to sync.
  • Be careful not to click anywhere in the waterfall window – or this will mess up the sync
  • Under Rig Control menu:
    • Select “Hamlib NET rigctl” as the model
    • Enter localhost:4532 as the control port
    • Select 57600 as the serial rate
    • Make sure that “follow rig” and “floating center” are checked
    • After you get the rigctld daemon started, come back here and ‘Check’ ‘enable rig’. If it doesn’t stay checked, then there is a problem with the connection.
  • Under the Audio sample rate menu, select the correct sample rate for your audio device (e.g. 96k)

Notes: It seems there is some kind of AGC hardwired into CubicSDR.  https://github.com/cjcliffe/CubicSDR/issues/826

TCP and rigctld settings

  • Open a terminal window
  • type: rigctld -m 1 4532 &
  • This starts the server running in the background using the HAMLIB test dummy rig
  • to set frequency to 7.010 MHz, type:

    echo ‘F 7010000’ | nc -w 1 localhost 4532

  • This should change the center frequency and frequency in CubicSDR

Max settings

For this test, you can use any of the MaxSDR tutorials available  at https://github.com/tkzic/max8radio

We’ll be using maxsdr7a.maxpat

ignore the max-console messages about missing externals.

The key is to choose the default audio input device and set it to be the same as what is coming out of CubicSDR.  ie., “BlackHole 2ch”

  • Set the audio input device to match CubicSDR, as described above. Also match the sample rate (e.g., 96k)
  • Set the audio output device to your internal soundcard/speakers
  • Start audio and recall preset 1 or some normal settings for SSB
  • It should be receiving I/Q data now from Cubic SDR
  • Note: may need to flip the I/Q input due to anomaly in CubicSDR.
  • Now load another Max patch to do the frequency control: rigctld1.maxpat

This patch sends frequency data to the rigctld daemon via the [shell] object. You can change the frequency using the number box.

That’s about it for now.

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: https://reactivemusic.net/?p=5859

Github: https://github.com/tkzic/internet-sensors

1. mxj object

Need to update, but the Oracle link leads to a dead end message. Go to the Oracle download link https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html but instead of pressing the green download button, <ctrl> click and save the link as described in the instructions from intrepidOlivia in this link https://gist.github.com/wavezhang/ba8425f24a968ec9b2a8619d7c2d86a6

2. aka.objects

I have used aka.shell, and aka.speech – among others. These objects no longer work. Replace with Jeremy Bernstein’s shell object: https://github.com/jeremybernstein/shell/releases/tag/1.0b2

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) https://developer.spotify.com/console/get-audio-features-track/?id=06AKEBrKUckW0KREUWRnvT

Echonest blog:  https://blog.echonest.com/

Amen – algorithmic remix project:  https://github.com/algorithmic-music-exploration/amen

5. Google speech to text

Several issues:

  • Replacing [aka.shell] 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 xively.com is gone. Maybe purchased by google? Anyway – this project is toast

7. Twitter via Ruby

Got this working again.

8. Bird calls from xeno-canto.com

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: igor-zachetly-ping-uin.p.mashape.com (Patron::HostResolutionError)

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

 

Generic SDR realtime IQ converter

With CubicSDR, HAMLIB, and Max

update: 1/25/2021 – Using this general setup with Airspy, CubicSDR, rigctld, and netcat (nc) to send IQ data into the basicSDR3.maxpat patch


CubicSDR uses the SoapySDR library as generic tool for extracting realtime IQ data streams from common SDR devices. It also provides TCP external frequency control using HAMLIB.

http://cubicsdr.com/

Although its not the main purpose of CubicSDR, the IQ streaming capability will connect SDR devices to Max, Pd, and other DSP platforms, to build experimental radios. All without building external objects or hardware device drivers.  The convenience of using CubicSDR for this purpose far outweighs the overhead.

A prototype with Max and rtl_sdr

How to use CubicSDR as a front-end for SDR experiments in Max.

The signal path for this test is:

  1. antenna
  2. NooElec HAM IT UP upconverter
  3. rtl-sdr dongle
  4. CubicSDR
  5. Soundflower (or a “loop-backed” external audio device)
  6. Max

Running in the other direction, the frequency control path is:

  1. netcat running in Mac OS X terminal (or a Max patch that sends TCP)
  2. rigctld (hamlib TCP server)
  3. CubicSDR
  4. rtl-sdr dongle

There’s a lot of stuff going on here, so the choice to use hardware audio routing instead of Soundflower and netcat instead of TCP in Max, is an effort toward simplicity.

CubicSDR settings:

  • Plug in the rtl-sdr before launching CubicSDR, so it will be discovered on the setup screen
  • On the main display, click just to the right of the mode buttons to bring up a drop down menu of audio devices
  • select I/Q mode
  • select the audio device, or Soundflower, that you will use to route audio to Max
  • If using an upconverter, set the ‘frequency offset’ in the settings menu (e.g. -125000000)
  • click on any of the frequency digits, press space, and enter in the same frequency as the Center Frequency (e.g., 7000000)
  • click the ‘V’ to the left of the frequency digits, to select ‘delta lock mode’. This causes the frequency and center frequency to sync.
  • Be careful not to click anywhere in the waterfall window – or this will mess up the sync
  • Under Rig Control menu:
    • Select “Hamlib NET rigctl” as the model
    • Enter localhost:4532 as the control port
    • Select 57600 as the serial rate
    • Make sure that “follow rig” and “floating center” are checked
    • ‘Check’ ‘enable rig’. If it doesn’t stay checked, then there is a problem with the connection.
  • Under the Audio sample rate menu, select the correct sample rate for your audio device (e.g. 96k)

TCP and rigctld settings

  • Open a terminal window
  • type: rigctld -m 1 4532 &
  • This starts the server running in the background using the HAMLIB test dummy rig
  • to set frequency to 7.010 MHz, type:

    echo ‘F 7010000’ | nc -w 1 localhost 4532

  • This should change the center frequency and frequency in CubicSDR

Max settings

For this test, you can use any of the MaxSDR tutorials available at https://github.com/tkzic/maxradio but I chose to use the main program, currently maxsdr7a.maxpat. The key is to choose the default audio input device and set it to be the same as what is coming out of CubicSDR.  I used a stereo patch cord to connect the line output of my Apollo Twin interface to the input jacks – but you can also use Soundflower.

  • Set the audio input device to match CubicSDR, as described above. Also match the sample rate (e.g., 96k)
  • Set the audio output device to your internal soundcard/speakers
  • You may need to toggle the flip IQ button
  • Start audio and recall preset 1 or some normal settings for SSB
  • It should be receiving I/Q data now from Cubic SDR

Links:

Installing Hamlib: https://reactivemusic.net/?p=19402

Installing CubicSDR: https://github.com/cjcliffe/CubicSDR/releases

Supported SDR devices: https://reactivemusic.net/?p=19746

Notes:

I had some success using the Max TCP external described at the Installing Hamlib link above, but temporarily abandoned it due to some latency and dropouts.

Local version of this patch is: tcpClient-small2.maxpat

Next steps:

  • hardware (i.e., MIDI controller) control of frequency – and refinement of Max TCP patch. Can likely re-use the patch from the remote radio project.
  • Convert to PD : TCP/IP code is builtin
  • Consider forking CubicSDR and adding direct MIDI/OSC control of UI.

Black on white with Max 7

Making Max 7 look like 6.

What’s this about?

The UI in Max 7 reverses foreground and background from previous versions of Max (and Pd).  Additionally,  a secondary toolbar menu frames the patcher and all sub-patchers. For example, here is a simple Max 6 patch and its Max 7 equivalent.

Max 6:

Max 7:

Regardless of which look you find more appealing, the new UI is problematic in several ways.

  • Light text on dark background can be difficult (blurry)  for people with vision impairment – given the same font size and screen brightness.
  • Patches created in previous versions of Max lose their original design.
  • Larger objects and toolbar frames consume more screen space.
  • If you like to sketch ideas with pencil – an empty white patcher screen is like paper.

Max 7 doesn’t include a black-on-white style, but you can make your own. And lose the toolbar. Here is a new and improved version of the patch:

Making a new style

The process is arcane. But it took less than a half hour to get results. Then I wasted time endlessly tweaking.

The secret recipe came from a 2014 Cycling 74 forum post by Phiol, with assistance from Ben Bracken. Everything you need to know is explained in Phiol’s first 2 posts in the thread. https://cycling74.com/forums/topic/custom-color-scheme-layout-setup-walkthrough/#.V6oHMZMrIcg

I encourage you to read both posts and follow the steps precisely. There are no shortcuts. I will paraphrase Phiol’s method here:

  1. In a default patcher, make a bunch of objects and then in the Format Palette (object inspector) change them to whatever colors you want
  2. Select all the objects in the patcher
  3. In the Format palette, make a new style – this style will be for multiple objects
  4. Select the patcher to activate it in the Format palette
  5. In the Style menu (located in the patcher inspector window), select the style you just made, applying it to the patcher level
  6. Delete all of the objects in the patcher
  7. Save a new template (in dropdown file menu “create template”) and make it your default.

And then the bad news:

Step 1. is important.
  • You must start from a blank “Default Patcher Template” and choose “Default Max7”
  • You cannot copy/paste objects that you had already done your custom colors. You will have to start from scratch. one by one.
  • In the inspector window, make sure the “Appearance style” has nothing selected in it’s umenu

Then do all the steps mentioned in the previous thread.

The Glitch/bug:

-Gradients objects do not work.
For example, [message and umenu] would not keep my custom colors.

Workaround: Once you have started a new patch, reselect your “custom_style” in patch inspector window or the ‘format’ sub menu. That is, click the style that should already be selected/checked – and now it should work.

So yes, for now, as we start a new patch we will we have to make it a habit to always select our “custom_style” in patcher inspector window or the format sub-menu.

patcher inspector window

format submenu

(click the paintbucket icon on the top toolbar)

 

Copy style to library

Also, when you open older Max6 patches and/or the help patch and want to apply your new custom style template, make sure that in the “Format” dropdown menu you have selected the “copy style to library”.

Loading Max 6 patches

Once you’ve done this, you will be able to apply you’re custom style to older/help patchers and resave them with your custom look. To do so, you open Inpector’s Appearance again, and select your “custom_style” that will be in the Library style.

Walking through the process of step one

If you are totally confused at this point, so was I.

Starting with step one above,  make a patch with common objects, that looks something like this:

Select each object individually, then with inspector, change the background color to white, or a lighter shade, and the text color to black.

You may need to experiment. Try with a small number of objects at first – because you will probably need to do the whole process several times. As noted above, you have start from the begining  each time by hand. You can’t modify a style after you save it.

Then, you should be able to follow the rest of the steps from Phiol’s post.

The objects used for this style are:

  • umenu*
  • button
  • dial
  • toggle
  • generic object
  • textedit
  • slider
  • message*

*these objects use gradients

Making a white patcher background

  • open a blank patcher
  • ctrl click on the background and select “Inspector Window”.
  • Change the unlocked and locked background colors to white.
  • Then, from the File menu, select ‘create template’ and give it the same name as the template you selected in step 7 above (and make sure to check ‘default for new patchers’)

Getting rid of the tool bar frame

The procedure is basically the same as setting the white background.

  • In a blankpatcher, open the inspector window and uncheck ‘show toolbar on open’.
  •  Then, from the File menu, select ‘create template’ and give it the same name as the template you selected in step 7 above (and make sure to check ‘default for new patchers’)

Note: you can toggle the toolbar anytime with <cmd>8

 If subpatchers  still have the default look

If you create a subpatch and it reverts back to the default style then…

  • In a blank patcher, open the inspector window and set the subpatcher template to your new tempate created in step 7 above.
  •  Then, from the File menu, select ‘create template’ and give it the same name as the template you selected in step 7 above (and make sure to check ‘default for new patchers’)

More about styles and templates in Max 7

Check out the Cycling 74 vignettes about styles and templates to get a better understanding of what’s going on here:

https://docs.cycling74.com/max7/vignettes/styles

https://docs.cycling74.com/max7/vignettes/templates

Virtual serial ports in Windows

Using Virtual Serial Port Manager

Setting a local bridge to connect the 2 virtual serial ports allows a Max patch to communicate with a radio on a real serial port and pass through the data to a virtual serial port that can be used by another program, such as a logger. The patch looks like this:

Screen Shot 2016-04-07 at 10.09.47 PM

 

Its looks like a feedback loop but its not. In this case the bridge is: com1 <-> com2. Com1 is port a in the above patch. Data sent to com1 can be read from com2 and vice versa.

 

SQLite database for remote radio in Max

under construction…

Max/MSP features a full implementation of SQLite using the js (javascript) object. Here we describe a database to track radio frequencies. Frequencies are stored by time, type, and mode. The frequencies can be retrieved in various ways, like with a scanner radio.

Tables can be created and maintained outside of Max using the command line (sqlite3) or database apps like SQLiteStudio.

Max patches:

(not yet available on github:

  • freqdb4.maxpat (database UI)
  • swBase3.js (SQLite code)
  • lp_radio2.maxpate (Launchpad)

DB structure:

The database is called newtestDB1

tables:

You can see the table schema in the screenshots. The tables were created using command line sqlite3 and SQLiteStudio.

freq table:

One record for each stored frequency. This table retains its state from each previous use, but new records can be added using the Max patch, or the Launchpad.

Screen Shot 2016-04-05 at 11.00.31 PM

xtime: Timestamp in UTC.

frequency: Hz.
mode:

  • usb: 0
  • lsb 1
  • cw 2
  • am 3
  • fm 4

filter: bandpass filter setting in Hz. (default is 6000)

typecodes:

0 : unknown
1 : AM/SW broadcast
2 : clock
3 : digital mode
4 : local broadcast
5 : mostly noise

zone: cq zone number

rating: 0-5 (0 = unrated)

confidence: 0-5 (0 = unknown)

tags: (general text notes)

preset table:

The preset table contains one record for each 8×8 launchpad button, for each of 3 screens.

  • screen 0: fixed presets (red) (static and persistent)
  • screen 1: time presets (green) (rebuilt with each time query)
  • screen 2: user presets (yellow) (persistent but can be modified using the Launchpad)

Data from each of theses screens is also displayed in jit.cellblock objects in the Max patch. All of the fields correspond to the fields in the freq table – except for screen, row, and col which are locators for the launchpad.

Screen Shot 2016-04-05 at 11.11.08 PM

Using the database

Launchpad presets

There are three screens of presets color coded using the Launchpad mixer button (upper right). Press it to cycle through the 3 screens.

0 fixed presets (red)

The fixed presets are static. But can be changed using SQLiteStudio. They contain commonly used radio frequencies, like the SW, Ham, and CB bands. And clock stations.

To select a preset, press its button on the Launchpad.

Currently assigned presets:

Screen Shot 2016-04-05 at 11.39.12 PM

1 Time Presets (green)

Time presets are frequencies with Timestamps that match a selected range. For example, every frequency within one hour of the current time. These can be selected with a query in the Max patch, or using default values from the Launchpad. The query will randomly match up to 64 records. If the query returns less than 64 records, you will get all matching records, but in random order.

From the Max patch:

Match hours plus/minus current time (0-12).

Type the number of hours in the number box and press the button under the delay object. This reloads the presets.

Screen Shot 2016-04-05 at 11.36.35 PM

You can view the results in the jit.cellblock:

Screen Shot 2016-04-05 at 11.39.07 PM

 

Match a specific time range:

Enter the start/end times and press the button.

Screen Shot 2016-04-05 at 11.40.51 PM

 

Selecting from launchpad

trk button: re-runs query using last set number of hours plus/minus current time. Default is one.

solo button: select one random preset using current hour range, and play it?

 

User Presets (yellow)

The user presets work like the pushbuttons on a car radio. Press to select. Hold to save the currently tuned radio frequency.

The learn button (upper left) gives feedback. If you press a pad for which no frequency has been assigned, the learn button will flash red. When you save a new preset, the learn button flashes green to indicated that the saving is done. If you press a pad for a preset that has already been saved, there will be no flash, but the radio frequency will change.

Adding new frequency records

You can add records using the Max patch or the Launchpad, or from SQLiteStudio.

Adding records from Max:

Tunning the radio fills in all of the fields except for typecode. Tune the radio. Then press one of the typecode buttons. Then press the big green button. You have added a new record.

Screen Shot 2016-04-05 at 11.55.57 PM

 

Adding records with Launchpad:

Press the Arm button (lower right) to add a record for the currently tuned frequency, using an ‘unknown typecode’

Adding records from SQLiteStudio

Just do it.