33package com.jogamp.audio.windows.waveout;
39import com.jogamp.common.util.InterruptSource;
40import com.jogamp.common.util.InterruptedRuntimeException;
43import java.lang.reflect.*;
47 private static Mixer mixer;
49 volatile boolean fillerAlive;
50 volatile boolean mixerAlive;
51 volatile boolean shutdown;
52 volatile Object shutdownLock =
new Object();
55 private final long event;
57 private volatile ArrayList<Track> tracks =
new ArrayList<Track>();
59 private final Vec3f leftSpeakerPosition =
new Vec3f(-1, 0, 0);
60 private final Vec3f rightSpeakerPosition =
new Vec3f( 1, 0, 0);
62 private float falloffFactor = 1.0f;
69 event = CreateEvent();
73 new FillerThread().start();
74 final MixerThread m =
new MixerThread();
75 m.setPriority(Thread.MAX_PRIORITY - 1);
83 synchronized void add(
final Track track) {
84 final ArrayList<Track> newTracks =
new ArrayList<Track>(tracks);
89 synchronized void remove(
final Track track) {
90 final ArrayList<Track> newTracks =
new ArrayList<Track>(tracks);
91 newTracks.remove(track);
99 leftSpeakerPosition.set(x, y, z);
106 rightSpeakerPosition.set(x, y, z);
120 falloffFactor = factor;
124 synchronized(shutdownLock) {
128 while(fillerAlive || mixerAlive) {
131 }
catch (
final InterruptedException e) {
132 throw new InterruptedRuntimeException(e);
137 class FillerThread
extends InterruptSource.Thread {
139 super(
null,
null,
"Mixer Thread");
147 final List<Track> curTracks = tracks;
149 for (
final Iterator<Track> iter = curTracks.iterator(); iter.hasNext(); ) {
150 final Track track = iter.next();
153 }
catch (
final IOException e) {
160 java.lang.Thread.sleep(100);
161 }
catch (
final InterruptedException e) {
162 throw new InterruptedRuntimeException(e);
171 class MixerThread
extends InterruptSource.Thread {
174 float[] mixingBuffer;
175 private final Vec3f temp =
new Vec3f();
178 super(
null,
null,
"Mixer Thread");
179 if (!initializeWaveOut(event)) {
180 throw new InternalError(
"Error initializing waveout device");
190 final long mixerBuffer = getNextMixerBuffer();
191 if (mixerBuffer != 0) {
192 ByteBuffer buf = getMixerBufferData(mixerBuffer);
199 buf = newDirectByteBuffer(getMixerBufferDataAddress(mixerBuffer),
200 getMixerBufferDataCapacity(mixerBuffer));
204 throw new InternalError(
"Couldn't wrap the native address with a direct byte buffer");
211 if ((mixingBuffer ==
null) || (mixingBuffer.length < (buf.capacity() / 2 ))) {
212 mixingBuffer =
new float[buf.capacity() / 2];
215 for (
int i = 0; i < mixingBuffer.length; i++) {
216 mixingBuffer[i] = 0.0f;
221 if ((mixingBuffer.length % 2) != 0) {
222 final String msg =
"FATAL ERROR: odd number of samples in the mixing buffer";
223 System.out.println(msg);
224 throw new InternalError(msg);
228 final List<Track> curTracks = tracks;
230 for (
final Iterator<Track> iter = curTracks.iterator(); iter.hasNext(); ) {
231 final Track track = iter.next();
233 if (track.isPlaying()) {
235 final Vec3f pos = track.getPosition();
236 final float leftGain = gain(pos, leftSpeakerPosition);
237 final float rightGain = gain(pos, rightSpeakerPosition);
240 while (i < mixingBuffer.length) {
241 if (track.hasNextSample()) {
242 final float sample = track.nextSample();
243 mixingBuffer[i++] = sample * leftGain;
244 mixingBuffer[i++] = sample * rightGain;
258 for (
int i = 0; i < mixingBuffer.length; i++) {
259 final short val = (short) mixingBuffer[i];
260 buf.put(outPos++, (
byte) val);
261 buf.put(outPos++, (
byte) (val >> 8));
263 if (!prepareMixerBuffer(mixerBuffer)) {
264 throw new RuntimeException(
"Error preparing mixer buffer");
266 if (!writeMixerBuffer(mixerBuffer)) {
267 throw new RuntimeException(
"Error writing mixer buffer to device");
273 if (!WaitForSingleObject(event)) {
274 throw new RuntimeException(
"Error while waiting for event object");
290 synchronized(shutdownLock) {
291 shutdownLock.notifyAll();
301 private float gain(
final Vec3f pos,
final Vec3f speakerPos) {
302 temp.sub(pos, speakerPos);
303 final float dotp = temp.dot(temp);
304 return (falloffFactor / (falloffFactor + dotp));
309 private static native
boolean initializeWaveOut(
long eventObject);
311 private static native
void shutdownWaveOut();
316 private static native
long getNextMixerBuffer();
320 private static native ByteBuffer getMixerBufferData(
long mixerBuffer);
323 private static native
long getMixerBufferDataAddress(
long mixerBuffer);
324 private static native
int getMixerBufferDataCapacity(
long mixerBuffer);
326 private static native
boolean prepareMixerBuffer(
long mixerBuffer);
328 private static native
boolean writeMixerBuffer(
long mixerBuffer);
331 private static native
long CreateEvent();
332 private static native
boolean WaitForSingleObject(
long event);
333 private static native
void SetEvent(
long event);
334 private static native
void CloseHandle(
long handle);
339 private static Class directByteBufferClass;
340 private static Constructor directByteBufferConstructor;
341 private static Map createdBuffers =
new HashMap();
343 private static ByteBuffer newDirectByteBuffer(
final long address,
final long capacity) {
344 final Long key = Long.valueOf(address);
345 ByteBuffer buf = (ByteBuffer) createdBuffers.get(key);
347 buf = newDirectByteBufferImpl(address, capacity);
349 createdBuffers.put(key, buf);
354 private static ByteBuffer newDirectByteBufferImpl(
final long address,
final long capacity) {
355 if (directByteBufferClass ==
null) {
357 directByteBufferClass = Class.forName(
"java.nio.DirectByteBuffer");
358 final byte[] tmp =
new byte[0];
359 directByteBufferConstructor =
360 directByteBufferClass.getDeclaredConstructor(
new Class[] { Integer.TYPE,
363 directByteBufferConstructor.setAccessible(
true);
364 }
catch (
final Exception e) {
369 if (directByteBufferConstructor !=
null) {
372 directByteBufferConstructor.newInstance(
new Object[] {
373 Integer.valueOf((
int) capacity),
375 Integer.valueOf((
int) address)
377 }
catch (
final Exception e) {
void setRightSpeakerPosition(final float x, final float y, final float z)
void setFalloffFactor(final float factor)
This defines a scale factor of sorts – the higher the number, the larger an area the sound will affec...
void setLeftSpeakerPosition(final float x, final float y, final float z)