Forums > Dev

talking to jit.net.send from outside max

November 6, 2006 | 7:03 pm

Hi,

I’m trying to stream data from the localhost tcp to max, from another
application (c++). I tried Olaf Matthes’ netsend externals, but I’m having
some trouble (could be me) and prefer to not use 3rd party externals. The
only tcp externals in max afaik are jit.net.send/recv.

If I open up a socket from my application, jit.net.recv indicates there is a
connection, but if I send something like a string or double, it doesn’t
output anything. Using the same code with netreceive does give me output in
max.

Do I have to format data in a specific way in order to be compatible with
jit.net.recv??

cheers, -thijs


November 6, 2006 | 7:13 pm

I don’t know how to send messages to the jit.net objects, but here’s
the spec for matrices:

http://cycling74.com/twiki/bin/view/ProductDocumentation/JitterSdkNetworkingSpec

wes


November 6, 2006 | 7:13 pm

Hi Thijs,

Yes, you have to format data carefully. The below link from the
Jitter SDK gives details about working with the jit.net objects.

http://cycling74.com/twiki/bin/view/ProductDocumentation/JitterSdkNetworkingSpec

Ben

On 11/6/06, Thijs Koerselman

wrote:
> Hi,
>
> I’m trying to stream data from the localhost tcp to max, from another
> application (c++). I tried Olaf Matthes’ netsend externals, but I’m having
> some trouble (could be me) and prefer to not use 3rd party externals. The
> only tcp externals in max afaik are jit.net.send/recv.
>
> If I open up a socket from my application, jit.net.recv indicates there is a
> connection, but if I send something like a string or double, it doesn’t
> output anything. Using the same code with netreceive does give me output in
> max.
>
> Do I have to format data in a specific way in order to be compatible with
> jit.net.recv??
>
> cheers, -thijs
>
>
>
>
>


November 6, 2006 | 8:04 pm

On 11/6/06, Ben Nevile wrote:
>
> Hi Thijs,
>
> Yes, you have to format data carefully. The below link from the
> Jitter SDK gives details about working with the jit.net objects.
>
>
> http://cycling74.com/twiki/bin/view/ProductDocumentation/JitterSdkNetworkingSpec

Ah thanks guys! I was already looking into OSC using UDP but that involves
careful formatting too. I need to send a lot of data (100fps motion capture)
which is then processed by jitter, so I think my best bet is to format it
into jitter matrices.

cheers, -thijs


November 6, 2006 | 9:38 pm

Blinkenlights is an alternative format that might be easier to use
than Jitter matrices, and there are externals that convert the format
to/from Jitter. However, if you suffer from tritosphobia
(tritossymballomenomerosphobia?), as you say, then there’s no point
in plugging jit.bixcp.to/jit.bixcp.from, never mind the extended
versions in Litter Bundle for Jitter.

Oops.-)

On 6-Nov-2006, at 21:04, Thijs Koerselman wrote:

> I need to send a lot of data (100fps motion capture) which is then
> processed by jitter, so I think my best bet is to format it into
> jitter matrices.

————– http://www.bek.no/~pcastine/Litter/ ————-
Peter Castine +–> Litter Power & Litter Bundle for Jitter
Universal Binaries on the way
iCE: Sequencing, Recording &
Interface Building for |home | chez nous|
Max/MSP Extremely cool |bei uns | i nostri|
http://www.dspaudio.com/ http://www.castine.de


November 6, 2006 | 10:06 pm

On Nov 6, 2006, at 11:13 AM, Wesley Smith wrote:

> I don’t know how to send messages to the jit.net objects,

This is almost covered by the last paragraph and the gimme_deserialize
() code, but it’s missing some crucial information. Thanks for
pointing this out.

First, it’s missing the chunk description, which begins with a big
endian chunk id ‘JMMP’, followed by a big endian 32 bit integer
chunk size, then the data such as the gimme_deserialize() code
expects. It’s also missing the actual values of the
ATOM_SERIALIZATION_*_CODE ids. These are single char values:

#define ATOM_SERIALIZATION_SYMBOL_CODE ‘s’
#define ATOM_SERIALIZATION_LONG_CODE ‘l’
#define ATOM_SERIALIZATION_FLOAT_CODE ‘f’

We can remedy this and and add perhaps add a gimme_serialize()
example to the SDK documentation, but let us know if the above
doesn’t work for you.

-Joshua


November 6, 2006 | 10:52 pm

Here’s a link to the start of a C++ class I made to send matrices into Jitter.

http://www.mat.ucsb.edu/~whsmith/Jit-Net-TCP.zip

I only spent a day on it, so it is poorly factored and a bit sloppy,
but it works and is at least easy to see what’s going on so you won’t
have to start from scratch. It uses BSD sockets for doing TCP.

wes


November 6, 2006 | 11:07 pm

On Nov 6, 2006, at 2:06 PM, Joshua Kit Clayton wrote:

>> I don’t know how to send messages to the jit.net objects,
>
> This is almost covered by the last paragraph and the
> gimme_deserialize() code, but it’s missing some crucial
> information. Thanks for pointing this out.

Upon closer read of this doc (glanced too quickly), it looks like
it’s all covered in the packet header description at top and the last
paragraph text. Sorry for the noise.

-Joshua


November 7, 2006 | 10:01 am

On 11/6/06, Joshua Kit Clayton wrote:
>
>
> > This is almost covered by the last paragraph and the
> > gimme_deserialize() code, but it’s missing some crucial
> > information. Thanks for pointing this out.
>
> Upon closer read of this doc (glanced too quickly), it looks like
> it’s all covered in the packet header description at top and the last
> paragraph text. Sorry for the noise.

Thanks for all the help, and thanks Wes for the example! I don’t expect much
trouble now. (fingers crossed). I already figured I had to define the
serialization codes myself, but since they are mentioned like you said, that
wasn’t too difficult ;-)

cheers, -thijs


November 7, 2006 | 4:34 pm

ok, got to the point where I start hurting myself…. I took the example
Wesley posted, modified it to use winsock (cause that’s what the rest of my
project is using) and cleaned it up. I cannot find anything wrong.

-socket is created and connected
-no errors from the send functions, amount of bytes send is correct.
-i send the 2 headers first, than the data, everything in there seems fine.
Header sizes and content info are correct.

nothing happens in jitter, except that it tells me jit.net.recv connected,
like it should.

I’m not sure how to use the recv function inside my code, or what I should
do with the latency packet, so I’m not using those right now. Can that have
anything to do with it?

If someone wants to take a look at my code I’d really appreciate it. I
cleaned it up and think its very clear.

-exampleclient.cpp contains main program
-jitnet.h/cpp contains class for connecting and sending data to jitter.

cheers, -thijs


November 7, 2006 | 8:46 pm

Hi Thijs,

Are you doing this work on Windows? All information needs to be sent
in big-endian format.

Ben

On 11/7/06, Thijs Koerselman

wrote:
> ok, got to the point where I start hurting myself…. I took the example
> Wesley posted, modified it to use winsock (cause that’s what the rest of my
> project is using) and cleaned it up. I cannot find anything wrong.
>
> -socket is created and connected
> -no errors from the send functions, amount of bytes send is correct.
> -i send the 2 headers first, than the data, everything in there seems fine.
> Header sizes and content info are correct.
>
> nothing happens in jitter, except that it tells me jit.net.recv connected,
> like it should.
>
> I’m not sure how to use the recv function inside my code, or what I should
> do with the latency packet, so I’m not using those right now. Can that have
> anything to do with it?
>
> If someone wants to take a look at my code I’d really appreciate it. I
> cleaned it up and think its very clear.
>
>
> -exampleclient.cpp contains main program
> -jitnet.h/cpp contains class for connecting and sending data to jitter.
>
>
> cheers, -thijs
>
>
>
>
>
>
>
>
>


November 8, 2006 | 3:36 am

On 11/7/06, Ben Nevile wrote:
>
> Hi Thijs,
>
> Are you doing this work on Windows? All information needs to be sent
> in big-endian format.

Hi Ben, that’s something I haven’t really thought about :-) I’ll look into
it tomorrow when I get back to work. I know what it’s about, but I never had
to deal with that before. thanks for pointing it out, hope that’s it.

best, -thijs


November 8, 2006 | 12:59 pm

So I converted my headers to big endian, using the htonl() function. Max
crashes upon sending the second (288-byte) header. Nothing is attached to
the jit.net.recv object, so this crash has to be because I’m sending invalid
data.

Below is the function I use to create the headers. Anything wrong with it? I
also looked for a way to convert the double "time" but I can’t seem to find
anything about reversing the byte order of 64bit types. Am I not supposed to
use the htonl/htons functions for byte ordering? They only support unsigned
16 and 32 bit types(?)

cheers, -thijs

void CJitNet :: makeMatrixHeader(int planecount, int type, int *dim, int
dimcount)
{
long i;
int typeSize;

switch(type)
{
case 3: typeSize = sizeof(double);
break;
case 2: typeSize = sizeof(float);
break;
case 1: typeSize = sizeof(long);
break;
case 0:
default: typeSize = sizeof(char);
break;
}
m_chunkHeader.id = htonl(JIT_MATRIX_PACKET_ID);
m_chunkHeader.size = htonl(sizeof(t_jit_net_packet_matrix));

m_matrixHeader.id = htonl(JIT_MATRIX_PACKET_ID);
m_matrixHeader.size = htonl(sizeof(t_jit_net_packet_matrix));
m_matrixHeader.planecount = htonl(planecount);
m_matrixHeader.type = htonl(type);
m_matrixHeader.dimcount = htonl(dimcount);

for(i=0; i < dimcount; i++) {
m_matrixHeader.dim[i] = htonl(dim[i]);
}

while(i < JIT_MATRIX_MAX_DIMCOUNT) {
m_matrixHeader.dim[i] = 0L;
i++;
}
//special case for first value
m_matrixHeader.dimstride[0] = htonl(typeSize * planecount);

for(i=1; i < = dimcount; i++) {
m_matrixHeader.dimstride[i] =
htonl(dim[i-1]*m_matrixHeader.dimstride[i-1]);
}

while(i < JIT_MATRIX_MAX_DIMCOUNT) {
m_matrixHeader.dimstride[i] = 0L;
i++;
}
m_matrixHeader.datasize
htonl(m_matrixHeader.dimstride[dimcount-1]*m_matrixHeader.dim[dimcount-1]);
m_matrixHeader.time = 0.0; // 64bit byte order conversion??
}


November 8, 2006 | 4:31 pm

Hi Thijs,

You can look at jit.byteorder.h to see how we handle byte reordering
in jitter. That header uses the below two functions:

float swapf32(float f){
unsigned char c,*a;

a = (unsigned char *)&f;
c=a[3]; a[3]=a[0]; a[0]=c;
c=a[2]; a[2]=a[1]; a[1]=c;

return f;
}

double swapf64(double f){
unsigned char c,*a;

a = (unsigned char *)&f;
c=a[7]; a[7]=a[0]; a[0]=c;
c=a[6]; a[6]=a[1]; a[1]=c;
c=a[5]; a[5]=a[2]; a[2]=c;
c=a[4]; a[4]=a[3]; a[3]=c;

return f;
}

On 11/8/06, Thijs Koerselman

wrote:
> So I converted my headers to big endian, using the htonl() function. Max
> crashes upon sending the second (288-byte) header. Nothing is attached to
> the jit.net.recv object, so this crash has to be because I’m sending invalid
> data.
>
> Below is the function I use to create the headers. Anything wrong with it? I
> also looked for a way to convert the double "time" but I can’t seem to find
> anything about reversing the byte order of 64bit types. Am I not supposed to
> use the htonl/htons functions for byte ordering? They only support unsigned
> 16 and 32 bit types(?)
>
> cheers, -thijs
>
>
> void CJitNet :: makeMatrixHeader(int planecount, int type, int *dim, int
> dimcount)
> {
> long i;
> int typeSize;
>
> switch(type)
> {
> case 3: typeSize = sizeof(double);
> break;
> case 2: typeSize = sizeof(float);
> break;
> case 1: typeSize = sizeof(long);
> break;
> case 0:
> default: typeSize = sizeof(char);
> break;
> }
> m_chunkHeader.id = htonl(JIT_MATRIX_PACKET_ID);
> m_chunkHeader.size =
> htonl(sizeof(t_jit_net_packet_matrix));
>
> m_matrixHeader.id = htonl(JIT_MATRIX_PACKET_ID);
> m_matrixHeader.size =
> htonl(sizeof(t_jit_net_packet_matrix));
> m_matrixHeader.planecount = htonl(planecount);
> m_matrixHeader.type = htonl(type);
> m_matrixHeader.dimcount = htonl(dimcount);
>
> for(i=0; i < dimcount; i++) {
> m_matrixHeader.dim[i] = htonl(dim[i]);
> }
>
> while(i < JIT_MATRIX_MAX_DIMCOUNT) {
> m_matrixHeader.dim[i] = 0L;
> i++;
> }
> //special case for first value
> m_matrixHeader.dimstride[0] = htonl(typeSize * planecount);
>
> for(i=1; i < = dimcount; i++) {
> m_matrixHeader.dimstride[i] =
> htonl(dim[i-1]*m_matrixHeader.dimstride[i-1]);
> }
>
> while(i < JIT_MATRIX_MAX_DIMCOUNT) {
> m_matrixHeader.dimstride[i] = 0L;
> i++;
> }
> m_matrixHeader.datasize
> htonl(m_matrixHeader.dimstride[dimcount-1]*m_matrixHeader.dim[dimcount-1]);
> m_matrixHeader.time = 0.0; // 64bit byte order conversion??
> }
>
>
>
>
>
>
>
>
>


November 8, 2006 | 5:58 pm

On 8-Nov-2006, at 17:31, Ben Nevile wrote:
> That header uses the below two functions:

Yeah, you _can_ do it that way, but only the following will warm the
true C coder’s heart (salt to taste for floats and doubles):

UInt32
ReverseBytes(
UInt32 iBytes)

{
iBytes = ((iBytes >> 8) & 0x00ff00ff) | ((iBytes < < 8) &
0xff00ff00);
return ((iBytes >> 16) & 0x0000ffff) | ((iBytes < < 16) &
0xffff0000);
}

– Because you didn’t ask for it, P.


November 8, 2006 | 7:22 pm

> Yeah, you _can_ do it that way, but only the following will warm the
> true C coder’s heart

Oh Peter, I can always count on you to brighten my day! We use macros
in jit.byteorder.h:

#define SWAP16(x) ((short)(((((unsigned
short)(x))>>8)&0x00ff)+((((unsigned short)(x))< <8)&0xff00)))
#define SWAP32(x) ((long)(((((unsigned
long)(x))>>24L)&0x000000ff)+((((unsigned long)(x))>>8L)&0x0000ff00)+
((((unsigned long)(x))< <24L)&0xff000000)+((((unsigned
long)(x))< <8L)&0x00ff0000)))

(salt to taste for floats and doubles):
>
> UInt32
> ReverseBytes(
> UInt32 iBytes)
>
> {
> iBytes = ((iBytes >> 8) & 0x00ff00ff) | ((iBytes < < 8) &
> 0xff00ff00);
> return ((iBytes >> 16) & 0x0000ffff) | ((iBytes < < 16) &
> 0xffff0000);
> }
>
> — Because you didn’t ask for it, P.
>
>
>


November 9, 2006 | 11:51 am

Thank you so much guys! I finally got it all working. I took me a while to
iron out some bugs that were hard to find. In the end everything was related
to byteorder or header formatting.

I noticed that if you send the matrix header packet, and you use an invalid
id, jit.net.recv crashes. It would be nice if it generates a error message
instead;-)

I’m still in the dark about the time attribute and the latency packet. Can I
just ignore these? The latency info is just for analysing the connection
right?

Anyways I’m happy it’s working now.

cheers, -thijs


November 9, 2006 | 7:43 pm

> I noticed that if you send the matrix header packet, and you use an invalid
> id, jit.net.recv crashes. It would be nice if it generates a error message
> instead;-)

agreed, but this change won’t happen for a long time.

> I’m still in the dark about the time attribute and the latency packet. Can I
> just ignore these?

Yes.

Ben


Viewing 18 posts - 1 through 18 (of 18 total)