Playing back an audio file at an arbitrary rate with upsampling and downsampling 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 &lt; 1, and downsampling to speedup the playback when the rate &gt; 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?
Some solutions that are ordered by complexity, simplest first.


The simplest solution is the one you have already implemented- pick the nearest value.
The next simplest is linear interpolation.  You use the two nearest values and use a weighted average based on how far the point is from each.  For instance, if the point you want is .3 samples past $x_1$ and .7 samples before $x_2$, the value would be $y = x_1*.7 + x_2*.3$.  This is still pretty simple and should have much better sound performance than your current solution.
The next simplest is quadratic interpolation, or, more generally, polynomial interpolation.  Polynomial interpolation is also sometimes referred to as spline interpolation.
The most complicated solution is Lanczos resampling.  This is where you use a windowed sinc filter to low-pass filter the data.  You pick the particular set of taps to use from the filter based on the particular delay (i.e. at what point you are between the samples).