| /* | |
| * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code 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 | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| package com.sun.media.sound; | |
| import java.nio.ByteBuffer; | |
| import java.nio.ByteOrder; | |
| import java.nio.DoubleBuffer; | |
| import java.nio.FloatBuffer; | |
| import javax.sound.sampled.AudioFormat; | |
| import javax.sound.sampled.AudioFormat.Encoding; | |
| /** | |
| * This class is used to convert between 8,16,24,32,32+ bit signed/unsigned | |
| * big/little endian fixed/floating point byte buffers and float buffers. | |
| * | |
| * @author Karl Helgason | |
| */ | |
| public abstract class AudioFloatConverter { | |
| /*************************************************************************** | |
| * | |
| * LSB Filter, used filter least significant byte in samples arrays. | |
| * | |
| * Is used filter out data in lsb byte when SampleSizeInBits is not | |
| * dividable by 8. | |
| * | |
| **************************************************************************/ | |
| private static class AudioFloatLSBFilter extends AudioFloatConverter { | |
| private final AudioFloatConverter converter; | |
| private final int offset; | |
| private final int stepsize; | |
| private final byte mask; | |
| private byte[] mask_buffer; | |
| AudioFloatLSBFilter(AudioFloatConverter converter, AudioFormat format) { | |
| int bits = format.getSampleSizeInBits(); | |
| boolean bigEndian = format.isBigEndian(); | |
| this.converter = converter; | |
| stepsize = (bits + 7) / 8; | |
| offset = bigEndian ? (stepsize - 1) : 0; | |
| int lsb_bits = bits % 8; | |
| if (lsb_bits == 0) | |
| mask = (byte) 0x00; | |
| else if (lsb_bits == 1) | |
| mask = (byte) 0x80; | |
| else if (lsb_bits == 2) | |
| mask = (byte) 0xC0; | |
| else if (lsb_bits == 3) | |
| mask = (byte) 0xE0; | |
| else if (lsb_bits == 4) | |
| mask = (byte) 0xF0; | |
| else if (lsb_bits == 5) | |
| mask = (byte) 0xF8; | |
| else if (lsb_bits == 6) | |
| mask = (byte) 0xFC; | |
| else if (lsb_bits == 7) | |
| mask = (byte) 0xFE; | |
| else | |
| mask = (byte) 0xFF; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| byte[] ret = converter.toByteArray(in_buff, in_offset, in_len, | |
| out_buff, out_offset); | |
| int out_offset_end = in_len * stepsize; | |
| for (int i = out_offset + offset; i < out_offset_end; i += stepsize) { | |
| out_buff[i] = (byte) (out_buff[i] & mask); | |
| } | |
| return ret; | |
| } | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| if (mask_buffer == null || mask_buffer.length < in_buff.length) | |
| mask_buffer = new byte[in_buff.length]; | |
| System.arraycopy(in_buff, 0, mask_buffer, 0, in_buff.length); | |
| int in_offset_end = out_len * stepsize; | |
| for (int i = in_offset + offset; i < in_offset_end; i += stepsize) { | |
| mask_buffer[i] = (byte) (mask_buffer[i] & mask); | |
| } | |
| float[] ret = converter.toFloatArray(mask_buffer, in_offset, | |
| out_buff, out_offset, out_len); | |
| return ret; | |
| } | |
| } | |
| /*************************************************************************** | |
| * | |
| * 64 bit float, little/big-endian | |
| * | |
| **************************************************************************/ | |
| // PCM 64 bit float, little-endian | |
| private static class AudioFloatConversion64L extends AudioFloatConverter { | |
| ByteBuffer bytebuffer = null; | |
| DoubleBuffer floatbuffer = null; | |
| double[] double_buff = null; | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int in_len = out_len * 8; | |
| if (bytebuffer == null || bytebuffer.capacity() < in_len) { | |
| bytebuffer = ByteBuffer.allocate(in_len).order( | |
| ByteOrder.LITTLE_ENDIAN); | |
| floatbuffer = bytebuffer.asDoubleBuffer(); | |
| } | |
| bytebuffer.position(0); | |
| floatbuffer.position(0); | |
| bytebuffer.put(in_buff, in_offset, in_len); | |
| if (double_buff == null | |
| || double_buff.length < out_len + out_offset) | |
| double_buff = new double[out_len + out_offset]; | |
| floatbuffer.get(double_buff, out_offset, out_len); | |
| int out_offset_end = out_offset + out_len; | |
| for (int i = out_offset; i < out_offset_end; i++) { | |
| out_buff[i] = (float) double_buff[i]; | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int out_len = in_len * 8; | |
| if (bytebuffer == null || bytebuffer.capacity() < out_len) { | |
| bytebuffer = ByteBuffer.allocate(out_len).order( | |
| ByteOrder.LITTLE_ENDIAN); | |
| floatbuffer = bytebuffer.asDoubleBuffer(); | |
| } | |
| floatbuffer.position(0); | |
| bytebuffer.position(0); | |
| if (double_buff == null || double_buff.length < in_offset + in_len) | |
| double_buff = new double[in_offset + in_len]; | |
| int in_offset_end = in_offset + in_len; | |
| for (int i = in_offset; i < in_offset_end; i++) { | |
| double_buff[i] = in_buff[i]; | |
| } | |
| floatbuffer.put(double_buff, in_offset, in_len); | |
| bytebuffer.get(out_buff, out_offset, out_len); | |
| return out_buff; | |
| } | |
| } | |
| // PCM 64 bit float, big-endian | |
| private static class AudioFloatConversion64B extends AudioFloatConverter { | |
| ByteBuffer bytebuffer = null; | |
| DoubleBuffer floatbuffer = null; | |
| double[] double_buff = null; | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int in_len = out_len * 8; | |
| if (bytebuffer == null || bytebuffer.capacity() < in_len) { | |
| bytebuffer = ByteBuffer.allocate(in_len).order( | |
| ByteOrder.BIG_ENDIAN); | |
| floatbuffer = bytebuffer.asDoubleBuffer(); | |
| } | |
| bytebuffer.position(0); | |
| floatbuffer.position(0); | |
| bytebuffer.put(in_buff, in_offset, in_len); | |
| if (double_buff == null | |
| || double_buff.length < out_len + out_offset) | |
| double_buff = new double[out_len + out_offset]; | |
| floatbuffer.get(double_buff, out_offset, out_len); | |
| int out_offset_end = out_offset + out_len; | |
| for (int i = out_offset; i < out_offset_end; i++) { | |
| out_buff[i] = (float) double_buff[i]; | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int out_len = in_len * 8; | |
| if (bytebuffer == null || bytebuffer.capacity() < out_len) { | |
| bytebuffer = ByteBuffer.allocate(out_len).order( | |
| ByteOrder.BIG_ENDIAN); | |
| floatbuffer = bytebuffer.asDoubleBuffer(); | |
| } | |
| floatbuffer.position(0); | |
| bytebuffer.position(0); | |
| if (double_buff == null || double_buff.length < in_offset + in_len) | |
| double_buff = new double[in_offset + in_len]; | |
| int in_offset_end = in_offset + in_len; | |
| for (int i = in_offset; i < in_offset_end; i++) { | |
| double_buff[i] = in_buff[i]; | |
| } | |
| floatbuffer.put(double_buff, in_offset, in_len); | |
| bytebuffer.get(out_buff, out_offset, out_len); | |
| return out_buff; | |
| } | |
| } | |
| /*************************************************************************** | |
| * | |
| * 32 bit float, little/big-endian | |
| * | |
| **************************************************************************/ | |
| // PCM 32 bit float, little-endian | |
| private static class AudioFloatConversion32L extends AudioFloatConverter { | |
| ByteBuffer bytebuffer = null; | |
| FloatBuffer floatbuffer = null; | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int in_len = out_len * 4; | |
| if (bytebuffer == null || bytebuffer.capacity() < in_len) { | |
| bytebuffer = ByteBuffer.allocate(in_len).order( | |
| ByteOrder.LITTLE_ENDIAN); | |
| floatbuffer = bytebuffer.asFloatBuffer(); | |
| } | |
| bytebuffer.position(0); | |
| floatbuffer.position(0); | |
| bytebuffer.put(in_buff, in_offset, in_len); | |
| floatbuffer.get(out_buff, out_offset, out_len); | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int out_len = in_len * 4; | |
| if (bytebuffer == null || bytebuffer.capacity() < out_len) { | |
| bytebuffer = ByteBuffer.allocate(out_len).order( | |
| ByteOrder.LITTLE_ENDIAN); | |
| floatbuffer = bytebuffer.asFloatBuffer(); | |
| } | |
| floatbuffer.position(0); | |
| bytebuffer.position(0); | |
| floatbuffer.put(in_buff, in_offset, in_len); | |
| bytebuffer.get(out_buff, out_offset, out_len); | |
| return out_buff; | |
| } | |
| } | |
| // PCM 32 bit float, big-endian | |
| private static class AudioFloatConversion32B extends AudioFloatConverter { | |
| ByteBuffer bytebuffer = null; | |
| FloatBuffer floatbuffer = null; | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int in_len = out_len * 4; | |
| if (bytebuffer == null || bytebuffer.capacity() < in_len) { | |
| bytebuffer = ByteBuffer.allocate(in_len).order( | |
| ByteOrder.BIG_ENDIAN); | |
| floatbuffer = bytebuffer.asFloatBuffer(); | |
| } | |
| bytebuffer.position(0); | |
| floatbuffer.position(0); | |
| bytebuffer.put(in_buff, in_offset, in_len); | |
| floatbuffer.get(out_buff, out_offset, out_len); | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int out_len = in_len * 4; | |
| if (bytebuffer == null || bytebuffer.capacity() < out_len) { | |
| bytebuffer = ByteBuffer.allocate(out_len).order( | |
| ByteOrder.BIG_ENDIAN); | |
| floatbuffer = bytebuffer.asFloatBuffer(); | |
| } | |
| floatbuffer.position(0); | |
| bytebuffer.position(0); | |
| floatbuffer.put(in_buff, in_offset, in_len); | |
| bytebuffer.get(out_buff, out_offset, out_len); | |
| return out_buff; | |
| } | |
| } | |
| /*************************************************************************** | |
| * | |
| * 8 bit signed/unsigned | |
| * | |
| **************************************************************************/ | |
| // PCM 8 bit, signed | |
| private static class AudioFloatConversion8S extends AudioFloatConverter { | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| byte x = in_buff[ix++]; | |
| out_buff[ox++] = x > 0 ? x / 127.0f : x / 128.0f; | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| final float x = in_buff[ix++]; | |
| out_buff[ox++] = (byte) (x > 0 ? x * 127 : x * 128); | |
| } | |
| return out_buff; | |
| } | |
| } | |
| // PCM 8 bit, unsigned | |
| private static class AudioFloatConversion8U extends AudioFloatConverter { | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| byte x = (byte) (in_buff[ix++] - 128); | |
| out_buff[ox++] = x > 0 ? x / 127.0f : x / 128.0f; | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| float x = in_buff[ix++]; | |
| out_buff[ox++] = (byte) (128 + (x > 0 ? x * 127 : x * 128)); | |
| } | |
| return out_buff; | |
| } | |
| } | |
| /*************************************************************************** | |
| * | |
| * 16 bit signed/unsigned, little/big-endian | |
| * | |
| **************************************************************************/ | |
| // PCM 16 bit, signed, little-endian | |
| private static class AudioFloatConversion16SL extends AudioFloatConverter { | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int len = out_offset + out_len; | |
| for (int ox = out_offset; ox < len; ox++) { | |
| short x = (short) (in_buff[ix++] & 0xFF | (in_buff[ix++] << 8)); | |
| out_buff[ox] = x > 0 ? x / 32767.0f : x / 32768.0f; | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ox = out_offset; | |
| int len = in_offset + in_len; | |
| for (int ix = in_offset; ix < len; ix++) { | |
| float f = in_buff[ix]; | |
| short x = (short) (f > 0 ? f * 32767 : f * 32768); | |
| out_buff[ox++] = (byte) x; | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| } | |
| return out_buff; | |
| } | |
| } | |
| // PCM 16 bit, signed, big-endian | |
| private static class AudioFloatConversion16SB extends AudioFloatConverter { | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| short x = (short) ((in_buff[ix++] << 8) | (in_buff[ix++] & 0xFF)); | |
| out_buff[ox++] = x > 0 ? x / 32767.0f : x / 32768.0f; | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| float f = in_buff[ix++]; | |
| short x = (short) (f > 0 ? f * 32767.0f : f * 32768.0f); | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| out_buff[ox++] = (byte) x; | |
| } | |
| return out_buff; | |
| } | |
| } | |
| // PCM 16 bit, unsigned, little-endian | |
| private static class AudioFloatConversion16UL extends AudioFloatConverter { | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8); | |
| x -= 32768; | |
| out_buff[ox++] = x > 0 ? x / 32767.0f : x / 32768.0f; | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| float f = in_buff[ix++]; | |
| int x = 32768 + (int) (f > 0 ? f * 32767 : f * 32768); | |
| out_buff[ox++] = (byte) x; | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| } | |
| return out_buff; | |
| } | |
| } | |
| // PCM 16 bit, unsigned, big-endian | |
| private static class AudioFloatConversion16UB extends AudioFloatConverter { | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| int x = ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); | |
| x -= 32768; | |
| out_buff[ox++] = x > 0 ? x / 32767.0f : x / 32768.0f; | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| float f = in_buff[ix++]; | |
| int x = 32768 + (int) (f > 0 ? f * 32767 : f * 32768); | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| out_buff[ox++] = (byte) x; | |
| } | |
| return out_buff; | |
| } | |
| } | |
| /*************************************************************************** | |
| * | |
| * 24 bit signed/unsigned, little/big-endian | |
| * | |
| **************************************************************************/ | |
| // PCM 24 bit, signed, little-endian | |
| private static class AudioFloatConversion24SL extends AudioFloatConverter { | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) | |
| | ((in_buff[ix++] & 0xFF) << 16); | |
| if (x > 0x7FFFFF) | |
| x -= 0x1000000; | |
| out_buff[ox++] = x > 0 ? x / 8388607.0f : x / 8388608.0f; | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| float f = in_buff[ix++]; | |
| int x = (int) (f > 0 ? f * 8388607.0f : f * 8388608.0f); | |
| if (x < 0) | |
| x += 0x1000000; | |
| out_buff[ox++] = (byte) x; | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| out_buff[ox++] = (byte) (x >>> 16); | |
| } | |
| return out_buff; | |
| } | |
| } | |
| // PCM 24 bit, signed, big-endian | |
| private static class AudioFloatConversion24SB extends AudioFloatConverter { | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| int x = ((in_buff[ix++] & 0xFF) << 16) | |
| | ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); | |
| if (x > 0x7FFFFF) | |
| x -= 0x1000000; | |
| out_buff[ox++] = x > 0 ? x / 8388607.0f : x / 8388608.0f; | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| float f = in_buff[ix++]; | |
| int x = (int) (f > 0 ? f * 8388607.0f : f * 8388608.0f); | |
| if (x < 0) | |
| x += 0x1000000; | |
| out_buff[ox++] = (byte) (x >>> 16); | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| out_buff[ox++] = (byte) x; | |
| } | |
| return out_buff; | |
| } | |
| } | |
| // PCM 24 bit, unsigned, little-endian | |
| private static class AudioFloatConversion24UL extends AudioFloatConverter { | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) | |
| | ((in_buff[ix++] & 0xFF) << 16); | |
| x -= 0x800000; | |
| out_buff[ox++] = x > 0 ? x / 8388607.0f : x / 8388608.0f; | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| float f = in_buff[ix++]; | |
| int x = (int) (f > 0 ? f * 8388607.0f : f * 8388608.0f); | |
| x += 0x800000; | |
| out_buff[ox++] = (byte) x; | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| out_buff[ox++] = (byte) (x >>> 16); | |
| } | |
| return out_buff; | |
| } | |
| } | |
| // PCM 24 bit, unsigned, big-endian | |
| private static class AudioFloatConversion24UB extends AudioFloatConverter { | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| int x = ((in_buff[ix++] & 0xFF) << 16) | |
| | ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); | |
| x -= 0x800000; | |
| out_buff[ox++] = x > 0 ? x / 8388607.0f : x / 8388608.0f; | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| float f = in_buff[ix++]; | |
| int x = (int) (f > 0 ? f * 8388607.0f : f * 8388608.0f); | |
| x += 8388608; | |
| out_buff[ox++] = (byte) (x >>> 16); | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| out_buff[ox++] = (byte) x; | |
| } | |
| return out_buff; | |
| } | |
| } | |
| /*************************************************************************** | |
| * | |
| * 32 bit signed/unsigned, little/big-endian | |
| * | |
| **************************************************************************/ | |
| // PCM 32 bit, signed, little-endian | |
| private static class AudioFloatConversion32SL extends AudioFloatConverter { | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) | | |
| ((in_buff[ix++] & 0xFF) << 16) | | |
| ((in_buff[ix++] & 0xFF) << 24); | |
| out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF); | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF); | |
| out_buff[ox++] = (byte) x; | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| out_buff[ox++] = (byte) (x >>> 16); | |
| out_buff[ox++] = (byte) (x >>> 24); | |
| } | |
| return out_buff; | |
| } | |
| } | |
| // PCM 32 bit, signed, big-endian | |
| private static class AudioFloatConversion32SB extends AudioFloatConverter { | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| int x = ((in_buff[ix++] & 0xFF) << 24) | | |
| ((in_buff[ix++] & 0xFF) << 16) | | |
| ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); | |
| out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF); | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF); | |
| out_buff[ox++] = (byte) (x >>> 24); | |
| out_buff[ox++] = (byte) (x >>> 16); | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| out_buff[ox++] = (byte) x; | |
| } | |
| return out_buff; | |
| } | |
| } | |
| // PCM 32 bit, unsigned, little-endian | |
| private static class AudioFloatConversion32UL extends AudioFloatConverter { | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) | | |
| ((in_buff[ix++] & 0xFF) << 16) | | |
| ((in_buff[ix++] & 0xFF) << 24); | |
| x -= 0x80000000; | |
| out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF); | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF); | |
| x += 0x80000000; | |
| out_buff[ox++] = (byte) x; | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| out_buff[ox++] = (byte) (x >>> 16); | |
| out_buff[ox++] = (byte) (x >>> 24); | |
| } | |
| return out_buff; | |
| } | |
| } | |
| // PCM 32 bit, unsigned, big-endian | |
| private static class AudioFloatConversion32UB extends AudioFloatConverter { | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| int x = ((in_buff[ix++] & 0xFF) << 24) | | |
| ((in_buff[ix++] & 0xFF) << 16) | | |
| ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); | |
| x -= 0x80000000; | |
| out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF); | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF); | |
| x += 0x80000000; | |
| out_buff[ox++] = (byte) (x >>> 24); | |
| out_buff[ox++] = (byte) (x >>> 16); | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| out_buff[ox++] = (byte) x; | |
| } | |
| return out_buff; | |
| } | |
| } | |
| /*************************************************************************** | |
| * | |
| * 32+ bit signed/unsigned, little/big-endian | |
| * | |
| **************************************************************************/ | |
| // PCM 32+ bit, signed, little-endian | |
| private static class AudioFloatConversion32xSL extends AudioFloatConverter { | |
| private final int xbytes; | |
| AudioFloatConversion32xSL(int xbytes) { | |
| this.xbytes = xbytes; | |
| } | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| ix += xbytes; | |
| int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) | |
| | ((in_buff[ix++] & 0xFF) << 16) | |
| | ((in_buff[ix++] & 0xFF) << 24); | |
| out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF); | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF); | |
| for (int j = 0; j < xbytes; j++) { | |
| out_buff[ox++] = 0; | |
| } | |
| out_buff[ox++] = (byte) x; | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| out_buff[ox++] = (byte) (x >>> 16); | |
| out_buff[ox++] = (byte) (x >>> 24); | |
| } | |
| return out_buff; | |
| } | |
| } | |
| // PCM 32+ bit, signed, big-endian | |
| private static class AudioFloatConversion32xSB extends AudioFloatConverter { | |
| private final int xbytes; | |
| AudioFloatConversion32xSB(int xbytes) { | |
| this.xbytes = xbytes; | |
| } | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| int x = ((in_buff[ix++] & 0xFF) << 24) | |
| | ((in_buff[ix++] & 0xFF) << 16) | |
| | ((in_buff[ix++] & 0xFF) << 8) | |
| | (in_buff[ix++] & 0xFF); | |
| ix += xbytes; | |
| out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF); | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF); | |
| out_buff[ox++] = (byte) (x >>> 24); | |
| out_buff[ox++] = (byte) (x >>> 16); | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| out_buff[ox++] = (byte) x; | |
| for (int j = 0; j < xbytes; j++) { | |
| out_buff[ox++] = 0; | |
| } | |
| } | |
| return out_buff; | |
| } | |
| } | |
| // PCM 32+ bit, unsigned, little-endian | |
| private static class AudioFloatConversion32xUL extends AudioFloatConverter { | |
| private final int xbytes; | |
| AudioFloatConversion32xUL(int xbytes) { | |
| this.xbytes = xbytes; | |
| } | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| ix += xbytes; | |
| int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) | |
| | ((in_buff[ix++] & 0xFF) << 16) | |
| | ((in_buff[ix++] & 0xFF) << 24); | |
| x -= 0x80000000; | |
| out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF); | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF); | |
| x += 0x80000000; | |
| for (int j = 0; j < xbytes; j++) { | |
| out_buff[ox++] = 0; | |
| } | |
| out_buff[ox++] = (byte) x; | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| out_buff[ox++] = (byte) (x >>> 16); | |
| out_buff[ox++] = (byte) (x >>> 24); | |
| } | |
| return out_buff; | |
| } | |
| } | |
| // PCM 32+ bit, unsigned, big-endian | |
| private static class AudioFloatConversion32xUB extends AudioFloatConverter { | |
| private final int xbytes; | |
| AudioFloatConversion32xUB(int xbytes) { | |
| this.xbytes = xbytes; | |
| } | |
| @Override | |
| public float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < out_len; i++) { | |
| int x = ((in_buff[ix++] & 0xFF) << 24) | | |
| ((in_buff[ix++] & 0xFF) << 16) | | |
| ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF); | |
| ix += xbytes; | |
| x -= 0x80000000; | |
| out_buff[ox++] = x * (1.0f / 2147483647.0f); | |
| } | |
| return out_buff; | |
| } | |
| @Override | |
| public byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| int ix = in_offset; | |
| int ox = out_offset; | |
| for (int i = 0; i < in_len; i++) { | |
| int x = (int) (in_buff[ix++] * 2147483647.0f); | |
| x += 0x80000000; | |
| out_buff[ox++] = (byte) (x >>> 24); | |
| out_buff[ox++] = (byte) (x >>> 16); | |
| out_buff[ox++] = (byte) (x >>> 8); | |
| out_buff[ox++] = (byte) x; | |
| for (int j = 0; j < xbytes; j++) { | |
| out_buff[ox++] = 0; | |
| } | |
| } | |
| return out_buff; | |
| } | |
| } | |
| public static AudioFloatConverter getConverter(AudioFormat format) { | |
| AudioFloatConverter conv = null; | |
| if (format.getFrameSize() == 0) | |
| return null; | |
| if (format.getFrameSize() != | |
| ((format.getSampleSizeInBits() + 7) / 8) * format.getChannels()) { | |
| return null; | |
| } | |
| if (format.getEncoding().equals(Encoding.PCM_SIGNED)) { | |
| if (format.isBigEndian()) { | |
| if (format.getSampleSizeInBits() <= 8) { | |
| conv = new AudioFloatConversion8S(); | |
| } else if (format.getSampleSizeInBits() > 8 && | |
| format.getSampleSizeInBits() <= 16) { | |
| conv = new AudioFloatConversion16SB(); | |
| } else if (format.getSampleSizeInBits() > 16 && | |
| format.getSampleSizeInBits() <= 24) { | |
| conv = new AudioFloatConversion24SB(); | |
| } else if (format.getSampleSizeInBits() > 24 && | |
| format.getSampleSizeInBits() <= 32) { | |
| conv = new AudioFloatConversion32SB(); | |
| } else if (format.getSampleSizeInBits() > 32) { | |
| conv = new AudioFloatConversion32xSB(((format | |
| .getSampleSizeInBits() + 7) / 8) - 4); | |
| } | |
| } else { | |
| if (format.getSampleSizeInBits() <= 8) { | |
| conv = new AudioFloatConversion8S(); | |
| } else if (format.getSampleSizeInBits() > 8 && | |
| format.getSampleSizeInBits() <= 16) { | |
| conv = new AudioFloatConversion16SL(); | |
| } else if (format.getSampleSizeInBits() > 16 && | |
| format.getSampleSizeInBits() <= 24) { | |
| conv = new AudioFloatConversion24SL(); | |
| } else if (format.getSampleSizeInBits() > 24 && | |
| format.getSampleSizeInBits() <= 32) { | |
| conv = new AudioFloatConversion32SL(); | |
| } else if (format.getSampleSizeInBits() > 32) { | |
| conv = new AudioFloatConversion32xSL(((format | |
| .getSampleSizeInBits() + 7) / 8) - 4); | |
| } | |
| } | |
| } else if (format.getEncoding().equals(Encoding.PCM_UNSIGNED)) { | |
| if (format.isBigEndian()) { | |
| if (format.getSampleSizeInBits() <= 8) { | |
| conv = new AudioFloatConversion8U(); | |
| } else if (format.getSampleSizeInBits() > 8 && | |
| format.getSampleSizeInBits() <= 16) { | |
| conv = new AudioFloatConversion16UB(); | |
| } else if (format.getSampleSizeInBits() > 16 && | |
| format.getSampleSizeInBits() <= 24) { | |
| conv = new AudioFloatConversion24UB(); | |
| } else if (format.getSampleSizeInBits() > 24 && | |
| format.getSampleSizeInBits() <= 32) { | |
| conv = new AudioFloatConversion32UB(); | |
| } else if (format.getSampleSizeInBits() > 32) { | |
| conv = new AudioFloatConversion32xUB((( | |
| format.getSampleSizeInBits() + 7) / 8) - 4); | |
| } | |
| } else { | |
| if (format.getSampleSizeInBits() <= 8) { | |
| conv = new AudioFloatConversion8U(); | |
| } else if (format.getSampleSizeInBits() > 8 && | |
| format.getSampleSizeInBits() <= 16) { | |
| conv = new AudioFloatConversion16UL(); | |
| } else if (format.getSampleSizeInBits() > 16 && | |
| format.getSampleSizeInBits() <= 24) { | |
| conv = new AudioFloatConversion24UL(); | |
| } else if (format.getSampleSizeInBits() > 24 && | |
| format.getSampleSizeInBits() <= 32) { | |
| conv = new AudioFloatConversion32UL(); | |
| } else if (format.getSampleSizeInBits() > 32) { | |
| conv = new AudioFloatConversion32xUL((( | |
| format.getSampleSizeInBits() + 7) / 8) - 4); | |
| } | |
| } | |
| } else if (format.getEncoding().equals(Encoding.PCM_FLOAT)) { | |
| if (format.getSampleSizeInBits() == 32) { | |
| if (format.isBigEndian()) | |
| conv = new AudioFloatConversion32B(); | |
| else | |
| conv = new AudioFloatConversion32L(); | |
| } else if (format.getSampleSizeInBits() == 64) { | |
| if (format.isBigEndian()) | |
| conv = new AudioFloatConversion64B(); | |
| else | |
| conv = new AudioFloatConversion64L(); | |
| } | |
| } | |
| if ((format.getEncoding().equals(Encoding.PCM_SIGNED) || | |
| format.getEncoding().equals(Encoding.PCM_UNSIGNED)) && | |
| (format.getSampleSizeInBits() % 8 != 0)) { | |
| conv = new AudioFloatLSBFilter(conv, format); | |
| } | |
| if (conv != null) | |
| conv.format = format; | |
| return conv; | |
| } | |
| private AudioFormat format; | |
| public final AudioFormat getFormat() { | |
| return format; | |
| } | |
| public abstract float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_offset, int out_len); | |
| public final float[] toFloatArray(byte[] in_buff, float[] out_buff, | |
| int out_offset, int out_len) { | |
| return toFloatArray(in_buff, 0, out_buff, out_offset, out_len); | |
| } | |
| public final float[] toFloatArray(byte[] in_buff, int in_offset, | |
| float[] out_buff, int out_len) { | |
| return toFloatArray(in_buff, in_offset, out_buff, 0, out_len); | |
| } | |
| public final float[] toFloatArray(byte[] in_buff, float[] out_buff, | |
| int out_len) { | |
| return toFloatArray(in_buff, 0, out_buff, 0, out_len); | |
| } | |
| public final float[] toFloatArray(byte[] in_buff, float[] out_buff) { | |
| return toFloatArray(in_buff, 0, out_buff, 0, out_buff.length); | |
| } | |
| public abstract byte[] toByteArray(float[] in_buff, int in_offset, | |
| int in_len, byte[] out_buff, int out_offset); | |
| public final byte[] toByteArray(float[] in_buff, int in_len, | |
| byte[] out_buff, int out_offset) { | |
| return toByteArray(in_buff, 0, in_len, out_buff, out_offset); | |
| } | |
| public final byte[] toByteArray(float[] in_buff, int in_offset, int in_len, | |
| byte[] out_buff) { | |
| return toByteArray(in_buff, in_offset, in_len, out_buff, 0); | |
| } | |
| public final byte[] toByteArray(float[] in_buff, int in_len, | |
| byte[] out_buff) { | |
| return toByteArray(in_buff, 0, in_len, out_buff, 0); | |
| } | |
| public final byte[] toByteArray(float[] in_buff, byte[] out_buff) { | |
| return toByteArray(in_buff, 0, in_buff.length, out_buff, 0); | |
| } | |
| } |