简体   繁体   English

一次只能播放一个声音片段

[英]Can only play one sound clip at a time

I wrote a custom sound system for my game, but if two sounds are requested to play within a few ms of eachother only one sound clip will play. 我为游戏编写了一个自定义的声音系统,但是如果要求在彼此之间几毫秒内播放两种声音,则只会播放一个声音片段。

I tried running the playback on a new thread like this but it did not work. 我尝试在这样的新线程上运行播放,但没有成功。 No exceptions are being thrown, it just wont play both sounds. 没有异常被抛出,它不会同时播放两种声音。

Thread one = new Thread() {
    public void run() {
        try {
            CustomSound.playSound(id, loop, dist);
        } catch (Exception e) {
        e.printStackTrace();
        }
    }  
};

Here is the sound player class 这是声音播放器类

public class CustomSound {

    /*
     * Directory of your sound files
     * format is WAV
     */
    private static final String DIRECTORY = sign.signlink.findcachedir()+"audio/effects/";

    /*
     * Current volume state
     * 36 chosen for default 50% volume state
     */
    public static float settingModifier = 70f;

    /*
     * Current volume state
     */
    public static boolean isMuted;

    /*
     * Clips
     */
    private static Clip[] clipIndex = null;

    /*
     * Get number of files in directory
     */
    private static final int getDirectoryLength() {
        return new File(DIRECTORY).list().length;
    }

    /**
     * Loads the sound clips into memory
     * during startup to prevent lag if loading
     * them during runtime.
     **/
    public static void preloadSounds() {
        clipIndex = new Clip[getDirectoryLength()];
        int counter = 0;
        for (int i = 0; i < clipIndex.length; i++) {
            try {
                File f = new File(DIRECTORY+"sound "+i+".wav");
                AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(f);
                clipIndex[i] = AudioSystem.getClip();
                clipIndex[i].open(audioInputStream);    
                counter++;
            } catch (MalformedURLException e) {
                System.out.println("Sound effect not found: "+i);
                e.printStackTrace();
                return;
            } catch (UnsupportedAudioFileException e) {
                System.out.println("Unsupported format for sound: "+i);
                return;
            } catch (LineUnavailableException e) {
                e.printStackTrace();
                return;
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }   
        }
        System.out.println("Succesfully loaded: "+counter+" custom sound clips.");
    }

    /**
     * Plays a sound
     * @param soundID - The ID of the sound
     * @param loop - How many times to loop this sound
     * @param distanceFromSource - The distance from the source in tiles
     */
    public static void playSound(final int soundID, int loop, int distanceFromSource) { 

        try {
            if (!isMuted) {
                clipIndex[soundID].setFramePosition(0);
                applyVolumeSetting(clipIndex[soundID], getDistanceModifier(distanceFromSource)*settingModifier);
                if (loop == 1 || loop == 0) {
                    clipIndex[soundID].start(); 
                } else {
                    clipIndex[soundID].loop(loop);
                }
                /* shows how to close line when clip is finished playing
            clipIndex[soundID].addLineListener(new LineListener() {
                public void update(LineEvent myLineEvent) {
                    if (myLineEvent.getType() == LineEvent.Type.STOP)
                        clipIndex[soundID].close();
                }
            });
                 */
            }
        } catch (Exception e) {
            System.out.println("Error please report: ");
            e.printStackTrace();
        }
    }

    /**
     * Applies volume setting to the clip
     * @param line - the Clip to adjust volume setting for
     * @param volume - the volume percentage (0-100)
     * @return - the volume with applied setting
     */
    public static float applyVolumeSetting(Clip line, double volume) {
        //System.out.println("Modifying volume to "+volume);
        if (volume > 100.0) volume = 100.0;
        if (volume >= 0.0) {
            FloatControl ctrl = null;
            try {
                ctrl = (FloatControl)(line.getControl(FloatControl.Type.MASTER_GAIN));
            } catch (IllegalArgumentException iax1) {
                try {
                    ctrl = (FloatControl)(line.getControl(FloatControl.Type.VOLUME));
                } catch (IllegalArgumentException iax2) {
                    System.out.println("Controls.setVolume() not supported.");
                    return -1;
                }
            }
            float minimum = ctrl.getMinimum();
            float maximum = ctrl.getMaximum();
            float newValue = (float)(minimum + volume * (maximum - minimum) / 100.0F);
            //System.out.println("System min: " + minimum);
            //System.out.println("System max: " + maximum);         
            if (newValue <= ctrl.getMinimum())
                newValue = ctrl.getMinimum();
            if (newValue >= ctrl.getMaximum())
                newValue = ctrl.getMaximum();           

            ctrl.setValue(newValue);
            //System.out.println("Setting modifier = " + volume);
            //System.out.println("New value = " + newValue);
            return newValue;
        }
        return -1;
    }

    /**
     * Calculates tile distance modifier
     * @param tileDistance - distance in tiles from source
     * @return - the distance modifier
     */
    public static float getDistanceModifier(int tileDistance) {
        if (tileDistance <= 0) {
            tileDistance = 0;
        }
        if (tileDistance >= 10) {
            tileDistance = 10;
        }
        float distanceModifier = 0;
        if (tileDistance == 10)
            distanceModifier = 0.40f;
        if (tileDistance == 9)
            distanceModifier = 0.55f;
        if (tileDistance == 8)
            distanceModifier = 0.60f;
        if (tileDistance == 7)
            distanceModifier = 0.65f;
        if (tileDistance == 6)
            distanceModifier = 0.70f;
        if (tileDistance == 5)
            distanceModifier = 0.75f;
        if (tileDistance == 4)
            distanceModifier = 0.80f;
        if (tileDistance == 3)
            distanceModifier = 0.85f;
        if (tileDistance == 2)
            distanceModifier = 0.90f;
        if (tileDistance == 1)
            distanceModifier = 0.95f;
        if (tileDistance == 0)
            distanceModifier = 1.00f;

        return distanceModifier;
    }

}

When I tested your code on my Windows machine, I had no problems playing two different sounds in short succession: 当我在Windows计算机上测试您的代码时,我很快就可以连续播放两种不同的声音了:

public static void main(String[] args) throws Exception {

    CustomSound.preloadSounds();

    CustomSound.playSound(0, 0, 0);
    CustomSound.playSound(1, 0, 0);

    Thread.sleep(5000);
}

Note however, that DataLine#start() is an asynchronous call. 但是请注意, DataLine#start()是异步调用。 That could be related to your problem. 那可能与您的问题有关。

Also, according to the documentation of DataLine#start() , 另外,根据DataLine#start()的文档,

If invoked on a line that is already running, this method does nothing. 如果在已经运行的行上调用,则此方法不执行任何操作。

If that is your problem, and you want to play the same sound twice simultaneously, one possible solution would be to get another Clip instance that plays the same sound and start that. 如果这是您的问题,并且您想同时播放两次相同的声音,则一种可能的解决方案是让另一个Clip实例播放相同的声音并开始播放。

However I'm no expert at Java's sound API so there might a more efficient way. 但是,我不是Java的声音API的专家,所以可能会有更有效的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM