[C API] Process sound effects without a channel?

Hello all,

I want to make a bare-bones subtractive PDSynth voice, and I want the resulting instrument to polyphonic, not paraphonic.

It seems like I need to achieve this by using a custom generator which handles the oscillation and filtering, and letting the rest of the PDSynth and PDSynthInstrument APIs handle note management, amplitude envelopes, etc.

The API already includes a handful of effects, including a state-variable 2-Pole filter. I'd like to use that filter as part of the render callback in a custom generator so I don't have to roll my own unless I really really want to.

However, the only APIs for using effects are with PDChannel objects, and I'm struggling to work out how I could use effects from within the context of a PDSynth's custom generator, and have that do what I want.

For custom effects the user provides an effectProc where the actual sample-by-sample processing is done. Is there a way to get access to whatever effectProc function is defined for built-in effects and use that independently? Is there some other/better way to user built-in effect functions in the context of custom PDSynth voices?

Thanks,
--Z

Ok with some digging I've come up with a sort-of solution.

For the pathological "I have data and I want it processed" case, one can:

  1. Make a channel with a custom source providing your input data. (mute the channel if you don't want to hear the processing.)
  2. Add the effect with which you want to process that data to that channel.
  3. Add a custom effect to capture the processed data. You can also un-mute the channel, or use a delay line afterwards if you want to send that to some other audio channel.

It feels supremely hack-y compared to having a single, in-line function to process data, and requires managing a multi-threaded producer/consumer scenario since all the processing still has to be done on the audio thread, but it does technically work.

For the polyphonic synth case, it's appears to be missing a key component.

If you add PDSynths to individual channels, it's possible to get polyphonic effects. In the case of the sybtractive synth voice, I can:

  1. Add a new Channel, PDSynth voice, TwoPoleFilter, and Envelope.
  2. Add the filter and PDSynth to the channel
  3. Set the envelope to modulate the TwoPoleFilter cut off.
  4. set the envelope to modulate parameter 0 of the synth This one is key. PDSynth parameters are 1-indexed, but parameter 0 still gets note-on/off events, so you can set a modulator there which doesn't affect the generator, but can sill react to what the PDSynth is doing.
  5. Almost Profit.

The problem I'm running into now is that PDSynth voices cannot be added to both a Channel and a PDSynthInstrument at the same time, meaning I have to roll my own note/voice management.

If I add the PDSynth voice to a channel before adding it to a PDSynthInstrument I get an error "Failed to add voice to instrument":

pdcpp::DefaultChannel().addSource(m_Voice);
m_Synth.addVoice(m_Voice, 0.0f, 127.0f, 0.0f); // Get an error here.
m_Synth.noteOn(33, 1.0f);

and the other way around results in error-less silence:

m_Synth.addVoice(m_Voice, 0.0f, 127.0f, 0.0f);
pdcpp::DefaultChannel().addSource(m_Voice);
m_Synth.noteOn(33, 1.0f); // No error, but no sound either.

(Using the C++ API here for examples, but they are one-for-one with what you'd expect the C API do be doing under the hood)

If each voice could be sent to an independent channel, and a PDSynthInstrument could be relied upon to manage notes, pitch-bend, etc., then the above solution would work.

1 Like