Max Crashes, no explanation


    Jun 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

    • Jun 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
    • Jun 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
    • Jun 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
    • Jun 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
    • Jun 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
    • Jun 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
    • Jun 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)
      {
      ;
      }
    • Jun 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
    • Jun 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)
    • Jun 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
    • Jun 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
    • Jun 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) {
      ;
      }
    • Jun 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:
      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
    • Jun 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
    • Jul 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):
      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
    • Jul 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.
    • Jul 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:
      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