Twitter streaming from php to Max

update 6/2014 – This project is part of the Internet sensors projects: https://reactivemusic.net/?p=5859. Check the link for current versions.

original post

notes

Got a test patch running today which breaks out tweets (in php and curl) and sends them to Max via Osc.

(update) Have parsed data to remove  hyperlinks and Twitter symbols.

It took some tweaking of global variables in php – and probably would be better written using classes (as in this example: http://stackoverflow.com/questions/1397234/php-curl-read-incrementally – see post from GZipp.

Max patch: tkzic/max teaching examples/twitter-php-streamer1.maxpat

php code: twitterStreamMax.php

<?php

// max-osc-play.php
//
//	collection of php OSC code from Max stock-market thing
//

include 'udp.php';		// udp data sending stuff

$DESTINATION = 'localhost';
$SENDPORT = '7400';
$RECVPORT = '7401';

//////////////////////////////////////////////////////////////////////////////////////////

	$USERNAME = 'username';
	$PASSWORD = 'password';
	$QUERY    = 'cats';		// the hashtag # is optional

	// these variables are defined as global so they can be used inside the write callback function
	global $osc;
	global $kount;

	// initialize OSC
	$osc = new OSCClient();  // OSC object
	$osc->set_destination($DESTINATION, $SENDPORT);

	// This amazing program uses curl to access the Twitter streaming API and breaks the data
	// into individual tweets which can be saved in a database, sent out via OSC, or whatever
	//

	/**
	 * Called every time a chunk of data is read, this will be a json encoded message
	 * 
	 * @param resource $handle The curl handle
	 * @param string   $data   The data chunk (json message)
	 */
	function writeCallback($handle, $data)
	{
	    /*
	    echo "-----------------------------------------------------------\n";
	    echo $data;
	    echo "-----------------------------------------------------------\n";
	    */

		$maxdata = "/tweet" ;				// header - begin   
		global $kount;					// test counter
		global $osc;						// osc object

	    $json = json_decode($data);
	    if (isset($json->user) && isset($json->text)) {

			// here we have a single tweet
	        echo "@{$json->user->screen_name}: {$json->text}\n\n";

			// do some cleaning up...
			// remove URL's
			$s = $json->text;		// raw tweet text

			// ok now need to do the same thing below for URL,s RT's @'s etc., 
			// and then remove redundant spaces	
			/* example
			Depending on how greedy you'd like to be, you could do something like:

			$pg_url = preg_replace("/[^a-zA-Z 0-9]+/", " ", $pg_url);

			This will replace anything that isn't a letter, number or space

			*/		

			// display all hashtags and their indices
			foreach( $json->entities->hashtags as $obj )
			{
			  echo "#:{$obj->text}\n";		// display hashtag
			  // get rid of the hashtag
			 	// note: this gets rid of all hashtags, which could obscure the meaning of the tweet, if
				// the hashtag is used inside a sentence like: "my #cat is purple" - would be changed to: "my is purple"
				// so we could use some intelligent parsing here...

			//  $s = str_replace("#{$obj->text}", "", $s );

			// this is a more benign approach, which leaves the word but removes the #

			$s = str_replace("#{$obj->text}", "{$obj->text}", $s );

			}

			foreach( $json->entities->urls as $obj )
			{
			  echo "U:{$obj->url}\n";		// display url			
			  $s = str_replace("{$obj->url}", "", $s );   // get rid of the url		
			}

			foreach( $json->entities->user_mentions as $obj )
			{
				echo "@:{$obj->screen_name}\n";		// display 			
				$s = str_replace("RT @{$obj->screen_name}:", "", $s );   // get rid of re-tweets
				$s = str_replace("@{$obj->screen_name}:", "", $s );   // get rid of other user mentions
				$s = str_replace("@{$obj->screen_name}", "", $s );   // get rid of other user mentions		
			}

			// $s = str_replace("RT ", "", $s );   // get rid of RT's (re-tweet indicators)

			// $s = preg_replace( '/[^[:print:]]/', '',$s); // remove non printable characters

			$s = htmlspecialchars_decode($s);		// decode stuff like &gt;

			$s = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\x9F]/u', '', $s); // get rid of unicode junk

			$s = preg_replace('/[^(\x20-\x7F)]*/','', $s);		// get rid of other non printable stuff

			$s = preg_replace('!\s+!', ' ', $s);	// remove redundant white space

			echo "revised tweet: {$s}\n";

			$maxdata = "/tweet " . "{$json->text}";
			// $maxdata = $maxdata . " " . $kount++;
		   	$osc->send(new OSCMessage($maxdata));

	    }

	    return strlen($data);
	}

// initialize OSC 

// initialize curl

	$ch = curl_init();

	curl_setopt($ch, CURLOPT_URL, 'https://stream.twitter.com/1/statuses/filter.json?track=' . urlencode($QUERY));
	curl_setopt($ch, CURLOPT_USERPWD, "$USERNAME:$PASSWORD");
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'writeCallback');
	curl_setopt($ch, CURLOPT_TIMEOUT, 20); // disconnect after 20 seconds for testing
	curl_setopt($ch, CURLOPT_VERBOSE, 1);  // debugging
	curl_setopt($ch, CURLOPT_ENCODING,  'gzip, deflate'); // req'd to get gzip
	curl_setopt($ch, CURLOPT_USERAGENT, 'tstreamer/1.0'); // req'd to get gzip

	curl_exec($ch); // commence streaming

	$info = curl_getinfo($ch);

	var_dump($info);

?>

data recording

Thoughts on a streaming API project model with Max.

I’ve been trying to come up with generalized methods to handle the class of Max projects which read a stream of data from the Web, and use it to trigger events, for example, sound and graphics.

OSC is generally a good way to get data into Max from Web API’s. One issue with data streams, is that they do not always provide a constant flow. In some cases, this is what makes them musical. The rhythm of the flow becomes the rhythm of the music.

But in some cases we are vexed by too little flow or too much.

When the flow is too sparse, and the project requires a constant flow – the stream can be fattened up by using a [metro] object to output the current stream value at a higher frequency.

When the flow is too fast – you can use [speedlim] for numbers – but not for text data like tweets about cats, which seem to stream in like a flood. One solution is to use a data-recorder, like our modified CNMAT list recorder in the Irish Train project.

You would need separate access to the record and play ‘heads’ – so for example you could record in real time, but start playing back at a slower rate (while the recording continues). This is essentially a form of stream buffering. The data recorder approach would also allow you to use various algorithms to ‘thin’ the data – for example, to keep up with the real time rate, but by using less of the data.

[update] got this working with the modified CNMAT data recorder patch. It allows separate control of recording and playback, simultaneously.

patch is in tkzic/max teaching examples/ data-recorder-tester.maxpat

 

Osc in php

The Osc code from the stock market music project https://reactivemusic.net/?p=12029 is not really doing Osc.

But… it works well going from php->max. In the other direction its using a kluge of nc and an alarm clock shell program – to receive messages from Max in UDP, but its really kind of horrible – so I’m going to look again for an OSC library in php.

update 2/2013 This is hard to believe, but I haven’t yet found a real OSC libraries for php. Apparently php is so uncool, that nobody wants to write for it anymore. Anyway, the code above, works unidirectionally, so its of some use for existing php code.

Local files are max-php-osc-tester.maxpat and max-osc-play.php in tkzic/api

Analysis that might help with parsing:

from Captain Caveman

http://forum.cockos.com/showthread.php?t=99076

 

Twitter streaming php decoder breaks out individual tweets

This code was adapted (i.e. stolen verbatim) from a stackoverflow post by drew010

http://stackoverflow.com/questions/10337984/using-the-curl-output

Here’s the code. It solves a huge problem for the class of projects which need to grab a large amount of tweets in real time to either save in a database, or trigger some action.

My version of the code is in tkzic/api/twitterStream1.php

<?php

$USERNAME = 'youruser';
$PASSWORD = 'yourpass';
$QUERY    = 'nike';

/**
 * Called every time a chunk of data is read, this will be a json encoded message
 * 
 * @param resource $handle The curl handle
 * @param string   $data   The data chunk (json message)
 */
function writeCallback($handle, $data)
{
    /*
    echo "-----------------------------------------------------------\n";
    echo $data;
    echo "-----------------------------------------------------------\n";
    */

    $json = json_decode($data);
    if (isset($json->user) && isset($json->text)) {
        echo "@{$json->user->screen_name}: {$json->text}\n\n";
    }

    return strlen($data);
}

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://stream.twitter.com/1/statuses/filter.json?track=' . urlencode($QUERY));
curl_setopt($ch, CURLOPT_USERPWD, "$USERNAME:$PASSWORD");
curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'writeCallback');
curl_setopt($ch, CURLOPT_TIMEOUT, 20); // disconnect after 20 seconds for testing
curl_setopt($ch, CURLOPT_VERBOSE, 1);  // debugging
curl_setopt($ch, CURLOPT_ENCODING,  'gzip, deflate'); // req'd to get gzip
curl_setopt($ch, CURLOPT_USERAGENT, 'tstreamer/1.0'); // req'd to get gzip

curl_exec($ch); // commence streaming

$info = curl_getinfo($ch);

var_dump($info);

Csound in Pure Data on Raspberry-Pi

Today I got Csound running inside Pure Data (using the [csoundapi~] object) on Raspberry-Pi.

These instructions assume you have already installed pd-extended on R-Pi. See this post to learn how. https://reactivemusic.net/?p=4930

Install Csound

# sudo apt-get install cloud

Install csoundapi~

# sudo apt-get install pd-csound

Copy csoundapi~ library into the pd-extended extras folder

# cd /usr/lib/pd/csound/extras
# sudo cp csoundapi~.pd_linux ../../pd-extended/extra

Here’s a test patch:

Here’s the Csound source file (should be in the same folder as the test patch)

<CsoundSynthesizer>
<CsOptions>
</CsOptions>
<CsInstruments>
;Example by Joachim Heintz

sr = 44100
nchnls = 2
0dbfs = 1
ksmps = 8

giSine    ftgen     0, 0, 2^10, 10, 1

instr 1
kFreq     invalue   "freq"
kAmp      invalue   "amp"
aSin      oscili    kAmp, kFreq, giSine
          outs      aSin, aSin
endin

</CsInstruments>
<CsScore>
i 1 0 10000
</CsScore>
</CsoundSynthesizer>

Here are the source files:

http://zerokidz.com/rpi/csound/cstest2.pd

http://zerokidz.com/rpi/csound/control.csd

Here’s the command line to run the test:

# pd-extended -nogui -noadc cstest2.pd

Here are general instructions on running csound in Pure Data from Victor Lazzarini:

http://booki.flossmanuals.net/csound/_draft/_v/1.0/csound-in-pd/

 

csoundapi~ in Pd

notes

A preliminary test before trying this in Raspberry-Pi, I used the general instructions for csound in pd from Victor Lazzarini found here:

http://booki.flossmanuals.net/csound/_draft/_v/1.0/csound-in-pd/

to get csound running in pd-extended in Mac OS.

Looks pretty straightforward – biggest question will be compiling the external if it doesn’t install via package manager.

local test files are in tkzic/rpi/pd/csound

Here’s something from Victor Lazzarini which shows csound running on R-Pi

http://csound.1045644.n5.nabble.com/csound-on-raspberry-pi-td5718623.html

Here is installation instructions from Richard Dobson

http://csound.1045644.n5.nabble.com/Raspberry-Pi-w-Csound-td5717410.html

 

 

Running http: requests from Max

notes
  1. How to separate the status return code  from the actual response data?

For jit.uldl-  status reports get sent out the right outlet and errors are reported in the Max window. However their doesn’t appear to be a way to get the http: status codes or other header data.

For curl, you can write the response (JSON for example) to a file. Then you can read the file using the [js] object and parse the JSON. If you are using [aka.shell] to run the curl command, the stdout and stderr can be routed from the object – for instance, into the Max window. The -v flag (verbose mode) causes curl to output a bunch of header data.

 

 

 

 

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