Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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??

like image 933
arakn0 Avatar asked Jul 15 '10 21:07

arakn0


2 Answers

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

like image 60
Nils Pipenbrinck Avatar answered Nov 16 '22 02:11

Nils Pipenbrinck


Linear interpolation introduces artifacts. There is nice java library with high-quality resampling - JSSRC (http://jssrc.khadkevich.org/).

The code is now available on Github: https://github.com/hutm/JSSRC

like image 39
Maksim Khadkevich Avatar answered Nov 16 '22 00:11

Maksim Khadkevich