001: /*
002: * $RCSfile: JOALSample.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.6 $
041: * $Date: 2007/06/19 05:53:08 $
042: * $State: Exp $
043: */
044:
045: package org.jdesktop.j3d.audioengines.joal;
046:
047: import com.sun.j3d.audioengines.AuralParameters;
048: import com.sun.j3d.audioengines.Sample;
049: import java.io.IOException;
050: import java.io.InputStream;
051: import java.net.MalformedURLException;
052: import java.net.URL;
053: import java.nio.ByteBuffer;
054: import javax.media.j3d.AudioDevice3D;
055: import javax.media.j3d.MediaContainer;
056: import javax.media.j3d.Sound;
057: import javax.media.j3d.Transform3D;
058: import javax.media.j3d.View;
059: import javax.vecmath.Point3d;
060: import javax.vecmath.Point3f;
061: import javax.vecmath.Vector3d;
062: import javax.vecmath.Vector3f;
063: import net.java.games.joal.AL;
064: import net.java.games.joal.util.ALut;
065:
066: /** This is the JOAL Sample object which encapsulates all the functionality
067: * and holds all the data associated with a Sample.
068: *
069: * @author David Grace (dave@dutchie.net)
070: */
071: public class JOALSample extends Sample {
072:
073: private static boolean debug = true;
074: private static boolean debugPosition = false;
075: private static boolean debugDirection = false;
076: private static boolean debugDistanceGain = false;
077: private static boolean debugGain = false;
078: private static boolean debugLoopCount = false;
079: private static boolean debugMute = false;
080: private static boolean debugLoad = true;
081: private static boolean debugDuration = false;
082: private static boolean debugClear = true;
083:
084: private int index;
085:
086: private int[] buffer;
087: private int[] source;
088:
089: private AL al;
090:
091: private static double pi = Math.PI;
092:
093: private int sampleSize;
094: private int sampleBits;
095: private int sampleFrequency;
096: private int sampleChannels = 1;
097:
098: /** Creates a new instance of JOALSample */
099: public JOALSample() {
100: }
101:
102: /**
103: * Null Sound identifier denotes sound is not created or initialized
104: */
105: public static final int NULL_SAMPLE = -1;
106:
107: /**
108: * sound data associated with sound source
109: */
110: protected MediaContainer soundData = null;
111:
112: /**
113: * sound data associated with sound source
114: */
115: protected int soundType = -1;
116:
117: /**
118: * Overall Scale Factor applied to sound gain.
119: */
120: protected float gain = 1.0f; // Valid values are >= 0.0.
121:
122: /**
123: * Overall Scale Factor applied to sound.
124: * @since Java 3D 1.3
125: */
126: protected float rateScaleFactor = 1.0f; // Valid values are >= 0.0.
127:
128: /**
129: * Number of times sound is looped/repeated during play
130: */
131: protected int loopCount = 0; // Range from 0 to POSITIVE_INFINITY(-1)
132:
133: /*
134: * Duration of sample
135: * This should match the Sound node constant of same name
136: */
137: public static final int DURATION_UNKNOWN = -1;
138: protected long duration = DURATION_UNKNOWN;
139:
140: protected int numberOfChannels = 0;
141: protected boolean mute = false; // denotes if sample is muted
142: // (playing with zero gain)
143:
144: /*
145: *
146: * Fields associated with positional sound samples
147: *
148: */
149: /*
150: * Local to Vworld transform
151: */
152: protected Transform3D vworldXfrm = new Transform3D();
153: protected boolean vwXfrmFlag = false;
154:
155: /*
156: * Origin of Sound source in Listener's space.
157: */
158: protected Point3f position = new Point3f(0.0f, 0.0f, 0.0f);
159: protected float[] positionArray = new float[] { 0, 0, 0 };
160: /*
161: * Pairs of distances and gain scale factors that define piecewise linear
162: * gain attenuation between each pair.
163: */
164: protected double[] attenuationDistance = null;
165: protected float[] attenuationGain = null;;
166:
167: /**
168: * dirty flags denoting what has changed since last rendering
169: */
170: protected int dirtyFlags = 0xFFFF;
171:
172: /*
173: *
174: * Direction sample fields
175: *
176: */
177: /**
178: * The Cone Sound's direction vector. This is the cone axis.
179: */
180: protected Vector3f direction = new Vector3f(0.0f, 0.0f, 1.0f);
181: protected float[] directionArray = new float[] { 0, 0, 0 };
182: /**
183: * Pairs of distances and gain scale factors that define piecewise linear
184: * gain BACK attenuation between each pair.
185: * These are used for defining elliptical attenuation regions.
186: */
187: protected double[] backAttenuationDistance = null;
188: protected float[] backAttenuationGain = null;
189:
190: /**
191: * Directional Sound's gain can be attenuated based on the listener's
192: * location off-angle from the source source direction.
193: * This can be set by three parameters:
194: * angular distance in radians
195: * gain scale factor
196: * filtering (currently the only filtering supported is lowpass)
197: */
198: protected double[] angularDistance = { 0.0, (Math.PI * 0.5) };
199: protected float[] angularGain = { 1.0f, 0.0f };
200:
201: /**
202: * Distance Filter
203: * Each sound source is attenuated by a filter based on it's distance
204: * from the listener.
205: * For now the only supported filterType will be LOW_PASS frequency
206: * cutoff.
207: * At some time full FIR filtering will be supported.
208: */
209: public static final int NO_FILTERING = -1;
210: public static final int LOW_PASS = 1;
211:
212: protected int angularFilterType = NO_FILTERING;
213: protected float[] angularFilterCutoff = { Sound.NO_FILTER,
214: Sound.NO_FILTER };
215:
216: /*
217: * Obstruction and Occlusion parameters
218: * For now the only type of filtering supported is a low-pass filter
219: * defined by a frequency cutoff value.
220: * @since Java 3D 1.3
221: */
222: protected float obstructionGain = 1.0f; // scale factor
223: protected int obstructionFilterType = NO_FILTERING;
224: protected float obstructionFilterCutoff = Sound.NO_FILTER;
225: protected float occlusionGain = 1.0f; // scale factor
226: protected int occlusionFilterType = NO_FILTERING;
227: protected float occlusionFilterCutoff = Sound.NO_FILTER;
228:
229: public long getDuration() {
230: long duration = (long) ((double) sampleSize / sampleFrequency * 1000);
231: if (debug && debugDuration)
232: System.out.println("JOALSample - getDuration of " + index
233: + " is " + duration);
234: return duration;
235: }
236:
237: public long getStartTime() {
238: return 0;
239: }
240:
241: public int getNumberOfChannelsUsed() {
242: int[] i = new int[1];
243: al.alGetBufferiv(index, AL.AL_CHANNELS, i, 0);
244: sampleChannels = i[0];
245: //System.out.println("JOALSample - getNumberOfChannelsUsed of " + index + " is " + sampleChannels);
246: return sampleChannels;
247: }
248:
249: public void setDirtyFlags(int flags) {
250: dirtyFlags = flags;
251: }
252:
253: public int getDirtyFlags() {
254: return dirtyFlags;
255: }
256:
257: public void setSoundType(int type) {
258: soundType = type;
259: }
260:
261: public int getSoundType() {
262: return soundType;
263: }
264:
265: public void setSoundData(MediaContainer ref) {
266: soundData = ref;
267: }
268:
269: public MediaContainer getSoundData() {
270: return soundData;
271: }
272:
273: public void setMuteFlag(boolean flag) {
274: if (debug & debugMute)
275: System.out.println("JOALSample - setMuteFlag " + flag);
276: mute = flag;
277: if (mute) {
278: al.alSourcef(index, AL.AL_GAIN, 0);
279: } else {
280: al.alSourcef(index, AL.AL_GAIN, gain);
281: }
282: }
283:
284: public boolean getMuteFlag() {
285: return mute;
286: }
287:
288: public void setVWrldXfrmFlag(boolean flag) {
289: // this flag is ONLY true if the VirtualWorld Transform is ever set
290: vwXfrmFlag = flag;
291: }
292:
293: public boolean getVWrldXfrmFlag() {
294: return vwXfrmFlag;
295: }
296:
297: public void setGain(float scaleFactor) {
298: if (debug & debugGain)
299: System.out.println("JOALSample - setGain " + scaleFactor);
300: gain = scaleFactor;
301: al.alSourcef(index, AL.AL_GAIN, scaleFactor);
302: }
303:
304: public float getGain() {
305: return gain;
306: }
307:
308: public void setLoopCount(int count) {
309: if (debug & debugLoopCount)
310: System.out.println("JOALSample - setLoopCount " + count);
311: loopCount = count;
312: if (count == 0)
313: al.alSourcei(index, AL.AL_LOOPING, AL.AL_FALSE);
314: else if (count > 0)
315: al.alSourcei(index, AL.AL_LOOPING, AL.AL_TRUE);
316: else
317: al.alSourcei(index, AL.AL_LOOPING, AL.AL_TRUE);
318: }
319:
320: public int getLoopCount() {
321: return loopCount;
322: }
323:
324: public void setPosition(Point3d position) {
325: if (debug & debugPosition)
326: System.out.println("JOALSample - setPosition " + position);
327: this .position.set(position);
328: //this.position = position;
329: positionArray[0] = (float) position.x;
330: positionArray[1] = (float) position.y;
331: positionArray[2] = (float) position.z;
332: al.alSourcefv(index, AL.AL_POSITION, positionArray, 0);
333: return;
334: }
335:
336: // TODO: no get method for Position
337:
338: public void setDistanceGain(double[] frontDistance,
339: float[] frontAttenuationScaleFactor, double[] backDistance,
340: float[] backAttenuationScaleFactor) {
341: if (debug & debugDistanceGain)
342: System.out.println("JOALSample - setDistanceGain "
343: + frontDistance + ", "
344: + frontAttenuationScaleFactor);
345:
346: if (frontDistance == null) {
347: //al.alSourcef(index, AL.AL_ROLLOFF_FACTOR, 0);
348: } else if (frontDistance.length == 1) {
349: double d = frontDistance[0];
350: float f = frontAttenuationScaleFactor[0];
351: al.alSourcefv(index, AL.AL_REFERENCE_DISTANCE,
352: new float[] { (float) d }, 0);
353: al.alSourcef(index, AL.AL_ROLLOFF_FACTOR, 1);
354: } else if (frontDistance.length > 1) {
355: double d = frontDistance[0];
356: double dmax = frontDistance[frontDistance.length - 1];
357: float f = frontAttenuationScaleFactor[0];
358: float fmax = frontAttenuationScaleFactor[frontAttenuationScaleFactor.length - 1];
359: //al.alSourcefv(index, AL.AL_REFERENCE_DISTANCE, new float[]{(float) (dmax / 2)}, 0);
360: al.alSourcefv(index, AL.AL_MAX_DISTANCE,
361: new float[] { (float) (dmax) }, 0);
362: al.alSourcef(index, AL.AL_ROLLOFF_FACTOR, 1);
363: }
364:
365: if (frontDistance != null) {
366: int size = frontDistance.length;
367: attenuationDistance = new double[size];
368: attenuationGain = new float[size];
369: for (int i = 0; i < size; i++) {
370: attenuationDistance[i] = frontDistance[i];
371: attenuationGain[i] = frontAttenuationScaleFactor[i];
372: }
373: } else {
374: attenuationDistance = null;
375: attenuationGain = null;
376: }
377: if (backDistance != null && frontDistance != null) {
378: int size = backDistance.length;
379: backAttenuationDistance = new double[size];
380: backAttenuationGain = new float[size];
381: for (int i = 0; i < size; i++) {
382: backAttenuationDistance[i] = backDistance[i];
383: backAttenuationGain[i] = backAttenuationScaleFactor[i];
384: }
385: } else {
386: backAttenuationDistance = null;
387: backAttenuationGain = null;
388: }
389: return;
390: }
391:
392: // TODO: no get method for Back Attenuation
393:
394: public void setDirection(Vector3d direction) {
395: if (debug && debugDirection)
396: System.out
397: .println("JOALSample - setDirection " + direction);
398: this .direction.set(direction);
399: directionArray[0] = (float) direction.x;
400: directionArray[1] = (float) direction.y;
401: directionArray[2] = (float) direction.z;
402: al.alSourcefv(index, AL.AL_DIRECTION, directionArray, 0);
403: return;
404: }
405:
406: // TODO: no get method for Direction
407:
408: public void setAngularAttenuation(int filterType, double[] angle,
409: float[] attenuationScaleFactor, float[] filterCutoff) {
410: if (angle != null) {
411: if (angle.length == 1) {
412: float f = radiansToDegrees(angle[0]);
413: //al.alSourcef(index, AL.AL_CONE_OUTER_ANGLE, (float) angle[0]);
414: //al.alSourcef(index, AL.AL_CONE_OUTER_ANGLE, 30);
415: //al.alSourcef(index, AL.AL_CONE_INNER_ANGLE, 45);
416: al.alSourcef(index, AL.AL_CONE_INNER_ANGLE, f / 2);
417: al.alSourcef(index, AL.AL_CONE_OUTER_ANGLE, f);
418:
419: } else if (angle.length == 2) {
420: float f1 = radiansToDegrees(angle[0]);
421: float f2 = radiansToDegrees(angle[1]);
422: al.alSourcef(index, AL.AL_CONE_INNER_ANGLE, f1);
423: al.alSourcef(index, AL.AL_CONE_OUTER_ANGLE, f2);
424: } else {
425: float f1 = radiansToDegrees(angle[0]);
426: float f2 = radiansToDegrees(angle[angle.length - 1]);
427: al.alSourcef(index, AL.AL_CONE_INNER_ANGLE, f1);
428: al.alSourcef(index, AL.AL_CONE_OUTER_ANGLE, f2);
429: }
430: }
431:
432: if (angle != null) {
433: int size = angle.length;
434: angularDistance = new double[size];
435: angularGain = new float[size];
436: if (filterType != NO_FILTERING && filterCutoff != null)
437: angularFilterCutoff = new float[size];
438: else
439: angularFilterCutoff = null;
440: for (int i = 0; i < size; i++) {
441: angularDistance[i] = angle[i];
442: angularGain[i] = attenuationScaleFactor[i];
443: if (filterType != NO_FILTERING)
444: angularFilterCutoff[i] = filterCutoff[i];
445: }
446: angularFilterType = filterType;
447: } else {
448: angularDistance = null;
449: angularGain = null;
450: angularFilterCutoff = null;
451: angularFilterType = NO_FILTERING;
452: }
453: }
454:
455: // TODO: no get method for Angular Attenuation
456:
457: /*
458: * Set Rate ScaleFactor
459: * @since Java 3D 1.3
460: */
461: public void setRateScaleFactor(float scaleFactor) {
462: rateScaleFactor = scaleFactor;
463: al.alSourcef(index, AL.AL_PITCH, scaleFactor);
464: }
465:
466: /*
467: * Get Rate ScaleFactor
468: * @since Java 3D 1.3
469: */
470: public float getRateScaleFactor() {
471: return rateScaleFactor;
472: }
473:
474: /*
475: * Set Obstruction Gain
476: * @since Java 3D 1.3
477: */
478: public void setObstructionGain(float scaleFactor) {
479: obstructionGain = scaleFactor;
480: }
481:
482: /*
483: * Get Obstruction Gain
484: * @since Java 3D 1.3
485: */
486: public float getObstructionGain() {
487: return obstructionGain;
488: }
489:
490: /*
491: * Set Obstruction Filter Cutoff Frequency
492: * @since Java 3D 1.3
493: */
494: public void setObstructionFilter(float cutoffFrequency) {
495: obstructionFilterType = LOW_PASS;
496: obstructionFilterCutoff = cutoffFrequency;
497: }
498:
499: // TODO: no get method for Obstruction Filtering
500:
501: /*
502: * Set Occlusion Gain
503: * @since Java 3D 1.3
504: */
505: public void setOcclusionGain(float scaleFactor) {
506: occlusionGain = scaleFactor;
507: }
508:
509: /*
510: * Get Occlusion Gain
511: * @since Java 3D 1.3
512: */
513: public float getOcclusionGain() {
514: return occlusionGain;
515: }
516:
517: /*
518: * Set Occlusion Filter Cutoff Frequency
519: * @since Java 3D 1.3
520: */
521: public void setOcclusionFilter(float cutoffFrequency) {
522: occlusionFilterType = LOW_PASS;
523: occlusionFilterCutoff = cutoffFrequency;
524: }
525:
526: // TODO: no get method for Occlusion Filtering
527:
528: /**
529: * Clears/re-initialize fields associated with sample data
530: * for this sound,
531: * and frees any device specific data associated with this sample.
532: */
533: public void clear() {
534: if (debug && debugClear)
535: System.out.println("JOALSample - clear");
536: //Added to clear function to clear resources held by JOAL/OpenAL
537: //clearOpenALBuffer();
538: soundData = (MediaContainer) null;
539: soundType = NULL_SAMPLE;
540: gain = 1.0f;
541: loopCount = 0;
542: duration = DURATION_UNKNOWN;
543: numberOfChannels = 0;
544: vworldXfrm.setIdentity();
545: vwXfrmFlag = false;
546: position.set(0, 0, 0);
547: positionArray[0] = 0;
548: positionArray[1] = 0;
549: positionArray[2] = 0;
550: attenuationDistance = null;
551: attenuationGain = null;
552: direction.set(0.0f, 0.0f, 1.0f);
553: directionArray[0] = 0;
554: directionArray[1] = 0;
555: directionArray[2] = 0;
556: backAttenuationDistance = null;
557: backAttenuationGain = null;
558: if (angularDistance != null) {
559: angularDistance[0] = 0.0f;
560: angularDistance[1] = (float) (Math.PI) * 0.5f;
561: }
562: if (angularGain != null) {
563: angularGain[0] = 1.0f;
564: angularGain[1] = 0.0f;
565: }
566: angularFilterType = NO_FILTERING;
567: if (angularFilterCutoff != null) {
568: angularFilterCutoff[0] = Sound.NO_FILTER;
569: angularFilterCutoff[1] = Sound.NO_FILTER;
570: }
571: obstructionGain = 1.0f;
572: obstructionFilterType = NO_FILTERING;
573: obstructionFilterCutoff = Sound.NO_FILTER;
574: occlusionGain = 1.0f;
575: occlusionFilterType = NO_FILTERING;
576: occlusionFilterCutoff = Sound.NO_FILTER;
577: }
578:
579: /*
580: * Render
581: */
582: public void render(int dirtyFlags, View view,
583: AuralParameters attribs) {
584: // meant to be overridden
585: }
586:
587: /**
588: * Load the sound ready to by played.
589: *
590: * @return error true if error occurred
591: */
592: public boolean load(AL al, MediaContainer soundData, int soundType) {
593: if (debug && debugLoad) {
594: if (soundData.getURLObject() != null)
595: System.out.print("JOALSample - load "
596: + soundData.getURLObject() + "...");
597: else
598: System.out.print("JOALSample - load " + soundData
599: + "...");
600: }
601: this .al = al;
602: this .soundType = soundType;
603:
604: InputStream is = soundData.getInputStream();
605: if (is == null) {
606: URL url = soundData.getURLObject();
607: // Issue 481: JOALSample: cannot load if only URLString is given in MediaContainer
608: if (null == url) {
609: try {
610: url = new URL(soundData.getURLString());
611: } catch (MalformedURLException ex) {
612: ex.printStackTrace();
613: return true;
614: }
615: }
616: try {
617: is = url.openStream();
618: } catch (IOException ex) {
619: ex.printStackTrace();
620: return true;
621: }
622: }
623: //if (debug && debugLoad) System.out.println("JOALSample - load - is: " + is);
624: buffer = new int[1];
625:
626: // Sources are points emitting sound.
627: source = new int[1];
628:
629: int[] format = new int[1];
630: int[] size = new int[1];
631: ByteBuffer[] data = new ByteBuffer[1];
632: int[] freq = new int[1];
633: int[] loop = new int[1];
634:
635: // load wav data into buffers
636: al.alGenBuffers(1, buffer, 0);
637: int errorCode = al.alGetError();
638:
639: //Note: This function should really return true when an error is generated by JOAL
640: // but an error code of 40961 is given with some samples that are still played
641: // by JOAL (bug 490). Thus the checking of this error is disabled as a fix to
642: // this bug.
643:
644: if (errorCode != AL.AL_NO_ERROR) {
645: System.out
646: .print(" error generating buffer - JOAL error code: "
647: + errorCode + " - ");
648: //return true;
649: }
650:
651: ALut.alutLoadWAVFile(is, format, data, size, freq, loop);
652: al
653: .alBufferData(buffer[0], format[0], data[0], size[0],
654: freq[0]);
655:
656: // bind buffers into audio sources
657: al.alGenSources(1, source, 0);
658: sampleSize = size[0];
659: sampleFrequency = freq[0];
660: sampleBits = format[0];
661:
662: if (soundType == AudioDevice3D.BACKGROUND_SOUND) {
663: if (debug && debugLoad)
664: System.out.print(" BackgroundSound...");
665: al.alSourcei(source[0], AL.AL_BUFFER, buffer[0]);
666: al.alSourcef(source[0], AL.AL_PITCH, 1.0f);
667: al.alSourcef(source[0], AL.AL_GAIN, 1.0f);
668: //al.alSourcefv(source[0], AL.AL_POSITION, position, 0);
669: //al.alSourcefv(source[0], AL.AL_POSITION, sourceVel, 0);
670: al.alSourcei(source[0], AL.AL_LOOPING, AL.AL_TRUE);
671: al.alSourcei(source[0], AL.AL_ROLLOFF_FACTOR, 0);
672: al.alSourcei(source[0], AL.AL_SOURCE_RELATIVE, AL.AL_TRUE);
673: if (debug && debugLoad)
674: System.out.println(" success, sourceID: " + source[0]);
675: } else if (soundType == AudioDevice3D.POINT_SOUND) {
676: if (debug && debugLoad)
677: System.out.print(" PointSound...");
678: al.alGenSources(1, source, 0);
679:
680: al.alSourcei(source[0], AL.AL_BUFFER, buffer[0]);
681: al.alSourcef(source[0], AL.AL_PITCH, 1.0f);
682: al.alSourcef(source[0], AL.AL_GAIN, 1.0f);
683: //al.alSourcefv(source[0], AL.AL_POSITION, position, 0);
684: //al.alSourcefv(source[0], AL.AL_POSITION, sourceVel, 0);
685: al.alSourcei(source[0], AL.AL_LOOPING, AL.AL_TRUE);
686: if (debug && debugLoad)
687: System.out.println(" success, sourceID: " + source[0]);
688: } else if (soundType == AudioDevice3D.CONE_SOUND) {
689: if (debug && debugLoad)
690: System.out.print(" ConeSound...");
691: al.alGenSources(1, source, 0);
692:
693: al.alSourcei(source[0], AL.AL_BUFFER, buffer[0]);
694: al.alSourcef(source[0], AL.AL_PITCH, 1.0f);
695: al.alSourcef(source[0], AL.AL_GAIN, 1.0f);
696: //al.alSourcefv(source[0], AL.AL_POSITION, position, 0);
697: //al.alSourcefv(source[0], AL.AL_POSITION, sourceVel, 0);
698: al.alSourcei(source[0], AL.AL_LOOPING, AL.AL_TRUE);
699: if (debug && debugLoad)
700: System.out.println(" success, sourceID: " + source[0]);
701: }
702:
703: index = source[0];
704: return false;
705: }
706:
707: /**
708: * Load the sound ready to by played reusing the shared buffer.
709: *
710: * @return error true if error occurred
711: */
712: public boolean load(AL al, int[] buffer, int soundType) {
713: if (debug && debugLoad) {
714: System.out.print("JOALSample - load using shared buffer"
715: + "...");
716: }
717: this .al = al;
718: this .soundType = soundType;
719:
720: this .buffer = buffer;
721:
722: // Sources are points emitting sound.
723: source = new int[1];
724:
725: int[] format = new int[1];
726: int[] size = new int[1];
727: ByteBuffer[] data = new ByteBuffer[1];
728: int[] freq = new int[1];
729: int[] loop = new int[1];
730:
731: al
732: .alBufferData(buffer[0], format[0], data[0], size[0],
733: freq[0]);
734:
735: // bind buffers into audio sources
736: al.alGenSources(1, source, 0);
737: sampleSize = size[0];
738: sampleFrequency = freq[0];
739: sampleBits = format[0];
740:
741: if (soundType == AudioDevice3D.BACKGROUND_SOUND) {
742: if (debug && debugLoad)
743: System.out.print(" BackgroundSound...");
744: al.alSourcei(source[0], AL.AL_BUFFER, buffer[0]);
745: al.alSourcef(source[0], AL.AL_PITCH, 1.0f);
746: al.alSourcef(source[0], AL.AL_GAIN, 1.0f);
747: //al.alSourcefv(source[0], AL.AL_POSITION, position, 0);
748: //al.alSourcefv(source[0], AL.AL_POSITION, sourceVel, 0);
749: al.alSourcei(source[0], AL.AL_LOOPING, AL.AL_TRUE);
750: al.alSourcei(source[0], AL.AL_ROLLOFF_FACTOR, 0);
751: al.alSourcei(source[0], AL.AL_SOURCE_RELATIVE, AL.AL_TRUE);
752: if (debug && debugLoad)
753: System.out.println(" success, sourceID: " + source[0]);
754: } else if (soundType == AudioDevice3D.POINT_SOUND) {
755: if (debug && debugLoad)
756: System.out.print(" PointSound...");
757: al.alGenSources(1, source, 0);
758:
759: al.alSourcei(source[0], AL.AL_BUFFER, buffer[0]);
760: al.alSourcef(source[0], AL.AL_PITCH, 1.0f);
761: al.alSourcef(source[0], AL.AL_GAIN, 1.0f);
762: //al.alSourcefv(source[0], AL.AL_POSITION, position, 0);
763: //al.alSourcefv(source[0], AL.AL_POSITION, sourceVel, 0);
764: al.alSourcei(source[0], AL.AL_LOOPING, AL.AL_TRUE);
765: if (debug && debugLoad)
766: System.out.println(" success, sourceID: " + source[0]);
767: } else if (soundType == AudioDevice3D.CONE_SOUND) {
768: if (debug && debugLoad)
769: System.out.print(" ConeSound...");
770: al.alGenSources(1, source, 0);
771:
772: al.alSourcei(source[0], AL.AL_BUFFER, buffer[0]);
773: al.alSourcef(source[0], AL.AL_PITCH, 1.0f);
774: al.alSourcef(source[0], AL.AL_GAIN, 1.0f);
775: //al.alSourcefv(source[0], AL.AL_POSITION, position, 0);
776: //al.alSourcefv(source[0], AL.AL_POSITION, sourceVel, 0);
777: al.alSourcei(source[0], AL.AL_LOOPING, AL.AL_TRUE);
778: if (debug && debugLoad)
779: System.out.println(" success, sourceID: " + source[0]);
780: }
781:
782: index = source[0];
783: return false;
784: }
785:
786: public int startSample() {
787: al.alGetError();
788: al.alSourcePlay(index);
789: int errorCode = al.alGetError();
790: if (errorCode == AL.AL_NO_ERROR)
791: return 1;
792: else
793: return -1;
794: }
795:
796: public int stopSample() {
797: al.alGetError();
798: al.alSourceStop(index);
799: int errorCode = al.alGetError();
800: if (errorCode == AL.AL_NO_ERROR)
801: return 1;
802: else {
803: System.out
804: .println("JOALAudioDevice3D - stopSample...error stopping sample "
805: + index);
806: return -1;
807: }
808: }
809:
810: // Debug print flags and methods
811: static final protected boolean debugFlag = false;
812: static final protected boolean internalErrors = false;
813:
814: protected void debugPrint(String message) {
815: if (debugFlag)
816: System.out.println(message);
817: }
818:
819: protected void debugPrintln(String message) {
820: if (debugFlag)
821: System.out.println(message);
822: }
823:
824: private float radiansToDegrees(double radians) {
825: return (float) (radians * 180 / pi);
826: }
827:
828: public AL getAl() {
829: return al;
830: }
831:
832: public int[] getBuffer() {
833: return buffer;
834: }
835:
836: /** Clears all resources held by JOAL/OpenAL
837: */
838: private void clearOpenALBuffer() {
839: al.alDeleteBuffers(1, buffer, 0);
840: al.alDeleteSources(1, source, 0);
841: }
842: }
|