I was playing around with some loop stretching code and got this ultra simple one working. Sounds actually pretty good. And is time-perfect, meaning that it outputs the correct size. I was testing SoundTouch but it kept removing 1ms of my sample data from the start of the audio. :-\ I even tested the command-line version from the site and the result was 100% the same. Not sure what’s going on. Anyway, the code is simple, but maybe I will improve it over time and make it into a module if anyone wants.
void WLoopChanger::process(AudioSampleBuffer& audio, const int beats, const float sampleRate, const int sectionsPerBeat, const float originalBPM, const float targetBPM)
{
AudioSampleBuffer copyAudio(audio);
//
double nSamplesPerSection = ((60.0 / double(targetBPM)) / double(sectionsPerBeat)) * double(sampleRate);
double nSamplesPerSectionOriginal = ((60.0 / double(originalBPM)) / double(sectionsPerBeat)) * double(sampleRate);
int finalSize = int(nSamplesPerSection * double(beats) * double(sectionsPerBeat));
int nSamplesPerSubSectionFade = int(jmax(4.0, nSamplesPerSectionOriginal / 8.0));
//
audio.setSize(2, finalSize, false, false, true);
audio.clear();
//
for (int xp = 0; xp < (beats * sectionsPerBeat); xp++)
{
int xStart = int(nSamplesPerSection * double(xp));
int xStartOriginal = int(nSamplesPerSectionOriginal * double(xp));
//
if (xp > 0)
{
xStart -= nSamplesPerSubSectionFade;
xStartOriginal -= nSamplesPerSubSectionFade;
}
//
for (int xsamp = 0; xsamp < (nSamplesPerSection + nSamplesPerSubSectionFade); xsamp++)
{
float multiplier = 1.0f;
//
if (xp > 0 && xsamp < nSamplesPerSubSectionFade)
{
multiplier = (1.0f / nSamplesPerSubSectionFade) * float(xsamp);
}
//
if (xsamp > nSamplesPerSection)
{
multiplier = 1.0f - ((1.0f / nSamplesPerSubSectionFade) * float(xsamp - nSamplesPerSection));
}
//
if (((xsamp + xStart) < (audio.getNumSamples() - 1)) &&
((xsamp + xStartOriginal) < (copyAudio.getNumSamples() - 1)))
{
audio.addSample(0, xsamp + xStart, copyAudio.getSample(0, xsamp + xStartOriginal) * multiplier);
audio.addSample(1, xsamp + xStart, copyAudio.getSample(1, xsamp + xStartOriginal) * multiplier);
}
}
}
}
Cheers, WilliamK
www.Wusik.com