Path: blob/main/src/lwjgl/java/paulscode/sound/Source.java
8644 views
package paulscode.sound;12import java.net.URL;3import java.util.LinkedList;4import java.util.ListIterator;5import javax.sound.sampled.AudioFormat;67/**8* The Source class is used to store information about a source.9* Source objects are stored in a map in the Library class. The10* information they contain is used to create library-specific sources.11* This is the template class which is extended for each specific library.12* This class is also used by the "No Sound" library to represent a mute13* source.14*<br><br>15*<b><i> SoundSystem License:</b></i><br><b><br>16* You are free to use this library for any purpose, commercial or otherwise.17* You may modify this library or source code, and distribute it any way you18* like, provided the following conditions are met:19*<br>20* 1) You may not falsely claim to be the author of this library or any21* unmodified portion of it.22*<br>23* 2) You may not copyright this library or a modified version of it and then24* sue me for copyright infringement.25*<br>26* 3) If you modify the source code, you must clearly document the changes27* made before redistributing the modified source code, so other users know28* it is not the original code.29*<br>30* 4) You are not required to give me credit for this library in any derived31* work, but if you do, you must also mention my website:32* http://www.paulscode.com33*<br>34* 5) I the author will not be responsible for any damages (physical,35* financial, or otherwise) caused by the use if this library or any part36* of it.37*<br>38* 6) I the author do not guarantee, warrant, or make any representations,39* either expressed or implied, regarding the use of this library or any40* part of it.41* <br><br>42* Author: Paul Lamb43* <br>44* http://www.paulscode.com45* </b>46*/47public class Source48{49/**50* The library class associated with this type of channel.51*/52protected Class libraryType = Library.class;5354/**55* Used to return a current value from one of the synchronized56* boolean-interface methods.57*/58private static final boolean GET = false;5960/**61* Used to set the value in one of the synchronized boolean-interface methods.62*/63private static final boolean SET = true;6465/**66* Used when a parameter for one of the synchronized boolean-interface methods67* is not aplicable.68*/69private static final boolean XXX = false;7071/**72* Processes status messages, warnings, and error messages.73*/74private SoundSystemLogger logger;7576/**77* True if this source is being directly fed with raw audio data.78*/79public boolean rawDataStream = false;8081/**82* Format the raw data will be in if this is a Raw Data Stream source.83*/84public AudioFormat rawDataFormat = null;8586/**87* Determines whether a source should be removed after it finishes playing.88*/89public boolean temporary = false;9091/**92* Determines whether or not this is a priority source. Priority sources will93* not be overwritten by other sources when there are no available channels.94*/95public boolean priority = false;9697/**98* Whether or not this source should be streamed.99*/100public boolean toStream = false;101102/**103* Whether this source should loop or only play once.104*/105public boolean toLoop = false;106107/**108* Whether this source needs to be played (for example if it was playing and109* looping when it got culled).110*/111public boolean toPlay = false;112113/**114* Unique name for this source. More than one source can not have the same115* sourcename.116*/117public String sourcename = "";118119/**120* The audio file which this source should play.121*/122public FilenameURL filenameURL = null;123124/**125* This source's position in 3D space.126*/127public Vector3D position;128129/**130* Attenuation model to use for this source.131*/132public int attModel = 0;133134/**135* Either fade distance or rolloff factor, depending on the value of attModel.136*/137public float distOrRoll = 0.0f;138139/**140* Source's velocity in world-space, for use in Doppler effect.141*/142public Vector3D velocity;143144/**145* This source's volume (a float between 0.0 - 1.0). This value is used146* internally for attenuation, and should not be used to manually change a147* source's volume.148*/149public float gain = 1.0f;150151/**152* This value should be used to manually increase or decrease source volume.153*/154public float sourceVolume = 1.0f;155156/**157* Indicates to the streaming thread that this source is removed and needs cleanup.158* @see https://github.com/MinecraftForge/MinecraftForge/pull/4765159*/160public boolean removed = false;161162/**163* This value represents the source's pitch (float value between 0.5f - 2.0f).164*/165protected float pitch = 1.0f;166167/**168* This source's distance from the listener.169*/170public float distanceFromListener = 0.0f;171172/**173* Channel to play this source on.174*/175public Channel channel = null;176177/**178* Holds the data used by normal sources.179*/180public SoundBuffer soundBuffer = null;181182/**183* False when this source gets culled.184*/185private boolean active = true;186187/**188* Whether or not this source has been stopped.189*/190private boolean stopped = true;191192/**193* Whether or not this source has been paused.194*/195private boolean paused = false;196197/**198* Codec used to read data for streaming sources.199*/200protected ICodec codec = null;201202/**203* Codec used to read in some initial data from the next sound in the queue.204*/205protected ICodec nextCodec = null;206207/**208* List of buffers to hold some initial data from the next sound in the queue.209*/210protected LinkedList<SoundBuffer> nextBuffers = null;211212213/**214* The list of files to stream when the current stream finishes.215*/216protected LinkedList<FilenameURL> soundSequenceQueue = null;217218/**219* Ensures that only one thread accesses the soundSequenceQueue at a time.220*/221protected final Object soundSequenceLock = new Object();222223/**224* Used by streaming sources to indicate whether or not the initial225* stream-buffers still need to be queued.226*/227public boolean preLoad = false;228229/**230* Specifies the gain factor used for the fade-out effect, or -1 when231* source is not currently fading out.232*/233protected float fadeOutGain = -1.0f;234235/**236* Specifies the gain factor used for the fade-in effect, or 1 when237* source is not currently fading in.238*/239protected float fadeInGain = 1.0f;240241/**242* Specifies the number of miliseconds it should take to fade out.243*/244protected long fadeOutMilis = 0;245246/**247* Specifies the number of miliseconds it should take to fade in.248*/249protected long fadeInMilis = 0;250251/**252* System time in miliseconds when the last fade in/out volume check occurred.253*/254protected long lastFadeCheck = 0;255256/**257* Constructor: Creates a new source using the specified parameters.258* @param priority Setting this to true will prevent other sounds from overriding this one.259* @param toStream Setting this to true will create a streaming source.260* @param toLoop Should this source loop, or play only once.261* @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.262* @param filenameURL The filename/URL of the sound file to play at this source.263* @param soundBuffer Buffer containing audio data, or null if not loaded yet.264* @param x X position for this source.265* @param y Y position for this source.266* @param z Z position for this source.267* @param attModel Attenuation model to use.268* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of 'att'.269* @param temporary Whether or not to remove this source after it finishes playing.270*/271public Source( boolean priority, boolean toStream, boolean toLoop,272String sourcename, FilenameURL filenameURL,273SoundBuffer soundBuffer, float x, float y, float z,274int attModel, float distOrRoll, boolean temporary )275{276// grab a handle to the message logger:277logger = SoundSystemConfig.getLogger();278279this.priority = priority;280this.toStream = toStream;281this.toLoop = toLoop;282this.sourcename = sourcename;283this.filenameURL = filenameURL;284this.soundBuffer = soundBuffer;285position = new Vector3D( x, y, z );286this.attModel = attModel;287this.distOrRoll = distOrRoll;288this.velocity = new Vector3D( 0, 0, 0 );289this.temporary = temporary;290291if( toStream && filenameURL != null )292codec = SoundSystemConfig.getCodec( filenameURL.getFilename() );293}294295/**296* Constructor: Creates a new source matching the specified one.297* @param old Source to copy information from.298* @param soundBuffer Buffer containing audio data, or null if not loaded yet.299*/300public Source( Source old, SoundBuffer soundBuffer )301{302// grab a handle to the message logger:303logger = SoundSystemConfig.getLogger();304305priority = old.priority;306toStream = old.toStream;307toLoop = old.toLoop;308sourcename = old.sourcename;309filenameURL = old.filenameURL;310position = old.position.clone();311attModel = old.attModel;312distOrRoll = old.distOrRoll;313velocity = old.velocity.clone();314temporary = old.temporary;315316sourceVolume = old.sourceVolume;317318rawDataStream = old.rawDataStream;319rawDataFormat = old.rawDataFormat;320321this.soundBuffer = soundBuffer;322323if( toStream && filenameURL != null )324codec = SoundSystemConfig.getCodec( filenameURL.getFilename() );325}326327/**328* Constructor: Creates a new streaming source that will be directly fed with329* raw audio data.330* @param audioFormat Format that the data will be in.331* @param priority Setting this to true will prevent other sounds from overriding this one.332* @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.333* @param x X position for this source.334* @param y Y position for this source.335* @param z Z position for this source.336* @param attModel Attenuation model to use.337* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of 'att'.338*/339public Source( AudioFormat audioFormat, boolean priority, String sourcename,340float x, float y, float z, int attModel, float distOrRoll )341{342// grab a handle to the message logger:343logger = SoundSystemConfig.getLogger();344345this.priority = priority;346this.toStream = true;347this.toLoop = false;348this.sourcename = sourcename;349this.filenameURL = null;350this.soundBuffer = null;351position = new Vector3D( x, y, z );352this.attModel = attModel;353this.distOrRoll = distOrRoll;354this.velocity = new Vector3D( 0, 0, 0 );355this.temporary = false;356357rawDataStream = true;358rawDataFormat = audioFormat;359}360/* Override methods */361362/**363* Shuts the source down and removes references to all instantiated objects.364*/365public void cleanup()366{367if( codec != null )368codec.cleanup();369370synchronized( soundSequenceLock )371{372if( soundSequenceQueue != null )373soundSequenceQueue.clear();374soundSequenceQueue = null;375}376377sourcename = null;378filenameURL = null;379position = null;380soundBuffer = null;381codec = null;382}383384/**385* If this is a streaming source, queues up the next sound to play when386* the previous stream ends. This method has no effect on non-streaming387* sources.388* @param filenameURL The filename/URL of the sound file to stream next.389*/390public void queueSound( FilenameURL filenameURL )391{392if( !toStream )393{394errorMessage( "Method 'queueSound' may only be used for " +395"streaming and MIDI sources." );396return;397}398if( filenameURL == null )399{400errorMessage( "File not specified in method 'queueSound'" );401return;402}403404synchronized( soundSequenceLock )405{406if( soundSequenceQueue == null )407soundSequenceQueue = new LinkedList<FilenameURL>();408soundSequenceQueue.add( filenameURL );409}410}411412/**413* Removes the first occurrence of the specified filename from the list of414* sounds to play when the previous stream ends. This method has no effect415* on non-streaming sources.416* @param filename Filename/identifier of a sound file to remove from the queue.417*/418public void dequeueSound( String filename )419{420if( !toStream )421{422errorMessage( "Method 'dequeueSound' may only be used for " +423"streaming and MIDI sources." );424return;425}426if( filename == null || filename.equals( "" ) )427{428errorMessage( "Filename not specified in method 'dequeueSound'" );429return;430}431432synchronized( soundSequenceLock )433{434if( soundSequenceQueue != null )435{436ListIterator<FilenameURL> i = soundSequenceQueue.listIterator();437while( i.hasNext() )438{439if( i.next().getFilename().equals( filename ) )440{441i.remove();442break;443}444}445}446}447}448449/**450* Fades out the volume of whatever this source is currently playing, then451* begins playing the specified filename at the source's previously assigned452* volume level. If the filename parameter is null or empty, the source will453* simply fade out and stop. The miliseconds parameter must be non-negative or454* zero. This method will remove anything that is currently in the list of455* queued sounds that would have played next when the current sound finished456* playing. This method has no effect on non-streaming sources.457* @param filenameURL Filename/URL of the sound file to play next, or null for none.458* @param milis Number of miliseconds the fadeout should take.459*/460public void fadeOut( FilenameURL filenameURL, long milis )461{462if( !toStream )463{464errorMessage( "Method 'fadeOut' may only be used for " +465"streaming and MIDI sources." );466return;467}468if( milis < 0 )469{470errorMessage( "Miliseconds may not be negative in method " +471"'fadeOut'." );472return;473}474475fadeOutMilis = milis;476fadeInMilis = 0;477fadeOutGain = 1.0f;478lastFadeCheck = System.currentTimeMillis();479480synchronized( soundSequenceLock )481{482if( soundSequenceQueue != null )483soundSequenceQueue.clear();484485if( filenameURL != null )486{487if( soundSequenceQueue == null )488soundSequenceQueue = new LinkedList<FilenameURL>();489soundSequenceQueue.add( filenameURL );490}491}492}493494/**495* Fades out the volume of whatever this source is currently playing, then496* fades the volume back in playing the specified file. Final volume after497* fade-in completes will be equal to the source's previously assigned volume498* level. The filenameURL parameter may not be null or empty. The miliseconds499* parameters must be non-negative or zero. This method will remove anything500* that is currently in the list of queued sounds that would have played next501* when the current sound finished playing. This method has no effect on502* non-streaming sources.503* @param filenameURL Filename/URL of the sound file to play next, or null for none.504* @param milisOut Number of miliseconds the fadeout should take.505* @param milisIn Number of miliseconds the fadein should take.506*/507public void fadeOutIn( FilenameURL filenameURL, long milisOut, long milisIn )508{509if( !toStream )510{511errorMessage( "Method 'fadeOutIn' may only be used for " +512"streaming and MIDI sources." );513return;514}515if( filenameURL == null )516{517errorMessage( "Filename/URL not specified in method 'fadeOutIn'." );518return;519}520if( milisOut < 0 || milisIn < 0 )521{522errorMessage( "Miliseconds may not be negative in method " +523"'fadeOutIn'." );524return;525}526527fadeOutMilis = milisOut;528fadeInMilis = milisIn;529530fadeOutGain = 1.0f;531lastFadeCheck = System.currentTimeMillis();532533synchronized( soundSequenceLock )534{535if( soundSequenceQueue == null )536soundSequenceQueue = new LinkedList<FilenameURL>();537soundSequenceQueue.clear();538soundSequenceQueue.add( filenameURL );539}540}541542/**543* Resets this source's volume if it is fading out or in. Returns true if this544* source is currently in the process of fading out. When fade-out completes,545* this method transitions the source to the next sound in the sound sequence546* queue if there is one. This method has no effect on non-streaming sources.547* @return True if this source is in the process of fading out.548*/549public boolean checkFadeOut()550{551if( !toStream )552return false;553554if( fadeOutGain == -1.0f && fadeInGain == 1.0f )555return false;556557long currentTime = System.currentTimeMillis();558long milisPast = currentTime - lastFadeCheck;559lastFadeCheck = currentTime;560561if( fadeOutGain >= 0.0f )562{563if( fadeOutMilis == 0 )564{565fadeOutGain = -1.0f;566fadeInGain = 0.0f;567if( !incrementSoundSequence() )568{569stop();570}571positionChanged();572preLoad = true;573return false;574}575else576{577float fadeOutReduction = ((float)milisPast) / ((float)fadeOutMilis);578fadeOutGain -= fadeOutReduction;579if( fadeOutGain <= 0.0f )580{581fadeOutGain = -1.0f;582fadeInGain = 0.0f;583if( !incrementSoundSequence() )584stop();585positionChanged();586preLoad = true;587return false;588}589}590positionChanged();591return true;592}593594if( fadeInGain < 1.0f )595{596fadeOutGain = -1.0f;597if( fadeInMilis == 0 )598{599fadeOutGain = -1.0f;600fadeInGain = 1.0f;601}602else603{604float fadeInIncrease = ((float)milisPast) / ((float)fadeInMilis);605fadeInGain += fadeInIncrease;606if( fadeInGain >= 1.0f )607{608fadeOutGain = -1.0f;609fadeInGain = 1.0f;610}611}612positionChanged();613return true;614}615return false;616}617618/**619* Removes the next filename/URL from the sound sequence queue and assigns it to620* this source. This method has no effect on non-streaming sources. This621* method is used internally by SoundSystem, and it is unlikely that the user622* will ever need to use it.623* @return True if there was something in the queue.624*/625public boolean incrementSoundSequence()626{627if( !toStream )628{629errorMessage( "Method 'incrementSoundSequence' may only be used " +630"for streaming and MIDI sources." );631return false;632}633634synchronized( soundSequenceLock )635{636if( soundSequenceQueue != null && soundSequenceQueue.size() > 0 )637{638filenameURL = soundSequenceQueue.remove( 0 );639if( codec != null )640codec.cleanup();641codec = SoundSystemConfig.getCodec( filenameURL.getFilename() );642return true;643}644}645return false;646}647648/**649* Reads in initial buffers of data from the next sound in the sound sequence650* queue, to reduce lag when the transition occurrs. This method has no effect651* on non-streaming sources. This method is used internally by SoundSystem, and652* it is unlikely that the user will ever need to use it.653* @return False if there is nothing in the queue to read from.654*/655public boolean readBuffersFromNextSoundInSequence()656{657if( !toStream )658{659errorMessage( "Method 'readBuffersFromNextSoundInSequence' may " +660"only be used for streaming sources." );661return false;662}663664synchronized( soundSequenceLock )665{666if( soundSequenceQueue != null && soundSequenceQueue.size() > 0 )667{668if( nextCodec != null )669nextCodec.cleanup();670nextCodec = SoundSystemConfig.getCodec(671soundSequenceQueue.get( 0 ).getFilename() );672nextCodec.initialize( soundSequenceQueue.get( 0 ).getURL() );673674SoundBuffer buffer = null;675for( int i = 0;676i < SoundSystemConfig.getNumberStreamingBuffers()677&& !nextCodec.endOfStream();678i++ )679{680buffer = nextCodec.read();681if( buffer != null )682{683if( nextBuffers == null )684nextBuffers = new LinkedList<SoundBuffer>();685nextBuffers.add( buffer );686}687}688return true;689}690}691return false;692}693694695/**696* Returns the size of the sound sequence queue (if this is a streaming source).697* @return Number of sounds left in the queue, or zero if none.698*/699public int getSoundSequenceQueueSize()700{701if( soundSequenceQueue == null )702return 0;703return soundSequenceQueue.size();704}705706/**707* Sets whether or not this source should be removed when it finishes playing.708* @param tmp True or false.709*/710public void setTemporary( boolean tmp )711{712temporary = tmp;713}714715/**716* Called every time the listener's position or orientation changes.717*/718public void listenerMoved()719{}720721/**722* Moves the source to the specified position.723* @param x X coordinate to move to.724* @param y Y coordinate to move to.725* @param z Z coordinate to move to.726*/727public void setPosition( float x, float y, float z )728{729position.x = x;730position.y = y;731position.z = z;732}733734/**735* Called every time the source changes position.736*/737public void positionChanged()738{}739740/**741* Sets whether or not this source is a priority source. A priority source742* will not be overritten by another source if there are no channels available743* to play on.744* @param pri True or false.745*/746public void setPriority( boolean pri )747{748priority = pri;749}750751/**752* Sets whether this source should loop or only play once.753* @param lp True or false.754*/755public void setLooping( boolean lp )756{757toLoop = lp;758}759760/**761* Sets this source's attenuation model.762* @param model Attenuation model to use.763*/764public void setAttenuation( int model )765{766attModel = model;767}768769/**770* Sets this source's fade distance or rolloff factor, depending on the771* attenuation model.772* @param dr New value for fade distance or rolloff factor.773*/774public void setDistOrRoll( float dr)775{776distOrRoll = dr;777}778779/**780* Sets this source's velocity, for use in Doppler effect.781* @param x Velocity along world x-axis.782* @param y Velocity along world y-axis.783* @param z Velocity along world z-axis.784*/785public void setVelocity( float x, float y, float z )786{787this.velocity.x = x;788this.velocity.y = y;789this.velocity.z = z;790}791792/**793* Returns the source's distance from the listener.794* @return How far away the source is.795*/796public float getDistanceFromListener()797{798return distanceFromListener;799}800801/**802* Manually sets the specified source's pitch.803* @param value A float value ( 0.5f - 2.0f ).804*/805public void setPitch( float value )806{807float newPitch = value;808if( newPitch < 0.5f )809newPitch = 0.5f;810else if( newPitch > 2.0f )811newPitch = 2.0f;812pitch = newPitch;813}814815/**816* Returns the pitch of the specified source.817* @return Float value representing the source pitch (0.5f - 2.0f).818*/819public float getPitch()820{821return pitch;822}823824/**825* Indicates whether or not this source's associated library requires some826* codecs to reverse-order the audio data they generate.827* @return True if audio data should be reverse-ordered.828*/829public boolean reverseByteOrder()830{831return SoundSystemConfig.reverseByteOrder( libraryType );832}833834/**835* Changes the sources peripheral information to match the supplied parameters.836* @param priority Setting this to true will prevent other sounds from overriding this one.837* @param toStream Setting this to true will create a streaming source.838* @param toLoop Should this source loop, or play only once.839* @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.840* @param filenameURL Filename/URL of the sound file to play at this source.841* @param x X position for this source.842* @param y Y position for this source.843* @param z Z position for this source.844* @param attModel Attenuation model to use.845* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of 'att'.846* @param temporary Whether or not to remove this source after it finishes playing.847*/848public void changeSource( boolean priority, boolean toStream,849boolean toLoop, String sourcename,850FilenameURL filenameURL, SoundBuffer soundBuffer,851float x, float y, float z, int attModel,852float distOrRoll, boolean temporary )853{854this.priority = priority;855this.toStream = toStream;856this.toLoop = toLoop;857this.sourcename = sourcename;858this.filenameURL = filenameURL;859this.soundBuffer = soundBuffer;860position.x = x;861position.y = y;862position.z = z;863this.attModel = attModel;864this.distOrRoll = distOrRoll;865this.temporary = temporary;866}867868/**869* Feeds raw data to the specified channel.870* @param buffer Byte buffer containing raw audio data to stream.871* @param c Channel to stream on.872* @return Number of prior buffers that have been processed, or -1 if unable to queue the buffer (if the source was culled, for example).873*/874public int feedRawAudioData( Channel c, byte[] buffer )875{876if( !active( GET, XXX) )877{878toPlay = true;879return -1;880}881if( channel != c )882{883channel = c;884channel.close();885channel.setAudioFormat( rawDataFormat );886positionChanged();887}888889// change the state of this source to not stopped and not paused:890stopped( SET, false );891paused( SET, false );892893return channel.feedRawAudioData( buffer );894}895896/**897* Plays the source on the specified channel.898* @param c Channel to play on.899*/900public void play( Channel c )901{902if( !active( GET, XXX) )903{904if( toLoop )905toPlay = true;906return;907}908if( channel != c )909{910channel = c;911channel.close();912}913// change the state of this source to not stopped and not paused:914stopped( SET, false );915paused( SET, false );916}917/* END Override methods */918919/**920* Streams the source on its current channel921* @return False when stream has finished playing.922*/923public boolean stream()924{925if( channel == null )926return false;927928if( preLoad )929{930if( rawDataStream )931preLoad = false;932else933return preLoad();934}935936if( rawDataStream )937{938if( stopped() || paused() )939return true;940if( channel.buffersProcessed() > 0 )941channel.processBuffer();942return true;943}944else945{946if( codec == null )947return false;948if( stopped() )949return false;950if( paused() )951return true;952953int processed = channel.buffersProcessed();954955SoundBuffer buffer = null;956for( int i = 0; i < processed; i++ )957{958buffer = codec.read();959if( buffer != null )960{961if( buffer.audioData != null )962channel.queueBuffer( buffer.audioData );963buffer.cleanup();964buffer = null;965return true;966}967else if( codec.endOfStream() )968{969synchronized( soundSequenceLock )970{971if( SoundSystemConfig.getStreamQueueFormatsMatch() )972{973if( soundSequenceQueue != null &&974soundSequenceQueue.size() > 0 )975{976if( codec != null )977codec.cleanup();978filenameURL = soundSequenceQueue.remove( 0 );979codec = SoundSystemConfig.getCodec(980filenameURL.getFilename() );981codec.initialize( filenameURL.getURL() );982buffer = codec.read();983if( buffer != null )984{985if( buffer.audioData != null )986channel.queueBuffer( buffer.audioData );987buffer.cleanup();988buffer = null;989return true;990}991}992else if( toLoop )993{994codec.initialize( filenameURL.getURL() );995buffer = codec.read();996if( buffer != null )997{998if( buffer.audioData != null )999channel.queueBuffer( buffer.audioData );1000buffer.cleanup();1001buffer = null;1002return true;1003}1004}1005}1006}1007}1008/*1009if( codec.endOfStream() )1010{1011synchronized( soundSequenceLock )1012{1013if( SoundSystemConfig.getStreamQueueFormatsMatch() )1014{1015if( soundSequenceQueue != null &&1016soundSequenceQueue.size() > 0 )1017{1018if( codec != null )1019codec.cleanup();1020filenameURL = soundSequenceQueue.remove( 0 );1021codec = SoundSystemConfig.getCodec(1022filenameURL.getFilename() );1023codec.initialize( filenameURL.getURL() );1024return true;1025}1026else if( toLoop )1027{1028codec.initialize( filenameURL.getURL() );1029buffer = codec.read();1030if( buffer != null )1031{1032if( buffer.audioData != null )1033channel.queueBuffer( buffer.audioData );1034buffer.cleanup();1035buffer = null;1036}1037}1038}1039}1040return false;1041}1042*/1043}1044}1045return false;1046}10471048/**1049* Queues up the initial stream-buffers for the stream.1050* @return False if the end of the stream was reached.1051*/1052public boolean preLoad()1053{1054if( channel == null )1055return false;10561057if( codec == null )1058return false;10591060SoundBuffer buffer = null;10611062boolean noNextBuffers = false;1063synchronized( soundSequenceLock )1064{1065if( nextBuffers == null || nextBuffers.isEmpty() )1066noNextBuffers = true;1067}10681069if( nextCodec != null && !noNextBuffers )1070{1071codec = nextCodec;1072nextCodec = null;1073synchronized( soundSequenceLock )1074{1075while( !nextBuffers.isEmpty() )1076{1077buffer = nextBuffers.remove( 0 );1078if( buffer != null )1079{1080if( buffer.audioData != null )1081channel.queueBuffer( buffer.audioData );1082buffer.cleanup();1083buffer = null;1084}1085}1086}1087}1088else1089{1090nextCodec = null;1091URL url = filenameURL.getURL();10921093codec.initialize( url );1094for( int i = 0; i < SoundSystemConfig.getNumberStreamingBuffers();1095i++ )1096{1097buffer = codec.read();1098if( buffer != null )1099{1100if( buffer.audioData != null )1101channel.queueBuffer( buffer.audioData );1102buffer.cleanup();1103buffer = null;1104}1105}1106}11071108return true;1109}11101111/**1112* Pauses the source.1113*/1114public void pause()1115{1116toPlay = false;1117paused( SET, true );1118if( channel != null )1119channel.pause();1120else1121errorMessage( "Channel null in method 'pause'" );1122}11231124/**1125* Stops the source.1126*/1127public void stop()1128{1129toPlay = false;1130stopped( SET, true );1131paused( SET, false );1132if( channel != null )1133channel.stop();1134else1135errorMessage( "Channel null in method 'stop'" );1136}11371138/**1139* Rewinds the source. If the source was paused, then it is stopped.1140*/1141public void rewind()1142{1143if( paused( GET, XXX ) )1144{1145stop();1146}1147if( channel != null )1148{1149boolean rePlay = playing();1150channel.rewind();1151if( toStream && rePlay )1152{1153stop();1154play( channel );1155}1156}1157else1158errorMessage( "Channel null in method 'rewind'" );1159}11601161/**1162* Dequeues any previously queued data.1163*/1164public void flush()1165{1166if( channel != null )1167channel.flush();1168else1169errorMessage( "Channel null in method 'flush'" );1170}11711172/**1173* Stops and flushes the source, and prevents it from being played again until1174* the activate() is called.1175*/1176public void cull()1177{1178if( !active( GET, XXX ) )1179return;1180if( playing() && toLoop )1181toPlay = true;1182if( rawDataStream )1183toPlay = true;1184active( SET, false );1185if( channel != null )1186channel.close();1187channel = null;1188}11891190/**1191* Allows a previously culled source to be played again.1192*/1193public void activate()1194{1195active( SET, true );1196}11971198/**1199* Returns false if the source has been culled.1200* @return True or False1201*/1202public boolean active()1203{1204return active( GET, XXX );1205}12061207/**1208* Returns true if the source is playing.1209* @return True or False1210*/1211public boolean playing()1212{1213if( channel == null || channel.attachedSource != this )1214return false;1215else if( paused() || stopped() )1216return false;1217else1218return channel.playing();1219}12201221/**1222* Returns true if the source has been stopped.1223* @return True or False1224*/1225public boolean stopped()1226{1227return stopped( GET, XXX );1228}12291230/**1231* Returns true if the source has been paused.1232* @return True or False1233*/1234public boolean paused()1235{1236return paused( GET, XXX );1237}12381239/**1240* Returns the number of miliseconds since the source began playing.1241* @return miliseconds, or -1 if not playing or unable to calculate1242*/1243public float millisecondsPlayed()1244{1245if( channel == null )1246return( -1 );1247else1248return channel.millisecondsPlayed();1249}12501251/**1252* Sets or returns whether or not the source has been culled.1253* @return True or False1254*/1255private synchronized boolean active( boolean action, boolean value )1256{1257if( action == SET )1258active = value;1259return active;1260}12611262/**1263* Sets or returns whether or not the source has been stopped.1264* @return True or False1265*/1266private synchronized boolean stopped( boolean action, boolean value )1267{1268if( action == SET )1269stopped = value;1270return stopped;1271}12721273/**1274* Sets or returns whether or not the source has been paused.1275* @return True or False1276*/1277private synchronized boolean paused( boolean action, boolean value )1278{1279if( action == SET )1280paused = value;1281return paused;1282}12831284/**1285* Returns the name of the class.1286* @return SoundLibraryXXXX.1287*/1288public String getClassName()1289{1290String libTitle = SoundSystemConfig.getLibraryTitle( libraryType );12911292if( libTitle.equals( "No Sound" ) )1293return "Source";1294else1295return "Source" + libTitle;1296}1297/**1298* Prints a message.1299* @param message Message to print.1300*/1301protected void message( String message )1302{1303logger.message( message, 0 );1304}13051306/**1307* Prints an important message.1308* @param message Message to print.1309*/1310protected void importantMessage( String message )1311{1312logger.importantMessage( message, 0 );1313}13141315/**1316* Prints the specified message if error is true.1317* @param error True or False.1318* @param message Message to print if error is true.1319* @return True if error is true.1320*/1321protected boolean errorCheck( boolean error, String message )1322{1323return logger.errorCheck( error, getClassName(), message, 0 );1324}13251326/**1327* Prints an error message.1328* @param message Message to print.1329*/1330protected void errorMessage( String message )1331{1332logger.errorMessage( getClassName(), message, 0 );1333}13341335/**1336* Prints an exception's error message followed by the stack trace.1337* @param e Exception containing the information to print.1338*/1339protected void printStackTrace( Exception e )1340{1341logger.printStackTrace( e, 1 );1342}1343}134413451346