829N/A/*
6321N/A * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
829N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
829N/A *
829N/A * This code is free software; you can redistribute it and/or modify it
829N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
829N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
829N/A *
829N/A * This code is distributed in the hope that it will be useful, but WITHOUT
829N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
829N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
829N/A * version 2 for more details (a copy is included in the LICENSE file that
829N/A * accompanied this code).
829N/A *
829N/A * You should have received a copy of the GNU General Public License version
829N/A * 2 along with this work; if not, write to the Free Software Foundation,
829N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
829N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
829N/A */
829N/Apackage com.sun.media.sound;
829N/A
829N/A/**
829N/A * A simple look-ahead volume limiter with very fast attack and fast release.
829N/A * This filter is used for preventing clipping.
829N/A *
829N/A * @author Karl Helgason
829N/A */
6321N/Apublic final class SoftLimiter implements SoftAudioProcessor {
829N/A
829N/A float lastmax = 0;
829N/A float gain = 1;
829N/A float[] temp_bufferL;
829N/A float[] temp_bufferR;
829N/A boolean mix = false;
829N/A SoftAudioBuffer bufferL;
829N/A SoftAudioBuffer bufferR;
829N/A SoftAudioBuffer bufferLout;
829N/A SoftAudioBuffer bufferRout;
829N/A float controlrate;
829N/A
829N/A public void init(float samplerate, float controlrate) {
829N/A this.controlrate = controlrate;
829N/A }
829N/A
829N/A public void setInput(int pin, SoftAudioBuffer input) {
829N/A if (pin == 0)
829N/A bufferL = input;
829N/A if (pin == 1)
829N/A bufferR = input;
829N/A }
829N/A
829N/A public void setOutput(int pin, SoftAudioBuffer output) {
829N/A if (pin == 0)
829N/A bufferLout = output;
829N/A if (pin == 1)
829N/A bufferRout = output;
829N/A }
829N/A
829N/A public void setMixMode(boolean mix) {
829N/A this.mix = mix;
829N/A }
829N/A
829N/A public void globalParameterControlChange(int[] slothpath, long param,
829N/A long value) {
829N/A }
829N/A
829N/A double silentcounter = 0;
829N/A
829N/A public void processAudio() {
829N/A if (this.bufferL.isSilent()
829N/A && (this.bufferR == null || this.bufferR.isSilent())) {
829N/A silentcounter += 1 / controlrate;
829N/A
829N/A if (silentcounter > 60) {
829N/A if (!mix) {
829N/A bufferLout.clear();
1990N/A if (bufferRout != null) bufferRout.clear();
829N/A }
829N/A return;
829N/A }
829N/A } else
829N/A silentcounter = 0;
829N/A
829N/A float[] bufferL = this.bufferL.array();
829N/A float[] bufferR = this.bufferR == null ? null : this.bufferR.array();
829N/A float[] bufferLout = this.bufferLout.array();
829N/A float[] bufferRout = this.bufferRout == null
829N/A ? null : this.bufferRout.array();
829N/A
829N/A if (temp_bufferL == null || temp_bufferL.length < bufferL.length)
829N/A temp_bufferL = new float[bufferL.length];
829N/A if (bufferR != null)
829N/A if (temp_bufferR == null || temp_bufferR.length < bufferR.length)
829N/A temp_bufferR = new float[bufferR.length];
829N/A
829N/A float max = 0;
829N/A int len = bufferL.length;
829N/A
829N/A if (bufferR == null) {
829N/A for (int i = 0; i < len; i++) {
829N/A if (bufferL[i] > max)
829N/A max = bufferL[i];
829N/A if (-bufferL[i] > max)
829N/A max = -bufferL[i];
829N/A }
829N/A } else {
829N/A for (int i = 0; i < len; i++) {
829N/A if (bufferL[i] > max)
829N/A max = bufferL[i];
829N/A if (bufferR[i] > max)
829N/A max = bufferR[i];
829N/A if (-bufferL[i] > max)
829N/A max = -bufferL[i];
829N/A if (-bufferR[i] > max)
829N/A max = -bufferR[i];
829N/A }
829N/A }
829N/A
829N/A float lmax = lastmax;
829N/A lastmax = max;
829N/A if (lmax > max)
829N/A max = lmax;
829N/A
829N/A float newgain = 1;
829N/A if (max > 0.99f)
829N/A newgain = 0.99f / max;
829N/A else
829N/A newgain = 1;
829N/A
829N/A if (newgain > gain)
829N/A newgain = (newgain + gain * 9) / 10f;
829N/A
829N/A float gaindelta = (newgain - gain) / len;
829N/A if (mix) {
829N/A if (bufferR == null) {
829N/A for (int i = 0; i < len; i++) {
829N/A gain += gaindelta;
829N/A float bL = bufferL[i];
829N/A float tL = temp_bufferL[i];
829N/A temp_bufferL[i] = bL;
829N/A bufferLout[i] += tL * gain;
829N/A }
829N/A } else {
829N/A for (int i = 0; i < len; i++) {
829N/A gain += gaindelta;
829N/A float bL = bufferL[i];
829N/A float bR = bufferR[i];
829N/A float tL = temp_bufferL[i];
829N/A float tR = temp_bufferR[i];
829N/A temp_bufferL[i] = bL;
829N/A temp_bufferR[i] = bR;
829N/A bufferLout[i] += tL * gain;
829N/A bufferRout[i] += tR * gain;
829N/A }
829N/A }
829N/A
829N/A } else {
829N/A if (bufferR == null) {
829N/A for (int i = 0; i < len; i++) {
829N/A gain += gaindelta;
829N/A float bL = bufferL[i];
829N/A float tL = temp_bufferL[i];
829N/A temp_bufferL[i] = bL;
829N/A bufferLout[i] = tL * gain;
829N/A }
829N/A } else {
829N/A for (int i = 0; i < len; i++) {
829N/A gain += gaindelta;
829N/A float bL = bufferL[i];
829N/A float bR = bufferR[i];
829N/A float tL = temp_bufferL[i];
829N/A float tR = temp_bufferR[i];
829N/A temp_bufferL[i] = bL;
829N/A temp_bufferR[i] = bR;
829N/A bufferLout[i] = tL * gain;
829N/A bufferRout[i] = tR * gain;
829N/A }
829N/A }
829N/A
829N/A }
829N/A gain = newgain;
829N/A }
829N/A
829N/A public void processControlLogic() {
829N/A }
829N/A}