Linear interpolation

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

On my LFO I use the code below for interpolation and it sounds OK. But the same code on an oscillator sounds worse than no interpolation. Also it's very slow for 14 voices unison(stacked oscillator). Can someone spot some mistakes or have a better way of interpolating.

Code: Select all

       float f;
		float whole;

		unsigned int pos = (phase * wavevector.size()) - 0.5;  

		f = modf(phase,&whole);   //calulate the fraction		

		result = (wavevector[pos]*(1 - f)) + (wavevector[pos+1] * f); 

Post

Using modf() is typically slow, converting floating point to integer+fractional parts is usually best done with something like the following:

Code: Select all

  // scale for tablesize
  float pos = phase * tablesize;

  // convert to integer (fast with sensible compiler options)
  // casting to unsigned might or might not be marginally slower
  int posInt = (int) pos;

  // convert the integer back to float (also pretty fast)
  // then subtract to get fractional part of position only
  pos -= posInt;

  // now the lerp can be done something like:
  result = (1-pos) * wave[posInt] + pos * wave[posInt+1];
No idea about the "sounds worse" part, maybe you are not handling the wrap around case properly or something?

Post

It's hard to see without the range reduction on the phase variable - if wavevector.size() returns the actual number of samples in buffer, it would seem like you're going to access up to two elements past the buffer end. Otherwise, it looks like it should. People usually make the buffersize a power of two, then you get virtually free range reduction (modf can be 'slow'):

Code: Select all

for(int i = 0; i < nSamples; ++i)
{
	x = (int)phase;
	fraction = phase - x;
	output[i] = waveTable[x] * (1.0f - fraction) + waveTable[x + 1] * fraction;

	phase += rotation;
	phaseWrap = (int)phase;
	phase = phase - phaseWrap + (phaseWrap & (waveSize - 1));
}
where phase is a float, and rotation is the phase increment/sample, phaseWrap & waveSize are integers. Here i have also ensured the buffer is an extra two samples long (with correct values), so the reduction code can be as simple as possible. waveSize must still be without the extra two samples.

Depending on what you are synthesizing, if your CPU is somewhat new, it may be faster using something like iir 'filters'/resonators or function approximations. This is also because these algorithms tend to be more suited for SIMD accelerations.

Post

mystran wrote:Using modf() is typically slow, converting floating point to integer+fractional parts is usually best done with something like the following:

Code: Select all

  // scale for tablesize
  float pos = phase * tablesize;

  // convert to integer (fast with sensible compiler options)
  // casting to unsigned might or might not be marginally slower
  int posInt = (int) pos;

  // convert the integer back to float (also pretty fast)
  // then subtract to get fractional part of position only
  pos -= posInt;

  // now the lerp can be done something like:
  result = (1-pos) * wave[posInt] + pos * wave[posInt+1]; 
No idea about the "sounds worse" part, maybe you are not handling the wrap around case properly or something?
This worked great. It sounds better and does not use much extra CPU. Thanks! :)

Post

ftr

the entire rest of the world uses linear interpolation, but information isn't as "precious" and guarded as it is amongst audio developers. i think they call it lerp but too afraid of secret polcie to ask and got back to my audio developer seat before anyone saw.

and like this drops a *
x[n] + fraction * (x[n + 1] - x[n])
you come and go, you come and go. amitabha neither a follower nor a leader be tagore "where roads are made i lose my way" where there is certainty, consideration is absent.

Post Reply

Return to “DSP and Plugin Development”