Reputation: 23
I'm writing a granular synthesis engine with linear interpolation. The problem is that interpolation as currently implemented is roughly 10% heavier on the CPU than the processing without interpolation.
I am posting a simplified sample program showcasing the processing I apply to an interleaved sample buffer. Is there any way I could make the calculation inside the interpolation
function more efficient and thus less heavy on the CPU? The function works perfectly and results in very smooth sounding audio. It's just the CPU consumption that should be optimized.
I write code in my free time and I'm therefore not a very experienced programmer. I can't seem to wrap my head around this. Been struggling with this for weeks now.
I've edited the code to correct a type mismatch of the dist
variable. Another edit to avoid int/long truncated results.
int main(void) {
long i;
long oldlength = 5000;
long newlength = 10000;
double dist;
double oldbuffer[oldlength]; // assume the buffer contains values
double newbuffer[newlength];
// method with linear interpolation
for (i = 0; i < newlength; i++) {
dist = ((double)i / (double)newlength) * (double)oldlength;
newbuffer[i] = interpolation(dist, oldbuffer, 1, 0);
}
// method without linear interpolation
for (i = 0; i < newlength; i++) {
dist = ((double)i / (double)newlength) * (double)oldlength;
newbuffer[i] = oldbuffer[(long)dist];
}
return 0;
}
double interpolation(double dist, float *buffer, short chcount, short ch) {
// dist = current read position in buffer
// buffer = interleaved sample buffer
// chcount = channels contained in sample buffer
// ch = channel to be read from buffer
long i = (long)dist; // get truncated index
dist -= (long)dist; // calculate fraction value for interpolation
return buffer[i * chcount + ch] + dist * (buffer[(i + 1) * chcount + ch] - buffer[i * chcount + ch]);
}
Upvotes: 1
Views: 2135
Reputation: 6204
There is one notable issue in your current code. The two lines:
dist = (i / newlength) * oldlength;
will always return 0
because i
and newlength
are both integers so i / newlength
will return an integer result. To fix it simply do:
dist = ((double) i / newlength) * oldlength;
Next, how are you measuring that the interpolation code takes 10% more CPU? The code as is executes so fast that any time/profile measurement would be mostly meaningless. This is also combined with the fact that any decent compiler could probably optimize the loops entirely away in a release build.
I made two quick changes to your code to make benchmarking results more meaningful. One is to repeat the interpolation tests multiple times like:
long NUMTESTS = 100000;
...
for (int j = 0; j < NUMTESTS; ++j) {
for (i = 0; i < newlength; i++) {
dist = ((double) i / newlength) * oldlength;
newbuffer[i] = interpolation(dist, oldbuffer, 1, 0);
}
}
Adjust the value of NUMTESTS
as needed to give you at least several seconds of runtime per test. The second is to make sure the compiler cannot optimize the loops away. At the end do something like:
double sum = 0;
...
for (i = 0; i < newlength; ++i)
{
sum += newbuffer[i];
}
printf("buffer = %f\n", sum);
With these changes in VS2013 I get identical run times of 6.6 seconds for both the interpolation and non-interpolation loops (using 100,000 test loops as above).
Upvotes: 1