/*
* %W %E
*
* Copyright 1998-2000 by Sun Microsystems, Inc.,
* 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
* All rights reserved.
*
* This software is the confidential and proprietary information
* of Sun Microsystems, Inc. ("Confidential Information"). You
* shall not disclose such Confidential Information and shall use
* it only in accordance with the terms of the license agreement
* you entered into with Sun.
*/
package com.sun.media.codec.audio.rc;
import javax.media.format.AudioFormat;
import javax.media.Format;
import javax.media.Buffer;
import javax.media.ResourceUnavailableException;
import com.sun.media.codec.audio.AudioCodec;
import com.sun.media.*;
/*
* This audio codec does the rate conversion between any two of
* 8k, 11.025k, 16k, 22.05k, 32k, 44.1k and 48k.
*/
public class RateCvrt extends AudioCodec {
public RateCvrt() {
inputFormats = new Format[] {
new AudioFormat(AudioFormat.LINEAR)
};
}
public String getName() {
return "Rate Conversion";
}
public Format[] getSupportedOutputFormats(Format input) {
if ( input == null ) {
return new Format[] {
new AudioFormat(AudioFormat.LINEAR)
};
}
if ( input instanceof AudioFormat) {
// supported rate: 8000, 11025, 16k, 22.5k, 32k, 44.1k, 48k
AudioFormat af = (AudioFormat) input;
int ssize = af.getSampleSizeInBits();
int chnl = af.getChannels();
int endian = af.getEndian();
int signed = af.getSigned();
outputFormats = new Format[] {
new AudioFormat(AudioFormat.LINEAR,
8000.0,
ssize,
chnl,
endian,
signed),
new AudioFormat(AudioFormat.LINEAR,
11025.0,
ssize,
chnl,
endian,
signed),
new AudioFormat(AudioFormat.LINEAR,
16000.0,
ssize,
chnl,
endian,
signed),
new AudioFormat(AudioFormat.LINEAR,
22050.0,
ssize,
chnl,
endian,
signed),
new AudioFormat(AudioFormat.LINEAR,
32000.0,
ssize,
chnl,
endian,
signed),
new AudioFormat(AudioFormat.LINEAR,
44100.0,
ssize,
chnl,
endian,
signed),
new AudioFormat(AudioFormat.LINEAR,
48000.0,
ssize,
chnl,
endian,
signed),
};
} else {
outputFormats = new Format[0];
}
return outputFormats;
}
public synchronized int process(Buffer in, Buffer out) {
if (!checkInputBuffer(in) ) {
//System.out.println("return due to bad input buffer");
return BUFFER_PROCESSED_FAILED;
}
if (isEOM(in) ) {
propagateEOM(out);
return BUFFER_PROCESSED_OK;
}
int inOffset = in.getOffset();
int inLen = in.getLength();
// TODO: may the rate change in the middle?
double inRate = ((AudioFormat)inputFormat).getSampleRate();
double outRate = ((AudioFormat)outputFormat).getSampleRate();
int chnl = ((AudioFormat)inputFormat).getChannels();
int bsize = ((AudioFormat)inputFormat).getSampleSizeInBits()/8;
int step = 0;
if ( chnl == 2 ) {
if (bsize == 2)
step = 4;
else
step = 2;
} else {
if ( bsize == 2)
step = 2;
else
step = 1;
}
if ( outRate == 0.0 || inRate == 0.0 ) {
return BUFFER_PROCESSED_FAILED;
}
double ratio = inRate/outRate;
int outLen = (int)((inLen-inOffset)*outRate/inRate + 0.5);
switch ( step ) {
case 2: // make sure outLen is even
if ( outLen%2 == 1)
outLen++;
break;
case 4: // make sure outLen is the multiply of 4
if ( outLen%4 != 0 )
outLen = (outLen/4 + 1) << 2;
break;
}
if ( inputFormat.getDataType() == Format.byteArray ) {
return doByteCvrt(in, inLen, inOffset, out, outLen, step, ratio);
} else if ( inputFormat.getDataType() == Format.shortArray) {
return doShortCvrt(in, inLen, inOffset, out, outLen, step, ratio);
} else if ( inputFormat.getDataType() == Format.intArray) {
return doIntCvrt(in, inLen, inOffset, out, outLen, step, ratio);
}
return BUFFER_PROCESSED_FAILED;
}
private int doByteCvrt(Buffer in, int inLen, int inOffset, Buffer out, int outLen, int step, double ratio) {
byte[] inData = (byte[])in.getData();
byte[] outData = validateByteArraySize(out, outLen);
int outOffset = 0;
out.setData(outData);
out.setFormat(outputFormat);
out.setOffset(0);
out.setLength(outLen);
// start to convert
double sum = 0.0;
int inPtr = inOffset;
int outPtr = outOffset;
int inEnd = inOffset + inLen;
if ( ratio == 1.0 ) { // no format changed
System.arraycopy(inData, inOffset, outData, outOffset, inLen);
return BUFFER_PROCESSED_OK;
}
if ( ratio > 1.0 ) { // subsampling
while ((inPtr <= (inEnd - step)) && (outPtr <= (outLen - step))) {
for ( int i = 0; i < step; i++) {
outData[outPtr++] = inData[inPtr+i];
}
sum += ratio;
while ( sum > 0.0 ) {
inPtr += step;
sum -= 1.0;
}
}
} else { // ratio < 1.0, up sampling
byte[] d = new byte[step];
while (inPtr <= (inEnd - step) ) {
for ( int i = 0; i < step; i++ ) {
outData[outPtr++] = inData[inPtr+i];
d[i]= inData[inPtr+i];
}
while ( (sum += ratio) < 1.0) {
if ( outPtr <= (outLen - step) )
for ( int i = 0; i < step; i++) {
outData[outPtr++] = d[i];
}
}
sum -= 1.0;
inPtr += step;
}
}
return BUFFER_PROCESSED_OK;
}
private int doShortCvrt(Buffer in, int inLen, int inOffset, Buffer out, int outLen, int step, double ratio) {
short[] inData = (short[])in.getData();
short[] outData = validateShortArraySize(out, outLen);
int outOffset = 0;
out.setData(outData);
out.setFormat(outputFormat);
out.setOffset(0);
out.setLength(outLen);
// start to convert
double sum = 0.0;
int inPtr = inOffset;
int outPtr = outOffset;
int inEnd = inOffset + inLen;
if ( ratio == 1.0 ) { // no format changed
System.arraycopy(inData, inOffset, outData, outOffset, inLen);
return BUFFER_PROCESSED_OK;
}
if ( ratio > 1.0 ) { // subsampling
while ((inPtr <= (inEnd - step)) && (outPtr <= (outLen - step))) {
for ( int i = 0; i < step; i++) {
outData[outPtr++] = inData[inPtr+i];
}
sum += ratio;
while ( sum > 0.0 ) {
inPtr += step;
sum -= 1.0;
}
}
} else { // ratio < 1.0, up sampling
short[] d = new short[step];
while (inPtr <= (inEnd - step) ) {
for ( int i = 0; i < step; i++ ) {
outData[outPtr++] = inData[inPtr+i];
d[i]= inData[inPtr+i];
}
while ( (sum += ratio) < 1.0 ) {
if ( outPtr <= (outLen - step) )
for ( int i = 0; i < step; i++)
outData[outPtr++] = d[i];
}
sum -= 1.0;
inPtr += step;
}
}
return BUFFER_PROCESSED_OK;
}
private int doIntCvrt(Buffer in, int inLen, int inOffset, Buffer out, int outLen, int step, double ratio) {
int[] inData = (int[])in.getData();
int[] outData = validateIntArraySize(out, outLen);
int outOffset = 0;
out.setData(outData);
out.setFormat(outputFormat);
out.setOffset(0);
out.setLength(outLen);
// start to convert
double sum = 0.0;
int inPtr = inOffset;
int outPtr = outOffset;
int inEnd = inOffset + inLen;
if ( ratio == 1.0 ) { // no format changed
System.arraycopy(inData, inOffset, outData, outOffset, inLen);
return BUFFER_PROCESSED_OK;
}
if ( ratio > 1.0 ) { // subsampling
while ((inPtr <= (inEnd - step)) && (outPtr <= (outLen - step))) {
for ( int i = 0; i < step; i++) {
outData[outPtr++] = inData[inPtr+i];
}
sum += ratio;
while ( sum > 0.0 ) {
inPtr += step;
sum -= 1.0;
}
}
} else { // ratio < 1.0, up sampling
int[] d = new int[step];
while (inPtr <= (inEnd - step) ) {
for ( int i = 0; i < step; i++ ) {
outData[outPtr++] = inData[inPtr+i];
d[i]= inData[inPtr+i];
}
while ( (sum += ratio) < 1.0 ) {
if ( outPtr <= (outLen - step) )
for ( int i = 0; i < step; i++)
outData[outPtr++] = d[i];
}
sum -= 1.0;
inPtr += step;
}
}
return BUFFER_PROCESSED_OK;
}
}
|