Artifacts when adjusting gain while audio still playing


I'm new to audio proessing in general so I'm sure this'll be straight forward for somebody to answer, but I honestly can't find much information about this online.

If I adjust the gain value before playing the audio and THEN play the audio, its gain is adjusted correctly and there are no artifacts. If I adjust the gain during playback, the gain is adjusted properly but there are all kinds of clicks in the sound. Is there a different way of implementing gain other than a simple multiplier on the output? What am I missing here? The extra stack allocation that might happen from retrieving a member by value can't possibly cause the problem, could it?

In the renderNextBlock() function of the SamplerVoice class, I'm adjusting the signal's gain like so:

void SampleVoice::renderNextBlock(AudioSampleBuffer& buffer, int startSample, int numSamples){
    SampleSound::Ptr s = (SampleSound::Ptr)getCurrentlyPlayingSound();
    if (s != nullptr){
        double sample_length = s->getAudioData()->getNumSamples();
        int num_channels = s->getAudioData()->getNumChannels();
        if (getCurrentlyPlayingSound().get()){

           //get write pointers for buffer, etc...

            for (int i= start; i<numSamples+start; i++){
                const int pos = (int) samplePosition;
                const double alpha = (double) (samplePosition - pos);
                const double invAlpha = 1.0f - alpha;
                // just using a very simple linear interpolation here..
                float l = ((inL[pos]) * invAlpha +  (inL[pos+1]) * alpha);
                float r = inR != nullptr ? (inR[pos]) * invAlpha + (inR[pos+1] * alpha) : l;
                *outL += l*noteEvent->getVolume();
                *outR += r*noteEvent->getVolume();
                samplePosition += pitchRatio;


noteEvent->getVolume() refers to a member containing a gain multiplier (double) value ranging from 0.0 to 1.0. Why would changing this value result in clicks in the sound? The audio DOES get quieter or louder when I adjust the volume, but it's also very clicky. Not sure what's up. There's no allocation involved with updating that member or retrieving its value.


I fixed it by changing the gain in increments of the amount changed. For instance, if the gain multiplier was set to 0.8 from 1.0, that's a difference of -0.2 gain. For each sample in the callback, add the difference / numSamples to the previous gain setting to create a slurring or gradual gain change. 


yes, you'll be fine making a ramp between the actual gain and the target one. that's the usual way to avoid what's commonly called 'zipper noise'.


"zipper noise," interesting. I have a lot to learn :)


It gets quite complicated if you aren't careful. There are a bunch of solutions to the problem.  Here's the low-pass filter solution from the music-dsp archives.

I've got a little set of classes which do the ramp solution, the important one I've put here:

But I don't really like my current approach. See the comments.