Big trouble with a max object I made: addftx not working properly on Windows, working perfectly on O


    Mar 14 2006 | 2:11 pm
    Hello,
    I have an object with 5 inlets. In new, I'm doing:
    floatin(x,4);
    intin(x,3);
    intin(x,2);
    intin(x,1);
    in main, I'm doing:
    addint((method)testobj_int);
    addinx((method)testobj_in1, 1);
    addinx((method)testobj_in2, 2);
    addinx((method)testobj_in3, 3);
    addftx((method)testobj_ft4, 4);
    This object just post out the value received from the inlet.
    It's working perfectly on Mac. On Windows, the float inlet is receiving
    random big big values.
    I don't know what's wrong?
    - my code
    - my VCPROJ options
    - my maxmsp sdk install
    - anything else
    (problem is not in %f, because before being empty, my object was sending
    values to an outlet, and the value sent was also wrong).
    Attached, mxo for OSX, mxe for XP, source and win project.
    Best regards and thanks for your help,
    Chris
    NB: (maxmsp 457)
    Results of the patch on windows:
    sending an int gives:
    ft4=0.000000
    in3=11
    in2=11
    in1=11
    sending a float gives :
    ft4=-36893488147419103000.000000
    in3=0
    in2=0
    in1=0
    The patch is:
    #include "ext.h"
    typedef struct testobj
    {
    Object x_ob;
    } t_testobj;
    void *testobj_class;
    void testobj_int(t_testobj *x, long n);
    void testobj_in1(t_testobj *x, long n);
    void testobj_in2(t_testobj *x, long n);
    void testobj_in3(t_testobj *x, long n);
    void testobj_ft4(t_testobj *x, float g);
    void *testobj_new(Symbol *s);
    void main(void)
    {
    setup((t_messlist **)&testobj_class, (method)testobj_new, 0L,
    (short)sizeof(t_testobj), 0L, 0);
    addint((method)testobj_int);
    addinx((method)testobj_in1, 1);
    addinx((method)testobj_in2, 2);
    addinx((method)testobj_in3, 3);
    addftx((method)testobj_ft4, 4);
    }
    void testobj_int(t_testobj *x, long n) { post("int=%d",n); }
    void testobj_in1(t_testobj *x, long n) { post("in1=%d",n); }
    void testobj_in2(t_testobj *x, long n) { post("in2=%d",n); }
    void testobj_in3(t_testobj *x, long n) { post("in3=%d",n); }
    void testobj_ft4(t_testobj *x, float g) { post("ft4=%f",g); }
    void *testobj_new(Symbol *s)
    {
    t_testobj *x = (t_testobj *)newobject(testobj_class);
    floatin(x,4);
    intin(x,3);
    intin(x,2);
    intin(x,1);
    return(x);
    }

    • Mar 14 2006 | 2:15 pm
      On Windows, arguments using float values must be doubles.
      jb
    • Mar 14 2006 | 2:17 pm
      Hi Chris,
      as far as i know (although being biased by PureData), float handlers
      take double arguments, like in
      void testobj_ft4(t_testobj *x, double g);
      greetings,
      Thomas
      --
      Thomas Grill
    • Mar 14 2006 | 2:25 pm
      not sure, but I remember functions which interface with max need to use
      double instead of float. Try this:
      void testobj_ft4(t_testobj *x, double g);
      void testobj_ft4(t_testobj *x, double g) { post("ft4=%f",g); }
      hth, t_
    • Mar 14 2006 | 2:27 pm
      I need to type faster, 3rd place damn it ;-)
      t_
    • Mar 14 2006 | 2:29 pm
      Thijs Koerselman schrieb:
      > not sure, but I remember functions which interface with max need to
      > use double instead of float. Try this:
      >
      > void testobj_ft4(t_testobj *x, double g);
      > void testobj_ft4(t_testobj *x, double g) { post("ft4=%f",g); }
      it's
      void testobj_ft4(t_testobj *x, double g) { post("ft4=%lf",g); }
      greetings,
      Thomas
      --
      Thomas Grill
    • Mar 14 2006 | 2:36 pm
    • Mar 14 2006 | 2:42 pm
      Yes, go ahead and use double for both.
      jb
    • Mar 14 2006 | 2:49 pm
      On 14-Mar-2006, at 15:27, Thijs Koerselman wrote:
      > I need to type faster, 3rd place damn it ;-)
      And I need to read faster, I don't even rate an honorable mention
      this time %-}
      The float/double thing is up there in the top 3 max-dev FAQs. And it
      is, admittedly, a little weird that all Mac compilers nowadays
      default to double-precision when they see float in a function
      prototype while Windows compilers (universally?) insist on single-
      precision.
      Given that there's no list FAQ, it would be, imho, a Good Idea(tm) if
      the SDK uniformly used explicit double in all sample code. I can
      understand if this is not the absolute highest priority at C74.
      My highest priorities are cool new stuff for Litter Power and iCE, so
      I'll get back to work (and miss the next opportunity to be a hero for
      a minute).
      -- P.
      -------------- http://www.bek.no/~pcastine/Litter/ -------------
      Peter Castine | +--> Litter Power & Litter Bundle for Jitter
      |....................................................
      p@castine.de | iCE: Sequencing, Recording, and Interface Building
      pcastine@gmx.net | for Max/MSP
      pcastine@bek.no | http://www.dspaudio.com/ Extremely cool
      4-15@kagi.com |....................................................
      | home|chez nous|wir|i nostri http://www.castine.de/
    • Mar 14 2006 | 3:02 pm
      > The float/double thing is up there in the top 3 max-dev FAQs. And it is,
      > admittedly, a little weird that all Mac compilers nowadays default to
      > double-precision when they see float in a function prototype while
      I don't understand...
      calling this code in my objects
      void myfunc(float f);
      void test()
      {
      post("sizeof(float)=%d
      sizeof(double)=%dn",sizeof(float),sizeof(double));
      myfunc(1.0f);
      }
      void myfunc(float f)
      {
      post("sizeof(f)=%dn",sizeof(f));
      }
      gives as result:
      sizeof(float)=4 sizeof(double)=8
      sizeof(f)=4
    • Mar 14 2006 | 6:27 pm
      I"m not quite sure what your code is telling us and I am not
      convinced it is telling us what you think it's telling us (or what I
      think you think it thinks it's telling us). Looking at the
      disassembled code may be instructive and not a little surprising (see
      below).
      In any case, Max passes de-atomized floats as 64-bit IEEE-754 double-
      precision values to your functions. That's the Max API, like it or
      love it.
      On Windows you *must* declare floating-point parameters as doubles in
      function prototypes & definitions, otherwise your code is tanked.
      On Mac OS you *may* declare floating-point parameters as doubles.
      (Incidentally, in the early days of Mac OS PPC Max development it was
      also mandatory to declare those parameters as doubles.)
      For cross-platform compatibility, the simplest, most straight-forward
      solution is to always use double in your callbacks.
      On 14-Mar-2006, at 16:02, Chris wrote:
      > I don't understand...
      > calling this code in my objects
      > void myfunc(float f);
      > void test()
      > {
      > post("sizeof(float)=%d sizeof(double)=%dn",sizeof
      > (float),sizeof(double));
      > myfunc(1.0f);
      The call to myfunc(), on CW (w/PPC Carbon Target), generates a lwz
      instruction to pass 1.0f. Which means your carefully specified single-
      precision is loaded into a 64-bit register, complete with conversion
      to double-precision. Go figure.
      > }
      > void myfunc(float f)
      > {
      > post("sizeof(f)=%dn",sizeof(f));
      While we're here and being anal-retentive, you would be universally
      safer to use a %ld or %lu specifier in your format string, since
      sizeof() returns an unsigned long, which is not necessarily the same
      size as an int. Granted, nowadays int is pretty much always 32-bit,
      but that's not what the ANSI C spec says.
      > }
      >
      >
      > gives as result:
      >
      > sizeof(float)=4 sizeof(double)=8
      > sizeof(f)=4
      -------------- http://www.bek.no/~pcastine/Litter/ -------------
      Peter Castine | +--> Litter Power & Litter Bundle for Jitter
      |....................................................
      p@castine.de | iCE: Sequencing, Recording, and Interface Building
      pcastine@gmx.net | for Max/MSP
      pcastine@bek.no | http://www.dspaudio.com/ Extremely cool
      4-15@kagi.com |....................................................
      | home|chez nous|wir|i nostri http://www.castine.de/
    • Mar 14 2006 | 6:49 pm
      > I"m not quite sure what your code is telling us and I am not convinced
      > it is telling us what you think it's telling us (or what I think you
      > think it thinks it's telling us). Looking at the disassembled code may
      > be instructive and not a little surprising (see below).
      the code was just to show that I didn't understand where 32b float was
      transformed as 64b double.
      > In any case, Max passes de-atomized floats as 64-bit IEEE-754
      > double-precision values to your functions. That's the Max API, like it
      > or love it.
      OK...
      > On Windows you *must* declare floating-point parameters as doubles in
      > On Mac OS you *may* declare floating-point parameters as doubles.
      > For cross-platform compatibility, the simplest, most straight-forward
      > solution is to always use double in your callbacks.
      I just changed all my max object callbacks using float to double. That's
      a good advide.
      The SDK doc should be changed to remove all float from examples.
      Best regards,
      Chris
    • Mar 16 2006 | 5:44 pm
      Hi,
      I just remarked than outlet(x,double x)
      doesn't exists on windows (nor on mac), we have to use outlet(x,float x)
      this is not very logical. We are obliged to use double when the real
      number comes from an inlet, but for outlet, we have to use float...
      Regards
      Chris
    • Mar 16 2006 | 7:55 pm
      On Mar 16, 2006, at 9:44 AM, Chris wrote:
      > I just remarked than outlet(x,double x)
      > doesn't exists on windows (nor on mac), we have to use outlet
      > (x,float x)
      >
      > this is not very logical. We are obliged to use double when the
      > real number comes from an inlet, but for outlet, we have to use
      > float...
      Basically these are two different things. One is has to do with a
      function pointer (not known at compile time as far as Max is
      concerned) which is dynamically bound and the stack is built up
      manually by Max at runtime based on some assumptions (in this case
      that a floating point number is a double). The other is a clearly
      prototyped API function which the compiler can handle as defined.
      There's nothing precluding the introduction of an outlet_double() in
      the future, nor is this logically inconsistent. The heritage for
      passing doubles on the stack for our dynamically bound function
      pointers comes from the PPC architecture passing both floats and
      doubles on the stack as double precision values. We decided to keep
      this convention on Intel.
      Note that in Max floats are currently always passed between objects
      at 32bit resolution. This might be increased in a future version (for
      which our use of doubles on the stack will prove useful). However,
      for now it is a limitation.
      Hope this sheds a bit of light on what's going on. If you really want
      to avoid this float/double confusion, simply define all your
      functions with A_GIMME and manage the atoms which are passed between
      objects in your object. The other method signatures and outlet calls
      are really there only for convenience.
      -Joshua
    • Mar 16 2006 | 9:03 pm
      > Basically these are two different things. One is has to do with a
      > function pointer (not known at compile time as far as Max is concerned)
      > which is dynamically bound and the stack is built up manually by Max at
      > runtime based on some assumptions (in this case that a floating point
      > number is a double). The other is a clearly prototyped API function
      > which the compiler can handle as defined. There's nothing precluding the
      > introduction of an outlet_double() in the future, nor is this logically
      > inconsistent. The heritage for passing doubles on the stack for our
      > dynamically bound function pointers comes from the PPC architecture
      > passing both floats and doubles on the stack as double precision values.
      > We decided to keep this convention on Intel.
      >
      > Note that in Max floats are currently always passed between objects at
      > 32bit resolution. This might be increased in a future version (for which
      > our use of doubles on the stack will prove useful). However, for now it
      > is a limitation.
      Thanks for your precisions
      > Hope this sheds a bit of light on what's going on. If you really want to
      > avoid this float/double confusion, simply define all your functions with
      > A_GIMME and manage the atoms which are passed between objects in your
      > object. The other method signatures and outlet calls are really there
      > only for convenience.
      Not especially, A_FLOAT is more convenient... I'll use double for inlets.
      That was just to point the difference and try to understand.
      Best regards,
      CHris