xFade/CrossFade Sample Loop


#1

Does JUCE have some sort of basic support for this?

I’ve tried to make modifications to the juce_Synthesizer class with no avail:

[code]void DoInterpolate(float* l, float r, const float inL, const float* inR, double sourceSamplePosition)
{
const int pos = (int) sourceSamplePosition;
const float alpha = (float) (sourceSamplePosition - pos);
const float invAlpha = 1.0f - alpha;

// just using a very simple linear interpolation here..
*l = (inL [pos] * invAlpha + inL [pos + 1] * alpha);
*r = (inR != nullptr) ? (inR [pos] * invAlpha + inR [pos + 1] * alpha)
                            : *l;

}

//==============================================================================
void SamplerVoice::renderNextBlock (AudioSampleBuffer& outputBuffer, int startSample, int numSamples)
{
const SamplerSound* const playingSound = static_cast <SamplerSound*> (getCurrentlyPlayingSound().getObject());

if (playingSound != nullptr)
{
	const int mid = playingSound->length / 2;
	const int tenth = playingSound->length / 10;
	const float invtenth = 1.f/tenth;
	double FadePosition = 0.f;
	bool togglefade = false;

    const float* const inL = playingSound->data->getSampleData (0, 0);
    const float* const inR = playingSound->data->getNumChannels() > 1
                                ? playingSound->data->getSampleData (1, 0) : nullptr;

    float* outL = outputBuffer.getSampleData (0, startSample);
    float* outR = outputBuffer.getNumChannels() > 1 ? outputBuffer.getSampleData (1, startSample) : nullptr;

    while (--numSamples >= 0)
    {
        float l = 0.f;
        float r = 0.f;

		DoInterpolate(&l, &r, inL, inR, sourceSamplePosition);

        l *= lgain;
        r *= rgain;


        if (isInAttack)
        {
            l *= attackReleaseLevel;
            r *= attackReleaseLevel;

            attackReleaseLevel += attackDelta;

            if (attackReleaseLevel >= 1.0f)
            {
                attackReleaseLevel = 1.0f;
                isInAttack = false;
            }
        }
        else if (isInRelease)
        {
            l *= attackReleaseLevel;
            r *= attackReleaseLevel;

            attackReleaseLevel += releaseDelta;

            if (attackReleaseLevel <= 0.0f)
            {
                stopNote (false);
                break;
            }
        }



		if(sourceSamplePosition >= playingSound->length-tenth)
        {
			if(togglefade == false)
			{
				togglefade = true;
				FadePosition = mid;
			}

			l *= 1.0f - float((sourceSamplePosition - (playingSound->length-tenth)) * invtenth);
			r *= 1.0f - float((sourceSamplePosition - (playingSound->length-tenth)) * invtenth);

			float l2 = 0.f;
			float r2 = 0.f;
			DoInterpolate(&l2, &r2, inL, inR, FadePosition);
			l2 *= lgain;
			r2 *= rgain;
			l2 *= float((sourceSamplePosition - (playingSound->length-tenth)) * invtenth);
			r2 *= float((sourceSamplePosition - (playingSound->length-tenth)) * invtenth);

			l += l2;
			r += r2;

			FadePosition += pitchRatio;
		}



        if (outR != nullptr)
        {
            *outL++ += l;
            *outR++ += r;
        }
        else
        {
            *outL++ += (l + r) * 0.5f;
        }

        sourceSamplePosition += pitchRatio;

        if (sourceSamplePosition > playingSound->length)
        {
            //stopNote (false);
			togglefade = false;
			sourceSamplePosition = FadePosition;
            break;
        }
    }
}

}[/code]


#2

I decided to use Audacity to pre-bake the crossfade into the samples.

I duplicated each channel, reversed the duplicate and set a cross fade out effect
then on the original channel I set a cross fade in effect
baked out the sample

so now all I need to do is make the samples loop in juce_Sampler … continued here:
http://rawmaterialsoftware.com/viewtopic.php?f=8&t=10994