Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
lDEVinux
GitHub Repository: lDEVinux/eaglercraft
Path: blob/main/src/lwjgl/java/paulscode/sound/Source.java
8644 views
1
package paulscode.sound;
2
3
import java.net.URL;
4
import java.util.LinkedList;
5
import java.util.ListIterator;
6
import javax.sound.sampled.AudioFormat;
7
8
/**
9
* The Source class is used to store information about a source.
10
* Source objects are stored in a map in the Library class. The
11
* information they contain is used to create library-specific sources.
12
* This is the template class which is extended for each specific library.
13
* This class is also used by the "No Sound" library to represent a mute
14
* source.
15
*<br><br>
16
*<b><i> SoundSystem License:</b></i><br><b><br>
17
* You are free to use this library for any purpose, commercial or otherwise.
18
* You may modify this library or source code, and distribute it any way you
19
* like, provided the following conditions are met:
20
*<br>
21
* 1) You may not falsely claim to be the author of this library or any
22
* unmodified portion of it.
23
*<br>
24
* 2) You may not copyright this library or a modified version of it and then
25
* sue me for copyright infringement.
26
*<br>
27
* 3) If you modify the source code, you must clearly document the changes
28
* made before redistributing the modified source code, so other users know
29
* it is not the original code.
30
*<br>
31
* 4) You are not required to give me credit for this library in any derived
32
* work, but if you do, you must also mention my website:
33
* http://www.paulscode.com
34
*<br>
35
* 5) I the author will not be responsible for any damages (physical,
36
* financial, or otherwise) caused by the use if this library or any part
37
* of it.
38
*<br>
39
* 6) I the author do not guarantee, warrant, or make any representations,
40
* either expressed or implied, regarding the use of this library or any
41
* part of it.
42
* <br><br>
43
* Author: Paul Lamb
44
* <br>
45
* http://www.paulscode.com
46
* </b>
47
*/
48
public class Source
49
{
50
/**
51
* The library class associated with this type of channel.
52
*/
53
protected Class libraryType = Library.class;
54
55
/**
56
* Used to return a current value from one of the synchronized
57
* boolean-interface methods.
58
*/
59
private static final boolean GET = false;
60
61
/**
62
* Used to set the value in one of the synchronized boolean-interface methods.
63
*/
64
private static final boolean SET = true;
65
66
/**
67
* Used when a parameter for one of the synchronized boolean-interface methods
68
* is not aplicable.
69
*/
70
private static final boolean XXX = false;
71
72
/**
73
* Processes status messages, warnings, and error messages.
74
*/
75
private SoundSystemLogger logger;
76
77
/**
78
* True if this source is being directly fed with raw audio data.
79
*/
80
public boolean rawDataStream = false;
81
82
/**
83
* Format the raw data will be in if this is a Raw Data Stream source.
84
*/
85
public AudioFormat rawDataFormat = null;
86
87
/**
88
* Determines whether a source should be removed after it finishes playing.
89
*/
90
public boolean temporary = false;
91
92
/**
93
* Determines whether or not this is a priority source. Priority sources will
94
* not be overwritten by other sources when there are no available channels.
95
*/
96
public boolean priority = false;
97
98
/**
99
* Whether or not this source should be streamed.
100
*/
101
public boolean toStream = false;
102
103
/**
104
* Whether this source should loop or only play once.
105
*/
106
public boolean toLoop = false;
107
108
/**
109
* Whether this source needs to be played (for example if it was playing and
110
* looping when it got culled).
111
*/
112
public boolean toPlay = false;
113
114
/**
115
* Unique name for this source. More than one source can not have the same
116
* sourcename.
117
*/
118
public String sourcename = "";
119
120
/**
121
* The audio file which this source should play.
122
*/
123
public FilenameURL filenameURL = null;
124
125
/**
126
* This source's position in 3D space.
127
*/
128
public Vector3D position;
129
130
/**
131
* Attenuation model to use for this source.
132
*/
133
public int attModel = 0;
134
135
/**
136
* Either fade distance or rolloff factor, depending on the value of attModel.
137
*/
138
public float distOrRoll = 0.0f;
139
140
/**
141
* Source's velocity in world-space, for use in Doppler effect.
142
*/
143
public Vector3D velocity;
144
145
/**
146
* This source's volume (a float between 0.0 - 1.0). This value is used
147
* internally for attenuation, and should not be used to manually change a
148
* source's volume.
149
*/
150
public float gain = 1.0f;
151
152
/**
153
* This value should be used to manually increase or decrease source volume.
154
*/
155
public float sourceVolume = 1.0f;
156
157
/**
158
* Indicates to the streaming thread that this source is removed and needs cleanup.
159
* @see https://github.com/MinecraftForge/MinecraftForge/pull/4765
160
*/
161
public boolean removed = false;
162
163
/**
164
* This value represents the source's pitch (float value between 0.5f - 2.0f).
165
*/
166
protected float pitch = 1.0f;
167
168
/**
169
* This source's distance from the listener.
170
*/
171
public float distanceFromListener = 0.0f;
172
173
/**
174
* Channel to play this source on.
175
*/
176
public Channel channel = null;
177
178
/**
179
* Holds the data used by normal sources.
180
*/
181
public SoundBuffer soundBuffer = null;
182
183
/**
184
* False when this source gets culled.
185
*/
186
private boolean active = true;
187
188
/**
189
* Whether or not this source has been stopped.
190
*/
191
private boolean stopped = true;
192
193
/**
194
* Whether or not this source has been paused.
195
*/
196
private boolean paused = false;
197
198
/**
199
* Codec used to read data for streaming sources.
200
*/
201
protected ICodec codec = null;
202
203
/**
204
* Codec used to read in some initial data from the next sound in the queue.
205
*/
206
protected ICodec nextCodec = null;
207
208
/**
209
* List of buffers to hold some initial data from the next sound in the queue.
210
*/
211
protected LinkedList<SoundBuffer> nextBuffers = null;
212
213
214
/**
215
* The list of files to stream when the current stream finishes.
216
*/
217
protected LinkedList<FilenameURL> soundSequenceQueue = null;
218
219
/**
220
* Ensures that only one thread accesses the soundSequenceQueue at a time.
221
*/
222
protected final Object soundSequenceLock = new Object();
223
224
/**
225
* Used by streaming sources to indicate whether or not the initial
226
* stream-buffers still need to be queued.
227
*/
228
public boolean preLoad = false;
229
230
/**
231
* Specifies the gain factor used for the fade-out effect, or -1 when
232
* source is not currently fading out.
233
*/
234
protected float fadeOutGain = -1.0f;
235
236
/**
237
* Specifies the gain factor used for the fade-in effect, or 1 when
238
* source is not currently fading in.
239
*/
240
protected float fadeInGain = 1.0f;
241
242
/**
243
* Specifies the number of miliseconds it should take to fade out.
244
*/
245
protected long fadeOutMilis = 0;
246
247
/**
248
* Specifies the number of miliseconds it should take to fade in.
249
*/
250
protected long fadeInMilis = 0;
251
252
/**
253
* System time in miliseconds when the last fade in/out volume check occurred.
254
*/
255
protected long lastFadeCheck = 0;
256
257
/**
258
* Constructor: Creates a new source using the specified parameters.
259
* @param priority Setting this to true will prevent other sounds from overriding this one.
260
* @param toStream Setting this to true will create a streaming source.
261
* @param toLoop Should this source loop, or play only once.
262
* @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.
263
* @param filenameURL The filename/URL of the sound file to play at this source.
264
* @param soundBuffer Buffer containing audio data, or null if not loaded yet.
265
* @param x X position for this source.
266
* @param y Y position for this source.
267
* @param z Z position for this source.
268
* @param attModel Attenuation model to use.
269
* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of 'att'.
270
* @param temporary Whether or not to remove this source after it finishes playing.
271
*/
272
public Source( boolean priority, boolean toStream, boolean toLoop,
273
String sourcename, FilenameURL filenameURL,
274
SoundBuffer soundBuffer, float x, float y, float z,
275
int attModel, float distOrRoll, boolean temporary )
276
{
277
// grab a handle to the message logger:
278
logger = SoundSystemConfig.getLogger();
279
280
this.priority = priority;
281
this.toStream = toStream;
282
this.toLoop = toLoop;
283
this.sourcename = sourcename;
284
this.filenameURL = filenameURL;
285
this.soundBuffer = soundBuffer;
286
position = new Vector3D( x, y, z );
287
this.attModel = attModel;
288
this.distOrRoll = distOrRoll;
289
this.velocity = new Vector3D( 0, 0, 0 );
290
this.temporary = temporary;
291
292
if( toStream && filenameURL != null )
293
codec = SoundSystemConfig.getCodec( filenameURL.getFilename() );
294
}
295
296
/**
297
* Constructor: Creates a new source matching the specified one.
298
* @param old Source to copy information from.
299
* @param soundBuffer Buffer containing audio data, or null if not loaded yet.
300
*/
301
public Source( Source old, SoundBuffer soundBuffer )
302
{
303
// grab a handle to the message logger:
304
logger = SoundSystemConfig.getLogger();
305
306
priority = old.priority;
307
toStream = old.toStream;
308
toLoop = old.toLoop;
309
sourcename = old.sourcename;
310
filenameURL = old.filenameURL;
311
position = old.position.clone();
312
attModel = old.attModel;
313
distOrRoll = old.distOrRoll;
314
velocity = old.velocity.clone();
315
temporary = old.temporary;
316
317
sourceVolume = old.sourceVolume;
318
319
rawDataStream = old.rawDataStream;
320
rawDataFormat = old.rawDataFormat;
321
322
this.soundBuffer = soundBuffer;
323
324
if( toStream && filenameURL != null )
325
codec = SoundSystemConfig.getCodec( filenameURL.getFilename() );
326
}
327
328
/**
329
* Constructor: Creates a new streaming source that will be directly fed with
330
* raw audio data.
331
* @param audioFormat Format that the data will be in.
332
* @param priority Setting this to true will prevent other sounds from overriding this one.
333
* @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.
334
* @param x X position for this source.
335
* @param y Y position for this source.
336
* @param z Z position for this source.
337
* @param attModel Attenuation model to use.
338
* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of 'att'.
339
*/
340
public Source( AudioFormat audioFormat, boolean priority, String sourcename,
341
float x, float y, float z, int attModel, float distOrRoll )
342
{
343
// grab a handle to the message logger:
344
logger = SoundSystemConfig.getLogger();
345
346
this.priority = priority;
347
this.toStream = true;
348
this.toLoop = false;
349
this.sourcename = sourcename;
350
this.filenameURL = null;
351
this.soundBuffer = null;
352
position = new Vector3D( x, y, z );
353
this.attModel = attModel;
354
this.distOrRoll = distOrRoll;
355
this.velocity = new Vector3D( 0, 0, 0 );
356
this.temporary = false;
357
358
rawDataStream = true;
359
rawDataFormat = audioFormat;
360
}
361
/* Override methods */
362
363
/**
364
* Shuts the source down and removes references to all instantiated objects.
365
*/
366
public void cleanup()
367
{
368
if( codec != null )
369
codec.cleanup();
370
371
synchronized( soundSequenceLock )
372
{
373
if( soundSequenceQueue != null )
374
soundSequenceQueue.clear();
375
soundSequenceQueue = null;
376
}
377
378
sourcename = null;
379
filenameURL = null;
380
position = null;
381
soundBuffer = null;
382
codec = null;
383
}
384
385
/**
386
* If this is a streaming source, queues up the next sound to play when
387
* the previous stream ends. This method has no effect on non-streaming
388
* sources.
389
* @param filenameURL The filename/URL of the sound file to stream next.
390
*/
391
public void queueSound( FilenameURL filenameURL )
392
{
393
if( !toStream )
394
{
395
errorMessage( "Method 'queueSound' may only be used for " +
396
"streaming and MIDI sources." );
397
return;
398
}
399
if( filenameURL == null )
400
{
401
errorMessage( "File not specified in method 'queueSound'" );
402
return;
403
}
404
405
synchronized( soundSequenceLock )
406
{
407
if( soundSequenceQueue == null )
408
soundSequenceQueue = new LinkedList<FilenameURL>();
409
soundSequenceQueue.add( filenameURL );
410
}
411
}
412
413
/**
414
* Removes the first occurrence of the specified filename from the list of
415
* sounds to play when the previous stream ends. This method has no effect
416
* on non-streaming sources.
417
* @param filename Filename/identifier of a sound file to remove from the queue.
418
*/
419
public void dequeueSound( String filename )
420
{
421
if( !toStream )
422
{
423
errorMessage( "Method 'dequeueSound' may only be used for " +
424
"streaming and MIDI sources." );
425
return;
426
}
427
if( filename == null || filename.equals( "" ) )
428
{
429
errorMessage( "Filename not specified in method 'dequeueSound'" );
430
return;
431
}
432
433
synchronized( soundSequenceLock )
434
{
435
if( soundSequenceQueue != null )
436
{
437
ListIterator<FilenameURL> i = soundSequenceQueue.listIterator();
438
while( i.hasNext() )
439
{
440
if( i.next().getFilename().equals( filename ) )
441
{
442
i.remove();
443
break;
444
}
445
}
446
}
447
}
448
}
449
450
/**
451
* Fades out the volume of whatever this source is currently playing, then
452
* begins playing the specified filename at the source's previously assigned
453
* volume level. If the filename parameter is null or empty, the source will
454
* simply fade out and stop. The miliseconds parameter must be non-negative or
455
* zero. This method will remove anything that is currently in the list of
456
* queued sounds that would have played next when the current sound finished
457
* playing. This method has no effect on non-streaming sources.
458
* @param filenameURL Filename/URL of the sound file to play next, or null for none.
459
* @param milis Number of miliseconds the fadeout should take.
460
*/
461
public void fadeOut( FilenameURL filenameURL, long milis )
462
{
463
if( !toStream )
464
{
465
errorMessage( "Method 'fadeOut' may only be used for " +
466
"streaming and MIDI sources." );
467
return;
468
}
469
if( milis < 0 )
470
{
471
errorMessage( "Miliseconds may not be negative in method " +
472
"'fadeOut'." );
473
return;
474
}
475
476
fadeOutMilis = milis;
477
fadeInMilis = 0;
478
fadeOutGain = 1.0f;
479
lastFadeCheck = System.currentTimeMillis();
480
481
synchronized( soundSequenceLock )
482
{
483
if( soundSequenceQueue != null )
484
soundSequenceQueue.clear();
485
486
if( filenameURL != null )
487
{
488
if( soundSequenceQueue == null )
489
soundSequenceQueue = new LinkedList<FilenameURL>();
490
soundSequenceQueue.add( filenameURL );
491
}
492
}
493
}
494
495
/**
496
* Fades out the volume of whatever this source is currently playing, then
497
* fades the volume back in playing the specified file. Final volume after
498
* fade-in completes will be equal to the source's previously assigned volume
499
* level. The filenameURL parameter may not be null or empty. The miliseconds
500
* parameters must be non-negative or zero. This method will remove anything
501
* that is currently in the list of queued sounds that would have played next
502
* when the current sound finished playing. This method has no effect on
503
* non-streaming sources.
504
* @param filenameURL Filename/URL of the sound file to play next, or null for none.
505
* @param milisOut Number of miliseconds the fadeout should take.
506
* @param milisIn Number of miliseconds the fadein should take.
507
*/
508
public void fadeOutIn( FilenameURL filenameURL, long milisOut, long milisIn )
509
{
510
if( !toStream )
511
{
512
errorMessage( "Method 'fadeOutIn' may only be used for " +
513
"streaming and MIDI sources." );
514
return;
515
}
516
if( filenameURL == null )
517
{
518
errorMessage( "Filename/URL not specified in method 'fadeOutIn'." );
519
return;
520
}
521
if( milisOut < 0 || milisIn < 0 )
522
{
523
errorMessage( "Miliseconds may not be negative in method " +
524
"'fadeOutIn'." );
525
return;
526
}
527
528
fadeOutMilis = milisOut;
529
fadeInMilis = milisIn;
530
531
fadeOutGain = 1.0f;
532
lastFadeCheck = System.currentTimeMillis();
533
534
synchronized( soundSequenceLock )
535
{
536
if( soundSequenceQueue == null )
537
soundSequenceQueue = new LinkedList<FilenameURL>();
538
soundSequenceQueue.clear();
539
soundSequenceQueue.add( filenameURL );
540
}
541
}
542
543
/**
544
* Resets this source's volume if it is fading out or in. Returns true if this
545
* source is currently in the process of fading out. When fade-out completes,
546
* this method transitions the source to the next sound in the sound sequence
547
* queue if there is one. This method has no effect on non-streaming sources.
548
* @return True if this source is in the process of fading out.
549
*/
550
public boolean checkFadeOut()
551
{
552
if( !toStream )
553
return false;
554
555
if( fadeOutGain == -1.0f && fadeInGain == 1.0f )
556
return false;
557
558
long currentTime = System.currentTimeMillis();
559
long milisPast = currentTime - lastFadeCheck;
560
lastFadeCheck = currentTime;
561
562
if( fadeOutGain >= 0.0f )
563
{
564
if( fadeOutMilis == 0 )
565
{
566
fadeOutGain = -1.0f;
567
fadeInGain = 0.0f;
568
if( !incrementSoundSequence() )
569
{
570
stop();
571
}
572
positionChanged();
573
preLoad = true;
574
return false;
575
}
576
else
577
{
578
float fadeOutReduction = ((float)milisPast) / ((float)fadeOutMilis);
579
fadeOutGain -= fadeOutReduction;
580
if( fadeOutGain <= 0.0f )
581
{
582
fadeOutGain = -1.0f;
583
fadeInGain = 0.0f;
584
if( !incrementSoundSequence() )
585
stop();
586
positionChanged();
587
preLoad = true;
588
return false;
589
}
590
}
591
positionChanged();
592
return true;
593
}
594
595
if( fadeInGain < 1.0f )
596
{
597
fadeOutGain = -1.0f;
598
if( fadeInMilis == 0 )
599
{
600
fadeOutGain = -1.0f;
601
fadeInGain = 1.0f;
602
}
603
else
604
{
605
float fadeInIncrease = ((float)milisPast) / ((float)fadeInMilis);
606
fadeInGain += fadeInIncrease;
607
if( fadeInGain >= 1.0f )
608
{
609
fadeOutGain = -1.0f;
610
fadeInGain = 1.0f;
611
}
612
}
613
positionChanged();
614
return true;
615
}
616
return false;
617
}
618
619
/**
620
* Removes the next filename/URL from the sound sequence queue and assigns it to
621
* this source. This method has no effect on non-streaming sources. This
622
* method is used internally by SoundSystem, and it is unlikely that the user
623
* will ever need to use it.
624
* @return True if there was something in the queue.
625
*/
626
public boolean incrementSoundSequence()
627
{
628
if( !toStream )
629
{
630
errorMessage( "Method 'incrementSoundSequence' may only be used " +
631
"for streaming and MIDI sources." );
632
return false;
633
}
634
635
synchronized( soundSequenceLock )
636
{
637
if( soundSequenceQueue != null && soundSequenceQueue.size() > 0 )
638
{
639
filenameURL = soundSequenceQueue.remove( 0 );
640
if( codec != null )
641
codec.cleanup();
642
codec = SoundSystemConfig.getCodec( filenameURL.getFilename() );
643
return true;
644
}
645
}
646
return false;
647
}
648
649
/**
650
* Reads in initial buffers of data from the next sound in the sound sequence
651
* queue, to reduce lag when the transition occurrs. This method has no effect
652
* on non-streaming sources. This method is used internally by SoundSystem, and
653
* it is unlikely that the user will ever need to use it.
654
* @return False if there is nothing in the queue to read from.
655
*/
656
public boolean readBuffersFromNextSoundInSequence()
657
{
658
if( !toStream )
659
{
660
errorMessage( "Method 'readBuffersFromNextSoundInSequence' may " +
661
"only be used for streaming sources." );
662
return false;
663
}
664
665
synchronized( soundSequenceLock )
666
{
667
if( soundSequenceQueue != null && soundSequenceQueue.size() > 0 )
668
{
669
if( nextCodec != null )
670
nextCodec.cleanup();
671
nextCodec = SoundSystemConfig.getCodec(
672
soundSequenceQueue.get( 0 ).getFilename() );
673
nextCodec.initialize( soundSequenceQueue.get( 0 ).getURL() );
674
675
SoundBuffer buffer = null;
676
for( int i = 0;
677
i < SoundSystemConfig.getNumberStreamingBuffers()
678
&& !nextCodec.endOfStream();
679
i++ )
680
{
681
buffer = nextCodec.read();
682
if( buffer != null )
683
{
684
if( nextBuffers == null )
685
nextBuffers = new LinkedList<SoundBuffer>();
686
nextBuffers.add( buffer );
687
}
688
}
689
return true;
690
}
691
}
692
return false;
693
}
694
695
696
/**
697
* Returns the size of the sound sequence queue (if this is a streaming source).
698
* @return Number of sounds left in the queue, or zero if none.
699
*/
700
public int getSoundSequenceQueueSize()
701
{
702
if( soundSequenceQueue == null )
703
return 0;
704
return soundSequenceQueue.size();
705
}
706
707
/**
708
* Sets whether or not this source should be removed when it finishes playing.
709
* @param tmp True or false.
710
*/
711
public void setTemporary( boolean tmp )
712
{
713
temporary = tmp;
714
}
715
716
/**
717
* Called every time the listener's position or orientation changes.
718
*/
719
public void listenerMoved()
720
{}
721
722
/**
723
* Moves the source to the specified position.
724
* @param x X coordinate to move to.
725
* @param y Y coordinate to move to.
726
* @param z Z coordinate to move to.
727
*/
728
public void setPosition( float x, float y, float z )
729
{
730
position.x = x;
731
position.y = y;
732
position.z = z;
733
}
734
735
/**
736
* Called every time the source changes position.
737
*/
738
public void positionChanged()
739
{}
740
741
/**
742
* Sets whether or not this source is a priority source. A priority source
743
* will not be overritten by another source if there are no channels available
744
* to play on.
745
* @param pri True or false.
746
*/
747
public void setPriority( boolean pri )
748
{
749
priority = pri;
750
}
751
752
/**
753
* Sets whether this source should loop or only play once.
754
* @param lp True or false.
755
*/
756
public void setLooping( boolean lp )
757
{
758
toLoop = lp;
759
}
760
761
/**
762
* Sets this source's attenuation model.
763
* @param model Attenuation model to use.
764
*/
765
public void setAttenuation( int model )
766
{
767
attModel = model;
768
}
769
770
/**
771
* Sets this source's fade distance or rolloff factor, depending on the
772
* attenuation model.
773
* @param dr New value for fade distance or rolloff factor.
774
*/
775
public void setDistOrRoll( float dr)
776
{
777
distOrRoll = dr;
778
}
779
780
/**
781
* Sets this source's velocity, for use in Doppler effect.
782
* @param x Velocity along world x-axis.
783
* @param y Velocity along world y-axis.
784
* @param z Velocity along world z-axis.
785
*/
786
public void setVelocity( float x, float y, float z )
787
{
788
this.velocity.x = x;
789
this.velocity.y = y;
790
this.velocity.z = z;
791
}
792
793
/**
794
* Returns the source's distance from the listener.
795
* @return How far away the source is.
796
*/
797
public float getDistanceFromListener()
798
{
799
return distanceFromListener;
800
}
801
802
/**
803
* Manually sets the specified source's pitch.
804
* @param value A float value ( 0.5f - 2.0f ).
805
*/
806
public void setPitch( float value )
807
{
808
float newPitch = value;
809
if( newPitch < 0.5f )
810
newPitch = 0.5f;
811
else if( newPitch > 2.0f )
812
newPitch = 2.0f;
813
pitch = newPitch;
814
}
815
816
/**
817
* Returns the pitch of the specified source.
818
* @return Float value representing the source pitch (0.5f - 2.0f).
819
*/
820
public float getPitch()
821
{
822
return pitch;
823
}
824
825
/**
826
* Indicates whether or not this source's associated library requires some
827
* codecs to reverse-order the audio data they generate.
828
* @return True if audio data should be reverse-ordered.
829
*/
830
public boolean reverseByteOrder()
831
{
832
return SoundSystemConfig.reverseByteOrder( libraryType );
833
}
834
835
/**
836
* Changes the sources peripheral information to match the supplied parameters.
837
* @param priority Setting this to true will prevent other sounds from overriding this one.
838
* @param toStream Setting this to true will create a streaming source.
839
* @param toLoop Should this source loop, or play only once.
840
* @param sourcename A unique identifier for this source. Two sources may not use the same sourcename.
841
* @param filenameURL Filename/URL of the sound file to play at this source.
842
* @param x X position for this source.
843
* @param y Y position for this source.
844
* @param z Z position for this source.
845
* @param attModel Attenuation model to use.
846
* @param distOrRoll Either the fading distance or rolloff factor, depending on the value of 'att'.
847
* @param temporary Whether or not to remove this source after it finishes playing.
848
*/
849
public void changeSource( boolean priority, boolean toStream,
850
boolean toLoop, String sourcename,
851
FilenameURL filenameURL, SoundBuffer soundBuffer,
852
float x, float y, float z, int attModel,
853
float distOrRoll, boolean temporary )
854
{
855
this.priority = priority;
856
this.toStream = toStream;
857
this.toLoop = toLoop;
858
this.sourcename = sourcename;
859
this.filenameURL = filenameURL;
860
this.soundBuffer = soundBuffer;
861
position.x = x;
862
position.y = y;
863
position.z = z;
864
this.attModel = attModel;
865
this.distOrRoll = distOrRoll;
866
this.temporary = temporary;
867
}
868
869
/**
870
* Feeds raw data to the specified channel.
871
* @param buffer Byte buffer containing raw audio data to stream.
872
* @param c Channel to stream on.
873
* @return Number of prior buffers that have been processed, or -1 if unable to queue the buffer (if the source was culled, for example).
874
*/
875
public int feedRawAudioData( Channel c, byte[] buffer )
876
{
877
if( !active( GET, XXX) )
878
{
879
toPlay = true;
880
return -1;
881
}
882
if( channel != c )
883
{
884
channel = c;
885
channel.close();
886
channel.setAudioFormat( rawDataFormat );
887
positionChanged();
888
}
889
890
// change the state of this source to not stopped and not paused:
891
stopped( SET, false );
892
paused( SET, false );
893
894
return channel.feedRawAudioData( buffer );
895
}
896
897
/**
898
* Plays the source on the specified channel.
899
* @param c Channel to play on.
900
*/
901
public void play( Channel c )
902
{
903
if( !active( GET, XXX) )
904
{
905
if( toLoop )
906
toPlay = true;
907
return;
908
}
909
if( channel != c )
910
{
911
channel = c;
912
channel.close();
913
}
914
// change the state of this source to not stopped and not paused:
915
stopped( SET, false );
916
paused( SET, false );
917
}
918
/* END Override methods */
919
920
/**
921
* Streams the source on its current channel
922
* @return False when stream has finished playing.
923
*/
924
public boolean stream()
925
{
926
if( channel == null )
927
return false;
928
929
if( preLoad )
930
{
931
if( rawDataStream )
932
preLoad = false;
933
else
934
return preLoad();
935
}
936
937
if( rawDataStream )
938
{
939
if( stopped() || paused() )
940
return true;
941
if( channel.buffersProcessed() > 0 )
942
channel.processBuffer();
943
return true;
944
}
945
else
946
{
947
if( codec == null )
948
return false;
949
if( stopped() )
950
return false;
951
if( paused() )
952
return true;
953
954
int processed = channel.buffersProcessed();
955
956
SoundBuffer buffer = null;
957
for( int i = 0; i < processed; i++ )
958
{
959
buffer = codec.read();
960
if( buffer != null )
961
{
962
if( buffer.audioData != null )
963
channel.queueBuffer( buffer.audioData );
964
buffer.cleanup();
965
buffer = null;
966
return true;
967
}
968
else if( codec.endOfStream() )
969
{
970
synchronized( soundSequenceLock )
971
{
972
if( SoundSystemConfig.getStreamQueueFormatsMatch() )
973
{
974
if( soundSequenceQueue != null &&
975
soundSequenceQueue.size() > 0 )
976
{
977
if( codec != null )
978
codec.cleanup();
979
filenameURL = soundSequenceQueue.remove( 0 );
980
codec = SoundSystemConfig.getCodec(
981
filenameURL.getFilename() );
982
codec.initialize( filenameURL.getURL() );
983
buffer = codec.read();
984
if( buffer != null )
985
{
986
if( buffer.audioData != null )
987
channel.queueBuffer( buffer.audioData );
988
buffer.cleanup();
989
buffer = null;
990
return true;
991
}
992
}
993
else if( toLoop )
994
{
995
codec.initialize( filenameURL.getURL() );
996
buffer = codec.read();
997
if( buffer != null )
998
{
999
if( buffer.audioData != null )
1000
channel.queueBuffer( buffer.audioData );
1001
buffer.cleanup();
1002
buffer = null;
1003
return true;
1004
}
1005
}
1006
}
1007
}
1008
}
1009
/*
1010
if( codec.endOfStream() )
1011
{
1012
synchronized( soundSequenceLock )
1013
{
1014
if( SoundSystemConfig.getStreamQueueFormatsMatch() )
1015
{
1016
if( soundSequenceQueue != null &&
1017
soundSequenceQueue.size() > 0 )
1018
{
1019
if( codec != null )
1020
codec.cleanup();
1021
filenameURL = soundSequenceQueue.remove( 0 );
1022
codec = SoundSystemConfig.getCodec(
1023
filenameURL.getFilename() );
1024
codec.initialize( filenameURL.getURL() );
1025
return true;
1026
}
1027
else if( toLoop )
1028
{
1029
codec.initialize( filenameURL.getURL() );
1030
buffer = codec.read();
1031
if( buffer != null )
1032
{
1033
if( buffer.audioData != null )
1034
channel.queueBuffer( buffer.audioData );
1035
buffer.cleanup();
1036
buffer = null;
1037
}
1038
}
1039
}
1040
}
1041
return false;
1042
}
1043
*/
1044
}
1045
}
1046
return false;
1047
}
1048
1049
/**
1050
* Queues up the initial stream-buffers for the stream.
1051
* @return False if the end of the stream was reached.
1052
*/
1053
public boolean preLoad()
1054
{
1055
if( channel == null )
1056
return false;
1057
1058
if( codec == null )
1059
return false;
1060
1061
SoundBuffer buffer = null;
1062
1063
boolean noNextBuffers = false;
1064
synchronized( soundSequenceLock )
1065
{
1066
if( nextBuffers == null || nextBuffers.isEmpty() )
1067
noNextBuffers = true;
1068
}
1069
1070
if( nextCodec != null && !noNextBuffers )
1071
{
1072
codec = nextCodec;
1073
nextCodec = null;
1074
synchronized( soundSequenceLock )
1075
{
1076
while( !nextBuffers.isEmpty() )
1077
{
1078
buffer = nextBuffers.remove( 0 );
1079
if( buffer != null )
1080
{
1081
if( buffer.audioData != null )
1082
channel.queueBuffer( buffer.audioData );
1083
buffer.cleanup();
1084
buffer = null;
1085
}
1086
}
1087
}
1088
}
1089
else
1090
{
1091
nextCodec = null;
1092
URL url = filenameURL.getURL();
1093
1094
codec.initialize( url );
1095
for( int i = 0; i < SoundSystemConfig.getNumberStreamingBuffers();
1096
i++ )
1097
{
1098
buffer = codec.read();
1099
if( buffer != null )
1100
{
1101
if( buffer.audioData != null )
1102
channel.queueBuffer( buffer.audioData );
1103
buffer.cleanup();
1104
buffer = null;
1105
}
1106
}
1107
}
1108
1109
return true;
1110
}
1111
1112
/**
1113
* Pauses the source.
1114
*/
1115
public void pause()
1116
{
1117
toPlay = false;
1118
paused( SET, true );
1119
if( channel != null )
1120
channel.pause();
1121
else
1122
errorMessage( "Channel null in method 'pause'" );
1123
}
1124
1125
/**
1126
* Stops the source.
1127
*/
1128
public void stop()
1129
{
1130
toPlay = false;
1131
stopped( SET, true );
1132
paused( SET, false );
1133
if( channel != null )
1134
channel.stop();
1135
else
1136
errorMessage( "Channel null in method 'stop'" );
1137
}
1138
1139
/**
1140
* Rewinds the source. If the source was paused, then it is stopped.
1141
*/
1142
public void rewind()
1143
{
1144
if( paused( GET, XXX ) )
1145
{
1146
stop();
1147
}
1148
if( channel != null )
1149
{
1150
boolean rePlay = playing();
1151
channel.rewind();
1152
if( toStream && rePlay )
1153
{
1154
stop();
1155
play( channel );
1156
}
1157
}
1158
else
1159
errorMessage( "Channel null in method 'rewind'" );
1160
}
1161
1162
/**
1163
* Dequeues any previously queued data.
1164
*/
1165
public void flush()
1166
{
1167
if( channel != null )
1168
channel.flush();
1169
else
1170
errorMessage( "Channel null in method 'flush'" );
1171
}
1172
1173
/**
1174
* Stops and flushes the source, and prevents it from being played again until
1175
* the activate() is called.
1176
*/
1177
public void cull()
1178
{
1179
if( !active( GET, XXX ) )
1180
return;
1181
if( playing() && toLoop )
1182
toPlay = true;
1183
if( rawDataStream )
1184
toPlay = true;
1185
active( SET, false );
1186
if( channel != null )
1187
channel.close();
1188
channel = null;
1189
}
1190
1191
/**
1192
* Allows a previously culled source to be played again.
1193
*/
1194
public void activate()
1195
{
1196
active( SET, true );
1197
}
1198
1199
/**
1200
* Returns false if the source has been culled.
1201
* @return True or False
1202
*/
1203
public boolean active()
1204
{
1205
return active( GET, XXX );
1206
}
1207
1208
/**
1209
* Returns true if the source is playing.
1210
* @return True or False
1211
*/
1212
public boolean playing()
1213
{
1214
if( channel == null || channel.attachedSource != this )
1215
return false;
1216
else if( paused() || stopped() )
1217
return false;
1218
else
1219
return channel.playing();
1220
}
1221
1222
/**
1223
* Returns true if the source has been stopped.
1224
* @return True or False
1225
*/
1226
public boolean stopped()
1227
{
1228
return stopped( GET, XXX );
1229
}
1230
1231
/**
1232
* Returns true if the source has been paused.
1233
* @return True or False
1234
*/
1235
public boolean paused()
1236
{
1237
return paused( GET, XXX );
1238
}
1239
1240
/**
1241
* Returns the number of miliseconds since the source began playing.
1242
* @return miliseconds, or -1 if not playing or unable to calculate
1243
*/
1244
public float millisecondsPlayed()
1245
{
1246
if( channel == null )
1247
return( -1 );
1248
else
1249
return channel.millisecondsPlayed();
1250
}
1251
1252
/**
1253
* Sets or returns whether or not the source has been culled.
1254
* @return True or False
1255
*/
1256
private synchronized boolean active( boolean action, boolean value )
1257
{
1258
if( action == SET )
1259
active = value;
1260
return active;
1261
}
1262
1263
/**
1264
* Sets or returns whether or not the source has been stopped.
1265
* @return True or False
1266
*/
1267
private synchronized boolean stopped( boolean action, boolean value )
1268
{
1269
if( action == SET )
1270
stopped = value;
1271
return stopped;
1272
}
1273
1274
/**
1275
* Sets or returns whether or not the source has been paused.
1276
* @return True or False
1277
*/
1278
private synchronized boolean paused( boolean action, boolean value )
1279
{
1280
if( action == SET )
1281
paused = value;
1282
return paused;
1283
}
1284
1285
/**
1286
* Returns the name of the class.
1287
* @return SoundLibraryXXXX.
1288
*/
1289
public String getClassName()
1290
{
1291
String libTitle = SoundSystemConfig.getLibraryTitle( libraryType );
1292
1293
if( libTitle.equals( "No Sound" ) )
1294
return "Source";
1295
else
1296
return "Source" + libTitle;
1297
}
1298
/**
1299
* Prints a message.
1300
* @param message Message to print.
1301
*/
1302
protected void message( String message )
1303
{
1304
logger.message( message, 0 );
1305
}
1306
1307
/**
1308
* Prints an important message.
1309
* @param message Message to print.
1310
*/
1311
protected void importantMessage( String message )
1312
{
1313
logger.importantMessage( message, 0 );
1314
}
1315
1316
/**
1317
* Prints the specified message if error is true.
1318
* @param error True or False.
1319
* @param message Message to print if error is true.
1320
* @return True if error is true.
1321
*/
1322
protected boolean errorCheck( boolean error, String message )
1323
{
1324
return logger.errorCheck( error, getClassName(), message, 0 );
1325
}
1326
1327
/**
1328
* Prints an error message.
1329
* @param message Message to print.
1330
*/
1331
protected void errorMessage( String message )
1332
{
1333
logger.errorMessage( getClassName(), message, 0 );
1334
}
1335
1336
/**
1337
* Prints an exception's error message followed by the stack trace.
1338
* @param e Exception containing the information to print.
1339
*/
1340
protected void printStackTrace( Exception e )
1341
{
1342
logger.printStackTrace( e, 1 );
1343
}
1344
}
1345
1346