org.blockartistry.DynSurround.client.sound.SoundEngine.java Source code

Java tutorial

Introduction

Here is the source code for org.blockartistry.DynSurround.client.sound.SoundEngine.java

Source

/*
 * This file is part of Dynamic Surroundings, licensed under the MIT License (MIT).
 *
 * Copyright (c) OreCruncher, Abastro
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package org.blockartistry.DynSurround.client.sound;

import java.nio.IntBuffer;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.apache.commons.lang3.StringUtils;
import org.blockartistry.DynSurround.DSurround;
import org.blockartistry.DynSurround.ModOptions;
import org.lwjgl.BufferUtils;
import org.lwjgl.openal.AL;
import org.lwjgl.openal.AL10;
import org.lwjgl.openal.ALC10;
import org.lwjgl.openal.ALC11;

import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.SoundHandler;
import net.minecraft.client.audio.SoundManager;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.client.event.sound.SoundSetupEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import paulscode.sound.SoundSystem;
import paulscode.sound.SoundSystemConfig;

@Mod.EventBusSubscriber(value = Side.CLIENT, modid = DSurround.MOD_ID)
public class SoundEngine {

    private static final int MAX_STREAM_CHANNELS = 16;
    private static final int SOUND_QUEUE_SLACK = 6;

    private static SoundEngine instance = null;

    public static SoundEngine instance() {
        if (instance == null)
            instance = new SoundEngine();

        return instance;
    }

    private SoundHandler handler = Minecraft.getMinecraft().getSoundHandler();
    private SoundManager manager = this.handler.sndManager;

    private SoundEngine() {
        MinecraftForge.EVENT_BUS.register(this);
    }

    public int currentSoundCount() {
        return this.manager.playingSoundsStopTime.size();
    }

    public int maxSoundCount() {
        return SoundSystemConfig.getNumberNormalChannels() + SoundSystemConfig.getNumberStreamingChannels();
    }

    private boolean canFitSound() {
        return currentSoundCount() < (SoundSystemConfig.getNumberNormalChannels() - SOUND_QUEUE_SLACK);
    }

    public boolean isSoundPlaying(@Nonnull final BasicSound<?> sound) {
        return this.manager.isSoundPlaying(sound) || this.manager.invPlayingSounds.containsKey(sound)
                || this.manager.delayedSounds.containsKey(sound);
    }

    public boolean isSoundPlaying(@Nonnull final String soundId) {
        if (StringUtils.isEmpty(soundId))
            return false;
        return this.manager.playingSounds.containsKey(soundId);
    }

    public void stopSound(@Nonnull final String sound, @Nonnull final SoundCategory cat) {
        if (sound != null)
            this.manager.stop(sound, cat);
    }

    public void stopSound(@Nonnull final BasicSound<?> sound) {
        if (sound != null)
            this.manager.stopSound(sound);
    }

    public void stopAllSounds() {
        this.manager.stopAllSounds();
    }

    @Nullable
    public String playSound(@Nonnull final BasicSound<?> sound) {
        if (!canFitSound()) {
            if (ModOptions.enableDebugLogging)
                DSurround.log().debug("> NO ROOM: [%s]", sound.toString());
            return null;
        }

        if (!StringUtils.isEmpty(sound.getId()))
            this.manager.stopSound(sound);

        this.manager.playSound(sound);

        if (ModOptions.enableDebugLogging) {
            if (StringUtils.isEmpty(sound.getId())) {
                DSurround.log().debug("> NOT QUEUED: [%s]", sound.toString());
            } else {
                final StringBuilder builder = new StringBuilder();
                builder.append("> QUEUED: [").append(sound.toString()).append(']');
                if (DSurround.log().testTrace(ModOptions.Trace.TRUE_SOUND_VOLUME)) {
                    final SoundSystem ss = this.manager.sndSystem;
                    // Force a flush of all commands so we can get
                    // the actual volume and pitch used within the
                    // sound library.
                    ss.CommandQueue(null);
                    final float v = ss.getVolume(sound.getId());
                    final float p = ss.getPitch(sound.getId());
                    builder.append("; v: ").append(v).append(", p: ").append(p);
                }
                DSurround.log().debug(builder.toString());
            }
        }

        return sound.getId();
    }

    @Nullable
    public String playSound(@Nonnull final BlockPos pos, @Nonnull final SoundEvent soundIn,
            @Nonnull final SoundCategory category, final float volume, final float pitch) {
        final BasicSound<?> sound = new AdhocSound(soundIn, category);
        sound.setVolume(volume).setPitch(pitch).setPosition(pos);
        return this.playSound(sound);
    }

    @SubscribeEvent(priority = EventPriority.HIGH)
    public static void onSoundSetup(@Nonnull final SoundSetupEvent event) {
        configureSound();
    }

    private static void alErrorCheck() {
        final int error = AL10.alGetError();
        if (error != AL10.AL_NO_ERROR)
            DSurround.log().warn("OpenAL error: %d", error);
    }

    private static void configureSound() {
        int totalChannels = -1;

        try {

            final boolean create = !AL.isCreated();
            if (create) {
                AL.create();
                alErrorCheck();
            }

            final IntBuffer ib = BufferUtils.createIntBuffer(1);
            ALC10.alcGetInteger(AL.getDevice(), ALC11.ALC_MONO_SOURCES, ib);
            alErrorCheck();
            totalChannels = ib.get(0);

            if (create)
                AL.destroy();

        } catch (final Throwable e) {
            e.printStackTrace();
        }

        int normalChannelCount = ModOptions.normalSoundChannelCount;
        int streamChannelCount = ModOptions.streamingSoundChannelCount;

        if (ModOptions.autoConfigureChannels && totalChannels > 64) {
            totalChannels = ((totalChannels + 1) * 3) / 4;
            streamChannelCount = Math.min(totalChannels / 5, MAX_STREAM_CHANNELS);
            normalChannelCount = totalChannels - streamChannelCount;
        }

        DSurround.log().info("Sound channels: %d normal, %d streaming (total avail: %s)", normalChannelCount,
                streamChannelCount, totalChannels == -1 ? "UNKNOWN" : Integer.toString(totalChannels));
        SoundSystemConfig.setNumberNormalChannels(normalChannelCount);
        SoundSystemConfig.setNumberStreamingChannels(streamChannelCount);

        // Setup sound buffering
        if (ModOptions.streamBufferCount != 0)
            SoundSystemConfig.setNumberStreamingBuffers(ModOptions.streamBufferCount);
        if (ModOptions.streamBufferSize != 0)
            SoundSystemConfig.setStreamingBufferSize(ModOptions.streamBufferSize * 1024);
        DSurround.log().info("Stream buffers: %d x %d", SoundSystemConfig.getNumberStreamingBuffers(),
                SoundSystemConfig.getStreamingBufferSize());
    }

}