Obtaining total number of active voices

In my SynthVoice.h I have a need to find out how many voices are currently active.

In case you are wondering, and there may be another way to find out what I need, it is for my Portamento. I need to know when all notes (voices), except one, has been released so I can save that voice’s frequency (note).

I can find out easily enough in PluginProcessor, however I need the result in SynthVoice. If I only I knew how to access a PluginProcessor function in SynthVoice it would also solve my problem.

What is the easiest, or rather fastest way to do that?

When you create the SynthVoice give it a backlink to the processor.
Caveat: circular include.
Solution: forward declare the processor in the SynthVoice.h and include in the cpp only.

Thank you very much for that information. I will try to figure out how to do it that way.

“Solution: forward declare the processor in the SynthVoice.h and include in the cpp only.”

When you write “cpp only” do you mean I need to separate my SynthVoice.h into “h” and “cpp” files?

It is very complicated to get it done with header only. In that case you need to be extra careful with the include order. So easy to get into a situation where the error message doesn’t make any sense.

So I would strongly recommend to separate it in headers and cpp.

I appreciate the guidance. I am very close to finishing my quite complicated synth, and fear I have to spent to much time, and break something by splitting SynthVoice up. So for now I just solved my problem really simple, which off course will get me stoned and burned, not necessarily in that order, by some, with a global int array, not bool so I can just sum it up without an “if”;

On startNote;

voiceActive[voiceNumber] = 1;

On stopNote;

voiceActive[voiceNumber] = 0;

And when I need to know how many are active;

int voicesActive = 0;1

for (int voice = 0; voice < maxVoices; voice++)
	voicesActive += voiceActive[voice];

Not throwing stones, but kindly showing the BigInteger class, that even allows:

BigInteger voiceActive;

// startNote:
voiceActive.setBit (voiceNumber, true);

// stopNote:
voiceActive.setBit (voiceNumber, false);

auto numAvtiveVoices = voiceActive.countNumberOfSetBits();

Have fun

1 Like

Oh I was definitely not aware of that. I have several things I can use that for, thanks!

You must not use global or static variables in plugins. It’s not a code style issue, it’s a concrete code correctness issue, global variables are shared by all plugin instances running in the host, so your plugin wouldn’t work correctly if there are multiple instances of it running.

I see, thanks.

You wouldn’t have a float array sum trick up your sleeve?

As it happens I have:
https://en.cppreference.com/w/cpp/algorithm/accumulate

It works like:

#include <vector>
#include <algorithm>

std::vector<float> v;
auto sum = std::accumulate (v.begin(), v.end(), 0.0f);
2 Likes

Nice, thanks!

I think your synthesizer should have a getNumActiveVoices method. Handling this in the processor breaks encapsulation, and trying to track this with arrays of data is confusing and error prone. Each voice knows whether it’s on or not, so just ask them instead of trying to store this data in another place and keep it in sync.

It can be as simple as this:

int Synthesiser::getNumActiveVoices() const
{
    int num = 0;
 
    for (auto* voice : voices)
        if (voice->isVoiceActive())
            ++num;

    return num;
}

Thanks for chiming in, but my synthesizer does not seem to use “Synthesizer”. This is what my SynthVoice.h starts with;

class SynthVoice : public SynthesiserVoice {
public:
	SynthVoice ()
	{
...

Ah, I thought you had made a subclass of juce::Synthesiser to implement some custom functionality. That’s what I would suggest doing.

So what is the best way “Juce Plugin” coding method to define variables, including parameters, that can be accessed across one or perhaps all of the following; PluginProcessor, PluginEditor, DAW, and SynthVoice? A link to an example or tutorial perhaps?

This isn’t really a plugin-specific problem, it’s more of a general software architecture problem. Really, you shouldn’t be sharing a single piece of data across that many scopes at all – and, this information “how many voices are active” also doesn’t have to live as a piece of stateful data at all, because it can be a member function of the object managing the voices (ie, the Synth class), like I mentioned above. If this is the case, then the only dependency cycle that needs to exist is that the SynthVoice must know about the Synth, but this cycle already exists in the juce Synth/SynthVoice class pair anyway.

Here’s what I would do:

struct MySynth : juce::Synthesiser
{
    int numActiveVoices() const
    {
        int num = 0;

       for (auto* voice : voices)
           if (voice->isVoiceActive())
               ++num;

       return num;
    }
};

struct MySynthVoice : juce::SynthesiserVoice
{
    MySynthVoice (MySynth& parent)
      : SynthesiserVoice (&parent), synth(parent)

    // now you can call synth.numActiveVoices() anywhere in this class!

private:
    MySynth& synth;
};

The synth voice doesn’t need to know about the processor, and the processor doesn’t need to know about the synth voices. The synth is entirely encapsulated as one mega-object.

Hope this helps.

1 Like

Thank you very much for that. This was a specific case and I was wondering how to best define and use a parameter variable across my plugin.

For example say I have an effect with a dry/wet parameter. I can use the effect during rendering either in SynthVoice or in PluginProcessor, as well as both. The parameter can be changed via the PluginEditor or the DAW. I am guessing ValueTree and did look at the JUCE tutorial which unfortunately only shows how to define a parameter only used in PluginProcessor.

Ah, I see. For this case, I would usually bundle all the plugin’s relevant info and all parameter objects into a State struct. Then, instantiate one in the processor, and make the editor take a State& as a constructor argument.

Even if you don’t want to make a new struct for this, the point is that nothing needs to be global/static, you can pass an object owned by the processor into the editor by reference

1 Like