Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epoxy
GitHub Repository: epoxy/proj11
Path: blob/master/SLICK_HOME/src/org/newdawn/slick/Music.java
1456 views
1
package org.newdawn.slick;
2
3
import java.net.URL;
4
import java.util.ArrayList;
5
6
import org.newdawn.slick.openal.Audio;
7
import org.newdawn.slick.openal.AudioImpl;
8
import org.newdawn.slick.openal.SoundStore;
9
import org.newdawn.slick.util.Log;
10
11
/**
12
* A piece of music loaded and playable within the game. Only one piece of music can
13
* play at any given time and a channel is reserved so music will always play.
14
*
15
* @author kevin
16
* @author Nathan Sweet <[email protected]>
17
*/
18
public class Music {
19
/** The music currently being played or null if none */
20
private static Music currentMusic;
21
22
/**
23
* Poll the state of the current music. This causes streaming music
24
* to stream and checks listeners. Note that if you're using a game container
25
* this will be auto-magically called for you.
26
*
27
* @param delta The amount of time since last poll
28
*/
29
public static void poll(int delta) {
30
if (currentMusic != null) {
31
SoundStore.get().poll(delta);
32
if (!SoundStore.get().isMusicPlaying()) {
33
if (!currentMusic.positioning) {
34
Music oldMusic = currentMusic;
35
currentMusic = null;
36
oldMusic.fireMusicEnded();
37
}
38
} else {
39
currentMusic.update(delta);
40
}
41
}
42
}
43
44
/** The sound from FECK representing this music */
45
private Audio sound;
46
/** True if the music is playing */
47
private boolean playing;
48
/** The list of listeners waiting for notification that the music ended */
49
private ArrayList listeners = new ArrayList();
50
/** The volume of this music */
51
private float volume = 1.0f;
52
/** Start gain for fading in/out */
53
private float fadeStartGain;
54
/** End gain for fading in/out */
55
private float fadeEndGain;
56
/** Countdown for fading in/out */
57
private int fadeTime;
58
/** Duration for fading in/out */
59
private int fadeDuration;
60
/** True if music should be stopped after fading in/out */
61
private boolean stopAfterFade;
62
/** True if the music is being repositioned and it is therefore normal that it's not playing */
63
private boolean positioning;
64
/** The position that was requested */
65
private float requiredPosition = -1;
66
67
/**
68
* Create and load a piece of music (either OGG or MOD/XM)
69
*
70
* @param ref The location of the music
71
* @throws SlickException
72
*/
73
public Music(String ref) throws SlickException {
74
this(ref, false);
75
}
76
77
/**
78
* Create and load a piece of music (either OGG or MOD/XM)
79
*
80
* @param ref The location of the music
81
* @throws SlickException
82
*/
83
public Music(URL ref) throws SlickException {
84
this(ref, false);
85
}
86
87
/**
88
* Create and load a piece of music (either OGG or MOD/XM)
89
*
90
* @param url The location of the music
91
* @param streamingHint A hint to indicate whether streaming should be used if possible
92
* @throws SlickException
93
*/
94
public Music(URL url, boolean streamingHint) throws SlickException {
95
SoundStore.get().init();
96
String ref = url.getFile();
97
98
try {
99
if (ref.toLowerCase().endsWith(".ogg")) {
100
if (streamingHint) {
101
sound = SoundStore.get().getOggStream(url);
102
} else {
103
sound = SoundStore.get().getOgg(url.openStream());
104
}
105
} else if (ref.toLowerCase().endsWith(".wav")) {
106
sound = SoundStore.get().getWAV(url.openStream());
107
} else if (ref.toLowerCase().endsWith(".xm") || ref.toLowerCase().endsWith(".mod")) {
108
sound = SoundStore.get().getMOD(url.openStream());
109
} else if (ref.toLowerCase().endsWith(".aif") || ref.toLowerCase().endsWith(".aiff")) {
110
sound = SoundStore.get().getAIF(url.openStream());
111
} else {
112
throw new SlickException("Only .xm, .mod, .ogg, and .aif/f are currently supported.");
113
}
114
} catch (Exception e) {
115
Log.error(e);
116
throw new SlickException("Failed to load sound: "+url);
117
}
118
}
119
120
/**
121
* Create and load a piece of music (either OGG or MOD/XM)
122
*
123
* @param ref The location of the music
124
* @param streamingHint A hint to indicate whether streaming should be used if possible
125
* @throws SlickException
126
*/
127
public Music(String ref, boolean streamingHint) throws SlickException {
128
SoundStore.get().init();
129
130
try {
131
if (ref.toLowerCase().endsWith(".ogg")) {
132
if (streamingHint) {
133
sound = SoundStore.get().getOggStream(ref);
134
} else {
135
sound = SoundStore.get().getOgg(ref);
136
}
137
} else if (ref.toLowerCase().endsWith(".wav")) {
138
sound = SoundStore.get().getWAV(ref);
139
} else if (ref.toLowerCase().endsWith(".xm") || ref.toLowerCase().endsWith(".mod")) {
140
sound = SoundStore.get().getMOD(ref);
141
} else if (ref.toLowerCase().endsWith(".aif") || ref.toLowerCase().endsWith(".aiff")) {
142
sound = SoundStore.get().getAIF(ref);
143
} else {
144
throw new SlickException("Only .xm, .mod, .ogg, and .aif/f are currently supported.");
145
}
146
} catch (Exception e) {
147
Log.error(e);
148
throw new SlickException("Failed to load sound: "+ref);
149
}
150
}
151
152
/**
153
* Add a listener to this music
154
*
155
* @param listener The listener to add
156
*/
157
public void addListener(MusicListener listener) {
158
listeners.add(listener);
159
}
160
161
/**
162
* Remove a listener from this music
163
*
164
* @param listener The listener to remove
165
*/
166
public void removeListener(MusicListener listener) {
167
listeners.remove(listener);
168
}
169
170
/**
171
* Fire notifications that this music ended
172
*/
173
private void fireMusicEnded() {
174
playing = false;
175
for (int i=0;i<listeners.size();i++) {
176
((MusicListener) listeners.get(i)).musicEnded(this);
177
}
178
}
179
180
/**
181
* Fire notifications that this music was swapped out
182
*
183
* @param newMusic The new music that will be played
184
*/
185
private void fireMusicSwapped(Music newMusic) {
186
playing = false;
187
for (int i=0;i<listeners.size();i++) {
188
((MusicListener) listeners.get(i)).musicSwapped(this, newMusic);
189
}
190
}
191
/**
192
* Loop the music
193
*/
194
public void loop() {
195
loop(1.0f, 1.0f);
196
}
197
198
/**
199
* Play the music
200
*/
201
public void play() {
202
play(1.0f, 1.0f);
203
}
204
205
/**
206
* Play the music at a given pitch and volume
207
*
208
* @param pitch The pitch to play the music at (1.0 = default)
209
* @param volume The volume to play the music at (1.0 = default)
210
*/
211
public void play(float pitch, float volume) {
212
startMusic(pitch, volume, false);
213
}
214
215
/**
216
* Loop the music at a given pitch and volume
217
*
218
* @param pitch The pitch to play the music at (1.0 = default)
219
* @param volume The volume to play the music at (1.0 = default)
220
*/
221
public void loop(float pitch, float volume) {
222
startMusic(pitch, volume, true);
223
}
224
225
/**
226
* play or loop the music at a given pitch and volume
227
* @param pitch The pitch to play the music at (1.0 = default)
228
* @param volume The volume to play the music at (1.0 = default)
229
* @param loop if false the music is played once, the music is looped otherwise
230
*/
231
private void startMusic(float pitch, float volume, boolean loop) {
232
if (currentMusic != null) {
233
currentMusic.stop();
234
currentMusic.fireMusicSwapped(this);
235
}
236
237
currentMusic = this;
238
if (volume < 0.0f)
239
volume = 0.0f;
240
if (volume > 1.0f)
241
volume = 1.0f;
242
243
sound.playAsMusic(pitch, volume, loop);
244
playing = true;
245
setVolume(volume);
246
if (requiredPosition != -1) {
247
setPosition(requiredPosition);
248
}
249
}
250
251
/**
252
* Pause the music playback
253
*/
254
public void pause() {
255
playing = false;
256
AudioImpl.pauseMusic();
257
}
258
259
/**
260
* Stop the music playing
261
*/
262
public void stop() {
263
sound.stop();
264
}
265
266
/**
267
* Resume the music playback
268
*/
269
public void resume() {
270
playing = true;
271
AudioImpl.restartMusic();
272
}
273
274
/**
275
* Check if the music is being played
276
*
277
* @return True if the music is being played
278
*/
279
public boolean playing() {
280
return (currentMusic == this) && (playing);
281
}
282
283
/**
284
* Set the volume of the music as a factor of the global volume setting
285
*
286
* @param volume The volume to play music at. 0 - 1, 1 is Max
287
*/
288
public void setVolume(float volume) {
289
// Bounds check
290
if(volume > 1) {
291
volume = 1;
292
} else if(volume < 0) {
293
volume = 0;
294
}
295
296
this.volume = volume;
297
// This sound is being played as music
298
if (currentMusic == this) {
299
SoundStore.get().setCurrentMusicVolume(volume);
300
}
301
}
302
303
/**
304
* Get the individual volume of the music
305
* @return The volume of this music, still effected by global SoundStore volume. 0 - 1, 1 is Max
306
*/
307
public float getVolume() {
308
return volume;
309
}
310
311
/**
312
* Fade this music to the volume specified
313
*
314
* @param duration Fade time in milliseconds.
315
* @param endVolume The target volume
316
* @param stopAfterFade True if music should be stopped after fading in/out
317
*/
318
public void fade (int duration, float endVolume, boolean stopAfterFade) {
319
this.stopAfterFade = stopAfterFade;
320
fadeStartGain = volume;
321
fadeEndGain = endVolume;
322
fadeDuration = duration;
323
fadeTime = duration;
324
}
325
326
/**
327
* Update the current music applying any effects that need to updated per
328
* tick.
329
*
330
* @param delta The amount of time in milliseconds thats passed since last update
331
*/
332
void update(int delta) {
333
if (!playing) {
334
return;
335
}
336
337
if (fadeTime > 0) {
338
fadeTime -= delta;
339
if (fadeTime < 0) {
340
fadeTime = 0;
341
if (stopAfterFade) {
342
stop();
343
return;
344
}
345
}
346
347
float offset = (fadeEndGain - fadeStartGain) * (1 - (fadeTime / (float)fadeDuration));
348
setVolume(fadeStartGain + offset);
349
}
350
}
351
352
/**
353
* Seeks to a position in the music. For streaming music, seeking before the current position causes
354
* the stream to be reloaded.
355
*
356
* @param position Position in seconds.
357
* @return True if the seek was successful
358
*/
359
public boolean setPosition(float position) {
360
if (playing) {
361
requiredPosition = -1;
362
363
positioning = true;
364
playing = false;
365
boolean result = sound.setPosition(position);
366
playing = true;
367
positioning = false;
368
369
return result;
370
} else {
371
requiredPosition = position;
372
return false;
373
}
374
}
375
376
/**
377
* The position into the sound thats being played
378
*
379
* @return The current position in seconds.
380
*/
381
public float getPosition () {
382
return sound.getPosition();
383
}
384
}
385
386