Twitter streaming API in Max

World map and radio simulation

note August 3, 2022 –

This program is broken on Mac OS Monterey. The PHP code is throwing errors in the OSC library.  I’m not certain there is a reasonable workaround at this point and will be looking at replacing the php code with node.js or another more reliable platform. Also, as noted below – php is no longer installed in Mac os – so it requires homebrew or macports

features

  • Twitter streaming v1.1 API and Twitter Apps (using http requests and Oauth in php)
  • lat/lon conversion and map plotting in Max
  • sending data to Max using OSC in php
  • ‘speaking’ tweets using several voices (text to speech)
  • Using geo-coordinates to control an FM synthesizer
  • Converting Tweet text to Morse code
  • Using a data recorder to replay/save data streams (Max lists)

Compare to satellite photo of earth – note the pattern of lights.

download

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

folder: twitter-stream

files

Max
  • world3.maxpat (main patch)
  • data_recorder_list-tz.maxpat (abstraction for recording data)
  • data-recorder-wrapper.maxpat (abstraction for recording data)
  • worldMap.jpg
  • twitter-morning.txt (sample data – not required)
php
  • ctwitter_max3.php (main program)
  • ctwitter_stream_max3.php (twitter engine)
  • udp.php (Osc client)

3 August, 2022

(note: starting with mac os monterey, php is no longer included in mac os. You can install it with homebrew. See this post: https://www.ergonis.com/products/tips/install-php-on-macos.php

externals

[note]  The project displays Tweets without these externals, but you won’t hear any speech

authorization

In addition to having a Twitter account, you will need to set up a Twitter application from the developer site here:

https://dev.twitter.com/apps

Good instructions on how to do this can be found in this stackoverflow.com post under this heading: So you want to use the Twitter v1.1 API?

http://stackoverflow.com/questions/12916539/simplest-php-example-for-retrieving-user-timeline-with-twitter-api-version-1-1

When you get to step 5 – in the instructions – instead of writing your own code, just use a text editor to copy your access tokens into this php program which is provided:

  • ctwitter_max3.php

Replace the strings in this line of code by copying and pasting the appropriate ones from your Twitter application:

$t->login('consumer_key', 'consumer secret', 'access token', 'access secret');

 

So it will end up looking something like this:

$t->login('ZdzfNaeflihFydfOHeOA', 'eXzUOfhif4riifgRbCTnnSN0T7neYtg8dIWDC7j3bs', '205589709-5kRI1fllJvU94jjffeerSn9LrTajtxSrvO8', 'u5MuSxPseBemUIBWlMxEFaw899feedXA0eHlReCnQ');

Yeah – its cryptic…

instructions

1. open the Max Patch: world3.maxpat

2. in a terminal window run the php program: ctwitter_max3.php. [note] it runs forever. Press <ctrl-c> when you want to stop streaming Tweets.

php ./ctwitter_max3.php

3. Switch back to world3.maxpat to see dots populating the map

4. In Max, press the speaker icon (lower left) to turn on audio.

5. Activate  voice synth/morse code using the blue toggle (lower left)

6. Clear the map by pressing the blue message box: “clear, drawpict a 0 0”

7. Stop the Tweet stream by pressing <ctrl-c> in the terminal window

special voice fx

If you have Soundflower installed, the Mac OS speech synth output can be routed back to Max for audio processing. This is somewhat complicated, but shows how to process audio in Max from other sources.

  • In MacOS System Preferences, set audio output device to Soundflower 2ch
  • Turn up hardware volume control on your computer
  • In Max, Options | Audio Status, set input device to Soundflower 2ch
  • In world3.maxpat double click on [p audio engine] (lower left). Then in the audio-engine sub-patch activate the toggle, (lower right) for voice-fx

data recording

The built-in data recorder/playback is on the left side of world3.maxpat:

  • toggle ‘record’ (red toggle)  to start or stop data recording
  • Note that data will only be recorded when the php program is streaming Tweets in the terminal window (see above)
  • Press /play message or other transport controls to replay data
<span style="font-family: 'Helvetica Neue', Helvetica, Helvetica, Arial, sans-serif; font-size: 23px; font-weight: bold; line-height: 1.1;">
</span>
<span style="font-family: 'Helvetica Neue', Helvetica, Helvetica, Arial, sans-serif; font-size: 23px; font-weight: bold; line-height: 1.1;">revision history</span>
<span style="font-family: 'Helvetica Neue', Helvetica, Helvetica, Arial, sans-serif; font-size: 23px; font-weight: bold; line-height: 1.1;">
</span>

revision history

1/19/2021

Updates for Max8 and Catalina:

Replaced [aka.speech] external with Jeremy Bernstein’s [shell] external and the Mac OS command line ‘say’ command.

Reinstalled Java Development Kit for [mxj] object

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.

  • updated 3/26/2014 – fixed runtime error in php server
  • updated 2/2/2014 – simplified user interface and updated audio engine
  • updated 9/2/2013 for Twitter v1.1 API with Oauth – note that older versions of this project are broken due to discontinued Twitter v1.0 API as of June 2013

phantomJS

phantomJS runs outside the browser but implements enough of the DOM that you can use it for testing, rendering screenshots, running http: requests, etc.,

http://phantomjs.org/index.html

Have installed locally in: tkzic/phantomjs (binary is in the bin/ folder)

Parsing Tweets

A method using regexp and php. Actually what this does is parse Tweets using regexp to reformat the text as html with links. A tutorial here:

http://saturnboy.com/2010/02/parsing-twitter-with-regexp/

This is a php library that breaks out hashtags, usernames, etc., but doesn’t really provide a way to isolate the remaining stuff. I have put it in tkzic/API –  there is an example php program provided.

https://github.com/mzsanford/twitter-text-php

hashtags – using regular expressions

http://stackoverflow.com/questions/11551065/parsing-tweets-to-extract-hashtags-in-r

twitter-text-rb : ruby gem which parses out usernames and hashtags

https://github.com/twitter/twitter-text-rb

 

Car engine enhancement with Max and OBD-II

Much of our driving experience is wrapped up in sounds that happen when you press the pedal to the metal. Like Superman emerging from a phone booth, this 2006 Jetta seems different.  The project connects RPM data from an OBD2 diagnostic sensor with the input of the car radio. Via synthesizers.

[update 11/2013 – source code is available at https://github.com/tkzic/automax  – this version features

  • V8 engine
  • Jet engine
  • Spaceship
  • Star Trek TOS transporter button
  • Korg nano-control Midi controller interface]

This project uses the RPM data from an automobile OBD-II port to control the engine speed of an engine simulation from Andy Farnell’s book “Designing Sound”

Here’s the patch that polls and translates OBD-II data

patch is tkzic/automax/rpm4.maxpat

Here’s a Max version of the Farnell car engine simulation:

patch is tkzic/automax/waveguide_engine2e-1.maxpat

 

 

 

Using a Wiimote with Osculator in Max

Update 6/2014: The Max patch is available from the max-projects archive: https://reactivemusic.net/?p=11130

original post

I had a difficult day with wiimotes…

Here’s a general purpose Max patch to read Wiimote Osc data from Osculator:

Located in tkzic/max teaching examples/wiimote/wiimote_read.maxpat

<code>
----------begin_max5_patcher----------
1412.3oc2ZsrjahCEcs8WgJVSr06GYWlY0rJUMyxolJEFqzMorAW.ticmJ+6
iPxNF2sMPm1Hn7hz.JXw4dz8w4J3GSmDrHamtH.7Qv+BlL4GSmLwNT0.SNb8
jf0Q6hWEUXusfT82yV7sfP2+UodWoc3O+O+4Gxy1VpAygf4Hvb7waYSTY7iI
oO7kbcbo6Iww7YbNiSUg.DGMCZN.kUGvvYPv+c3WltcsYFWoKsOY5gQ+ZVZY
Qxy5pwPXyOxMr6NK2uQ6dFAAg092ulyjkV3ZLgOfYA0lxzn01eYvmxShVEbB
BIoGQ.pZreNcZ0eBeezUgNcIHIeeCjDBBYyXHjjhL7ByROLRKjDrYRpt0SGb
qeWCVuBo9kKROX7DOX7wYqWqSKek0GEGqWoyiJSxR+HXW39vm6XrBVQswJtC
XQ6LQ9CKrWO6hbi7hbCdfcLhZhNjF+h9Kn.w8fs+0UYl4nq1ncQBHbYGIW0F
wWxFoyDJnRH90iJ2XQk57unSiVrRWmadU5SCJiJqxctHJ8gS4OW7Pb1prb2M
AmoXbAkYbIqfGz3nJ4Jt8xKkwEIFZWqlR3Jv39z0RNz19ttlk41a6pwPX0Yq
u2SgUX3XfdOyE5thdQCcjabbC7NC+5JhpaWnKaL3aclMNt8snLlz1Wiy2RPT
7FJHRGPcnwOZrCMn7QMv7LVnyAkYf0Uje8wRRAetHd6pnxr7YfDcH36IIm5t
aURpNNaapcJIWeEj.g1rCxP.EZEwxrGnuaQrW1s0GB7WrsrLKsoV3bgiHwwv
wFCJQWyw6b+s5VIxK4eZRzDk7JQST9MK6yPqYJuAKmP3G8nOZ3zalgOzMmuo
ACGaBfYmLZwsqVy.lLzEKWzz5MyZntdukhdrC7QgZ4y29oQdMWifNrppbqTn
Hlmjq56UJ5NJ5w+r825dhcEilcVaSHHODrODD0gjYG1RMorGiqYiAMIXrs4f
Ca6dOHJA26Ky45nkUpPWmUpAlxUEY4fkQkQfsEFaEjcTtJ3hhTwMzlAiMCcH
nzoREiQ2FUpmbHdYunRJAQO0u.kAURaWo3KwtiCcsDmyCCaOvmQjDEDW6zam
DWBxi1kfNioXBHwSFGV4OiSpfyvr9LxWI68P++5uqdgIcstpKot.0i4zQvAb
2gdSuz05Lyv8RWQPezZyZcQQzC5WQXysJDluIeektFI2HbxbBCxkJd0IbjRw
LmfgD5oE1ttGGtFeEts2fXSePYsFe0Yp8xz4aUTAtOTyd1t.bGs+bJ7XnWg5
6zvcD4JGE84drAf6IhULlJIAlSZh9culwiEjvnVJHwdOEjtVQIAdLnp1z6IR
IYbOI9jy8mocXuy7gjZnzit3eBL+OZU30Ai2kfAgICgGNGOJRI3bT.0jgc3z
c6eFLOI2brXNpoNzTVWHkKMMeP3RDTMbj41kaLrgN4IMPAgv1oJ2KeRo5X2d
uc0nmUmhHEDrcqBogVI1HDUb8chENJ7Jqdglcvoy8V0akIw+N9bWhcXuG2L6
DZ6b4EecuV6qZ7yorhrs4wGgzw0FvIabotnLI0typ0toJHV6ldLY4RcZc4NK
SJpT.YMJ3EW75Jddwi5x3w1ND.Ml.j+XnpumY.tM.I7KdPsfGLzu3osErpO1
GOgGmuQaKXu.08If3cgendCNht.Gh+Vt5BdPb+4N2kDzUe0o9BOntfGkmCuH
slfl5YD0ZFQOim1Vx33QFAI7GfrOpVcg7nGDsKwXdrhQmxA4uRpJbGvi+RIJ
6R7k+7djcpBleCtZS9ixyA6sk7Qp7KdZ0Y1e544cge3b+hmV62gf7KfZsZAV
4W.0dKpROVfuKEvTiM.I7LdZMH62DOtMEJZylmz4EGlRKTBVG8M2l3wCsWlj
5tzNiA45mRNd+xoUy1Om9+nVZpDJ
-----------end_max5_patcher-----------
</code>

Some tips…

  • Use a real Wii remote, not the Nyko. If you do get the Nyko, get the one with motion-plus.
  • update Osculator to the latest version
  • Under parameters (in osculator) press + to add the little pacman symbol labeled “same address”, and set the the OSC URL to whatever you’ll be using like 9000 for Max
  • remember to add the Event type (OSC routing) and value (pacman thing) for every wiimote event you’ll be using
  • remember to enter checkbox on the wiimote window for every type of data you want to send

 

 

Real time Irish train map in Max

Using node.js

Time compressed video of Irish railway data from November 30th 2012.

update notes 2/11/2021

After many years…. I was able to get this running

  • in the project folder (ie., /trains)
    • npm init
    • then do: npm install <package> for these packages:
      • request
      • xml2js
      • util
      • http
      • ws
  • then just ran: node max-train1.js and started polling in train-drawing4.maxpat and the data started rolling in
  • webSockets code was replace using ws library

Also using sample webSockets code from here to handle the map points: https://masteringjs.io/tutorials/node/websockets

Next steps:

I would like to update all of this in node for max – but its also nice to have an example of doing OSC communication with Max the old way.

Original documentation follows


This map is centered on Dublin. Each train is a different color and the train number gets printed next to the current position. So for example you can see P607 coming into Dublin from the South.

It gets updates every 10 seconds or so – but sometimes the trains seem to ‘jump’ so I don’t think the actual  data itself gets updated that fast.

download

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

folder: trains

files:

main Max patches
  • max-train3.maxpat
  • train-drawing4.maxpat
abstractions and other files
  • data_recorder_list-tz.maxpat
node.js
  • max-train1.js: (main server)
  • bigInt.js: (Osc support)
  • byteConverter.js: (Osc support)
  • libOsc.js: (Osc library)
  • max.html: (the web client file – runs in browser)

node.js installation

Install node.js on your computer (or a separate server). Instructions here: http://nodejs.org

In a terminal window go to the project folder ie., /internetsensors/trains

type: npm init

(just accept all the default values)

The following node packages are required. Install using npm. For example:

type: npm install request

Do the same with all these packages

  • request
  • xml2js
  • util
  • http
  • ws

instructions

These instructions are a bit confusing. A simpler UI is in the works. (that’s funny – I said it 8 years ago)

  • Open both Max patches: max-train3 and train-drawing4
  • To run the server, open a terminal window, go to trains folder, and type:
node ./max-train1.js
  • Back in Max, in train-drawing4, you can start and stop polling with the toggle button in the upper left corner. If you want to toggle playback from the data recorder, you’ll need to have some data recorded – or load a file (this is done from max-train3)
  •  In max-train3, select a preset in the preset object. Try the top left one, The presets go from low res to high res on Dublin (left to right).
  •  You can load train-data1.txt by clicking read message on the data recorder. Then press play, or use metro (set to low number) for high speed.
  • In train-drawing4 you’ll need to manually clear the lcd and lcdsprites in the drawing section.
  • In max-train3 you can clear the color database using labeled button (if the train names don’t print on the map)

Running the chat thing

When you connect to the node server in a web browser, for example using the following url:

http://localhost:8124

You will get a message welcoming you and asking you to enter your name. After you enter your name, Max will send you a response. Then you can enter map points using the following format:

Dublin 53.15 -6.90

The map point will be drawn on the map in the Max patch.

how does it work?

Data communication is done with OSC messages. Here’s how

  • Max sends a /getTrains message to a node.js server
  • The server runs an http: request to the Irish rail API
  • The server parses the response data and sends back a bunch of /train name x y messages. to Max
  • You can also connect to the node server from web browsers in kind of a ‘chat’ thing (using Web sockets) and enter geographical place names with lat/lon – which get pinned to the map – and Max sends back personalized thank-you notes.

Here’s what the raw data looks like:

Note: if there’s no data at this link, check the time of day. Trains stop running around midnight UTC.

Programming:

Essentially what this program does is collect current train position data from Ireland and display it as points on an XY grid.

components:

  • Max/MSP
  • node.js
  • Web browser
  • Irish train API

Server

The server is written in node.js. This was my first real project using node. So I tried to make it do a bunch of things, just to test them out.The necessary features are

  • web server to make http: requests to get the train data
  • UDP server to pass data and messages back and forth from Max to node.js using Osc
  • convert XML train data to JSON,
  • convert point data from lat/lon to XY format
Additional features of the server include:
  • chat server using socket.io which allows several web browser sessions to connect to the server, talk with each other, send point data to Max, and receive acknowledgement from Max
Localhost vs. separate server

This is probably the most confusing part about this program. You can run it on the Mac in localhost mode, or you can run the node.js program on a separate server, as long as there is a direct ip path back to the computer where Max is running.  Running a separate server makes more sense if you are using the chat or a remote web control aspect of this. I have run the node program on a Ubuntu server on my local network without making any changes other than to the IP addresses as explained next.

You need to make 2 changes to go from localhost mode, to separate server mode:

In the client program, max.html – near the top, change the ip address from localhost to the specific ip like this:

// note: if you want to run this program on something other than localhost, then put in the ip
// address of the server here, instead of local host...

//     var socket = io.connect('http://localhost:8124');
//
       var socket = io.connect(192.168.1.10:8124');

 

In the server program, max-train1.js – change the destination address for UDP to the address of the computer where max is running:


var dSendAddress = '127.0.0.1';	// send response messages to max at this address
// do this if max is running somewhere other than the same computer as the node server
// var dSendAddress = '192.168.1.104';	// send response messages to max at this address

 

Also in the Max patch max-train3.maxpat you will need to change the [udpsend] object to give it the host address of the node server.

screenshots:

max-train3.maxpat

train-drawing4.maxpat

Data recorder:

To be able to save and replay data I included a data recorder in the patch. Its a revision of the data recorder from CNMAT by Michael Z. This version

  • works with lists that start with a symbol (not just ones that start with numbers)
  • handles the time delta correctly on the first record
  • adds additional transport controls, for example playback using a [metro] at any speed – and ability to goto a particular position in the data file

The actual code for the patch is horrendous. Its filled with debugging objects and is a maze of patch cords lacking explanation. But it works…

what’s next

  • Make sure that the Max Patch loads a preset map setting by default
  • put a timestamp message in the node console and Max console so we know at the end of a train list what the current time is.
  • clean up  instructions 
  • make a screencast do demonstrate how to use this needlessly complicated patch.

sending Tweets with curl in Max,

Using xively.com and zapier.com

Note: To get this project to work you’ll need a Twitter account. And you’ll need to set up a device (feed) at xively.com and a ‘zap’ at zapier.com as directed in this post. It explains how to send tweets using triggers.

 https://reactivemusic.net/?p=6903

Also, you may notice delays due to the number of steps involved.

Looking for an easier way? Send Tweets using ruby: https://reactivemusic.net/?p=7013

download

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

folder: twitter-curl

files

Max
  • tweetCurl5a.maxpat
externals

[aka.shell] download from here: http://www.iamas.ac.jp/~aka/max/ – and add the path to the folder to Options | File Preferences in Max

authorization

  • xively.com feed id and api-key is embedded in max patch
  • you need a Twitter account
  • you need to set up a xively.com feed with twitter trigger, (as described here  https://reactivemusic.net/?p=6903) to get your own feed id, API-key, and authorize access to your Twitter account

instructions

  • Open the Max patch: tweetcurl5a.maxpat
  • enter your xively feed number and API-key into the fields (then press enter)
  • Type your Tweet text.
  • Press the big green button.

notes on curl

You can use curl for http: requests in Max by formatting the command line with [sprintf] and running it in [aka.shell]. There are a few idiosyncrasies – for example with escape sequences.

In tweetCurl5a.maxpat, the curl command is built in two sections:

  1. The request data is written to a data file /tmp/abc.json
  2.  the actual curl command is formatted and run from the command line. 
Here is the part of the patch which formats request data:

Using ‘quotes’ with [sprintf]

You’ll notice a lot of backslashes used in [sprintf]. This is done to preserve quotes. Normally a quote in [sprintf] indicates a string. Use 3 backslashes to escape a quote:

\\\"

Passing arguments into [sprintf]

The [sprintf] code is obtuse because we are formatting JSON data. The resulting data looks like this:

{ "id":95586, "datastreams":[{ "current_value":"this is a tweet", "id": "tweet"}]}

 

Note that you can pass arguments into [sprintf] using %s – but if you are using a [textedit] to collect data from the user, you’ll need to use [tosymbol] to consolidate the text into a single symbol before passing into [sprintf]

Here’s the code which writes the formatted JSON data to a file:

The next step is to format the curl command, which will read the JSON data file and send an http: request to cosm.com. Here you can see the [sprintf] for this command.

Redirecting aka.shell output to the Max window

At the very end of the [sprintf] you will see

>2&1

This is the linux method to redirect error messages and standard output from [aka.shell] to the same place, which in this case will be the Max window.

command line curl

By the way, here is what the curl command will look like on the command line

curl -v --request PUT --data-binary @/tmp/abc.json --header "X-ApiKey: abcdefg1234567" http://api.cosm.com/v2/feeds/95586.json 2>&1

 

Note: The actual ApiKey above has been replaced with: abcdefg1234567 – so that you don’t accidentally send embarrassing Tweets from my account.

Soundcloud API in Max

In this patch, Max uses the Soundcloud API to find available tracks for a user and then stream or download one of the tracks.

Features:
  • Resolve the user-id for a given Soundcloud user name – in this case “dannyzic”
  • Process the JSON response to get a track list
  • Request the first track as either a download or streaming file
  • Play the track in Max using [jit.qt.movie]

The Soundcloud API reference provides examples using curl.

http://developers.soundcloud.com/docs/api/reference

download

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

folder: soundcloud

files

main Max patch
  • soundcloud2.maxpat
abstractions and other files
  • sc-process-user-data.js
  • sc-process-track-data.js

authorization

  • The Soundcloud client-id is embedded in the Max patch. To get a client ID you will first need a Soundcloud account. Then register an app at: http://soundcloud.com/you/apps

instructions

  • Open the Max patch: soundcloud2
  • Unlock the patch and enter your client-id in the yellow [message] object in the upper right corner. Lock and save the patch.
  • Click the green button to resolve the Username: ‘dannyzic’
  • Click the blue button retrieve ‘tracks’ for this user
  • Click the yellow button to begin streaming the first available track
  • Optional: click the red button to download the track.

GPS on Raspberry Pi

Successfully installed this GPS board on the R-Pi.

By Kevin Townsend at adafruit.com

http://learn.adafruit.com/adafruit-ultimate-gps-on-the-raspberry-pi/introduction

The drivers for the console cable were already in the Raspian distribution on the R-Pi.

I installed the gpsd (daemon) software as directed in the above tutorial.

Documentation for gpsd is here:

http://gpsd.berlios.de/client-howto.html

Sample C code is: gpxlogger.c and cgps.c – which can be found in tkzic/rpi/gpsd 3.7/

(todo – write sample code and add to telemetry tracker)