2 * Copyright (c) 2003-2005 jMonkeyEngine
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * Created on Apr 22, 2005
36 package com.jmex.sound.openAL;
39 import java.util.logging.Level;
41 import org.lwjgl.openal.AL;
43 import com.jme.math.Vector3f;
44 import com.jme.renderer.Camera;
45 import com.jme.util.LoggingSystem;
46 import com.jmex.sound.openAL.objects.Listener;
47 import com.jmex.sound.openAL.objects.MusicStream;
48 import com.jmex.sound.openAL.objects.Sample3D;
49 import com.jmex.sound.openAL.objects.util.StreamPlayer;
50 import com.jmex.sound.openAL.objects.util.dsp.Equalizer;
51 import com.jmex.sound.openAL.scene.Configuration;
52 import com.jmex.sound.openAL.scene.SoundNode;
54 public class SoundSystem {
56 private static Listener listener;
57 private static Camera camera;
59 public static final int OUTPUT_DEFAULT=0;
61 public static final int OUTPUT_DSOUND =1;
62 public static final int OUTPUT_WINMM =2;
63 public static final int OUTPUT_ASIO =3;
65 public static final int OUTPUT_OSS =5;
66 public static final int OUTPUT_ESD =6;
67 public static final int OUTPUT_ALSA =7;
69 public static final int OUTPUT_MAC = 8;
71 private static int OS_DETECTED;
72 private static final int OS_LINUX=1;
73 private static final int OS_WINDOWS=2;
74 private static final int OS_MAC = 3;
76 private static SoundNode[] nodes;
77 private static Sample3D[] sample3D;
78 private static MusicStream[] stream;
82 LoggingSystem.getLogger().log(Level.INFO,"DETECT OPERATING SYSTEM");
84 LoggingSystem.getLogger().log(Level.INFO,"CREATE OPENAL");
86 LoggingSystem.getLogger().log(Level.INFO,"CREATE LISTENER");
87 listener=new Listener();
93 private static void initializeOpenAL() {
96 LoggingSystem.getLogger().log(Level.INFO, "OpenAL initalized!");
97 } catch (Exception e) {
98 LoggingSystem.getLogger().log(Level.SEVERE,
99 "Failed to Initialize OpenAL...");
104 private static void detectOS() {
105 String osName=System.getProperty("os.name");
106 osName=osName.toUpperCase();
107 if(osName.startsWith("LINUX")) OS_DETECTED=OS_LINUX;
108 if(osName.startsWith("WINDOWS")) OS_DETECTED=OS_WINDOWS;
109 if(osName.startsWith("MAC")) OS_DETECTED=OS_MAC;
114 * init the sound system by setting it's listener's position to the cameras position
117 * @param outputMethod
119 public static void init(Camera cam, int outputMethod){
121 if(outputMethod==OUTPUT_DEFAULT){
122 outputMethod=OS_DETECTED;
124 switch(outputMethod){
137 * Get the "ears" of the sound system
140 public static Camera getCamera(){
145 * Set the "ears" of the sound system
148 public static void setCamera(Camera c){
154 private static void updateListener(){
156 listener.setPosition(camera.getLocation());
158 float[] orientation = listener.getOrientation();
162 dir = camera.getDirection();
165 dir=new Vector3f(0, 0, -1);
166 up=new Vector3f(0, 1, 0);
168 orientation[0] = -dir.x;
169 orientation[1] = dir.y;
170 orientation[2] = dir.z;
171 orientation[3] = up.x;
172 orientation[4] = -up.y;
173 orientation[5] = up.z;
179 * Updates the geometric states of all nodes in the scene
180 * @param time currently not used
182 public static void update(float time){
183 if(nodes==null) return;
185 for(int a=0; a<nodes.length; a++){
186 nodes[a].updateWorldData(time);
193 * Updates the geometric states of the given node in the scene
194 * @param nodeName the node to update
195 * @param time currently not used
197 public static void update(int nodeName, float time){
198 if(nodes==null) return;
199 if(nodeName<0 || nodeName>=nodes.length) return;
200 nodes[nodeName].updateWorldData(time);
207 * Draws all nodes in the scene
208 * @param time currently not used
210 public static void draw(){
211 if(nodes==null) return;
212 for(int a=0; a<nodes.length; a++){
219 * Draws the given node in the scene
220 * @param nodeName the node to update
221 * @param time currently not used
223 public static void draw(int nodeName){
224 if(nodes==null) return;
225 if(nodeName<0 || nodeName>=nodes.length) return;
226 nodes[nodeName].draw();
230 * Creates a node ans return an integer as it's identifier.
231 * @return the node identifier
233 public static int createSoundNode(){
235 nodes=new SoundNode[1];
236 nodes[0]=new SoundNode();
239 SoundNode[] tmp=new SoundNode[nodes.length];
240 System.arraycopy(nodes, 0, tmp, 0, tmp.length);
241 nodes=new SoundNode[tmp.length+1];
242 System.arraycopy(tmp, 0, nodes, 0, tmp.length);
243 nodes[tmp.length]=new SoundNode();
249 * Creates a 3D sample and returns an identifier for it
250 * @param file the sample file name
251 * @return the 3D sample identifier
253 public static int create3DSample(URL url){
255 sample3D=new Sample3D[1];
256 sample3D[0]=new Sample3D(listener, url);
259 Sample3D[] tmp=new Sample3D[sample3D.length];
260 System.arraycopy(sample3D, 0, tmp, 0, tmp.length);
261 sample3D=new Sample3D[tmp.length+1];
262 System.arraycopy(tmp, 0, sample3D, 0, tmp.length);
263 sample3D[tmp.length]=new Sample3D(listener, url);
270 * Creates a Music stream and returns an identifier for it
271 * @param file streaming file name
272 * @param loadIntoMemory
273 * @return the stream identifier
275 public static int createStream(String file, boolean loadIntoMemory){
277 stream=new MusicStream[1];
278 stream[0]=new MusicStream(file, loadIntoMemory);
281 MusicStream[] tmp=new MusicStream[stream.length];
282 System.arraycopy(stream, 0, tmp, 0, tmp.length);
283 stream=new MusicStream[tmp.length+1];
284 System.arraycopy(tmp, 0, stream, 0, tmp.length);
285 stream[tmp.length]=new MusicStream(file, loadIntoMemory);
291 * Checks if a stream is opened. If it is, this can be used to know
292 * that the file is really a audio file
294 * @return true if the stream is opened
296 public static boolean isStreamOpened(int streamName){
299 }else if(streamName<0 || streamName>=stream.length){
302 return stream[streamName].isOpened();
311 public static void setStreamLooping(int streamName, boolean loop){
314 }else if(streamName<0 || streamName>=stream.length){
317 stream[streamName].loop(loop);
323 * Get the length of the given stream in milliseconds
325 * @return the stream length in millis
327 public static float getStreamLength(int streamName){
330 }else if(streamName<0 || streamName>=stream.length){
333 return stream[streamName].length();
337 public static boolean playStream(int streamName){
340 }else if(streamName<0 || streamName>=stream.length){
343 return stream[streamName].play();
350 public static boolean pauseStream(int streamName){
353 }else if(streamName<0 || streamName>=stream.length){
356 return stream[streamName].pause();
360 public static void stopStream(int streamName){
363 }else if(streamName<0 || streamName>=stream.length){
366 stream[streamName].stop();
371 * Sets the spatial position of a given sample
372 * @param sample the sample identifier
373 * @param x the x position of the sample
374 * @param y the y position of the sample
375 * @param z the z position of the sample
377 public static void setSamplePosition(int sample, float x, float y, float z){
380 }else if(sample<0 || sample>=sample3D.length){
383 sample3D[sample].setPosition(x, y, z);
388 * Sets the velocity of a given sample
389 * @param sample the sample identifier
390 * @param x the x velocity of the sample
391 * @param y the y velocity of the sample
392 * @param z the z velocity of the sample
394 public static void setSampleVelocity(int sample, float x, float y, float z){
397 }else if(sample<0 || sample>=sample3D.length){
400 sample3D[sample].setVelocity(x, y, z);
405 * Set the FX configuration of the given sample
406 * @param sample sample the sample identifier
407 * @param conf the config
409 public static void setSampleConfig(int sample, Configuration conf){
412 }else if(sample<0 || sample>=sample3D.length){
415 sample3D[sample].setConfiguration(conf);
421 * Binds an event to the given sample. The event number sould be a unique id.
422 * Binding an event to sample will make it play only if the event is fired
423 * on the container node
424 * @param sample the sample to which the event will be bound
425 * @param event the unique event number
427 public static void bindEventToSample(int sample, int event){
430 }else if(sample<0 || sample>=sample3D.length){
433 sample3D[sample].bindEvent(event);
438 * Fires an event on all nodes
439 * @param eventName the event to fire
441 public static void onEvent(int eventName){
442 if(nodes==null) return;
443 for(int a=0; a<nodes.length; a++){
444 nodes[a].onEvent(eventName);
454 public static void onEvent(int nodeName, int eventName){
455 if(nodes==null) return;
456 if(nodeName<0 || nodeName>=nodes.length) return;
457 nodes[nodeName].onEvent(eventName);
463 * Set the FX configuration of the given stream
464 * @param sample stream the sample identifier
465 * @param conf the config
467 public static void setStreamConfig(int streamName, Configuration conf){
470 }else if(streamName<0 || streamName>=stream.length){
473 stream[streamName].setConfiguration(conf);
479 * Sets the units from which the sample will stop playing
480 * @param sample the sample identifier
481 * @param dist the distance unit from which the sample will stop playing
483 public static void setSampleMaxAudibleDistance(int sample, int dist){
486 }else if(sample<0 || sample>=sample3D.length){
489 sample3D[sample].setMaxAudibleDistance(dist);
494 public static void setSampleMinAudibleDistance(int sample, int dist){
497 }else if(sample<0 || sample>=sample3D.length){
500 sample3D[sample].setMinDistance(dist);
506 * Adds a sample to the given node identifier
510 public static void addSampleToNode(int sample, int destNode){
513 }else if(sample3D==null){
515 }else if(destNode<0 || destNode>=nodes.length){
517 }else if(sample<0 || sample>=sample3D.length){
520 nodes[destNode].attachChild(sample3D[sample]);
524 public static void setRolloffFactor(float rolloff){
525 for ( int i = 0; i < sample3D.length; i++ ) {
526 setSampleRolloffFactor( i, rolloff );
530 public static void setSampleRolloffFactor(int sample, float rolloff){
533 }else if(sample<0 || sample>=sample3D.length){
536 sample3D[sample].setRolloffFactor( rolloff );
541 * Set the volume of the given sample
545 public static void setSampleVolume(int sample, float volume){
548 }else if(sample<0 || sample>=sample3D.length){
551 sample3D[sample].setVolume(volume);
556 * Sets the volume of all samples attached to a given node.
558 * @param node We change the volume of this nodes children.
559 * @param volume The volume to set. Should be a value between 0 - 1.
561 public static void setNodeVolume(int node, float volume) {
562 if(nodes==null) return;
563 if(node<0 || node>=nodes.length) return;
564 for (int i = 0; i < nodes[node].getQuantity(); i++) {
565 ((Sample3D)nodes[node].getChild(i)).setVolume(volume);
571 public static void setEqualizer(Equalizer e){
572 StreamPlayer.getInstance().setEqualizer(e);