Forums > Dev

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

March 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:
#P window setfont "Sans Serif" 9.;
#P flonum 261 51 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P number 175 48 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P window linecount 1;
#P newex 192 117 66 9109513 testobj;
#P connect 1 0 0 0;
#P connect 1 0 0 1;
#P connect 1 0 0 2;
#P connect 1 0 0 3;
#P connect 1 0 0 4;
#P connect 2 0 0 0;
#P connect 2 0 0 1;
#P connect 2 0 0 2;
#P connect 2 0 0 3;
#P connect 2 0 0 4;
#P window clipboard copycount 3;

#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);
}


March 14, 2006 | 2:15 pm

On Windows, arguments using float values must be doubles.

jb


March 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

http://grrrr.org


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


March 14, 2006 | 2:27 pm

I need to type faster, 3rd place damn it ;-)

t_


March 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

http://grrrr.org


March 14, 2006 | 2:36 pm


March 14, 2006 | 2:42 pm

Yes, go ahead and use double for both.

jb


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


March 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


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


March 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


March 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


March 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


March 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


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