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 Phaser extends AbstractAudio {
039:
040: // Private class data
041: private double this Out1, this Out2, this Out3, this Out4;
042: private double prevIn1, prevIn2, prevIn3, prevIn4;
043: private double leftThisOut1, leftThisOut2, leftThisOut3,
044: leftThisOut4;
045: private double rightThisOut1, rightThisOut2, rightThisOut3,
046: rightThisOut4;
047: private double leftPrevIn1, leftPrevIn2, leftPrevIn3, leftPrevIn4;
048: private double rightPrevIn1, rightPrevIn2, rightPrevIn3,
049: rightPrevIn4;
050:
051: private double sweepRate;
052: private double sweepRange;
053: private double baseFreq;
054: private double wp;
055: private double minWp;
056: private double maxWp;
057: private double step;
058: private double currentStep;
059: private double sweepValue = 0;
060: private boolean invertPhase;
061: private int dryLevel;
062: private int wetLevel;
063: private int feedbackLevel;
064:
065: private int sampleRate = 0;
066: private int numberOfChannels = 0;
067: private boolean initializationComplete;
068:
069: public Phaser() {
070:
071: super ("Phaser", AbstractAudio.PROCESSOR);
072:
073: initializationComplete = false;
074: invertPhase = false;
075:
076: }
077:
078: // Process the samples that pass thru this effect
079: public int getSamples(short[] buffer, int length) {
080:
081: int len = previous.getSamples(buffer, length);
082:
083: if (getByPass() || !initializationComplete)
084: return len;
085:
086: // Not in bypass mode, process the samples
087: if (numberOfChannels == 1)
088: return processMonoSamples(buffer, len);
089: else
090: return processStereoSamples(buffer, len);
091:
092: }
093:
094: protected int processMonoSamples(short[] buffer, int len) {
095:
096: // Do the processing
097: for (int i = 0; i < len; i++) {
098:
099: // Calculate A in difference equation
100: double A = (1.0 - wp) / (1.0 + wp);
101:
102: int inSample = (int) buffer[i];
103:
104: double in = inSample
105: + (((invertPhase ? -1 : 1) * feedbackLevel * this Out4) / 100.0);
106:
107: // Do the first allpass filter
108: this Out1 = A * (in + this Out1) - prevIn1;
109: prevIn1 = in;
110:
111: // Do the second allpass filter
112: this Out2 = A * (this Out1 + this Out2) - prevIn2;
113: prevIn2 = this Out1;
114:
115: // Do the third allpass filter
116: this Out3 = A * (this Out2 + this Out3) - prevIn3;
117: prevIn3 = this Out2;
118:
119: // Do the forth allpass filter
120: this Out4 = A * (this Out3 + this Out4) - prevIn4;
121: prevIn4 = this Out3;
122:
123: double outSample = ((this Out4 * wetLevel) / 100.0)
124: + ((inSample * dryLevel) / 100.0);
125:
126: // Clip output to legal levels
127: if (outSample > 32767.0)
128: outSample = 32767;
129: else if (outSample < -32768.0)
130: outSample = -32768;
131:
132: buffer[i] = (short) outSample;
133:
134: // Update sweep
135: wp *= currentStep; // Apply step value
136:
137: if (wp > maxWp) // Exceed max Wp ?
138: currentStep = 1.0 / step;
139: else if (wp < minWp) // Exceed min Wp ?
140: currentStep = step;
141: }
142: return len;
143:
144: }
145:
146: protected int processStereoSamples(short[] buffer, int len) {
147:
148: // Do the processing
149: for (int i = 0; i < len / 2; i++) {
150:
151: // Calculate A in difference equation
152: double A = (1.0 - wp) / (1.0 + wp);
153:
154: int leftInSample = (int) buffer[2 * i];
155: int rightInSample = (int) buffer[2 * i + 1];
156:
157: double leftIn = leftInSample
158: + (((invertPhase ? -1 : 1) * feedbackLevel * leftThisOut4) / 100.0);
159:
160: double rightIn = rightInSample
161: + (((invertPhase ? -1 : 1) * feedbackLevel * rightThisOut4) / 100.0);
162:
163: // Do the first allpass filter - left channel
164: leftThisOut1 = A * (leftIn + leftThisOut1) - leftPrevIn1;
165: leftPrevIn1 = leftIn;
166:
167: // Do the first allpass filter - right channel
168: rightThisOut1 = A * (rightIn + rightThisOut1)
169: - rightPrevIn1;
170: rightPrevIn1 = rightIn;
171:
172: // Do the second allpass filter - left channel
173: leftThisOut2 = A * (leftThisOut1 + leftThisOut2)
174: - leftPrevIn2;
175: leftPrevIn2 = leftThisOut1;
176:
177: // Do the second allpass filter - right channel
178: rightThisOut2 = A * (rightThisOut1 + rightThisOut2)
179: - rightPrevIn2;
180: rightPrevIn2 = rightThisOut1;
181:
182: // Do the third allpass filter - left channel
183: leftThisOut3 = A * (leftThisOut2 + leftThisOut3)
184: - leftPrevIn3;
185: leftPrevIn3 = leftThisOut2;
186:
187: // Do the third allpass filter - right channel
188: rightThisOut3 = A * (rightThisOut2 + rightThisOut3)
189: - rightPrevIn3;
190: rightPrevIn3 = rightThisOut2;
191:
192: // Do the forth allpass filter - left channel
193: leftThisOut4 = A * (leftThisOut3 + leftThisOut4)
194: - leftPrevIn4;
195: leftPrevIn4 = leftThisOut3;
196:
197: // Do the forth allpass filter - right channel
198: rightThisOut4 = A * (rightThisOut3 + rightThisOut4)
199: - rightPrevIn4;
200: rightPrevIn4 = rightThisOut3;
201:
202: double leftOutSample = ((leftThisOut4 * wetLevel) / 100.0)
203: + ((leftInSample * dryLevel) / 100.0);
204:
205: double rightOutSample = ((rightThisOut4 * wetLevel) / 100.0)
206: + ((rightInSample * dryLevel) / 100.0);
207:
208: // Clip output to legal levels
209: if (leftOutSample > 32767.0)
210: leftOutSample = 32767;
211: else if (leftOutSample < -32768.0)
212: leftOutSample = -32768;
213:
214: if (rightOutSample > 32767.0)
215: rightOutSample = 32767;
216: else if (rightOutSample < -32768.0)
217: rightOutSample = -32768;
218:
219: buffer[2 * i] = (short) leftOutSample;
220: buffer[2 * i + 1] = (short) rightOutSample;
221:
222: // Update sweep
223: wp *= currentStep; // Apply step value
224:
225: if (wp > maxWp) // Exceed max Wp ?
226: currentStep = 1.0 / step;
227: else if (wp < minWp) // Exceed min Wp ?
228: currentStep = step;
229: }
230:
231: return len;
232:
233: }
234:
235: public void setSweepRate(double sweepRate) {
236:
237: this .sweepRate = sweepRate;
238:
239: // Redo initialization
240: doInitialization();
241:
242: }
243:
244: public void setSweepRange(double sweepRange) {
245:
246: this .sweepRange = sweepRange;
247:
248: // Redo initialization
249: doInitialization();
250:
251: }
252:
253: // Mode is either sin or triangle
254: public void setBaseFreq(double baseFreq) {
255:
256: this .baseFreq = baseFreq;
257:
258: // Redo initialization
259: doInitialization();
260:
261: }
262:
263: public void setDryLevel(int dryLevel) {
264:
265: this .dryLevel = dryLevel;
266:
267: }
268:
269: public void setWetLevel(int wetLevel) {
270:
271: this .wetLevel = wetLevel;
272:
273: }
274:
275: public void setFeedbackPhase(boolean invertPhase) {
276:
277: this .invertPhase = invertPhase;
278:
279: }
280:
281: public void setFeedbackLevel(int feedbackLevel) {
282:
283: this .feedbackLevel = feedbackLevel;
284:
285: }
286:
287: public void doInitialization() {
288:
289: // Cannot initialize until sample rate is known
290: if (sampleRate != 0) {
291:
292: wp = minWp = (2.0 * Math.PI * baseFreq) / sampleRate;
293:
294: // Convert octave range to freq range
295: double freqRange = Math.pow(2.0, sweepRange);
296:
297: maxWp = minWp * freqRange;
298:
299: currentStep = step = Math.pow(freqRange, sweepRate
300: / (sampleRate / 2.0));
301:
302: // Indicate initialization is complete
303: initializationComplete = true;
304: }
305:
306: }
307:
308: public void minMaxSamplingRate(int min, int max, int preferred) {
309:
310: super .minMaxSamplingRate(min, max, preferred);
311: sampleRate = preferred;
312: doInitialization();
313:
314: }
315:
316: // Negotiate the number of channels
317: public void minMaxChannels(int min, int max, int preferred) {
318:
319: super.minMaxChannels(min, max, preferred);
320: numberOfChannels = preferred;
321:
322: }
323:
324: }
|