Mercurial > hg > openjdk6.drops
view jdk/src/share/classes/com/sun/media/sound/SoftReverb.java @ 10:a6a6e9c3d502 jdk6-b10
Import b10
author | Mark Wielaard <mark@klomp.org> |
---|---|
date | Fri, 30 May 2008 00:00:00 +0200 |
parents | |
children | 7c56bb8ffc4b |
line wrap: on
line source
/* * 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; import java.util.Arrays; /** * Reverb effect based on allpass/comb filters. First audio is send to 8 * parelled comb filters and then mixed together and then finally send thru 3 * different allpass filters. * * @author Karl Helgason */ public class SoftReverb implements SoftAudioProcessor { private class Delay { private float[] delaybuffer; private int rovepos = 0; public Delay() { delaybuffer = null; } public void setDelay(int delay) { if (delay == 0) delaybuffer = null; else delaybuffer = new float[delay]; rovepos = 0; } public void processReplace(float[] in, float[] out) { float[] delaybuffer = this.delaybuffer; if (delaybuffer == null) return; int len = in.length; int rnlen = delaybuffer.length; int rovepos = this.rovepos; for (int i = 0; i < len; i++) { float x = in[i]; out[i] = delaybuffer[rovepos]; delaybuffer[rovepos] = x; rovepos = rovepos + 1; if (rovepos == rnlen) rovepos = 0; //rovepos = (rovepos + 1) % rnlen; } this.rovepos = rovepos; } } private class AllPass { private float[] delaybuffer; private int delaybuffersize; private int rovepos = 0; private float feedback; public AllPass(int size) { delaybuffer = new float[size]; delaybuffersize = size; } public void setFeedBack(float feedback) { this.feedback = feedback; } int ucount = 0; public void processReplace(float in[], float out[]) { int len = in.length; for (int i = 0; i < len; i++) { float delayout = delaybuffer[rovepos]; // undenormalise(delayout) /* if (((delayout > 0.0) && (delayout < 1.0E-10)) || ((delayout < 0.0) && (delayout > -1.0E-10))) delayout = 0; */ float input = in[i]; out[i] = -input + delayout; delaybuffer[rovepos] = input + delayout * feedback; if (++rovepos == delaybuffersize) rovepos = 0; } ucount++; if (ucount == 10) { ucount = 0; for (int i = 0; i < delaybuffer.length; i++) { double v = delaybuffer[i]; if (((v > 0.0) && (v < 1.0E-10)) || ((v < 0.0) && (v > -1.0E-10))) { delaybuffer[i] = 0; } } } } } private class Comb { private float[] delaybuffer; private int delaybuffersize; private int rovepos = 0; private float feedback; private float filtertemp = 0; private float filtercoeff1 = 0; private float filtercoeff2 = 1; public Comb(int size) { delaybuffer = new float[size]; delaybuffersize = size; } public void setFeedBack(float feedback) { this.feedback = feedback; } int ucount = 0; public void processMix(float in[], float out[]) { int len = in.length; float filtercoeff2 = this.filtercoeff2 * feedback; for (int i = 0; i < len; i++) { float delayout = delaybuffer[rovepos]; // One Pole Lowpass Filter filtertemp = (delayout * filtercoeff2) + (filtertemp * filtercoeff1); // undenormalise(filtertemp) /* if (((filtertemp > 0.0) && (filtertemp < 1.0E-10)) || ((filtertemp < 0.0) && (filtertemp > -1.0E-10))) filtertemp = 0; */ out[i] += delayout; delaybuffer[rovepos] = in[i] + (filtertemp);// * feedback); if (++rovepos == delaybuffersize) rovepos = 0; } ucount++; if (ucount == 10) { ucount = 0; if (((filtertemp > 0.0) && (filtertemp < 1.0E-10)) || ((filtertemp < 0.0) && (filtertemp > -1.0E-10))) { filtertemp = 0; } for (int i = 0; i < delaybuffer.length; i++) { double v = delaybuffer[i]; if (((v > 0.0) && (v < 1.0E-10)) || ((v < 0.0) && (v > -1.0E-10))) { delaybuffer[i] = 0; } } } } public void setDamp(float val) { filtercoeff1 = val; filtercoeff2 = 1 - filtercoeff1; } } private float roomsize; private float damp; private float gain = 1; private Delay delay; private Comb[] combL; private Comb[] combR; private AllPass[] allpassL; private AllPass[] allpassR; private float[] input; private float[] outR; private float[] outL; private boolean mix = true; private SoftAudioBuffer inputA; private SoftAudioBuffer left; private SoftAudioBuffer right; private SoftSynthesizer synth; private boolean dirty = true; private float dirty_roomsize; private float dirty_damp; private float dirty_predelay; private float dirty_gain; public void init(SoftSynthesizer synth) { this.synth = synth; double samplerate = synth.getFormat().getSampleRate(); double freqscale = ((double) samplerate) / 44100.0; // freqscale = 1.0/ freqscale; int stereospread = 23; delay = new Delay(); combL = new Comb[8]; combR = new Comb[8]; combL[0] = new Comb((int) (freqscale * (1116))); combR[0] = new Comb((int) (freqscale * (1116 + stereospread))); combL[1] = new Comb((int) (freqscale * (1188))); combR[1] = new Comb((int) (freqscale * (1188 + stereospread))); combL[2] = new Comb((int) (freqscale * (1277))); combR[2] = new Comb((int) (freqscale * (1277 + stereospread))); combL[3] = new Comb((int) (freqscale * (1356))); combR[3] = new Comb((int) (freqscale * (1356 + stereospread))); combL[4] = new Comb((int) (freqscale * (1422))); combR[4] = new Comb((int) (freqscale * (1422 + stereospread))); combL[5] = new Comb((int) (freqscale * (1491))); combR[5] = new Comb((int) (freqscale * (1491 + stereospread))); combL[6] = new Comb((int) (freqscale * (1557))); combR[6] = new Comb((int) (freqscale * (1557 + stereospread))); combL[7] = new Comb((int) (freqscale * (1617))); combR[7] = new Comb((int) (freqscale * (1617 + stereospread))); allpassL = new AllPass[4]; allpassR = new AllPass[4]; allpassL[0] = new AllPass((int) (freqscale * (556))); allpassR[0] = new AllPass((int) (freqscale * (556 + stereospread))); allpassL[1] = new AllPass((int) (freqscale * (441))); allpassR[1] = new AllPass((int) (freqscale * (441 + stereospread))); allpassL[2] = new AllPass((int) (freqscale * (341))); allpassR[2] = new AllPass((int) (freqscale * (341 + stereospread))); allpassL[3] = new AllPass((int) (freqscale * (225))); allpassR[3] = new AllPass((int) (freqscale * (225 + stereospread))); for (int i = 0; i < allpassL.length; i++) { allpassL[i].setFeedBack(0.5f); allpassR[i].setFeedBack(0.5f); } /* Init other settings */ globalParameterControlChange(new int[]{0x01 * 128 + 0x01}, 0, 4); } public void setInput(int pin, SoftAudioBuffer input) { if (pin == 0) inputA = input; } public void setOutput(int pin, SoftAudioBuffer output) { if (pin == 0) left = output; if (pin == 1) right = output; } public void setMixMode(boolean mix) { this.mix = mix; } private double silentcounter = 1000; public void processAudio() { if (this.inputA.isSilent()) { silentcounter += 1 / synth.getControlRate(); if (silentcounter > 60) { if (!mix) { left.clear(); right.clear(); } return; } } else silentcounter = 0; float[] inputA = this.inputA.array(); float[] left = this.left.array(); float[] right = this.right == null ? null : this.right.array(); int numsamples = inputA.length; if (input == null || input.length < numsamples) input = new float[numsamples]; float again = gain * 0.018f / 2; for (int i = 0; i < numsamples; i++) input[i] = inputA[i] * again; delay.processReplace(input, input); if (right != null) { if (outR == null || outR.length < numsamples) outR = new float[numsamples]; Arrays.fill(outR, 0); for (int i = 0; i < combR.length; i++) combR[i].processMix(input, outR); for (int i = 0; i < allpassL.length; i++) allpassR[i].processReplace(outR, outR); if (mix) { for (int i = 0; i < numsamples; i++) right[i] += outR[i]; } else { for (int i = 0; i < numsamples; i++) right[i] = outR[i]; } } if (outL == null || outL.length < numsamples) outL = new float[numsamples]; Arrays.fill(outL, 0); for (int i = 0; i < combL.length; i++) combL[i].processMix(input, outL); for (int i = 0; i < allpassL.length; i++) allpassL[i].processReplace(outL, outL); if (mix) { for (int i = 0; i < numsamples; i++) left[i] += outL[i]; } else { for (int i = 0; i < numsamples; i++) left[i] = outL[i]; } } public void globalParameterControlChange(int[] slothpath, long param, long value) { if (slothpath.length == 1) { if (slothpath[0] == 0x01 * 128 + 0x01) { if (param == 0) { if (value == 0) { // Small Room A small size room with a length // of 5m or so. dirty_roomsize = (1.1f); dirty_damp = (5000); dirty_predelay = (0); dirty_gain = (4); dirty = true; } if (value == 1) { // Medium Room A medium size room with a length // of 10m or so. dirty_roomsize = (1.3f); dirty_damp = (5000); dirty_predelay = (0); dirty_gain = (3); dirty = true; } if (value == 2) { // Large Room A large size room suitable for // live performances. dirty_roomsize = (1.5f); dirty_damp = (5000); dirty_predelay = (0); dirty_gain = (2); dirty = true; } if (value == 3) { // Medium Hall A medium size concert hall. dirty_roomsize = (1.8f); dirty_damp = (24000); dirty_predelay = (0.02f); dirty_gain = (1.5f); dirty = true; } if (value == 4) { // Large Hall A large size concert hall // suitable for a full orchestra. dirty_roomsize = (1.8f); dirty_damp = (24000); dirty_predelay = (0.03f); dirty_gain = (1.5f); dirty = true; } if (value == 8) { // Plate A plate reverb simulation. dirty_roomsize = (1.3f); dirty_damp = (2500); dirty_predelay = (0); dirty_gain = (6); dirty = true; } } else if (param == 1) { dirty_roomsize = ((float) (Math.exp((value - 40) * 0.025))); dirty = true; } } } } public void processControlLogic() { if (dirty) { dirty = false; setRoomSize(dirty_roomsize); setDamp(dirty_damp); setPreDelay(dirty_predelay); setGain(dirty_gain); } } public void setRoomSize(float value) { roomsize = 1 - (0.17f / value); for (int i = 0; i < 8; i++) { combL[i].feedback = roomsize; combR[i].feedback = roomsize; } } public void setPreDelay(float value) { delay.setDelay((int)(value * synth.getFormat().getSampleRate())); } public void setGain(float gain) { this.gain = gain; } public void setDamp(float value) { double x = (value / synth.getFormat().getSampleRate()) * (2 * Math.PI); double cx = 2 - Math.cos(x); damp = (float)(cx - Math.sqrt(cx * cx - 1)); if (damp > 1) damp = 1; if (damp < 0) damp = 0; // damp = value * 0.4f; for (int i = 0; i < 8; i++) { combL[i].setDamp(damp); combR[i].setDamp(damp); } } }