Java examples for javax.sound.sampled:Audio
Converts (re samples and mono to/from stereo) audio data.
/*/* w ww . jav a 2 s . c o m*/ Copyright 2009 The Open University http://www.open.ac.uk/lts/projects/audioapplets/ This file is part of the "Open University audio applets" project. The "Open University audio applets" project is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The "Open University audio applets" project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the "Open University audio applets" project. If not, see <http://www.gnu.org/licenses/>. */ //package com.java2s; public class Main { /** * Converts (resamples and mono to/from stereo) audio data. * @param data Input data * @param length Amount of input buffer that is actually used * @param inStereo True if input is stereo * @param outStereo True if output should be stereo * @param inFrequency Frequency of input * @param outFrequency Frequency of output * @return Converted audio data */ public static byte[] convert(byte[] data, int length, boolean inStereo, boolean outStereo, int inFrequency, int outFrequency) { if (inStereo == outStereo && inFrequency == outFrequency) { return trimArray(data, length); } short[] converted = byteToShort(data, length, inStereo && !outStereo); converted = resample(converted, converted.length, outStereo, inFrequency, outFrequency); return shortToByte(converted, converted.length, !inStereo && outStereo); } /** * @param data Data * @param length Length of valid data * @return Array trimmed to length (or same array if it already is) */ public static short[] trimArray(short[] data, int length) { if (data.length == length) { return data; } else { short[] output = new short[length]; System.arraycopy(output, 0, data, 0, length); return output; } } /** * @param data Data * @param length Length of valid data * @return Array trimmed to length (or same array if it already is) */ public static byte[] trimArray(byte[] data, int length) { if (data.length == length) { return data; } else { byte[] output = new byte[length]; System.arraycopy(output, 0, data, 0, length); return output; } } /** * Converts audio data in 'byte' format (little-endian 16-bit) to short array * @param data Data * @param length Number of bytes to actually use * @param reduceStereo If true, reduces stereo data to become mono * @return Short version of data */ public static short[] byteToShort(byte[] data, int length, boolean reduceStereo) { if (reduceStereo) { short[] shortData = new short[length / 4]; for (int i = 0; i < shortData.length; i++) { short val1 = (short) ((data[i * 4 + 1] << 8) | (data[i * 4] & 0xff)); short val2 = (short) ((data[i * 4 + 3] << 8) | (data[i * 4 + 2] & 0xff)); shortData[i] = (short) (((int) val1 + (int) val2) / 2); } return shortData; } else { short[] shortData = new short[length / 2]; for (int i = 0; i < shortData.length; i++) { shortData[i] = (short) ((data[i * 2 + 1] << 8) | (data[i * 2] & 0xff)); } return shortData; } } /** * Resamples audio data using simple methods. * @param data Input data * @param length Amount of input buffer that is actually used * @param stereo True if input is stereo * @param inFrequency Frequency of input * @param outFrequency Frequency of output * @return Resampled audio data */ public static short[] resample(short[] data, int length, boolean stereo, int inFrequency, int outFrequency) { if (inFrequency < outFrequency) { return upsample(data, length, stereo, inFrequency, outFrequency); } if (inFrequency > outFrequency) { return downsample(data, length, stereo, inFrequency, outFrequency); } return trimArray(data, length); } /** * Converts audio data in 'short' format (little-endian) to byte array. * @param data Data buffer * @param length Length of buffer that's used (number of shorts) * @param expandMono If true, expands mono data into stereo * @return Byte array containing translated version */ public static byte[] shortToByte(short[] data, int length, boolean expandMono) { byte[] byteData; if (expandMono) { byteData = new byte[length * 4]; for (int i = 0; i < length; i++) { byteData[i * 4] = (byte) data[i]; byteData[i * 4 + 1] = (byte) (data[i] >> 8); byteData[i * 4 + 2] = (byte) data[i]; byteData[i * 4 + 3] = (byte) (data[i] >> 8); } } else { byteData = new byte[length * 2]; for (int i = 0; i < length; i++) { byteData[i * 2] = (byte) data[i]; byteData[i * 2 + 1] = (byte) (data[i] >> 8); } } return byteData; } /** * Basic upsampling algorithm. Uses a linear approximation to fill in the * missing data. * @param data Input data * @param length Amount of input buffer that is actually used * @param stereo True if input is stereo * @param inFrequency Frequency of input * @param outFrequency Frequency of output * @return Upsampled audio data */ private static short[] upsample(short[] data, int length, boolean stereo, int inFrequency, int outFrequency) { // Special case for no action if (inFrequency == outFrequency) { return trimArray(data, length); } double scale = (double) inFrequency / (double) outFrequency; double pos = 0.0; short[] output; if (!stereo) { output = new short[(int) (length / scale)]; for (int i = 0; i < output.length; i++) { int inPos = (int) pos; double proportion = pos - inPos; if (inPos >= length - 1) { inPos = length - 2; proportion = 1.0; } output[i] = (short) Math .round(data[inPos] * (1.0 - proportion) + data[inPos + 1] * proportion); pos += scale; } } else { output = new short[2 * (int) ((length / 2) / scale)]; for (int i = 0; i < output.length / 2; i++) { int inPos = (int) pos; double proportion = pos - inPos; int inRealPos = inPos * 2; if (inRealPos >= length - 3) { inRealPos = length - 4; proportion = 1.0; } output[i * 2] = (short) Math.round(data[inRealPos] * (1.0 - proportion) + data[inRealPos + 2] * proportion); output[i * 2 + 1] = (short) Math.round(data[inRealPos + 1] * (1.0 - proportion) + data[inRealPos + 3] * proportion); pos += scale; } } return output; } /** * Basic downsampling algorithm. Uses linear approximation to reduce data. * @param data Input data * @param length Amount of input buffer that is actually used * @param stereo True if input is stereo * @param inFrequency Frequency of input * @param outFrequency Frequency of output * @return Downsampled audio data */ private static short[] downsample(short[] data, int length, boolean stereo, int inFrequency, int outFrequency) { // Special case for no action if (inFrequency == outFrequency) { return trimArray(data, length); } double scale = (double) outFrequency / (double) inFrequency; short[] output; double pos = 0.0; int outPos = 0; if (!stereo) { double sum = 0.0; output = new short[(int) (length * scale)]; int inPos = 0; while (outPos < output.length) { double thisVal = (double) data[inPos++]; double nextPos = pos + scale; if (nextPos >= 1.0) { sum += thisVal * (1.0 - pos); output[outPos++] = (short) Math.round(sum); nextPos -= 1.0; sum = nextPos * thisVal; } else { sum += scale * thisVal; } pos = nextPos; if (inPos >= length && outPos < output.length) { output[outPos++] = (short) Math.round(sum / pos); } } } else { double sum1 = 0.0, sum2 = 0.0; output = new short[2 * (int) ((length / 2) * scale)]; int inPos = 0; while (outPos < output.length) { double thisVal1 = (double) data[inPos++], thisVal2 = (double) data[inPos++]; double nextPos = pos + scale; if (nextPos >= 1.0) { sum1 += thisVal1 * (1.0 - pos); sum2 += thisVal2 * (1.0 - pos); output[outPos++] = (short) Math.round(sum1); output[outPos++] = (short) Math.round(sum2); nextPos -= 1.0; sum1 = nextPos * thisVal1; sum2 = nextPos * thisVal2; } else { sum1 += scale * thisVal1; sum2 += scale * thisVal2; } pos = nextPos; if (inPos >= length && outPos < output.length) { output[outPos++] = (short) Math.round(sum1 / pos); output[outPos++] = (short) Math.round(sum2 / pos); } } } return output; } }