| /* |
| * Copyright (c) 2007, 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; |
| |
| /** |
| * A simple look-ahead volume limiter with very fast attack and fast release. |
| * This filter is used for preventing clipping. |
| * |
| * @author Karl Helgason |
| */ |
| public final 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(); |
| if (bufferRout != null) 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() { |
| } |
| } |