0

I am implementing real time linear interpolation of audio data, which is stored in interleaved audio buffers. Audio files can be single- or multichannel. In case of single channel audio files, I interpolate as follows:

f_dex = offset + ((position / oldlength) * (newlength * b_channelcount));
i_dex = trunc(f_dex); // get truncated index
fraction = f_dex - i_dex; // calculate fraction value for interpolation
b_read = (b_sample[i_dex] + fraction * (b_sample[i_dex + b_channelcount] - b_sample[i_dex]));
outsample_left += b_read;
outsample_right += b_read;

This sounds wonderful and I'm not having any issues. However, when I want to read multichannel files, I must correct the calculated read position to make sure it is on the first sample in the corresponding frame, such as:

f_dex = offset + ((position / oldlength) * (newlength * b_channelcount));
if ((long)trunc(f_dex) % 2) {
    f_dex -= 1.0;
}
i_dex = trunc(f_dex); // get truncated index
fraction = f_dex - i_dex; // calculate fraction value for interpolation
outsample_left += (b_sample[i_dex] + fraction * (b_sample[i_dex + b_channelcount] - b_sample[i_dex])) * w_read;
outsample_right += (b_sample[i_dex + 1] + fraction * (b_sample[(i_dex + 1) + b_channelcount] - b_sample[i_dex + 1])) * w_read;

Now this introduces some digital noise and I can't really explain why. Is there any other/better way to apply real time linear interpolation to interleaved stereo files?

duplode
  • 33,731
  • 7
  • 79
  • 150

1 Answers1

0

I'm a little confused by your variable names, position, oldlength and outsample_left/outsample_right seem to be for the output while newlength and offset are from the input, b_sample?

I think that your problem is including b_channelcount in the computation of f_dex. Try instead

f_dex = offset + ((position / oldlength) * newlength);

and you can leave out the % 2 check and adjustment. That adjustment isn't doing what you intend.

Addendum 11/7: I missed something, you also need to adjust your use of i_dex, as I've set up f_dex here it counts the whole block for each channel as 1. Where before you had b_sample[i_dex], instead use b_sample[i_dex*b_channelcount]; this will put you on the first sample of the block (left if stereo). Likewise you can use b_sample[i_dex*b_channelcount + 1] for a right channel if there is one, b_sample[(i_dex+1)*b_channelcount] for the first sample of the next block for interpolation, etc.

hcs
  • 1,514
  • 9
  • 14
  • `for (i = 0; i < newlength; i++) { f_dex = (i / oldlength) * newlength; i_dex = trunc(f_dex); // get truncated index fraction = f_dex - i_dex; b_read = buffer[i_dex] + fraction * (buffer[i_dex + b_channelcount] - buffer[i_dex]); out_left[i] = b_read * pan_left; out_right[i] = b_read * pan_right; }` – Matthias Müller Nov 07 '14 at 09:53
  • I'm sorry, I can't seem to figure out how to post proper code in comments..if possible at all..Anyway this should make the variable names and intentions a bit clearer. I see this working with single channel files, but it won't work with multi channel. In addition, how can I make sure that the calculation for `f_dex` is on the first sample in the frame? – Matthias Müller Nov 07 '14 at 10:00
  • @MatthiasMüller a simple solution is to edit that code into the initial question (not necessarily replacing your old code though that is an option). I've edited my answer t cover the issue that `f_dex` (and thus `i_dex`) is now counting frames instead of individual samples. – hcs Nov 07 '14 at 19:38
  • Thank you very much @hcs! This solved my problem and the code runs stable now! And thanks for the tips concerning editing the posts. – Matthias Müller Nov 08 '14 at 11:33