Signal inlets 2+ won't work
I'm working on an external with five signal inlets, and I can't seem to get any input from inlets 2 onward. I've included the project folder (an Xcode project) and the compiled external as an attachment, in case anybody wants to try those out. Here is my perform routine.
void rhythm_perform64(t_rhythm *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam)
{
t_double *in3 = ins[2]; //works if I change to ins[1] or ins[0]
t_double *outL = outs[0];
t_double *outR = outs[1];
int n = sampleframes;
//fields
int len = x->length;
int wCount = x->writeCount;
while (n--) {
//write values to array
if (wCount > len-1) {
wCount = 0;
}
*outL++ = wCount;
*outR++ = *in3++;
//increment count and update value
wCount++;
x->writeCount = wCount;
}
}
The code above will not get any output from outR. However, when I change the inlet declaration to 'ins[1]' or 'ins[0]', those inlet's input is passed to the second outlet, as expected.
Here is my new instance routine, in which the inlets are initially created:
void *rhythm_new(t_symbol *s, long argc, t_atom *argv)
{
t_rhythm *x = (t_rhythm *)object_alloc(rhythm_class);
x->m_outlet3 = floatout((t_rhythm *)x);
if (x) {
dsp_setup((t_pxobject *)x, 5);
outlet_new(x, "signal");
outlet_new(x, "signal");
}
return (x);
}
As you can see, I HAVE created 5 inlets.
I haven't found anything related to this in the documentation or the forums so far, so any help would be much appreciated.
Hi John,
try to put the Z_NO_INPLACE
flag into your new instance routine and it should work :
void *rhythm_new(t_symbol *s, long argc, t_atom *argv)
{
t_rhythm *x = (t_rhythm *)object_alloc(rhythm_class);
x->m_outlet3 = floatout((t_rhythm *)x);
if (x) {
dsp_setup((t_pxobject *)x, 5); // MSP inlets: arg is # of inlets and is REQUIRED!
// use 0 if you don't need inlets
outlet_new(x, "signal"); // signal outlet (note "signal" rather than NULL)
outlet_new(x, "signal");
}
x->ob.z_misc |= Z_NO_INPLACE; //
Aha! Works like a charm! But I must ask, why? All I got from the documentation was that it is a "flag indicating the object doesn’t want signals in place." So what does 'in place' mean?
"in-place" refers to an optimization where memory may be shared between the input and output pointers. This reduces the amount of memory required to represent the signal vectors. The resulting behavior is that when you write to the output you are over-writing the input. Depending on the logic of your perform routine this may or may not be a problem.
In your particular case it is a problem that requires either the Z_NO_INPLACE flag or altering your perform method so that you don't write to outL
prior to reading from in3
.
Hope this helps,
Tim
Yo, Timothy and John I just want to say THANK YOU for this post. I'm writing a Max6 external that currently takes in three signal inputs and I couldn't figure out what was going on. I've been beating my head against the wall for the past four hours. I was actually going to post about this exact problem when I decided to check and see if someone else had run into the issue.
Just wanted to say thanks! That solves another related problem, for future reference: I built an oscillator with a phase modulation input which would only work if the modulation source was plugged into some arbitrary MSP object sitting to the left of the oscillator. Adding this flag fixed it.
My code needed to initialize the output buffers to all zeros, which discarded the input buffer's content whenever the in-place optimisation was active. My guess is that whenever two or more objects use the same audio source object, only the last connected object to have its output buffer computed can use in-place optimisation since the other objects need to have an unaltered copy of the source buffer to work on. It looks like Max computes the output buffers left to right, so adding an extra MSP node on the right means that in-place optimisation is deactivated for all MSP nodes on its left.
Hey gang -- thanks for this post from me too. Suggestion: perhaps a mention of this in the documentation besides a rather cryptic "flag indicating the object doesn't want signals in place" might be a nice idea? I pretty much wasted a whole weekend figuring I had done something so obviously stupid that it wasn't worth consulting the forum. Yes, it was stupid but perhaps not-so-obvious. Shoulda done a forum search earlier on.
I wholeheartedly agree that confining a vital piece of information such as this to a single line of text on page 436 of the documentation is problematic. It took me about a week to figure this out. In my opinion it should be mentioned in the documentation's introductory chapter to building MSP objects.
And perhaps a source example using multichannel input/output showing how this is used? split~ doesn't really do it (I know because I think I have that code *memorized* now... :-)
And perhaps a source example using multichannel input/output showing how this is used?
+1 (would love more examples in general 🙏)
Huge bump - I'm using min-devkit and it seems like I've encountered a similar issue, but frankly I cannot figure out how to access the flag.
I couldn't find anything in regard to the new instance routine within the documentation.
Hey Wojciech --
In your 'my object_new()' method, put this somewhere towards the end:
x->ob.z_misc |= Z_NO_INPLACE;
'x' is declared as:
t_myobject *x;
and initialized like this at the top:
x = (t_myobject *)object_alloc(myobject_class);
Arg! What an annoying thing!
brad