Path: blob/main/src/lwjgl/java/paulscode/sound/SoundSystem.java
8644 views
package paulscode.sound;12import java.net.URL;3import java.util.HashMap;4import java.util.Iterator;5import java.util.LinkedList;6import java.util.List;7import java.util.ListIterator;8import java.util.Random;9import java.util.Set;10import javax.sound.sampled.AudioFormat;1112/**13* The SoundSystem class is the core class for the SoundSystem library. It is14* capable of interfacing with external sound library and codec library15* pluggins. This core class is stripped down to give it a smaller memory16* footprint and to make it more customizable. This library was created to17* provide a simple, common interface to a variety of 3rd-party sound and codec18* libraries, and to simplify switching between them on the fly. If no19* external pluggins are loaded, this core class by itself is only capable of20* playing MIDI files. Specific implementations (such as SoundSystemJPCT) will21* extend this core class. They will automatically link with popular22* external pluggins and provide extra methods for ease of use.23* There should be only one instance of this class in any program! The24* SoundSystem can be constructed by defining which sound library to use, or by25* allowing SoundSystem to perform its own library compatibility checking. See26* {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for information27* about changing default settings and linking with external pluggins.28*<br><br>29*<b><i> SoundSystem License:</b></i><br><b><br>30* You are free to use this library for any purpose, commercial or otherwise.31* You may modify this library or source code, and distribute it any way you32* like, provided the following conditions are met:33*<br>34* 1) You may not falsely claim to be the author of this library or any35* unmodified portion of it.36*<br>37* 2) You may not copyright this library or a modified version of it and then38* sue me for copyright infringement.39*<br>40* 3) If you modify the source code, you must clearly document the changes41* made before redistributing the modified source code, so other users know42* it is not the original code.43*<br>44* 4) You are not required to give me credit for this library in any derived45* work, but if you do, you must also mention my website:46* http://www.paulscode.com47*<br>48* 5) I the author will not be responsible for any damages (physical,49* financial, or otherwise) caused by the use if this library or any part50* of it.51*<br>52* 6) I the author do not guarantee, warrant, or make any representations,53* either expressed or implied, regarding the use of this library or any54* part of it.55* <br><br>56* Author: Paul Lamb57* <br>58* http://www.paulscode.com59* </b>60*/61public class SoundSystem62{63/**64* Used to return a current value from one of the synchronized65* boolean-interface methods.66*/67private static final boolean GET = false;68/**69* Used to set the value in one of the synchronized boolean-interface methods.70*/71private static final boolean SET = true;72/**73* Used when a parameter for one of the synchronized boolean-interface methods74* is not aplicable.75*/76private static final boolean XXX = false;7778/**79* Processes status messages, warnings, and error messages.80*/81protected SoundSystemLogger logger;8283/**84* Handle to the active sound library.85*/86protected Library soundLibrary;8788/**89* List of queued commands to perform.90*/91protected List<CommandObject> commandQueue;9293/**94* Used internally by SoundSystem to keep track of play/pause/stop/rewind95* commands. This prevents source management (culling and activating) from96* being adversely affected by the quickPlay, quickStream, and backgroundMusic97* methods.98*/99private List<CommandObject> sourcePlayList;100101/**102* Processes queued commands in the background.103*/104protected CommandThread commandThread;105106/**107* Generates random numbers.108*/109public Random randomNumberGenerator;110111/**112* Name of this class.113*/114protected String className = "SoundSystem";115116/**117* Indicates the currently loaded sound-library, or null if none.118*/119private static Class currentLibrary = null;120121/**122* Becomes true when the sound library has been initialized.123*/124private static boolean initialized = false;125126/**127* Indicates the last exception that was thrown.128*/129private static SoundSystemException lastException = null;130131/**132* Constructor: Create the sound system using the default library. If the133* default library is not compatible, another library type will be loaded134* instead, in the order of library preference.135* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for136* information about sound library types.137*/138public SoundSystem()139{140// create the message logger:141logger = SoundSystemConfig.getLogger();142// if the user didn't create one, then do it now:143if( logger == null )144{145logger = new SoundSystemLogger();146SoundSystemConfig.setLogger( logger );147}148149linkDefaultLibrariesAndCodecs();150151LinkedList<Class> libraries = SoundSystemConfig.getLibraries();152153if( libraries != null )154{155ListIterator<Class> i = libraries.listIterator();156Class c;157while( i.hasNext() )158{159c = i.next();160try161{162init( c );163return;164}165catch( SoundSystemException sse )166{167logger.printExceptionMessage( sse, 1 );168}169}170}171try172{173init( Library.class );174return;175}176catch( SoundSystemException sse )177{178logger.printExceptionMessage( sse, 1 );179}180}181182/**183* Constructor: Create the sound system using the specified library.184* @param libraryClass Library to use.185* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for186* information about chosing a sound library.187*/188public SoundSystem( Class libraryClass ) throws SoundSystemException189{190// create the message logger:191logger = SoundSystemConfig.getLogger();192// if the user didn't create one, then do it now:193if( logger == null )194{195logger = new SoundSystemLogger();196SoundSystemConfig.setLogger( logger );197}198linkDefaultLibrariesAndCodecs();199200init( libraryClass );201}202203/**204* Links with any default libraries or codecs should be made in this method.205* This method is empty in the core SoundSystem class, and should be overriden206* by classes which extend SoundSystem.207* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for208* information about linking with sound libraries and codecs.209*/210protected void linkDefaultLibrariesAndCodecs()211{212}213214/**215* Loads the message logger, initializes the specified sound library, and216* starts the command thread. Also instantiates the random number generator217* and the command queue.218* @param libraryClass Library to initialize.219* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for220* information about chosing a sound library.221*/222protected void init( Class libraryClass ) throws SoundSystemException223{224message( "", 0 );225message( "Starting up " + className + " version "+ SoundSystem.class.getPackage().getImplementationVersion()+"...", 0 );226227// create the random number generator:228randomNumberGenerator = new Random();229// create the command queue:230commandQueue = new LinkedList<CommandObject>();231// create the working source playlist:232sourcePlayList = new LinkedList<CommandObject>();233234// Instantiate and start the Command Processer thread:235commandThread = new CommandThread( this ); // Gets a SoundSystem handle236commandThread.start();237238snooze( 200 );239240newLibrary( libraryClass );241message( "", 0 );242}243244/**245* Ends the command thread, shuts down the sound system, and removes references246* to all instantiated objects.247*/248public void cleanup()249{250boolean killException = false;251message( "", 0 );252message( className + " shutting down...", 0 );253254// End the command thread:255try256{257commandThread.kill(); // end the command processor loop.258commandThread.interrupt(); // wake the thread up so it can end.259}260catch( Exception e )261{262killException = true;263}264265if( !killException )266{267// wait up to 5 seconds for command thread to end:268for( int i = 0; i < 50; i++ )269{270if( !commandThread.alive() )271break;272snooze( 100 );273}274}275276// Let user know if there was a problem ending the command thread277if( killException || commandThread.alive() )278{279errorMessage( "Command thread did not die!", 0 );280message( "Ignoring errors... continuing clean-up.", 0 );281}282283initialized( SET, false );284currentLibrary( SET, null );285try286{287// Stop all sources and shut down the sound library:288if( soundLibrary != null )289soundLibrary.cleanup();290}291catch( Exception e )292{293errorMessage( "Problem during Library.cleanup()!", 0 );294message( "Ignoring errors... continuing clean-up.", 0 );295}296297try298{299// remove any queued commands:300if( commandQueue != null )301commandQueue.clear();302}303catch( Exception e )304{305errorMessage( "Unable to clear the command queue!", 0 );306message( "Ignoring errors... continuing clean-up.", 0 );307}308309try310{311// empty the source management list:312if( sourcePlayList != null )313sourcePlayList.clear();314}315catch( Exception e )316{317errorMessage( "Unable to clear the source management list!", 0 );318message( "Ignoring errors... continuing clean-up.", 0 );319}320321// Remove references to all instantiated objects:322randomNumberGenerator = null;323soundLibrary = null;324commandQueue = null;325sourcePlayList = null;326commandThread = null;327328importantMessage( "Author: Paul Lamb, www.paulscode.com", 1 );329message( "", 0 );330}331332/**333* Wakes up the Command Thread to process commands. This method should be334* used if there is a need to call methods 'ManageSources' and 'CommandQueue'335* externally. In most cases, this method will not be needed, since336* SoundSystem automatically wakes the Command Thread every time commands are337* placed into either the ManageSources queue or CommandQueue to be processed.338*/339public void interruptCommandThread()340{341if( commandThread == null )342{343errorMessage( "Command Thread null in method " +344"'interruptCommandThread'", 0 );345return;346}347// Wake the command thread to process commands:348commandThread.interrupt();349}350351/**352* Pre-loads a sound into memory. The file may either be located within the353* JAR or at an online location. If the file is online, filename must begin354* with "http://", since that is how SoundSystem recognizes URL's. If the file355* is located within the compiled JAR, the package in which sound files are356* located may be set by calling SoundSystemConfig.setSoundFilesPackage().357* @param filename Filename of the sound file to load.358*/359public void loadSound( String filename )360{361// Queue a command to load the sound file:362CommandQueue( new CommandObject( CommandObject.LOAD_SOUND,363new FilenameURL( filename ) ) );364// Wake the command thread to process commands:365commandThread.interrupt();366}367368/**369* Pre-loads a sound specified by the given URL into memory. The second370* parameter 'identifier' should look like a filename, and it must have the371* correct extension so SoundSystem knows what codec to use for the file372* referenced by the URL instance.373* @param url URL handle to the sound file to load.374* @param identifier Filename/identifier of the file referenced by the URL.375*/376public void loadSound( URL url, String identifier )377{378// Queue a command to load the sound file from a URL:379CommandQueue( new CommandObject( CommandObject.LOAD_SOUND,380new FilenameURL( url, identifier ) ) );381// Wake the command thread to process commands:382commandThread.interrupt();383}384385/**386* Saves raw PCM audio data in the specified audio format, under the specified387* identifier. This identifier can be later used in place of 'filename'388* parameters to reference the sample data.389* @param data The sample data390* @param format Format the sample data is stored in391* @param identifier What to call the sample.392*/393public void loadSound( byte[] data, AudioFormat format, String identifier )394{395// Queue a command to load the sound file from a URL:396CommandQueue( new CommandObject( CommandObject.LOAD_DATA,397identifier,398new SoundBuffer( data, format ) ) );399// Wake the command thread to process commands:400commandThread.interrupt();401}402403404/**405* Removes a pre-loaded sound from memory. This is a good method to use for406* freeing up memory after a large sound file is no longer needed. NOTE: the407* source will remain in memory after calling this method as long as the408* sound is attached to an existing source. When calling this method, calls409* should also be made to method removeSource( String ) for all sources which410* this sound is bound to.411* @param filename Filename/identifier of the sound file to unload.412*/413public void unloadSound( String filename )414{415// Queue a command to unload the sound file:416CommandQueue( new CommandObject( CommandObject.UNLOAD_SOUND, filename ) );417// Wake the command thread to process commands:418commandThread.interrupt();419}420421/**422* If the specified source is a streaming source or MIDI source, this method423* queues up the next sound to play when the previous playback ends. The file424* may either be located within the JAR or at an online location. If the file425* is online, filename must begin with "http://", since that is how SoundSystem426* recognizes URL paths. If the file is located within the compiled JAR, the427* package in which sound files are located may be set by calling428* SoundSystemConfig.setSoundFilesPackage(). This method has no effect on429* non-streaming sources.430* @param sourcename Source identifier.431* @param filename Name of the sound file to play next.432*/433public void queueSound( String sourcename, String filename )434{435// Queue a command to queue the sound:436CommandQueue( new CommandObject( CommandObject.QUEUE_SOUND, sourcename,437new FilenameURL( filename ) ) );438// Wake the command thread to process commands:439commandThread.interrupt();440}441442/**443* If the specified source is a streaming source or MIDI source, this method444* queues up the next sound to play when the previous playback ends. The third445* parameter 'identifier' should look like a filename, and it must have the446* correct extension so SoundSystem knows what codec to use for the file447* referenced by the URL instance. This method has no effect on non-streaming448* sources.449* @param sourcename Source identifier.450* @param url URL handle to the sound file to load.451* @param identifier Filename/identifier of the file referenced by the URL.452*/453public void queueSound( String sourcename, URL url, String identifier )454{455// Queue a command to queue the sound:456CommandQueue( new CommandObject( CommandObject.QUEUE_SOUND, sourcename,457new FilenameURL( url, identifier ) ) );458// Wake the command thread to process commands:459commandThread.interrupt();460}461462/**463* Removes the first occurrence of the specified filename/identifier from the464* specified source's list of sounds to play when previous playback ends. This465* method has no effect on non-streaming sources.466* @param sourcename Source identifier.467* @param filename Filename/identifier of the sound file to play next.468*/469public void dequeueSound( String sourcename, String filename )470{471// Queue a command to dequeue the sound:472CommandQueue( new CommandObject( CommandObject.DEQUEUE_SOUND,473sourcename, filename ) );474// Wake the command thread to process commands:475commandThread.interrupt();476}477478/**479* Fades out the volume of whatever the specified source is currently playing,480* then begins playing the specified file at the source's previously481* assigned volume level. The file may either be located within the JAR or at482* an online location. If the file is online, filename must begin with483* "http://", since that is how SoundSystem recognizes URL paths. If the file484* is located within the compiled JAR, the package in which sound files are485* located may be set by calling SoundSystemConfig.setSoundFilesPackage(). If486* the filename parameter is null or empty, the specified source will simply487* fade out and stop. The miliseconds parameter must be non-negative or zero.488* This method will remove anything that is currently in the specified source's489* list of queued sounds that would have played next when the current sound490* finished playing. This method may only be used for streaming and MIDI491* sources.492* @param sourcename Name of the source to fade out.493* @param filename Name of a sound file to play next, or null for none.494* @param milis Number of miliseconds the fadeout should take.495*/496public void fadeOut( String sourcename, String filename, long milis )497{498FilenameURL fu = null;499if( filename != null )500fu = new FilenameURL( filename );501// Queue a command to fade out:502CommandQueue( new CommandObject( CommandObject.FADE_OUT, sourcename, fu,503milis ) );504// Wake the command thread to process commands:505commandThread.interrupt();506}507508/**509* Fades out the volume of whatever the specified source is currently playing,510* then begins playing the specified file at the source's previously511* assigned volume level. If the url parameter is null or empty, the512* specified source will simply fade out and stop. The third513* parameter 'identifier' should look like a filename, and it must have the514* correct extension so SoundSystem knows what codec to use for the file515* referenced by the URL instance. The miliseconds parameter must be516* non-negative or zero. This method will remove anything that is currently in517* the specified source's list of queued sounds that would have played next518* when the current sound finished playing. This method may only be used for519* streaming and MIDI sources.520* @param sourcename Name of the source to fade out.521* @param url URL handle to the sound file to play next, or null for none.522* @param identifier Filename/identifier of the file referenced by the URL.523* @param milis Number of miliseconds the fadeout should take.524*/525public void fadeOut( String sourcename, URL url, String identifier,526long milis )527{528FilenameURL fu = null;529if( url != null && identifier != null )530fu = new FilenameURL( url, identifier );531// Queue a command to fade out:532CommandQueue( new CommandObject( CommandObject.FADE_OUT, sourcename, fu,533milis ) );534// Wake the command thread to process commands:535commandThread.interrupt();536}537538/**539* Fades out the volume of whatever the specified source is currently playing,540* then fades the volume back in playing the specified filename. Final volume541* after fade-in completes will be equal to the source's previously assigned542* volume level. The filename parameter may not be null or empty. The file543* may either be located within the JAR or at an online location. If the file544* is online, filename must begin with "http://", since that is how545* SoundSystem recognizes URL paths. If the file is located within the546* compiled JAR, the package in which sound files are located may be set by547* calling SoundSystemConfig.setSoundFilesPackage(). The miliseconds548* parameters must be non-negative or zero. This method will remove anything549* that is currently in the specified source's list of queued sounds that would550* have played next when the current sound finished playing. This method may551* only be used for streaming and MIDI sources.552* @param sourcename Name of the source to fade out/in.553* @param filename Name of a sound file to play next, or null for none.554* @param milisOut Number of miliseconds the fadeout should take.555* @param milisIn Number of miliseconds the fadein should take.556*/557public void fadeOutIn( String sourcename, String filename, long milisOut,558long milisIn )559{560// Queue a command to load the sound file:561CommandQueue( new CommandObject( CommandObject.FADE_OUT_IN,562sourcename,563new FilenameURL( filename ), milisOut,564milisIn ) );565// Wake the command thread to process commands:566commandThread.interrupt();567}568569/**570* Fades out the volume of whatever the specified source is currently playing,571* then fades the volume back in playing the specified file. Final volume572* after fade-in completes will be equal to the source's previously assigned573* volume level. The url parameter may not be null or empty. The third574* parameter 'identifier' should look like a filename, and it must have the575* correct extension so SoundSystem knows what codec to use for the file576* referenced by the URL instance. The miliseconds parameters must be577* non-negative or zero. This method will remove anything that is currently578* in the specified source's list of queued sounds that would have played next579* when the current sound finished playing. This method may only be used for580* streaming and MIDI sources.581* @param sourcename Name of the source to fade out/in.582* @param url URL handle to the sound file to play next.583* @param identifier Filename/identifier of the file referenced by the URL.584* @param milisOut Number of miliseconds the fadeout should take.585* @param milisIn Number of miliseconds the fadein should take.586*/587public void fadeOutIn( String sourcename, URL url, String identifier,588long milisOut, long milisIn )589{590// Queue a command to load the sound file:591CommandQueue( new CommandObject( CommandObject.FADE_OUT_IN,592sourcename,593new FilenameURL( url, identifier ),594milisOut, milisIn ) );595// Wake the command thread to process commands:596commandThread.interrupt();597}598599/**600* Makes sure the current volume levels of streaming sources and MIDI are601* correct. This method is designed to help reduce the "jerky" fading behavior602* that happens when using some library and codec pluggins (such as603* LibraryJavaSound and CodecJOrbis). This method has no effect on normal604* "non-streaming" sources. It would normally be called somewhere in the main605* "game loop". IMPORTANT: To optimize frame-rates, do not call this method606* for every frame. It is better to just call this method at some acceptable607* "granularity" (play around with different granularities to find what sounds608* acceptable for a particular situation).609*/610public void checkFadeVolumes()611{612// Queue a command to load check fading source volumes:613CommandQueue( new CommandObject( CommandObject.CHECK_FADE_VOLUMES ) );614// Wake the command thread to process commands:615commandThread.interrupt();616}617618/**619* Creates a new permanant, streaming, priority source with zero attenuation.620* The file may either be located within the JAR or at an online location. If621* the file is online, filename must begin with "http://", since that is how622* SoundSystem recognizes URL paths. If the file is located within the623* compiled JAR, the package in which sound files are located may be set by624* calling SoundSystemConfig.setSoundFilesPackage().625* @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.626* @param filename Filename of the sound file to stream at this source.627* @param toLoop Should this source loop, or play only once.628*/629public void backgroundMusic( String sourcename, String filename,630boolean toLoop )631{632// Queue a command to quick stream a new source:633CommandQueue( new CommandObject( CommandObject.QUICK_PLAY, true,634true, toLoop, sourcename,635new FilenameURL( filename ), 0, 0, 0,636SoundSystemConfig.ATTENUATION_NONE, 0, false ) );637CommandQueue( new CommandObject( CommandObject.PLAY, sourcename) );638639commandThread.interrupt();640}641642/**643* Creates a new permanant, streaming, priority source with zero attenuation.644* The third parameter 'identifier' should look like a filename, and it must645* have the correct extension so SoundSystem knows what codec to use for the646* file referenced by the URL instance.647* @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.648* @param url URL handle to the sound file to stream at this source.649* @param identifier Filename/identifier of the file referenced by the URL.650* @param toLoop Should this source loop, or play only once.651*/652public void backgroundMusic( String sourcename, URL url, String identifier,653boolean toLoop )654{655// Queue a command to quick stream a new source:656CommandQueue( new CommandObject( CommandObject.QUICK_PLAY, true,657true, toLoop, sourcename,658new FilenameURL( url, identifier ),6590, 0, 0,660SoundSystemConfig.ATTENUATION_NONE,6610, false ) );662CommandQueue( new CommandObject( CommandObject.PLAY, sourcename) );663664commandThread.interrupt();665}666667/**668* Creates a new non-streaming source.669* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more670* information about Attenuation, fade distance, and rolloff factor.671* @param priority Setting this to true will prevent other sounds from overriding this one.672* @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.673* @param filename Filename/identifier of the sound file to play at this source.674* @param toLoop Should this source loop, or play only once.675* @param x X position for this source.676* @param y Y position for this source.677* @param z Z position for this source.678* @param attmodel Attenuation model to use.679* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel".680*/681public void newSource( boolean priority, String sourcename, String filename,682boolean toLoop, float x, float y, float z,683int attmodel, float distOrRoll )684{685CommandQueue( new CommandObject( CommandObject.NEW_SOURCE, priority,686false, toLoop, sourcename,687new FilenameURL( filename ), x, y, z,688attmodel, distOrRoll ) );689commandThread.interrupt();690}691692/**693* Creates a new non-streaming source.694* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more695* information about Attenuation, fade distance, and rolloff factor.696* @param priority Setting this to true will prevent other sounds from overriding this one.697* @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.698* @param url URL handle to the sound file to stream at this source.699* @param identifier Filename/identifier of the file referenced by the URL.700* @param toLoop Should this source loop, or play only once.701* @param x X position for this source.702* @param y Y position for this source.703* @param z Z position for this source.704* @param attmodel Attenuation model to use.705* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel".706*/707public void newSource( boolean priority, String sourcename, URL url,708String identifier, boolean toLoop, float x, float y,709float z, int attmodel, float distOrRoll )710{711CommandQueue( new CommandObject( CommandObject.NEW_SOURCE, priority,712false, toLoop, sourcename,713new FilenameURL( url, identifier ),714x, y, z,715attmodel, distOrRoll ) );716commandThread.interrupt();717}718719/**720* Creates a new streaming source. The file may either be located within the721* JAR or at an online location. If the file is online, filename must begin722* with "http://", since that is how SoundSystem recognizes URL paths. If the723* file is located within the compiled JAR, the package in which sound files724* are located may be set by calling SoundSystemConfig.setSoundFilesPackage().725* @param priority Setting this to true will prevent other sounds from overriding this one.726* @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.727* @param filename The filename of the sound file to play at this source.728* @param toLoop Should this source loop, or play only once.729* @param x X position for this source.730* @param y Y position for this source.731* @param z Z position for this source.732* @param attmodel Attenuation model to use.733* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel".734*/735public void newStreamingSource( boolean priority, String sourcename,736String filename, boolean toLoop, float x,737float y, float z, int attmodel,738float distOrRoll )739{740CommandQueue( new CommandObject( CommandObject.NEW_SOURCE, priority,741true, toLoop, sourcename,742new FilenameURL( filename ), x, y, z,743attmodel, distOrRoll ) );744commandThread.interrupt();745}746747/**748* Creates a new streaming source. The fourth parameter 'identifier' should749* look like a filename, and it must have the correct extension so SoundSystem750* knows what codec to use for the file referenced by the URL instance.751* @param priority Setting this to true will prevent other sounds from overriding this one.752* @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.753* @param url URL handle to the sound file to stream at this source.754* @param identifier Filename/identifier of the file referenced by the URL.755* @param toLoop Should this source loop, or play only once.756* @param x X position for this source.757* @param y Y position for this source.758* @param z Z position for this source.759* @param attmodel Attenuation model to use.760* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel".761*/762public void newStreamingSource( boolean priority, String sourcename,763URL url, String identifier, boolean toLoop,764float x, float y, float z, int attmodel,765float distOrRoll )766{767CommandQueue( new CommandObject( CommandObject.NEW_SOURCE, priority,768true, toLoop, sourcename,769new FilenameURL( url, identifier ),770x, y, z, attmodel, distOrRoll ) );771commandThread.interrupt();772}773774/**775* Opens a direct line for streaming audio data. This method creates a new776* streaming source to play the data at. The resulting streaming source can be777* manipulated the same as any other streaming source. Raw data can be sent to778* the new streaming source using the feedRawAudioData() method.779* @param audioFormat Format that the data will be in.780* @param priority Setting this to true will prevent other sounds from overriding this one.781* @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.782* @param x X position for this source.783* @param y Y position for this source.784* @param z Z position for this source.785* @param attModel Attenuation model to use.786* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel".787*/788public void rawDataStream( AudioFormat audioFormat, boolean priority,789String sourcename, float x, float y, float z,790int attModel, float distOrRoll )791{792CommandQueue( new CommandObject( CommandObject.RAW_DATA_STREAM,793audioFormat, priority, sourcename, x,794y, z, attModel, distOrRoll ) );795commandThread.interrupt();796}797798/**799* Creates a temporary source and plays it. After the source finishes playing,800* it is removed. Returns a randomly generated name for the new source. NOTE:801* to make a source created by this method permanant, call the setActive()802* method using the return value for sourcename.803* @param priority Setting this to true will prevent other sounds from overriding this one.804* @param filename Filename/identifier of the sound file to play at this source.805* @param toLoop Should this source loop, or play only once.806* @param x X position for this source.807* @param y Y position for this source.808* @param z Z position for this source.809* @param attmodel Attenuation model to use.810* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel".811* @return The new sorce's name.812*/813public String quickPlay( boolean priority, String filename, boolean toLoop,814float x, float y, float z, int attmodel,815float distOrRoll )816{817//generate a random name for this source:818String sourcename = "Source_"819+ randomNumberGenerator.nextInt()820+ "_" + randomNumberGenerator.nextInt();821822// Queue a command to quick play this new source:823CommandQueue( new CommandObject( CommandObject.QUICK_PLAY, priority,824false, toLoop, sourcename,825new FilenameURL( filename ), x, y, z,826attmodel, distOrRoll, true ) );827CommandQueue( new CommandObject( CommandObject.PLAY, sourcename) );828// Wake the command thread to process commands:829commandThread.interrupt();830831// return the new source name.832return sourcename;833}834835/**836* Creates a temporary source and plays it. After the source finishes playing,837* it is removed. Returns a randomly generated name for the new source. NOTE:838* to make a source created by this method permanant, call the setActive()839* method using the return value for sourcename.840* @param priority Setting this to true will prevent other sounds from overriding this one.841* @param url URL handle to the sound file to stream at this source.842* @param identifier Filename/identifier of the file referenced by the URL.843* @param toLoop Should this source loop, or play only once.844* @param x X position for this source.845* @param y Y position for this source.846* @param z Z position for this source.847* @param attmodel Attenuation model to use.848* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel".849* @return The new sorce's name.850*/851public String quickPlay( boolean priority, URL url, String identifier,852boolean toLoop, float x, float y, float z,853int attmodel, float distOrRoll )854{855//generate a random name for this source:856String sourcename = "Source_"857+ randomNumberGenerator.nextInt()858+ "_" + randomNumberGenerator.nextInt();859860// Queue a command to quick play this new source:861CommandQueue( new CommandObject( CommandObject.QUICK_PLAY, priority,862false, toLoop, sourcename,863new FilenameURL( url, identifier ),864x, y, z, attmodel, distOrRoll,865true ) );866CommandQueue( new CommandObject( CommandObject.PLAY, sourcename) );867// Wake the command thread to process commands:868commandThread.interrupt();869870// return the new source name.871return sourcename;872}873874/**875* Creates a temporary source and streams it. After the source finishes876* playing, it is removed. The file may either be located within the877* JAR or at an online location. If the file is online, filename must begin878* with "http://", since that is how SoundSystem recognizes URL paths. If the879* file is located within the compiled JAR, the package in which sound files880* are located may be set by calling SoundSystemConfig.setSoundFilesPackage().881* Returns a randomly generated name for the new source. NOTE: to make a882* source created by this method permanant, call the setActive() method using883* the return value for sourcename.884* @param priority Setting this to true will prevent other sounds from overriding this one.885* @param filename Filename of the sound file to stream at this source.886* @param toLoop Should this source loop, or play only once.887* @param x X position for this source.888* @param y Y position for this source.889* @param z Z position for this source.890* @param attmodel Attenuation model to use.891* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel".892* @return The new sorce's name.893*/894public String quickStream( boolean priority, String filename,895boolean toLoop, float x, float y, float z,896int attmodel, float distOrRoll )897{898//generate a random name for this source:899String sourcename = "Source_"900+ randomNumberGenerator.nextInt()901+ "_" + randomNumberGenerator.nextInt();902903// Queue a command to quick stream this new source:904CommandQueue( new CommandObject( CommandObject.QUICK_PLAY, priority,905true, toLoop, sourcename,906new FilenameURL( filename ), x, y, z,907attmodel, distOrRoll, true ) );908CommandQueue( new CommandObject( CommandObject.PLAY, sourcename) );909// Wake the command thread to process commands:910commandThread.interrupt();911912// return the new source name.913return sourcename;914}915/**916* Creates a temporary source and streams it. After the source finishes917* playing, it is removed. The third parameter 'identifier' should918* look like a filename, and it must have the correct extension so SoundSystem919* knows what codec to use for the file referenced by the URL instance.920* Returns a randomly generated name for the new source. NOTE: to make a921* source created by this method permanant, call the setActive() method using922* the return value for sourcename.923* @param priority Setting this to true will prevent other sounds from overriding this one.924* @param url URL handle to the sound file to stream at this source.925* @param identifier Filename/identifier of the file referenced by the URL.926* @param toLoop Should this source loop, or play only once.927* @param x X position for this source.928* @param y Y position for this source.929* @param z Z position for this source.930* @param attmodel Attenuation model to use.931* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel".932* @return The new sorce's name.933*/934public String quickStream( boolean priority, URL url, String identifier,935boolean toLoop, float x, float y, float z,936int attmodel, float distOrRoll )937{938//generate a random name for this source:939String sourcename = "Source_"940+ randomNumberGenerator.nextInt()941+ "_" + randomNumberGenerator.nextInt();942943// Queue a command to quick stream this new source:944CommandQueue( new CommandObject( CommandObject.QUICK_PLAY, priority,945true, toLoop, sourcename,946new FilenameURL( url, identifier ),947x, y, z, attmodel, distOrRoll,948true ) );949CommandQueue( new CommandObject( CommandObject.PLAY, sourcename) );950// Wake the command thread to process commands:951commandThread.interrupt();952953// return the new source name.954return sourcename;955}956957/**958* Move a source to the specified location.959* @param sourcename Identifier for the source.960* @param x destination X coordinate.961* @param y destination Y coordinate.962* @param z destination Z coordinate.963*/964public void setPosition( String sourcename, float x, float y, float z )965{966CommandQueue( new CommandObject( CommandObject.SET_POSITION,967sourcename, x, y, z ) );968commandThread.interrupt();969}970/**971* Manually sets the specified source's volume.972* @param sourcename Source to move.973* @param value New volume, float value ( 0.0f - 1.0f ).974*/975public void setVolume( String sourcename, float value )976{977CommandQueue( new CommandObject( CommandObject.SET_VOLUME,978sourcename, value ) );979commandThread.interrupt();980}981982/**983* Returns the current volume of the specified source, or zero if the specified984* source was not found.985* @param sourcename Source to read volume from.986* @return Float value representing the source volume (0.0f - 1.0f).987*/988public float getVolume( String sourcename )989{990synchronized( SoundSystemConfig.THREAD_SYNC )991{992if( soundLibrary != null )993return soundLibrary.getVolume( sourcename );994else995return 0.0f;996}997}998999/**1000* Manually sets the specified source's pitch.1001* @param sourcename The source's name.1002* @param value A float value ( 0.5f - 2.0f ).1003*/1004public void setPitch( String sourcename, float value )1005{1006CommandQueue( new CommandObject( CommandObject.SET_PITCH,1007sourcename, value ) );1008commandThread.interrupt();1009}10101011/**1012* Returns the pitch of the specified source.1013* @param sourcename The source's name.1014* @return Float value representing the source pitch (0.5f - 2.0f).1015*/1016public float getPitch( String sourcename )1017{1018if( soundLibrary != null )1019return soundLibrary.getPitch( sourcename );1020else1021return 1.0f;1022}10231024/**1025* Set a source's priority factor. A priority source will not be overriden when1026* too many sources are playing at once.1027* @param sourcename Identifier for the source.1028* @param pri Setting this to true makes this source a priority source.1029*/1030public void setPriority( String sourcename, boolean pri )1031{1032CommandQueue( new CommandObject( CommandObject.SET_PRIORITY,1033sourcename, pri ) );1034commandThread.interrupt();1035}1036/**1037* Changes a source to looping or non-looping.1038* @param sourcename Identifier for the source.1039* @param lp This source should loop.1040*/1041public void setLooping( String sourcename, boolean lp )1042{1043CommandQueue( new CommandObject( CommandObject.SET_LOOPING,1044sourcename, lp ) );1045commandThread.interrupt();1046}1047/**1048* Changes a source's attenuation model.1049* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more1050* information about Attenuation.1051* @param sourcename Identifier for the source.1052* @param model Attenuation model to use.1053*/1054public void setAttenuation( String sourcename, int model )1055{1056CommandQueue( new CommandObject( CommandObject.SET_ATTENUATION,1057sourcename, model ) );1058commandThread.interrupt();1059}1060/**1061* Changes a source's fade distance or rolloff factor.1062* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more1063* information about fade distance and rolloff.1064* @param sourcename Identifier for the source.1065* @param dr Either the fading distance or rolloff factor, depending on the attenuation model used.1066*/1067public void setDistOrRoll( String sourcename, float dr)1068{1069CommandQueue( new CommandObject( CommandObject.SET_DIST_OR_ROLL,1070sourcename, dr ) );1071commandThread.interrupt();1072}10731074/**1075* Changes the Doppler factor, for determining Doppler effect scale.1076* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more1077* information about Doppler effect.1078* @param dopplerFactor New value for Doppler factor.1079*/1080public void changeDopplerFactor( float dopplerFactor)1081{1082CommandQueue( new CommandObject( CommandObject.CHANGE_DOPPLER_FACTOR,1083dopplerFactor ) );1084commandThread.interrupt();1085}10861087/**1088* Changes the Doppler velocity, for use in Doppler effect.1089* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more1090* information about Doppler effect.1091* @param dopplerVelocity New value for Doppler velocity.1092*/1093public void changeDopplerVelocity( float dopplerVelocity )1094{1095CommandQueue( new CommandObject( CommandObject.CHANGE_DOPPLER_VELOCITY,1096dopplerVelocity ) );1097commandThread.interrupt();1098}10991100/**1101* Sets the specified source's velocity, for use in Doppler effect.1102* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more1103* information about Doppler effect.1104* @param sourcename The source's name.1105* @param x Velocity along world x-axis.1106* @param y Velocity along world y-axis.1107* @param z Velocity along world z-axis.1108*/1109public void setVelocity( String sourcename, float x, float y, float z )1110{1111CommandQueue( new CommandObject( CommandObject.SET_VELOCITY,1112sourcename, x, y, z ) );1113commandThread.interrupt();1114}11151116/**1117* Sets the listener's velocity, for use in Doppler effect.1118* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more1119* information about Doppler effect.1120* @param x Velocity along world x-axis.1121* @param y Velocity along world y-axis.1122* @param z Velocity along world z-axis.1123*/1124public void setListenerVelocity( float x, float y, float z )1125{1126CommandQueue( new CommandObject( CommandObject.SET_LISTENER_VELOCITY,1127x, y, z ) );1128commandThread.interrupt();1129}11301131/**1132* Returns the number of miliseconds since the specified source began playing.1133* @return miliseconds, or -1 if not playing or unable to calculate1134*/1135public float millisecondsPlayed( String sourcename )1136{1137synchronized( SoundSystemConfig.THREAD_SYNC )1138{1139return soundLibrary.millisecondsPlayed( sourcename );1140}1141}11421143/**1144* Feeds raw data through the specified source. The source must be a1145* streaming source and it can not be already associated with a file or URL to1146* stream from. Only use this for streaming sources created with the1147* rawDataStream() method. NOTE: Be carefull how much data you send to a1148* source to stream. The data will be processed at playback speed, so if you1149* queue up 1 hour worth of data, it will take 1 hour to play (not to mention1150* hogging a ton of memory). To clear out all queued data from the source, use1151* the flush() method. Also note: if there is a break in the data stream,1152* you will hear clicks and studders, so ensure that the data flow is steady.1153* @param sourcename Name of the streaming source to play from.1154* @param buffer Byte buffer containing raw audio data to stream.1155*/1156public void feedRawAudioData( String sourcename, byte[] buffer )1157{1158CommandQueue( new CommandObject( CommandObject.FEED_RAW_AUDIO_DATA,1159sourcename, buffer ) );1160commandThread.interrupt();1161}1162/**1163* Plays the specified source.1164* @param sourcename Identifier for the source.1165*/1166public void play( String sourcename )1167{1168CommandQueue( new CommandObject( CommandObject.PLAY, sourcename) );1169commandThread.interrupt();1170}1171/**1172* Pauses the specified source.1173* @param sourcename Identifier for the source.1174*/1175public void pause( String sourcename )1176{1177CommandQueue( new CommandObject( CommandObject.PAUSE, sourcename) );1178commandThread.interrupt();1179}1180/**1181* Stops the specified source.1182* @param sourcename Identifier for the source.1183*/1184public void stop( String sourcename )1185{1186CommandQueue( new CommandObject( CommandObject.STOP, sourcename) );1187commandThread.interrupt();1188}1189/**1190* Rewinds the specified source.1191* @param sourcename Identifier for the source.1192*/1193public void rewind( String sourcename )1194{1195CommandQueue( new CommandObject( CommandObject.REWIND, sourcename) );1196commandThread.interrupt();1197}1198/**1199* Flushes all previously queued audio data from a streaming source.1200* @param sourcename Identifier for the source.1201*/1202public void flush( String sourcename )1203{1204CommandQueue( new CommandObject( CommandObject.FLUSH, sourcename) );1205commandThread.interrupt();1206}12071208/**1209* Culls the specified source. A culled source can not be played until it has1210* been activated again.1211* @param sourcename Identifier for the source.1212*/1213public void cull( String sourcename )1214{1215CommandQueue( new CommandObject( CommandObject.CULL, sourcename) );1216commandThread.interrupt();1217}12181219/**1220* Activates the specified source after it was culled, so it can be played1221* again.1222* @param sourcename Identifier for the source.1223*/1224public void activate( String sourcename )1225{1226CommandQueue( new CommandObject( CommandObject.ACTIVATE, sourcename) );1227commandThread.interrupt();1228}12291230/**1231* Sets a flag for a source indicating whether it should be used or if it1232* should be removed after it finishes playing. One possible use for this1233* method is to make temporary sources that were created with quickPlay()1234* permanant. Another use could be to have a source automatically removed1235* after it finishes playing. NOTE: Setting a source to temporary does not1236* stop it, and setting a source to permanant does not play it. It is also1237* important to note that a looping temporary source will not be removed as1238* long as it keeps playing.1239* @param sourcename Identifier for the source.1240* @param temporary True = temporary, False = permanant.1241*/1242public void setTemporary( String sourcename, boolean temporary )1243{1244CommandQueue( new CommandObject( CommandObject.SET_TEMPORARY,1245sourcename, temporary ) );1246commandThread.interrupt();1247}12481249/**1250* Removes the specified source and clears up any memory it used.1251* @param sourcename Identifier for the source.1252*/1253public void removeSource( String sourcename )1254{1255CommandQueue( new CommandObject( CommandObject.REMOVE_SOURCE,1256sourcename ) );1257commandThread.interrupt();1258}1259/**1260* Moves the listener relative to the current location.1261* @param x X offset.1262* @param y Y offset.1263* @param z Z offset.1264*/1265public void moveListener( float x, float y, float z )1266{1267CommandQueue( new CommandObject( CommandObject.MOVE_LISTENER,1268x, y, z ) );1269commandThread.interrupt();1270}1271/**1272* Moves the listener to the specified location.1273* @param x Destination X coordinate.1274* @param y Destination Y coordinate.1275* @param z Destination Z coordinate.1276*/1277public void setListenerPosition( float x, float y, float z )1278{1279CommandQueue( new CommandObject( CommandObject.SET_LISTENER_POSITION,1280x, y, z ) );1281commandThread.interrupt();1282}1283/**1284* Turns the listener counterclockwise by "angle" radians around the y-axis,1285* relative to the current angle.1286* @param angle radian offset.1287*/1288public void turnListener( float angle )1289{1290CommandQueue( new CommandObject( CommandObject.TURN_LISTENER,1291angle ) );1292commandThread.interrupt();1293}1294/**1295* Sets the listener's angle in radians around the y-axis.1296* @param angle radians.1297*/1298public void setListenerAngle( float angle )1299{1300CommandQueue( new CommandObject( CommandObject.SET_LISTENER_ANGLE,1301angle ) );1302commandThread.interrupt();1303}1304/**1305* Sets the listener's orientation.1306* @param lookX X coordinate of the (normalized) look-at vector.1307* @param lookY Y coordinate of the (normalized) look-at vector.1308* @param lookZ Z coordinate of the (normalized) look-at vector.1309* @param upX X coordinate of the (normalized) up-direction vector.1310* @param upY Y coordinate of the (normalized) up-direction vector.1311* @param upZ Z coordinate of the (normalized) up-direction vector.1312*/1313public void setListenerOrientation( float lookX, float lookY, float lookZ,1314float upX, float upY, float upZ )1315{1316CommandQueue( new CommandObject( CommandObject.SET_LISTENER_ORIENTATION,1317lookX, lookY, lookZ, upX, upY, upZ ) );1318commandThread.interrupt();1319}13201321/**1322* Sets the overall volume, affecting all sources.1323* @param value New volume, float value ( 0.0f - 1.0f ).1324*/1325public void setMasterVolume( float value )1326{1327CommandQueue( new CommandObject( CommandObject.SET_MASTER_VOLUME,1328value ) );1329commandThread.interrupt();1330}13311332/**1333* Returns the overall volume, affecting all sources.1334* @return Float value representing the master volume (0.0f - 1.0f).1335*/1336public float getMasterVolume()1337{1338return SoundSystemConfig.getMasterGain();1339}13401341/**1342* Method for obtaining information about the listener's position and1343* orientation.1344* @return a {@link paulscode.sound.ListenerData ListenerData} object.1345*/1346public ListenerData getListenerData()1347{1348synchronized( SoundSystemConfig.THREAD_SYNC )1349{1350return soundLibrary.getListenerData();1351}1352}1353/**1354* Switches to the specified library, and preserves all sources.1355* @param libraryClass Library to use.1356* @return True if switch was successful.1357* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for1358* information about chosing a sound library.1359*/1360public boolean switchLibrary( Class libraryClass )1361throws SoundSystemException1362{1363synchronized( SoundSystemConfig.THREAD_SYNC )1364{1365initialized( SET, false );13661367HashMap<String, Source> sourceMap = null;1368ListenerData listenerData = null;13691370boolean wasMidiChannel = false;1371MidiChannel midiChannel = null;1372FilenameURL midiFilenameURL = null;1373String midiSourcename = "";1374boolean midiToLoop = true;13751376if( soundLibrary != null )1377{1378currentLibrary( SET, null );1379sourceMap = copySources( soundLibrary.getSources() );1380listenerData = soundLibrary.getListenerData();1381midiChannel = soundLibrary.getMidiChannel();1382if( midiChannel != null )1383{1384wasMidiChannel = true;1385midiToLoop = midiChannel.getLooping();1386midiSourcename = midiChannel.getSourcename();1387midiFilenameURL = midiChannel.getFilenameURL();1388}13891390soundLibrary.cleanup();1391soundLibrary = null;1392}1393message( "", 0 );1394message( "Switching to "1395+ SoundSystemConfig.getLibraryTitle( libraryClass ), 0 );1396message( "(" + SoundSystemConfig.getLibraryDescription( libraryClass )1397+ ")", 1 );13981399try1400{1401soundLibrary = (Library) libraryClass.newInstance();1402}1403catch( InstantiationException ie )1404{1405errorMessage( "The specified library did not load properly", 1 );1406}1407catch( IllegalAccessException iae )1408{1409errorMessage( "The specified library did not load properly", 1 );1410}1411catch( ExceptionInInitializerError eiie )1412{1413errorMessage( "The specified library did not load properly", 1 );1414}1415catch( SecurityException se )1416{1417errorMessage( "The specified library did not load properly", 1 );1418}14191420if( errorCheck( soundLibrary == null, "Library null after " +1421"initialization in method 'switchLibrary'", 1 ) )1422{1423SoundSystemException sse = new SoundSystemException(1424className + " did not load properly. " +1425"Library was null after initialization.",1426SoundSystemException.LIBRARY_NULL );1427lastException( SET, sse );1428initialized( SET, true );1429throw sse;1430}14311432try1433{1434soundLibrary.init();1435}1436catch( SoundSystemException sse )1437{1438lastException( SET, sse );1439initialized( SET, true );1440throw sse;1441}14421443soundLibrary.setListenerData( listenerData );1444if( wasMidiChannel )1445{1446if( midiChannel != null )1447midiChannel.cleanup();1448midiChannel = new MidiChannel( midiToLoop, midiSourcename,1449midiFilenameURL );1450soundLibrary.setMidiChannel( midiChannel );1451}1452soundLibrary.copySources( sourceMap );14531454message( "", 0 );14551456lastException( SET, null );1457initialized( SET, true );14581459return true;1460}1461}14621463/**1464* Switches to the specified library, loosing all sources.1465* @param libraryClass Library to use.1466* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for1467* information about chosing a sound library.1468*/1469public boolean newLibrary( Class libraryClass )1470throws SoundSystemException1471{1472initialized( SET, false );14731474CommandQueue( new CommandObject( CommandObject.NEW_LIBRARY,1475libraryClass ) );1476commandThread.interrupt();14771478for( int x = 0; (!initialized( GET, XXX )) && (x < 100); x++ )1479{1480snooze( 400 );1481commandThread.interrupt();1482}14831484if( !initialized( GET, XXX ) )1485{1486SoundSystemException sse = new SoundSystemException(1487className +1488" did not load after 30 seconds.",1489SoundSystemException.LIBRARY_NULL );1490lastException( SET, sse );1491throw sse;1492}1493else1494{1495SoundSystemException sse = lastException( GET, null );1496if( sse != null )1497throw sse;1498}1499return true;1500}15011502/**1503* Switches to the specified library, loosing all sources. This method is used1504* internally by SoundSystem for thread synchronization, and it can not be1505* called directly - please use the newLibrary() method instead.1506* @param libraryClass Library to use.1507* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for1508* information about chosing a sound library.1509*/1510private void CommandNewLibrary( Class libraryClass )1511{1512initialized( SET, false );15131514String headerMessage = "Initializing ";1515if( soundLibrary != null )1516{1517currentLibrary( SET, null );1518// we are switching libraries1519headerMessage = "Switching to ";1520soundLibrary.cleanup();1521soundLibrary = null;1522}1523message( headerMessage +1524SoundSystemConfig.getLibraryTitle( libraryClass ), 0 );1525message( "(" + SoundSystemConfig.getLibraryDescription( libraryClass )1526+ ")", 1 );15271528try1529{1530soundLibrary = (Library) libraryClass.newInstance();1531}1532catch( InstantiationException ie )1533{1534errorMessage( "The specified library did not load properly", 1 );1535}1536catch( IllegalAccessException iae )1537{1538errorMessage( "The specified library did not load properly", 1 );1539}1540catch( ExceptionInInitializerError eiie )1541{1542errorMessage( "The specified library did not load properly", 1 );1543}1544catch( SecurityException se )1545{1546errorMessage( "The specified library did not load properly", 1 );1547}15481549if( errorCheck( soundLibrary == null, "Library null after " +1550"initialization in method 'newLibrary'", 1 ) )1551{1552lastException( SET, new SoundSystemException(1553className + " did not load properly. " +1554"Library was null after initialization.",1555SoundSystemException.LIBRARY_NULL ) );1556importantMessage( "Switching to silent mode", 1 );15571558try1559{1560soundLibrary = new Library();1561}1562catch( SoundSystemException sse )1563{1564lastException( SET, new SoundSystemException(1565"Silent mode did not load properly. " +1566"Library was null after initialization.",1567SoundSystemException.LIBRARY_NULL ) );1568initialized( SET, true );1569return;1570}1571}15721573try1574{1575soundLibrary.init();1576}1577catch( SoundSystemException sse )1578{1579lastException( SET, sse );1580initialized( SET, true );1581return;1582}15831584lastException( SET, null );1585initialized( SET, true );15861587return;1588}1589/**1590* Calls the library's initialize() method. This method is used1591* internally by SoundSystem for thread synchronization, and it can not be1592* called directly.1593*/1594private void CommandInitialize()1595{1596try1597{1598if( errorCheck( soundLibrary == null, "Library null after " +1599"initialization in method 'CommandInitialize'",16001 ) )1601{1602SoundSystemException sse = new SoundSystemException(1603className + " did not load properly. " +1604"Library was null after initialization.",1605SoundSystemException.LIBRARY_NULL );1606lastException( SET, sse );1607throw sse;1608}1609soundLibrary.init();1610}1611catch( SoundSystemException sse )1612{1613lastException( SET, sse );1614initialized( SET, true );1615}1616}1617/**1618* Loads sample data from a sound file or URL into memory. This method is used1619* internally by SoundSystem for thread synchronization, and it can not be1620* called directly - please use the loadSound() method instead.1621* @param filenameURL Filename/URL of the sound file to load.1622*/1623private void CommandLoadSound( FilenameURL filenameURL )1624{1625if( soundLibrary != null )1626soundLibrary.loadSound( filenameURL );1627else1628errorMessage(1629"Variable 'soundLibrary' null in method 'CommandLoadSound'", 0 );1630}1631/**1632* Saves the specified sample data, under the specified identifier. This1633* identifier can be later used in place of 'filename' parameters to reference1634* the sample data. This method is used internally by SoundSystem for thread1635* synchronization, and it can not be called directly - please use the1636* loadSound() method instead.1637* @param buffer the sample data and audio format to save.1638* @param identifier What to call the sample.1639*/1640private void CommandLoadSound( SoundBuffer buffer, String identifier )1641{1642if( soundLibrary != null )1643soundLibrary.loadSound( buffer, identifier );1644else1645errorMessage(1646"Variable 'soundLibrary' null in method 'CommandLoadSound'", 0 );1647}1648/**1649* Removes previously loaded sampled data from memory. This method is used1650* internally by SoundSystem for thread synchronization, and it can not be1651* called directly - please use the unloadSound() method instead.1652* @param filename Filename or string identifyer of sound to unload.1653*/1654private void CommandUnloadSound( String filename )1655{1656if( soundLibrary != null )1657soundLibrary.unloadSound( filename );1658else1659errorMessage(1660"Variable 'soundLibrary' null in method 'CommandLoadSound'", 0 );1661}1662/**1663* If the specified source is a streaming source or MIDI source, this method1664* queues up the next sound to play when the previous playback ends. This1665* method has no effect on non-streaming sources. This method is used1666* internally by SoundSystem for thread synchronization, and it can not be1667* called directly - please use the queueSound() method instead.1668* @param sourcename Source identifier.1669* @param filenameURL Filename/URL of the sound file to play next.1670*/1671private void CommandQueueSound( String sourcename,1672FilenameURL filenameURL )1673{1674if( soundLibrary != null )1675soundLibrary.queueSound( sourcename, filenameURL );1676else1677errorMessage(1678"Variable 'soundLibrary' null in method 'CommandQueueSound'", 0 );1679}1680/**1681* Removes the first occurrence of the specified filename/identifier from the1682* specified source's list of sounds to play when previous playback ends. This1683* method has no effect on non-streaming sources. This method is used1684* internally by SoundSystem for thread synchronization, and it can not be1685* called directly - please use the dequeueSound() method instead.1686* @param sourcename Source identifier.1687* @param filename Filename/identifier of the sound file to remove from the queue.1688*/1689private void CommandDequeueSound( String sourcename, String filename )1690{1691if( soundLibrary != null )1692soundLibrary.dequeueSound( sourcename, filename );1693else1694errorMessage(1695"Variable 'soundLibrary' null in method 'CommandDequeueSound'", 0 );1696}1697/**1698* Fades out the volume of whatever the specified source is currently playing,1699* then begins playing the specified file at the source's previously1700* assigned volume level. If the filenameURL parameter is null or empty, the1701* specified source will simply fade out and stop. The miliseconds parameter1702* must be non-negative or zero. This method will remove anything that is1703* currently in the specified source's list of queued sounds that would have1704* played next when the current sound finished playing. This method may only1705* be used for streaming and MIDI sources. This method is used1706* internally by SoundSystem for thread synchronization, and it can not be1707* called directly - please use the fadeOut() method instead.1708* @param sourcename Name of the source to fade out.1709* @param filenameURL Filename/URL of a sound file to play next, or null for none.1710* @param milis Number of miliseconds the fadeout should take.1711*/1712private void CommandFadeOut( String sourcename, FilenameURL filenameURL,1713long milis )1714{1715if( soundLibrary != null )1716soundLibrary.fadeOut( sourcename, filenameURL, milis );1717else1718errorMessage(1719"Variable 'soundLibrary' null in method 'CommandFadeOut'", 0 );1720}1721/**1722* Fades out the volume of whatever the specified source is currently playing,1723* then fades the volume back in playing the specified file. Final volume1724* after fade-in completes will be equal to the source's previously assigned1725* volume level. The filenameURL parameter may not be null or empty. The1726* miliseconds parameters must be non-negative or zero. This method will1727* remove anything that is currently in the specified source's list of queued1728* sounds that would have played next when the current sound finished playing.1729* This method may only be used for streaming and MIDI sources. This method is1730* used internally by SoundSystem for thread synchronization, and it can not be1731* called directly - please use the fadeOutIn() method instead.1732* @param sourcename Name of the source to fade out/in.1733* @param filenameURL Filename/URL of a sound file to play next, or null for none.1734* @param milisOut Number of miliseconds the fadeout should take.1735* @param milisIn Number of miliseconds the fadein should take.1736*/1737private void CommandFadeOutIn( String sourcename, FilenameURL filenameURL,1738long milisOut, long milisIn )1739{1740if( soundLibrary != null )1741soundLibrary.fadeOutIn( sourcename, filenameURL, milisOut,1742milisIn );1743else1744errorMessage(1745"Variable 'soundLibrary' null in method 'CommandFadeOutIn'", 0 );1746}1747/**1748* Makes sure the current volume levels of streaming sources and MIDI are1749* correct. This method is designed to help reduce the "jerky" fading behavior1750* that happens when using some library and codec pluggins (such as1751* LibraryJavaSound and CodecJOrbis). This method has no effect on normal1752* "non-streaming" sources. It would normally be called somewhere in the main1753* "game loop". IMPORTANT: To optimize frame-rates, do not call this method1754* for every frame. It is better to just call this method at some acceptable1755* "granularity" (play around with different granularities to find what sounds1756* acceptable for a particular situation). This method is used1757* internally by SoundSystem for thread synchronization, and it can not be1758* called directly - please use the checkFadeVolumes() method instead.1759*/1760private void CommandCheckFadeVolumes()1761{1762if( soundLibrary != null )1763soundLibrary.checkFadeVolumes();1764else1765errorMessage( "Variable 'soundLibrary' null in method " +1766"'CommandCheckFadeVolumes'", 0 );1767}1768/**1769* Loads a sound file into memory. This method is used internally by1770* SoundSystem for thread synchronization, and it can not be called directly -1771* please use the newSource() method instead.1772* @param priority Setting this to true will prevent other sounds from overriding this one.1773* @param toStream Whether or not to stream the source.1774* @param toLoop Whether or not to loop the source.1775* @param sourcename A unique identifier for the source.1776* @param filenameURL Filename/URL of the sound file to play at this source.1777* @param x X position for this source.1778* @param y Y position for this source.1779* @param z Z position for this source.1780* @param attModel Attenuation model to use.1781* @param distORroll Either the fading distance or rolloff factor, depending on the value of "attmodel".1782*/1783private void CommandNewSource( boolean priority, boolean toStream,1784boolean toLoop, String sourcename,1785FilenameURL filenameURL, float x,1786float y, float z, int attModel,1787float distORroll )1788{1789if( soundLibrary != null )1790{1791if( filenameURL.getFilename().matches(1792SoundSystemConfig.EXTENSION_MIDI )1793&& !SoundSystemConfig.midiCodec() )1794{1795soundLibrary.loadMidi( toLoop, sourcename, filenameURL );1796}1797else1798{1799soundLibrary.newSource( priority, toStream, toLoop, sourcename,1800filenameURL, x, y, z, attModel,1801distORroll );1802}1803}1804else1805errorMessage(1806"Variable 'soundLibrary' null in method 'CommandNewSource'", 0 );1807}1808/**1809* Opens a direct line for streaming audio data. This method is used1810* internally by SoundSystem, and it can not be called directly - please use1811* the rawDataStream() method instead.1812* @param audioFormat Format that the data will be in.1813* @param priority Setting this to true will prevent other sounds from overriding this one.1814* @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.1815* @param x X position for this source.1816* @param y Y position for this source.1817* @param z Z position for this source.1818* @param attModel Attenuation model to use.1819* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of "attmodel".1820*/1821private void CommandRawDataStream( AudioFormat audioFormat,1822boolean priority, String sourcename,1823float x, float y, float z,1824int attModel, float distOrRoll )1825{1826if( soundLibrary != null )1827soundLibrary.rawDataStream( audioFormat, priority, sourcename,1828x, y, z, attModel, distOrRoll );1829else1830errorMessage(1831"Variable 'soundLibrary' null in method 'CommandRawDataStream'", 0 );1832}1833/**1834* Creates a temporary source and either plays or streams it. After the source1835* finishes playing, it is removed. This method is used internally by1836* SoundSystem for thread synchronization, and it can not be called directly -1837* please use the quickPlay() method instead.1838* @param priority Setting this to true will prevent other sounds from overriding this one.1839* @param toStream Whether or not to stream the source.1840* @param toLoop Whether or not to loop the source.1841* @param sourcename A unique identifier for the source.1842* @param filenameURL Filename/URL of the sound file to play at this source.1843* @param x X position for this source.1844* @param y Y position for this source.1845* @param z Z position for this source.1846* @param attModel Attenuation model to use.1847* @param distORroll Either the fading distance or rolloff factor, depending on the value of "attmodel".1848* @param temporary Whether or not the source should be removed after it finishes playing.1849*/1850private void CommandQuickPlay( boolean priority, boolean toStream,1851boolean toLoop, String sourcename,1852FilenameURL filenameURL, float x, float y,1853float z, int attModel, float distORroll,1854boolean temporary )1855{1856if( soundLibrary != null )1857{1858if( filenameURL.getFilename().matches( SoundSystemConfig.EXTENSION_MIDI ) &&1859!SoundSystemConfig.midiCodec() )1860{1861soundLibrary.loadMidi( toLoop, sourcename, filenameURL );1862}1863else1864{1865soundLibrary.quickPlay( priority, toStream, toLoop, sourcename,1866filenameURL, x, y, z, attModel,1867distORroll, temporary );1868}1869}1870else1871errorMessage(1872"Variable 'soundLibrary' null in method 'CommandQuickPlay'", 0 );1873}1874/**1875* Moves a source to the specified coordinates. This method is used1876* internally by SoundSystem for thread synchronization, and it can not be1877* called directly - please use the setPosition() method instead.1878* @param sourcename Source to move.1879* @param x Destination X coordinate.1880* @param y Destination Y coordinate.1881* @param z Destination Z coordinate.1882*/1883private void CommandSetPosition( String sourcename, float x, float y,1884float z)1885{1886if( soundLibrary != null )1887soundLibrary.setPosition( sourcename, x, y, z );1888else1889errorMessage(1890"Variable 'soundLibrary' null in method 'CommandMoveSource'", 0 );1891}1892/**1893* Manually sets the specified source's volume. This method is used1894* internally by SoundSystem for thread synchronization, and it can not be1895* called directly - please use the setVolume() method instead.1896* @param sourcename Source to change the volume of.1897* @param value New volume, float value ( 0.0f - 1.0f ).1898*/1899private void CommandSetVolume( String sourcename, float value )1900{1901if( soundLibrary != null )1902soundLibrary.setVolume( sourcename, value );1903else1904errorMessage(1905"Variable 'soundLibrary' null in method 'CommandSetVolume'", 0 );1906}1907/**1908* Manually sets the specified source's pitch. This method is used1909* internally by SoundSystem for thread synchronization, and it can not be1910* called directly - please use the setPitch() method instead.1911* @param sourcename Source to change the pitch of.1912* @param value New pitch, float value ( 0.5f - 2.0f ).1913*/1914private void CommandSetPitch( String sourcename, float value )1915{1916if( soundLibrary != null )1917soundLibrary.setPitch( sourcename, value );1918else1919errorMessage(1920"Variable 'soundLibrary' null in method 'CommandSetPitch'", 0 );1921}1922/**1923* Set a source's priority factor. A priority source will not be overriden when1924* too many sources are playing at once. This method is used1925* internally by SoundSystem for thread synchronization, and it can not be1926* called directly - please use the setPriority() method instead.1927* @param sourcename Identifier for the source.1928* @param pri Setting this to true makes this source a priority source.1929*/1930private void CommandSetPriority( String sourcename, boolean pri )1931{1932if( soundLibrary != null )1933soundLibrary.setPriority( sourcename, pri );1934else1935errorMessage(1936"Variable 'soundLibrary' null in method 'CommandSetPriority'", 0 );1937}1938/**1939* Changes a source to looping or non-looping. This method is used1940* internally by SoundSystem for thread synchronization, and it can not be1941* called directly - please use the setLooping() method instead.1942* @param sourcename Identifier for the source.1943* @param lp This source should loop.1944*/1945private void CommandSetLooping( String sourcename, boolean lp )1946{1947if( soundLibrary != null )1948soundLibrary.setLooping( sourcename, lp );1949else1950errorMessage(1951"Variable 'soundLibrary' null in method 'CommandSetLooping'", 0 );1952}1953/**1954* Changes a source's attenuation model. This method is used1955* internally by SoundSystem for thread synchronization, and it can not be1956* called directly - please use the setAttenuation() method instead.1957* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more1958* information about Attenuation.1959* @param sourcename Identifier for the source.1960* @param model Attenuation model to use.1961*/1962private void CommandSetAttenuation( String sourcename, int model )1963{1964if( soundLibrary != null )1965soundLibrary.setAttenuation( sourcename, model );1966else1967errorMessage(1968"Variable 'soundLibrary' null in method 'CommandSetAttenuation'",19690 );1970}1971/**1972* Changes a source's fade distance or rolloff factor.1973* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more1974* information about fade distance and rolloff.1975* @param sourcename Identifier for the source.1976* @param dr Either the fading distance or rolloff factor, depending on the attenuation model used.1977*/1978private void CommandSetDistOrRoll( String sourcename, float dr )1979{1980if( soundLibrary != null )1981soundLibrary.setDistOrRoll( sourcename, dr );1982else1983errorMessage(1984"Variable 'soundLibrary' null in method 'CommandSetDistOrRoll'",19850 );1986}1987/**1988* Changes the Doppler factor. This method is used internally by SoundSystem1989* for thread synchronization, and it can not be called directly - please use1990* the setDopplerFactor() method instead.1991* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more1992* information about Doppler effect.1993* @param dopplerFactor New Doppler factor, for determining Doppler effect scale.1994*/1995private void CommandChangeDopplerFactor( float dopplerFactor )1996{1997if( soundLibrary != null )1998{1999SoundSystemConfig.setDopplerFactor( dopplerFactor );2000soundLibrary.dopplerChanged();2001}2002else2003errorMessage(2004"Variable 'soundLibrary' null in method 'CommandSetDopplerFactor'",20050 );2006}2007/**2008* Changes the Doppler velocity. This method is used internally by SoundSystem2009* for thread synchronization, and it can not be called directly - please use2010* the setDopplerVelocity() method instead.2011* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more2012* information about Doppler effect.2013* @param dopplerVelocity New Doppler velocity, for use in Doppler effect.2014*/2015private void CommandChangeDopplerVelocity( float dopplerVelocity )2016{2017if( soundLibrary != null )2018{2019SoundSystemConfig.setDopplerVelocity( dopplerVelocity );2020soundLibrary.dopplerChanged();2021}2022else2023errorMessage(2024"Variable 'soundLibrary' null in method 'CommandSetDopplerFactor'",20250 );2026}2027/**2028* Changes a source's velocity, for use in Doppler effect. This method is used2029* internally by SoundSystem for thread synchronization, and it can not be2030* called directly - please use the setVelocity() method instead.2031* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more2032* information about Doppler effect.2033* @param sourcename Identifier for the source.2034* @param x Source's velocity along the world x-axis.2035* @param y Source's velocity along the world y-axis.2036* @param z Source's velocity along the world z-axis.2037*/2038private void CommandSetVelocity( String sourcename, float x, float y, float z )2039{2040if( soundLibrary != null )2041soundLibrary.setVelocity( sourcename, x, y, z );2042else2043errorMessage(2044"Variable 'soundLibrary' null in method 'CommandVelocity'",20450 );2046}2047/**2048* Changes the listener's velocity, for use in Doppler effect. This method is2049* used internally by SoundSystem for thread synchronization, and it can not be2050* called directly - please use the setListenerVelocity() method instead.2051* See {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more2052* information about Doppler effect.2053* @param x Velocity along the world x-axis.2054* @param y Velocity along the world y-axis.2055* @param z Velocity along the world z-axis.2056*/2057private void CommandSetListenerVelocity( float x, float y, float z )2058{2059if( soundLibrary != null )2060soundLibrary.setListenerVelocity( x, y, z );2061else2062errorMessage(2063"Variable 'soundLibrary' null in method 'CommandSetListenerVelocity'",20640 );2065}2066/**2067* Plays the specified source. This method is used2068* internally by SoundSystem for thread synchronization, and it can not be2069* called directly - please use the play() method instead.2070* @param sourcename Identifier for the source.2071*/2072private void CommandPlay( String sourcename )2073{2074if( soundLibrary != null )2075soundLibrary.play( sourcename );2076else2077errorMessage(2078"Variable 'soundLibrary' null in method 'CommandPlay'", 0 );2079}2080/**2081* Feeds raw data through the specified source. The source must be a2082* streaming source and it can not be already associated with a file or URL to2083* stream from. This method is used internally by SoundSystem for thread2084* synchronization, and it can not be called directly - please use the2085* feedRawAudioData() method instead.2086* @param sourcename Name of the streaming source to play from.2087* @param buffer Byte buffer containing raw audio data to stream.2088*/2089private void CommandFeedRawAudioData( String sourcename, byte[] buffer )2090{2091if( soundLibrary != null )2092soundLibrary.feedRawAudioData( sourcename, buffer );2093else2094errorMessage(2095"Variable 'soundLibrary' null in method 'CommandFeedRawAudioData'", 0 );2096}2097/**2098* Pauses the specified source. This method is used2099* internally by SoundSystem for thread synchronization, and it can not be2100* called directly - please use the pause() method instead.2101* @param sourcename Identifier for the source.2102*/2103private void CommandPause( String sourcename )2104{2105if( soundLibrary != null )2106soundLibrary.pause( sourcename );2107else2108errorMessage(2109"Variable 'soundLibrary' null in method 'CommandPause'", 0 );2110}2111/**2112* Stops the specified source. This method is used2113* internally by SoundSystem for thread synchronization, and it can not be2114* called directly - please use the stop() method instead.2115* @param sourcename Identifier for the source.2116*/2117private void CommandStop( String sourcename )2118{2119if( soundLibrary != null )2120soundLibrary.stop( sourcename );2121else2122errorMessage(2123"Variable 'soundLibrary' null in method 'CommandStop'", 0 );2124}2125/**2126* Rewinds the specified source. This method is used2127* internally by SoundSystem for thread synchronization, and it can not be2128* called directly - please use the rewind() method instead.2129* @param sourcename Identifier for the source.2130*/2131private void CommandRewind( String sourcename )2132{2133if( soundLibrary != null )2134soundLibrary.rewind( sourcename );2135else2136errorMessage(2137"Variable 'soundLibrary' null in method 'CommandRewind'", 0 );2138}2139/**2140* Flushes all previously queued audio data from a streaming source. This2141* method is used internally by SoundSystem for thread synchronization, and it2142* can not be called directly - please use the flush() method instead.2143* @param sourcename Identifier for the source.2144*/2145private void CommandFlush( String sourcename )2146{2147if( soundLibrary != null )2148soundLibrary.flush( sourcename );2149else2150errorMessage(2151"Variable 'soundLibrary' null in method 'CommandFlush'", 0 );2152}2153/**2154* Sets a flag for a source indicating whether it should be used or if it2155* should be removed after it finishes playing. One possible use for this2156* method is to make temporary sources that were created with quickPlay()2157* permanant. Another use could be to have a source automatically removed2158* after it finishes playing. NOTE: Setting a source to inactive does not stop2159* it, and setting a source to active does not play it. It is also important2160* to note that a looping inactive source will not be removed as long as2161* it keeps playing. This method is used2162* internally by SoundSystem for thread synchronization, and it can not be2163* called directly - please use the setTemporary() method instead.2164* @param sourcename Identifier for the source.2165* @param temporary True or False.2166*/2167private void CommandSetTemporary( String sourcename, boolean temporary )2168{2169if( soundLibrary != null )2170soundLibrary.setTemporary( sourcename, temporary );2171else2172errorMessage(2173"Variable 'soundLibrary' null in method 'CommandSetActive'", 0 );2174}2175/**2176* Removes the specified source and clears up any memory it used. This method2177* is used internally by SoundSystem for thread synchronization, and it can not2178* be called directly - please use the removeSource() method instead.2179* @param sourcename Identifier for the source.2180*/2181private void CommandRemoveSource( String sourcename )2182{2183if( soundLibrary != null )2184soundLibrary.removeSource( sourcename );2185else2186errorMessage(2187"Variable 'soundLibrary' null in method 'CommandRemoveSource'", 0 );2188}2189/**2190* Moves the listener relative to the current location. This method is used2191* internally by SoundSystem for thread synchronization, and it can not be2192* called directly - please use the moveListener() method instead.2193* @param x X offset.2194* @param y Y offset.2195* @param z Z offset.2196*/2197private void CommandMoveListener( float x, float y, float z )2198{2199if( soundLibrary != null )2200soundLibrary.moveListener( x, y, z );2201else2202errorMessage(2203"Variable 'soundLibrary' null in method 'CommandMoveListener'", 0 );2204}2205/**2206* Moves the listener to the specified location. This method is used2207* internally by SoundSystem for thread synchronization, and it can not be2208* called directly - please use the setListenerPosition() method instead.2209* @param x Destination X coordinate.2210* @param y Destination Y coordinate.2211* @param z Destination Z coordinate.2212*/2213private void CommandSetListenerPosition( float x, float y, float z )2214{2215if( soundLibrary != null )2216soundLibrary.setListenerPosition( x, y, z );2217else2218errorMessage(2219"Variable 'soundLibrary' null in method 'CommandSetListenerPosition'",22200 );2221}2222/**2223* Turns the listener counterclockwise by "angle" radians around the y-axis,2224* relative to the current angle. This method is used2225* internally by SoundSystem for thread synchronization, and it can not be2226* called directly - please use the turnListener() method instead.2227* @param angle radian offset.2228*/2229private void CommandTurnListener( float angle )2230{2231if( soundLibrary != null )2232soundLibrary.turnListener( angle );2233else2234errorMessage(2235"Variable 'soundLibrary' null in method 'CommandTurnListener'",22360 );2237}2238/**2239* Sets the listener's angle in radians around the y-axis. This method is used2240* internally by SoundSystem for thread synchronization, and it can not be2241* called directly - please use the setListenerAngle() method instead.2242* @param angle radians.2243*/2244private void CommandSetListenerAngle( float angle )2245{2246if( soundLibrary != null )2247soundLibrary.setListenerAngle( angle );2248else2249errorMessage(2250"Variable 'soundLibrary' null in method 'CommandSetListenerAngle'",22510 );2252}2253/**2254* Sets the listener's orientation. This method is used2255* internally by SoundSystem for thread synchronization, and it can not be2256* called directly - please use the setListenerOrientation() method instead.2257* @param lookX X coordinate of the (normalized) look-at vector.2258* @param lookY Y coordinate of the (normalized) look-at vector.2259* @param lookZ Z coordinate of the (normalized) look-at vector.2260* @param upX X coordinate of the (normalized) look-at vector.2261* @param upY Y coordinate of the (normalized) look-at vector.2262* @param upZ Z coordinate of the (normalized) look-at vector.2263*/2264private void CommandSetListenerOrientation( float lookX, float lookY,2265float lookZ, float upX,2266float upY, float upZ )2267{2268if( soundLibrary != null )2269soundLibrary.setListenerOrientation( lookX, lookY, lookZ, upX, upY,2270upZ );2271else2272errorMessage(2273"Variable 'soundLibrary' null in method 'CommandSetListenerOrientation'",22740 );2275}2276/**2277* Culls the specified source. A culled source can not be played until it has2278* been activated again. This method is used2279* internally by SoundSystem for thread synchronization, and it can not be2280* called directly - please use the cull() method instead.2281* @param sourcename Identifier for the source.2282*/2283private void CommandCull( String sourcename )2284{2285if( soundLibrary != null )2286soundLibrary.cull( sourcename );2287else2288errorMessage(2289"Variable 'soundLibrary' null in method 'CommandCull'", 0 );2290}2291/**2292* Activates a previously culled source, so it can be played again. This2293* method is used internally by SoundSystem for thread synchronization, and it2294* can not be called directly - please use the activate() method instead.2295* @param sourcename Identifier for the source.2296*/2297private void CommandActivate( String sourcename )2298{2299if( soundLibrary != null )2300soundLibrary.activate( sourcename );2301else2302errorMessage(2303"Variable 'soundLibrary' null in method 'CommandActivate'",23040 );2305}2306/**2307* Sets the overall volume, affecting all sources. This method is used2308* internally by SoundSystem for thread synchronization, and it can not be2309* called directly - please use the setMasterVolume() method instead.2310* @param value New volume, float value ( 0.0f - 1.0f ).2311*/2312private void CommandSetMasterVolume( float value )2313{2314if( soundLibrary != null )2315soundLibrary.setMasterVolume( value );2316else2317errorMessage(2318"Variable 'soundLibrary' null in method 'CommandSetMasterVolume'",23190 );2320}23212322/**2323* This method can be overridden by extended classes to be used for source2324* management (culling and activating sources based on established rules). One2325* possible use for this method is sorting sources by distance, culling the2326* furthest, and activating the closest.2327* This method is automatically called on the CommandThread before processing2328* queued commands, so you do not need to call it anywhere else. Note: use2329* methods cull() and activate() here, NOT CommandCull() and CommandActivate()2330* (thread safety issue).2331* IMPORTANT: Always use synchronized( SoundSystemConfig.THREAD_SYNC ) when2332* manually manipulating sources from outside the Command Thread!2333*/2334protected void ManageSources()2335{2336// OVERRIDDEN METHODS MUST USE THIS:23372338/*******2339synchronized( SoundSystemConfig.THREAD_SYNC )2340{2341// TODO: Sort the sources, cull and activate, etc.2342}2343********/2344}23452346/**2347* Queues a command.2348* If newCommand is null, all commands are dequeued and executed.2349* This is automatically used by the sound system, so it is not2350* likely that a user would ever need to use this method.2351* See {@link paulscode.sound.CommandObject CommandObject} for more information2352* about commands.2353* @param newCommand Command to queue, or null to execute commands.2354* @return True if more commands exist, false if queue is empty.2355*/2356public boolean CommandQueue( CommandObject newCommand )2357{2358synchronized( SoundSystemConfig.THREAD_SYNC )2359{2360if( newCommand == null )2361{2362// New command is null - that means execute all queued commands.2363boolean activations = false;2364CommandObject commandObject;23652366// Loop through the command queue:2367while( commandQueue != null && commandQueue.size() > 0 )2368{2369// Grab the oldest command in the queue:2370commandObject = commandQueue.remove( 0 );2371// See what it is, and execute the proper Command method:2372if( commandObject != null )2373{2374switch( commandObject.Command )2375{2376case CommandObject.INITIALIZE:2377CommandInitialize();2378break;2379case CommandObject.LOAD_SOUND:2380CommandLoadSound(2381(FilenameURL) commandObject.objectArgs[0] );2382break;2383case CommandObject.LOAD_DATA:2384CommandLoadSound(2385(SoundBuffer) commandObject.objectArgs[0],2386commandObject.stringArgs[0] );2387break;2388case CommandObject.UNLOAD_SOUND:2389CommandUnloadSound( commandObject.stringArgs[0] );2390break;2391case CommandObject.QUEUE_SOUND:2392CommandQueueSound( commandObject.stringArgs[0],2393(FilenameURL) commandObject.objectArgs[0] );2394break;2395case CommandObject.DEQUEUE_SOUND:2396CommandDequeueSound( commandObject.stringArgs[0],2397commandObject.stringArgs[1] );2398break;2399case CommandObject.FADE_OUT:2400CommandFadeOut( commandObject.stringArgs[0],2401(FilenameURL) commandObject.objectArgs[0],2402commandObject.longArgs[0] );2403break;2404case CommandObject.FADE_OUT_IN:2405CommandFadeOutIn( commandObject.stringArgs[0],2406(FilenameURL) commandObject.objectArgs[0],2407commandObject.longArgs[0],2408commandObject.longArgs[1] );2409break;2410case CommandObject.CHECK_FADE_VOLUMES:2411CommandCheckFadeVolumes();2412break;2413case CommandObject.NEW_SOURCE:2414CommandNewSource( commandObject.boolArgs[0],2415commandObject.boolArgs[1],2416commandObject.boolArgs[2],2417commandObject.stringArgs[0],2418(FilenameURL) commandObject.objectArgs[0],2419commandObject.floatArgs[0],2420commandObject.floatArgs[1],2421commandObject.floatArgs[2],2422commandObject.intArgs[0],2423commandObject.floatArgs[3] );2424break;2425case CommandObject.RAW_DATA_STREAM:2426CommandRawDataStream(2427(AudioFormat) commandObject.objectArgs[0],2428commandObject.boolArgs[0],2429commandObject.stringArgs[0],2430commandObject.floatArgs[0],2431commandObject.floatArgs[1],2432commandObject.floatArgs[2],2433commandObject.intArgs[0],2434commandObject.floatArgs[3] );2435break;2436case CommandObject.QUICK_PLAY:2437CommandQuickPlay( commandObject.boolArgs[0],2438commandObject.boolArgs[1],2439commandObject.boolArgs[2],2440commandObject.stringArgs[0],2441(FilenameURL) commandObject.objectArgs[0],2442commandObject.floatArgs[0],2443commandObject.floatArgs[1],2444commandObject.floatArgs[2],2445commandObject.intArgs[0],2446commandObject.floatArgs[3],2447commandObject.boolArgs[3] );2448break;2449case CommandObject.SET_POSITION:2450CommandSetPosition( commandObject.stringArgs[0],2451commandObject.floatArgs[0],2452commandObject.floatArgs[1],2453commandObject.floatArgs[2] );2454break;2455case CommandObject.SET_VOLUME:2456CommandSetVolume( commandObject.stringArgs[0],2457commandObject.floatArgs[0] );2458break;2459case CommandObject.SET_PITCH:2460CommandSetPitch( commandObject.stringArgs[0],2461commandObject.floatArgs[0] );2462break;2463case CommandObject.SET_PRIORITY:2464CommandSetPriority( commandObject.stringArgs[0],2465commandObject.boolArgs[0] );2466break;2467case CommandObject.SET_LOOPING:2468CommandSetLooping( commandObject.stringArgs[0],2469commandObject.boolArgs[0] );2470break;2471case CommandObject.SET_ATTENUATION:2472CommandSetAttenuation( commandObject.stringArgs[0],2473commandObject.intArgs[0] );2474break;2475case CommandObject.SET_DIST_OR_ROLL:2476CommandSetDistOrRoll( commandObject.stringArgs[0],2477commandObject.floatArgs[0] );2478break;2479case CommandObject.CHANGE_DOPPLER_FACTOR:2480CommandChangeDopplerFactor(2481commandObject.floatArgs[0] );2482break;2483case CommandObject.CHANGE_DOPPLER_VELOCITY:2484CommandChangeDopplerVelocity(2485commandObject.floatArgs[0] );2486break;2487case CommandObject.SET_VELOCITY:2488CommandSetVelocity( commandObject.stringArgs[0],2489commandObject.floatArgs[0],2490commandObject.floatArgs[1],2491commandObject.floatArgs[2]2492);2493break;2494case CommandObject.SET_LISTENER_VELOCITY:2495CommandSetListenerVelocity(2496commandObject.floatArgs[0],2497commandObject.floatArgs[1],2498commandObject.floatArgs[2]2499);2500break;2501// Methods related to playing sources must be processed2502// after cull/activate commands in order for source2503// management to work properly, so save them for2504// later:2505//------------------------------------------------------2506case CommandObject.PLAY:2507sourcePlayList.add( commandObject );2508break;2509case CommandObject.FEED_RAW_AUDIO_DATA:2510sourcePlayList.add( commandObject );2511break;2512//------------------------------------------------------2513case CommandObject.PAUSE:2514CommandPause( commandObject.stringArgs[0] );2515break;2516case CommandObject.STOP:2517CommandStop( commandObject.stringArgs[0] );2518break;2519case CommandObject.REWIND:2520CommandRewind( commandObject.stringArgs[0] );2521break;2522case CommandObject.FLUSH:2523CommandFlush( commandObject.stringArgs[0] );2524break;2525case CommandObject.CULL:2526CommandCull( commandObject.stringArgs[0] );2527break;2528case CommandObject.ACTIVATE:2529activations = true;2530CommandActivate( commandObject.stringArgs[0] );2531break;2532case CommandObject.SET_TEMPORARY:2533CommandSetTemporary( commandObject.stringArgs[0],2534commandObject.boolArgs[0] );2535break;2536case CommandObject.REMOVE_SOURCE:2537CommandRemoveSource( commandObject.stringArgs[0] );2538break;2539case CommandObject.MOVE_LISTENER:2540CommandMoveListener( commandObject.floatArgs[0],2541commandObject.floatArgs[1],2542commandObject.floatArgs[2]);2543break;2544case CommandObject.SET_LISTENER_POSITION:2545CommandSetListenerPosition(2546commandObject.floatArgs[0],2547commandObject.floatArgs[1],2548commandObject.floatArgs[2]);2549break;2550case CommandObject.TURN_LISTENER:2551CommandTurnListener( commandObject.floatArgs[0] );2552break;2553case CommandObject.SET_LISTENER_ANGLE:2554CommandSetListenerAngle(2555commandObject.floatArgs[0]);2556break;2557case CommandObject.SET_LISTENER_ORIENTATION:2558CommandSetListenerOrientation(2559commandObject.floatArgs[0],2560commandObject.floatArgs[1],2561commandObject.floatArgs[2],2562commandObject.floatArgs[3],2563commandObject.floatArgs[4],2564commandObject.floatArgs[5]);2565break;2566case CommandObject.SET_MASTER_VOLUME:2567CommandSetMasterVolume(2568commandObject.floatArgs[0] );2569break;2570case CommandObject.NEW_LIBRARY:2571CommandNewLibrary( commandObject.classArgs[0] );2572break;2573// If we don't recognize the command, just skip it:2574default:2575break;2576}2577}2578}25792580// If any sources were reactivated, check if they need to be2581// replayed:2582if( activations )2583soundLibrary.replaySources();25842585// Now that we have the correct sources culled and activated, we2586// can start playing sources. Loop through the playlist and2587// execute the commands:2588while( sourcePlayList != null && sourcePlayList.size() > 0 )2589{2590// Grab the oldest command in the queue:2591commandObject = sourcePlayList.remove( 0 );2592if( commandObject != null )2593{2594// See what it is, and execute the proper Command method:2595switch( commandObject.Command )2596{2597case CommandObject.PLAY:2598CommandPlay( commandObject.stringArgs[0] );2599break;2600case CommandObject.FEED_RAW_AUDIO_DATA:2601CommandFeedRawAudioData(2602commandObject.stringArgs[0],2603commandObject.buffer );2604break;2605}2606}2607}26082609return( commandQueue != null && commandQueue.size() > 0 );2610}2611else2612{2613// make sure the commandQueue exists:2614if( commandQueue == null )2615return false;2616// queue a new command2617commandQueue.add( newCommand );2618// Of course there is something in the list now, since we just2619// added it:2620return true;2621}2622}2623}26242625/**2626* Searches for and removes any temporary sources that have finished2627* playing. This method is used internally by SoundSystem, and it is2628* unlikely that the user will ever need to use it.2629*/2630public void removeTemporarySources()2631{2632synchronized( SoundSystemConfig.THREAD_SYNC )2633{2634if( soundLibrary != null )2635soundLibrary.removeTemporarySources();2636}2637}26382639/**2640* Returns true if the specified source is playing.2641* @param sourcename Unique identifier of the source to check.2642* @return True or false.2643*/2644public boolean playing( String sourcename )2645{2646synchronized( SoundSystemConfig.THREAD_SYNC )2647{2648if( soundLibrary == null )2649return false;26502651Source src = soundLibrary.getSources().get( sourcename );26522653if( src == null )2654return false;26552656return src.playing();2657}2658}26592660/**2661* Returns true if anything is currently playing.2662* @return True or false.2663*/2664public boolean playing()2665{2666synchronized( SoundSystemConfig.THREAD_SYNC )2667{2668if( soundLibrary == null )2669return false;26702671HashMap<String, Source> sourceMap = soundLibrary.getSources();2672if( sourceMap == null )2673return false;26742675Set<String> keys = sourceMap.keySet();2676Iterator<String> iter = keys.iterator();2677String sourcename;2678Source source;26792680while( iter.hasNext() )2681{2682sourcename = iter.next();2683source = sourceMap.get( sourcename );2684if( source != null )2685if( source.playing() )2686return true;2687}26882689return false;2690}2691}26922693/**2694* Copies and returns the peripheral information from a map of sources. This2695* method is used internally by SoundSystem, and it is unlikely that the user2696* will ever need to use it.2697* @param sourceMap Sources to copy.2698* @return New map of sources.2699*/2700private HashMap<String, Source> copySources( HashMap<String,2701Source> sourceMap )2702{2703Set<String> keys = sourceMap.keySet();2704Iterator<String> iter = keys.iterator();2705String sourcename;2706Source source;27072708// New map of generic source data:2709HashMap<String, Source> returnMap = new HashMap<String, Source>();271027112712// loop through and store information from all the sources:2713while( iter.hasNext() )2714{2715sourcename = iter.next();2716source = sourceMap.get( sourcename );2717if( source != null )2718returnMap.put( sourcename, new Source( source, null ) );2719}2720return returnMap;2721}27222723/**2724* Checks if the specified library type is compatible.2725* @param libraryClass Libary type to check.2726* @return True or false.2727*/2728public static boolean libraryCompatible( Class libraryClass )2729{2730// create the message logger:2731SoundSystemLogger logger = SoundSystemConfig.getLogger();2732// if the user didn't create one, then do it now:2733if( logger == null )2734{2735logger = new SoundSystemLogger();2736SoundSystemConfig.setLogger( logger );2737}2738logger.message( "", 0 );2739logger.message( "Checking if " +2740SoundSystemConfig.getLibraryTitle( libraryClass ) +2741" is compatible...", 0 );27422743boolean comp = SoundSystemConfig.libraryCompatible( libraryClass );27442745if( comp )2746logger.message( "...yes", 1 );2747else2748logger.message( "...no", 1 );27492750return comp;2751}27522753/**2754* Returns the currently loaded library, or -1 if none.2755* @return Global library identifier2756*/2757public static Class currentLibrary()2758{2759return( currentLibrary( GET, null ) );2760}27612762/**2763* Returns false if a sound library is busy initializing.2764* @return True or false.2765*/2766public static boolean initialized()2767{2768return( initialized( GET, XXX ) );2769}27702771/**2772* Returns the last SoundSystemException thrown, or null if none.2773* @return The last exception.2774*/2775public static SoundSystemException getLastException()2776{2777return( lastException( GET, null ) );2778}27792780/**2781* Stores a SoundSystemException which can be retreived later with the2782* 'getLastException' method.2783* @param e Exception to store.2784*/2785public static void setException( SoundSystemException e )2786{2787lastException( SET, e );2788}27892790/**2791* Sets or returns the value of boolean 'initialized'.2792* @param action Action to perform (GET or SET).2793* @param value New value if action is SET, otherwise XXX.2794* @return value of boolean 'initialized'.2795*/2796private static boolean initialized( boolean action, boolean value )2797{2798synchronized( SoundSystemConfig.THREAD_SYNC )2799{2800if( action == SET )2801initialized = value;2802return initialized;2803}2804}28052806/**2807* Sets or returns the value of boolean 'initialized'.2808* @param action Action to perform (GET or SET).2809* @param value New value if action is SET, otherwise XXX.2810* @return value of boolean 'initialized'.2811*/2812private static Class currentLibrary( boolean action,2813Class value )2814{2815synchronized( SoundSystemConfig.THREAD_SYNC )2816{2817if( action == SET )2818currentLibrary = value;2819return currentLibrary;2820}2821}28222823/**2824* Sets or returns the error code for the last error that occurred. If no2825* errors have occurred, returns SoundSystem.ERROR_NONE2826* @param action Action to perform (GET or SET).2827* @param e New exception if action is SET, otherwise XXX.2828* @return Last SoundSystemException thrown.2829*/2830private static SoundSystemException lastException( boolean action,2831SoundSystemException e )2832{2833synchronized( SoundSystemConfig.THREAD_SYNC )2834{2835if( action == SET )2836lastException = e;2837return lastException;2838}2839}28402841/**2842* Sleeps for the specified number of milliseconds.2843*/2844protected static void snooze( long milliseconds )2845{2846try2847{2848Thread.sleep( milliseconds );2849}2850catch( InterruptedException e ){}2851}28522853/**2854* Prints a message.2855* @param message Message to print.2856* @param indent Number of tabs to indent the message.2857*/2858protected void message( String message, int indent )2859{2860logger.message( message, indent );2861}28622863/**2864* Prints an important message.2865* @param message Message to print.2866* @param indent Number of tabs to indent the message.2867*/2868protected void importantMessage( String message, int indent )2869{2870logger.importantMessage( message, indent );2871}28722873/**2874* Prints the specified message if error is true.2875* @param error True or False.2876* @param message Message to print if error is true.2877* @param indent Number of tabs to indent the message.2878* @return True if error is true.2879*/2880protected boolean errorCheck( boolean error, String message, int indent )2881{2882return logger.errorCheck( error, className, message, indent );2883}28842885/**2886* Prints an error message.2887* @param message Message to print.2888* @param indent Number of tabs to indent the message.2889*/2890protected void errorMessage( String message, int indent )2891{2892logger.errorMessage( className, message, indent );2893}2894}289528962897