    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    }