001: /*
002: * $RCSfile: Sample.java,v $
003: *
004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * - Redistribution of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * - Redistribution in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * Neither the name of Sun Microsystems, Inc. or the names of
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * This software is provided "AS IS," without a warranty of any
023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
034: * POSSIBILITY OF SUCH DAMAGES.
035: *
036: * You acknowledge that this software is not designed, licensed or
037: * intended for use in the design, construction, operation or
038: * maintenance of any nuclear facility.
039: *
040: * $Revision: 1.4 $
041: * $Date: 2007/02/09 17:20:02 $
042: * $State: Exp $
043: */
044:
045: package com.sun.j3d.audioengines;
046:
047: import javax.media.j3d.*;
048: import javax.vecmath.*;
049:
050: /**
051: * The Sample class defines the data and methods associated with a sound
052: * sample played through the AudioDevice.
053: * This contains all the data fields for non-spatialized and spatialized
054: * (positional and directional) sound samples.
055: */
056: public class Sample {
057:
058: // Debug print flags and methods
059: static final protected boolean debugFlag = false;
060: static final protected boolean internalErrors = false;
061:
062: protected void debugPrint(String message) {
063: if (debugFlag)
064: System.out.println(message);
065: }
066:
067: protected void debugPrintln(String message) {
068: if (debugFlag)
069: System.out.println(message);
070: }
071:
072: /**
073: * Null Sound identifier denotes sound is not created or initialized
074: */
075: public static final int NULL_SAMPLE = -1;
076:
077: /**
078: * sound data associated with sound source
079: */
080: protected MediaContainer soundData = null;
081:
082: /**
083: * sound data associated with sound source
084: */
085: protected int soundType = -1;
086:
087: /**
088: * Overall Scale Factor applied to sound gain.
089: */
090: protected float gain = 1.0f; // Valid values are >= 0.0.
091:
092: /**
093: * Overall Scale Factor applied to sound.
094: * @since Java 3D 1.3
095: */
096: protected float rateScaleFactor = 1.0f; // Valid values are >= 0.0.
097:
098: /**
099: * Number of times sound is looped/repeated during play
100: */
101: protected int loopCount = 0; // Range from 0 to POSITIVE_INFINITY(-1)
102:
103: /*
104: * Duration of sample
105: * This should match the Sound node constant of same name
106: */
107: public static final int DURATION_UNKNOWN = -1;
108: protected long duration = DURATION_UNKNOWN;
109:
110: protected int numberOfChannels = 0;
111: protected boolean mute = false; // denotes if sample is muted
112: // (playing with zero gain)
113:
114: /*
115: *
116: * Fields associated with positional sound samples
117: *
118: */
119: /*
120: * Local to Vworld transform
121: */
122: protected Transform3D vworldXfrm = new Transform3D();
123: protected boolean vwXfrmFlag = false;
124:
125: /*
126: * Origin of Sound source in Listener's space.
127: */
128: protected Point3f position = new Point3f(0.0f, 0.0f, 0.0f);
129:
130: /*
131: * Pairs of distances and gain scale factors that define piecewise linear
132: * gain attenuation between each pair.
133: */
134: protected double[] attenuationDistance = null;
135: protected float[] attenuationGain = null;;
136:
137: /**
138: * dirty flags denoting what has changed since last rendering
139: */
140: protected int dirtyFlags = 0xFFFF;
141:
142: /*
143: *
144: * Direction sample fields
145: *
146: */
147: /**
148: * The Cone Sound's direction vector. This is the cone axis.
149: */
150: protected Vector3f direction = new Vector3f(0.0f, 0.0f, 1.0f);
151:
152: /**
153: * Pairs of distances and gain scale factors that define piecewise linear
154: * gain BACK attenuation between each pair.
155: * These are used for defining elliptical attenuation regions.
156: */
157: protected double[] backAttenuationDistance = null;
158: protected float[] backAttenuationGain = null;
159:
160: /**
161: * Directional Sound's gain can be attenuated based on the listener's
162: * location off-angle from the source source direction.
163: * This can be set by three parameters:
164: * angular distance in radians
165: * gain scale factor
166: * filtering (currently the only filtering supported is lowpass)
167: */
168: protected double[] angularDistance = { 0.0, (Math.PI * 0.5) };
169: protected float[] angularGain = { 1.0f, 0.0f };
170:
171: /**
172: * Distance Filter
173: * Each sound source is attenuated by a filter based on it's distance
174: * from the listener.
175: * For now the only supported filterType will be LOW_PASS frequency
176: * cutoff.
177: * At some time full FIR filtering will be supported.
178: */
179: public static final int NO_FILTERING = -1;
180: public static final int LOW_PASS = 1;
181:
182: protected int angularFilterType = NO_FILTERING;
183: protected float[] angularFilterCutoff = { Sound.NO_FILTER,
184: Sound.NO_FILTER };
185:
186: /*
187: * Obstruction and Occlusion parameters
188: * For now the only type of filtering supported is a low-pass filter
189: * defined by a frequency cutoff value.
190: * @since Java 3D 1.3
191: */
192: protected float obstructionGain = 1.0f; // scale factor
193: protected int obstructionFilterType = NO_FILTERING;
194: protected float obstructionFilterCutoff = Sound.NO_FILTER;
195: protected float occlusionGain = 1.0f; // scale factor
196: protected int occlusionFilterType = NO_FILTERING;
197: protected float occlusionFilterCutoff = Sound.NO_FILTER;
198:
199: /*
200: * Construct a new audio device Sample object
201: */
202: public Sample() {
203: if (debugFlag)
204: debugPrintln("Sample constructor");
205: }
206:
207: public long getDuration() {
208: return 0;
209: }
210:
211: public long getStartTime() {
212: return 0;
213: }
214:
215: public int getNumberOfChannelsUsed() {
216: return 0;
217: }
218:
219: public void setDirtyFlags(int flags) {
220: dirtyFlags = flags;
221: }
222:
223: public int getDirtyFlags() {
224: return dirtyFlags;
225: }
226:
227: public void setSoundType(int type) {
228: soundType = type;
229: }
230:
231: public int getSoundType() {
232: return soundType;
233: }
234:
235: public void setSoundData(MediaContainer ref) {
236: soundData = ref;
237: }
238:
239: public MediaContainer getSoundData() {
240: return soundData;
241: }
242:
243: public void setMuteFlag(boolean flag) {
244: mute = flag;
245: }
246:
247: public boolean getMuteFlag() {
248: return mute;
249: }
250:
251: public void setVWrldXfrmFlag(boolean flag) {
252: // this flag is ONLY true if the VirtualWorld Transform is ever set
253: vwXfrmFlag = flag;
254: }
255:
256: public boolean getVWrldXfrmFlag() {
257: return vwXfrmFlag;
258: }
259:
260: public void setGain(float scaleFactor) {
261: gain = scaleFactor;
262: }
263:
264: public float getGain() {
265: return gain;
266: }
267:
268: public void setLoopCount(int count) {
269: loopCount = count;
270: }
271:
272: public int getLoopCount() {
273: return loopCount;
274: }
275:
276: public void setPosition(Point3d position) {
277: this .position.set(position);
278: return;
279: }
280:
281: // TODO: no get method for Position
282:
283: public void setDistanceGain(double[] frontDistance,
284: float[] frontAttenuationScaleFactor, double[] backDistance,
285: float[] backAttenuationScaleFactor) {
286: if (frontDistance != null) {
287: int size = frontDistance.length;
288: attenuationDistance = new double[size];
289: attenuationGain = new float[size];
290: for (int i = 0; i < size; i++) {
291: attenuationDistance[i] = frontDistance[i];
292: attenuationGain[i] = frontAttenuationScaleFactor[i];
293: }
294: } else {
295: attenuationDistance = null;
296: attenuationGain = null;
297: }
298: if (backDistance != null && frontDistance != null) {
299: int size = backDistance.length;
300: backAttenuationDistance = new double[size];
301: backAttenuationGain = new float[size];
302: for (int i = 0; i < size; i++) {
303: backAttenuationDistance[i] = backDistance[i];
304: backAttenuationGain[i] = backAttenuationScaleFactor[i];
305: }
306: } else {
307: backAttenuationDistance = null;
308: backAttenuationGain = null;
309: }
310: return;
311: }
312:
313: // TODO: no get method for Back Attenuation
314:
315: public void setDirection(Vector3d direction) {
316: this .direction.set(direction);
317: return;
318: }
319:
320: // TODO: no get method for Direction
321:
322: public void setAngularAttenuation(int filterType, double[] angle,
323: float[] attenuationScaleFactor, float[] filterCutoff) {
324: if (angle != null) {
325: int size = angle.length;
326: angularDistance = new double[size];
327: angularGain = new float[size];
328: if (filterType != NO_FILTERING && filterCutoff != null)
329: angularFilterCutoff = new float[size];
330: else
331: angularFilterCutoff = null;
332: for (int i = 0; i < size; i++) {
333: angularDistance[i] = angle[i];
334: angularGain[i] = attenuationScaleFactor[i];
335: if (filterType != NO_FILTERING)
336: angularFilterCutoff[i] = filterCutoff[i];
337: }
338: angularFilterType = filterType;
339: } else {
340: angularDistance = null;
341: angularGain = null;
342: angularFilterCutoff = null;
343: angularFilterType = NO_FILTERING;
344: }
345: }
346:
347: // TODO: no get method for Angular Attenuation
348:
349: /*
350: * Set Rate ScaleFactor
351: * @since Java 3D 1.3
352: */
353: public void setRateScaleFactor(float scaleFactor) {
354: rateScaleFactor = scaleFactor;
355: }
356:
357: /*
358: * Get Rate ScaleFactor
359: * @since Java 3D 1.3
360: */
361: public float getRateScaleFactor() {
362: return rateScaleFactor;
363: }
364:
365: /*
366: * Set Obstruction Gain
367: * @since Java 3D 1.3
368: */
369: public void setObstructionGain(float scaleFactor) {
370: obstructionGain = scaleFactor;
371: }
372:
373: /*
374: * Get Obstruction Gain
375: * @since Java 3D 1.3
376: */
377: public float getObstructionGain() {
378: return obstructionGain;
379: }
380:
381: /*
382: * Set Obstruction Filter Cutoff Frequency
383: * @since Java 3D 1.3
384: */
385: public void setObstructionFilter(float cutoffFrequency) {
386: obstructionFilterType = LOW_PASS;
387: obstructionFilterCutoff = cutoffFrequency;
388: }
389:
390: // TODO: no get method for Obstruction Filtering
391:
392: /*
393: * Set Occlusion Gain
394: * @since Java 3D 1.3
395: */
396: public void setOcclusionGain(float scaleFactor) {
397: occlusionGain = scaleFactor;
398: }
399:
400: /*
401: * Get Occlusion Gain
402: * @since Java 3D 1.3
403: */
404: public float getOcclusionGain() {
405: return occlusionGain;
406: }
407:
408: /*
409: * Set Occlusion Filter Cutoff Frequency
410: * @since Java 3D 1.3
411: */
412: public void setOcclusionFilter(float cutoffFrequency) {
413: occlusionFilterType = LOW_PASS;
414: occlusionFilterCutoff = cutoffFrequency;
415: }
416:
417: // TODO: no get method for Occlusion Filtering
418:
419: /**
420: * Clears/re-initialize fields associated with sample data
421: * for this sound,
422: * and frees any device specific data associated with this sample.
423: */
424: public void clear() {
425: if (debugFlag)
426: debugPrintln("Sample.clear() entered");
427: soundData = (MediaContainer) null;
428: soundType = NULL_SAMPLE;
429: gain = 1.0f;
430: loopCount = 0;
431: duration = DURATION_UNKNOWN;
432: numberOfChannels = 0;
433: vworldXfrm.setIdentity();
434: vwXfrmFlag = false;
435: position.set(0.0f, 0.0f, 0.0f);
436: attenuationDistance = null;
437: attenuationGain = null;
438: direction.set(0.0f, 0.0f, 1.0f);
439: backAttenuationDistance = null;
440: backAttenuationGain = null;
441: if (angularDistance != null) {
442: angularDistance[0] = 0.0f;
443: angularDistance[1] = (float) (Math.PI) * 0.5f;
444: }
445: if (angularGain != null) {
446: angularGain[0] = 1.0f;
447: angularGain[1] = 0.0f;
448: }
449: angularFilterType = NO_FILTERING;
450: if (angularFilterCutoff != null) {
451: angularFilterCutoff[0] = Sound.NO_FILTER;
452: angularFilterCutoff[1] = Sound.NO_FILTER;
453: }
454: obstructionGain = 1.0f;
455: obstructionFilterType = NO_FILTERING;
456: obstructionFilterCutoff = Sound.NO_FILTER;
457: occlusionGain = 1.0f;
458: occlusionFilterType = NO_FILTERING;
459: occlusionFilterCutoff = Sound.NO_FILTER;
460: }
461:
462: /*
463: * Render
464: */
465: public void render(int dirtyFlags, View view,
466: AuralParameters attribs) {
467: // meant to be overridden
468: }
469: }
|