Help - Search - Members - Calendar
Full Version: upsampling PCM
Hydrogenaudio Forums > Hydrogenaudio Forum > Scientific Discussion
amigo
I am looking for an open source library or algorithm to upsampling pcm file from 8k to 16k(or 32k is better).
Since system limitation, integer (fixed point) is better than floating-point. And, speed is more important than quality.
I had try resample(http://www-ccrma.stanford.edu/~jos/), but it seem a little bit complex.

Additionally, how to convert 8 bitspersample data to 16 bitspersample?
cabbagerat
QUOTE(amigo @ Sep 30 2006, 22:54) *

I am looking for an open source library or algorithm to upsampling pcm file from 8k to 16k(or 32k is better).
Since system limitation, integer (fixed point) is better than floating-point. And, speed is more important than quality.

libsamplerate is a starting point. It does need floating point though. If it's all about performance, then coding a simple zeroeth order hold or linear interpolation SRC program with fixed point would be trivial. I can describe the algorithms required if you need them.

QUOTE(amigo @ Sep 30 2006, 22:54) *

Additionally, how to convert 8 bitspersample data to 16 bitspersample?
The fastest way would be simple sign extension. It's likely that your hardware (it sounds like you are targetting an embedded system) will have an instruction to provide sign extension from 8 to 16 (ARMv5, x86 and others have such instructions). If you are writing in C, then a good compiler should generate these instructions from an explicit or implicit cast.
pest
QUOTE(amigo @ Sep 30 2006, 22:54) *

Additionally, how to convert 8 bitspersample data to 16 bitspersample?


8bit pcm (can) be unsigned so i would do something as

CODE

  upsampled = ((signed short int)(sample)-128) << 8



edit: 8-bit pcm isn't always unsigned rolleyes.gif

amigo
QUOTE(cabbagerat @ Oct 1 2006, 18:32) *

libsamplerate is a starting point. It does need floating point though. If it's all about performance, then coding a simple zeroeth order hold or linear interpolation SRC program with fixed point would be trivial. I can describe the algorithms required if you need them.


Yes, I need. Thank you smile.gif
cabbagerat
Ok, the zeroth order hold algorithm is very simple. In your target pulse train (Y[n]) you set Y[n] to the value of X[n] which is most recent. For upsampling from 8k to 16k, your new sample train will look like Y = X[0] X[0] X[1] X[1] X[2] X[2] and so on. Upsampling from 8 to 32k, your result train will look like this: Y = X[0] X[0] X[0] X[0] X[1] X[1] X[1] X[1] and so on. This algorithm is very poor from a quality perspective, but can be implemented almost for free on low-powered embedded systems (you just pass the DAC the same value for a few consecutive bits).

A slightly (but only slightly) better (from a quality perspective) and not much slower algorithm would be a linear interpolation. For example - Y = X[0] (0.5*X[0]+0.5*X[1]) X[1] (0.5*X[1]+0.5*X[2]). As I am sure you can see, you can implement this with an average of one add and two shifts every second sample - or half and add and one shift a sample. Unless your hardware is very, very slow then this won't prove taxing at all.

The quality of these algorithms is very poor. Their only advantage is high efficiency and ease of implementation. If you have any CPU power to spare, I would encourage you to use a better algorithm. Such algorithms have been discussed here in the past, or you can look at a good textbook.
SebastianG
If you go for speed and are not satisfied with the quality of linear interpolation for 8->16 kHz you could also try this:

... X[3] f(3) X[4] f(4) X[5] f(5) ...

where f(index) =
+ a * (X[index-0]+X[index+1])
+ b * (X[index-1]+X[index+2])
+ c * (X[index-2]+X[index+3])
+ ...

linear interpolation for 2X oversampling is a special case of this with a=1/2, b=c=0
(corresponds to half-band LPF with 2 zeros at -1)

The next best thing would be to use
a = 9/16
b = -1/16, c=0
(corresponds to half-band LPF with 4 zeros at -1 plus two other zeros)

If still not good enough try
a = 150/256
b = -25/256
c = 3/256
(corresponds to half-band LPF with 6 zeros at -1 plus four other zeros)

For 4X oversampling you could repeat this step. If you do, make the first stage at least as good as the second because the quality of the first stage is more important than the 2nd for oversampling. For example: Use the three-coefficient interpolation for the first stage (1X->2X) and the two-coefficient interpolation for the 2nd stage (2X->4X). That should be a good quality/speed trade-off.

An implementation may look like this:
itpl = (150*(X[i]+X[i+1]) - 25*(X[i-1]+X[i+2]) + 3*(X[i-2]+X[i+3]) + 128) >> 8;
pest
QUOTE(SebastianG @ Oct 2 2006, 12:21) *

itpl = (150*(X[i]+X[i+1]) - 25*(X[i-1]+X[i+2]) + 3*(X[i-2]+X[i+3]) + 128) >> 8;


isn't a 127 better for the rounder if you work on signed data.
SebastianG
It doesn't really matter, does it?

(x+128)>>8 maps -128..127 to 0 and is exactly the same as round(x/256.0)
(x+127)>>8 maps -127..128 to 0 which is more like round((x-1)/256.0)
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2008 Invision Power Services, Inc.