FMusic done, including callbacks!

Added synctest to fmod, showing how to use FMusic
This commit is contained in:
Brian Matzon 2004-05-31 12:42:09 +00:00
parent 9c8ac5d794
commit 5803d98ddc
9 changed files with 633 additions and 167 deletions

View file

@ -33,9 +33,12 @@ package org.lwjgl.fmod;
import java.io.File;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.StringTokenizer;
import org.lwjgl.Sys;
/**
* $Id$
* <br>
@ -45,7 +48,7 @@ import java.util.StringTokenizer;
public class FMOD {
/** Array of hashmaps for callbacks */
private static HashMap[] callbacks = new HashMap[14];
private static HashMap[] callbacks = new HashMap[17];
/** FMOD System level clear dsp unit */
static FSoundDSPUnit fmodClearUnit;
@ -66,46 +69,56 @@ public class FMOD {
static FloatBuffer fmodFFTBuffer;
/** Type defining the music callback entries in callback hashmap array */
public static final int FMUSIC_CALLBACK = 0;
public static final int FMUSIC_INSTCALLBACK = 0;
/** Type defining the music callback entries in callback hashmap array */
public static final int FMUSIC_ORDERCALLBACK = 1;
/** Type defining the music callback entries in callback hashmap array */
public static final int FMUSIC_ROWCALLBACK = 2;
/** Type defining the music callback entries in callback hashmap array */
public static final int FMUSIC_ZXXCALLBACK = 3;
/** Type defining the dsp callback entries in callback hashmap array */
public static final int FSOUND_DSPCALLBACK = 1;
public static final int FSOUND_DSPCALLBACK = 4;
/** Type defining the stream callback entries in callback hashmap array */
public static final int FSOUND_STREAMCALLBACK = 2;
public static final int FSOUND_STREAMCALLBACK = 5;
/** Type defining the alloc callback entries in callback hashmap array */
public static final int FSOUND_ALLOCCALLBACK = 3;
public static final int FSOUND_ALLOCCALLBACK = 6;
/** Type defining the realloc callback entries in callback hashmap array */
public static final int FSOUND_REALLOCCALLBACK = 4;
public static final int FSOUND_REALLOCCALLBACK = 7;
/** Type defining the free callback entries in callback hashmap array */
public static final int FSOUND_FREECALLBACK = 5;
public static final int FSOUND_FREECALLBACK = 8;
/** Type defining the open callback entries in callback hashmap array */
public static final int FSOUND_OPENCALLBACK = 6;
public static final int FSOUND_OPENCALLBACK = 9;
/** Type defining the close callback entries in callback hashmap array */
public static final int FSOUND_CLOSECALLBACK = 7;
public static final int FSOUND_CLOSECALLBACK = 10;
/** Type defining the metadata callback entries in callback hashmap array */
public static final int FSOUND_METADATACALLBACK = 8;
public static final int FSOUND_METADATACALLBACK = 11;
/** Type defining the read callback entries in callback hashmap array */
public static final int FSOUND_READCALLBACK = 9;
public static final int FSOUND_READCALLBACK = 12;
/** Type defining the seek callback entries in callback hashmap array */
public static final int FSOUND_SEEKCALLBACK = 10;
public static final int FSOUND_SEEKCALLBACK = 13;
/** Type defining the tell callback entries in callback hashmap array */
public static final int FSOUND_TELLCALLBACK = 11;
public static final int FSOUND_TELLCALLBACK = 14;
/** Type defining the "end" callback entries in callback hashmap array */
public static final int FSOUND_ENDCALLBACK = 12;
public static final int FSOUND_ENDCALLBACK = 15;
/** Type defining the "sync" callback entries in callback hashmap array */
public static final int FSOUND_SYNCCALLBACK = 13;
public static final int FSOUND_SYNCCALLBACK = 16;
/** Have we been created? */
protected static boolean created;
@ -304,10 +317,23 @@ public class FMOD {
* @param callbackHandler Object to register as the call back handler
*/
static void registerCallback(int type, long handle, Object handled, Object callbackHandler) {
Long callbackID = new Long(handle);
ArrayList callbackList = (ArrayList) callbacks[type].get(callbackID);
if (callbackList == null ) {
if (callbackHandler == null) {
Sys.log("No callbackhandlers registered for handle: " + handle);
} else {
callbackList = new ArrayList();
callbacks[type].put(callbackID, callbackList);
}
}
// are we going to add or remove from the list?
if(callbackHandler == null) {
callbacks[type].remove(new Long(handle));
callbacks[type].remove(callbackID);
} else {
callbacks[type].put(new Long(handle), new FMOD.WrappedCallback(handled, callbackHandler));
callbackList.add(new FMOD.WrappedCallback(handled, callbackHandler));
}
}
@ -316,8 +342,8 @@ public class FMOD {
* @param handle Handle to native object being monitored
* @return Call back handler, or null if no such handler
*/
static WrappedCallback getCallback(int type, long handle) {
return (WrappedCallback) callbacks[type].get(new Long(handle));
static ArrayList getCallbacks(int type, long handle) {
return (ArrayList) callbacks[type].get(new Long(handle));
}
/**

View file

@ -32,7 +32,9 @@
package org.lwjgl.fmod;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.ArrayList;
import org.lwjgl.fmod.callbacks.FMusicCallback;
@ -107,27 +109,38 @@ public class FMusic {
* </i>
* </p>
*
* @param name_or_data Name of song or data containing song to load (if loading from memory and not file). On PlayStation 2 data must be 16 byte aligned if loading from memory
* @param data containing song to load. On PlayStation 2 data must be 16 byte aligned if loading from memory
* @param offset Optional. 0 by default. If > 0, this value is used to specify an offset in a file, so fmod will seek before opening
* @param length Optional. 0 by default. If > 0, this value is used to specify the length of a memory block when using FSOUND_LOADMEMORY, or it is the length of a file or file segment if the offset parameter is used. On PlayStation 2 this must be 16 byte aligned for memory loading
* @param mode Mode for opening song. With module files, only FSOUND_LOADMEMORY, FSOUND_NONBLOCKING, FSOUND_LOOP_NORMAL, or FSOUND_LOOP_OFF are supported. For FSB files, FSOUND_2D, FSOUND_HW3D, FSOUND_FORCEMONO also work
* @param sampleList Optional. Buffer of sample indicies to load. Leave as Null if you want all samples to be loaded (default behaviour). See Remarks for more on this
* @return On success, a FMusicModule instance is returned. On failure, Null is returned
*/
public static FMusicModule FMUSIC_LoadSongEx(ByteBuffer name_or_data, int offset, int length, int mode, IntBuffer sampleList) {
long result = 0;
if((mode & FSound.FSOUND_LOADMEMORY) == FSound.FSOUND_LOADMEMORY) {
result = nFMUSIC_LoadSongEx(name_or_data, name_or_data.position(), offset, length, mode, (sampleList != null) ? sampleList : null, (sampleList != null) ? sampleList.position() : 0, (sampleList != null) ? sampleList.remaining() : 0);
} else {
byte[] data = new byte[name_or_data.remaining()];
result = nFMUSIC_LoadSongEx(new String(data), offset, length, mode, (sampleList != null) ? sampleList : null, (sampleList != null) ? sampleList.position() : 0, (sampleList != null) ? sampleList.remaining() : 0);
}
public static FMusicModule FMUSIC_LoadSongEx(ByteBuffer data, int offset, int length, int mode, IntBuffer sampleList) {
long result = nFMUSIC_LoadSongEx(data, data.position(), offset, length, mode, (sampleList != null) ? sampleList : null, (sampleList != null) ? sampleList.position() : 0, (sampleList != null) ? sampleList.remaining() : 0);
if(result != FMUSIC_TYPE_NONE) {
return new FMusicModule(result);
}
return null;
}
/**
* @see #FMUSIC_LoadSongEx(ByteBuffer, int, int, int, IntBuffer)
* @param name of song
* @param offset Optional. 0 by default. If > 0, this value is used to specify an offset in a file, so fmod will seek before opening
* @param length Optional. 0 by default. If > 0, this value is used to specify the length of a memory block when using FSOUND_LOADMEMORY, or it is the length of a file or file segment if the offset parameter is used. On PlayStation 2 this must be 16 byte aligned for memory loading
* @param mode Mode for opening song. With module files, only FSOUND_LOADMEMORY, FSOUND_NONBLOCKING, FSOUND_LOOP_NORMAL, or FSOUND_LOOP_OFF are supported. For FSB files, FSOUND_2D, FSOUND_HW3D, FSOUND_FORCEMONO also work
* @param sampleList Optional. Buffer of sample indicies to load. Leave as Null if you want all samples to be loaded (default behaviour). See Remarks for more on this
* @return On success, a FMusicModule instance is returned. On failure, Null is returned
*/
public static FMusicModule FMUSIC_LoadSongEx(String name, int offset, int length, int mode, IntBuffer sampleList) {
long result = nFMUSIC_LoadSongEx(name, offset, length, mode, (sampleList != null) ? sampleList : null, (sampleList != null) ? sampleList.position() : 0, (sampleList != null) ? sampleList.remaining() : 0);
if(result != FMUSIC_TYPE_NONE) {
return new FMusicModule(result);
}
return null;
}
private static native long nFMUSIC_LoadSongEx(ByteBuffer data, int dataOffset, int offset, int length, int mode, IntBuffer sampleList, int bufferOffset, int remaining);
private static native long nFMUSIC_LoadSongEx(String name, int offset, int length, int mode, IntBuffer sampleList, int bufferOffset, int remaining);
@ -148,8 +161,10 @@ public class FMusic {
*/
public static boolean FMUSIC_FreeSong(FMusicModule module) {
// when freeing a song, we automatically deregister any callbacks
FMOD.registerCallback(FMOD.FMUSIC_CALLBACK, module.moduleHandle, null, null);
FMOD.registerCallback(FMOD.FMUSIC_INSTCALLBACK, module.moduleHandle, null, null);
FMOD.registerCallback(FMOD.FMUSIC_ORDERCALLBACK, module.moduleHandle, null, null);
FMOD.registerCallback(FMOD.FMUSIC_ROWCALLBACK, module.moduleHandle, null, null);
FMOD.registerCallback(FMOD.FMUSIC_ZXXCALLBACK, module.moduleHandle, null, null);
return nFMUSIC_FreeSong(module.moduleHandle);
}
private static native boolean nFMUSIC_FreeSong(long module);
@ -204,10 +219,10 @@ public class FMusic {
* @return On success, true is returned. On failure, false is returned
*/
public static boolean FMUSIC_SetZxxCallback(FMusicModule module, FMusicCallback callback) {
FMOD.registerCallback(FMOD.FMUSIC_CALLBACK, module.moduleHandle, module, callback);
return nFMUSIC_SetZxxCallback(module.moduleHandle, callback);
FMOD.registerCallback(FMOD.FMUSIC_ZXXCALLBACK, module.moduleHandle, module, callback);
return nFMUSIC_SetZxxCallback(module.moduleHandle);
}
private static native boolean nFMUSIC_SetZxxCallback(long module, FMusicCallback callback);
private static native boolean nFMUSIC_SetZxxCallback(long module);
/**
* Sets a user callback to occur on every row divisible by the rowstep parameter, played from a MOD, S3M, XM or IT file.
@ -231,10 +246,10 @@ public class FMusic {
* @return On success, true is returned. On failure, false is returned
*/
public static boolean FMUSIC_SetRowCallback(FMusicModule module, FMusicCallback callback, int rowstep) {
FMOD.registerCallback(FMOD.FMUSIC_CALLBACK, module.moduleHandle, module, callback);
return nFMUSIC_SetRowCallback(module.moduleHandle, callback, rowstep);
FMOD.registerCallback(FMOD.FMUSIC_ROWCALLBACK, module.moduleHandle, module, callback);
return nFMUSIC_SetRowCallback(module.moduleHandle, rowstep);
}
private static native boolean nFMUSIC_SetRowCallback(long module, FMusicCallback callback, int rowstep);
private static native boolean nFMUSIC_SetRowCallback(long module, int rowstep);
/**
* Sets a user callback to occur on every order divisible by the orderstep parameter, played from a MOD, S3M, XM or IT file
@ -258,10 +273,10 @@ public class FMusic {
* @return On success, true is returned. On failure, false is returned
*/
public static boolean FMUSIC_SetOrderCallback(FMusicModule module, FMusicCallback callback, int orderstep) {
FMOD.registerCallback(FMOD.FMUSIC_CALLBACK, module.moduleHandle, module, callback);
return nFMUSIC_SetOrderCallback(module.moduleHandle, callback, orderstep);
FMOD.registerCallback(FMOD.FMUSIC_ORDERCALLBACK, module.moduleHandle, module, callback);
return nFMUSIC_SetOrderCallback(module.moduleHandle, orderstep);
}
private static native boolean nFMUSIC_SetOrderCallback(long module, FMusicCallback callback, int orderstep);
private static native boolean nFMUSIC_SetOrderCallback(long module, int orderstep);
/**
* Sets a user callback to occur every time a instrument is played, triggered from a MOD, S3M, XM or IT file.
@ -285,10 +300,10 @@ public class FMusic {
* @return On success, true is returned. On failure, false is returned
*/
public static boolean FMUSIC_SetInstCallback(FMusicModule module, FMusicCallback callback, int instrument) {
FMOD.registerCallback(FMOD.FMUSIC_CALLBACK, module.moduleHandle, module, callback);
return nFMUSIC_SetInstCallback(module.moduleHandle, callback, instrument);
FMOD.registerCallback(FMOD.FMUSIC_INSTCALLBACK, module.moduleHandle, module, callback);
return nFMUSIC_SetInstCallback(module.moduleHandle, instrument);
}
private static native boolean nFMUSIC_SetInstCallback(long module, FMusicCallback callback, int instrument);
private static native boolean nFMUSIC_SetInstCallback(long module, int instrument);
/**
* Replaces a mod's sample with a sample definition specified.
@ -712,10 +727,12 @@ public class FMusic {
* @param module Module to get the open state from
* @return On success, userdata set by FMUSIC_SetUserData is returned. On failure, Null is returned.
*/
public static ByteBuffer FMUSIC_GetUserData(FMusicModule module) {
return nFMUSIC_GetUserData(module.moduleHandle);
public static ByteBuffer FMUSIC_GetUserData(FMusicModule module, int capacity) {
ByteBuffer buffer = nFMUSIC_GetUserData(module.moduleHandle, capacity);
buffer.order(ByteOrder.nativeOrder());
return buffer;
}
private static native ByteBuffer nFMUSIC_GetUserData(long module);
private static native ByteBuffer nFMUSIC_GetUserData(long module, int capacity);
/**
* This is the callback rutine called by the native implementation whenever a
@ -724,10 +741,64 @@ public class FMusic {
* @param handle Handle to native object being monitored
* @param param parameter passed to callback
*/
private static void music_callback(long modulehandle, int param) {
// locate out callback and call it back
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) FMOD.getCallback(FMOD.FSOUND_DSPCALLBACK, modulehandle);
FMusicCallback callback = (FMusicCallback) wCallback.callback;
callback.FMUSIC_CALLBACK((FMusicModule) wCallback.handled, param);
public static void music_instcallback(long modulehandle, int param) {
// we got a callback - notify everybody
ArrayList handlers = FMOD.getCallbacks(FMOD.FMUSIC_INSTCALLBACK, modulehandle);
for(int i=0; i<handlers.size(); i++) {
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) handlers.get(i);
FMusicCallback callback = (FMusicCallback) wCallback.callback;
callback.FMUSIC_CALLBACK((FMusicModule) wCallback.handled, param);
}
}
/**
* This is the callback rutine called by the native implementation whenever a
* register callback is notified.
*
* @param handle Handle to native object being monitored
* @param param parameter passed to callback
*/
public static void music_ordercallback(long modulehandle, int param) {
// we got a callback - notify everybody
ArrayList handlers = FMOD.getCallbacks(FMOD.FMUSIC_ORDERCALLBACK, modulehandle);
for(int i=0; i<handlers.size(); i++) {
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) handlers.get(i);
FMusicCallback callback = (FMusicCallback) wCallback.callback;
callback.FMUSIC_CALLBACK((FMusicModule) wCallback.handled, param);
}
}
/**
* This is the callback rutine called by the native implementation whenever a
* register callback is notified.
*
* @param handle Handle to native object being monitored
* @param param parameter passed to callback
*/
public static void music_rowcallback(long modulehandle, int param) {
// we got a callback - notify everybody
ArrayList handlers = FMOD.getCallbacks(FMOD.FMUSIC_ROWCALLBACK, modulehandle);
for(int i=0; i<handlers.size(); i++) {
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) handlers.get(i);
FMusicCallback callback = (FMusicCallback) wCallback.callback;
callback.FMUSIC_CALLBACK((FMusicModule) wCallback.handled, param);
}
}
/**
* This is the callback rutine called by the native implementation whenever a
* register callback is notified.
*
* @param handle Handle to native object being monitored
* @param param parameter passed to callback
*/
public static void music_zxxcallback(long modulehandle, int param) {
// we got a callback - notify everybody
ArrayList handlers = FMOD.getCallbacks(FMOD.FMUSIC_ZXXCALLBACK, modulehandle);
for(int i=0; i<handlers.size(); i++) {
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) handlers.get(i);
FMusicCallback callback = (FMusicCallback) wCallback.callback;
callback.FMUSIC_CALLBACK((FMusicModule) wCallback.handled, param);
}
}
}

View file

@ -34,6 +34,7 @@ package org.lwjgl.fmod;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import org.lwjgl.fmod.callbacks.FSoundCloseCallback;
import org.lwjgl.fmod.callbacks.FSoundDSPCallback;
@ -354,13 +355,18 @@ public class FSound {
public static void FSOUND_File_SetCallbacks(
FSoundOpenCallback open, FSoundCloseCallback close, FSoundReadCallback read,
FSoundSeekCallback seek, FSoundTellCallback tell) {
FMOD.registerCallback(FMOD.FSOUND_OPENCALLBACK, -1, null, open);
FMOD.registerCallback(FMOD.FSOUND_CLOSECALLBACK, -1, null, open);
FMOD.registerCallback(FMOD.FSOUND_READCALLBACK, -1, null, open);
FMOD.registerCallback(FMOD.FSOUND_SEEKCALLBACK, -1, null, open);
FMOD.registerCallback(FMOD.FSOUND_TELLCALLBACK, -1, null, open);
nFSOUND_File_SetCallbacks();
if(open != null && close != null && read != null && seek != null && tell != null) {
FMOD.registerCallback(FMOD.FSOUND_OPENCALLBACK, -1, null, open);
FMOD.registerCallback(FMOD.FSOUND_CLOSECALLBACK, -1, null, open);
FMOD.registerCallback(FMOD.FSOUND_READCALLBACK, -1, null, open);
FMOD.registerCallback(FMOD.FSOUND_SEEKCALLBACK, -1, null, open);
FMOD.registerCallback(FMOD.FSOUND_TELLCALLBACK, -1, null, open);
nFSOUND_File_SetCallbacks();
} else {
throw new IllegalArgumentException("Cannot supply null callback");
}
}
private static native void nFSOUND_File_SetCallbacks();
@ -922,26 +928,39 @@ public class FSound {
* 0 or above - The absolute index into the sample pool. The pool will grow as the index gets larger. If a slot is already used it will be replaced.
* FSOUND_FREE - Let FSOUND select an arbitrary sample slot.
* FSOUND_UNMANAGED - Dont have this sample managed within fsounds sample management system
* @param name_or_data Name of sound file or pointer to memory image to load.
* @param data ByteBuffer of memory image to load.
* @param inputmode Description of the data format, OR in the bits defined in FSOUND_MODES to describe the data being loaded.
* @param offset Optional. 0 by default. If > 0, this value is used to specify an offset in a file, so fmod will seek before opening. length must also be specified if this value is used.
* @param length Optional. 0 by default. If > 0, this value is used to specify the length of a memory block when using FSOUND_LOADMEMORY, or it is the length of a file or file segment if the offset parameter is used. On PlayStation 2 this must be 16 byte aligned for memory loading.
* @return On success, a sample is returned. On failure, NULL is returned.
*/
public static FSoundSample FSOUND_Sample_Load(int index, ByteBuffer name_or_data, int inputmode, int offset, int length) {
long result = 0;
if((inputmode & FSound.FSOUND_LOADMEMORY) == FSound.FSOUND_LOADMEMORY) {
result = nFSOUND_Sample_Load(index, name_or_data, name_or_data.position(), inputmode, offset, length);
} else {
byte[] data = new byte[name_or_data.remaining()];
result = nFSOUND_Sample_Load(index, new String(data), inputmode, offset, length);
}
public static FSoundSample FSOUND_Sample_Load(int index, ByteBuffer data, int inputmode, int offset, int length) {
long result = nFSOUND_Sample_Load(index, data, data.position(), inputmode, offset, length);
if(result != 0) {
return new FSoundSample(result);
}
return null;
}
/**
* @see #FSOUND_Sample_Load(int, ByteBuffer, int, int, int)
* @param index Sample pool index. See remarks for more on the sample pool.
* 0 or above - The absolute index into the sample pool. The pool will grow as the index gets larger. If a slot is already used it will be replaced.
* FSOUND_FREE - Let FSOUND select an arbitrary sample slot.
* FSOUND_UNMANAGED - Dont have this sample managed within fsounds sample management system
* @param name Name of sound file.
* @param inputmode Description of the data format, OR in the bits defined in FSOUND_MODES to describe the data being loaded.
* @param offset Optional. 0 by default. If > 0, this value is used to specify an offset in a file, so fmod will seek before opening. length must also be specified if this value is used.
* @param length Optional. 0 by default. If > 0, this value is used to specify the length of a memory block when using FSOUND_LOADMEMORY, or it is the length of a file or file segment if the offset parameter is used. On PlayStation 2 this must be 16 byte aligned for memory loading.
* @return On success, a sample is returned. On failure, NULL is returned.
*/
public static FSoundSample FSOUND_Sample_Load(int index, String name, int inputmode, int offset, int length) {
long result = nFSOUND_Sample_Load(index, name, inputmode, offset, length);
if(result != 0) {
return new FSoundSample(result);
}
return null;
}
private static native long nFSOUND_Sample_Load(int index, ByteBuffer data, int dataOffset, int inputmode, int offset, int length);
private static native long nFSOUND_Sample_Load(int index, String name, int inputmode, int offset, int length);
@ -3508,9 +3527,13 @@ public class FSound {
* @param param parameter passed to callback
*/
private static void dsp_callback(long dspHandle, ByteBuffer originalbuffer, ByteBuffer newbuffer, int length) {
// locate out callback and call it back
FSoundDSPCallback callback = (FSoundDSPCallback) ((FMOD.WrappedCallback) FMOD.getCallback(FMOD.FSOUND_DSPCALLBACK, dspHandle)).callback;
callback.FSOUND_DSPCALLBACK(originalbuffer, newbuffer, length);
// we got a callback - notify everybody
ArrayList handlers = FMOD.getCallbacks(FMOD.FSOUND_DSPCALLBACK, dspHandle);
for(int i=0; i<handlers.size(); i++) {
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) handlers.get(i);
FSoundDSPCallback callback = (FSoundDSPCallback) wCallback.callback;
callback.FSOUND_DSPCALLBACK(originalbuffer, newbuffer, length);
}
}
/**
@ -3521,10 +3544,13 @@ public class FSound {
* @param param parameter passed to callback
*/
private static void stream_callback(long streamHandle, ByteBuffer buff, int length) {
// locate out callback and call it back
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) FMOD.getCallback(FMOD.FSOUND_STREAMCALLBACK, streamHandle);
FSoundStreamCallback callback = (FSoundStreamCallback) wCallback.callback;
callback.FSOUND_STREAMCALLBACK((FSoundStream) wCallback.handled, buff, length);
// we got a callback - notify everybody
ArrayList handlers = FMOD.getCallbacks(FMOD.FSOUND_STREAMCALLBACK, streamHandle);
for(int i=0; i<handlers.size(); i++) {
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) handlers.get(i);
FSoundStreamCallback callback = (FSoundStreamCallback) wCallback.callback;
callback.FSOUND_STREAMCALLBACK((FSoundStream) wCallback.handled, buff, length);
}
}
/**
@ -3535,10 +3561,13 @@ public class FSound {
* @param param parameter passed to callback
*/
private static void end_callback(long streamHandle) {
// locate out callback and call it back
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) FMOD.getCallback(FMOD.FSOUND_ENDCALLBACK, streamHandle);
FSoundStreamCallback callback = (FSoundStreamCallback) wCallback.callback;
callback.FSOUND_STREAMCALLBACK((FSoundStream) wCallback.handled, null, 0);
// we got a callback - notify everybody
ArrayList handlers = FMOD.getCallbacks(FMOD.FSOUND_ENDCALLBACK, streamHandle);
for(int i=0; i<handlers.size(); i++) {
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) handlers.get(i);
FSoundStreamCallback callback = (FSoundStreamCallback) wCallback.callback;
callback.FSOUND_STREAMCALLBACK((FSoundStream) wCallback.handled, null, 0);
}
}
/**
@ -3549,10 +3578,13 @@ public class FSound {
* @param param parameter passed to callback
*/
private static void sync_callback(long streamHandle, ByteBuffer buff, int lenght) {
// locate out callback and call it back
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) FMOD.getCallback(FMOD.FSOUND_SYNCCALLBACK, streamHandle);
FSoundStreamCallback callback = (FSoundStreamCallback) wCallback.callback;
callback.FSOUND_STREAMCALLBACK((FSoundStream) wCallback.handled, buff, lenght);
// we got a callback - notify everybody
ArrayList handlers = FMOD.getCallbacks(FMOD.FSOUND_SYNCCALLBACK, streamHandle);
for(int i=0; i<handlers.size(); i++) {
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) handlers.get(i);
FSoundStreamCallback callback = (FSoundStreamCallback) wCallback.callback;
callback.FSOUND_STREAMCALLBACK((FSoundStream) wCallback.handled, buff, lenght);
}
}
/**
@ -3563,9 +3595,10 @@ public class FSound {
* @param param parameter passed to callback
*/
private static int open_callback(String name) {
// locate out callback and call it back
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) FMOD.getCallback(FMOD.FSOUND_OPENCALLBACK, -1);
FSoundOpenCallback callback = (FSoundOpenCallback) wCallback.callback;
// we got a callback - notify THE handler
ArrayList handlers = FMOD.getCallbacks(FMOD.FSOUND_OPENCALLBACK, -1);
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) handlers.get(0);
FSoundOpenCallback callback = (FSoundOpenCallback) wCallback.callback;
return callback.FSOUND_OPENCALLBACK(name);
}
@ -3577,9 +3610,10 @@ public class FSound {
* @param param parameter passed to callback
*/
private static void close_callback(int handle) {
// locate out callback and call it back
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) FMOD.getCallback(FMOD.FSOUND_CLOSECALLBACK, -1);
FSoundCloseCallback callback = (FSoundCloseCallback) wCallback.callback;
// we got a callback - notify THE handler
ArrayList handlers = FMOD.getCallbacks(FMOD.FSOUND_CLOSECALLBACK, -1);
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) handlers.get(0);
FSoundCloseCallback callback = (FSoundCloseCallback) wCallback.callback;
callback.FSOUND_CLOSECALLBACK(handle);
}
@ -3591,9 +3625,10 @@ public class FSound {
* @param param parameter passed to callback
*/
private static int read_callback(ByteBuffer buffer, int size, int handle) {
// locate out callback and call it back
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) FMOD.getCallback(FMOD.FSOUND_CLOSECALLBACK, -1);
FSoundReadCallback callback = (FSoundReadCallback) wCallback.callback;
// we got a callback - notify THE handler
ArrayList handlers = FMOD.getCallbacks(FMOD.FSOUND_READCALLBACK, -1);
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) handlers.get(0);
FSoundReadCallback callback = (FSoundReadCallback) wCallback.callback;
return callback.FSOUND_READCALLBACK(buffer, size, handle);
}
@ -3605,9 +3640,10 @@ public class FSound {
* @param param parameter passed to callback
*/
private static int seek_callback(int handle, int pos, int mode) {
// locate out callback and call it back
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) FMOD.getCallback(FMOD.FSOUND_CLOSECALLBACK, -1);
FSoundSeekCallback callback = (FSoundSeekCallback) wCallback.callback;
// we got a callback - notify THE handler
ArrayList handlers = FMOD.getCallbacks(FMOD.FSOUND_SEEKCALLBACK, -1);
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) handlers.get(0);
FSoundSeekCallback callback = (FSoundSeekCallback) wCallback.callback;
return callback.FSOUND_SEEKCALLBACK(handle, pos, mode);
}
@ -3619,9 +3655,10 @@ public class FSound {
* @param param parameter passed to callback
*/
private static int tell_callback(int handle) {
// locate out callback and call it back
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) FMOD.getCallback(FMOD.FSOUND_CLOSECALLBACK, -1);
FSoundTellCallback callback = (FSoundTellCallback) wCallback.callback;
// we got a callback - notify THE handler
ArrayList handlers = FMOD.getCallbacks(FMOD.FSOUND_TELLCALLBACK, -1);
FMOD.WrappedCallback wCallback = (FMOD.WrappedCallback) handlers.get(0);
FSoundTellCallback callback = (FSoundTellCallback) wCallback.callback;
return callback.FSOUND_TELLCALLBACK(handle);
}
// ----------------------------------------------------------

View file

@ -38,7 +38,11 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.lwjgl.fmod.*;
import org.lwjgl.fmod.FMOD;
import org.lwjgl.fmod.FMODException;
import org.lwjgl.fmod.FMusic;
import org.lwjgl.fmod.FMusicModule;
import org.lwjgl.fmod.FSound;
/**
* $Id$
@ -74,12 +78,18 @@ public class MusicPlayer {
}
System.out.println("Loading " + args[0]);
// choose either way of loading...
// using name (path)
FMusicModule module = FMusic.FMUSIC_LoadSong(args[0]);
//ByteBuffer buffer = ByteBuffer.allocateDirect(11).order(ByteOrder.nativeOrder());
//buffer.put("razorbck.it".getBytes());
//buffer.flip();
//FMusicModule module = FMusic.FMUSIC_LoadSongEx(getData(args[0]), 0, 0, 0, null);
//FMusicModule module = FMusic.FMUSIC_LoadSongEx(buffer, 0, 0, 0, null);
// using name (path), extended mode
//FMusicModule module = FMusic.FMUSIC_LoadSongEx(args[0], 0, 0, 0, null);
// using memory buffers
//ByteBuffer data = getData(args[0]);
//FMusicModule module = FMusic.FMUSIC_LoadSongEx(data, 0, data.remaining(), FSound.FSOUND_LOADMEMORY, null);
if(module != null) {
System.out.println("Loaded. Playing module of type: " + FMusic.FMUSIC_GetType(module));
@ -96,6 +106,7 @@ public class MusicPlayer {
FMusic.FMUSIC_FreeSong(module);
} else {
System.out.println("Unable to play: " + args[0]);
System.out.println("Error: " + FMOD.FMOD_ErrorString(FSound.FSOUND_GetError()));
}
FSound.FSOUND_Close();
@ -104,39 +115,40 @@ public class MusicPlayer {
/**
* Reads the file into a ByteBuffer
*
* @param filename Name of file to load
*
* @param filename
* Name of file to load
* @return ByteBuffer containing file data
*/
static protected ByteBuffer getData(String filename) {
ByteBuffer buffer = null;
ByteBuffer buffer = null;
System.out.println("Attempting to load: " + filename);
try {
BufferedInputStream bis = new BufferedInputStream(MusicPlayer.class.getClassLoader().getResourceAsStream(filename));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bufferLength = 4096;
byte[] readBuffer = new byte[bufferLength];
int read = -1;
while((read = bis.read(readBuffer, 0, bufferLength)) != -1) {
baos.write(readBuffer, 0, read);
}
//done reading, close
bis.close();
// if ogg vorbis data, we need to pass it unmodified to alBufferData
buffer = ByteBuffer.allocateDirect(baos.size());
buffer.order(ByteOrder.nativeOrder());
buffer.put(baos.toByteArray());
buffer.flip();
System.out.println("loaded " + buffer.remaining() + " bytes");
} catch (Exception ioe) {
ioe.printStackTrace();
System.out.println("Attempting to load: " + filename);
try {
BufferedInputStream bis = new BufferedInputStream(StreamPlayer.class.getClassLoader().getResourceAsStream(filename));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bufferLength = 4096;
byte[] readBuffer = new byte[bufferLength];
int read = -1;
while ((read = bis.read(readBuffer, 0, bufferLength)) != -1) {
baos.write(readBuffer, 0, read);
}
return buffer;
//done reading, close
bis.close();
// if ogg vorbis data, we need to pass it unmodified to alBufferData
buffer = ByteBuffer.allocateDirect(baos.size());
buffer.order(ByteOrder.nativeOrder());
buffer.put(baos.toByteArray());
buffer.flip();
System.out.println("loaded " + buffer.remaining() + " bytes");
} catch (Exception ioe) {
ioe.printStackTrace();
}
return buffer;
}
}

View file

@ -0,0 +1,242 @@
/*
* Copyright (c) 2004 LWJGL Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions 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 'LWJGL' nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.lwjgl.test.fmod;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.Sys;
import org.lwjgl.fmod.FMOD;
import org.lwjgl.fmod.FMODException;
import org.lwjgl.fmod.FMusic;
import org.lwjgl.fmod.FMusicModule;
import org.lwjgl.fmod.FSound;
import org.lwjgl.fmod.callbacks.FMusicCallback;
/**
* $Id$ <br>
*
* @author Brian Matzon <brian@matzon.dk>
* @version $Revision$
*/
public class SyncTest {
/** Path to file to play */
private String filePath;
/** Module instance loaded */
private FMusicModule module;
/** Whether test is running */
private boolean running = true;
/** Current row */
private int row;
/** Current order */
private int order;
/** Number of orders in the song */
private int numOrders;
/**
* Creates a new SyncTest
* @param string
*/
public SyncTest(String filePath) {
this.filePath = filePath;
// create thread to exit when a key has been pressed
Thread t = new Thread() {
public void run() {
try {
System.in.read();
} catch (IOException ioe) {
}
running = false;
}
};
t.setDaemon(true);
t.start();
}
/**
*
* @param args
*/
public static void main(String[] args) {
// check for file existance
File file = new File(args[0]);
if (!file.exists()) {
System.out.println("No such file: " + args[0]);
return;
}
// initialize FMOD
try {
System.out.println("Initializing FMOD");
FMOD.create();
} catch (FMODException fmode) {
fmode.printStackTrace();
return;
}
// start actual test
SyncTest sync = new SyncTest(args[0]);
sync.executeTest();
}
/**
* Executes the test
*/
public void executeTest() {
// do setup
setup();
// if we have a module - get going
if (module != null) {
// high priority... - might otherwise skip
Sys.setProcessPriority(Sys.HIGH_PRIORITY);
// go go go!
run();
}
// we're done - clean up
destroy();
}
/**
* Setup FMOD
*/
private void setup() {
if (!FSound.FSOUND_Init(44100, 32, 0)) {
System.out.println("Failed to initialize FMOD");
System.out.println("Error: " + FMOD.FMOD_ErrorString(FSound.FSOUND_GetError()));
return;
}
// load module
System.out.println("Loading " + filePath);
module = FMusic.FMUSIC_LoadSong(filePath);
if (module == null) {
System.out.println("Unable to load " + filePath + ": " + FMOD.FMOD_ErrorString(FSound.FSOUND_GetError()));
return;
}
// get number of orders
numOrders = FMusic.FMUSIC_GetNumOrders(module);
// install order callback
FMusic.FMUSIC_SetOrderCallback(module, new FMusicCallback() {
public void FMUSIC_CALLBACK(FMusicModule module, int param) {
order = param;
}
}, 1);
// install row callback
// will be called once PER CHANNEL! - but since we only set the row
// no harm is done :)
FMusic.FMUSIC_SetRowCallback(module, new FMusicCallback() {
public void FMUSIC_CALLBACK(FMusicModule module, int param) {
row = param;
}
}, 1);
// try to add some userdata
ByteBuffer buffer = BufferUtils.createByteBuffer(24);
buffer.putInt(1).putInt(2).putInt(3).putInt(4).putInt(5).putInt(6).rewind();
FMusic.FMUSIC_SetUserData(module, buffer);
}
/**
* Update status of module - spew it out in console
*/
private void update() {
// mark as not running when finished
if(FMusic.FMUSIC_IsFinished(module)) {
running = false;
}
int patternLength = FMusic.FMUSIC_GetPatternLength(module, order);
int time = FMusic.FMUSIC_GetTime(module) / 1000;
int time2 = FMusic.FMUSIC_GetTime(module) % 1000 / 10;
double cpu = Math.round(FSound.FSOUND_GetCPUUsage() * 100.0) / 100.0;
System.out.println("O: " +
((order < 10) ? "0" : "") + order + "/" + numOrders + " | R: "
+ ((row < 10) ? "0" : "") + row + "/" + patternLength + " | T: "
+ time + "."
+ ((time2 < 10) ? "0" : "") + time2 + " | BPM: " + FMusic.FMUSIC_GetBPM(module) + " | Play: " + FMusic.FMUSIC_IsFinished(module)
+ " | C: " + FSound.FSOUND_GetChannelsPlaying() + " | CPU: " + cpu);
}
/**
* Runs the actual test - that is, play | update ad nausea
*/
private void run() {
// play
FMusic.FMUSIC_PlaySong(module);
// loop, printing update, if we actually changed row
int lastRow = row;
while(running) {
if(lastRow != row) {
lastRow = row;
update();
} else {
Thread.yield();
}
}
}
// clean up our own mess
private void destroy() {
if(module != null) {
// retrieve userdata
ByteBuffer buffer = FMusic.FMUSIC_GetUserData(module, 24);
// should contain 1,2,3,4,5,6
for(int i=0; i<6; i++) {
System.out.println(buffer.getInt());
}
FMusic.FMUSIC_FreeSong(module);
}
FSound.FSOUND_Close();
FMOD.destroy();
}
}