001 package net.minecraft.src;
002
003 import net.minecraftforge.client.*;
004 import net.minecraftforge.client.event.sound.*;
005 import net.minecraftforge.common.MinecraftForge;
006 import static net.minecraftforge.client.event.sound.SoundEvent.*;
007 import cpw.mods.fml.common.Side;
008 import cpw.mods.fml.common.asm.SideOnly;
009 import java.io.File;
010 import java.util.HashSet;
011 import java.util.Iterator;
012 import java.util.Random;
013 import java.util.Set;
014 import paulscode.sound.SoundSystem;
015 import paulscode.sound.SoundSystemConfig;
016 import paulscode.sound.codecs.CodecJOrbis;
017 import paulscode.sound.codecs.CodecWav;
018 import paulscode.sound.libraries.LibraryLWJGLOpenAL;
019
020 @SideOnly(Side.CLIENT)
021 public class SoundManager
022 {
023 /** A reference to the sound system. */
024 public static SoundSystem sndSystem;
025
026 /** Sound pool containing sounds. */
027 public SoundPool soundPoolSounds = new SoundPool();
028
029 /** Sound pool containing streaming audio. */
030 public SoundPool soundPoolStreaming = new SoundPool();
031
032 /** Sound pool containing music. */
033 public SoundPool soundPoolMusic = new SoundPool();
034
035 /**
036 * The last ID used when a sound is played, passed into SoundSystem to give active sounds a unique ID
037 */
038 private int latestSoundID = 0;
039
040 /** A reference to the game settings. */
041 private GameSettings options;
042 private Set field_82470_g = new HashSet();
043
044 /** Set to true when the SoundManager has been initialised. */
045 private static boolean loaded = false;
046
047 /** RNG. */
048 private Random rand = new Random();
049 private int ticksBeforeMusic;
050
051 public static int MUSIC_INTERVAL = 12000;
052
053 public SoundManager()
054 {
055 this.ticksBeforeMusic = this.rand.nextInt(MUSIC_INTERVAL);
056 }
057
058 /**
059 * Used for loading sound settings from GameSettings
060 */
061 public void loadSoundSettings(GameSettings par1GameSettings)
062 {
063 this.soundPoolStreaming.isGetRandomSound = false;
064 this.options = par1GameSettings;
065
066 if (!loaded && (par1GameSettings == null || par1GameSettings.soundVolume != 0.0F || par1GameSettings.musicVolume != 0.0F))
067 {
068 this.tryToSetLibraryAndCodecs();
069 }
070 ModCompatibilityClient.audioModLoad(this);
071 MinecraftForge.EVENT_BUS.post(new SoundLoadEvent(this));
072 }
073
074 /**
075 * Tries to add the paulscode library and the relevant codecs. If it fails, the volumes (sound and music) will be
076 * set to zero in the options file.
077 */
078 private void tryToSetLibraryAndCodecs()
079 {
080 try
081 {
082 float var1 = this.options.soundVolume;
083 float var2 = this.options.musicVolume;
084 this.options.soundVolume = 0.0F;
085 this.options.musicVolume = 0.0F;
086 this.options.saveOptions();
087 SoundSystemConfig.addLibrary(LibraryLWJGLOpenAL.class);
088 SoundSystemConfig.setCodec("ogg", CodecJOrbis.class);
089 SoundSystemConfig.setCodec("mus", CodecMus.class);
090 SoundSystemConfig.setCodec("wav", CodecWav.class);
091 ModCompatibilityClient.audioModAddCodecs();
092 MinecraftForge.EVENT_BUS.post(new SoundSetupEvent(this));
093 sndSystem = new SoundSystem();
094 this.options.soundVolume = var1;
095 this.options.musicVolume = var2;
096 this.options.saveOptions();
097 }
098 catch (Throwable var3)
099 {
100 var3.printStackTrace();
101 System.err.println("error linking with the LibraryJavaSound plug-in");
102 }
103
104 loaded = true;
105 }
106
107 /**
108 * Called when one of the sound level options has changed.
109 */
110 public void onSoundOptionsChanged()
111 {
112 if (!loaded && (this.options.soundVolume != 0.0F || this.options.musicVolume != 0.0F))
113 {
114 this.tryToSetLibraryAndCodecs();
115 }
116
117 if (loaded)
118 {
119 if (this.options.musicVolume == 0.0F)
120 {
121 sndSystem.stop("BgMusic");
122 }
123 else
124 {
125 sndSystem.setVolume("BgMusic", this.options.musicVolume);
126 }
127 }
128 }
129
130 /**
131 * Called when Minecraft is closing down.
132 */
133 public void closeMinecraft()
134 {
135 if (loaded)
136 {
137 sndSystem.cleanup();
138 }
139 }
140
141 /**
142 * Adds a sounds with the name from the file. Args: name, file
143 */
144 public void addSound(String par1Str, File par2File)
145 {
146 this.soundPoolSounds.addSound(par1Str, par2File);
147 }
148
149 /**
150 * Adds an audio file to the streaming SoundPool.
151 */
152 public void addStreaming(String par1Str, File par2File)
153 {
154 this.soundPoolStreaming.addSound(par1Str, par2File);
155 }
156
157 /**
158 * Adds an audio file to the music SoundPool.
159 */
160 public void addMusic(String par1Str, File par2File)
161 {
162 this.soundPoolMusic.addSound(par1Str, par2File);
163 }
164
165 /**
166 * If its time to play new music it starts it up.
167 */
168 public void playRandomMusicIfReady()
169 {
170 if (loaded && this.options.musicVolume != 0.0F)
171 {
172 if (!sndSystem.playing("BgMusic") && !sndSystem.playing("streaming"))
173 {
174 if (this.ticksBeforeMusic > 0)
175 {
176 --this.ticksBeforeMusic;
177 return;
178 }
179
180 SoundPoolEntry var1 = this.soundPoolMusic.getRandomSound();
181 var1 = ModCompatibilityClient.audioModPickBackgroundMusic(this, var1);
182 var1 = SoundEvent.getResult(new PlayBackgroundMusicEvent(this, var1));
183
184 if (var1 != null)
185 {
186 this.ticksBeforeMusic = this.rand.nextInt(MUSIC_INTERVAL) + MUSIC_INTERVAL;
187 sndSystem.backgroundMusic("BgMusic", var1.soundUrl, var1.soundName, false);
188 sndSystem.setVolume("BgMusic", this.options.musicVolume);
189 sndSystem.play("BgMusic");
190 }
191 }
192 }
193 }
194
195 /**
196 * Sets the listener of sounds
197 */
198 public void setListener(EntityLiving par1EntityLiving, float par2)
199 {
200 if (loaded && this.options.soundVolume != 0.0F)
201 {
202 if (par1EntityLiving != null)
203 {
204 float var3 = par1EntityLiving.prevRotationYaw + (par1EntityLiving.rotationYaw - par1EntityLiving.prevRotationYaw) * par2;
205 double var4 = par1EntityLiving.prevPosX + (par1EntityLiving.posX - par1EntityLiving.prevPosX) * (double)par2;
206 double var6 = par1EntityLiving.prevPosY + (par1EntityLiving.posY - par1EntityLiving.prevPosY) * (double)par2;
207 double var8 = par1EntityLiving.prevPosZ + (par1EntityLiving.posZ - par1EntityLiving.prevPosZ) * (double)par2;
208 float var10 = MathHelper.cos(-var3 * 0.017453292F - (float)Math.PI);
209 float var11 = MathHelper.sin(-var3 * 0.017453292F - (float)Math.PI);
210 float var12 = -var11;
211 float var13 = 0.0F;
212 float var14 = -var10;
213 float var15 = 0.0F;
214 float var16 = 1.0F;
215 float var17 = 0.0F;
216 sndSystem.setListenerPosition((float)var4, (float)var6, (float)var8);
217 sndSystem.setListenerOrientation(var12, var13, var14, var15, var16, var17);
218 }
219 }
220 }
221
222 public void func_82464_d()
223 {
224 Iterator var1 = this.field_82470_g.iterator();
225
226 while (var1.hasNext())
227 {
228 String var2 = (String)var1.next();
229 sndSystem.stop(var2);
230 }
231
232 this.field_82470_g.clear();
233 }
234
235 public void playStreaming(String par1Str, float par2, float par3, float par4)
236 {
237 if (loaded && (this.options.soundVolume != 0.0F || par1Str == null))
238 {
239 String var5 = "streaming";
240
241 if (sndSystem.playing(var5))
242 {
243 sndSystem.stop(var5);
244 }
245
246 if (par1Str != null)
247 {
248 SoundPoolEntry var6 = this.soundPoolStreaming.getRandomSoundFromSoundPool(par1Str);
249 var6 = SoundEvent.getResult(new PlayStreamingEvent(this, var6, par1Str, par2, par3, par4));
250
251 if (var6 != null)
252 {
253 if (sndSystem.playing("BgMusic"))
254 {
255 sndSystem.stop("BgMusic");
256 }
257
258 float var7 = 16.0F;
259 sndSystem.newStreamingSource(true, var5, var6.soundUrl, var6.soundName, false, par2, par3, par4, 2, var7 * 4.0F);
260 sndSystem.setVolume(var5, 0.5F * this.options.soundVolume);
261 MinecraftForge.EVENT_BUS.post(new PlayStreamingSourceEvent(this, var5, par2, par3, par4));
262 sndSystem.play(var5);
263 }
264 }
265 }
266 }
267
268 public void func_82460_a(Entity par1Entity)
269 {
270 this.func_82462_a(par1Entity, par1Entity);
271 }
272
273 public void func_82462_a(Entity par1Entity, Entity par2Entity)
274 {
275 String var3 = "entity_" + par1Entity.entityId;
276
277 if (this.field_82470_g.contains(var3))
278 {
279 if (sndSystem.playing(var3))
280 {
281 sndSystem.setPosition(var3, (float)par2Entity.posX, (float)par2Entity.posY, (float)par2Entity.posZ);
282 sndSystem.setVelocity(var3, (float)par2Entity.motionX, (float)par2Entity.motionY, (float)par2Entity.motionZ);
283 }
284 else
285 {
286 this.field_82470_g.remove(var3);
287 }
288 }
289 }
290
291 public boolean func_82465_b(Entity par1Entity)
292 {
293 if (par1Entity != null && loaded && this.options.musicVolume != 0.0F)
294 {
295 String var2 = "entity_" + par1Entity.entityId;
296 return sndSystem.playing(var2);
297 }
298 else
299 {
300 return false;
301 }
302 }
303
304 public void func_82469_c(Entity par1Entity)
305 {
306 if (par1Entity != null && loaded && this.options.musicVolume != 0.0F)
307 {
308 String var2 = "entity_" + par1Entity.entityId;
309
310 if (this.field_82470_g.contains(var2))
311 {
312 if (sndSystem.playing(var2))
313 {
314 sndSystem.stop(var2);
315 }
316
317 this.field_82470_g.remove(var2);
318 }
319 }
320 }
321
322 public void func_82468_a(Entity par1Entity, float par2)
323 {
324 if (par1Entity != null && loaded && this.options.musicVolume != 0.0F)
325 {
326 if (loaded && this.options.soundVolume != 0.0F)
327 {
328 String var3 = "entity_" + par1Entity.entityId;
329
330 if (sndSystem.playing(var3))
331 {
332 sndSystem.setVolume(var3, par2 * this.options.soundVolume);
333 }
334 }
335 }
336 }
337
338 public void func_82463_b(Entity par1Entity, float par2)
339 {
340 if (par1Entity != null && loaded && this.options.musicVolume != 0.0F)
341 {
342 if (loaded && this.options.soundVolume != 0.0F)
343 {
344 String var3 = "entity_" + par1Entity.entityId;
345
346 if (sndSystem.playing(var3))
347 {
348 sndSystem.setPitch(var3, par2);
349 }
350 }
351 }
352 }
353
354 public void func_82467_a(String par1Str, Entity par2Entity, float par3, float par4, boolean par5)
355 {
356 if (par2Entity != null)
357 {
358 if (loaded && (this.options.soundVolume != 0.0F || par1Str == null))
359 {
360 String var6 = "entity_" + par2Entity.entityId;
361
362 if (this.field_82470_g.contains(var6))
363 {
364 this.func_82460_a(par2Entity);
365 }
366 else
367 {
368 if (sndSystem.playing(var6))
369 {
370 sndSystem.stop(var6);
371 }
372
373 if (par1Str == null)
374 {
375 return;
376 }
377
378 SoundPoolEntry var7 = this.soundPoolSounds.getRandomSoundFromSoundPool(par1Str);
379
380 if (var7 != null && par3 > 0.0F)
381 {
382 float var8 = 16.0F;
383
384 if (par3 > 1.0F)
385 {
386 var8 *= par3;
387 }
388
389 sndSystem.newSource(par5, var6, var7.soundUrl, var7.soundName, false, (float)par2Entity.posX, (float)par2Entity.posY, (float)par2Entity.posZ, 2, var8);
390 sndSystem.setLooping(var6, true);
391 sndSystem.setPitch(var6, par4);
392
393 if (par3 > 1.0F)
394 {
395 par3 = 1.0F;
396 }
397
398 sndSystem.setVolume(var6, par3 * this.options.soundVolume);
399 sndSystem.setVelocity(var6, (float)par2Entity.motionX, (float)par2Entity.motionY, (float)par2Entity.motionZ);
400 sndSystem.play(var6);
401 this.field_82470_g.add(var6);
402 }
403 }
404 }
405 }
406 }
407
408 /**
409 * Plays a sound. Args: soundName, x, y, z, volume, pitch
410 */
411 public void playSound(String par1Str, float par2, float par3, float par4, float par5, float par6)
412 {
413 if (loaded && this.options.soundVolume != 0.0F)
414 {
415 SoundPoolEntry var7 = this.soundPoolSounds.getRandomSoundFromSoundPool(par1Str);
416 var7 = SoundEvent.getResult(new PlaySoundEvent(this, var7, par1Str, par2, par3, par4, par5, par6));
417
418 if (var7 != null && par5 > 0.0F)
419 {
420 this.latestSoundID = (this.latestSoundID + 1) % 256;
421 String var8 = "sound_" + this.latestSoundID;
422 float var9 = 16.0F;
423
424 if (par5 > 1.0F)
425 {
426 var9 *= par5;
427 }
428
429 sndSystem.newSource(par5 > 1.0F, var8, var7.soundUrl, var7.soundName, false, par2, par3, par4, 2, var9);
430 sndSystem.setPitch(var8, par6);
431
432 if (par5 > 1.0F)
433 {
434 par5 = 1.0F;
435 }
436
437 sndSystem.setVolume(var8, par5 * this.options.soundVolume);
438 MinecraftForge.EVENT_BUS.post(new PlaySoundSourceEvent(this, var8, par2, par3, par4));
439 sndSystem.play(var8);
440 }
441 }
442 }
443
444 /**
445 * Plays a sound effect with the volume and pitch of the parameters passed. The sound isn't affected by position of
446 * the player (full volume and center balanced)
447 */
448 public void playSoundFX(String par1Str, float par2, float par3)
449 {
450 if (loaded && this.options.soundVolume != 0.0F)
451 {
452 SoundPoolEntry var4 = this.soundPoolSounds.getRandomSoundFromSoundPool(par1Str);
453 var4 = SoundEvent.getResult(new PlaySoundEffectEvent(this, var4, par1Str, par2, par3));
454
455 if (var4 != null)
456 {
457 this.latestSoundID = (this.latestSoundID + 1) % 256;
458 String var5 = "sound_" + this.latestSoundID;
459 sndSystem.newSource(false, var5, var4.soundUrl, var4.soundName, false, 0.0F, 0.0F, 0.0F, 0, 0.0F);
460
461 if (par2 > 1.0F)
462 {
463 par2 = 1.0F;
464 }
465
466 par2 *= 0.25F;
467 sndSystem.setPitch(var5, par3);
468 sndSystem.setVolume(var5, par2 * this.options.soundVolume);
469 MinecraftForge.EVENT_BUS.post(new PlaySoundEffectSourceEvent(this, var5));
470 sndSystem.play(var5);
471 }
472 }
473 }
474
475 public void func_82466_e()
476 {
477 Iterator var1 = this.field_82470_g.iterator();
478
479 while (var1.hasNext())
480 {
481 String var2 = (String)var1.next();
482 sndSystem.pause(var2);
483 }
484 }
485
486 public void func_82461_f()
487 {
488 Iterator var1 = this.field_82470_g.iterator();
489
490 while (var1.hasNext())
491 {
492 String var2 = (String)var1.next();
493 sndSystem.play(var2);
494 }
495 }
496 }