jdk/src/share/classes/com/sun/media/sound/SoftLimiter.java
changeset 1846 4a53d636e2f4
child 4385 cf4674d08b51
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftLimiter.java	Mon Jan 19 20:11:58 2009 +0300
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * A simple look-ahead volume limiter with very fast attack and fast release.
+ * This filter is used for preventing clipping.
+ *
+ * @author Karl Helgason
+ */
+public class SoftLimiter implements SoftAudioProcessor {
+
+    float lastmax = 0;
+    float gain = 1;
+    float[] temp_bufferL;
+    float[] temp_bufferR;
+    boolean mix = false;
+    SoftAudioBuffer bufferL;
+    SoftAudioBuffer bufferR;
+    SoftAudioBuffer bufferLout;
+    SoftAudioBuffer bufferRout;
+    float controlrate;
+
+    public void init(float samplerate, float controlrate) {
+        this.controlrate = controlrate;
+    }
+
+    public void setInput(int pin, SoftAudioBuffer input) {
+        if (pin == 0)
+            bufferL = input;
+        if (pin == 1)
+            bufferR = input;
+    }
+
+    public void setOutput(int pin, SoftAudioBuffer output) {
+        if (pin == 0)
+            bufferLout = output;
+        if (pin == 1)
+            bufferRout = output;
+    }
+
+    public void setMixMode(boolean mix) {
+        this.mix = mix;
+    }
+
+    public void globalParameterControlChange(int[] slothpath, long param,
+            long value) {
+    }
+
+    double silentcounter = 0;
+
+    public void processAudio() {
+        if (this.bufferL.isSilent()
+                && (this.bufferR == null || this.bufferR.isSilent())) {
+            silentcounter += 1 / controlrate;
+
+            if (silentcounter > 60) {
+                if (!mix) {
+                    bufferLout.clear();
+                    bufferRout.clear();
+                }
+                return;
+            }
+        } else
+            silentcounter = 0;
+
+        float[] bufferL = this.bufferL.array();
+        float[] bufferR = this.bufferR == null ? null : this.bufferR.array();
+        float[] bufferLout = this.bufferLout.array();
+        float[] bufferRout = this.bufferRout == null
+                                ? null : this.bufferRout.array();
+
+        if (temp_bufferL == null || temp_bufferL.length < bufferL.length)
+            temp_bufferL = new float[bufferL.length];
+        if (bufferR != null)
+            if (temp_bufferR == null || temp_bufferR.length < bufferR.length)
+                temp_bufferR = new float[bufferR.length];
+
+        float max = 0;
+        int len = bufferL.length;
+
+        if (bufferR == null) {
+            for (int i = 0; i < len; i++) {
+                if (bufferL[i] > max)
+                    max = bufferL[i];
+                if (-bufferL[i] > max)
+                    max = -bufferL[i];
+            }
+        } else {
+            for (int i = 0; i < len; i++) {
+                if (bufferL[i] > max)
+                    max = bufferL[i];
+                if (bufferR[i] > max)
+                    max = bufferR[i];
+                if (-bufferL[i] > max)
+                    max = -bufferL[i];
+                if (-bufferR[i] > max)
+                    max = -bufferR[i];
+            }
+        }
+
+        float lmax = lastmax;
+        lastmax = max;
+        if (lmax > max)
+            max = lmax;
+
+        float newgain = 1;
+        if (max > 0.99f)
+            newgain = 0.99f / max;
+        else
+            newgain = 1;
+
+        if (newgain > gain)
+            newgain = (newgain + gain * 9) / 10f;
+
+        float gaindelta = (newgain - gain) / len;
+        if (mix) {
+            if (bufferR == null) {
+                for (int i = 0; i < len; i++) {
+                    gain += gaindelta;
+                    float bL = bufferL[i];
+                    float tL = temp_bufferL[i];
+                    temp_bufferL[i] = bL;
+                    bufferLout[i] += tL * gain;
+                }
+            } else {
+                for (int i = 0; i < len; i++) {
+                    gain += gaindelta;
+                    float bL = bufferL[i];
+                    float bR = bufferR[i];
+                    float tL = temp_bufferL[i];
+                    float tR = temp_bufferR[i];
+                    temp_bufferL[i] = bL;
+                    temp_bufferR[i] = bR;
+                    bufferLout[i] += tL * gain;
+                    bufferRout[i] += tR * gain;
+                }
+            }
+
+        } else {
+            if (bufferR == null) {
+                for (int i = 0; i < len; i++) {
+                    gain += gaindelta;
+                    float bL = bufferL[i];
+                    float tL = temp_bufferL[i];
+                    temp_bufferL[i] = bL;
+                    bufferLout[i] = tL * gain;
+                }
+            } else {
+                for (int i = 0; i < len; i++) {
+                    gain += gaindelta;
+                    float bL = bufferL[i];
+                    float bR = bufferR[i];
+                    float tL = temp_bufferL[i];
+                    float tR = temp_bufferR[i];
+                    temp_bufferL[i] = bL;
+                    temp_bufferR[i] = bR;
+                    bufferLout[i] = tL * gain;
+                    bufferRout[i] = tR * gain;
+                }
+            }
+
+        }
+        gain = newgain;
+    }
+
+    public void processControlLogic() {
+    }
+}