001package net.minecraft.client.audio;
002
003import net.minecraftforge.client.*;
004import net.minecraftforge.client.event.sound.*;
005import net.minecraftforge.common.MinecraftForge;
006import static net.minecraftforge.client.event.sound.SoundEvent.*;
007import cpw.mods.fml.relauncher.Side;
008import cpw.mods.fml.relauncher.SideOnly;
009import java.io.File;
010import java.util.ArrayList;
011import java.util.HashSet;
012import java.util.Iterator;
013import java.util.List;
014import java.util.Random;
015import java.util.Set;
016import net.minecraft.client.settings.GameSettings;
017import net.minecraft.entity.Entity;
018import net.minecraft.entity.EntityLiving;
019import net.minecraft.util.MathHelper;
020import paulscode.sound.SoundSystem;
021import paulscode.sound.SoundSystemConfig;
022import paulscode.sound.codecs.CodecJOrbis;
023import paulscode.sound.codecs.CodecWav;
024import paulscode.sound.libraries.LibraryLWJGLOpenAL;
025
026@SideOnly(Side.CLIENT)
027public 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}