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