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