c++ Fixed-Dynamic Channel Count?
-
I've been struggling to figure out how to create nodes that will work very efficiently with arbitrary channel numbers.
I've been poking around with the C++ external node template for a month trying to figure this one out but I'm going round in circles. I'm starting to think that I'm missing something. Is my task impossible? And am I misunderstanding something about how Hise (or channels) work?
I'm essentially wanting to fix the number of channels at runtime, with as few variables or calls as possible, and no conditionals. I'm going crazy trying to find the best way to do it. I've had no luck so far.
I'm wondering if Hise already has solutions to this built in, a lot of the default scriptnodes appear to handle multichannel. Is this done without overhead? The default c++ external node template starts up with a fixed channel count of 2 set at compile time, this of course is great for efficiency but not flexible. However I feel you don't need to be that flexible with channel counts, my understanding was that they are known as soon as the plugin loads into the daw. And so surely there in a middle ground, where you can almost have the efficiency of fixed, but decided at the moment the plugin is loaded in? I feel like templating could solve this, but the declarations and usage of the scriptnodes are all already managed by hise.
There may already be a solution and I've simply missed it. Or I may be asking the impossible, to create fixed size arrays for something that is known only at compile time.
I suppose my last resort solution would be to use pointers and swap out the function call for the code inside process() where channels are fixed, to different versions with the appropriate channel count. I would do the swap during the prepare() function, this approach will quite quickly bloat the project with multiple copies of essentially the same code but would have no extra variables created and no conditionals. I suppose it would work for stereo and mono without too much bloat.
-
You're right in the sense that if you compile a node, it requires a static channel count if you intend to load it into the hardcoded fx module. However, the scriptnode API uses two different classes for it's processing data, one with a (templated) fixed channel count and one with a dynamic channel count that allows the dynamic logic of the scriptnode nodes:
struct ProcessData<3>; // compile time channel count of three struct ProcessDataDyn; // dynamic channel count
Both classes have the exact same methods and properties, so they are interchangeable from a template perspective:
template <int C> void process(ProcessData<C>& data) { for(int i = 0; i < data.getNumChannels(); i++) { for(int s = 0; s < data.getNumSamples(); s++) data[i][s] = 0.0f; } } void process(ProcessDataDyn& data) { for(int i = 0; i < data.getNumChannels(); i++) { for(int s = 0; s < data.getNumSamples(); s++) data[i][s] = 0.0f; } }
Now if you want your node to be used with a dynamic channel count inside a scriptnode network, all you need to do is to erase the function
getFixChannelAmount()
(as it's hinted in the comment from the ThirdParty template). If you then compile the node, the templated process function will then be called with the dynamicsnex::ProcessDataDyn
struct which you can iterate dynamically.If you want to squeeze out the last CPU cycles, you can branch with the constexpr function
hasCompileTimeSize()
, but usually the compiler is smart enough to figure that out on its own. -
Thanks for your reply, this makes sense.
I probably should've explained what I was trying to achieve.
I am wanting to make sure I am mono and stereo compatible in the daw.
Perhaps the best way is simply to create a mono and a stereo version of the same script, if it's not possible to fix the size at runtime. I'm not really needing an adaptive channel count, in the sense that I know the number of channels will never change during runtime after being set for the first time. Iterating over the samples is often one of the bottlenecks in my code, I am trying to work out the absolute best way to do it.Or maybe I am still misunderstanding how these things work.
I will continue to test.