1

I'm having trouble using Java's Clip class in a game I've been developing. Specifically, I think the problem is in using the same clip multiple times simultaneously. I did some googling and some people suggested running the clip in its own thread. I wanted to copy the clip object so it would use a different clip object in every thread to avoid the need to "reset" the clip, but I'm still running into problems. In fact, the problem is that the game seems to freeze up when the same clip plays several times simultaneously.

Someone on Reddit suggested that the issue may be because the Clip class is not synchronous, and that I would have to open the clip every time I want to use it. Obviously, this won't work, since the sounds are used very frequently.

In case someone may be able to point out a fatal flaw with the class, here's the code:

/**
    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();
    }
}

So is what I'm trying to do, using an enum and static play() method, possible for what I'm trying to accomplish? Or will I have to find another way? I'm fine with using a different class, or even a library if necessary, but I'd rather stay within core Java.

Can someone think of a way to do what I'm looking to do?

4

1 回答 1

1

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

TinySound 是一个很好的库,但我不记得他的 Clips 是否也允许并发播放。您可能会在全力以赴之前检查一下。在 Java-gaming.org 上有一个关于这个库的实质性线程。

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

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

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

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

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

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

忘记!我之前有另一个混音器的演示,它同时以各种方式使用单个枪声: 在此处输入链接描述 JGO 上列出的代码是陈旧的,但是线程中有一个页面可以是基本思想用于制作自己的并发剪辑。

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

于 2013-10-04T23:53:41.857 回答