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.prevRotationPitch + (par1EntityLiving.rotationPitch - par1EntityLiving.prevRotationPitch) * par2; 207 float var4 = par1EntityLiving.prevRotationYaw + (par1EntityLiving.rotationYaw - par1EntityLiving.prevRotationYaw) * par2; 208 double var5 = par1EntityLiving.prevPosX + (par1EntityLiving.posX - par1EntityLiving.prevPosX) * (double)par2; 209 double var7 = par1EntityLiving.prevPosY + (par1EntityLiving.posY - par1EntityLiving.prevPosY) * (double)par2; 210 double var9 = par1EntityLiving.prevPosZ + (par1EntityLiving.posZ - par1EntityLiving.prevPosZ) * (double)par2; 211 float var11 = MathHelper.cos(-var4 * 0.017453292F - (float)Math.PI); 212 float var12 = MathHelper.sin(-var4 * 0.017453292F - (float)Math.PI); 213 float var13 = -var12; 214 float var14 = -MathHelper.sin(-var3 * 0.017453292F - (float)Math.PI); 215 float var15 = -var11; 216 float var16 = 0.0F; 217 float var17 = 1.0F; 218 float var18 = 0.0F; 219 sndSystem.setListenerPosition((float)var5, (float)var7, (float)var9); 220 sndSystem.setListenerOrientation(var13, var14, var15, var16, var17, var18); 221 } 222 } 223 } 224 225 /** 226 * Stops all currently playing sounds 227 */ 228 public void stopAllSounds() 229 { 230 Iterator var1 = this.playingSounds.iterator(); 231 232 while (var1.hasNext()) 233 { 234 String var2 = (String)var1.next(); 235 sndSystem.stop(var2); 236 } 237 238 this.playingSounds.clear(); 239 } 240 241 public void playStreaming(String par1Str, float par2, float par3, float par4) 242 { 243 if (loaded && (this.options.soundVolume != 0.0F || par1Str == null)) 244 { 245 String var5 = "streaming"; 246 247 if (sndSystem.playing(var5)) 248 { 249 sndSystem.stop(var5); 250 } 251 252 if (par1Str != null) 253 { 254 SoundPoolEntry var6 = this.soundPoolStreaming.getRandomSoundFromSoundPool(par1Str); 255 var6 = SoundEvent.getResult(new PlayStreamingEvent(this, var6, par1Str, par2, par3, par4)); 256 257 if (var6 != null) 258 { 259 if (sndSystem.playing("BgMusic")) 260 { 261 sndSystem.stop("BgMusic"); 262 } 263 264 float var7 = 16.0F; 265 sndSystem.newStreamingSource(true, var5, var6.soundUrl, var6.soundName, false, par2, par3, par4, 2, var7 * 4.0F); 266 sndSystem.setVolume(var5, 0.5F * this.options.soundVolume); 267 MinecraftForge.EVENT_BUS.post(new PlayStreamingSourceEvent(this, var5, par2, par3, par4)); 268 sndSystem.play(var5); 269 } 270 } 271 } 272 } 273 274 /** 275 * Updates the sound associated with the entity with that entity's position and velocity. Args: the entity 276 */ 277 public void updateSoundLocation(Entity par1Entity) 278 { 279 this.updateSoundLocation(par1Entity, par1Entity); 280 } 281 282 /** 283 * Updates the sound associated with soundEntity with the position and velocity of trackEntity. Args: soundEntity, 284 * trackEntity 285 */ 286 public void updateSoundLocation(Entity par1Entity, Entity par2Entity) 287 { 288 String var3 = "entity_" + par1Entity.entityId; 289 290 if (this.playingSounds.contains(var3)) 291 { 292 if (sndSystem.playing(var3)) 293 { 294 sndSystem.setPosition(var3, (float)par2Entity.posX, (float)par2Entity.posY, (float)par2Entity.posZ); 295 sndSystem.setVelocity(var3, (float)par2Entity.motionX, (float)par2Entity.motionY, (float)par2Entity.motionZ); 296 } 297 else 298 { 299 this.playingSounds.remove(var3); 300 } 301 } 302 } 303 304 /** 305 * Returns true if a sound is currently associated with the given entity, or false otherwise. 306 */ 307 public boolean isEntitySoundPlaying(Entity par1Entity) 308 { 309 if (par1Entity == null) 310 { 311 return false; 312 } 313 else 314 { 315 String var2 = "entity_" + par1Entity.entityId; 316 return sndSystem.playing(var2); 317 } 318 } 319 320 /** 321 * Stops playing the sound associated with the given entity 322 */ 323 public void stopEntitySound(Entity par1Entity) 324 { 325 if (par1Entity != null) 326 { 327 String var2 = "entity_" + par1Entity.entityId; 328 329 if (this.playingSounds.contains(var2)) 330 { 331 if (sndSystem.playing(var2)) 332 { 333 sndSystem.stop(var2); 334 } 335 336 this.playingSounds.remove(var2); 337 } 338 } 339 } 340 341 /** 342 * Sets the volume of the sound associated with the given entity, if one is playing. The volume is scaled by the 343 * global sound volume. Args: the entity, the volume (from 0 to 1) 344 */ 345 public void setEntitySoundVolume(Entity par1Entity, float par2) 346 { 347 if (par1Entity != null) 348 { 349 if (loaded && this.options.soundVolume != 0.0F) 350 { 351 String var3 = "entity_" + par1Entity.entityId; 352 353 if (sndSystem.playing(var3)) 354 { 355 sndSystem.setVolume(var3, par2 * this.options.soundVolume); 356 } 357 } 358 } 359 } 360 361 /** 362 * Sets the pitch of the sound associated with the given entity, if one is playing. Args: the entity, the pitch 363 */ 364 public void setEntitySoundPitch(Entity par1Entity, float par2) 365 { 366 if (par1Entity != null) 367 { 368 if (loaded && this.options.soundVolume != 0.0F) 369 { 370 String var3 = "entity_" + par1Entity.entityId; 371 372 if (sndSystem.playing(var3)) 373 { 374 sndSystem.setPitch(var3, par2); 375 } 376 } 377 } 378 } 379 380 /** 381 * If a sound is already playing from the given entity, update the position and velocity of that sound to match the 382 * entity. Otherwise, start playing a sound from that entity. Args: The sound name, the entity, the volume, the 383 * pitch, unknown flag 384 */ 385 public void playEntitySound(String par1Str, Entity par2Entity, float par3, float par4, boolean par5) 386 { 387 if (par2Entity != null) 388 { 389 if (loaded && (this.options.soundVolume != 0.0F || par1Str == null)) 390 { 391 String var6 = "entity_" + par2Entity.entityId; 392 393 if (this.playingSounds.contains(var6)) 394 { 395 this.updateSoundLocation(par2Entity); 396 } 397 else 398 { 399 if (sndSystem.playing(var6)) 400 { 401 sndSystem.stop(var6); 402 } 403 404 if (par1Str == null) 405 { 406 return; 407 } 408 409 SoundPoolEntry var7 = this.soundPoolSounds.getRandomSoundFromSoundPool(par1Str); 410 411 if (var7 != null && par3 > 0.0F) 412 { 413 float var8 = 16.0F; 414 415 if (par3 > 1.0F) 416 { 417 var8 *= par3; 418 } 419 420 sndSystem.newSource(par5, var6, var7.soundUrl, var7.soundName, false, (float)par2Entity.posX, (float)par2Entity.posY, (float)par2Entity.posZ, 2, var8); 421 sndSystem.setLooping(var6, true); 422 sndSystem.setPitch(var6, par4); 423 424 if (par3 > 1.0F) 425 { 426 par3 = 1.0F; 427 } 428 429 sndSystem.setVolume(var6, par3 * this.options.soundVolume); 430 sndSystem.setVelocity(var6, (float)par2Entity.motionX, (float)par2Entity.motionY, (float)par2Entity.motionZ); 431 sndSystem.play(var6); 432 this.playingSounds.add(var6); 433 } 434 } 435 } 436 } 437 } 438 439 /** 440 * Plays a sound. Args: soundName, x, y, z, volume, pitch 441 */ 442 public void playSound(String par1Str, float par2, float par3, float par4, float par5, float par6) 443 { 444 if (loaded && this.options.soundVolume != 0.0F) 445 { 446 SoundPoolEntry var7 = this.soundPoolSounds.getRandomSoundFromSoundPool(par1Str); 447 var7 = SoundEvent.getResult(new PlaySoundEvent(this, var7, par1Str, par2, par3, par4, par5, par6)); 448 449 if (var7 != null && par5 > 0.0F) 450 { 451 this.latestSoundID = (this.latestSoundID + 1) % 256; 452 String var8 = "sound_" + this.latestSoundID; 453 float var9 = 16.0F; 454 455 if (par5 > 1.0F) 456 { 457 var9 *= par5; 458 } 459 460 sndSystem.newSource(par5 > 1.0F, var8, var7.soundUrl, var7.soundName, false, par2, par3, par4, 2, var9); 461 sndSystem.setPitch(var8, par6); 462 463 if (par5 > 1.0F) 464 { 465 par5 = 1.0F; 466 } 467 468 sndSystem.setVolume(var8, par5 * this.options.soundVolume); 469 MinecraftForge.EVENT_BUS.post(new PlaySoundSourceEvent(this, var8, par2, par3, par4)); 470 sndSystem.play(var8); 471 } 472 } 473 } 474 475 /** 476 * Plays a sound effect with the volume and pitch of the parameters passed. The sound isn't affected by position of 477 * the player (full volume and center balanced) 478 */ 479 public void playSoundFX(String par1Str, float par2, float par3) 480 { 481 if (loaded && this.options.soundVolume != 0.0F) 482 { 483 SoundPoolEntry var4 = this.soundPoolSounds.getRandomSoundFromSoundPool(par1Str); 484 var4 = SoundEvent.getResult(new PlaySoundEffectEvent(this, var4, par1Str, par2, par3)); 485 486 if (var4 != null) 487 { 488 this.latestSoundID = (this.latestSoundID + 1) % 256; 489 String var5 = "sound_" + this.latestSoundID; 490 sndSystem.newSource(false, var5, var4.soundUrl, var4.soundName, false, 0.0F, 0.0F, 0.0F, 0, 0.0F); 491 492 if (par2 > 1.0F) 493 { 494 par2 = 1.0F; 495 } 496 497 par2 *= 0.25F; 498 sndSystem.setPitch(var5, par3); 499 sndSystem.setVolume(var5, par2 * this.options.soundVolume); 500 MinecraftForge.EVENT_BUS.post(new PlaySoundEffectSourceEvent(this, var5)); 501 sndSystem.play(var5); 502 } 503 } 504 } 505 506 /** 507 * Pauses all currently playing sounds 508 */ 509 public void pauseAllSounds() 510 { 511 Iterator var1 = this.playingSounds.iterator(); 512 513 while (var1.hasNext()) 514 { 515 String var2 = (String)var1.next(); 516 sndSystem.pause(var2); 517 } 518 } 519 520 /** 521 * Resumes playing all currently playing sounds (after pauseAllSounds) 522 */ 523 public void resumeAllSounds() 524 { 525 Iterator var1 = this.playingSounds.iterator(); 526 527 while (var1.hasNext()) 528 { 529 String var2 = (String)var1.next(); 530 sndSystem.play(var2); 531 } 532 } 533 }