talking to jit.net.send from outside max

Nov 6, 2006 at 7:03pm

talking to jit.net.send from outside max

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

#28548
Nov 6, 2006 at 7:13pm

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

#87792
Nov 6, 2006 at 7:13pm

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
>
>
>
>
>

#87793
Nov 6, 2006 at 8:04pm

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

#87794
Nov 6, 2006 at 9:38pm

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

#87795
Nov 6, 2006 at 10:06pm

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

#87796
Nov 6, 2006 at 10:52pm

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

#87797
Nov 6, 2006 at 11:07pm

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

#87798
Nov 7, 2006 at 10:01am

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

#87799
Nov 7, 2006 at 4:34pm

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

#87800
Nov 7, 2006 at 8:46pm

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
>
>
>
>
>
>
>
>
>

#87801
Nov 8, 2006 at 3:36am

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

#87802
Nov 8, 2006 at 12:59pm

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??
}

#87803
Nov 8, 2006 at 4:31pm

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??
> }
>
>
>
>
>
>
>
>
>

#87804
Nov 8, 2006 at 5:58pm

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.

#87805
Nov 8, 2006 at 7:22pm

> 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.
>
>
>

#87806
Nov 9, 2006 at 11:51am

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

#87807
Nov 9, 2006 at 7:43pm

> 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

#87808

You must be logged in to reply to this topic.