alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (AudioFloatFormatConverter.java)

This example Java source code file (AudioFloatFormatConverter.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

arraylist, audiofloatformatconverterinputstream, audiofloatinputstream, audiofloatinputstreamchannelmixer, audiofloatinputstreamresampler, audioformat, audioinputstream, encoding, illegalargumentexception, ioexception, softabstractresampler, softlinearresampler2, string, unsupported, util

The AudioFloatFormatConverter.java Java example source code

/*
 * Copyright (c) 2008, 2013, 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.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.AudioFormat.Encoding;
import javax.sound.sampled.spi.FormatConversionProvider;

/**
 * This class is used to convert between 8,16,24,32 bit signed/unsigned
 * big/litle endian fixed/floating stereo/mono/multi-channel audio streams and
 * perform sample-rate conversion if needed.
 *
 * @author Karl Helgason
 */
public final class AudioFloatFormatConverter extends FormatConversionProvider {

    private static class AudioFloatFormatConverterInputStream extends
            InputStream {
        private final AudioFloatConverter converter;

        private final AudioFloatInputStream stream;

        private float[] readfloatbuffer;

        private final int fsize;

        AudioFloatFormatConverterInputStream(AudioFormat targetFormat,
                AudioFloatInputStream stream) {
            this.stream = stream;
            converter = AudioFloatConverter.getConverter(targetFormat);
            fsize = ((targetFormat.getSampleSizeInBits() + 7) / 8);
        }

        public int read() throws IOException {
            byte[] b = new byte[1];
            int ret = read(b);
            if (ret < 0)
                return ret;
            return b[0] & 0xFF;
        }

        public int read(byte[] b, int off, int len) throws IOException {

            int flen = len / fsize;
            if (readfloatbuffer == null || readfloatbuffer.length < flen)
                readfloatbuffer = new float[flen];
            int ret = stream.read(readfloatbuffer, 0, flen);
            if (ret < 0)
                return ret;
            converter.toByteArray(readfloatbuffer, 0, ret, b, off);
            return ret * fsize;
        }

        public int available() throws IOException {
            int ret = stream.available();
            if (ret < 0)
                return ret;
            return ret * fsize;
        }

        public void close() throws IOException {
            stream.close();
        }

        public synchronized void mark(int readlimit) {
            stream.mark(readlimit * fsize);
        }

        public boolean markSupported() {
            return stream.markSupported();
        }

        public synchronized void reset() throws IOException {
            stream.reset();
        }

        public long skip(long n) throws IOException {
            long ret = stream.skip(n / fsize);
            if (ret < 0)
                return ret;
            return ret * fsize;
        }

    }

    private static class AudioFloatInputStreamChannelMixer extends
            AudioFloatInputStream {

        private final int targetChannels;

        private final int sourceChannels;

        private final AudioFloatInputStream ais;

        private final AudioFormat targetFormat;

        private float[] conversion_buffer;

        AudioFloatInputStreamChannelMixer(AudioFloatInputStream ais,
                int targetChannels) {
            this.sourceChannels = ais.getFormat().getChannels();
            this.targetChannels = targetChannels;
            this.ais = ais;
            AudioFormat format = ais.getFormat();
            targetFormat = new AudioFormat(format.getEncoding(), format
                    .getSampleRate(), format.getSampleSizeInBits(),
                    targetChannels, (format.getFrameSize() / sourceChannels)
                            * targetChannels, format.getFrameRate(), format
                            .isBigEndian());
        }

        public int available() throws IOException {
            return (ais.available() / sourceChannels) * targetChannels;
        }

        public void close() throws IOException {
            ais.close();
        }

        public AudioFormat getFormat() {
            return targetFormat;
        }

        public long getFrameLength() {
            return ais.getFrameLength();
        }

        public void mark(int readlimit) {
            ais.mark((readlimit / targetChannels) * sourceChannels);
        }

        public boolean markSupported() {
            return ais.markSupported();
        }

        public int read(float[] b, int off, int len) throws IOException {
            int len2 = (len / targetChannels) * sourceChannels;
            if (conversion_buffer == null || conversion_buffer.length < len2)
                conversion_buffer = new float[len2];
            int ret = ais.read(conversion_buffer, 0, len2);
            if (ret < 0)
                return ret;
            if (sourceChannels == 1) {
                int cs = targetChannels;
                for (int c = 0; c < targetChannels; c++) {
                    for (int i = 0, ix = off + c; i < len2; i++, ix += cs) {
                        b[ix] = conversion_buffer[i];
                    }
                }
            } else if (targetChannels == 1) {
                int cs = sourceChannels;
                for (int i = 0, ix = off; i < len2; i += cs, ix++) {
                    b[ix] = conversion_buffer[i];
                }
                for (int c = 1; c < sourceChannels; c++) {
                    for (int i = c, ix = off; i < len2; i += cs, ix++) {
                        b[ix] += conversion_buffer[i];
                    }
                }
                float vol = 1f / ((float) sourceChannels);
                for (int i = 0, ix = off; i < len2; i += cs, ix++) {
                    b[ix] *= vol;
                }
            } else {
                int minChannels = Math.min(sourceChannels, targetChannels);
                int off_len = off + len;
                int ct = targetChannels;
                int cs = sourceChannels;
                for (int c = 0; c < minChannels; c++) {
                    for (int i = off + c, ix = c; i < off_len; i += ct, ix += cs) {
                        b[i] = conversion_buffer[ix];
                    }
                }
                for (int c = minChannels; c < targetChannels; c++) {
                    for (int i = off + c; i < off_len; i += ct) {
                        b[i] = 0;
                    }
                }
            }
            return (ret / sourceChannels) * targetChannels;
        }

        public void reset() throws IOException {
            ais.reset();
        }

        public long skip(long len) throws IOException {
            long ret = ais.skip((len / targetChannels) * sourceChannels);
            if (ret < 0)
                return ret;
            return (ret / sourceChannels) * targetChannels;
        }

    }

    private static class AudioFloatInputStreamResampler extends
            AudioFloatInputStream {

        private final AudioFloatInputStream ais;

        private final AudioFormat targetFormat;

        private float[] skipbuffer;

        private SoftAbstractResampler resampler;

        private final float[] pitch = new float[1];

        private final float[] ibuffer2;

        private final float[][] ibuffer;

        private float ibuffer_index = 0;

        private int ibuffer_len = 0;

        private final int nrofchannels;

        private float[][] cbuffer;

        private final int buffer_len = 512;

        private final int pad;

        private final int pad2;

        private final float[] ix = new float[1];

        private final int[] ox = new int[1];

        private float[][] mark_ibuffer = null;

        private float mark_ibuffer_index = 0;

        private int mark_ibuffer_len = 0;

        AudioFloatInputStreamResampler(AudioFloatInputStream ais,
                AudioFormat format) {
            this.ais = ais;
            AudioFormat sourceFormat = ais.getFormat();
            targetFormat = new AudioFormat(sourceFormat.getEncoding(), format
                    .getSampleRate(), sourceFormat.getSampleSizeInBits(),
                    sourceFormat.getChannels(), sourceFormat.getFrameSize(),
                    format.getSampleRate(), sourceFormat.isBigEndian());
            nrofchannels = targetFormat.getChannels();
            Object interpolation = format.getProperty("interpolation");
            if (interpolation != null && (interpolation instanceof String)) {
                String resamplerType = (String) interpolation;
                if (resamplerType.equalsIgnoreCase("point"))
                    this.resampler = new SoftPointResampler();
                if (resamplerType.equalsIgnoreCase("linear"))
                    this.resampler = new SoftLinearResampler2();
                if (resamplerType.equalsIgnoreCase("linear1"))
                    this.resampler = new SoftLinearResampler();
                if (resamplerType.equalsIgnoreCase("linear2"))
                    this.resampler = new SoftLinearResampler2();
                if (resamplerType.equalsIgnoreCase("cubic"))
                    this.resampler = new SoftCubicResampler();
                if (resamplerType.equalsIgnoreCase("lanczos"))
                    this.resampler = new SoftLanczosResampler();
                if (resamplerType.equalsIgnoreCase("sinc"))
                    this.resampler = new SoftSincResampler();
            }
            if (resampler == null)
                resampler = new SoftLinearResampler2(); // new
                                                        // SoftLinearResampler2();
            pitch[0] = sourceFormat.getSampleRate() / format.getSampleRate();
            pad = resampler.getPadding();
            pad2 = pad * 2;
            ibuffer = new float[nrofchannels][buffer_len + pad2];
            ibuffer2 = new float[nrofchannels * buffer_len];
            ibuffer_index = buffer_len + pad;
            ibuffer_len = buffer_len;
        }

        public int available() throws IOException {
            return 0;
        }

        public void close() throws IOException {
            ais.close();
        }

        public AudioFormat getFormat() {
            return targetFormat;
        }

        public long getFrameLength() {
            return AudioSystem.NOT_SPECIFIED; // ais.getFrameLength();
        }

        public void mark(int readlimit) {
            ais.mark((int) (readlimit * pitch[0]));
            mark_ibuffer_index = ibuffer_index;
            mark_ibuffer_len = ibuffer_len;
            if (mark_ibuffer == null) {
                mark_ibuffer = new float[ibuffer.length][ibuffer[0].length];
            }
            for (int c = 0; c < ibuffer.length; c++) {
                float[] from = ibuffer[c];
                float[] to = mark_ibuffer[c];
                for (int i = 0; i < to.length; i++) {
                    to[i] = from[i];
                }
            }
        }

        public boolean markSupported() {
            return ais.markSupported();
        }

        private void readNextBuffer() throws IOException {

            if (ibuffer_len == -1)
                return;

            for (int c = 0; c < nrofchannels; c++) {
                float[] buff = ibuffer[c];
                int buffer_len_pad = ibuffer_len + pad2;
                for (int i = ibuffer_len, ix = 0; i < buffer_len_pad; i++, ix++) {
                    buff[ix] = buff[i];
                }
            }

            ibuffer_index -= (ibuffer_len);

            ibuffer_len = ais.read(ibuffer2);
            if (ibuffer_len >= 0) {
                while (ibuffer_len < ibuffer2.length) {
                    int ret = ais.read(ibuffer2, ibuffer_len, ibuffer2.length
                            - ibuffer_len);
                    if (ret == -1)
                        break;
                    ibuffer_len += ret;
                }
                Arrays.fill(ibuffer2, ibuffer_len, ibuffer2.length, 0);
                ibuffer_len /= nrofchannels;
            } else {
                Arrays.fill(ibuffer2, 0, ibuffer2.length, 0);
            }

            int ibuffer2_len = ibuffer2.length;
            for (int c = 0; c < nrofchannels; c++) {
                float[] buff = ibuffer[c];
                for (int i = c, ix = pad2; i < ibuffer2_len; i += nrofchannels, ix++) {
                    buff[ix] = ibuffer2[i];
                }
            }

        }

        public int read(float[] b, int off, int len) throws IOException {

            if (cbuffer == null || cbuffer[0].length < len / nrofchannels) {
                cbuffer = new float[nrofchannels][len / nrofchannels];
            }
            if (ibuffer_len == -1)
                return -1;
            if (len < 0)
                return 0;
            int offlen = off + len;
            int remain = len / nrofchannels;
            int destPos = 0;
            int in_end = ibuffer_len;
            while (remain > 0) {
                if (ibuffer_len >= 0) {
                    if (ibuffer_index >= (ibuffer_len + pad))
                        readNextBuffer();
                    in_end = ibuffer_len + pad;
                }

                if (ibuffer_len < 0) {
                    in_end = pad2;
                    if (ibuffer_index >= in_end)
                        break;
                }

                if (ibuffer_index < 0)
                    break;
                int preDestPos = destPos;
                for (int c = 0; c < nrofchannels; c++) {
                    ix[0] = ibuffer_index;
                    ox[0] = destPos;
                    float[] buff = ibuffer[c];
                    resampler.interpolate(buff, ix, in_end, pitch, 0,
                            cbuffer[c], ox, len / nrofchannels);
                }
                ibuffer_index = ix[0];
                destPos = ox[0];
                remain -= destPos - preDestPos;
            }
            for (int c = 0; c < nrofchannels; c++) {
                int ix = 0;
                float[] buff = cbuffer[c];
                for (int i = c + off; i < offlen; i += nrofchannels) {
                    b[i] = buff[ix++];
                }
            }
            return len - remain * nrofchannels;
        }

        public void reset() throws IOException {
            ais.reset();
            if (mark_ibuffer == null)
                return;
            ibuffer_index = mark_ibuffer_index;
            ibuffer_len = mark_ibuffer_len;
            for (int c = 0; c < ibuffer.length; c++) {
                float[] from = mark_ibuffer[c];
                float[] to = ibuffer[c];
                for (int i = 0; i < to.length; i++) {
                    to[i] = from[i];
                }
            }

        }

        public long skip(long len) throws IOException {
            if (len < 0)
                return 0;
            if (skipbuffer == null)
                skipbuffer = new float[1024 * targetFormat.getFrameSize()];
            float[] l_skipbuffer = skipbuffer;
            long remain = len;
            while (remain > 0) {
                int ret = read(l_skipbuffer, 0, (int) Math.min(remain,
                        skipbuffer.length));
                if (ret < 0) {
                    if (remain == len)
                        return ret;
                    break;
                }
                remain -= ret;
            }
            return len - remain;

        }

    }

    private final Encoding[] formats = {Encoding.PCM_SIGNED,
                                        Encoding.PCM_UNSIGNED,
                                        Encoding.PCM_FLOAT};

    public AudioInputStream getAudioInputStream(Encoding targetEncoding,
            AudioInputStream sourceStream) {
        if (sourceStream.getFormat().getEncoding().equals(targetEncoding))
            return sourceStream;
        AudioFormat format = sourceStream.getFormat();
        int channels = format.getChannels();
        Encoding encoding = targetEncoding;
        float samplerate = format.getSampleRate();
        int bits = format.getSampleSizeInBits();
        boolean bigendian = format.isBigEndian();
        if (targetEncoding.equals(Encoding.PCM_FLOAT))
            bits = 32;
        AudioFormat targetFormat = new AudioFormat(encoding, samplerate, bits,
                channels, channels * bits / 8, samplerate, bigendian);
        return getAudioInputStream(targetFormat, sourceStream);
    }

    public AudioInputStream getAudioInputStream(AudioFormat targetFormat,
            AudioInputStream sourceStream) {
        if (!isConversionSupported(targetFormat, sourceStream.getFormat()))
            throw new IllegalArgumentException("Unsupported conversion: "
                    + sourceStream.getFormat().toString() + " to "
                    + targetFormat.toString());
        return getAudioInputStream(targetFormat, AudioFloatInputStream
                .getInputStream(sourceStream));
    }

    public AudioInputStream getAudioInputStream(AudioFormat targetFormat,
            AudioFloatInputStream sourceStream) {

        if (!isConversionSupported(targetFormat, sourceStream.getFormat()))
            throw new IllegalArgumentException("Unsupported conversion: "
                    + sourceStream.getFormat().toString() + " to "
                    + targetFormat.toString());
        if (targetFormat.getChannels() != sourceStream.getFormat()
                .getChannels())
            sourceStream = new AudioFloatInputStreamChannelMixer(sourceStream,
                    targetFormat.getChannels());
        if (Math.abs(targetFormat.getSampleRate()
                - sourceStream.getFormat().getSampleRate()) > 0.000001)
            sourceStream = new AudioFloatInputStreamResampler(sourceStream,
                    targetFormat);
        return new AudioInputStream(new AudioFloatFormatConverterInputStream(
                targetFormat, sourceStream), targetFormat, sourceStream
                .getFrameLength());
    }

    public Encoding[] getSourceEncodings() {
        return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED,
                Encoding.PCM_FLOAT };
    }

    public Encoding[] getTargetEncodings() {
        return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED,
                Encoding.PCM_FLOAT };
    }

    public Encoding[] getTargetEncodings(AudioFormat sourceFormat) {
        if (AudioFloatConverter.getConverter(sourceFormat) == null)
            return new Encoding[0];
        return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED,
                Encoding.PCM_FLOAT };
    }

    public AudioFormat[] getTargetFormats(Encoding targetEncoding,
            AudioFormat sourceFormat) {
        if (AudioFloatConverter.getConverter(sourceFormat) == null)
            return new AudioFormat[0];
        int channels = sourceFormat.getChannels();

        ArrayList<AudioFormat> formats = new ArrayList();

        if (targetEncoding.equals(Encoding.PCM_SIGNED))
            formats.add(new AudioFormat(Encoding.PCM_SIGNED,
                    AudioSystem.NOT_SPECIFIED, 8, channels, channels,
                    AudioSystem.NOT_SPECIFIED, false));
        if (targetEncoding.equals(Encoding.PCM_UNSIGNED))
            formats.add(new AudioFormat(Encoding.PCM_UNSIGNED,
                    AudioSystem.NOT_SPECIFIED, 8, channels, channels,
                    AudioSystem.NOT_SPECIFIED, false));

        for (int bits = 16; bits < 32; bits += 8) {
            if (targetEncoding.equals(Encoding.PCM_SIGNED)) {
                formats.add(new AudioFormat(Encoding.PCM_SIGNED,
                        AudioSystem.NOT_SPECIFIED, bits, channels, channels
                                * bits / 8, AudioSystem.NOT_SPECIFIED, false));
                formats.add(new AudioFormat(Encoding.PCM_SIGNED,
                        AudioSystem.NOT_SPECIFIED, bits, channels, channels
                                * bits / 8, AudioSystem.NOT_SPECIFIED, true));
            }
            if (targetEncoding.equals(Encoding.PCM_UNSIGNED)) {
                formats.add(new AudioFormat(Encoding.PCM_UNSIGNED,
                        AudioSystem.NOT_SPECIFIED, bits, channels, channels
                                * bits / 8, AudioSystem.NOT_SPECIFIED, true));
                formats.add(new AudioFormat(Encoding.PCM_UNSIGNED,
                        AudioSystem.NOT_SPECIFIED, bits, channels, channels
                                * bits / 8, AudioSystem.NOT_SPECIFIED, false));
            }
        }

        if (targetEncoding.equals(Encoding.PCM_FLOAT)) {
            formats.add(new AudioFormat(Encoding.PCM_FLOAT,
                    AudioSystem.NOT_SPECIFIED, 32, channels, channels * 4,
                    AudioSystem.NOT_SPECIFIED, false));
            formats.add(new AudioFormat(Encoding.PCM_FLOAT,
                    AudioSystem.NOT_SPECIFIED, 32, channels, channels * 4,
                    AudioSystem.NOT_SPECIFIED, true));
            formats.add(new AudioFormat(Encoding.PCM_FLOAT,
                    AudioSystem.NOT_SPECIFIED, 64, channels, channels * 8,
                    AudioSystem.NOT_SPECIFIED, false));
            formats.add(new AudioFormat(Encoding.PCM_FLOAT,
                    AudioSystem.NOT_SPECIFIED, 64, channels, channels * 8,
                    AudioSystem.NOT_SPECIFIED, true));
        }

        return formats.toArray(new AudioFormat[formats.size()]);
    }

    public boolean isConversionSupported(AudioFormat targetFormat,
            AudioFormat sourceFormat) {
        if (AudioFloatConverter.getConverter(sourceFormat) == null)
            return false;
        if (AudioFloatConverter.getConverter(targetFormat) == null)
            return false;
        if (sourceFormat.getChannels() <= 0)
            return false;
        if (targetFormat.getChannels() <= 0)
            return false;
        return true;
    }

    public boolean isConversionSupported(Encoding targetEncoding,
            AudioFormat sourceFormat) {
        if (AudioFloatConverter.getConverter(sourceFormat) == null)
            return false;
        for (int i = 0; i < formats.length; i++) {
            if (targetEncoding.equals(formats[i]))
                return true;
        }
        return false;
    }

}

Other Java examples (source code examples)

Here is a short list of links related to this Java AudioFloatFormatConverter.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.