From 2d57c25287542dcbad59c6b4782e87f86bd0fbc6 Mon Sep 17 00:00:00 2001 From: Michael Bien Date: Mon, 29 Mar 2010 04:40:53 +0200 Subject: moved com.jogamp.javafx.* to com.jogamp.*. --- .../com/jogamp/audio/windows/waveout/Audio.java | 66 ++++ .../com/jogamp/audio/windows/waveout/Mixer.java | 362 +++++++++++++++++++++ .../jogamp/audio/windows/waveout/SoundBuffer.java | 124 +++++++ .../audio/windows/waveout/TestSpatialization.java | 89 +++++ .../com/jogamp/audio/windows/waveout/Track.java | 206 ++++++++++++ .../com/jogamp/audio/windows/waveout/Vec3f.java | 212 ++++++++++++ .../jogamp/javafx/audio/windows/waveout/Audio.java | 66 ---- .../jogamp/javafx/audio/windows/waveout/Mixer.java | 362 --------------------- .../javafx/audio/windows/waveout/SoundBuffer.java | 124 ------- .../audio/windows/waveout/TestSpatialization.java | 89 ----- .../jogamp/javafx/audio/windows/waveout/Track.java | 206 ------------ .../jogamp/javafx/audio/windows/waveout/Vec3f.java | 212 ------------ 12 files changed, 1059 insertions(+), 1059 deletions(-) create mode 100755 src/jogl/classes/com/jogamp/audio/windows/waveout/Audio.java create mode 100755 src/jogl/classes/com/jogamp/audio/windows/waveout/Mixer.java create mode 100755 src/jogl/classes/com/jogamp/audio/windows/waveout/SoundBuffer.java create mode 100755 src/jogl/classes/com/jogamp/audio/windows/waveout/TestSpatialization.java create mode 100755 src/jogl/classes/com/jogamp/audio/windows/waveout/Track.java create mode 100755 src/jogl/classes/com/jogamp/audio/windows/waveout/Vec3f.java delete mode 100755 src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Audio.java delete mode 100755 src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Mixer.java delete mode 100755 src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/SoundBuffer.java delete mode 100755 src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/TestSpatialization.java delete mode 100755 src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Track.java delete mode 100755 src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Vec3f.java (limited to 'src/jogl/classes/com') diff --git a/src/jogl/classes/com/jogamp/audio/windows/waveout/Audio.java b/src/jogl/classes/com/jogamp/audio/windows/waveout/Audio.java new file mode 100755 index 000000000..2b51be164 --- /dev/null +++ b/src/jogl/classes/com/jogamp/audio/windows/waveout/Audio.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.audio.windows.waveout; + +import java.io.*; + +public class Audio { + private static Audio instance = null; + private Mixer mixer; + + public synchronized static Audio getInstance() { + if (instance == null) { + instance = new Audio(); + } + return instance; + } + + private Audio() { + mixer = Mixer.getMixer(); + } + + public Mixer getMixer() { + return mixer; + } + + public Track newTrack(File file) throws IOException + { + Track res = new Track(file); + mixer.add(res); + return res; + } + + public void shutdown() { + mixer.shutdown(); + } +} diff --git a/src/jogl/classes/com/jogamp/audio/windows/waveout/Mixer.java b/src/jogl/classes/com/jogamp/audio/windows/waveout/Mixer.java new file mode 100755 index 000000000..60972873e --- /dev/null +++ b/src/jogl/classes/com/jogamp/audio/windows/waveout/Mixer.java @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.audio.windows.waveout; + +import java.io.*; +import java.nio.*; +import java.util.*; + +// Needed only for NIO workarounds on CVM +import java.lang.reflect.*; + +public class Mixer { + // This class is a singleton + private static Mixer mixer; + + private volatile boolean shutdown; + private volatile Object shutdownLock = new Object(); + private volatile boolean shutdownDone; + + // Windows Event object + private long event; + + private volatile ArrayList/**/ tracks = new ArrayList(); + + private Vec3f leftSpeakerPosition = new Vec3f(-1, 0, 0); + private Vec3f rightSpeakerPosition = new Vec3f( 1, 0, 0); + + private float falloffFactor = 1.0f; + + static { + mixer = new Mixer(); + } + + private Mixer() { + event = CreateEvent(); + new FillerThread().start(); + MixerThread m = new MixerThread(); + m.setPriority(Thread.MAX_PRIORITY - 1); + m.start(); + } + + public static Mixer getMixer() { + return mixer; + } + + synchronized void add(Track track) { + ArrayList/**/ newTracks = (ArrayList) tracks.clone(); + newTracks.add(track); + tracks = newTracks; + } + + synchronized void remove(Track track) { + ArrayList/**/ newTracks = (ArrayList) tracks.clone(); + newTracks.remove(track); + tracks = newTracks; + } + + // NOTE: due to a bug on the APX device, we only have mono sounds, + // so we currently only pay attention to the position of the left + // speaker + public void setLeftSpeakerPosition(float x, float y, float z) { + leftSpeakerPosition.set(x, y, z); + } + + // NOTE: due to a bug on the APX device, we only have mono sounds, + // so we currently only pay attention to the position of the left + // speaker + public void setRightSpeakerPosition(float x, float y, float z) { + rightSpeakerPosition.set(x, y, z); + } + + /** This defines a scale factor of sorts -- the higher the number, + the larger an area the sound will affect. Default value is + 1.0f. Valid values are [1.0f, ...]. The formula for the gain + for each channel is +
+     falloffFactor
+  -------------------
+  falloffFactor + r^2
+
+*/ + public void setFalloffFactor(float factor) { + falloffFactor = factor; + } + + public void shutdown() { + synchronized(shutdownLock) { + shutdown = true; + SetEvent(event); + try { + shutdownLock.wait(); + } catch (InterruptedException e) { + } + } + } + + class FillerThread extends Thread { + FillerThread() { + super("Mixer Thread"); + } + + public void run() { + while (!shutdown) { + List/**/ curTracks = tracks; + + for (Iterator iter = curTracks.iterator(); iter.hasNext(); ) { + Track track = (Track) iter.next(); + try { + track.fill(); + } catch (IOException e) { + e.printStackTrace(); + remove(track); + } + } + + try { + // Run ten times per second + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + class MixerThread extends Thread { + // Temporary mixing buffer + // Interleaved left and right channels + float[] mixingBuffer; + private Vec3f temp = new Vec3f(); + + MixerThread() { + super("Mixer Thread"); + if (!initializeWaveOut(event)) { + throw new InternalError("Error initializing waveout device"); + } + } + + public void run() { + while (!shutdown) { + // Get the next buffer + long mixerBuffer = getNextMixerBuffer(); + if (mixerBuffer != 0) { + ByteBuffer buf = getMixerBufferData(mixerBuffer); + + if (buf == null) { + // This is happening on CVM because + // JNI_NewDirectByteBuffer isn't implemented + // by default and isn't compatible with the + // JSR-239 NIO implementation (apparently) + buf = newDirectByteBuffer(getMixerBufferDataAddress(mixerBuffer), + getMixerBufferDataCapacity(mixerBuffer)); + } + + if (buf == null) { + throw new InternalError("Couldn't wrap the native address with a direct byte buffer"); + } + + // System.out.println("Mixing buffer"); + + // If we don't have enough samples in our mixing buffer, expand it + // FIXME: knowledge of native output rendering format + if ((mixingBuffer == null) || (mixingBuffer.length < (buf.capacity() / 2 /* bytes / sample */))) { + mixingBuffer = new float[buf.capacity() / 2]; + } else { + // Zap it + for (int i = 0; i < mixingBuffer.length; i++) { + mixingBuffer[i] = 0.0f; + } + } + + // This assertion should be in place if we have stereo + if ((mixingBuffer.length % 2) != 0) { + String msg = "FATAL ERROR: odd number of samples in the mixing buffer"; + System.out.println(msg); + throw new InternalError(msg); + } + + // Run down all of the registered tracks mixing them in + List/**/ curTracks = tracks; + + for (Iterator iter = curTracks.iterator(); iter.hasNext(); ) { + Track track = (Track) iter.next(); + // Consider only playing tracks + if (track.isPlaying()) { + // First recompute its gain + Vec3f pos = track.getPosition(); + float leftGain = gain(pos, leftSpeakerPosition); + float rightGain = gain(pos, rightSpeakerPosition); + // Now mix it in + int i = 0; + while (i < mixingBuffer.length) { + if (track.hasNextSample()) { + float sample = track.nextSample(); + mixingBuffer[i++] = sample * leftGain; + mixingBuffer[i++] = sample * rightGain; + } else { + // This allows tracks to stall without being abruptly cancelled + if (track.done()) { + remove(track); + } + break; + } + } + } + } + + // Now that we have our data, send it down to the card + int outPos = 0; + for (int i = 0; i < mixingBuffer.length; i++) { + short val = (short) mixingBuffer[i]; + buf.put(outPos++, (byte) val); + buf.put(outPos++, (byte) (val >> 8)); + } + if (!prepareMixerBuffer(mixerBuffer)) { + throw new RuntimeException("Error preparing mixer buffer"); + } + if (!writeMixerBuffer(mixerBuffer)) { + throw new RuntimeException("Error writing mixer buffer to device"); + } + } else { + // System.out.println("No mixer buffer available"); + + // Wait for a buffer to become available + if (!WaitForSingleObject(event)) { + throw new RuntimeException("Error while waiting for event object"); + } + + /* + try { + Thread.sleep(10); + } catch (InterruptedException e) { + } + */ + } + } + + // Need to shut down + shutdownWaveOut(); + synchronized(shutdownLock) { + shutdownLock.notifyAll(); + } + } + + // This defines the 3D spatialization gain function. + // The function is defined as: + // falloffFactor + // ------------------- + // falloffFactor + r^2 + private float gain(Vec3f pos, Vec3f speakerPos) { + temp.sub(pos, speakerPos); + float dotp = temp.dot(temp); + return (falloffFactor / (falloffFactor + dotp)); + } + } + + // Initializes waveout device + private static native boolean initializeWaveOut(long eventObject); + // Shuts down waveout device + private static native void shutdownWaveOut(); + + // Gets the next (opaque) buffer of data to fill from the native + // code, or 0 if none was available yet (it should not happen that + // none is available the way the code is written). + private static native long getNextMixerBuffer(); + // Gets the next ByteBuffer to fill out of the mixer buffer. It + // requires interleaved left and right channel samples, 16 signed + // bits per sample, little endian. Implicit 44.1 kHz sample rate. + private static native ByteBuffer getMixerBufferData(long mixerBuffer); + // We need these to work around the lack of + // JNI_NewDirectByteBuffer in CVM + the JSR 239 NIO classes + private static native long getMixerBufferDataAddress(long mixerBuffer); + private static native int getMixerBufferDataCapacity(long mixerBuffer); + // Prepares this mixer buffer for writing to the device. + private static native boolean prepareMixerBuffer(long mixerBuffer); + // Writes this mixer buffer to the device. + private static native boolean writeMixerBuffer(long mixerBuffer); + + // Helpers to prevent mixer thread from busy waiting + private static native long CreateEvent(); + private static native boolean WaitForSingleObject(long event); + private static native void SetEvent(long event); + private static native void CloseHandle(long handle); + + // We need a reflective hack to wrap a direct ByteBuffer around + // the native memory because JNI_NewDirectByteBuffer doesn't work + // in CVM + JSR-239 NIO + private static Class directByteBufferClass; + private static Constructor directByteBufferConstructor; + private static Map createdBuffers = new HashMap(); // Map Long, ByteBuffer + + private static ByteBuffer newDirectByteBuffer(long address, long capacity) { + Long key = new Long(address); + ByteBuffer buf = (ByteBuffer) createdBuffers.get(key); + if (buf == null) { + buf = newDirectByteBufferImpl(address, capacity); + if (buf != null) { + createdBuffers.put(key, buf); + } + } + return buf; + } + private static ByteBuffer newDirectByteBufferImpl(long address, long capacity) { + if (directByteBufferClass == null) { + try { + directByteBufferClass = Class.forName("java.nio.DirectByteBuffer"); + byte[] tmp = new byte[0]; + directByteBufferConstructor = + directByteBufferClass.getDeclaredConstructor(new Class[] { Integer.TYPE, + tmp.getClass(), + Integer.TYPE }); + directByteBufferConstructor.setAccessible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + + if (directByteBufferConstructor != null) { + try { + return (ByteBuffer) + directByteBufferConstructor.newInstance(new Object[] { + new Integer((int) capacity), + null, + new Integer((int) address) + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + return null; + } +} diff --git a/src/jogl/classes/com/jogamp/audio/windows/waveout/SoundBuffer.java b/src/jogl/classes/com/jogamp/audio/windows/waveout/SoundBuffer.java new file mode 100755 index 000000000..c45430d23 --- /dev/null +++ b/src/jogl/classes/com/jogamp/audio/windows/waveout/SoundBuffer.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.audio.windows.waveout; + +import java.io.*; + +class SoundBuffer { + private byte[] data; + private boolean needsByteSwap; + private int numBytes; + private int bytesPerSample; + private int numSamples; + private boolean playing; + private boolean empty; + + // Note: needsByteSwap argument makes assumptions about the format + SoundBuffer(int size, int bytesPerSample, boolean needsByteSwap) { + this.bytesPerSample = bytesPerSample; + this.needsByteSwap = needsByteSwap; + data = new byte[size * bytesPerSample]; + empty = true; + } + + boolean playing() { + return playing; + } + + void playing(boolean playing) { + this.playing = playing; + } + + boolean empty() { + return empty; + } + + void empty(boolean empty) { + this.empty = empty; + } + + void fill(InputStream input) throws IOException { + synchronized(this) { + if (playing) { + throw new IllegalStateException("Can not fill a buffer that is playing"); + } + } + + empty(true); + int num = input.read(data); + if (num > 0) { + numBytes = num; + numSamples = numBytes / bytesPerSample; + empty(false); + if ((numBytes % bytesPerSample) != 0) { + System.out.println("WARNING: needed integral multiple of " + bytesPerSample + + " bytes, but read " + numBytes + " bytes"); + } + } else { + numBytes = 0; + } + } + + int numSamples() { + return numSamples; + } + + // This is called by the mixer and must be extremely fast + // FIXME: may want to reconsider use of floating point at this point + // FIXME: assumes all sounds are of the same format to avoid normalization + float getSample(int sample) { + int startByte = sample * bytesPerSample; + // FIXME: assumes no more than 4 bytes per sample + int res = 0; + if (needsByteSwap) { + for (int i = startByte + bytesPerSample - 1; i >= startByte; i--) { + res <<= 8; + res |= (data[i] & 0xff); + } + } else { + int endByte = startByte + bytesPerSample - 1; + for (int i = startByte; i <= endByte; i++) { + res <<= 8; + res |= (data[i] & 0xff); + } + } + // Sign extend + if (bytesPerSample == 2) { + res = (short) res; + } else if (bytesPerSample == 1) { + res = (byte) res; + } + + return (float) res; + } +} diff --git a/src/jogl/classes/com/jogamp/audio/windows/waveout/TestSpatialization.java b/src/jogl/classes/com/jogamp/audio/windows/waveout/TestSpatialization.java new file mode 100755 index 000000000..78fb3493f --- /dev/null +++ b/src/jogl/classes/com/jogamp/audio/windows/waveout/TestSpatialization.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.audio.windows.waveout; + +import java.io.*; +import javax.media.nativewindow.NativeWindow; +import javax.media.opengl.GLDrawableFactory; + +public class TestSpatialization { + public static void main(String[] args) { + if (args.length != 1) { + System.out.println("Usage: TestSpatialization [file name]"); + System.exit(1); + } + + try { + // FIXME: this is a hack to get the native library loaded + try { + GLDrawableFactory.getFactory(NativeWindow.class); + } catch (Exception e) {} + // Initialize the audio subsystem + Audio audio = Audio.getInstance(); + // Create a track + Track track = audio.newTrack(new File(args[0])); + track.setPosition(1, 0, 0); + // Run for ten seconds + long startTime = System.currentTimeMillis(); + long duration = 10000; + long curTime = 0; + try { + Thread.sleep(500); + } catch (InterruptedException e) { + } + System.out.println("Playing..."); + track.setLooping(true); + track.play(); + while ((curTime = System.currentTimeMillis()) < startTime + duration) { + // Make one revolution every two seconds + float rads = (float) (((2 * Math.PI) * (((float) (curTime - startTime)) / 1000.0f)) / 2); + track.setPosition((float) Math.cos(rads), 0, (float) Math.sin(rads)); + // Would like to make it go in a circle, but since + // stereo doesn't work now, make it move along a line + // track.setPosition(-1.0f, 0, 2.0f * (float) Math.sin(rads)); + // Sleep a little between updates + try { + Thread.sleep(10); + } catch (InterruptedException e) { + } + } + System.out.println("Shutting down audio subsystem"); + audio.shutdown(); + System.out.println("Exiting."); + System.exit(0); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } +} diff --git a/src/jogl/classes/com/jogamp/audio/windows/waveout/Track.java b/src/jogl/classes/com/jogamp/audio/windows/waveout/Track.java new file mode 100755 index 000000000..b57bf1dc6 --- /dev/null +++ b/src/jogl/classes/com/jogamp/audio/windows/waveout/Track.java @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.audio.windows.waveout; + +import java.io.*; +import java.nio.*; + +public class Track { + // Default number of samples per buffer + private static final int BUFFER_SIZE = 32768; + // Number of bytes per sample (FIXME: dependence on audio format) + static final int BYTES_PER_SAMPLE = 2; + // Whether we need byte swapping (FIXME: dependence on audio format) + static final boolean NEEDS_BYTE_SWAP = true; + + // This is the buffer this track is currently playing from + private SoundBuffer activeBuffer; + // This is the sample position in the active buffer + private int samplePosition; + // This is the total number of samples in the file + private int totalSamples; + // This is the total number of samples we have read + private int samplesRead; + // This is the buffer that the background filler thread may be filling + private SoundBuffer fillingBuffer; + // If we're playing the file, this is its input stream + private InputStream input; + // Keep around the file name + private File file; + // Whether we're playing this sound + private boolean playing; + // Whether we're looping this sound + private boolean looping; + // The position of this sound; defaults to being at the origin + private volatile Vec3f position = new Vec3f(); + + Track(File file) throws IOException { + if (!file.getName().endsWith(".rawsound")) { + throw new IOException("Unsupported file format (currently supports only raw sounds)"); + } + + this.file = file; + openInput(); + + // Allocate the buffers + activeBuffer = new SoundBuffer(BUFFER_SIZE, BYTES_PER_SAMPLE, NEEDS_BYTE_SWAP); + fillingBuffer = new SoundBuffer(BUFFER_SIZE, BYTES_PER_SAMPLE, NEEDS_BYTE_SWAP); + + // Fill the first buffer immediately + fill(); + swapBuffers(); + } + + private void openInput() throws IOException { + input = new BufferedInputStream(new FileInputStream(file)); + totalSamples = (int) file.length() / BYTES_PER_SAMPLE; + } + + public File getFile() { + return file; + } + + public synchronized void play() { + if (input == null) { + try { + openInput(); + // Fill it immediately + fill(); + } catch (IOException e) { + e.printStackTrace(); + return; + } + } + + playing = true; + } + + public synchronized boolean isPlaying() { + return playing; + } + + public synchronized void setLooping(boolean looping) { + this.looping = looping; + } + + public synchronized boolean isLooping() { + return looping; + } + + public void setPosition(float x, float y, float z) { + position = new Vec3f(x, y, z); + } + + synchronized void fill() throws IOException { + if (input == null) { + return; + } + SoundBuffer curBuffer = fillingBuffer; + if (!curBuffer.empty()) { + return; + } + curBuffer.fill(input); + if (curBuffer.empty()) { + // End of file + InputStream tmp = null; + synchronized(this) { + tmp = input; + input = null; + } + tmp.close(); + + // If looping, re-open + if (isLooping()) { + openInput(); + // and fill + fill(); + } + } + } + + // These are only for use by the Mixer + private float leftGain; + private float rightGain; + + void setLeftGain(float leftGain) { + this.leftGain = leftGain; + } + + float getLeftGain() { + return leftGain; + } + + void setRightGain(float rightGain) { + this.rightGain = rightGain; + } + + float getRightGain() { + return rightGain; + } + + Vec3f getPosition() { + return position; + } + + // This is called by the mixer and must be extremely fast + // Note this assumes mono sounds (FIXME) + boolean hasNextSample() { + return (!activeBuffer.empty() && samplePosition < activeBuffer.numSamples()); + } + + // This is called by the mixer and must be extremely fast + float nextSample() { + float res = activeBuffer.getSample(samplePosition++); + ++samplesRead; + if (!hasNextSample()) { + swapBuffers(); + samplePosition = 0; + if (done()) { + playing = false; + } + } + return res; + } + + synchronized void swapBuffers() { + SoundBuffer tmp = activeBuffer; + activeBuffer = fillingBuffer; + fillingBuffer = tmp; + fillingBuffer.empty(true); + } + + // This provides a more robust termination condition + boolean done() { + return (samplesRead == totalSamples) && !looping; + } +} diff --git a/src/jogl/classes/com/jogamp/audio/windows/waveout/Vec3f.java b/src/jogl/classes/com/jogamp/audio/windows/waveout/Vec3f.java new file mode 100755 index 000000000..1afdaf081 --- /dev/null +++ b/src/jogl/classes/com/jogamp/audio/windows/waveout/Vec3f.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.audio.windows.waveout; + +/** 3-element single-precision vector */ + +class Vec3f { + public static final Vec3f X_AXIS = new Vec3f( 1, 0, 0); + public static final Vec3f Y_AXIS = new Vec3f( 0, 1, 0); + public static final Vec3f Z_AXIS = new Vec3f( 0, 0, 1); + public static final Vec3f NEG_X_AXIS = new Vec3f(-1, 0, 0); + public static final Vec3f NEG_Y_AXIS = new Vec3f( 0, -1, 0); + public static final Vec3f NEG_Z_AXIS = new Vec3f( 0, 0, -1); + + private float x; + private float y; + private float z; + + public Vec3f() {} + + public Vec3f(Vec3f arg) { + set(arg); + } + + public Vec3f(float x, float y, float z) { + set(x, y, z); + } + + public Vec3f copy() { + return new Vec3f(this); + } + + public void set(Vec3f arg) { + set(arg.x, arg.y, arg.z); + } + + public void set(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** Sets the ith component, 0 <= i < 3 */ + public void set(int i, float val) { + switch (i) { + case 0: x = val; break; + case 1: y = val; break; + case 2: z = val; break; + default: throw new IndexOutOfBoundsException(); + } + } + + /** Gets the ith component, 0 <= i < 3 */ + public float get(int i) { + switch (i) { + case 0: return x; + case 1: return y; + case 2: return z; + default: throw new IndexOutOfBoundsException(); + } + } + + public float x() { return x; } + public float y() { return y; } + public float z() { return z; } + + public void setX(float x) { this.x = x; } + public void setY(float y) { this.y = y; } + public void setZ(float z) { this.z = z; } + + public float dot(Vec3f arg) { + return x * arg.x + y * arg.y + z * arg.z; + } + + public float length() { + return (float) Math.sqrt(lengthSquared()); + } + + public float lengthSquared() { + return this.dot(this); + } + + public void normalize() { + float len = length(); + if (len == 0.0f) return; + scale(1.0f / len); + } + + /** Returns this * val; creates new vector */ + public Vec3f times(float val) { + Vec3f tmp = new Vec3f(this); + tmp.scale(val); + return tmp; + } + + /** this = this * val */ + public void scale(float val) { + x *= val; + y *= val; + z *= val; + } + + /** Returns this + arg; creates new vector */ + public Vec3f plus(Vec3f arg) { + Vec3f tmp = new Vec3f(); + tmp.add(this, arg); + return tmp; + } + + /** this = this + b */ + public void add(Vec3f b) { + add(this, b); + } + + /** this = a + b */ + public void add(Vec3f a, Vec3f b) { + x = a.x + b.x; + y = a.y + b.y; + z = a.z + b.z; + } + + /** Returns this + s * arg; creates new vector */ + public Vec3f addScaled(float s, Vec3f arg) { + Vec3f tmp = new Vec3f(); + tmp.addScaled(this, s, arg); + return tmp; + } + + /** this = a + s * b */ + public void addScaled(Vec3f a, float s, Vec3f b) { + x = a.x + s * b.x; + y = a.y + s * b.y; + z = a.z + s * b.z; + } + + /** Returns this - arg; creates new vector */ + public Vec3f minus(Vec3f arg) { + Vec3f tmp = new Vec3f(); + tmp.sub(this, arg); + return tmp; + } + + /** this = this - b */ + public void sub(Vec3f b) { + sub(this, b); + } + + /** this = a - b */ + public void sub(Vec3f a, Vec3f b) { + x = a.x - b.x; + y = a.y - b.y; + z = a.z - b.z; + } + + /** Returns this cross arg; creates new vector */ + public Vec3f cross(Vec3f arg) { + Vec3f tmp = new Vec3f(); + tmp.cross(this, arg); + return tmp; + } + + /** this = a cross b. NOTE: "this" must be a different vector than + both a and b. */ + public void cross(Vec3f a, Vec3f b) { + x = a.y * b.z - a.z * b.y; + y = a.z * b.x - a.x * b.z; + z = a.x * b.y - a.y * b.x; + } + + /** Sets each component of this vector to the product of the + component with the corresponding component of the argument + vector. */ + public void componentMul(Vec3f arg) { + x *= arg.x; + y *= arg.y; + z *= arg.z; + } + + public String toString() { + return "(" + x + ", " + y + ", " + z + ")"; + } +} diff --git a/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Audio.java b/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Audio.java deleted file mode 100755 index fe77c7c48..000000000 --- a/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Audio.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - */ - -package com.jogamp.javafx.audio.windows.waveout; - -import java.io.*; - -public class Audio { - private static Audio instance = null; - private Mixer mixer; - - public synchronized static Audio getInstance() { - if (instance == null) { - instance = new Audio(); - } - return instance; - } - - private Audio() { - mixer = Mixer.getMixer(); - } - - public Mixer getMixer() { - return mixer; - } - - public Track newTrack(File file) throws IOException - { - Track res = new Track(file); - mixer.add(res); - return res; - } - - public void shutdown() { - mixer.shutdown(); - } -} diff --git a/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Mixer.java b/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Mixer.java deleted file mode 100755 index 59877052f..000000000 --- a/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Mixer.java +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - */ - -package com.jogamp.javafx.audio.windows.waveout; - -import java.io.*; -import java.nio.*; -import java.util.*; - -// Needed only for NIO workarounds on CVM -import java.lang.reflect.*; - -public class Mixer { - // This class is a singleton - private static Mixer mixer; - - private volatile boolean shutdown; - private volatile Object shutdownLock = new Object(); - private volatile boolean shutdownDone; - - // Windows Event object - private long event; - - private volatile ArrayList/**/ tracks = new ArrayList(); - - private Vec3f leftSpeakerPosition = new Vec3f(-1, 0, 0); - private Vec3f rightSpeakerPosition = new Vec3f( 1, 0, 0); - - private float falloffFactor = 1.0f; - - static { - mixer = new Mixer(); - } - - private Mixer() { - event = CreateEvent(); - new FillerThread().start(); - MixerThread m = new MixerThread(); - m.setPriority(Thread.MAX_PRIORITY - 1); - m.start(); - } - - public static Mixer getMixer() { - return mixer; - } - - synchronized void add(Track track) { - ArrayList/**/ newTracks = (ArrayList) tracks.clone(); - newTracks.add(track); - tracks = newTracks; - } - - synchronized void remove(Track track) { - ArrayList/**/ newTracks = (ArrayList) tracks.clone(); - newTracks.remove(track); - tracks = newTracks; - } - - // NOTE: due to a bug on the APX device, we only have mono sounds, - // so we currently only pay attention to the position of the left - // speaker - public void setLeftSpeakerPosition(float x, float y, float z) { - leftSpeakerPosition.set(x, y, z); - } - - // NOTE: due to a bug on the APX device, we only have mono sounds, - // so we currently only pay attention to the position of the left - // speaker - public void setRightSpeakerPosition(float x, float y, float z) { - rightSpeakerPosition.set(x, y, z); - } - - /** This defines a scale factor of sorts -- the higher the number, - the larger an area the sound will affect. Default value is - 1.0f. Valid values are [1.0f, ...]. The formula for the gain - for each channel is -
-     falloffFactor
-  -------------------
-  falloffFactor + r^2
-
-*/ - public void setFalloffFactor(float factor) { - falloffFactor = factor; - } - - public void shutdown() { - synchronized(shutdownLock) { - shutdown = true; - SetEvent(event); - try { - shutdownLock.wait(); - } catch (InterruptedException e) { - } - } - } - - class FillerThread extends Thread { - FillerThread() { - super("Mixer Thread"); - } - - public void run() { - while (!shutdown) { - List/**/ curTracks = tracks; - - for (Iterator iter = curTracks.iterator(); iter.hasNext(); ) { - Track track = (Track) iter.next(); - try { - track.fill(); - } catch (IOException e) { - e.printStackTrace(); - remove(track); - } - } - - try { - // Run ten times per second - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - - class MixerThread extends Thread { - // Temporary mixing buffer - // Interleaved left and right channels - float[] mixingBuffer; - private Vec3f temp = new Vec3f(); - - MixerThread() { - super("Mixer Thread"); - if (!initializeWaveOut(event)) { - throw new InternalError("Error initializing waveout device"); - } - } - - public void run() { - while (!shutdown) { - // Get the next buffer - long mixerBuffer = getNextMixerBuffer(); - if (mixerBuffer != 0) { - ByteBuffer buf = getMixerBufferData(mixerBuffer); - - if (buf == null) { - // This is happening on CVM because - // JNI_NewDirectByteBuffer isn't implemented - // by default and isn't compatible with the - // JSR-239 NIO implementation (apparently) - buf = newDirectByteBuffer(getMixerBufferDataAddress(mixerBuffer), - getMixerBufferDataCapacity(mixerBuffer)); - } - - if (buf == null) { - throw new InternalError("Couldn't wrap the native address with a direct byte buffer"); - } - - // System.out.println("Mixing buffer"); - - // If we don't have enough samples in our mixing buffer, expand it - // FIXME: knowledge of native output rendering format - if ((mixingBuffer == null) || (mixingBuffer.length < (buf.capacity() / 2 /* bytes / sample */))) { - mixingBuffer = new float[buf.capacity() / 2]; - } else { - // Zap it - for (int i = 0; i < mixingBuffer.length; i++) { - mixingBuffer[i] = 0.0f; - } - } - - // This assertion should be in place if we have stereo - if ((mixingBuffer.length % 2) != 0) { - String msg = "FATAL ERROR: odd number of samples in the mixing buffer"; - System.out.println(msg); - throw new InternalError(msg); - } - - // Run down all of the registered tracks mixing them in - List/**/ curTracks = tracks; - - for (Iterator iter = curTracks.iterator(); iter.hasNext(); ) { - Track track = (Track) iter.next(); - // Consider only playing tracks - if (track.isPlaying()) { - // First recompute its gain - Vec3f pos = track.getPosition(); - float leftGain = gain(pos, leftSpeakerPosition); - float rightGain = gain(pos, rightSpeakerPosition); - // Now mix it in - int i = 0; - while (i < mixingBuffer.length) { - if (track.hasNextSample()) { - float sample = track.nextSample(); - mixingBuffer[i++] = sample * leftGain; - mixingBuffer[i++] = sample * rightGain; - } else { - // This allows tracks to stall without being abruptly cancelled - if (track.done()) { - remove(track); - } - break; - } - } - } - } - - // Now that we have our data, send it down to the card - int outPos = 0; - for (int i = 0; i < mixingBuffer.length; i++) { - short val = (short) mixingBuffer[i]; - buf.put(outPos++, (byte) val); - buf.put(outPos++, (byte) (val >> 8)); - } - if (!prepareMixerBuffer(mixerBuffer)) { - throw new RuntimeException("Error preparing mixer buffer"); - } - if (!writeMixerBuffer(mixerBuffer)) { - throw new RuntimeException("Error writing mixer buffer to device"); - } - } else { - // System.out.println("No mixer buffer available"); - - // Wait for a buffer to become available - if (!WaitForSingleObject(event)) { - throw new RuntimeException("Error while waiting for event object"); - } - - /* - try { - Thread.sleep(10); - } catch (InterruptedException e) { - } - */ - } - } - - // Need to shut down - shutdownWaveOut(); - synchronized(shutdownLock) { - shutdownLock.notifyAll(); - } - } - - // This defines the 3D spatialization gain function. - // The function is defined as: - // falloffFactor - // ------------------- - // falloffFactor + r^2 - private float gain(Vec3f pos, Vec3f speakerPos) { - temp.sub(pos, speakerPos); - float dotp = temp.dot(temp); - return (falloffFactor / (falloffFactor + dotp)); - } - } - - // Initializes waveout device - private static native boolean initializeWaveOut(long eventObject); - // Shuts down waveout device - private static native void shutdownWaveOut(); - - // Gets the next (opaque) buffer of data to fill from the native - // code, or 0 if none was available yet (it should not happen that - // none is available the way the code is written). - private static native long getNextMixerBuffer(); - // Gets the next ByteBuffer to fill out of the mixer buffer. It - // requires interleaved left and right channel samples, 16 signed - // bits per sample, little endian. Implicit 44.1 kHz sample rate. - private static native ByteBuffer getMixerBufferData(long mixerBuffer); - // We need these to work around the lack of - // JNI_NewDirectByteBuffer in CVM + the JSR 239 NIO classes - private static native long getMixerBufferDataAddress(long mixerBuffer); - private static native int getMixerBufferDataCapacity(long mixerBuffer); - // Prepares this mixer buffer for writing to the device. - private static native boolean prepareMixerBuffer(long mixerBuffer); - // Writes this mixer buffer to the device. - private static native boolean writeMixerBuffer(long mixerBuffer); - - // Helpers to prevent mixer thread from busy waiting - private static native long CreateEvent(); - private static native boolean WaitForSingleObject(long event); - private static native void SetEvent(long event); - private static native void CloseHandle(long handle); - - // We need a reflective hack to wrap a direct ByteBuffer around - // the native memory because JNI_NewDirectByteBuffer doesn't work - // in CVM + JSR-239 NIO - private static Class directByteBufferClass; - private static Constructor directByteBufferConstructor; - private static Map createdBuffers = new HashMap(); // Map Long, ByteBuffer - - private static ByteBuffer newDirectByteBuffer(long address, long capacity) { - Long key = new Long(address); - ByteBuffer buf = (ByteBuffer) createdBuffers.get(key); - if (buf == null) { - buf = newDirectByteBufferImpl(address, capacity); - if (buf != null) { - createdBuffers.put(key, buf); - } - } - return buf; - } - private static ByteBuffer newDirectByteBufferImpl(long address, long capacity) { - if (directByteBufferClass == null) { - try { - directByteBufferClass = Class.forName("java.nio.DirectByteBuffer"); - byte[] tmp = new byte[0]; - directByteBufferConstructor = - directByteBufferClass.getDeclaredConstructor(new Class[] { Integer.TYPE, - tmp.getClass(), - Integer.TYPE }); - directByteBufferConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - } - - if (directByteBufferConstructor != null) { - try { - return (ByteBuffer) - directByteBufferConstructor.newInstance(new Object[] { - new Integer((int) capacity), - null, - new Integer((int) address) - }); - } catch (Exception e) { - e.printStackTrace(); - } - } - return null; - } -} diff --git a/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/SoundBuffer.java b/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/SoundBuffer.java deleted file mode 100755 index 6b75450eb..000000000 --- a/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/SoundBuffer.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - */ - -package com.jogamp.javafx.audio.windows.waveout; - -import java.io.*; - -class SoundBuffer { - private byte[] data; - private boolean needsByteSwap; - private int numBytes; - private int bytesPerSample; - private int numSamples; - private boolean playing; - private boolean empty; - - // Note: needsByteSwap argument makes assumptions about the format - SoundBuffer(int size, int bytesPerSample, boolean needsByteSwap) { - this.bytesPerSample = bytesPerSample; - this.needsByteSwap = needsByteSwap; - data = new byte[size * bytesPerSample]; - empty = true; - } - - boolean playing() { - return playing; - } - - void playing(boolean playing) { - this.playing = playing; - } - - boolean empty() { - return empty; - } - - void empty(boolean empty) { - this.empty = empty; - } - - void fill(InputStream input) throws IOException { - synchronized(this) { - if (playing) { - throw new IllegalStateException("Can not fill a buffer that is playing"); - } - } - - empty(true); - int num = input.read(data); - if (num > 0) { - numBytes = num; - numSamples = numBytes / bytesPerSample; - empty(false); - if ((numBytes % bytesPerSample) != 0) { - System.out.println("WARNING: needed integral multiple of " + bytesPerSample + - " bytes, but read " + numBytes + " bytes"); - } - } else { - numBytes = 0; - } - } - - int numSamples() { - return numSamples; - } - - // This is called by the mixer and must be extremely fast - // FIXME: may want to reconsider use of floating point at this point - // FIXME: assumes all sounds are of the same format to avoid normalization - float getSample(int sample) { - int startByte = sample * bytesPerSample; - // FIXME: assumes no more than 4 bytes per sample - int res = 0; - if (needsByteSwap) { - for (int i = startByte + bytesPerSample - 1; i >= startByte; i--) { - res <<= 8; - res |= (data[i] & 0xff); - } - } else { - int endByte = startByte + bytesPerSample - 1; - for (int i = startByte; i <= endByte; i++) { - res <<= 8; - res |= (data[i] & 0xff); - } - } - // Sign extend - if (bytesPerSample == 2) { - res = (short) res; - } else if (bytesPerSample == 1) { - res = (byte) res; - } - - return (float) res; - } -} diff --git a/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/TestSpatialization.java b/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/TestSpatialization.java deleted file mode 100755 index 38e3bb808..000000000 --- a/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/TestSpatialization.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - */ - -package com.jogamp.javafx.audio.windows.waveout; - -import java.io.*; -import javax.media.nativewindow.NativeWindow; -import javax.media.opengl.GLDrawableFactory; - -public class TestSpatialization { - public static void main(String[] args) { - if (args.length != 1) { - System.out.println("Usage: TestSpatialization [file name]"); - System.exit(1); - } - - try { - // FIXME: this is a hack to get the native library loaded - try { - GLDrawableFactory.getFactory(NativeWindow.class); - } catch (Exception e) {} - // Initialize the audio subsystem - Audio audio = Audio.getInstance(); - // Create a track - Track track = audio.newTrack(new File(args[0])); - track.setPosition(1, 0, 0); - // Run for ten seconds - long startTime = System.currentTimeMillis(); - long duration = 10000; - long curTime = 0; - try { - Thread.sleep(500); - } catch (InterruptedException e) { - } - System.out.println("Playing..."); - track.setLooping(true); - track.play(); - while ((curTime = System.currentTimeMillis()) < startTime + duration) { - // Make one revolution every two seconds - float rads = (float) (((2 * Math.PI) * (((float) (curTime - startTime)) / 1000.0f)) / 2); - track.setPosition((float) Math.cos(rads), 0, (float) Math.sin(rads)); - // Would like to make it go in a circle, but since - // stereo doesn't work now, make it move along a line - // track.setPosition(-1.0f, 0, 2.0f * (float) Math.sin(rads)); - // Sleep a little between updates - try { - Thread.sleep(10); - } catch (InterruptedException e) { - } - } - System.out.println("Shutting down audio subsystem"); - audio.shutdown(); - System.out.println("Exiting."); - System.exit(0); - } catch (Exception e) { - e.printStackTrace(); - System.exit(1); - } - } -} diff --git a/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Track.java b/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Track.java deleted file mode 100755 index 40c39e755..000000000 --- a/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Track.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - */ - -package com.jogamp.javafx.audio.windows.waveout; - -import java.io.*; -import java.nio.*; - -public class Track { - // Default number of samples per buffer - private static final int BUFFER_SIZE = 32768; - // Number of bytes per sample (FIXME: dependence on audio format) - static final int BYTES_PER_SAMPLE = 2; - // Whether we need byte swapping (FIXME: dependence on audio format) - static final boolean NEEDS_BYTE_SWAP = true; - - // This is the buffer this track is currently playing from - private SoundBuffer activeBuffer; - // This is the sample position in the active buffer - private int samplePosition; - // This is the total number of samples in the file - private int totalSamples; - // This is the total number of samples we have read - private int samplesRead; - // This is the buffer that the background filler thread may be filling - private SoundBuffer fillingBuffer; - // If we're playing the file, this is its input stream - private InputStream input; - // Keep around the file name - private File file; - // Whether we're playing this sound - private boolean playing; - // Whether we're looping this sound - private boolean looping; - // The position of this sound; defaults to being at the origin - private volatile Vec3f position = new Vec3f(); - - Track(File file) throws IOException { - if (!file.getName().endsWith(".rawsound")) { - throw new IOException("Unsupported file format (currently supports only raw sounds)"); - } - - this.file = file; - openInput(); - - // Allocate the buffers - activeBuffer = new SoundBuffer(BUFFER_SIZE, BYTES_PER_SAMPLE, NEEDS_BYTE_SWAP); - fillingBuffer = new SoundBuffer(BUFFER_SIZE, BYTES_PER_SAMPLE, NEEDS_BYTE_SWAP); - - // Fill the first buffer immediately - fill(); - swapBuffers(); - } - - private void openInput() throws IOException { - input = new BufferedInputStream(new FileInputStream(file)); - totalSamples = (int) file.length() / BYTES_PER_SAMPLE; - } - - public File getFile() { - return file; - } - - public synchronized void play() { - if (input == null) { - try { - openInput(); - // Fill it immediately - fill(); - } catch (IOException e) { - e.printStackTrace(); - return; - } - } - - playing = true; - } - - public synchronized boolean isPlaying() { - return playing; - } - - public synchronized void setLooping(boolean looping) { - this.looping = looping; - } - - public synchronized boolean isLooping() { - return looping; - } - - public void setPosition(float x, float y, float z) { - position = new Vec3f(x, y, z); - } - - synchronized void fill() throws IOException { - if (input == null) { - return; - } - SoundBuffer curBuffer = fillingBuffer; - if (!curBuffer.empty()) { - return; - } - curBuffer.fill(input); - if (curBuffer.empty()) { - // End of file - InputStream tmp = null; - synchronized(this) { - tmp = input; - input = null; - } - tmp.close(); - - // If looping, re-open - if (isLooping()) { - openInput(); - // and fill - fill(); - } - } - } - - // These are only for use by the Mixer - private float leftGain; - private float rightGain; - - void setLeftGain(float leftGain) { - this.leftGain = leftGain; - } - - float getLeftGain() { - return leftGain; - } - - void setRightGain(float rightGain) { - this.rightGain = rightGain; - } - - float getRightGain() { - return rightGain; - } - - Vec3f getPosition() { - return position; - } - - // This is called by the mixer and must be extremely fast - // Note this assumes mono sounds (FIXME) - boolean hasNextSample() { - return (!activeBuffer.empty() && samplePosition < activeBuffer.numSamples()); - } - - // This is called by the mixer and must be extremely fast - float nextSample() { - float res = activeBuffer.getSample(samplePosition++); - ++samplesRead; - if (!hasNextSample()) { - swapBuffers(); - samplePosition = 0; - if (done()) { - playing = false; - } - } - return res; - } - - synchronized void swapBuffers() { - SoundBuffer tmp = activeBuffer; - activeBuffer = fillingBuffer; - fillingBuffer = tmp; - fillingBuffer.empty(true); - } - - // This provides a more robust termination condition - boolean done() { - return (samplesRead == totalSamples) && !looping; - } -} diff --git a/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Vec3f.java b/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Vec3f.java deleted file mode 100755 index 5b480a513..000000000 --- a/src/jogl/classes/com/jogamp/javafx/audio/windows/waveout/Vec3f.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - */ - -package com.jogamp.javafx.audio.windows.waveout; - -/** 3-element single-precision vector */ - -class Vec3f { - public static final Vec3f X_AXIS = new Vec3f( 1, 0, 0); - public static final Vec3f Y_AXIS = new Vec3f( 0, 1, 0); - public static final Vec3f Z_AXIS = new Vec3f( 0, 0, 1); - public static final Vec3f NEG_X_AXIS = new Vec3f(-1, 0, 0); - public static final Vec3f NEG_Y_AXIS = new Vec3f( 0, -1, 0); - public static final Vec3f NEG_Z_AXIS = new Vec3f( 0, 0, -1); - - private float x; - private float y; - private float z; - - public Vec3f() {} - - public Vec3f(Vec3f arg) { - set(arg); - } - - public Vec3f(float x, float y, float z) { - set(x, y, z); - } - - public Vec3f copy() { - return new Vec3f(this); - } - - public void set(Vec3f arg) { - set(arg.x, arg.y, arg.z); - } - - public void set(float x, float y, float z) { - this.x = x; - this.y = y; - this.z = z; - } - - /** Sets the ith component, 0 <= i < 3 */ - public void set(int i, float val) { - switch (i) { - case 0: x = val; break; - case 1: y = val; break; - case 2: z = val; break; - default: throw new IndexOutOfBoundsException(); - } - } - - /** Gets the ith component, 0 <= i < 3 */ - public float get(int i) { - switch (i) { - case 0: return x; - case 1: return y; - case 2: return z; - default: throw new IndexOutOfBoundsException(); - } - } - - public float x() { return x; } - public float y() { return y; } - public float z() { return z; } - - public void setX(float x) { this.x = x; } - public void setY(float y) { this.y = y; } - public void setZ(float z) { this.z = z; } - - public float dot(Vec3f arg) { - return x * arg.x + y * arg.y + z * arg.z; - } - - public float length() { - return (float) Math.sqrt(lengthSquared()); - } - - public float lengthSquared() { - return this.dot(this); - } - - public void normalize() { - float len = length(); - if (len == 0.0f) return; - scale(1.0f / len); - } - - /** Returns this * val; creates new vector */ - public Vec3f times(float val) { - Vec3f tmp = new Vec3f(this); - tmp.scale(val); - return tmp; - } - - /** this = this * val */ - public void scale(float val) { - x *= val; - y *= val; - z *= val; - } - - /** Returns this + arg; creates new vector */ - public Vec3f plus(Vec3f arg) { - Vec3f tmp = new Vec3f(); - tmp.add(this, arg); - return tmp; - } - - /** this = this + b */ - public void add(Vec3f b) { - add(this, b); - } - - /** this = a + b */ - public void add(Vec3f a, Vec3f b) { - x = a.x + b.x; - y = a.y + b.y; - z = a.z + b.z; - } - - /** Returns this + s * arg; creates new vector */ - public Vec3f addScaled(float s, Vec3f arg) { - Vec3f tmp = new Vec3f(); - tmp.addScaled(this, s, arg); - return tmp; - } - - /** this = a + s * b */ - public void addScaled(Vec3f a, float s, Vec3f b) { - x = a.x + s * b.x; - y = a.y + s * b.y; - z = a.z + s * b.z; - } - - /** Returns this - arg; creates new vector */ - public Vec3f minus(Vec3f arg) { - Vec3f tmp = new Vec3f(); - tmp.sub(this, arg); - return tmp; - } - - /** this = this - b */ - public void sub(Vec3f b) { - sub(this, b); - } - - /** this = a - b */ - public void sub(Vec3f a, Vec3f b) { - x = a.x - b.x; - y = a.y - b.y; - z = a.z - b.z; - } - - /** Returns this cross arg; creates new vector */ - public Vec3f cross(Vec3f arg) { - Vec3f tmp = new Vec3f(); - tmp.cross(this, arg); - return tmp; - } - - /** this = a cross b. NOTE: "this" must be a different vector than - both a and b. */ - public void cross(Vec3f a, Vec3f b) { - x = a.y * b.z - a.z * b.y; - y = a.z * b.x - a.x * b.z; - z = a.x * b.y - a.y * b.x; - } - - /** Sets each component of this vector to the product of the - component with the corresponding component of the argument - vector. */ - public void componentMul(Vec3f arg) { - x *= arg.x; - y *= arg.y; - z *= arg.z; - } - - public String toString() { - return "(" + x + ", " + y + ", " + z + ")"; - } -} -- cgit v1.2.3