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 package com.sun.media.sound;
26
27 import java.util.Arrays;
28
29 /**
30 * A chorus effect made using LFO and variable delay. One for each channel
31 * (left,right), with different starting phase for stereo effect.
32 *
33 * @author Karl Helgason
34 */
35 public final class SoftChorus implements SoftAudioProcessor {
36
37 private static class VariableDelay {
38
39 private final float[] delaybuffer;
40 private int rovepos = 0;
41 private float gain = 1;
42 private float rgain = 0;
43 private float delay = 0;
44 private float lastdelay = 0;
173 }
174 private boolean mix = true;
175 private SoftAudioBuffer inputA;
176 private SoftAudioBuffer left;
177 private SoftAudioBuffer right;
178 private SoftAudioBuffer reverb;
179 private LFODelay vdelay1L;
180 private LFODelay vdelay1R;
181 private float rgain = 0;
182 private boolean dirty = true;
183 private double dirty_vdelay1L_rate;
184 private double dirty_vdelay1R_rate;
185 private double dirty_vdelay1L_depth;
186 private double dirty_vdelay1R_depth;
187 private float dirty_vdelay1L_feedback;
188 private float dirty_vdelay1R_feedback;
189 private float dirty_vdelay1L_reverbsendgain;
190 private float dirty_vdelay1R_reverbsendgain;
191 private float controlrate;
192
193 public void init(float samplerate, float controlrate) {
194 this.controlrate = controlrate;
195 vdelay1L = new LFODelay(samplerate, controlrate);
196 vdelay1R = new LFODelay(samplerate, controlrate);
197 vdelay1L.setGain(1.0f); // %
198 vdelay1R.setGain(1.0f); // %
199 vdelay1L.setPhase(0.5 * Math.PI);
200 vdelay1R.setPhase(0);
201
202 globalParameterControlChange(new int[]{0x01 * 128 + 0x02}, 0, 2);
203 }
204
205 public void globalParameterControlChange(int[] slothpath, long param,
206 long value) {
207 if (slothpath.length == 1) {
208 if (slothpath[0] == 0x01 * 128 + 0x02) {
209 if (param == 0) { // Chorus Type
210 switch ((int)value) {
211 case 0: // Chorus 1 0 (0%) 3 (0.4Hz) 5 (1.9ms) 0 (0%)
212 globalParameterControlChange(slothpath, 3, 0);
213 globalParameterControlChange(slothpath, 1, 3);
214 globalParameterControlChange(slothpath, 2, 5);
215 globalParameterControlChange(slothpath, 4, 0);
216 break;
217 case 1: // Chorus 2 5 (4%) 9 (1.1Hz) 19 (6.3ms) 0 (0%)
218 globalParameterControlChange(slothpath, 3, 5);
219 globalParameterControlChange(slothpath, 1, 9);
220 globalParameterControlChange(slothpath, 2, 19);
221 globalParameterControlChange(slothpath, 4, 0);
222 break;
223 case 2: // Chorus 3 8 (6%) 3 (0.4Hz) 19 (6.3ms) 0 (0%)
224 globalParameterControlChange(slothpath, 3, 8);
254 } else if (param == 2) { // Mod Depth
255 dirty_vdelay1L_depth = ((value + 1) / 3200.0);
256 dirty_vdelay1R_depth = ((value + 1) / 3200.0);
257 dirty = true;
258 } else if (param == 3) { // Feedback
259 dirty_vdelay1L_feedback = (value * 0.00763f);
260 dirty_vdelay1R_feedback = (value * 0.00763f);
261 dirty = true;
262 }
263 if (param == 4) { // Send to Reverb
264 rgain = value * 0.00787f;
265 dirty_vdelay1L_reverbsendgain = (value * 0.00787f);
266 dirty_vdelay1R_reverbsendgain = (value * 0.00787f);
267 dirty = true;
268 }
269
270 }
271 }
272 }
273
274 public void processControlLogic() {
275 if (dirty) {
276 dirty = false;
277 vdelay1L.setRate(dirty_vdelay1L_rate);
278 vdelay1R.setRate(dirty_vdelay1R_rate);
279 vdelay1L.setDepth(dirty_vdelay1L_depth);
280 vdelay1R.setDepth(dirty_vdelay1R_depth);
281 vdelay1L.setFeedBack(dirty_vdelay1L_feedback);
282 vdelay1R.setFeedBack(dirty_vdelay1R_feedback);
283 vdelay1L.setReverbSendGain(dirty_vdelay1L_reverbsendgain);
284 vdelay1R.setReverbSendGain(dirty_vdelay1R_reverbsendgain);
285 }
286 }
287 double silentcounter = 1000;
288
289 public void processAudio() {
290
291 if (inputA.isSilent()) {
292 silentcounter += 1 / controlrate;
293
294 if (silentcounter > 1) {
295 if (!mix) {
296 left.clear();
297 right.clear();
298 }
299 return;
300 }
301 } else
302 silentcounter = 0;
303
304 float[] inputA = this.inputA.array();
305 float[] left = this.left.array();
306 float[] right = this.right == null ? null : this.right.array();
307 float[] reverb = rgain != 0 ? this.reverb.array() : null;
308
309 if (mix) {
310 vdelay1L.processMix(inputA, left, reverb);
311 if (right != null)
312 vdelay1R.processMix(inputA, right, reverb);
313 } else {
314 vdelay1L.processReplace(inputA, left, reverb);
315 if (right != null)
316 vdelay1R.processReplace(inputA, right, reverb);
317 }
318 }
319
320 public void setInput(int pin, SoftAudioBuffer input) {
321 if (pin == 0)
322 inputA = input;
323 }
324
325 public void setMixMode(boolean mix) {
326 this.mix = mix;
327 }
328
329 public void setOutput(int pin, SoftAudioBuffer output) {
330 if (pin == 0)
331 left = output;
332 if (pin == 1)
333 right = output;
334 if (pin == 2)
335 reverb = output;
336 }
337 }
|
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 import java.util.Arrays;
29
30 /**
31 * A chorus effect made using LFO and variable delay. One for each channel
32 * (left,right), with different starting phase for stereo effect.
33 *
34 * @author Karl Helgason
35 */
36 public final class SoftChorus implements SoftAudioProcessor {
37
38 private static class VariableDelay {
39
40 private final float[] delaybuffer;
41 private int rovepos = 0;
42 private float gain = 1;
43 private float rgain = 0;
44 private float delay = 0;
45 private float lastdelay = 0;
174 }
175 private boolean mix = true;
176 private SoftAudioBuffer inputA;
177 private SoftAudioBuffer left;
178 private SoftAudioBuffer right;
179 private SoftAudioBuffer reverb;
180 private LFODelay vdelay1L;
181 private LFODelay vdelay1R;
182 private float rgain = 0;
183 private boolean dirty = true;
184 private double dirty_vdelay1L_rate;
185 private double dirty_vdelay1R_rate;
186 private double dirty_vdelay1L_depth;
187 private double dirty_vdelay1R_depth;
188 private float dirty_vdelay1L_feedback;
189 private float dirty_vdelay1R_feedback;
190 private float dirty_vdelay1L_reverbsendgain;
191 private float dirty_vdelay1R_reverbsendgain;
192 private float controlrate;
193
194 @Override
195 public void init(float samplerate, float controlrate) {
196 this.controlrate = controlrate;
197 vdelay1L = new LFODelay(samplerate, controlrate);
198 vdelay1R = new LFODelay(samplerate, controlrate);
199 vdelay1L.setGain(1.0f); // %
200 vdelay1R.setGain(1.0f); // %
201 vdelay1L.setPhase(0.5 * Math.PI);
202 vdelay1R.setPhase(0);
203
204 globalParameterControlChange(new int[]{0x01 * 128 + 0x02}, 0, 2);
205 }
206
207 @Override
208 public void globalParameterControlChange(int[] slothpath, long param,
209 long value) {
210 if (slothpath.length == 1) {
211 if (slothpath[0] == 0x01 * 128 + 0x02) {
212 if (param == 0) { // Chorus Type
213 switch ((int)value) {
214 case 0: // Chorus 1 0 (0%) 3 (0.4Hz) 5 (1.9ms) 0 (0%)
215 globalParameterControlChange(slothpath, 3, 0);
216 globalParameterControlChange(slothpath, 1, 3);
217 globalParameterControlChange(slothpath, 2, 5);
218 globalParameterControlChange(slothpath, 4, 0);
219 break;
220 case 1: // Chorus 2 5 (4%) 9 (1.1Hz) 19 (6.3ms) 0 (0%)
221 globalParameterControlChange(slothpath, 3, 5);
222 globalParameterControlChange(slothpath, 1, 9);
223 globalParameterControlChange(slothpath, 2, 19);
224 globalParameterControlChange(slothpath, 4, 0);
225 break;
226 case 2: // Chorus 3 8 (6%) 3 (0.4Hz) 19 (6.3ms) 0 (0%)
227 globalParameterControlChange(slothpath, 3, 8);
257 } else if (param == 2) { // Mod Depth
258 dirty_vdelay1L_depth = ((value + 1) / 3200.0);
259 dirty_vdelay1R_depth = ((value + 1) / 3200.0);
260 dirty = true;
261 } else if (param == 3) { // Feedback
262 dirty_vdelay1L_feedback = (value * 0.00763f);
263 dirty_vdelay1R_feedback = (value * 0.00763f);
264 dirty = true;
265 }
266 if (param == 4) { // Send to Reverb
267 rgain = value * 0.00787f;
268 dirty_vdelay1L_reverbsendgain = (value * 0.00787f);
269 dirty_vdelay1R_reverbsendgain = (value * 0.00787f);
270 dirty = true;
271 }
272
273 }
274 }
275 }
276
277 @Override
278 public void processControlLogic() {
279 if (dirty) {
280 dirty = false;
281 vdelay1L.setRate(dirty_vdelay1L_rate);
282 vdelay1R.setRate(dirty_vdelay1R_rate);
283 vdelay1L.setDepth(dirty_vdelay1L_depth);
284 vdelay1R.setDepth(dirty_vdelay1R_depth);
285 vdelay1L.setFeedBack(dirty_vdelay1L_feedback);
286 vdelay1R.setFeedBack(dirty_vdelay1R_feedback);
287 vdelay1L.setReverbSendGain(dirty_vdelay1L_reverbsendgain);
288 vdelay1R.setReverbSendGain(dirty_vdelay1R_reverbsendgain);
289 }
290 }
291 double silentcounter = 1000;
292
293 @Override
294 public void processAudio() {
295
296 if (inputA.isSilent()) {
297 silentcounter += 1 / controlrate;
298
299 if (silentcounter > 1) {
300 if (!mix) {
301 left.clear();
302 right.clear();
303 }
304 return;
305 }
306 } else
307 silentcounter = 0;
308
309 float[] inputA = this.inputA.array();
310 float[] left = this.left.array();
311 float[] right = this.right == null ? null : this.right.array();
312 float[] reverb = rgain != 0 ? this.reverb.array() : null;
313
314 if (mix) {
315 vdelay1L.processMix(inputA, left, reverb);
316 if (right != null)
317 vdelay1R.processMix(inputA, right, reverb);
318 } else {
319 vdelay1L.processReplace(inputA, left, reverb);
320 if (right != null)
321 vdelay1R.processReplace(inputA, right, reverb);
322 }
323 }
324
325 @Override
326 public void setInput(int pin, SoftAudioBuffer input) {
327 if (pin == 0)
328 inputA = input;
329 }
330
331 @Override
332 public void setMixMode(boolean mix) {
333 this.mix = mix;
334 }
335
336 @Override
337 public void setOutput(int pin, SoftAudioBuffer output) {
338 if (pin == 0)
339 left = output;
340 if (pin == 1)
341 right = output;
342 if (pin == 2)
343 reverb = output;
344 }
345 }
|