Cross fading two buffers

“Moving” this here as a separate thread.

For a synthesizer in “class SynthVoice : public SynthesiserVoice” and in renderNextBlock, I occasionally have a need to volume cross fade two buffers, not on a per sample basis, but just per block, meaning that for a sample rate of 44100 and a buffer of 1024 it would cross fade over about 23ms. I need one buffer’s audio/data to fade out and the other to fade in. So my question is would SmoothedValue be the solution? I guess I should add that have tried just to use “applyGainRamp”, but it does not produce a smooth transition.

Daniel then replied;


It would work well just to use the inverse value of the out fading value:

auto gain = smoother.getNextValue();
sample = gain * endingSound;
sample += (1.0 - gain) * startingSound;

just one of many solutions… another would be to have a SmoothedValue for each, in case it is not always the same length for fading out and fading in.

And I replied to Daniel;

Hey Daniel, thanks and I assume that answer was for me.

Your example code seems to me it is meant as per sample. I need something that would work for a block, or to make it as smooth as possible, so as little transition as possible is audible, I could split the cross fade over more than one block, meaning in the first block I could do part of the cross fading, then more in the next block, and so on, until done. The two buffers, the audio are always the same size.

And Daniel replied again;

Ok, well that’s easy as well. In this case I wouldn’t use SmoothedValue:

buffer.copyFromWithRamp (channel, 0, fadeOutSound.getReadPointer (channel), 
                         buffer.getNumSamples(), 1.0f, 0.0f);
buffer.addFromWithRamp (channel, 0, fadeInSound.getReadPointer (channel), 
                        buffer.getNumSamples(), 0.0f, 1.0f);

However I would advise against using the block size as fade length, since that can vary and will change your sound at random.

A better apploach is to allow the crossfde to start at any position within a block and possibly span over multiple blocks.

And I replied to Daniel;

Yes i tried that approach, keeping start position and number of samples in mind, and even spanning it, but after several days of tweaking and losing more of my little remaining hair, I just can’t seem to get a good enough transition.

TGVoiceBuffer.applyGainRamp (renderStartSample, renderNumSamples, previousLevel, endLevel);

And again to Daniel;

Just wanted to note that I am making headway, that is getting better results, using your buffer.copyFromWithRamp, instead of mine intermediary first voiceBuffer.applyGainRamp for all local buffers, and then add to “global” buffer.

And again to Daniel;

fadeOutSound.getReadPointer (channel)

One thing i am not quite clear on. With the source parameter, like in your example “fadeOutSound.getReadPointer (channel)”, does that include a “source” sample start location, or is just setting start sample to “0”?