001: /*
002: * $RCSfile: FFTmediaLib.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:55:46 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.mlib;
013:
014: import java.awt.image.DataBuffer;
015: import java.text.NumberFormat;
016: import java.util.Arrays;
017: import java.util.Locale;
018: import javax.media.jai.operator.DFTDescriptor;
019: import com.sun.media.jai.opimage.FFT;
020: import com.sun.media.jai.util.MathJAI;
021:
022: import com.sun.medialib.mlib.*;
023:
024: /**
025: * The Fast Fourier Transform (FFT) class interface to mediaLib.
026: *
027: * @since EA4
028: */
029: public class FFTmediaLib extends FFT {
030: /* Flag to indicate the special case of unitary scaling with a
031: length equal to an odd power of 2. */
032: private boolean specialUnitaryScaling = false;
033:
034: /* The square root of 2. */
035: private static final double SQUARE_ROOT_OF_2 = Math.sqrt(2.0);
036:
037: /**
038: * Construct a new FFTmediaLib object.
039: *
040: * @param negatedExponent Whether the exponent is negated.
041: * @param scaleType The type of scaling to be applied.
042: * @param length The length of the FFT; must be a positive power of 2.
043: */
044: public FFTmediaLib(boolean negatedExponent, Integer scaleType,
045: int length) {
046: super (negatedExponent, scaleType, length);
047: }
048:
049: /**
050: * Initialize the length-dependent fields.
051: *
052: * @param length The length of the FFT; must be a positive power of 2.
053: */
054: public void setLength(int length) {
055: // Check whether it's necessary to continue.
056: if (lengthIsSet && length == this .length) {
057: return;
058: }
059:
060: // Ensure that the length is a positive power of two.
061: if (!MathJAI.isPositivePowerOf2(length)) {
062: throw new RuntimeException(JaiI18N
063: .getString("FFTmediaLib0"));
064: }
065:
066: // Cache the length.
067: this .length = length;
068:
069: // Allocate work buffer memory.
070: if (!lengthIsSet || length != real.length) {
071: real = new double[length];
072: imag = new double[length];
073: }
074:
075: // Set initialization flag.
076: lengthIsSet = true;
077:
078: // Set flag for special-case: unitary scaling and length = 2**N, N odd.
079: if (scaleType == SCALING_UNITARY) {
080: // The following calculation assumes that the length is a
081: // positive power of 2 which has been verified above.
082: int exponent = 0;
083: int powerOfTwo = 1;
084: while (powerOfTwo < length) {
085: powerOfTwo <<= 1;
086: exponent++;
087: }
088:
089: // Set the special case flag if the exponent is not even.
090: specialUnitaryScaling = exponent % 2 != 0;
091: }
092: }
093:
094: /**
095: * Get data from the internal work data arrays of the FFT object.
096: *
097: * @param dataType The data type of the source data according to
098: * one of the DataBuffer TYPE_* flags. This should be either
099: * DataBuffer.TYPE_FLOAT or DataBuffer.TYPE_DOUBLE.
100: * @param realArg Float or double array of real parts.
101: * @param offsetReal Offset into the array of real parts.
102: * @param strideReal The real array stride value.
103: * @param imagArg Float or double array of imaginary parts.
104: * @param offsetImag Offset into the array of imaginary parts.
105: * @param strideImag The imaginary array stride value.
106: * @param count The number of values to copy.
107: */
108: public void getData(int dataType, Object realArg, int offsetReal,
109: int strideReal, Object imagArg, int offsetImag,
110: int strideImag) {
111: switch (dataType) {
112: case DataBuffer.TYPE_FLOAT: {
113: float[] realFloat = (float[]) realArg;
114: if (imagArg != null) {
115: float[] imagFloat = (float[]) imagArg;
116: if (offsetReal == offsetImag
117: && strideReal == strideImag) {
118: for (int i = 0; i < length; i++) {
119: // XXX Should clampFloat() be invoked both
120: // in the next two lines and below?
121: realFloat[offsetReal] = (float) this .real[i];
122: imagFloat[offsetReal] = (float) this .imag[i];
123: offsetReal += strideReal;
124: }
125: } else {
126: for (int i = 0; i < length; i++) {
127: realFloat[offsetReal] = (float) this .real[i];
128: imagFloat[offsetImag] = (float) this .imag[i];
129: offsetReal += strideReal;
130: offsetImag += strideImag;
131: }
132: }
133: } else { // imagArg == null
134: for (int i = 0; i < length; i++) {
135: realFloat[offsetReal] = (float) this .real[i];
136: offsetReal += strideReal;
137: }
138: }
139: }
140: break;
141: case DataBuffer.TYPE_DOUBLE: {
142: double[] realDouble = (double[]) realArg;
143: if (imagArg != null) {
144: double[] imagDouble = (double[]) imagArg;
145: if (offsetReal == offsetImag
146: && strideReal == strideImag) {
147: for (int i = 0; i < length; i++) {
148: realDouble[offsetReal] = this .real[i];
149: imagDouble[offsetReal] = this .imag[i];
150: offsetReal += strideReal;
151: }
152: } else {
153: for (int i = 0; i < length; i++) {
154: realDouble[offsetReal] = this .real[i];
155: imagDouble[offsetImag] = this .imag[i];
156: offsetReal += strideReal;
157: offsetImag += strideImag;
158: }
159: }
160: } else { // imagArg == null
161: for (int i = 0; i < length; i++) {
162: realDouble[offsetReal] = this .real[i];
163: offsetReal += strideReal;
164: }
165: }
166: }
167: break;
168: default:
169: // NB: This statement should be unreachable as the destination
170: // image is required to be a floating point type and the
171: // RasterAccessor is supposed to promote the data type of
172: // all rasters to the "minimum" data type of all source
173: // and destination rasters involved.
174: throw new RuntimeException(dataType
175: + JaiI18N.getString("FFTmediaLib1"));
176: }
177: }
178:
179: /**
180: * Calculate the DFT of a complex sequence using the FFT algorithm.
181: */
182: public void transform() {
183: if (exponentSign < 0) {
184: if (scaleType == SCALING_NONE) {
185: Image.FFT_1(real, imag);
186: } else if (scaleType == SCALING_UNITARY) {
187: Image.FFT_3(real, imag);
188:
189: if (specialUnitaryScaling) {
190: // Divide by Math.sqrt(2.0) to account for the difference
191: // between the definition of mediaLib Group-III forward
192: // transform scaling when the length is an odd power of 2
193: // and that expected for unitary scaling.
194: for (int i = 0; i < length; i++) {
195: real[i] *= SQUARE_ROOT_OF_2;
196: imag[i] *= SQUARE_ROOT_OF_2;
197: }
198: }
199: } else if (scaleType == SCALING_DIMENSIONS) {
200: Image.FFT_2(real, imag);
201: }
202: } else {
203: if (scaleType == SCALING_NONE) {
204: Image.IFFT_2(real, imag);
205: } else if (scaleType == SCALING_UNITARY) {
206: Image.IFFT_3(real, imag);
207:
208: if (specialUnitaryScaling) {
209: // Multiply by Math.sqrt(2.0) to account for the difference
210: // between the definition of mediaLib Group-III forward
211: // transform scaling when the length is an odd power of 2
212: // and that expected for unitary scaling.
213: for (int i = 0; i < length; i++) {
214: real[i] /= SQUARE_ROOT_OF_2;
215: imag[i] /= SQUARE_ROOT_OF_2;
216: }
217: }
218: } else if (scaleType == SCALING_DIMENSIONS) {
219: Image.IFFT_1(real, imag);
220: }
221: }
222: }
223: }
|