1 /* 2 * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.media.sound; 27 28 /** 29 * A simple look-ahead volume limiter with very fast attack and fast release. 30 * This filter is used for preventing clipping. 31 * 32 * @author Karl Helgason 33 */ 34 public final class SoftLimiter implements SoftAudioProcessor { 35 36 float lastmax = 0; 37 float gain = 1; 38 float[] temp_bufferL; 39 float[] temp_bufferR; 40 boolean mix = false; 41 SoftAudioBuffer bufferL; 42 SoftAudioBuffer bufferR; 43 SoftAudioBuffer bufferLout; 44 SoftAudioBuffer bufferRout; 45 float controlrate; 46 47 @Override init(float samplerate, float controlrate)48 public void init(float samplerate, float controlrate) { 49 this.controlrate = controlrate; 50 } 51 52 @Override setInput(int pin, SoftAudioBuffer input)53 public void setInput(int pin, SoftAudioBuffer input) { 54 if (pin == 0) 55 bufferL = input; 56 if (pin == 1) 57 bufferR = input; 58 } 59 60 @Override setOutput(int pin, SoftAudioBuffer output)61 public void setOutput(int pin, SoftAudioBuffer output) { 62 if (pin == 0) 63 bufferLout = output; 64 if (pin == 1) 65 bufferRout = output; 66 } 67 68 @Override setMixMode(boolean mix)69 public void setMixMode(boolean mix) { 70 this.mix = mix; 71 } 72 73 @Override globalParameterControlChange(int[] slothpath, long param, long value)74 public void globalParameterControlChange(int[] slothpath, long param, 75 long value) { 76 } 77 78 double silentcounter = 0; 79 80 @Override processAudio()81 public void processAudio() { 82 if (this.bufferL.isSilent() 83 && (this.bufferR == null || this.bufferR.isSilent())) { 84 silentcounter += 1 / controlrate; 85 86 if (silentcounter > 60) { 87 if (!mix) { 88 bufferLout.clear(); 89 if (bufferRout != null) bufferRout.clear(); 90 } 91 return; 92 } 93 } else 94 silentcounter = 0; 95 96 float[] bufferL = this.bufferL.array(); 97 float[] bufferR = this.bufferR == null ? null : this.bufferR.array(); 98 float[] bufferLout = this.bufferLout.array(); 99 float[] bufferRout = this.bufferRout == null 100 ? null : this.bufferRout.array(); 101 102 if (temp_bufferL == null || temp_bufferL.length < bufferL.length) 103 temp_bufferL = new float[bufferL.length]; 104 if (bufferR != null) 105 if (temp_bufferR == null || temp_bufferR.length < bufferR.length) 106 temp_bufferR = new float[bufferR.length]; 107 108 float max = 0; 109 int len = bufferL.length; 110 111 if (bufferR == null) { 112 for (int i = 0; i < len; i++) { 113 if (bufferL[i] > max) 114 max = bufferL[i]; 115 if (-bufferL[i] > max) 116 max = -bufferL[i]; 117 } 118 } else { 119 for (int i = 0; i < len; i++) { 120 if (bufferL[i] > max) 121 max = bufferL[i]; 122 if (bufferR[i] > max) 123 max = bufferR[i]; 124 if (-bufferL[i] > max) 125 max = -bufferL[i]; 126 if (-bufferR[i] > max) 127 max = -bufferR[i]; 128 } 129 } 130 131 float lmax = lastmax; 132 lastmax = max; 133 if (lmax > max) 134 max = lmax; 135 136 float newgain = 1; 137 if (max > 0.99f) 138 newgain = 0.99f / max; 139 else 140 newgain = 1; 141 142 if (newgain > gain) 143 newgain = (newgain + gain * 9) / 10f; 144 145 float gaindelta = (newgain - gain) / len; 146 if (mix) { 147 if (bufferR == null) { 148 for (int i = 0; i < len; i++) { 149 gain += gaindelta; 150 float bL = bufferL[i]; 151 float tL = temp_bufferL[i]; 152 temp_bufferL[i] = bL; 153 bufferLout[i] += tL * gain; 154 } 155 } else { 156 for (int i = 0; i < len; i++) { 157 gain += gaindelta; 158 float bL = bufferL[i]; 159 float bR = bufferR[i]; 160 float tL = temp_bufferL[i]; 161 float tR = temp_bufferR[i]; 162 temp_bufferL[i] = bL; 163 temp_bufferR[i] = bR; 164 bufferLout[i] += tL * gain; 165 bufferRout[i] += tR * gain; 166 } 167 } 168 169 } else { 170 if (bufferR == null) { 171 for (int i = 0; i < len; i++) { 172 gain += gaindelta; 173 float bL = bufferL[i]; 174 float tL = temp_bufferL[i]; 175 temp_bufferL[i] = bL; 176 bufferLout[i] = tL * gain; 177 } 178 } else { 179 for (int i = 0; i < len; i++) { 180 gain += gaindelta; 181 float bL = bufferL[i]; 182 float bR = bufferR[i]; 183 float tL = temp_bufferL[i]; 184 float tR = temp_bufferR[i]; 185 temp_bufferL[i] = bL; 186 temp_bufferR[i] = bR; 187 bufferLout[i] = tL * gain; 188 bufferRout[i] = tR * gain; 189 } 190 } 191 192 } 193 gain = newgain; 194 } 195 196 @Override processControlLogic()197 public void processControlLogic() { 198 } 199 } 200