talking to jit.net.send from outside max


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

    • Nov 06 2006 | 7:13 pm
      I don't know how to send messages to the jit.net objects, but here's
      the spec for matrices:
      wes
    • Nov 06 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.
      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
      >
      >
      >
      >
      >
    • Nov 06 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.
      >
      >
      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
    • Nov 06 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|
    • Nov 06 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
    • Nov 06 2006 | 10:52 pm
      Here's a link to the start of a C++ class I made to send matrices into Jitter.
      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
    • Nov 06 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
    • Nov 07 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
    • Nov 07 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
    • Nov 07 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
      >
      >
      >
      >
      >
      >
      >
      >
      >
    • Nov 08 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
    • Nov 08 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 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??
      }
    • Nov 08 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 > 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??
      > }
      >
      >
      >
      >
      >
      >
      >
      >
      >
    • Nov 08 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.
    • Nov 08 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))< #define SWAP32(x) ((long)(((((unsigned
      long)(x))>>24L)&0x000000ff)+((((unsigned long)(x))>>8L)&0x0000ff00)+
      ((((unsigned long)(x))< long)(x))<
      (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.
      >
      >
      >
    • Nov 09 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
    • Nov 09 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