resample / upsample sound frames from 8Khz to 48Khz (Java/Android)

arakn0 picture arakn0 · Jul 15, 2010 · Viewed 10.3k times · Source

The application that I am trying to develop for andriod, records frames at 48Khz (PCM 16bits & mono) and sends them to the network. Also, there is an incoming stream of audio at 8Khz. So, I receive 8Khz sampled frames and play them (my AudioTrack object is set to 8Khz), but when playing them, everything works but the latency is HUGE. It takes like around 3 seconds until you hear something.

I think that if I upsample the received frames from 8Khz to 48Khz and play them, there won't be such a huge playing latency. In fact when I record and play frames at the same rate, the latency is really low. The bad thing is that I am forced to do it this way: send to 48Khz and receive to 8Khz.

As explained before, I'm trying to upsample a sound frame (16bits PCM) from 8Khz to 48Khz. Does anybody know any routine/library/API in Java that does this???

I know the basics about upsampling a discreet signal, but I consider that to design and implement my own FIR filter and convolute it with the audio stream ....is way too much. Also, it is over my knowledge.

So...does anybody can help me with this?? Does anybody know any library/routine in Java that I can use?? Any suggestions or alternatives??

Answer

Nils Pipenbrinck picture Nils Pipenbrinck · Jul 16, 2010

A quick and dirty solution would be linear interpolation. Since you're always sampling up by a factor of six this is really easy to do:

It works somewhat like this (C-code, and untested, and I don't handle the last iteration properly, but it shows the idea I think).

void resample (short * output, short * input, int n)
{
  // output ought to be 6 times as large as input (48000/8000).

  int i;
  for (i=0; i<n-1; i++)
  {
    output[i*6+0] = input[i]*6/6 + input[i+1]*0/6;
    output[i*6+1] = input[i]*5/6 + input[i+1]*1/6;
    output[i*6+2] = input[i]*4/6 + input[i+1]*2/6;
    output[i*6+3] = input[i]*3/6 + input[i+1]*3/6;
    output[i*6+4] = input[i]*2/6 + input[i+1]*4/6;
    output[i*6+5] = input[i]*1/6 + input[i+1]*5/6;
  }

Linear interpolation won't give you great sound quality but it is cheap and fast. You can improve this using cubic interpolation if you want to.

If you want a fast and high quality resampling I suggest that you compile a c resampling library like libresample using the Android-NDK and call it from java using JNI. That will be a lot faster. Writing the JNI code is something most people shy away from, but it's quite easy.. The NDK has lots of examples for this.

http://www.mega-nerd.com/SRC/index.html