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: /*
039: This parametric equalizer processor features three filter sections.
040: A high pass shelving filter with adjustable cutoff frequency, a bandpass
041: peaking filter with adjustable center frequency and quality factor (Q)
042: and a low pass shelving filter with adjustable cutoff frequency. All
043: filters are second order. This gives the highpass and lowpass filters
044: a slope of 12 db/octave rolloff. The range of boost and cut is
045: +/- 12 db.
046:
047: All filter sections are IIR filters. The frequency ranges of the highpass
048: and bandpass filters are limited by the Nyquist frequency. The limit
049: is one half the sampling rate. The dampling factor controls how much
050: peaking the highpass and lowpass filters have. A factor of 1.0 exhibits
051: very little if any peaking.
052: */
053:
054: public class ParametricEQ extends AbstractAudio {
055:
056: private static final double DAMPINGFACTOR = 1.0;
057:
058: // Private class data
059: private double[] dBuffer = new double[1];
060: public int sampleRate;
061: private int currentBPFreq;
062: private double currentBPQ;
063: private boolean initializationComplete;
064: private double gainFactor;
065:
066: private static final int HIGHPASSFREQMIN = 5000;
067: private static final int HIGHPASSFREQMAX = 16000;
068: public static final int HIGHPASSFREQDEF = 5000;
069:
070: private static final int BANDPASSFREQMIN = 1500;
071: private static final int BANDPASSFREQMAX = 6000;
072: public static final int BANDPASSFREQDEF = 3000;
073:
074: private static final double BANDPASSQMIN = 1.1;
075: private static final double BANDPASSQMAX = 16.0;
076: public static final double BANDPASSQDEF = 8.0;
077:
078: private static final int LOWPASSFREQMIN = 40;
079: private static final int LOWPASSFREQMAX = 1500;
080: public static final int LOWPASSFREQDEF = 200;
081:
082: // Individual filter object instances
083: private IIRLowpassFilterDesign lpfd;
084: private IIRLowpassFilter lowPassShelf = null;
085:
086: private IIRBandpassFilterDesign bpfd;
087: private IIRBandpassFilter bandPassPeak = null;
088:
089: private IIRHighpassFilterDesign hpfd;
090: private IIRHighpassFilter highPassShelf = null;
091:
092: public ParametricEQ() {
093:
094: super ("Parametric Equalizer", AbstractAudio.PROCESSOR);
095:
096: // Initialization will take place after sample rate is known
097: initializationComplete = false;
098:
099: // Default values for bandpass
100: currentBPFreq = this .BANDPASSFREQDEF;
101: currentBPQ = this .BANDPASSQDEF;
102:
103: }
104:
105: public int getSamples(short[] buffer, int length) {
106:
107: // If bypass is enabled, short circuit filtering
108: if (getByPass() || !initializationComplete)
109: return previous.getSamples(buffer, length);
110:
111: // Ask for a buffer of samples
112: int len = previous.getSamples(buffer, length);
113: if (len == -1)
114: return len;
115:
116: // Realloc buffer as required
117: if (dBuffer.length != len)
118: dBuffer = new double[len];
119:
120: // Move short samples into summation buffer for processing
121: // Prescale the data according to number of filter elements
122: for (int i = 0; i < len; i++)
123: dBuffer[i] = (double) buffer[i] * gainFactor;
124:
125: // Apply the filters
126: lowPassShelf.doFilter(buffer, dBuffer, len);
127: bandPassPeak.doFilter(buffer, dBuffer, len);
128: highPassShelf.doFilter(buffer, dBuffer, len);
129:
130: // Convert the double samples back into short samples after
131: // range constraining them.
132: for (int i = 0; i < len; i++) {
133: double dSample = dBuffer[i];
134: if (dSample > 32767.0)
135: dSample = 32767.0;
136: else if (dSample < -32768.0)
137: dSample = -32768.0;
138:
139: // Convert sample and store
140: buffer[i] = (short) dSample;
141: }
142:
143: return len;
144:
145: }
146:
147: // These methods called when UI controls are manipulated
148: public void lowPassShelfGain(double gain) {
149:
150: if (lowPassShelf != null)
151: lowPassShelf.setAmplitudeAdj(gain);
152:
153: }
154:
155: public void bandPassPeakGain(double gain) {
156:
157: if (bandPassPeak != null)
158: bandPassPeak.setAmplitudeAdj(gain);
159:
160: }
161:
162: public void highPassShelfGain(double gain) {
163:
164: if (highPassShelf != null)
165: highPassShelf.setAmplitudeAdj(gain);
166:
167: }
168:
169: public void lowPassShelfFreq(int freq) {
170:
171: if (lowPassShelf != null) {
172: // Recalculate and install the filter with new freq
173: lpfd = new IIRLowpassFilterDesign(freq, sampleRate,
174: DAMPINGFACTOR);
175: lpfd.doFilterDesign();
176: lowPassShelf.updateFilterCoefficients(lpfd);
177: }
178:
179: }
180:
181: public void bandPassPeakFreq(int freq) {
182:
183: currentBPFreq = freq;
184:
185: if ((bandPassPeak != null) && (freq < (sampleRate / 2))) {
186: // Recalculate and install the filter with new freq
187: bpfd = new IIRBandpassFilterDesign(currentBPFreq,
188: sampleRate, currentBPQ);
189: bpfd.doFilterDesign();
190: bandPassPeak.updateFilterCoefficients(bpfd);
191: }
192:
193: }
194:
195: public void highPassShelfFreq(int freq) {
196:
197: if ((highPassShelf != null) && (freq < (sampleRate / 2))) {
198: hpfd = new IIRHighpassFilterDesign(freq, sampleRate,
199: DAMPINGFACTOR);
200: hpfd.doFilterDesign();
201: highPassShelf.updateFilterCoefficients(hpfd);
202: }
203:
204: }
205:
206: public void bandPassPeakQ(double q) {
207:
208: currentBPQ = q;
209:
210: if (bandPassPeak != null) {
211: // Recalculate and install the filter with new freq
212: bpfd = new IIRBandpassFilterDesign(currentBPFreq,
213: sampleRate, currentBPQ);
214: bpfd.doFilterDesign();
215: bandPassPeak.updateFilterCoefficients(bpfd);
216: }
217:
218: }
219:
220: private void doInitialization() {
221:
222: // Total the number of filter gain elements in chain
223: int gainElements = 1;
224:
225: // Design the filters now that the sampling rate is known.
226: // Design the low pass filter
227: lpfd = new IIRLowpassFilterDesign(this .LOWPASSFREQDEF,
228: sampleRate, DAMPINGFACTOR);
229: lpfd.doFilterDesign();
230:
231: // Implement the filter design
232: lowPassShelf = new IIRLowpassFilter(lpfd);
233: gainElements++;
234:
235: // Design the band filter
236: bpfd = new IIRBandpassFilterDesign(currentBPFreq, sampleRate,
237: currentBPQ);
238: bpfd.doFilterDesign();
239:
240: // Implement the filter design
241: bandPassPeak = new IIRBandpassFilter(bpfd);
242: gainElements++;
243:
244: // Design the high pass filter
245: hpfd = new IIRHighpassFilterDesign(this .HIGHPASSFREQDEF,
246: sampleRate, DAMPINGFACTOR);
247: hpfd.doFilterDesign();
248:
249: // Implement the filter design
250: highPassShelf = new IIRHighpassFilter(hpfd);
251: gainElements++;
252:
253: gainFactor = 1.0 / gainElements;
254:
255: // All filters designed, indicate initialization is complete
256: initializationComplete = true;
257:
258: }
259:
260: public void minMaxSamplingRate(int min, int max, int preferred) {
261:
262: super.minMaxSamplingRate(min, max, preferred);
263: sampleRate = preferred;
264: doInitialization();
265:
266: }
267:
268: }
|