Forums > Dev

Max Crashes, no explanation

June 19, 2006 | 5:03 pm

Hi all,
I’m trying to write an MSP GUI object on Win32. I’ve been working with the stuff provided in the SDK, and I think I’m following all the directions, but I keep getting crashes. I get no errors on compiling my .mxe. I put it in the externals folder, and Max seems to recognize it, but when I try to instantiate it Max just vanishes. I get no errors on screen or in any of my syslogs; the program just disappears like it was never running at all. This seems very odd to me. Anybody have any ideas? I know writing externals on XP has some additional complications, but I would think I would get some kind of error.

I don’t have the code on me to post at the moment (will do so later if needed), but I’m really hoping for a general explanation – I must be missing something obvious, I think.

Thanks,
Mike


June 19, 2006 | 5:38 pm

We’re going to need to see some code. There’s no general explanation
for why things don’t work – except that there’s very likely a bug in
your code! We’d be more than happy to look at the problem, though.
Full source + Project file would be ideal.

jb


June 19, 2006 | 8:27 pm

On 19-Jun-2006, at 19:03, Mike Sayre wrote:

> I put it in the externals folder, and Max seems to recognize it,
> but when I try to instantiate it Max just vanishes.

1) So it’s probably in your instantiation routine

2) What I’ve most often tripped up over is integer div-by-zero, which
is rated "mostly harmless" on Mac OS but cause those sorts of
symptoms on Windows. Your problem may be entirely different, however.

Given (1), why don’t you post your object typedef and your init
routine as a starter?

– P.

————– http://www.bek.no/~pcastine/Litter/ ————-
Peter Castine +–> Litter Power & Litter Bundle for Jitter

iCE: Sequencing, Recording & |home | chez nous|
Interface Building for |bei uns | i nostri|
Max/MSP Extremely cool http://www.castine.de

http://www.dspaudio.com/


June 21, 2006 | 2:29 am

Alrighty, sorry about the delay. I can’t post the project file, or at least it wouldn’t be very useful, because I’m using the Bloodshed IDE, not VS. In any case, I don’t think that’s the issue because I can compile the SDK projects without any problems and they work fine in max. So we’ll start with instantiation stuff. This is my first external…so be gentle. Code follows…

< <<<<<<<<<<<<<<<<<<<<<<< specBars~.c >>>>>>>>>>>>>>>>>>>>>>>

#include "ext.h" //Req. for all Max externals
#include "z_dsp.h" //Req. for MSP objects
#include

//Math Lib
#include "ext_user.h" //Req. for UI objects

// the specBars object. Shows the amplitude of each FFT band as a vertical bar

void *specBars_class;

typedef struct _specBars
{
t_pxbox s_obj;
short s_binNum; // sigIn: FFT Bin number
float s_binAmp; // sigIn: amplitude of the bin
} t_specBars;

//////////////////////////Function Declarations///////////////////////////

//Object Creation (bookmark 2)
void specBars_dsp(t_specBars *x, t_signal **sp, short *count); //Setup object’s DSP (add to MSP’s DSP chain)
t_int *specBars_perform(t_int *w); //Perform Method
void *specBars_new(t_symbol *sym, short argc, t_atom *argv); //Instance creation function
void *specBars_menu (t_patcher *p, long left, long top, long font); //If object created with object palette
void specBars_free(t_specBars *x); //Free allocated memory

//Message functions (responses to messages) (bookmark 3)
void specBars_int(t_specBars *x, long n); //Function for int messages
void specBars_float(t_specBars *x, double f); //For Float messages
void specBars_update(t_specBars *x);
void specBars_psave (t_specBars *x, Binbuf *dest); //Saves the location, size, params of object to be recalled when patch is loaded

//Mouse Functions
void specBars_click(t_specBars *x, Point pt, short modifiers);
void specBars_assist(t_specBars *x, void *b, long m, long a, char *s); //Help text on mouseOver Inlets
void specBars_bidle(t_specBars *x, Point pt, short modifiers, short active); //When mouse is idle over object
void specBars_bidleout(t_specBars *x, Point pt); //When mouse moves off of object

//Drawing Functions (bookmark 4)
void movecursor(Point where); //Move cursor to a point. This function defined in Max kernal

//Unused
void specBars_clear(t_specBars *x); //Clear sample values to recover from MSP crash

////////////////////////////Function Definitions/////////////////////////////

//Object Creation Functions

void main(void)
{
setup((t_messlist **)&specBars_class,(method)specBars_new, (method)specBars_free,(short)sizeof(t_specBars), (method)specBars_menu,0,0);
addmess((method)specBars_dsp, "dsp", A_CANT, 0); //Req to add obj to DSP chain
addmess((method)specBars_assist, "assist", A_CANT, 0); //Show helptext for inlets

//UI-specific methods
addmess((method)specBars_click, "click", A_CANT, 0); //Respond to a click event
addmess((method)specBars_update, "update", A_CANT, 0); //Respond to update message (redraw)
addmess((method)specBars_psave, "psave", A_CANT, 0); //When patch is saved

dsp_initboxclass(); //init the class, this function for UI objects only
}

void specBars_dsp(t_specBars *x, t_signal **sp, short *count)
{
dsp_add(specBars_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
/* Add the object’s perform routine to the DSP chain
Arguments are passed as an array of arrays. The first arg to dsp_add specifies num of args
Each inlet’s signal vector pointed to with sp[inletNum]->s_vec
Vector size is sp[inletNum]->s_n
*/
t_int *specBars_perform(t_int *sig)
{
/* Perform routine is called at interrupt level.
MUST return a pointer to the sig vector array or MSP WILL CRASH
Must use index one greater than highest argument index – see return below
*/
float *inAmp; //Amplitude of the current bin
short *inBin; //Number of the current bin
short n; //Signal vector size

inAmp = (float *)(sig[1]); //First arg is at address [1]. Address [0] is address of perform routine
inBin = (short *)(sig[2]); //Cast signals as float + short int to make math possible
n = sig[3]; //Signal vector size

//Calculate values
while(n–) { // Loop through entire signal vector

}

return sig + 4; //There are 3 arguments, in array passed to this function, so must return value of 4
}

void *specBars_new(t_symbol *sym, short argc, t_atom *argv)
{
t_specBars *x = newobject(specBars_class);
dsp_setupbox((t_pxbox *)x,2);

// two signal inlets

// no signal outlet
/*
outlet_new((t_object *)x, "signal");
outlet_new((t_object *)x, "signal");
*/
return x;
}

void *specBars_menu (t_patcher *p, long left, long top, long font) //When the object is added using the object palette
{
}

void specBars_free(t_specBars *x) //Free memory used by the object when it is destroyed
{
void dsp_freebox(t_pxbox *x);
}

etc etc, message functions below

< <<<<<<<<<<<<<<<<<<<<< And there it is >>>>>>>>>>>>>>>>>>>

The message functions don’t have any content, so I didn’t include them. I suspect I have some errors above. Any ideas?

Thanks,
Mike


June 21, 2006 | 7:25 am

2 things that pop out at me, neither of which are obviously problematic:

You have an extra 0 at the end here. Probably not important.

> setup((t_messlist **)&specBars_class,(method)specBars_new, (method)
> specBars_free,(short)sizeof(t_specBars), (method)specBars_menu,0,0);

and if you’re defining your object as A_NOTHING (0 at the end of setup
() without a type), you can’t use an A_GIMME signature in specBars_new
():

> void *specBars_new(t_symbol *sym, short argc, t_atom *argv)

which should be specBars_new(void). You’re not using the args,
though, at least not yet. Probably you will, in conjunction with your
menu function. So I would change the first 0 in setup() to A_GIMME,
and leave specBars_new() as is.

You need to call box_new(), box_ready() and friends on your object,
just like with a normal Max UI object class, too. You may be crashing
simply because there’s no box!

If none of this helps, I might be able to find a few minutes to try
to build this in VS, but it won’t be until later in the week. One
thing to check is: does the object crash if loaded via the Install…
menu command? If so, the crash is in main(). If the object only
crashes when instantiated in the patcher, then the crash is (most
likely) in new().

jb


June 24, 2006 | 10:58 pm

Okay, removed that extra 0 and tried adding the box_new and box_ready functions, still getting the same crash. One thing I am curious about…for MSP UI objects, am I still supposed to be using box_new and box_ready? Those two functions are expecting a t_box, and the documentation says I’m supposed to use a t_pxbox in my typedef, which I did. It also said that the only difference is a few added fields – does that mean that these two functions don’t care if it’s a t_box or a t_pxbox?

Also, I had some trouble getting the patcher coordinates to work properly. The SDK says to use argv[1]->a_w.w_long; to get the left coordinate, let’s say, but that throws an invalid type error. I replaced it w argv[1].a_w.w_long;, which eliminates the error, but I’m not sure that even works properly. Sorry, my C is rusty.

Updated code below…

Cheers,
Mike

#include "ext.h" //Req. for all Max externals
#include "z_dsp.h" //Req. for MSP objects
#include

//Math Lib
#include "ext_user.h" //Req. for UI objects

// the specBars object. Shows the amplitude of each FFT band as a vertical bar

void *specBars_class;

typedef struct _specBars
{
t_pxbox b; //The box to draw in
short s_binNum; // sigIn: FFT Bin number
float s_binAmp; // sigIn: amplitude of the bin
void *theQelem; //Not quite sure what this is for yet
} t_specBars;

//////////////////////////Function Declarations///////////////////////////

//Object Creation (bookmark 2)
void specBars_dsp(t_specBars *x, t_signal **sp, short *count); //Setup object’s DSP (add to MSP’s DSP chain)
t_int *specBars_perform(t_int *w); //Perform Method
void *specBars_new(t_symbol *sym, short argc, t_atom *argv); //Instance creation function
void *specBars_menu (t_patcher *p, long left, long top, long font); //If object created with object palette
//void *specBars_free(t_specBars *x); //Free allocated memory

//Message functions (responses to messages) (bookmark 3)
void specBars_int(t_specBars *x, long n); //Function for int messages
void specBars_float(t_specBars *x, double f); //For Float messages
//void specBars_update(t_specBars *x);
//void specBars_psave (t_specBars *x, Binbuf *dest); //Saves the location, size, params of object to be recalled when patch is loaded

//Mouse Functions
//void specBars_click(t_specBars *x, Point pt, short modifiers);
void specBars_assist(t_specBars *x, void *b, long m, long a, char *s); //Help text on mouseOver Inlets
void specBars_bidle(t_specBars *x, Point pt, short modifiers, short active); //When mouse is idle over object
void specBars_bidleout(t_specBars *x, Point pt); //When mouse moves off of object

//Drawing Functions (bookmark 4)
void movecursor(Point where); //Move cursor to a point. This function defined in Max kernal

//Unused
void specBars_clear(t_specBars *x); //Clear sample values to recover from MSP crash

////////////////////////////Function Definitions/////////////////////////////

//Object Creation Functions

void main(void)
{
setup((t_messlist **)&specBars_class,(method)specBars_new, (method)dsp_freebox,(short)sizeof(t_specBars), (method)specBars_menu,0);
addmess((method)specBars_dsp, "dsp", A_CANT, 0); //Req to add obj to DSP chain
addmess((method)specBars_assist, "assist", A_CANT, 0); //Show helptext for inlets

//UI-specific methods
// addmess((method)specBars_click, "click", A_CANT, 0); //Respond to a click event
// addmess((method)specBars_update, "update", A_CANT, 0); //Respond to update message (redraw)
//addmess((method)specBars_psave, "psave", A_CANT, 0); //When patch is saved

dsp_initboxclass(); //init the class, this function for UI objects only
}

void specBars_dsp(t_specBars *x, t_signal **sp, short *count)
{
dsp_add(specBars_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
/* Add the object’s perform routine to the DSP chain
Arguments are passed as an array of arrays. The first arg to dsp_add specifies num of args
Each inlet’s signal vector pointed to with sp[inletNum]->s_vec
Vector size is sp[inletNum]->s_n
*/

#if FUTURE_FEATURE
#else
#endif
}

t_int *specBars_perform(t_int *sig)
{
/* Perform routine is called at interrupt level.
MUST return a pointer to the sig vector array or MSP WILL CRASH
Must use index one greater than highest argument index – see return below
*/
float *inAmp; //Amplitude of the current bin
short *inBin; //Number of the current bin
short n; //Signal vector size

inAmp = (float *)(sig[1]); //First arg is at address [1]. Address [0] is address of perform routine
inBin = (short *)(sig[2]); //Cast signals as float + short int to make math possible
n = sig[3]; //Signal vector size

//Calculate values
while(n–) { // Loop through entire signal vector

}

return (sig + 4); //There are 3 arguments, in array passed to this function, so must return value of 4
}

void *specBars_new(t_symbol *sym, short argc, t_atom *argv)
{
void *p; //The patcher
long left, top, right, bottom; //Coordinates in patcher
t_specBars *x;

x = (t_specBars *)newobject(specBars_class); //Assign the object to the pointer

p = argv->a_w.w_obj; //Get the patcher

dsp_setupbox((t_pxbox *)x,2); //Init DSP for the object

left = argv[1].a_w.w_long; //Get the coordinates
top = argv[2].a_w.w_long;
right = argv[3].a_w.w_long;
bottom = argv[4].a_w.w_long;

box_new((t_box *)x, p, F_DRAWFIRSTIN | F_SAVVY, left, top, right, bottom);
//x->my_qelem = qelem_new(x, (method)specBars_redraw);
// x->my_box.b_firstin = (void *)x;

box_ready ((t_box *)x);
// two signal inlets

// no signal outlet
/*
outlet_new((t_object *)x, "signal");
outlet_new((t_object *)x, "signal");
*/
return (x);
}

void *specBars_menu (t_patcher *p, long left, long top, long font) //When the object is added using the object palette
{
}

/*
void *specBars_free(t_specBars *x) //Free memory used by the object when it is destroyed
{
dsp_freebox(x);
box_free(*b);
}
*/

//UI Functions (responses to messages)

void specBars_int(t_specBars *x, long n)
{
specBars_float(x,(double)n);
}

void specBars_float(t_specBars *x, double f)
{
long in = proxy_getinlet((t_object *)x);

}

void specBars_clear(t_specBars *x)
{

}

void specBars_assist(t_specBars *x, void *b, long m, long a, char *s)
{
if (m == ASSIST_OUTLET) //If the selected in/out is an outlet
sprintf(s,"(signal) Output");
else { //If it’s an inlet
switch (a) {
case 0: sprintf(s,"(signal) Amplitude"); break;
case 1: sprintf(s,"(signal) bin number"); break;
}
}
}

//Drawing Functions


June 25, 2006 | 12:13 pm

On 25-Jun-2006, at 0:58, Mike Sayre wrote:
> Also, I had some trouble getting the patcher coordinates to work
> properly. The SDK says to use argv[1]->a_w.w_long; to get the left
> coordinate, let’s say, but that throws an invalid type error. I
> replaced it w argv[1].a_w.w_long;, which eliminates the error, but
> I’m not sure that even works properly. Sorry, my C is rusty.

For function signatures like foo(…, short argc, Atom* argv), you
want either

argv[1].a_w.w_long // array notation

OR

(argv + 1)->a_w.w_long // pointer notation

The two are equivalent in C. Which you prefer is a matter of
pragmatics. A lot of people use pointer notation for offset zero and
switch to array notation for other things, confusing both oxidized
and fresh-minted readers alike;-

> Okay, removed that extra 0 and tried adding the box_new and
> box_ready functions, still getting the same crash. One thing I am
> curious about…for MSP UI objects, am I still supposed to be using
> box_new and box_ready? Those two functions are expecting a t_box,
> and the documentation says I’m supposed to use a t_pxbox in my
> typedef, which I did. It also said that the only difference is a
> few added fields – does that mean that these two functions don’t
> care if it’s a t_box or a t_pxbox?

I seem to recall that there is a sentence in the MSP chapter of the
SDK explaining a special base type to use for an MSP UI. In C++
parlance this is a multiple inheritance thing (your object is an
object AND a UI object AND an MSP object). I’m sorry I don’t have
chapter and verse at my fingertips, but if no one else can give you
details over the weekend, (yet) another look at the docs may help.

Good luck,
Peter

————– http://www.bek.no/~pcastine/Litter/ ————-
Peter Castine +–> Litter Power & Litter Bundle for Jitter

iCE: Sequencing, Recording & |home | chez nous|
Interface Building for |bei uns | i nostri|
Max/MSP Extremely cool http://www.castine.de

http://www.dspaudio.com/


June 25, 2006 | 1:01 pm

OK, here’s some working code for you. The two biggest issues here

- you had no menu function defined, which means that every attempt to
instantiate your object was resulting in bogus data for argc & argv
in your _new() method, which you were relying on for creating the
object.

- even with that solved, there was another tricky issue. You have to
include "ext_user.h" BEFORE "z_dsp.h" or else the t_pxbox struct gets
defined as a void*, your object struct is too short, and all hell
breaks loose.

I added some other minor stuff, too, which you can look through at
your convenience. The object now instantiates for me on Mac, although
I didn’t test the dsp or perform methods or anything. That all looks
correctly defined, though.

jb

#include "ext.h" //Req. for all Max externals
// THIS HAS TO COME FIRST, OR z_dsp.h defines t_pxbox as a void*
#include "ext_user.h" //Req. for UI objects
///////////////////////////////////////////////////////////////////
#include "z_dsp.h" //Req. for MSP objects
#include

//Math Lib

// the specBars object. Shows the amplitude of each FFT band as a
vertical bar

void *specBars_class;

typedef struct _specBars
{
t_pxbox b; //The box to draw in
short s_binNum; // sigIn: FFT Bin number
float s_binAmp; // sigIn: amplitude of the bin
void *theQelem; //Not quite sure what this is for yet
} t_specBars;

//////////////////////////Function
Declarations///////////////////////////

//Object Creation (bookmark 2)
void specBars_dsp(t_specBars *x, t_signal **sp, short *count); //
Setup object’s DSP (add to MSP’s DSP chain)
t_int *specBars_perform(t_int *w); //Perform Method
void *specBars_new(t_symbol *sym, short argc, t_atom *argv); //
Instance creation function
void *specBars_menu (t_patcher *p, long left, long top, long
font); //If object created with object palette
//void *specBars_free(t_specBars *x); //Free allocated memory

//Message functions (responses to messages) (bookmark 3)
void specBars_int(t_specBars *x, long n); //Function for int
messages
void specBars_float(t_specBars *x, double f); //For Float messages
void specBars_update(t_specBars *x);
//void specBars_psave (t_specBars *x, Binbuf *dest); //Saves the
location, size, params of object to be recalled when patch is loaded

//Mouse Functions
//void specBars_click(t_specBars *x, Point pt, short modifiers);
void specBars_assist(t_specBars *x, void *b, long m, long a, char
*s); //Help text on mouseOver Inlets
void specBars_bidle(t_specBars *x, Point pt, short modifiers, short
active); //When mouse is idle over object
void specBars_bidleout(t_specBars *x, Point pt); //When mouse moves
off of object

//Drawing Functions (bookmark 4)
void movecursor(Point where); //Move cursor to a point. This
function defined in Max kernal

//Unused
void specBars_clear(t_specBars *x); //Clear sample values to
recover from MSP crash

////////////////////////////Function
Definitions/////////////////////////////

//Object Creation Functions

void main(void)
{
setup((t_messlist **)&specBars_class,(method)specBars_new, (method)
dsp_freebox,
(short)sizeof(t_specBars), (method)specBars_menu, 0);

addmess((method)specBars_dsp, "dsp", A_CANT, 0); //Req to add obj
to DSP chain
addmess((method)specBars_assist, "assist", A_CANT, 0); //Show
helptext for inlets

//UI-specific methods
// addmess((method)specBars_click, "click", A_CANT, 0); //Respond
to a click event
addmess((method)specBars_update, "update", A_CANT, 0); //Respond to
update message (redraw)
// addmess((method)specBars_psave, "psave", A_CANT, 0); //When
patch is saved

dsp_initboxclass(); //init the class, this function for UI
objects only
}

void specBars_dsp(t_specBars *x, t_signal **sp, short *count)
{
dsp_add(specBars_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
/* Add the object’s perform routine to the DSP chain
Arguments are passed as an array of arrays. The first arg to
dsp_add specifies num of args
Each inlet’s signal vector pointed to with sp[inletNum]->s_vec
Vector size is sp[inletNum]->s_n
*/

#if FUTURE_FEATURE
#else
#endif
}

t_int *specBars_perform(t_int *sig)
{
/* Perform routine is called at interrupt level.
MUST return a pointer to the sig vector array or MSP WILL CRASH
Must use index one greater than highest argument index – see return
below
*/
float *inAmp; //Amplitude of the current bin
short *inBin; //Number of the current bin
short n; //Signal vector size

inAmp = (float *)(sig[1]); //First arg is at address [1]. Address
[0] is address of perform routine
inBin = (short *)(sig[2]); //Cast signals as float + short int to
make math possible
n = sig[3]; //Signal vector size

//Calculate values
while(n–) { // Loop through entire signal vector

}

return (sig + 4); //There are 3 arguments, in array passed to
this function, so must return value of 4
}

void *specBars_new(t_symbol *sym, short argc, t_atom *argv)
{
void *p; //The patcher
long left, top, right, bottom; //Coordinates in patcher
t_specBars *x;

// let’s be a little safe here
if (x = (t_specBars *)newobject(specBars_class)) { //Assign the
object to the pointer
p = argv->a_w.w_obj; //Get the patcher

left = argv[1].a_w.w_long; //Get the coordinates
top = argv[2].a_w.w_long;
right = argv[3].a_w.w_long;
bottom = argv[4].a_w.w_long;
box_new((t_box *)x, p, F_DRAWFIRSTIN | F_SAVVY, left, top, right,
bottom);

// two signal inlets
// probably should have an initialized box, before setting it up
dsp_setupbox((t_pxbox *)x,2); //Init DSP for the object
x->b.z_box.b_firstin = (void *)x; // so that the left inlet == your
object

//x->my_qelem = qelem_new(x, (method)specBars_redraw);

// no signal outlet
/*
outlet_new((t_object *)x, "signal");
outlet_new((t_object *)x, "signal");
*/
box_ready ((t_box *)x);
}
return (x);
}

void *specBars_menu (t_patcher *p, long left, long top, long font) //
When the object is added using the object palette
{
t_atom argv[5];

// set up argv the way specBars_new wants it…
// first the patcher
argv[0].a_type = A_OBJ;
argv[0].a_w.w_obj = (t_object *)p;
// now the coordinates (font info not used)
argv[1].a_type = argv[2].a_type =
argv[3].a_type = argv[4].a_type = A_LONG;
argv[1].a_w.w_long = left;
argv[2].a_w.w_long = top;
argv[3].a_w.w_long = left + 20;
argv[4].a_w.w_long = top + 20;

return specBars_new(0, 5, argv);
}

//UI Functions (responses to messages)

void specBars_int(t_specBars *x, long n)
{
specBars_float(x,(double)n);
}

void specBars_float(t_specBars *x, double f)
{
long in = proxy_getinlet((t_object *)x);

}

void specBars_clear(t_specBars *x)
{

}

void specBars_assist(t_specBars *x, void *b, long m, long a, char *s)
{
if (m == ASSIST_OUTLET) //If the selected in/out is an outlet
sprintf(s,"(signal) Output");
else { //If it’s an inlet
switch (a) {
case 0: sprintf(s,"(signal) Amplitude"); break;
case 1: sprintf(s,"(signal) bin number"); break;
}
}
}

void specBars_update(t_specBars *x)
{
;
}


June 25, 2006 | 5:42 pm

Gracias, everyone, and thank you for the code, Jeremy. Thanks for all your help – I am still learning. I had been so focused on figuring out the instantiation routine that I forgot all about sending it arguments! Typical… I might have figured that out, but I was stuck on the type error in the code below. I will try this and get back to you.

As for the issue of array vs. pointer notation, I thought that was the case, but I wanted to be sure. I believe this means that there is a mistake in the SDK, because it definitely has me using both:

argv[1]->a_w.w_long;

(quoted directly from p. 203 – Instantiation Routine)

Any mods in da house?

Happy coding all,
Thanks again,
Mike


June 25, 2006 | 5:49 pm

Assuming you mean page 155… Yes, that’s a documentation bug. We’ll
try to get that fixed at some point.

jb

Am 25.06.2006 um 19:42 schrieb Mike Sayre:

> As for the issue of array vs. pointer notation, I thought that was
> the case, but I wanted to be sure. I believe this means that there
> is a mistake in the SDK, because it definitely has me using both:
>
> argv[1]->a_w.w_long;
>
> (quoted directly from p. 203 – Instantiation Routine)


June 26, 2006 | 12:46 am

Yes, p 155 in the Win version, or p. 203 in the Mac version (that’s the computer I was on when I looked up the page number).

Mike


June 27, 2006 | 8:15 pm

I tried the provided code that worked on Mac (thanks again Jeremy) but still got the crash. I found two problems not directly related to my code.

1) The Bloodshed IDE I’ve been using makes DLL’s with -msdll, not -shared. I’m not sure how to fix this within the program, so I compiled & linked at CL with Cygwin as follows:

gcc -c -DWIN_VERSION -DWIN_EXT_VERSION -I../../c74support/max-includes -I../.
./c74support/msp-includes specBars~.c

gcc -shared -o specBars~.mxe specBars~.o specBars~.def -L../../c74support/max
-includes -L../../c74support/msp-includes -lmaxapi -lmaxaudio

You will notice the lack of the -mno-cygwin flag. This brings us to…

2) The -mno-cygwin flag seems to be related to my insta-crash. If I put the cygwin1.dll in the support folder and drop that flag, then I get a different crash – an application hang. I seem to remember seeing a post a while ago about problems with -mno-cygwin, does anyone know more about this?

Good day,
Mike


June 27, 2006 | 8:21 pm

Here is the promised code…should be the same as that Jeremy provided. Should.

#include "ext.h" //Req. for all Max externals
#include "ext_user.h" //Req. for UI objects
#include "z_dsp.h" //Req. for MSP objects
#include

//Math Lib

// the specBars object. Shows the amplitude of each FFT band as a vertical bar

void *specBars_class;

typedef struct _specBars
{
t_pxbox b; //The box to draw in
short s_binNum; // sigIn: FFT Bin number
float s_binAmp; // sigIn: amplitude of the bin
void *theQelem; //Not quite sure what this is for yet
} t_specBars;

//////////////////////////Function Declarations///////////////////////////

//Object Creation (bookmark 2)
void specBars_dsp(t_specBars *x, t_signal **sp, short *count); //Setup object’s DSP (add to MSP’s DSP chain)
t_int *specBars_perform(t_int *w); //Perform Method
void *specBars_new(t_symbol *sym, short argc, t_atom *argv); //Instance creation function
void *specBars_menu (t_patcher *p, long left, long top, long font); //If object created with object palette
//void *specBars_free(t_specBars *x); //Free allocated memory

//Message functions (responses to messages) (bookmark 3)
void specBars_int(t_specBars *x, long n); //Function for int messages
void specBars_float(t_specBars *x, double f); //For Float messages
void specBars_update(t_specBars *x);
//void specBars_psave (t_specBars *x, Binbuf *dest); //Saves the location, size, params of object to be recalled when patch is loaded

//Mouse Functions
//void specBars_click(t_specBars *x, Point pt, short modifiers);
void specBars_assist(t_specBars *x, void *b, long m, long a, char *s); //Help text on mouseOver Inlets
void specBars_bidle(t_specBars *x, Point pt, short modifiers, short active); //When mouse is idle over object
void specBars_bidleout(t_specBars *x, Point pt); //When mouse moves off of object

//Drawing Functions (bookmark 4)
void movecursor(Point where); //Move cursor to a point. This function defined in Max kernal

////////////////////////////Function Definitions/////////////////////////////

//Object Creation Functions

void main(void)
{
setup((t_messlist **)&specBars_class,(method)specBars_new, (method)dsp_freebox,(short)sizeof(t_specBars), (method)specBars_menu,0);
addmess((method)specBars_dsp, "dsp", A_CANT, 0); //Req to add obj to DSP chain
addmess((method)specBars_assist, "assist", A_CANT, 0); //Show helptext for inlets

//UI-specific methods
// addmess((method)specBars_click, "click", A_CANT, 0); //Respond to a click event
addmess((method)specBars_update, "update", A_CANT, 0); //Respond to update message (redraw)
//addmess((method)specBars_psave, "psave", A_CANT, 0); //When patch is saved

dsp_initboxclass(); //init the class, this function for UI objects only
}

void specBars_dsp(t_specBars *x, t_signal **sp, short *count)
{
dsp_add(specBars_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
/* Add the object’s perform routine to the DSP chain
Arguments are passed as an array of arrays. The first arg to dsp_add specifies num of args
Each inlet’s signal vector pointed to with sp[inletNum]->s_vec
Vector size is sp[inletNum]->s_n
*/

#if FUTURE_FEATURE
#else
#endif
}

t_int *specBars_perform(t_int *sig)
{
/* Perform routine is called at interrupt level.
MUST return a pointer to the sig vector array or MSP WILL CRASH
Must use index one greater than highest argument index – see return below
*/
float *inAmp; //Amplitude of the current bin
short *inBin; //Number of the current bin
short n; //Signal vector size

inAmp = (float *)(sig[1]); //First arg is at address [1]. Address [0] is address of perform routine
inBin = (short *)(sig[2]); //Cast signals as float + short int to make math possible
n = sig[3]; //Signal vector size

//Calculate values
//while(n–) { // Loop through entire signal vector

//}

return (sig + 4); //There are 3 arguments, in array passed to this function, so must return value of 4
}

void *specBars_new(t_symbol *sym, short argc, t_atom *argv)
{
void *p; //The patcher
long left, top, right, bottom; //Coordinates in patcher
t_specBars *x;

if(x = (t_specBars *)newobject(specBars_class)) { //Assign the object to the pointer

p = argv->a_w.w_obj; //Get the patcher

left = argv[1].a_w.w_long; //Get the coordinates
top = argv[2].a_w.w_long;
right = argv[3].a_w.w_long;
bottom = argv[4].a_w.w_long;
box_new((t_box *)x, p, F_DRAWFIRSTIN | F_SAVVY, left, top, right, bottom);

dsp_setupbox((t_pxbox *)x,2); //Init DSP for the object
x->b.z_box.b_firstin = (void *)x; //Creates direct reference to object at left inlet
//x->theQelem = qelem_new(x, (method)specBars_redraw);

box_ready ((t_box *)x);
}
return (x);
}

void *specBars_menu (t_patcher *p, long left, long top, long font) //When the object is added using the object palette
{
t_atom argv[5];

//Set up arguments to send to specBars_new
argv[0].a_type = A_OBJ;
argv[0].a_w.w_obj = (t_object *)p;
argv[1].a_type = argv[2].a_type = argv[3].a_type = argv[4].a_type = A_LONG;
argv[1].a_w.w_long = left;
argv[2].a_w.w_long = top;
argv[3].a_w.w_long = left + 20;
argv[4].a_w.w_long = top + 20;

//Then call the instantiation function
return specBars_new(0, 5, argv);
}

//UI Functions (responses to messages)

void specBars_int(t_specBars *x, long n)
{
specBars_float(x,(double)n);
}

void specBars_float(t_specBars *x, double f)
{
long in = proxy_getinlet((t_object *)x);

}

void specBars_assist(t_specBars *x, void *b, long m, long a, char *s)
{
if (m == ASSIST_OUTLET) //If the selected in/out is an outlet
sprintf(s,"(signal) Output");
else { //If it’s an inlet
switch (a) {
case 0: sprintf(s,"(signal) Amplitude"); break;
case 1: sprintf(s,"(signal) bin number"); break;
}
}
}

void specBars_update(t_specBars *x) {
;
}


June 28, 2006 | 12:15 am

On Tue, 27 Jun 2006, Mike Sayre wrote:

> 2) The -mno-cygwin flag seems to be related to my insta-crash. If I
> put the cygwin1.dll in the support folder and drop that flag, then I get
> a different crash – an application hang. I seem to remember seeing a
> post a while ago about problems with -mno-cygwin, does anyone know more
> about this?

Yeah, if you can work to get your external to compile with the -mno-cygwin
flag, you will be much much better off. I had developed a windows version
of a fairly extensive external [rtcmix~] some time ago, but was getting
reports of all kinds of strange crashes, etc. Turns out that different
versions of the cygwin1.dll were at fault, and I also suspect that the
inclusion of the cygwin1.dll caused some additional problems (my code-base
has a unix heritage, so there were loads of, uh, "translation"
difficulties). I just recently managed to get it to compile completely
without requiring the cygwin1.dll, and the initial reports I’ve gotten
from some kind testing-souls are very good.

This is old, but I found this posting on the net:

http://www.delorie.com/howto/cygwin/mno-cygwin-howto.html

to be really useful, at least in explaining and getting me to think about
what I needed to do to stop cygwin1.dll references (heck, even realizing
that there *was* an "objdump -p" command was a biggie for me!). There are
probably some other good resources on the web, too.

I had to rewrite a couple of the unix-ey functions to get rid of some
unresolved references, and I also had to monkey a bit with the lib/include
search path (the article above discusses this) to get it to fly with
-mno-cygwin, but it’s definitely worth the effort.

Don’t get me wrong — I think cygwin is pretty astounding, and the folks
involved in creating/maintaining it are amazing. It just doesn’t work
well in a loadable-obj environment like max/msp.

brad

http://music.columbia.edu/~brad


June 28, 2006 | 12:19 am

> On Tue, 27 Jun 2006, Mike Sayre wrote:
>
>> 2) The -mno-cygwin flag seems to be related to my insta-crash. If I put
>> the cygwin1.dll in the support folder and drop that flag, then I get a
>> different crash – an application hang. I seem to remember seeing a post a
>> while ago about problems with -mno-cygwin, does anyone know more about
>> this?

Oh one thing — be sure that -mno-cygwin is included in *all* of your gcc
invocations. I build several subsidiary libs before linking them all
together in my final .mxe, and every object compilation needs to have that
flag or it seems to trigger a cygwin1.dll load.

brad

http://music.columbia.edu/~brad


July 12, 2006 | 4:19 pm

Hey cycling-dev gang –

Before I make a total fool of myself by announcing this on the main list,
I thought I’d see if any dev-people would try it out. I think this is a
fairly solid version of the [rtcmix~] object, and it seems to run ok on
both Windows and OSX (dunno about the intel macs):

http://music.columbia.edu/~brad/rtcmix~-beta/beta_v1.399/

One of the nifty new features is that it saves the RTcmix scripts as part
of the patcher now, so you don’t have to do a separate read/save message
to the object (you can if you want, of course). I’ve also had great
success in building pluggo (VST) plugins with this object, and it seems to
work well in standalones.

Let me know if you get a chance to try it. Thanks!

brad

http://music.columbia.edu/~brad


July 12, 2006 | 5:09 pm

On Jul 12, 2006, at 11:19 AM, Bradford Garton wrote:

> Hey cycling-dev gang –
>
> Before I make a total fool of myself by announcing this on the main
> list, I thought I’d see if any dev-people would try it out. I
> think this is a fairly solid version of the [rtcmix~] object, and
> it seems to run ok on both Windows and OSX (dunno about the intel
> macs):
>
> http://music.columbia.edu/~brad/rtcmix~-beta/beta_v1.399/
>
> One of the nifty new features is that it saves the RTcmix scripts
> as part of the patcher now, so you don’t have to do a separate read/
> save message to the object (you can if you want, of course).

Wow. Worth the price of admission alone.


July 27, 2006 | 3:41 pm

Hey cycling dev-people –

I’ve made an encapsulation of the ChucK DSP language similar to [rtcmix~].
I’d love for you to try this out:

http://music.columbia.edu/~brad/chuck-max-beta/beta_v0.7/

and let me know what you think, how it works, etc. I’ve included several
small example patches showing what it can do. OSX only for now, sorry!

thanks!

brad

http://music.columbia.edu/~brad


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