001: /*
002: * Copyright (c) 2000 Silvere Martin-Michiellot All Rights Reserved.
003: *
004: * Silvere Martin-Michiellot grants you ("Licensee") a non-exclusive,
005: * royalty free, license to use, modify and redistribute this
006: * software in source and binary code form,
007: * provided that i) this copyright notice and license appear on all copies of
008: * the software; and ii) Licensee does not utilize the software in a manner
009: * which is disparaging to Silvere Martin-Michiellot.
010: *
011: * This software is provided "AS IS," without a warranty of any kind. ALL
012: * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
013: * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
014: * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. Silvere Martin-Michiellot
015: * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES
016: * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
017: * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
018: * Silvere Martin-Michiellot OR ITS LICENSORS BE LIABLE
019: * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
020: * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
021: * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
022: * OR INABILITY TO USE SOFTWARE, EVEN IF Silvere Martin-Michiellot HAS BEEN
023: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
024: *
025: * This software is not designed or intended for use in on-line control of
026: * aircraft, air traffic, aircraft navigation or aircraft communications; or in
027: * the design, construction, operation or maintenance of any nuclear
028: * facility. Licensee represents and warrants that it will not use or
029: * redistribute the Software for such purposes.
030: *
031: */
032:
033: // This code is repackaged after the code from Craig A. Lindley, from Digital Audio with Java
034: // Site ftp://ftp.prenhall.com/pub/ptr/professional_computer_science.w-022/digital_audio/
035: // Email
036: package com.db.media.audio.dsp.processors;
037:
038: public class AllpassNetwork {
039:
040: // Private class data
041: private int sampleRate;
042: private int numberOfChannels;
043: private double delayInMs;
044: private double sustainTimeInMs;
045: private double gain1;
046: private double gain2;
047: private double gain3;
048: private int sustainSampleCount;
049: private double[] delayBuffer;
050: private int delayBufferSize;
051: private int writeIndex;
052: private int readIndex;
053:
054: public AllpassNetwork(int sampleRate, int numberOfChannels,
055: double delayInMs) {
056:
057: // Save incoming
058: this .sampleRate = sampleRate;
059: this .numberOfChannels = numberOfChannels;
060:
061: // Default gain of allpass network
062: double networkGain = 0.7;
063: gain1 = -networkGain;
064: gain2 = 1.0 - (networkGain * networkGain);
065: gain3 = networkGain;
066:
067: // Default sustain
068: sustainTimeInMs = 65.0;
069:
070: // Initialize delay parameters
071: setDelayInMs(delayInMs);
072:
073: }
074:
075: public void setDelayInMs(double delayInMs) {
076:
077: this .delayInMs = delayInMs;
078:
079: // Do calculation to determine delay buffer size
080: int delayOffset = (int) ((delayInMs + 0.5) * sampleRate * numberOfChannels) / 1000;
081:
082: delayBufferSize = AbstractAudio.SAMPLEBUFFERSIZE + delayOffset;
083:
084: // Allocate new delay buffer
085: delayBuffer = new double[delayBufferSize];
086:
087: // Initialize indices
088: // Index where dry sample is written
089: writeIndex = 0;
090:
091: // Index where wet sample is read
092: readIndex = AbstractAudio.SAMPLEBUFFERSIZE;
093:
094: // Calculate gain for filter
095: calcGain();
096:
097: }
098:
099: private void calcGain() {
100:
101: // Calculate gain for this filter such that a recirculating
102: // sample will reduce in level 60db in the specified
103: // sustain time.
104: double gain = Math.pow(0.001, delayInMs / sustainTimeInMs);
105:
106: // Now update the network gain
107: gain1 = -gain;
108: gain2 = 1.0 - (gain * gain);
109: gain3 = gain;
110:
111: }
112:
113: // Sustain time is the time it takes the signal to drop
114: // approximately 60 db (1/1000th) in level.
115: public void setSustainTimeInMs(double sustainTimeInMs) {
116:
117: this .sustainTimeInMs = sustainTimeInMs;
118:
119: // Number of samples needed for sustain duration
120: sustainSampleCount = (int) ((sustainTimeInMs * sampleRate * numberOfChannels) / 1000);
121:
122: // Calculate gain for this filter
123: calcGain();
124:
125: }
126:
127: // Do the data processing
128: public int doFilter(double[] inBuf, double[] outBuf, int length) {
129:
130: // See if at end of data
131: if (length != -1) {
132: // Sustain is not in effect because there are input samples
133: for (int i = 0; i < length; i++) {
134: double inSample = inBuf[i];
135: double outSample = inSample * gain1;
136: double delaySample = delayBuffer[readIndex++];
137: outSample += delaySample * gain2;
138:
139: // Output the new sample
140: outBuf[i] = outSample;
141:
142: // Apply gain and feedback to sample
143: inSample += delaySample * gain3;
144:
145: // Store sample in delay buffer
146: delayBuffer[writeIndex++] = inSample;
147:
148: // Update buffer indices
149: readIndex %= delayBufferSize;
150: writeIndex %= delayBufferSize;
151: }
152: return length;
153:
154: } else {
155:
156: // No more input samples are available therefore sustain is in
157: // mode is in effect.
158: int samplesToMove = Math.min(outBuf.length,
159: sustainSampleCount);
160: if (samplesToMove <= 0)
161: return -1;
162:
163: // No more input samples are available therefore sustain is in
164: // mode is in effect.
165: for (int i = 0; i < samplesToMove; i++) {
166: double delaySample = delayBuffer[readIndex++];
167: double outSample = delaySample * gain2;
168:
169: // Output is from delay buffer
170: outBuf[i] = outSample;
171:
172: // Apply gain and feedback to sample
173: double inSample = delaySample * gain3;
174:
175: // Store sample in delay buffer
176: delayBuffer[writeIndex++] = inSample;
177:
178: // Update buffer indices
179: readIndex %= delayBufferSize;
180: writeIndex %= delayBufferSize;
181: sustainSampleCount--;
182: }
183: return samplesToMove;
184: }
185:
186: }
187:
188: }
|