    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    }