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

Java example source code file (SoftMixingDataLine.java)

This example Java source code file (SoftMixingDataLine.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

applyreverb, audioformat, balance, chorussend, floatcontrol, gain, ioexception, maximum, minimum, mute, pan, reverbsend, softlinearresampler2, string, util

The SoftMixingDataLine.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.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.BooleanControl;
import javax.sound.sampled.Control;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.Control.Type;

/**
 * General software mixing line.
 *
 * @author Karl Helgason
 */
public abstract class SoftMixingDataLine implements DataLine {

    public static final FloatControl.Type CHORUS_SEND = new FloatControl.Type(
            "Chorus Send") {
    };

    protected static final 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 int nrofchannels = 0;

        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;

        public 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 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; i < b.length; 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 class Gain extends FloatControl {

        private Gain() {

            super(FloatControl.Type.MASTER_GAIN, -80f, 6.0206f, 80f / 128.0f,
                    -1, 0.0f, "dB", "Minimum", "", "Maximum");
        }

        public void setValue(float newValue) {
            super.setValue(newValue);
            calcVolume();
        }
    }

    private final class Mute extends BooleanControl {

        private Mute() {
            super(BooleanControl.Type.MUTE, false, "True", "False");
        }

        public void setValue(boolean newValue) {
            super.setValue(newValue);
            calcVolume();
        }
    }

    private final class ApplyReverb extends BooleanControl {

        private ApplyReverb() {
            super(BooleanControl.Type.APPLY_REVERB, false, "True", "False");
        }

        public void setValue(boolean newValue) {
            super.setValue(newValue);
            calcVolume();
        }

    }

    private final class Balance extends FloatControl {

        private Balance() {
            super(FloatControl.Type.BALANCE, -1.0f, 1.0f, (1.0f / 128.0f), -1,
                    0.0f, "", "Left", "Center", "Right");
        }

        public void setValue(float newValue) {
            super.setValue(newValue);
            calcVolume();
        }

    }

    private final class Pan extends FloatControl {

        private Pan() {
            super(FloatControl.Type.PAN, -1.0f, 1.0f, (1.0f / 128.0f), -1,
                    0.0f, "", "Left", "Center", "Right");
        }

        public void setValue(float newValue) {
            super.setValue(newValue);
            balance_control.setValue(newValue);
        }

        public float getValue() {
            return balance_control.getValue();
        }

    }

    private final class ReverbSend extends FloatControl {

        private ReverbSend() {
            super(FloatControl.Type.REVERB_SEND, -80f, 6.0206f, 80f / 128.0f,
                    -1, -80f, "dB", "Minimum", "", "Maximum");
        }

        public void setValue(float newValue) {
            super.setValue(newValue);
            balance_control.setValue(newValue);
        }

    }

    private final class ChorusSend extends FloatControl {

        private ChorusSend() {
            super(CHORUS_SEND, -80f, 6.0206f, 80f / 128.0f, -1, -80f, "dB",
                    "Minimum", "", "Maximum");
        }

        public void setValue(float newValue) {
            super.setValue(newValue);
            balance_control.setValue(newValue);
        }

    }

    private final Gain gain_control = new Gain();

    private final Mute mute_control = new Mute();

    private final Balance balance_control = new Balance();

    private final Pan pan_control = new Pan();

    private final ReverbSend reverbsend_control = new ReverbSend();

    private final ChorusSend chorussend_control = new ChorusSend();

    private final ApplyReverb apply_reverb = new ApplyReverb();

    private final Control[] controls;

    float leftgain = 1;

    float rightgain = 1;

    float eff1gain = 0;

    float eff2gain = 0;

    List<LineListener> listeners = new ArrayList();

    final Object control_mutex;

    SoftMixingMixer mixer;

    DataLine.Info info;

    protected abstract void processControlLogic();

    protected abstract void processAudioLogic(SoftAudioBuffer[] buffers);

    SoftMixingDataLine(SoftMixingMixer mixer, DataLine.Info info) {
        this.mixer = mixer;
        this.info = info;
        this.control_mutex = mixer.control_mutex;

        controls = new Control[] { gain_control, mute_control, balance_control,
                pan_control, reverbsend_control, chorussend_control,
                apply_reverb };
        calcVolume();
    }

    final void calcVolume() {
        synchronized (control_mutex) {
            double gain = Math.pow(10.0, gain_control.getValue() / 20.0);
            if (mute_control.getValue())
                gain = 0;
            leftgain = (float) gain;
            rightgain = (float) gain;
            if (mixer.getFormat().getChannels() > 1) {
                // -1 = Left, 0 Center, 1 = Right
                double balance = balance_control.getValue();
                if (balance > 0)
                    leftgain *= (1 - balance);
                else
                    rightgain *= (1 + balance);

            }
        }

        eff1gain = (float) Math.pow(10.0, reverbsend_control.getValue() / 20.0);
        eff2gain = (float) Math.pow(10.0, chorussend_control.getValue() / 20.0);

        if (!apply_reverb.getValue()) {
            eff1gain = 0;
        }
    }

    final void sendEvent(LineEvent event) {
        if (listeners.size() == 0)
            return;
        LineListener[] listener_array = listeners
                .toArray(new LineListener[listeners.size()]);
        for (LineListener listener : listener_array) {
            listener.update(event);
        }
    }

    public final void addLineListener(LineListener listener) {
        synchronized (control_mutex) {
            listeners.add(listener);
        }
    }

    public final void removeLineListener(LineListener listener) {
        synchronized (control_mutex) {
            listeners.add(listener);
        }
    }

    public final javax.sound.sampled.Line.Info getLineInfo() {
        return info;
    }

    public final Control getControl(Type control) {
        if (control != null) {
            for (int i = 0; i < controls.length; i++) {
                if (controls[i].getType() == control) {
                    return controls[i];
                }
            }
        }
        throw new IllegalArgumentException("Unsupported control type : "
                + control);
    }

    public final Control[] getControls() {
        return Arrays.copyOf(controls, controls.length);
    }

    public final boolean isControlSupported(Type control) {
        if (control != null) {
            for (int i = 0; i < controls.length; i++) {
                if (controls[i].getType() == control) {
                    return true;
                }
            }
        }
        return false;
    }

}

Other Java examples (source code examples)

Here is a short list of links related to this Java SoftMixingDataLine.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.