Skip to content

Commit

Permalink
* Smoothly interpolate pitch changes so they don't leave discontinuit…
Browse files Browse the repository at this point in the history
…ies when doing the resampling (sounds better)

* Added hermite interpolation for kicks, doesn't sound any better though so it's commented out
  • Loading branch information
asantoni committed Apr 28, 2008
1 parent 9b5985d commit 21c869c
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 4 deletions.
71 changes: 67 additions & 4 deletions mixxx/src/enginebufferscalelinear.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,19 @@
* *
***************************************************************************/

#include <QtCore>
#include "enginebufferscalelinear.h"
#include "mathstuff.h"
#include "readerextractwave.h"

#define RATE_LERP_LENGTH 200

EngineBufferScaleLinear::EngineBufferScaleLinear(ReaderExtractWave * wave) : EngineBufferScale(wave)
{
m_dBaseRate = 0.0f;
m_dTempo = 0.0f;
m_fOldTempo = 0.0f;
m_fOldBaseRate = 0.0f;
}

EngineBufferScaleLinear::~EngineBufferScaleLinear()
Expand All @@ -29,6 +36,9 @@ EngineBufferScaleLinear::~EngineBufferScaleLinear()

double EngineBufferScaleLinear::setTempo(double _tempo)
{
// if (m_fOldTempo != m_dTempo)
m_fOldTempo = m_dTempo; //Save the old tempo when the tempo changes

m_dTempo = _tempo;

if (m_dTempo>MAX_SEEK_SPEED)
Expand All @@ -47,6 +57,9 @@ double EngineBufferScaleLinear::setTempo(double _tempo)

void EngineBufferScaleLinear::setBaseRate(double dBaseRate)
{
// if (m_fOldBaseRate != m_dBaseRate)
m_fOldBaseRate = m_dBaseRate; //Save the old baserate when it changes

m_dBaseRate = dBaseRate*m_dTempo;
}

Expand All @@ -55,6 +68,18 @@ void EngineBufferScaleLinear::clear()
m_bClear = true;
}


// laurent de soras
inline float hermite4(float frac_pos, float xm1, float x0, float x1, float x2)
{
const float c = (x1 - xm1) * 0.5f;
const float v = x0 - x1;
const float w = c + v;
const float a = w + v + (x2 - x0) * 0.5f;
const float b_neg = w + a;
return ((((a * frac_pos) - b_neg) * frac_pos + c) * frac_pos + x0);
}

CSAMPLE * EngineBufferScaleLinear::scale(double playpos, unsigned long buf_size, float * pBase, unsigned long iBaseLength)
{
if (!pBase)
Expand All @@ -65,7 +90,9 @@ CSAMPLE * EngineBufferScaleLinear::scale(double playpos, unsigned long buf_size,
iBaseLength = READBUFFERSIZE; //Length of the base buffer
}

float rate_add = 2.*m_dBaseRate;
float rate_add_new = 2.*m_dBaseRate;
float rate_add_old = 2.*m_fOldBaseRate; //Smoothly interpolate to new playback rate
float rate_add = rate_add_new;

// Determine position in read_buffer to start from
new_playpos = playpos;
Expand All @@ -79,7 +106,23 @@ CSAMPLE * EngineBufferScaleLinear::scale(double playpos, unsigned long buf_size,
if (!even(prev)) prev--;
long next = (prev-2+READBUFFERSIZE)%READBUFFERSIZE;

//Smooth any changes in the playback rate over RATE_LERP_LENGTH samples. This
//prevents the change from being discontinuous and helps improve sound
//quality.
if (i < RATE_LERP_LENGTH)
{
rate_add = (rate_add_new-rate_add_old)/RATE_LERP_LENGTH*i + rate_add_old;
}
else
rate_add = rate_add_new;

CSAMPLE frac = new_playpos-floor(new_playpos);

//Hermite interpolation, see the comments in the "else" block below.
//buffer[i ] = hermite4(frac, wavebuffer[math_min(prev-2, 0)], wavebuffer[prev], wavebuffer[next], wavebuffer[(next+2)%READBUFFERSIZE]);
//buffer[i+1] = hermite4(frac, wavebuffer[math_min(prev-1, 1)], wavebuffer[prev+1], wavebuffer[(next+1)%READBUFFERSIZE], wavebuffer[(next+3)%READBUFFERSIZE]);

//Perform linear interpolation
buffer[i ] = wavebuffer[prev ] + frac*(wavebuffer[next ]-wavebuffer[prev ]);
buffer[i+1] = wavebuffer[prev+1] + frac*(wavebuffer[next+1]-wavebuffer[prev+1]);

Expand All @@ -92,10 +135,30 @@ CSAMPLE * EngineBufferScaleLinear::scale(double playpos, unsigned long buf_size,
{
long prev = (long)floor(new_playpos)%READBUFFERSIZE;
if (!even(prev)) prev--;

long next = (prev+2)%READBUFFERSIZE;

CSAMPLE frac = new_playpos - floor(new_playpos);

//Smooth any changes in the playback rate over RATE_LERP_LENGTH samples. This
//prevents the change from being discontinuous and helps improve sound
//quality.
if (i < RATE_LERP_LENGTH)
{
rate_add = (rate_add_new-rate_add_old)/RATE_LERP_LENGTH*i + rate_add_old;
}
else
rate_add = rate_add_new;

CSAMPLE frac = (new_playpos - floor(new_playpos))/2;

/* //Hermite interpolation - experimented with this to see if there was any noticeable increase
* in sound quality, but I couldn't hear any (the literature generally
* agrees that that is the case too) - Albert 04/27/08
buffer[i ] = hermite4(frac, wavebuffer[math_min(prev-2, 0)],
wavebuffer[prev], wavebuffer[next], wavebuffer[(next+2)%READBUFFERSIZE]);
buffer[i+1] = hermite4(frac, wavebuffer[math_min(prev-1, 1)],
wavebuffer[prev+1], wavebuffer[(next+1)%READBUFFERSIZE], wavebuffer[(next+3)%READBUFFERSIZE]);
*/

//Perform linear interpolation
buffer[i ] = wavebuffer[prev ] + frac*(wavebuffer[next ]-wavebuffer[prev ]);
buffer[i+1] = wavebuffer[prev+1] + frac*(wavebuffer[next+1]-wavebuffer[prev+1]);

Expand Down
4 changes: 4 additions & 0 deletions mixxx/src/enginebufferscalelinear.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ class EngineBufferScaleLinear : public EngineBufferScale {
/** Holds playback direction */
bool m_bBackwards;
bool m_bClear;
float m_fOldTempo; /** Keep the old tempo around so we can interpolate smoothly
between the old one and the new one to avoid any discontinuities
in the audio when you change the playback rate */
float m_fOldBaseRate; /** Same as old tempo, but for the base playback rate */
};

#endif

0 comments on commit 21c869c

Please sign in to comment.