Mixing kontrol rate and audio rate in a same UGen

Do you mean in this kind of faust2supercollider generate file, that currently only adds control input (gain, freq here) ?


FaustOsc : UGen
{
  *ar { | gain(0.0), freq(1000.0) |
      ^this.multiNew('audio', gain, freq)
  }

  *kr { | gain(0.0), freq(1000.0) |
      ^this.multiNew('control', gain, freq)
  } 

  name { ^"FaustOsc" }


  info { ^"Generated with Faust" }
}

Exactly! If you want more than one output, you would typically inherit from MultiOutUGen and call initOutputs in the init method:

init { |numOutputs ... inputs|
    this.inputs = inputs;
    ^this.initOutputs(numOutputs, this.rate);
}

You also need to pass the number of outputs to multiNew (which will forward it to init):

^this.multiNew('audio', numOutputs, <inputs...>);

Thanks, but not sure to understand. How is numOutputs computed then ? Do you have a complete example of MultiOutUGen based UGen ?

That is totally up to you! As I said, in your case it would be the number of audio outputs + the number of “control” outputs.

Do you have a complete example of MultiOutUGen based UGen ?

A very simple example would be the In UGen. For a more complex example, see VSTPlugin.

OK, C++ code updated, output control is written here: faust/architecture/supercollider.cpp at 8715622a78012c1cd385658e7a6d9ee5bb0ec19d · grame-cncm/faust · GitHub

And for a DSP with 0 input, 1 audio output and 1 control output, the generated sc file is now:

FaustOsc : MultiOutUGen
{
  *ar { | gain(0.0), freq(1000.0) |
      ^this.multiNew('audio', gain, freq)
  }

  *kr { | gain(0.0), freq(1000.0) |
      ^this.multiNew('control', gain, freq)
  } 

  init { | ... theInputs |
      inputs = theInputs
      ^this.initOutputs(2, rate)
  }

  name { ^"FaustOsc" }


  info { ^"Generated with Faust" }
}

But the generated audio output is distorted, as soon at the control output is also written, with the OUT0(curControl) = unit->getOutputControl(i)->updateOutput(); or fillBuffer(OUT(curControl), inNumSamples, unit->getOutputControl(i)->updateOutput());

Any idea ?

The code itself looks fine. Can you show your code for monitoring the sound? BTW, if you plot the outputs, it’s probably more clear what’s going on.

It’s actually working, I was testing incorrectly, thanks for the help :grinning: !

2 Likes

You’re right - you can know the block size when you construct the SynthDef in sclang, but when the synthdef file is deserialized from disk it may be in the context of a server with a different block size, so it would no longer be valid. Probably this could be made to work, except cached synthdefs would be invalid if you booted the server with a different block size, which is obviously not good. The alternative here would be to use a LocalBuf I guess - this would give you a fixed size buffer into which you could pack/unpack values.

From what I see, mixing audio rate and control rate should be possible after all. I’ll make a PoC.