Signal inlets 2+ won't work


    May 19 2012 | 10:51 am
    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.

    • May 19 2012 | 12:32 pm
      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; // 
      
    • May 19 2012 | 1:48 pm
      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?
    • Jun 18 2012 | 4:39 pm
      "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
    • Aug 20 2012 | 1:07 am
      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.
    • Oct 17 2019 | 10:31 pm
      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.
    • Jan 26 2020 | 11:14 pm
      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.
    • Jan 26 2020 | 11:22 pm
      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.
    • Jan 26 2020 | 11:52 pm
      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... :-)
    • Jan 28 2020 | 7:13 pm
      And perhaps a source example using multichannel input/output showing how this is used?
      +1 (would love more examples in general 🙏)