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 && loaded)
310            {
311                String var2 = "entity_" + par1Entity.entityId;
312                return sndSystem.playing(var2);
313            }
314            else
315            {
316                return false;
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 && loaded)
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 && loaded)
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 && loaded)
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    }