BUG? Strange SynthesiserSound stopNote() behavior

During debugging of an ADSR error, I noticed stopNote() seemed to be called twice. Once for the current voice which if I only play one note at a time and wait for it to finish before playing another note, is always voice number 1. But it also always calls stopNote() on the “first” voice, voice number 0. Now to clarify when I say voice number, I mean when you add voices like this;

mySynth.addVoice (new SynthVoice ());

The very first time that is called, the voice number is essentially number 0, next time number 1, and so on until you added how many voices you need for polyphonic.

It does not matter if setNoteStealingEnabled is set to false or true, or if you play one or more notes at the same time, when I release the last key, playing one or more keys, stopNote() is invoked on voice number 0.

In other words stopNote() is called one time extra, to much!

Here is my test code I used to determine the described behaviour;

In PluginProcessor;

    mySynth.clearVoices ();
    // Below is a global variable used to set a local variable in SynthVoice's 
    // constructor to keep track of what voice number is used when playing a key
	currentVoice = 0;
	for (int i = 0; i < 16; i++)
	{
		mySynth.addVoice (new SynthVoice ());
		currentVoice++;
	}
	mySynth.setNoteStealingEnabled (false);

In SynthVoice’s constructor;

class SynthVoice : public SynthesiserVoice {
public:
	SynthVoice ()
	{
		voiceNumber = currentVoice;
     }

In SynthVoice stopNote();

void stopNote (float velocity, bool allowTailOff)
	{
		if (voiceNumber == 0) testValue1++; // Test values are shown in real time in my Editor
		if (voiceNumber != 0) testValue2++;

		clearCurrentNote ();
	}

So is my observation correct? If not what am I missing? But if correct why is stopNote() in voice “0” always called when releasing a single key, or last key played together?

I should also note that stopNote() is invoked for each voice, when adding them in PluginProcessor.

Having the same issue, any updates?

So almost 4.5 years after I first posted about the above stopNote issue, which was later noted by another user, I still have a stopNote issue. Could be because I’m coded something incorrectly.

Today if I only press one note at a time, stopNote is called as it should once. Also if I consecutively and quickly press any two notes, stopNote is correctly called two times. However if I quickly press the same note twice or even more, stopNote is called twice as many as I press the note, as in pressing same notes twice, stopNote gets called four times.

Note the variable array testValue, is declared globally, and comes in handy when trying to track down bugs not easily detected by normal debug single-stepping code.

Here is my stopNote code;

	void stopNote (float velocity, bool allowTailOff)
	{
		ignoreUnused (velocity);

		synthParams.voicesActive.setBit (voiceNumber, false);
		testValue[1]++;
		if (allowTailOff == false)
		{
			testValue[2]++;
			for (int module = 0; module < maxModules; module++)
			{
                // Quick release unless envelope is already in quick release or done
				if (adsrVoice[module].getStage () < 7) 
				{
					adsrVoice[module].quickRelease ();
				}

				if (synthParams.tgPortamentoReleaseModeCKV[module] == 3) 
                    synthParams.lastCyclesPerSecond = cyclesPerSecond;
			}
		}
		else
		{
			testValue[3]++;
			for (int module = 0; module < maxModules; module++)
			{
                // Release unless envelope is already being released
				if (adsrVoice[module].getStage () < 4)
				{
					adsrVoice[module].release (synthParams.adsrTables[module]);
				}

				if (synthParams.tgPortamentoReleaseModeCKV[module] == 3) 
                    synthParams.lastCyclesPerSecond = cyclesPerSecond;
			}
		}
	}

As you can see above I got some counters which I display in PluginEditor, including one in startNote, and one in the below code;

Also at the end of my RenderNextBlock, I test if all 8 of my tone generators are released, and if so I do;

testValue[4]++;

adsrRunning = false;

voiceStatus = 0;

clearCurrentNote ();

So if I press same note consecutively, quickly before release is over, I get the following results for test variable testValue, showing where code is traversing;
[0] startNote = 2 times as should be,
[1] Top of stopNote = 4 times! synthVoice class code error. This should only be called twice!
[2] stopNote voice being stolen = 0 times as should be.
[3] stopNote envelope release stage being set = 4 times! Above counter does not take into account synthVoice class code error. This area should only be called twice! My code tests if envelope is already in one of its three release, so at least it’s not being released all over again.
[4] End of RenderNextBlock = 2 times as should be.

Furthermore by adding another test count variable array, equal to the size of number of voices, and because each of my voice’s contain a local variable holding instance # of voice, as in 0 - 9 for 10 voices, I know exactly which voice’s stopNote is being called erroneously, and as originally reported it is stopNote in the first voice, as in voice 0. More specifically my observation points to voice 0’s (the first voice you added via addVoice) stopNote is also being called when notes (keys) is being lifted in all voices!

Is there anyone who have the time to confirm or deny my observations? As you can see from an above reply, one other person have already confirmed the error. Any comment is greatly appreciated, thanks!

To rule out reported error is due to my code, I just created via ProJucer, the “AudioSynthesiserDemo”, and I can confirm it is the same issue!

Note I did change one line in the Juce demo to extend the tailoff. I changed;
tailOff *= 0.99;

to;
tailOff *= 0.9999;

So again pressing same note twice fast in a row, before first have been released, stopNote is called too often!

i would start by tracing the call stack to see who is calling stopNote and how many times it gets called per iteration of your audio callback

it is possible that there are multiple functions being called when you press a note, some of which lead to an invocation of stopNote. by tracing the call stack, you can find who the callers are and decide whether stopNote is being called from somewhere invalid

I don’t know, but keep in mind this bug have nothing to do with my code, as I explained above the error happens also using the “AudioSynthesiserDemo” code included with every JUCE download.

I would very much to figure out what is happening, as this apparent JUCE error could lead to other unruly behavior down the line. It have the potential to affects all who is using SynthVoice.

Isn’t this normal behaviour? If you press the same note in quick succession then it’s standard for the first one to cut short in order to be replaced by the second press.

Otherwise you’d get an accumulated build up of the same note.

You may be right, but then should the first note not actually be stolen? I know it is not, as I can see the order stopNote is processed. The stopNote continues to normal release, in other words “allowTailOff” is true. This can be a problem in that voice 0’s release is restarted.