使用Java的Clip类时出现问题

时间:2013-10-03 20:03:10

标签: java audio javasound

我在我开发的游戏中使用Java的Clip类时遇到了麻烦。具体来说,我认为问题在于同时多次使用相同的剪辑。我做了一些谷歌搜索,有些人建议在自己的线程中运行剪辑。我想复制剪辑对象,以便在每个线程中使用不同的剪辑对象,以避免需要“重置”剪辑,但我仍然遇到问题。事实上,问题是当同一个剪辑同时播放几次时,游戏似乎会冻结。

有人在Reddit上建议问题可能是因为Clip类不是同步的,而且每次我想要使用它时我都必须打开剪辑。显然,这是行不通的,因为声音经常使用。

如果某人可能能够指出该课程的致命缺陷,请输入以下代码:

/**
    This file is part of Generic Zombie Shooter.

    Generic Zombie Shooter is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Generic Zombie Shooter is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Generic Zombie Shooter.  If not, see <http://www.gnu.org/licenses/>.
 **/
package genericzombieshooter.misc;

import java.io.IOException;
import java.net.URL;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;

/**
 * Contains all pre-loaded sounds.
 * @author Darin Beaudreau
 */
public enum Sounds {
    // Weapon-Related
    POPGUN("shoot2.wav", false),
    RTPS("shoot1.wav", false),
    BOOMSTICK("shotgun1.wav", false),
    FLAMETHROWER("flamethrower.wav", true),
    THROW("throw2.wav", false),
    EXPLOSION("explosion2.wav", false),
    LANDMINE_ARMED("landmine_armed.wav", false),
    TELEPORT("teleport.wav", false),

    // Zombie-Related
    MOAN1("zombie_moan_01.wav", false),
    MOAN2("zombie_moan_02.wav", false),
    MOAN3("zombie_moan_03.wav", false),
    MOAN4("zombie_moan_04.wav", false),
    MOAN5("zombie_moan_05.wav", false),
    MOAN6("zombie_moan_06.wav", false),
    MOAN7("zombie_moan_07.wav", false),
    MOAN8("zombie_moan_08.wav", false),
    POISONCLOUD("poison_cloud.wav", false),

    // Game Sounds
    POWERUP("powerup.wav", false),
    PURCHASEWEAPON("purchase_weapon.wav", false),
    BUYAMMO("buy_ammo2.wav", false),
    PAUSE("pause.wav", false),
    UNPAUSE("unpause.wav", false);

    private Clip clip;
    private boolean looped;

    Sounds(String filename, boolean loop) {
        openClip(filename, loop);
    }

    private synchronized void openClip(String filename, boolean loop) {
        try {
            URL audioFile = Sounds.class.getResource("/resources/sounds/" + filename);

            AudioInputStream audio = AudioSystem.getAudioInputStream(audioFile);
            AudioFormat format = audio.getFormat();
            DataLine.Info info = new DataLine.Info(Clip.class, format);
            clip = (Clip) AudioSystem.getLine(info);

            clip.open(audio);
        } catch (UnsupportedAudioFileException uae) {
            System.out.println(uae);
        } catch (IOException ioe) {
            System.out.println(ioe);
        } catch (LineUnavailableException lue) {
            System.out.println(lue);
        }
        looped = loop;
    }

    public synchronized void play() {
        play(1.0);
    }

    public synchronized void play(final double gain) {
        Runnable soundPlay = new Runnable() {
            @Override
            public void run() {
                Clip clipCopy = (Clip)clip;
                FloatControl gainControl = (FloatControl)clipCopy.getControl(FloatControl.Type.MASTER_GAIN);
                float dB = (float)(Math.log(gain) / Math.log(10.0) * 20.0);
                gainControl.setValue(dB);
                if(!looped) reset(clipCopy);
                clipCopy.loop((looped)?Clip.LOOP_CONTINUOUSLY:0);

            }
        };
        new Thread(soundPlay).start();
    }

    public synchronized void reset() {
        reset(clip);
    }

    public synchronized void reset(Clip clipCopy) {
        synchronized(clipCopy) { clipCopy.stop(); }
        clipCopy.setFramePosition(0);
    }

    public static void init() {
        values();
    }
}

我正在尝试做什么,使用枚举和静态play()方法,可能是我想要完成的事情?或者我必须找到另一种方式?我可以使用不同的类,甚至是必要的库,但我宁愿留在核心Java中。

有人可以想办法做我想做的事吗?

1 个答案:

答案 0 :(得分:1)

剪辑不支持并发。您可以随时重新启动剪辑,并多次播放。但是在任何给定的时间,一次只能有一个给定Clip的实例播放。

TinySound是一个很好的库,但我不记得他的剪辑是否允许并发游戏。你可以在全部进入之前检查一下。在Java-gaming.org上有一个关于这个库的实质主题。

我不了解Net Beans,但是要在Eclipse中使用Git Hub源,我按照Git Hub提供的有关如何设置帐户和制作克隆的说明,然后将克隆下载到我的桌​​面上(使用Bash)。说明并不容易,但这是产品(GitHub)的一个非常基本的用途,你应该能够找到支持。

一旦项目在桌面上,我在Eclipse中创建一个新项目,并提供桌面克隆的根目录作为位置。 Eclipse具有用于将外部库链接到项目的其他设置。如果Net Beans没有类似的东西,我会感到非常惊讶。

Eclipse还可以创建项目或从zip文件链接库。 Zips与Jar文件的格式完全相同。 Net Beans应该有一种链接到项目的zip或jar的方法。在Eclipse中,他们对存储在zip中的项目使用术语“archived”。但是我不知道你拥有的zip是否只是作为外部项目加载所需的一切。我对GitHub的体验很小。

如果您想重复使用枪支或其他任何东西,您可能需要为每个要支持的并发副本制作一个剪辑。

我最终编写了自己的剪辑对象并为其提供了多个游标,以及一个混合来自并发游标的数据的界面。它运作得很好!我愿意寄给你一份试用版。它设置为使用连续运行的音频混音器(我认为与TinySound相同)。但是如果我发给你代码,你可能可以将Clip部分重写为独立。 “PFClip”还允许以不同的速度进行平移,音量设置和播放,因此您可以改变枪声的速度。这样做,它听起来像不同的枪(或爆炸,如果你让他们真的很慢)。[在这里获得最大的爆炸插入双关语。]

该库有一些很酷的附加功能:用于循环剪辑的PFLoop(允许一个以平滑的方式重叠两端),我只是制作了镶边,立体声合唱和音高变量回声。与TinySound不同,我不支持44100fps和16位的立体声wav格式。我为我正在制作的游戏写了这个,可以通过浏览器播放:http://hexara.com/game.html windchime效果是使用并发剪辑的东西。

忘记!我从前面开始有另一个混音器的演示,它以各种方式使用单枪声,同时: enter link description here JGO中列出的代码是陈旧的,但是线程中有一个页面,其基本思想可用于制作您自己的并发剪辑。

联系信息在第二个链接网站上提供。