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: The algorithm for this pitch shifter was adapted from the
040: article titled "Examining Audio DSP Algorithms" by
041: Dennis Cronin published in Dr. Dobb's Journal.
042: */
043:
044: public class PitchShifter extends AbstractAudio {
045:
046: // Fixed delay period with which to do pitch shifting
047: private static final int FIXEDDELAYINMS = 100;
048: // Fade in/out times
049: private static final int CROSSFADETIMEINMS = 12;
050: // Constant by which one tone differs from the next when the
051: // interval is a halftone.
052: private static final double twelvethRootOfTwo = Math.pow(2,
053: 1.0 / 12.0);
054:
055: // Private class data
056: private boolean initializationComplete;
057: private boolean sweepUp;
058: private double step;
059: private double sweep;
060: private int dryLevel;
061: private int wetLevel;
062: private int feedbackLevel;
063:
064: private int sampleRate = 0;
065: private int numberOfChannels = 0;
066: private int delayBufferSize = 0;
067: private short[] localBuffer = null;
068: private long[] delayBuffer = null;
069: private int readIndexALow;
070: private int readIndexAHigh;
071: private int readIndexBLow;
072: private int readIndexBHigh;
073: private int writeIndex;
074: private int numberOfDelaySamples;
075: private int numberOfCrossFadeSamples;
076: private int crossFadeCount;
077: private int activeSampleCount;
078: private int activeCount;
079: private boolean channelA;
080: private double blendA;
081: private double blendB;
082:
083: private double[] fadeIn;
084: private double[] fadeOut;
085: private double[] fadeA;
086: private double[] fadeB;
087:
088: // Class constructor
089: public PitchShifter() {
090:
091: super ("Pitch Shifter", AbstractAudio.PROCESSOR);
092:
093: // Initialize various parameters
094: initializationComplete = false; // Initialization not yet performed
095: sweepUp = true; // Assume upward change in frequency
096: sweep = 0.0; // Initial value for sweep rate
097: channelA = true; // Setup to use channel A sweep
098: blendA = 1.0; // Blend values for the two delay channels
099: blendB = 0.0;
100:
101: // Allocate local sample buffer
102: localBuffer = new short[AbstractAudio.SAMPLEBUFFERSIZE];
103:
104: }
105:
106: // Process the samples that pass thru this effect
107: public int getSamples(short[] buffer, int length) {
108:
109: // Don't perform processing until initialization is
110: // complete and bypass is not active.
111: if (getByPass() || !initializationComplete)
112: return previous.getSamples(buffer, length);
113:
114: // Read number of samples requested from previous stage
115: int len = previous.getSamples(localBuffer, length);
116:
117: double delaySampleA, delaySampleB;
118:
119: // Do the processing over the new buffer of samples
120: for (int i = 0; i < len; i++) {
121:
122: // Get a sample to process
123: long inputSample = localBuffer[i];
124:
125: // Grab four samples at a time. This is required for
126: // interpolation and blending.
127: long dsALow = delayBuffer[readIndexALow];
128: long dsAHigh = delayBuffer[readIndexAHigh];
129: long dsBLow = delayBuffer[readIndexBLow];
130: long dsBHigh = delayBuffer[readIndexBHigh];
131:
132: // Do the linear interpolation
133: if (sweepUp) {
134: delaySampleA = (dsAHigh * sweep)
135: + (dsALow * (1.0 - sweep));
136: delaySampleB = (dsBHigh * sweep)
137: + (dsBLow * (1.0 - sweep));
138: } else {
139: delaySampleA = (dsAHigh * (1.0 - sweep) + (dsALow * sweep));
140: delaySampleB = (dsBHigh * (1.0 - sweep) + (dsBLow * sweep));
141: }
142:
143: // Combine delay channels A and B with appropriate blending
144: double outputSample = (delaySampleA * blendA)
145: + (delaySampleB * blendB);
146:
147: // Store sample in delay buffer
148: delayBuffer[writeIndex] = (long) (inputSample + ((outputSample * feedbackLevel) / 100));
149:
150: // Update write index
151: writeIndex = (writeIndex + 1) % delayBufferSize;
152:
153: // Prepare sample for output by combining wet and dry
154: // values
155: outputSample = ((inputSample * dryLevel) / 100)
156: + ((outputSample * wetLevel) / 100);
157:
158: // Clamp output to legal range
159: if (outputSample > 32767)
160: outputSample = 32767;
161: if (outputSample < -32768)
162: outputSample = -32768;
163:
164: // Store output sample in outgoing buffer
165: buffer[i] = (short) outputSample;
166:
167: // Update cross fade blending values each sample interval
168: if (crossFadeCount != 0) {
169: crossFadeCount--;
170:
171: // Get new blending values for both channels
172: blendA = fadeA[crossFadeCount];
173: blendB = fadeB[crossFadeCount];
174: }
175:
176: // Update sweep value for each pass if processing
177: // mono signal and every other pass if processing
178: // stereo.
179: if ((numberOfChannels == 1) || ((i + 1) % 2 == 0))
180: sweep += step;
181:
182: if (sweepUp) {
183: // Upward frequency change
184:
185: // Advance indices to reduce delay
186: readIndexALow = readIndexAHigh;
187: readIndexAHigh = (readIndexAHigh + 1) % delayBufferSize;
188: readIndexBLow = readIndexBHigh;
189: readIndexBHigh = (readIndexBHigh + 1) % delayBufferSize;
190:
191: // Check for overflow
192: if (sweep < 1.0) {
193: // No overflow, continue with next sample
194: continue;
195: }
196:
197: // Octave exceeded bump ptrs again
198: sweep = 0.0;
199: readIndexALow = readIndexAHigh;
200: readIndexAHigh = (readIndexAHigh + 1) % delayBufferSize;
201: readIndexBLow = readIndexBHigh;
202: readIndexBHigh = (readIndexBHigh + 1) % delayBufferSize;
203:
204: // See if it is time to switch to other delay channel
205: if (activeCount-- == 0) {
206: // Reset fade in/out count
207: crossFadeCount = numberOfCrossFadeSamples;
208: activeCount = activeSampleCount;
209: if (channelA) {
210: channelA = false;
211: readIndexBHigh = (writeIndex + AbstractAudio.SAMPLEBUFFERSIZE)
212: % delayBufferSize;
213: // Swap blend coefficient arrays
214: fadeA = fadeOut;
215: fadeB = fadeIn;
216: } else {
217: channelA = true;
218: readIndexAHigh = (writeIndex + AbstractAudio.SAMPLEBUFFERSIZE)
219: % delayBufferSize;
220: // Swap blend coefficient arrays
221: fadeA = fadeIn;
222: fadeB = fadeOut;
223: }
224: }
225:
226: } else {
227: // Downward frequency change
228:
229: // Check for overflow
230: if (sweep < 1.0) {
231: // No overflow, advance indices
232: readIndexALow = readIndexAHigh;
233: readIndexAHigh = (readIndexAHigh + 1)
234: % delayBufferSize;
235: readIndexBLow = readIndexBHigh;
236: readIndexBHigh = (readIndexBHigh + 1)
237: % delayBufferSize;
238:
239: // Continue with processing the next sample
240: continue;
241: }
242: // Octave exceeded don't bump indices so the delay
243: // is increased
244: sweep = 0.0;
245:
246: // See if it is time to switch to other delay channel
247: if (activeCount-- == 0) {
248: // Reset fade in/out count
249: crossFadeCount = numberOfCrossFadeSamples;
250: activeCount = activeSampleCount;
251: if (channelA) {
252: channelA = false;
253: readIndexBHigh = (writeIndex + AbstractAudio.SAMPLEBUFFERSIZE)
254: % delayBufferSize;
255: // Swap blend coefficient arrays
256: fadeA = fadeOut;
257: fadeB = fadeIn;
258: } else {
259: channelA = true;
260: readIndexAHigh = (writeIndex + AbstractAudio.SAMPLEBUFFERSIZE)
261: % delayBufferSize;
262: // Swap blend coefficient arrays
263: fadeA = fadeIn;
264: fadeB = fadeOut;
265: }
266: }
267: }
268: }
269:
270: return len;
271:
272: }
273:
274: // Called when the user changes the dry level.
275: public void setDryLevel(int dryLevel) {
276:
277: // Value in the range 0..100
278: this .dryLevel = dryLevel;
279:
280: }
281:
282: // Called when the user changes the wet level.
283: public void setWetLevel(int wetLevel) {
284:
285: // Value in the range 0..100
286: this .wetLevel = wetLevel;
287:
288: }
289:
290: // Called when the user changes the feedback level.
291: public void setFeedbackLevel(int feedbackLevel) {
292:
293: // Value in the range 0..100
294: this .feedbackLevel = feedbackLevel;
295:
296: }
297:
298: // Called when the user changes the pitch shift value
299: public void setPitchShift(int pitchShift) {
300:
301: // Values are in half steps (semitones) in the
302: // range -12..0..+12 corresponding to -/+ 1 octave for
303: // a range of 2 octaves.
304:
305: // Determine which direction the sweep is going
306: sweepUp = (pitchShift >= 0);
307:
308: setIndices();
309:
310: double newStep = 1.0;
311:
312: // If pitch shift is 0 short circuit calculations
313: if (pitchShift == 0)
314: step = 0;
315:
316: else {
317: // Step is rate at which samples read out
318: for (int i = 0; i < Math.abs(pitchShift); i++) {
319: if (pitchShift > 0)
320: newStep *= twelvethRootOfTwo;
321: else
322: newStep /= twelvethRootOfTwo;
323: }
324: step = Math.abs(newStep - 1.0);
325: }
326: // Reset the following values whenever pitch shift value changes
327: sweep = 0.0;
328: crossFadeCount = 0;
329: activeSampleCount = numberOfDelaySamples
330: - (int) (numberOfCrossFadeSamples * (newStep - 1.0) - 2);
331:
332: }
333:
334: // Set read/write indices depending upon audio format and
335: // frequency change direction
336: private void setIndices() {
337:
338: // Index where dry sample is written
339: writeIndex = 0;
340: readIndexBLow = 0;
341: readIndexBHigh = 0;
342:
343: if (sweepUp) {
344: // Sweeping upward, start at max delay
345: readIndexALow = AbstractAudio.SAMPLEBUFFERSIZE;
346:
347: } else {
348:
349: // Sweeping downward, start at min delay
350: if (numberOfChannels == 1)
351: readIndexALow = delayBufferSize - 2;
352: else
353: readIndexALow = delayBufferSize - 4;
354: }
355: // Initialize other read ptr
356: if (numberOfChannels == 1)
357: readIndexAHigh = readIndexALow + 1;
358: else
359: readIndexAHigh = readIndexALow + 2;
360:
361: }
362:
363: // Do necessary initialization as required for pitch shifting
364: private void doInitialization() {
365:
366: // See if we have the necessary data to initialize delay
367: if ((sampleRate != 0) && (numberOfChannels != 0)
368: && (!initializationComplete)) {
369:
370: // Allocate delay buffer for the fixed delay time
371: numberOfDelaySamples = (FIXEDDELAYINMS * sampleRate * numberOfChannels) / 1000;
372:
373: // Total buffer size
374: delayBufferSize = AbstractAudio.SAMPLEBUFFERSIZE
375: + numberOfDelaySamples;
376:
377: // Allocate new delay buffer
378: delayBuffer = new long[delayBufferSize];
379:
380: // Initialize indices in the delay buffer
381: setIndices();
382:
383: // Calculate the number of cross fade samples
384: numberOfCrossFadeSamples = (CROSSFADETIMEINMS * sampleRate) / 1000;
385:
386: // Allocate arrays for cross fade coefficients
387: fadeIn = new double[numberOfCrossFadeSamples];
388: fadeOut = new double[numberOfCrossFadeSamples];
389:
390: // Fill in the arrays with fade in/out values. Sin and Cos
391: // values are used for smooth results.
392: for (int i = 0; i < numberOfCrossFadeSamples; i++) {
393: double angle = (i * Math.PI)
394: / (2.0 * numberOfCrossFadeSamples);
395: fadeIn[i] = Math.cos(angle);
396: fadeOut[i] = Math.sin(angle);
397: }
398: // Indicate initialization is complete
399: initializationComplete = true;
400: }
401:
402: }
403:
404: // Negotiate the sample rate
405: public void minMaxSamplingRate(int min, int max, int preferred) {
406:
407: super .minMaxSamplingRate(min, max, preferred);
408: sampleRate = preferred;
409: doInitialization();
410:
411: }
412:
413: // Negotiate the number of channels
414: public void minMaxChannels(int min, int max, int preferred) {
415:
416: super.minMaxChannels(min, max, preferred);
417: numberOfChannels = preferred;
418:
419: }
420:
421: }
|