Can you use for loops with ProcessorChain

for example, no pun intended:

chain.setBypassed<0>(true);
chain.setBypassed<1>(true);
chain.setBypassed<2>(true);

turned into

for(int x = 0; x < [chain size]; x++)
    chain.setBypassed<x>(true);

in my case, ive tried
(while x < 4)
and
(for( auto x = 0; x < 4; x++ ))
but neither work. i get an error of “no matches for arguments”

that’s because template arguments are known at compile time but for loop variables are not

how can i implement a function that can do what im looking for with the templates then?

With the current juce development tip, a specialisation of std::tuple_size for juce::dsp::ProcessorChain has been added. With that, you can build a bunch of helper functions to achieve something similar to what you want.

To iterate over a sequence of template indices, there is std::index_sequence. This helper will create an appropriate index sequence for every type that works with std::tuple_size:

template <class Tuple>
using makeTupleIndexSequence = std::make_index_sequence<std::tuple_size<std::remove_cvref_t<Tuple>>::value>;

Sidenote: std::remove_cvref is a C++ 20 helper. You can achieve the same by chaining std::remove_cv_t and std::remove_reference_t.

Now you can build a helper function like

template <class ProcessorChain, size_t... i>
void setAllBypassedHelper (bool shouldBeBypassed, ProcessorChain& chain, std::index_sequence<i...>)
{
    (chain.setBypassed<i> (shouldBeBypassed), ...);
}


template <class ProcessorChain>
void setAllBypassed (bool shouldBeBypassed, ProcessorChain& chain)
{
    setAllBypassedHelper (shouldBeBypassed, chain, makeTupleIndexSequence<ProcessorChain>());
}

Sidenote: The syntax used in setAllBypassedHelper is a C++ 17 fold expression, which is basically the loop thing you are looking for. It calls the expression passed in with all elements of the pack variable passed in, which is the index sequence in this case. There are ways to achieve the same in previous C++ standards, but they look extremely ugly :grimacing: If you are forced to use an older standard, just do some research.

Now, with all that, you can ultimatively write this one liner:

setAllBypassed (true, chain);

If the bunch of helper classes are worth it is a question that you’ll have to answer yourself. But once you get started writing such helpers, you’ll maybe tend to re-use them in other contexts. Hope that helped :slight_smile: One last note: All the code above is untested, so no guarantee that I made some mistake – but the concept works for sure :wink:

2 Likes

i have not tried that but theoretically it should also work to just have an enum to iterate over in a for loop because the indexes they represent are also defined at compile time

The difference is the fold expression from @PluginPenguin is executed at compile time potentially allowing the Optimiser additional tricks. It is effectively like writing out all individual calls.

I remember it didn’t work for me because the loop variable could take values outside the chain index. Some constexpr stuff that was over my head. The compiler wouldn’t let me.

1 Like

Would you mind sketching your proposal with a few lines of code? First of all, what do you mean by iterating over an enum? In any case, a for loop is never constexpr, even if theoretically all values could be evaluated at compile time. So I doubt that any solution using a real for loop would work, but I might be overlooking something…

daniel said he already tried that so i would rather not bother with it anymore. it seems not very useful too. the alternative, manually writing out some objects that have index values as template args for some reason, still seems the easiest way

tried implementing this, however it did not work as intended, i could compilation errors stating the template alias could not be configured or something along those lines.

i swapped out your method of

template<class Tuple>
using makeTupleIndexSequence = std::make_index_sequence<std::tuple_size<std::remove_cvref_t<Tuple>>::value>;

for

template<std::size_t... Ints>
using index_sequence = std::integer_sequence<std::size_t, Ints...>;

which compiles but now theres no audio. so im going to have to stick this out for a while and see if i can get this working! thanks for the insight

Mhm,

template<std::size_t... Ints>
using index_sequence = std::integer_sequence<std::size_t, Ints...>;

is no real replacement for my makeTupleIndexSequence, it’s rather a re-declaration of what std::index_sequence is, so this doesn’t make so much sense in this context to take that as a “replacement”. How do you use it?

My function had the intention to get the number of chained processors from the chain (which can be interpreted as a “tuple” in this context).

What juce commit are you on? As I said, the specialisation for std::tuple_size<juce::dsp::ProcessorChain> has been added a few weeks ago to the juce dev tip, so if your juce version is older this will probably fail to compile because the compiler can’t figure out how to evaluate the tuple size of a processor chain. But this is just guesswork, if you showed the actual compiler error message I would be interested in helping you or figuring out if there is a stupid error in my code example above, which I’d like to correct then of course :slight_smile:

6.1.2 → September 2021 build

this is not a necessary implementation so im not too worried about it, but id like to understand it more so i can use it for more complicated projects.

Ah, the std::tupe_size specialisation made it to the dev tip short after 6.1.2 has been released, so you’d need to switch to the develop branch indeed to make the code even compile

1 Like

perfect, thanks! works well now

1 Like