passing sp from dsp method to perform method

Oct 27, 2009 at 11:59am

passing sp from dsp method to perform method

Hi all,

Just exploring the porting of a few SC UGens to Max/MSP this week. I’ve read the API help and hunted through this forum, but haven’t found any discussion of the following. So I appeal for assistance…

I’m building an external which might end up with 11 inlets. I’ve reduced my problem to just the case of 1 in, 1 out, but I need to find a solution to this to get back to lots of inlets. I’m trying to avoid explicitly passing all the sp[i]->s_vec in the dsp function. hopefully code prototypes below make sense. I get a crash when I try to pass sp itself, but it’s fine if I am explicit about them all. So my question is whether it is valid to go about things this way, whether I should switch to using dsp_addv or some other method…

best,
Nick

Code excerpts:
this crashes randomly, due to NULL pointer turning up:

void weakly_dsp(t_weakly *unit, t_signal **sp, short *count)
{

//can’t guarantee sp will still be around? seems to end up as nil sometimes!

dsp_add(weakly_perform, 4, unit, sp, sp[0]->s_n, count);
}

t_int *weakly_perform(t_int *w)
{
t_weakly *unit = (t_weakly *)(w[1]);

//all ins then outs
if (unit->ob.z_disabled) // check for object being disabled
return w + 5;

int inNumSamples = (int)w[3];

//short * count= (short *)w[4];

t_signal ** sig= (t_signal**)w[2];

//get NULLs here occasionally!
if(!sig)
return w+5;

t_float *in = (t_float *)(sig[0]->s_vec);
t_float *out = (t_float *)(sig[1]->s_vec);

}

this is fine:

void weakly_dsp(t_weakly *unit, t_signal **sp, short *count)
{

//everything explicitly passed
dsp_add(weakly_perform, 4, unit, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
}

t_int *weakly_perform(t_int *w)
{
t_weakly *unit = (t_weakly *)(w[1]);

//all ins then outs
if (unit->ob.z_disabled) // check for object being disabled
return w + 5;

int inNumSamples = (int)w[4];

//all works fine
t_float *in = (t_float *)(w[2]);
t_float *out = (t_float *)(w[3]);

}

#46177
Oct 27, 2009 at 3:46pm

hi nick,

not sure the exact answer to your question, but i was working on an external lately and i needed a dynamic number of outlets. dspaddv made things much easier.

eric lyons objects use it. check el.clean_selector~ source for dynamic inlets

http://www.sarc.qub.ac.uk/~elyon/LyonSoftware/MaxMSP/

are you going to port your tartini pitch tracker?

cheers,

oli

#166329
Oct 27, 2009 at 8:20pm

Thanks Oli,

I’ll take a look at the dspaddv code example from Eric.

to answer my own initial question, pondering this I think the sp pointer in dsp_add isn’t safe in the long term, so I should probably put all pointers to memory buffers for inputs, and count information, into my own store in the unit. Will see how I get on with that approach…

If anyone out there has a more official viewpoint, would be interested to hear it.

Not sure how many UGens I’ll port, since I’ve written so many for SC. But going to try a few this week. Tartini is at heart Phil McLeod’s work (http://miracle.otago.ac.nz/postgrads/tartini/download.html), and he has updated his algorithms since my initial port, so if I find time to approach that again, I’d work on SC and Max simultaneously. One reason I’m looking into MSP externals is to extend the platforms I can offer work for…

best,
Nick

#166330
Oct 27, 2009 at 11:42pm

OK, I got this working, and with 11 inlets. Stored the required pointers in the object struct.

If anyone is curious, code and prebuilt external(OS X, Max 5)/help file for the WeaklyNonlinear chaotic oscillator here:

http://www.cogs.susx.ac.uk/users/nc81/courses/cm2/weakly~.zip

It’s a port of the SuperCollider UGen WeaklyNonlinear2. Now I’ve got the basic idea of external building, will see where I go next…

best,
N

#166331
Oct 27, 2009 at 11:42pm

Hi Nick,

I would say passing sp to dsp_add() then dereferencing in your _perform() is unsafe.

My approach in the past for this has been to take a copy of the data I need from sp into my object and just pass my object to dsp_add().

void weakly_dsp(t_weakly *unit, t_signal **sp, short *count)
{
 int index;
 for(index = 0; index < NUM_INLETS_AND_OUTLETS; index++)
 {
   unit->u_buffers[index] = sp[index]->s_vec;
 }

 unit->u_buffersize = sp[0]->s_n;

 dsp_add(weakly_perform, 1, unit);
}

..so u_buffers is a dynamically allocated array of pointers. I use enums so that NUM_INLETS_AND_OUTLETS gets set automatically then I can just forget about the _dsp() function and only ever have one argument in the perform method. Obviously this negates the efficiency available via not doing all the necessary lookups in _perform() but this methods was designed to help students avoid the hideous (and virtually untraceable) crashes when you make a mistake with arguments passed via the dsp_add() method in MSP.

brainstorm on in

#166332
Oct 27, 2009 at 11:47pm

Nick, we obviously posted simultaneoulsy. Looks like you used a similar approach. Martin

#166333
Oct 27, 2009 at 11:48pm

Cheers Martin,

I suspected as much and my solution is pretty much the same as your suggestion. but good to have it confirmed,

best,
Nick

#166334
Nov 1, 2009 at 9:46am

Hi – i just tried this and the object won’t load. i get the following:

weakly~: unable to load object bundle executable
2009-11-01 09:40:10.801 MaxMSP[323] CFLog (21): dyld returns 2 when trying to load /Applications/Max5/Cycling ’74/3rd_party/weakly~/weakly~.mxo/Contents/MacOS/weakly~

max5.0.8, G4 osx 10.4.11.

great to hear you are porting your sc stuff to max though, please do the gendy ugens!

#166335
Nov 1, 2009 at 12:37pm

@goodparleyandorfing – Looks like you have an intel only build (possibly a development build – don’t know how Nick is doing this)

I can’t download the zip right now (server is timing out), but you have an XCode project there and XCode on your machine you could try compiling it in Deployment mode (assuming Nick’s used the c74 templates)

Otherwise, hopefully he’ll be able to provide you with a UB version soon.

Alex

#166336
Nov 1, 2009 at 1:16pm

thanks alex, that makes sense – i will try compiling it. yeah, just curious really as i like nick collins’ SC stuff; realise it’s not an official distribution or anything yet

#166337
Nov 2, 2009 at 2:24pm

Ah, didn’t realise that the Xcode projects are set up for build machine only by default. I have turned now to Universal binary building.

New upload here:
http://www.cogs.susx.ac.uk/users/nc81/courses/cm2/weakly~.zip

And I’ve also made two externals now, so if you want to try a UB of lpcanalyzer~ too:
http://www.cogs.susx.ac.uk/users/nc81/code/NCmaxexternals.zip

btw, for future reference, I learnt an important lesson after head scratching with building lpcanalyzer~. Max/MSP doesn’t guarantee separate buffers for inputs and outputs (like SC, though SC has the CantAlias mode for UGens where this is an issue, not sure if anything equivalent in max land). So never accumulate to out buffer with processed samples of input; always make a separate working buffer of your own.

I make no promises on speed of porting or new externals. Will have to look into the FFT facilities next…

best
Nick

#166338
Nov 2, 2009 at 2:31pm
nickcollins wrote on Mon, 02 November 2009 07:24
Ah, didn’t realise that the Xcode projects are set up for build machine only by default. I have turned now to Universal binary building.

Yes – they are also set not to put optimisations on, so they are debuggable, but slow….

nickcollins wrote on Mon, 02 November 2009 07:24
btw, for future reference, I learnt an important lesson after head scratching with building lpcanalyzer~. Max/MSP doesn’t guarantee separate buffers for inputs and outputs (like SC, though SC has the CantAlias mode for UGens where this is an issue, not sure if anything equivalent in max land).

Yes – there is :

set z_misc in your t_pxobject structure to Z_NO_INPLACE during your new routine.

The other flags (put first / put last) are bogus however, and it’s pointless setting them.

Alex

#166339
Nov 2, 2009 at 3:22pm

Thanks Alex,

useful flag tip.

btw, do you do any further things as standard in modifying your Xcode settings aside from ‘Fastest, Smallest’ optimisation level in deployment: Auto-vectorisation or similar?

best
Nick

#166340
Nov 2, 2009 at 9:25pm

Hey Nick,

It may or may not help (you can never tell without profiling to validate), but in some cases I’ve seen that the 03 optimization is faster than 0s.

You mileage may vary…

#166341
Nov 2, 2009 at 10:14pm
Timothy Place wrote on Mon, 02 November 2009 14:25
Hey Nick,
It may or may not help (you can never tell without profiling to validate), but in some cases I’ve seen that the 03 optimization is faster than 0s.

I can second that, but this tends to be a marginal gain. Unrolling loops for very small loops (where the cost of the counter is high compared to what’s in the loop) can also be a win. It tends to be quite good when it is, but only in very few cases – otherwise it seems to make things worse.

I’ve never really seen auto-vectorise do anything much (but then if it’s straight forward, I vectorise by hand, so it’s not really an issue). Also, there are alignment issues, that I can only guess mean it must assume unaligned data loads and stores. Therefore, I’d conclude it’d only be worth it when you are doing a lot of calculations that are very straightforward and obviously parallel. I’ve never seen it hurt, on the other hand, so there’s no harm in having it on I don’t think.

There’s a neat trick for dealing with denorms that I’m using now, that saves having to deal with them in code and saves the costs associated with that – it’s a bit of a complicated issue, but if that’s at all relevant to you I could send you some code to show you what I’m doing. I mention this because it involves a compiler flag which is set by default in GCC, but I don’t see it directly in XCode….

A lot of the rest of the time my optimisations are in the code, and often (for smallish loops) when I debug I see that the assembly is really close to the written code in the loop, so there’s not more that can be done.

Alex

#166342
Nov 2, 2009 at 10:49pm

Hey Alex,

I would love to see the denormals trick that you are talking about since I have always been dealing with denormals in code.
How can you avoid that ?

If you want to reply privately you can reach me at:
superbigio@yahoo.com

Thanks.

- Luigi

#166343

You must be logged in to reply to this topic.