In your sample->setSoundGains() method, you want to gradually increment the gain over a short period of time, to smoothen the transition, so it’s not a sudden change (which causes a click sound).
JUCE has a class called SmoothedValue which does this, like this:
// Create gain like this:
SmoothedValue<FloatType> gain(startingGain);
You’re going to want to set the time it takes to ramp before you use it, with:
gain.reset(sampleRate, numOfSecondsToTransition);
Then, to use it, first set the new target gain:
gain.setTargetValue(newGain);
It automatically transitions, you just have to get the current value:
float newGain = gain.getNextValue();
Then, you use newGain to set your gain on the next sampler update. Note that the gain is updated every time you call getNextValue(), so be careful not to call it twice (once for each channel) in stereo projects.
For a possibly simpler solution, JUCE’s Gain class uses this method, and is another way to smoothly adjust the gain. In this case, the sampler always plays the same gain, and you apply Gain<FloatType>::processSample(sampleToAdjustGain) to the output of the sampler to adjust the sample’s gain.
That works like this:
First you have to have the gain variable created as a property of the class:
Gain<FloatType> gain;
Then, after the sampler generates a sample, you edit the sample:
float newSample = sampler->generateNextSample();
gain.setGainLinear(newGain);
newSample = gain.processSample(newSample);
The issue with the second method is similar to how the first one generates a new gain value each time you call, getNextValue(). Gain does the same thing, so if you have a stereo configuration and need to adjust two different samples that occur at the same time, you’ll need two Gain instances.
You can also write your own. You really just have to transition instead of suddenly jumping to a new gain and your click should go away!
As far as high CPU usage, I don’t know. I think it depends on what setSoundGains is doing. Ideally, it just sets a few values, doing minimal. Slider also has a property called onDragEnd which is a lambda that is called only when the dragging has just ended. If you use that as the slider’s callback (instead of sliderValueChanged), it would only send a message when the slider is finished being dragged. The disadvantage of this is that you won’t be able to hear real-time updates while dragging the slider, but it would potentially reduce CPU usage (although the slider itself updating shouldn’t use that much CPU; it’s about the same as saying the mouse moved – these are high-volume events).
(Note: I haven’t tested the aforementioned code.)