Background: My overall goal is to create an audio file player which can playback an audio file at an arbitrary rate. The rate can change continuously as the file plays. This means upsampling to slowdown the playback when the rate < 1
, and downsampling to speedup the playback when the rate > 1
. (I'm not concerned with maintaining pitch.)
Let's focus on the slowdown (upsample) part to make the question simpler.
I read that to upsample by a rational fraction L/M
, I should first
- Upsample by
L
- Apply an interpolation (lowpass) filter
- Downsample by
M
However, this doesn't work well for an online, live context, because L
or M
can be very large depending on the desired playback rate, requiring large buffers for upsampling/downsampling. I want to process the audio file in small chunks as it plays, so my buffers must be kept to a reasonable size.
I decided to try the following algorithm instead, for upsampling by an arbitrary floating point rate:
// pseudo-code upsample algorithm
sloppy_upsample(int source[], int destination[], float rate, int frames):
for each frame i:
destination[i] = source[round(i * rate)];
This is a sloppy "zero order hold" algorithm that probably doesn't get the sample rate exactly correct, but it actually sounds surprisingly good for my purposes. I also like this algorithm for its simplicity. But, of course, there's audible aliasing.
I know that I can apply a lowpass filter before upsampling to prevent aliasing, but I'm not sure what frequency to set the cutoff at. In similar situations such as this one, the cutoff could be set to less than L * 0.5
.
- Is it possible to select a good cutoff for my
sloppy_upsample
function above that prevents aliasing? - Is there another approach for upsampling/downsampling that works well for live playback?