//=============================================================================================== //USERSTREAM.EXE //Copyright (c), Firelight Technologies Pty, Ltd, 1999-2004. //This sample specifically demonstrates the user callback streaming facility, and generates a //very strange noise! :) //=============================================================================================== /** * I've ported the C++ FMOD example to use it with NativeFmod * * @author J�r�me JOUVIE (Jouvieje) * * WANT TO CONTACT ME ? * E-mail : * jerome.jouvie@gmail.com * My web sites : * http://jerome.jouvie.free.fr/ */ package org.jouvieje.Fmod.Examples; import java.nio.ByteBuffer; import java.nio.ShortBuffer; import javax.swing.JPanel; import org.jouvieje.Fmod.Fmod; import org.jouvieje.Fmod.Init; import org.jouvieje.Fmod.Callbacks.FSOUND_DSPCALLBACK; import org.jouvieje.Fmod.Callbacks.FSOUND_STREAMCALLBACK; import org.jouvieje.Fmod.Defines.FSOUND_MISC_VALUES; import org.jouvieje.Fmod.Defines.FSOUND_MODES; import org.jouvieje.Fmod.Defines.VERSIONS; import org.jouvieje.Fmod.Enumerations.FSOUND_OUTPUTTYPES; import org.jouvieje.Fmod.Examples.Util.ConsoleGUI; import org.jouvieje.Fmod.Examples.Util.FmodExampleFrame; import org.jouvieje.Fmod.Exceptions.InitException; import org.jouvieje.Fmod.Misc.BufferUtils; import org.jouvieje.Fmod.Misc.Pointer; import org.jouvieje.Fmod.Structures.FSOUND_DSPUNIT; import org.jouvieje.Fmod.Structures.FSOUND_STREAM; import org.jouvieje.libloader.LibLoader; public class UserStream extends ConsoleGUI implements FSOUND_OUTPUTTYPES, FSOUND_MISC_VALUES, FSOUND_MODES, VERSIONS { private static final long serialVersionUID = 1L; public static void main(String[] args) { new FmodExampleFrame(new UserStream()); } public UserStream() { super(); initFmod(); initialize(); } public JPanel getPanel() { return this; } public String getTitle() { return "FMOD User-stream example."; } private boolean init = false; private boolean deinit = false; private FSOUND_STREAM stream = null; private FSOUND_DSPUNIT dsp1 = null; private FSOUND_DSPUNIT dsp2 = null; /* * Callback used to divided the volume by 2 * When this callback is called two times, the sound is divided by 4 */ private FSOUND_DSPCALLBACK dspcallback = new FSOUND_DSPCALLBACK(){ public ByteBuffer FSOUND_DSPCALLBACK(ByteBuffer originalbuffer, ByteBuffer newBuffer, int length, Pointer userdata) { /* * newbuffer is a buffer that contains the music. You can consider this as a short array. * This array contains the right and left channel like that : * * | l | r | l | r | l | r | l | r | ... * The odd index are for the left channel and the even channels are for the right. */ /* * 4 bytes per samples : 2 for the left and 2 for the right channels. */ ShortBuffer shortBuffer = newBuffer.asShortBuffer(); for(int i = 0; i <= length - 1; i++) {// >>2 = 16bit stereo (4 bytes per sample) /* * The >> Operator : * It is a bit manipulation, it move to the left each bit. (<< is the same operator but move bit to the left) * Ex: * short a = 13; //in base 2 = 0000000000001101 * short b = a >> 1 // a >> 1 = 0000000000000110 so in base 10 : 6 * The value of b is 6 * * >> 1 is equivalent to an integer division by 2, that is for that reason the volume is half of * the original volume. * When we call two time this callback, the volume is divided by 2*2=4, so the volume is the quart * of the original volume * * Rem: >> 2 is equivalent to an integer division by 4 */ short left = (short)(shortBuffer.get(2 * i) >> 1); //Divide left channel by 2 short right = (short)(shortBuffer.get(2 * i + 1) >> 1); //Divide right channel by 2 shortBuffer.put(2 * i, left); shortBuffer.put(2 * i + 1, right); } newBuffer.rewind(); return newBuffer; } }; /* * [DESCRIPTION] * User streamer callback * * [PARAMETERS] * 'stream' pointer to the stream supplying the callback * 'buff' pointer to the streamer buffer to fill. * 'len' length of the data block in BYTES * * [REMARKS] * What a strange noise!!! * (heh heh) */ /* * This callback 'creates' the sound */ private FSOUND_STREAMCALLBACK streamcallback = new FSOUND_STREAMCALLBACK(){ float t1 = 0, t2 = 0; // time float v1 = 0, v2 = 0; // velocity public boolean FSOUND_STREAMCALLBACK(FSOUND_STREAM stream, ByteBuffer buff, int len, Pointer userdata) { /* * len is the length of the buffer in bytes. But we have 4 byte per SAMPLES, * that is for that reason that we need to divide by 4 (>>2) the length */ for(int i = 0; i < len >> 2; i++) {// >>2 because 16bit stereo (4 bytes per sample) buff.putShort((short)(Math.sin(t1) * 32767.0f)); //left channel buff.putShort((short)(Math.sin(t2) * 32767.0f)); //right channel t1 += 0.01f + v1; t2 += 0.0142f + v2; v1 += (float)(Math.sin(t1) * 0.002f); v2 += (float)(Math.sin(t2) * 0.002f); } buff.rewind(); // println("callback : buff = "+buff+", len = "+len+", time = "+((float)NativeFmod.FSOUND_Stream_GetTime(stream) / 1000.0f)+" param = "+userdata); return true; } }; /* * [DESCRIPTION] * End of stream user callback, initialized with FSOUND_Stream_SetEndCallback or * FSOUND_Stream_SetSynchCallback * * [PARAMETERS] * 'stream' A pointer to the stream that ended. * 'buff' This is NULL for end of stream callbacks, or a string for synch callbacks. * 'len' This is reserved and is always 0 for end and synch callbacks. ignore. * 'param' This is the value passed to FSOUND_Stream_SetEndCallback or * FSOUND_Stream_SetSynchCallback as a user data value. * * [RETURN_VALUE] * TRUE or FALSE, the value is ignored. */ private FSOUND_STREAMCALLBACK endcallback = new FSOUND_STREAMCALLBACK(){ public boolean FSOUND_STREAMCALLBACK(FSOUND_STREAM stream, ByteBuffer buff, int len, Pointer userdata) { //end of stream callback doesnt have a 'buff' value, if it doesnt it could be a synch point. print("\n"); if(buff != null) { //Retrieve the String pointed by the Buffer String synchpoint = BufferUtils.toString(buff); print("SYNCHPOINT : " + synchpoint + "\n"); } else print("STREAM ENDED!!\n"); return true; } }; public void initFmod() { /* * NativeFmod Init */ try { Init.loadLibraries(); } catch(InitException e) { printExit("NativeFmod error! " + e.getMessage() + "\n"); return; } /* * Checking NativeFmodEx version */ if(NATIVEFMOD_LIBRARY_VERSION != NATIVEFMOD_JAR_VERSION) { printExit("Error! NativeFmod library version (" + NATIVEFMOD_LIBRARY_VERSION + ") is different to jar version (" + NATIVEFMOD_JAR_VERSION + ")\n"); return; } /*==================================================*/ /* * Checking Fmod version */ if(Fmod.FSOUND_GetVersion() < FMOD_VERSION) { printExit("Error : You are using the wrong DLL version! You should be using FMOD " + FMOD_VERSION + "\n"); return; } init = true; } public void run() { if(!init) return; print("-------------------------------------------------------------\n"); print("FSOUND Streamer example.\n"); print("Copyright (c) Firelight Technologies Pty, Ltd, 2001-2004.\n"); print("-------------------------------------------------------------\n"); print("---------------------------------------------------------\n"); print("Output Type\n"); print("---------------------------------------------------------\n"); switch (LibLoader.getPlatform()) { case LibLoader.PLATFORM_WINDOWS: print("1 - Direct Sound\n"); print("2 - Windows Multimedia Waveout\n"); print("3 - ASIO\n"); break; case LibLoader.PLATFORM_LINUX: print("1 - OSS - Open Sound System\n"); print("2 - ESD - Elightment Sound Daemon\n"); print("3 - ALSA 0.9 - Advanced Linux Sound Architecture\n"); break; case LibLoader.PLATFORM_MACOSX: print("1 - Mac SoundManager\n"); break; default: print("1 - NoSound\n"); break; } print("---------------------------------------------------------\n"); // print driver names print("Press a corresponding number\n"); int output = -1; while(output < 1 || output > 4) { try { output = Integer.parseInt("" + getKey()); } catch(NumberFormatException e) { output = -1; } Thread.yield(); } switch (LibLoader.getPlatform()) { case LibLoader.PLATFORM_WINDOWS: switch(output) { case 1: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); break; case 2: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_WINMM); break; case 3: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_ASIO); break; } break; case LibLoader.PLATFORM_LINUX: switch(output) { case 1: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_OSS); break; case 2: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_ESD); break; case 3: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_ALSA); break; } break; case LibLoader.PLATFORM_MACOSX: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_MAC); break; default: Fmod.FSOUND_SetOutput(FSOUND_OUTPUT_NOSOUND); break; } // ========================================================================================== // SELECT DRIVER // ========================================================================================== // The following list are the drivers for the output method selected above. print("---------------------------------------------------------\n"); output = Fmod.FSOUND_GetOutput(); if(output == FSOUND_OUTPUT_NOSOUND) print("NoSound"); else if(output == FSOUND_OUTPUT_WINMM) print("Windows Multimedia Waveout"); else if(output == FSOUND_OUTPUT_DSOUND) print("Direct Sound"); else if(output == FSOUND_OUTPUT_ASIO) print("ASIO"); else if(output == FSOUND_OUTPUT_OSS) print("Open Sound System"); else if(output == FSOUND_OUTPUT_ESD) print("Enlightment Sound Daemon"); else if(output == FSOUND_OUTPUT_ALSA) print("Audio Linux System Audio"); else if(output == FSOUND_OUTPUT_MAC) print("Mac SoundManager"); print(" Driver list\n"); print("---------------------------------------------------------\n"); for(int i = 0; i <= Fmod.FSOUND_GetNumDrivers() - 1; i++) { print(i + " - " + Fmod.FSOUND_GetDriverName(i) + "\n"); } print("---------------------------------------------------------\n"); // print driver names print("Press a corresponding number\n"); int driver = -1; while(driver < 0 || driver > Fmod.FSOUND_GetNumDrivers() - 1) { try { driver = Integer.parseInt("" + getKey()); } catch(NumberFormatException e) { driver = -1; } Thread.yield(); } Fmod.FSOUND_SetDriver(driver); // Select sound card (0 = default) // ========================================================================================== // INITIALIZE // ========================================================================================== if(!Fmod.FSOUND_Init(44100, 16, 0)) { printExit(Fmod.FMOD_ErrorString(Fmod.FSOUND_GetError())); return; } // ========================================================================================== // CREATE USER STREAM // ========================================================================================== stream = Fmod.FSOUND_Stream_Create(streamcallback, 6 * 2048, FSOUND_NORMAL | FSOUND_16BITS | FSOUND_STEREO, 44100, null); if(stream == null) { printExit(Fmod.FMOD_ErrorString(Fmod.FSOUND_GetError())); return; } Fmod.FSOUND_Stream_SetEndCallback(stream, endcallback, null); dsp1 = Fmod.FSOUND_Stream_CreateDSP(stream, dspcallback, 0, null); // priority 0 = it comes first in dsp chain. dsp2 = Fmod.FSOUND_Stream_CreateDSP(stream, dspcallback, 1, null); // priority 1 = it comes last print("=========================================================================\n"); print("Playing stream...\n"); // ========================================================================================== // PLAY STREAM // ========================================================================================== if(Fmod.FSOUND_Stream_Play(FSOUND_FREE, stream) == -1) { printExit(Fmod.FMOD_ErrorString(Fmod.FSOUND_GetError())); return; } readInput("******* Hit ENTER to active stream DSP unit #1 to halve the stream volume..."); Fmod.FSOUND_DSP_SetActive(dsp1, true); readInput("******* Now hit ENTER to active stream DSP unit #2 to quarter the stream volume..."); Fmod.FSOUND_DSP_SetActive(dsp2, true); readInput("******* How hit a ENTER to finish..."); Fmod.FSOUND_DSP_SetActive(dsp1, false); Fmod.FSOUND_DSP_SetActive(dsp2, false); stop(); } public void stop() { if(!init || deinit) { return; } deinit = true; print("\n"); if(dsp1 != null && !dsp1.isNull()) { Fmod.FSOUND_DSP_Free(dsp1); } if(dsp2 != null && !dsp2.isNull()) { Fmod.FSOUND_DSP_Free(dsp2); } if(stream != null && !stream.isNull()) { Fmod.FSOUND_Stream_Close(stream); } print("Shutdown FMOD\n"); Fmod.FSOUND_Close(); } }