merci patco,
i have a hard time to spot your modifications in the semi-human-
readable php code without line breaks. could you paste it formatted
or just the changes?
thank you.
Am 07.10.2006 um 03:27 schrieb Patco:
Patco a écrit :
Max Neupert a écrit :
hi list,
i am trying to send a value from pd to a php page. i am using an udp connection vie netsend to fsockopen().
Hello, there is a php class for that: http://www.a2hd.com/software/OSC.phps The end of the file have to be modified, I've tested it once it's
more stable than netsend.attached is the modified php file Patco.
- Copyright 2003 * * Version 0.1 * * Requirements: PHP 4.1.0 or
later. * For information about Open Sound Control, * see http:// cnmat.berkeley.edu/OSC * * This is free software. * It may contain
bugs, design flaws or other unforseeable problems. * Please feel
free to report problems (or success stories) to the author. * *
License: LGPL version 2.1 or later. * * This library is free
software; you can redistribute it and/or * modify it under the
terms of the GNU Lesser General Public * License as published by
the Free Software Foundation; either * version 2.1 of the License,
or (at your option) any later version. * * This library is
distributed in the hope that it will be useful, * but WITHOUT ANY
WARRANTY; without even the implied warranty of * MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General
Public License for more details. * * You should have received a
copy of the GNU Lesser General Public * License along with this
library; if not, write to the Free Software * Foundation, Inc., 59
Temple Place, Suite 330, Boston, MA 02111-1307 USA * * For
questions regarding this library contact * Andy W. Schmeder */ //
Test if this machine is a little endian architecture function
test_little_endian() { $cpu_int = pack("L", 1); // Machine
dependent $be_int = pack("N", 1); // Machine independent if($cpu_int [0] == $be_int[0]) { return FALSE; } else { return TRUE; } } //
Test if this machine uses twos complement representation function
test_twos_complement() { $cpu_int = pack("i", -1); // Machine
dependent if(ord($cpu_int[0]) == 255) { return TRUE; } else
{ return FALSE; } } // Take note of the configuration for this
machine. $_arch_little_endian = test_little_endian();
$_arch_twos_complement = test_twos_complement(); if(!
$_arch_twos_complement) { trigger_error("WARNING: This machine does
not use twos-complement integers. " . "Negative numbers may not be
represented correctly.", E_USER_NOTICE); } /** This is a utility
function to convert from CPU byte order to network order (big
endian). * * It is necessary to use this function because PHP's pack () function does not support * big endian encoding for most data
types. (It only does big endian for unsigned ints). */ function
host_to_network_order($str) { global $_arch_little_endian; if ($_arch_little_endian) { $swstr = ""; for($i = 0; $i < strlen ($str); $i++) { $swstr .= $str[(strlen($str)-1)-$i]; } return
$swstr; } else { // No conversion necessary for big-endian arch
return $str; } } /** OSCDatagram is a virtual base class for
OSCMessage and OSCBundle. */ class OSCDatagram { // Virtual private
data var $bin = NULL; var $data = NULL; // Virtual functions
function get_binary() {} function clear() {} // Shared functions / ** Returns a semi-human readable representation of the binary data.
- Printable bytes will appear as "_C" where C is the printable
character. * Non-printable bytes will appear in hex, e.g. '20' for
a space (\s) character * Bytes are clustered in groups of 4 to show
the alignment. */ function get_human_readable() { $bin = $this-get_binary(); $hex = ""; for($i = 0; $i < strlen($bin); $i++) { if
(ord($bin[$i]) >= 33 && ord($bin[$i]) <= 126) { // Printable
characters $hex .= "_" . chr(ord($bin[$i])); } else { $hex .=
sprintf("%02x", ord($bin[$i])); } if($i != 0 && $i < strlen($bin)
&& ($i+1) % 4 == 0) { $hex .= " "; } } return $hex . "\n"; } /**
Pack data into $this->bin as 4-byte aligned, network-byte order. */
function pack_data($data, $type_hint) { $bin = ""; switch ($type_hint) { case "T": case "F": case "N": case "I": return; //
These types have no allocated space case "A": foreach($data as
$arg) { $this->pack_data($arg[0], $arg[1]); } break; case "s":
$data .= "\0"; // The builtin \0 terminator is ignored... we must
explicitly request one. $bin = pack("a*" . $this->get_strpad ($data), $data); break; case "b": $this->pack_data(strlen($data-bin), "i"); $bin = pack("a*" . $this->get_strpad($data->bin),
$data->bin); break; case "i": $bin = host_to_network_order(pack ("i", $data)); // Machine-independent size (4-bytes) break; case
"f": $bin = host_to_network_order(pack("f", $data)); // Machine- dependent size if(strlen($bin) != 4) { $this->error("Sorry, your
machine uses an unsupported single-precision floating point
size."); } break; case "d": $bin = host_to_network_order(pack("d",
$data)); // Machine-dependent size if(strlen($bin) != 8) { $this-error("Sorry, your machine uses an unsupported double-precision
floating point size."); } break; case "t": if(is_null($data))
{ $data = array(0, 1); } $bin = host_to_network_order(pack("L",
$data->sec)) . host_to_network_order(pack("L", $data->frac_sec));
break; } if(strlen($bin) % 4 != 0) { $this->error("$data failed to
align properly, size is " . strlen($bin) . " bytes."); } $this-bin .= $bin; } /** Utility to generate padding for strings */
function get_strpad($str) { $x = (strlen($str)) % 4; if($x == 0)
{ return ''; } else { $x = 4 - $x; } switch($x) { case 1: return
'x'; case 2: return 'xx'; case 3: return 'xxx'; default: $this-error("Pad calculation is screwy, x = $x"); } } /** Report an
error */ function error($message) { trigger_error("OSCDatagram
Error: $message", E_USER_ERROR); } } /** OSCMessage type */ class
OSCMessage extends OSCDatagram { var $address = "/"; var
$typetags = ","; var $data = array(); /** Make a new message -
Optionally specify address and arguements. * * e.g. $a = new
OSCMessage("/foo", array(1, 2.94, "bar")) * It is not possible to
provide type-hinting using this initialization method. */ function
OSCMessage($address = NULL, $args = NULL) { if(! is_null($address))
{ $this->address = $address; } if(is_array($args)) { foreach($args
as $arg) { $this->add_arg($arg); } } } /** Reset internal data
structures */ function clear() { $this->address = "/"; $this-typetags = ","; $this->data = array(); $this->bin = NULL; } /**
Set packet address * e.g. "/test". * See OSC spec for details on
allowed characters in an OSC address. */ function set_address ($addr) { $this->bin = NULL; $this->address = $addr; } /** Add an
arg to the OSC message. * $data can be an integer, float, string,
boolean, NULL, or an array of those types. * $type-hint is
optional. */ function add_arg($data, $type_hint = NULL) { $this-bin = NULL; if($type_hint == NULL) { $type_hint = $this->get_type
($data); } $data = $this->set_type($data, $type_hint); array_push ($this->data, array($data, $type_hint)); } /** Try to guess the
type of data. * If this does not work for you, try using a type- hint. */ function get_type($data) { switch(gettype($data)) { case
"integer": return "i"; case "double": case "float": return "f";
case "string": return "s"; case "boolean": if($data) { return
"T"; } else { return "F"; } case "array": // Array type will be
handled later... 'A' is not actually an OSC type. return "A"; case
"object": switch(strtolower(get_class($data))) { case "infinitum":
return "I"; case "timetag": return "t"; case "blob": return "b";
default: $this->error("Unknown or unsupported object type."); }
case "NULL": return "N"; default: $this->error("Unknown or
unsupported data type."); } } /** Cast data to type, and add type
info to typetags. */ function set_type($data, $type_tag) { switch ($type_tag) { case "i": $this->typetags .= "i"; return (int)$data;
case "f"; $this->typetags .= "f"; return (double)$data; case "d";
$this->typetags .= "d"; return (double)$data; case "s": case "c":
$this->typetags .= "s"; return (string)$data; case "T": $this-typetags .= "T"; return TRUE; case "F": $this->typetags .= "F";
return FALSE; case "N": $this->typetags .= "N"; return NULL; case
"I": $this->typetags .= "I"; return $data; case "t": $this-typetags .= "t"; return $data; case "b": $this->typetags .= "b";
return $data; case "A": // Array is now expanded... $this-
typetags .= "["; $data = (array)$data; for($i = 0; $i < count
($data); $i++) { $type_tag = $this->get_type($data[$i]); $data[$i]
= array($this->set_type($data[$i], $type_tag), $type_tag); } $this-typetags .= "]"; return $data; default: trigger_error
("Unrecognized type tag, '$type_tag'", E_USER_ERROR); } } function
get_binary() { // Check for cached binary representation and reuse
if found. if(! is_null($this->bin)) { return $this->bin; } // Pack
address... $this->pack_data($this->address, "s"); // Pack
typetags... $this->pack_data($this->typetags, "s"); // Pack args...
foreach($this->data as $arg) { $this->pack_data($arg[0], $arg [1]); } return $this->bin; } } /** OSCBundle datagram type * This
object can contain any number of other OSCDatagram objects. */
class OSCBundle extends OSCDatagram { var $data = array(); var
$timetag = NULL; /** Create a new OSCBundle datagram * * $init may
be an array of OSCDatagram objects, * e.g. $b = new OSCBundle(new
OSCMessage(...), new OSCBundle(...)) * * Otherwise, add messages at
runtime using OSCBundle::add_datagram. */ function OSCBundle($init
= NULL) { if(is_array($init)) { foreach($init as $d) { $this-add_datagram($d); } } } /** Set time tag as whole seconds since
July 1, 1970, and fraction of a second. * This feature is not
tested, but it should work if you need it. * * If timetag is not
set, it will default to "Immediate". */ function set_timetag ($timetag_obj) { $this->timetag = $timetag_obj; } /** Add an
OSCDatagram object to a bundle. * This can be either an OSCMessage
or an OSCBundle. * However, you cannot reasonably add a bundle to
itself. */ function add_datagram($osc_datagram) { $this->bin =
NULL; array_push($this->data, $osc_datagram); } function clear()
{ $this->bin = NULL; $this->data = NULL; } function get_binary()
{ if($this->bin != NULL) { return $this->bin; } $this->bin = "";
$this->pack_data("#bundle", "s"); $this->pack_data(NULL, "t");
foreach($this->data as $datagram) { $bin = $datagram->get_binary();
$this->pack_data((int)strlen($bin), "i"); $this->bin .= $bin; }
return $this->bin; } } /** OSCClient uses a connectionless UDP
socket to transmit binary to its destination. * * Example of use: *
- $c = new OSCClient(); * $c->set_destination("192.168.1.5", 3890);
- $c->send(new OSCMessage("/foo", array(1,2,3))); * ... etc. * *
Since it is connectionless, you can change the destination address/ port at any time. * If you are having problems establishing
communication, it may be due to a bad address, * improper setup of
the IP routing table, or a problem on the other end. When in doubt,
- use tcpdump or ethereal to check that packets are indeed being
transmitted. */ class OSCClient { var $sock = NULL; var $address
= NULL; var $port = NULL; function OSCClient($address = NULL, $port
= NULL) { $this->address = $address; $this->port = $port; if(($this-sock = socket_create(AF_INET, SOCK_DGRAM, 0)) < 0) { $this->error
("Could not create datagram socket."); } } /** Destructor function,
usually not needed, provided in case you want to free the socket.
*/ function destroy() { socket_close($this->sock); } /* // You can
enable this part if you have PHP 4.3.0 or later... function
enable_broadcast() { if(($ret = socket_set_option($this->sock,
SOL_SOCKET, SO_BROADCAST, 1)) < 0) { $this->error ("Failed to enable broadcast option."); } } function
disable_broadcast() { if(($ret = socket_set_option($this->sock,
SOL_SOCKET, SO_BROADCAST, 0)) < 0) { $this->error("Failed to
disable broadcast option."); } } */ /** Address is an IP address,
given as a string. * To convert a hostname to IP, use gethostbyname ('www.example.com') * You must also specify a port as an integer,
typically $port is larger than 1024. */ function set_destination ($address, $port) { $this->address = $address; $this->port =
$port; } /** send() accepts either an OSCDatagram object or a
binary string */ function send($message) { if(is_null($this-address) || is_null($this->port)) { $this->error("Destination is
not well-defined. Please use OSCClient::set_destination()."); } if (is_object($message)) { $message = $message->get_binary(); } if (($ret = socket_sendto($this->sock, $message, strlen($message), 0,
$this->address, $this->port)) < 0) { $this->error("Transmission
failure."); } if($ret != strlen($message)) { $mlen = strlen ($message); $this->error("Could not send the entire message, only
$ret bytes were sent, of $mlen total"); } return $ret; } /** Report
a fatal error. */ function error($message) { trigger_error ("OSCClient Error: $message", E_USER_ERROR); } } /** Object to
represent the OSC Infinitum type ("I") */ class Infinitum { } /**
64-bit OSC timetag type, Refer to NTP format for details. */ / **class Timetag { function Timetag($sec = 0, $frac_sec = 1) { $this-sec = $sec; $this->frac_sec = $frac_sec; } }*/ /** Binary Blob
datatype * Blob is basically a non-null-terminated string prefixed
by a size indicator. */ class Blob { function Blob($bin) { $this-bin = $bin; } } /** Run some tests to make sure the library
behaves in a sane way. the modifications begins here replace
localhost with server's adress and put the correct port */ function
test_osc_lib() { $c = new OSCClient(); $c->set_destination ("localhost", 3333); /** $m1 = new OSCMessage("/test", array(new
Timetag(3294967295, 5), new Infinitum(), new Blob("aoeuaoeu!")));
$m1->add_arg(28658.93, "d"); */ $m2 = new OSCMessage("/bar", array (test, one, two)); $b = new OSCBundle(); $b->add_datagram($m1); $b-add_datagram($m2); $b2 = new OSCBundle(array($m1, $b)); //echo $b2- get_human_readable(); //echo $m1->get_human_readable(); $c- send($m2); } // Uncomment to run the test test_osc_lib(); ?>