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