package gldemo; import org.lwjgl.opengl.*; import org.lwjgl.input.*; import org.lwjgl.util.glu.*; import glapp.*; import glsound.*; /** * Demo SoundScape class. Loads four sounds from wav files, places the sounds * in a space that user can navigate with arrow keys. Click mouse to move * one sound. *
* The SoundScape class wraps OpenAL functions. The class is static so can be * used without instantiation, similar to LWJGL Display, Mouse and Keyboard * classes: *
* SoundScape.create(); // init sound environment
* ...
* int soundData sd = SoundScape.loadSoundData("a_noise.wav");
* int soundSource ss = SoundScape.makeSoundSource(soundData);
* SoundScape.setSoundPosition(ss, 10, 2, 0);
* SoundScape.play(ss);
* ...
* SoundScape.destroy();
*
* The demo application uses GLApp.java for OpenGL rendering.
* * napier at potatoland dot org */ public class GLApp_DemoSound extends GLApp { // Handles for textures int sphereTextureHandle = 0; int marbleTextureHandle = 0; int groundTextureHandle = 0; // display list ID int sphereListID; // Point Light position float lightPosition[]= { -2f, 2f, 2f, 1.0f }; // Camera position static float[] cameraPos = {0f,1f,20f}; // Camera rotation in degrees float cameraRotation = 0f; // A constant used in navigation final float piover180 = 0.0174532925f; // sound sources int s1, s2, s3, s4; // World coordinates of sound sources float[] sPos1 = {-8f, 0f, -8f}; // left float[] sPos2 = { 0f, 0f, -8f}; // middle float[] sPos3 = { 8f, 0f, -8f}; // right float[] sPos4 = { 5f, 0f, 8f}; // close to camera /** * Start the application. demo.run() calls setup(), handles mouse and keyboard input, * and calls draw() in a loop. */ public static void main(String args[]) { GLApp_DemoSound demo = new GLApp_DemoSound(); demo.window_title = "GLApp Sound Demo"; demo.displayWidth = 800; demo.displayHeight = 600; demo.run(); } /** * Initialize the scene. Called by GLApp.run() */ public void setup() { // setup perspective setPerspective(); // Create a light (diffuse color, ambient color, specular color, position) float faDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; float faAmbient[] = { 0.2f, 0.2f, 0.3f, 1.0f }; setLight( GL11.GL_LIGHT1, faDiffuse, faAmbient, faDiffuse, lightPosition ); // set material properties setMaterial( new float[] {.9f,.9f,1f,1f}, .1f); // enable lighting and texturing GL11.glEnable(GL11.GL_LIGHTING); GL11.glEnable(GL11.GL_TEXTURE_2D); // Create texture and mipmap for frog sphere sphereTextureHandle = makeTexture("images/tree_frog_1_512.jpg"); // Create texture and mipmap for marble sphere marbleTextureHandle = makeTexture("images/marble.jpg"); // Create texture with anisotropic filtering and mipmap for ground plane groundTextureHandle = makeTexture("images/grass_1_512.jpg", true, true); //--------------------------------------------------------------- // Make sphere display list (for performance) //--------------------------------------------------------------- sphereListID = beginDisplayList(); renderSphere(); // draw the sphere into the display list endDisplayList(); //--------------------------------------------------------------- // Setup SoundScape //--------------------------------------------------------------- // initialize sound environment SoundScape.create(); // Over what distance should sounds drop off. This is not exact, as there // are many variables that affect how loud a sound is (some wav samples are // louder than others). Use the reference distance to control how "big" // the sounds are. The space in this scene is 20 units wide, and I use a // default reference distance of .5 to keep the sounds fairly isolated. SoundScape.setReferenceDistance(.5f); // load 2 sound samples (these hold the actual sound data) int frogSample = SoundScape.loadSoundData("sounds/frog.wav"); int cyberSample = SoundScape.loadSoundData("sounds/steam_loop.wav"); //jet_cruising_loop_1.wav"); // // make 4 sound sources (these are sound emitters that have a location in space) s1 = SoundScape.makeSoundSource( frogSample ); s2 = SoundScape.makeSoundSource( frogSample ); s3 = SoundScape.makeSoundSource( frogSample ); s4 = SoundScape.makeSoundSource( cyberSample ); // tweak pitch and volume on the sources SoundScape.setPitch(s1, .7f); // lower pitch frog SoundScape.setPitch(s2, .9f); // medium pitch frog SoundScape.setPitch(s3, 1.2f); // high pitch frog SoundScape.setGain(s4, 4.0f); // make this sound louder SoundScape.setReferenceDistance(s4,1); // and make it spread out more // set the sound emitter locations SoundScape.setSoundPosition(s1, sPos1); SoundScape.setSoundPosition(s2, sPos2); SoundScape.setSoundPosition(s3, sPos3); SoundScape.setSoundPosition(s4, sPos4); // make them repeat SoundScape.setLoop(s1,true); SoundScape.setLoop(s2,true); SoundScape.setLoop(s3,true); SoundScape.setLoop(s4,true); // turn them on SoundScape.play(s1); SoundScape.play(s2); SoundScape.play(s3); SoundScape.play(s4); } /** * Render one frame. Called by GLApp.run(). */ public void draw() { // clear depth buffer and color GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); // adjust camera position according to arrow key events setCameraPosition(); // SOUND: set listener at camera position float[] d = getDirection(cameraRotation); SoundScape.setListenerPosition(cameraPos[0],cameraPos[1],cameraPos[2]); SoundScape.setListenerOrientation(d[0], d[1], d[2], // we're facing this way 0f, 1f, 0f); // Y is "up" // select model view for subsequent transforms GL11.glMatrixMode(GL11.GL_MODELVIEW); GL11.glLoadIdentity(); // Place the viewpoint GLU.gluLookAt( // camera position cameraPos[0], cameraPos[1], cameraPos[2], // look at a point directly in front of camera cameraPos[0]- (float) Math.sin(cameraRotation* piover180), cameraPos[1], cameraPos[2]- (float) Math.cos(cameraRotation* piover180), // Y axis is up 0f, 1f, 0f); // draw the ground plane GL11.glBindTexture(GL11.GL_TEXTURE_2D, groundTextureHandle); GL11.glPushMatrix(); { GL11.glTranslatef(0f, -2.1f, 0f); // down a bit GL11.glScalef(10f, .01f, 10f); // squash it flat renderCube(2,20); } GL11.glPopMatrix(); // draw sphere at sound1 GL11.glBindTexture(GL11.GL_TEXTURE_2D, sphereTextureHandle); GL11.glPushMatrix(); { GL11.glTranslatef(sPos1[0], sPos1[1], sPos1[2]); callDisplayList(sphereListID); } GL11.glPopMatrix(); // draw sphere at sound 2 GL11.glBindTexture(GL11.GL_TEXTURE_2D, sphereTextureHandle); GL11.glPushMatrix(); { GL11.glTranslatef(sPos2[0], sPos2[1], sPos2[2]); callDisplayList(sphereListID); } GL11.glPopMatrix(); // draw sphere at sound 3 GL11.glBindTexture(GL11.GL_TEXTURE_2D, sphereTextureHandle); GL11.glPushMatrix(); { GL11.glTranslatef(sPos3[0], sPos3[1], sPos3[2]); callDisplayList(sphereListID); } GL11.glPopMatrix(); // draw sphere at sound 4 (marble texture) GL11.glBindTexture(GL11.GL_TEXTURE_2D, marbleTextureHandle); GL11.glPushMatrix(); { GL11.glTranslatef(sPos4[0], sPos4[1], sPos4[2]); callDisplayList(sphereListID); } GL11.glPopMatrix(); // Place the light. Light will move with the rest of the scene GL11.glLight(GL11.GL_LIGHT1, GL11.GL_POSITION, allocFloats(lightPosition)); // draw text print( 50, 550, "Use arrow keys to navigate"); print( 50, 525, "Click to move marble ball (and sound)"); } /** * set the field of view and view depth. */ public static void setPerspective() { // select projection matrix (controls perspective) GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glLoadIdentity(); GLU.gluPerspective(40f, // field of view angle aspectRatio, // proportions of viewport rectangle .1f, // Min Z: how far from eye position does view start 500f); // max Z: how far from eye position does view extend // return to modelview matrix GL11.glMatrixMode(GL11.GL_MODELVIEW); } /** * Adjust the Camera position based on keyboard arrow key input. */ public void setCameraPosition() { // Turn left if (Keyboard.isKeyDown(Keyboard.KEY_LEFT)) { cameraRotation += 1f; } // Turn right if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT)) { cameraRotation -= 1f; } // move forward in current direction if (Keyboard.isKeyDown(Keyboard.KEY_UP)) { cameraPos[0] -= (float) Math.sin(cameraRotation * piover180) * .1f; cameraPos[2] -= (float) Math.cos(cameraRotation * piover180) * .1f; } // move backward in current direction if (Keyboard.isKeyDown(Keyboard.KEY_DOWN)) { cameraPos[0] += (float) Math.sin(cameraRotation * piover180) * .1f; cameraPos[2] += (float) Math.cos(cameraRotation * piover180) * .1f; } // move camera down if (Keyboard.isKeyDown(Keyboard.KEY_PRIOR)) { cameraPos[1] += .1f; } // move camera up if (Keyboard.isKeyDown(Keyboard.KEY_NEXT)) { cameraPos[1] -= .1f; } } /** * Given camera rotation in degrees, make a vector that points in * direction camera is looking. Will use this to set direction of Sound Listener. * @return xyz direction as float[3] */ public float[] getDirection(float camera_rotation) { float[] direction = { (float) -Math.sin(camera_rotation * piover180), 0f, (float) -Math.cos(camera_rotation * piover180), }; return direction; } /** * Move sphere and sound to mouse click position. Have to pick a Z depth to * place the sphere at, so check the depth buffer at the cursor x,y to see * if user clicked on an object. If yes, put the sphere at that Z depth. If * user clicked empty space, put the sphere at Z=0 */ public void mouseDown(int x, int y) { float z = getZDepth(x,y); // get the Z depth at the cursor if (z == 0 || z == 1) { // if clicking on empty space z = getZDepthAtOrigin(); // get the Z depth at origin } sPos4 = getWorldCoordsAtScreen(x, y, z); // convert mouse xyz to world SoundScape.setSoundPosition(s4, sPos4); // put sound there } public void mouseMove(int x, int y) { } public void mouseUp(int x, int y) { } public void keyDown(int keycode) { } public void keyUp(int keycode) { } /** * Shutdown the OpenAL environment before exiting app. Cleanup() is called * by GLApp when the main loop exits. */ public void cleanup() { super.cleanup(); SoundScape.destroy(); } }