package org.red5.app.sip;
public class ResampleUtils {
public static byte[] resample( float sampleRateFactor, float[] s1 ) {
int o1 = 0;
int l1 = s1.length;
int resampledLength = (int) ( (float) l1 / sampleRateFactor );
float[] tmp = new float[ resampledLength ];
double oldIndex = o1;
for ( int i = o1; i < o1 + resampledLength; i++ ) {
if ( ( (int) oldIndex + 1 ) < s1.length ) {
tmp[ i ] = interpolate0( s1, (float) oldIndex );
}
else {
break; // end of source
}
oldIndex += sampleRateFactor;
}
oldIndex = o1;
for ( int i = o1; i < o1 + resampledLength; i++ ) {
if ( ( (int) oldIndex + 1 ) < s1.length ) {
tmp[ i ] = interpolate1( s1, (float) oldIndex );
}
else {
break; // end of source
}
oldIndex += sampleRateFactor;
}
byte[] outSample = new byte[ resampledLength * 2 ];
int pos = 0;
for ( int z = o1; z < o1 + resampledLength; z++ ) {
outSample[ pos++ ] = (byte) ( (int) tmp[ z ] & 0xFF );
outSample[ pos++ ] = (byte) ( ( (int) tmp[ z ] & 0xFF00 ) >> 8 );
}
return outSample;
}
public static int byte2int( byte b ) { // return (b>=0)? b : -((b^0xFF)+1);
// return (b>=0)? b : b+0x100;
return ( b + 0x100 ) % 0x100;
}
public static int byte2int( byte b1, byte b2 ) {
return ( ( ( b1 + 0x100 ) % 0x100 ) << 8 ) + ( b2 + 0x100 ) % 0x100;
}
/**
* zeroth order interpolation
*
* @param data
* seen as circular buffer when array out of bounds
*/
public static float interpolate0( float[] data, float index ) {
try {
return data[ ( (int) index ) % data.length ];
}
catch ( ArrayIndexOutOfBoundsException e ) {
return 0;
}
}
/**
* first order interpolation
*
* @param data
* seen as circular buffer when array out of bounds
*/
public static float interpolate1( float[] data, float index ) {
try {
int ip = ( (int) index );
float fp = index - ip;
return data[ ip % data.length ] * ( 1 - fp ) + data[ ( ip + 1 ) % data.length ] * fp;
}
catch ( ArrayIndexOutOfBoundsException e ) {
return 0;
}
}
/**
* second order interpolation
*
* @param data
* seen as circular buffer when array out of bounds
*/
public static float interpolate2( float[] data, float index ) {
try {
// Newton's 2nd order interpolation
int ip = ( (int) index );
float fp = index - ip;
float d0 = data[ ip % data.length ];
float d1 = data[ ( ip + 1 ) % data.length ];
float d2 = data[ ( ip + 2 ) % data.length ];
float a0 = d0;
float a1 = d1 - d0;
float a2 = ( d2 - d1 - a1 ) / 2;
return a0 + a1 * fp + a2 * fp * ( fp - 1 );
}
catch ( ArrayIndexOutOfBoundsException e ) {
return 0;
}
}
/**
* third order interpolation
*
* @param data
* seen as circular buffer when array out of bounds
*/
public static float interpolate3( float[] data, float index ) {
try {
// cubic hermite interpolation
int ip = (int) index;
float fp = index - ip;
float dm1 = data[ ( ip - 1 ) % data.length ];
float d0 = data[ ip % data.length ];
float d1 = data[ ( ip + 1 ) % data.length ];
float d2 = data[ ( ip + 2 ) % data.length ];
float a = ( 3 * ( d0 - d1 ) - dm1 + d2 ) / 2;
float b = 2 * d1 + dm1 - ( 5 * d0 + d2 ) / 2;
float c = ( d1 - dm1 ) / 2;
return ( ( ( a * fp ) + b ) * fp + c ) * fp + data[ ip % data.length ];
}
catch ( ArrayIndexOutOfBoundsException e ) {
return 0;
}
}
public static float[] normalize(float[] audio, int length)
{
// Scan for max peak value here
float peak = 0;
for (int n = 0; n < length; n++)
{
float val = Math.abs(audio[n]);
if (val > peak)
{
peak = val;
}
}
// Peak is now the loudest point, calculate ratio
float r1 = 32768 / peak;
// Don't increase by over 500% to prevent loud background noise, and normalize to 98%
float ratio = Math.min(r1, 5) * .98f;
for (int n = 0; n < length; n++)
{
audio[n] *= ratio;
}
return audio;
}
}