【问题标题】:How can a Java application play a sound clip?Java 应用程序如何播放声音剪辑?
【发布时间】:2011-06-17 16:55:11
【问题描述】:

以下是我见过的最有可能的解释的链接,但我仍有疑问。

How can I play sound in Java?

我将在这里引用代码:

public static synchronized void playSound(final String url) {
new Thread(new Runnable() {
  public void run() {
    try {
      Clip clip = AudioSystem.getClip();
      AudioInputStream inputStream = AudioSystem.getAudioInputStream(Main.class.getResourceAsStream("/path/to/sounds/" + url));
      clip.open(inputStream);
      clip.start(); 
    } catch (Exception e) {
      System.err.println(e.getMessage());
    }
  }
}).start();

}

  1. 这是否适用于应用程序,而不是 Applet?
  2. Main.class.getResourceAsStream() 方法似乎需要 import com.sun.tools.apt.Main; 但我找不到相关文档,也不知道它的作用.例如,“/path/to/sounds/”是绝对的,还是相对的,如果是后者,相对于哪里?

我现在花了很多时间尝试播放一个简单的声音效果。很难想象这是多么困难。我希望上面的代码可以正常工作。感谢您的帮助。

章节

【问题讨论】:

    标签: java audio clip javasound


    【解决方案1】:
    1. 这应该可以在应用程序中使用。
    2. 那行代码很可能引用了该方法所在的类。因此该方法最初在 Main 类中,如果您将该方法放在 FooBar 类中,则应将其更改为 FooBar.class.getResourceAsStream()。
    3. 这是一个相对路径。它将在每个包之外寻找资源。示例:假设运行这段代码的类位于 C:\Users\Jeffrey\bin\foo\bar\SoundPlayer.class 并且该类在包 foo.bar 中。这意味着 ClassLoader 将在 C:\Users\Jeffrey\bin\ 文件夹中查找资源。 (在您的情况下,它将在 C:\Users\Jeffrey\bin\path\to\sounds\ + url 中查找资源)

    我总是加载这样的声音:

     Clip sound = (Clip) AudioSystem.getLine(new Line.Info(Clip.class));
     sound.open(AudioSystem.getAudioInputStream(file));
    

    但你的方法也应该有效。

    【讨论】:

    • 关于#2,你真的应该让方法非静态,然后使用getClass()。
    • 感谢您将 Main.class 部分识别为红鲱鱼,并感谢您对 getResourceAsStream() 的帮助。
    【解决方案2】:

    这是否适用于应用程序,而不是 Applet?

    两者都适用。

    方法 Main.class.getResourceAsStream() 似乎需要 import com.sun.tools.apt.Main;

    你是从哪里得到这个想法的?我做了很多合理的例子,从来没有听说过你不应该使用的那个类。

    ..但是我找不到相关文档,..

    不,com.sun 类不仅没有记录,而且可能会在下一个微版本中更改。

    ..我不知道它的作用。比如“/path/to/sounds/”是绝对的,还是相对的,如果是后者,相对于哪里?

    它是相对于类路径的根目录。

    .. 难度之大令人难以置信。

    一般来说,媒体处理很棘手。


    顺便说一句 - 我对链接线程上的代码印象不深。 Thread 包装器 是不必要的,正如几个 cmets 中所提到的,即使同时播放多个 Clip 实例也是如此。

    请参阅我(撰写和)个人推荐的this code。

    【讨论】:

    • 有趣:你的最后一行是JOptionPane.showMessageDialog(null, "Close to end..");。如果它不存在,则声音剪辑将在开始时立即停止播放,因为程序将关闭。我想知道@Chap 是否知道这一点。
    • 对于此处的格式错误,请提前道歉;不知道如何实现引用块。或者新的线路,grrr。 Main.class.getResourceAsStream() 方法似乎需要 import com.sun.tools.apt.Main;你从哪里得到这个想法的?我做了很多合理的例子,从来没有听说过你不应该使用的那个类。是的 - 这是 NetBeans 或 Eclipse 的“清理导入”所建议的。
    • @toto:不,但我会很快弄清楚 :-) @andrew:感谢您的代码。我想我可以将它与查找“本地”音频文件资源的其他建议结合起来。
    • @Andrew:在一定程度上使用您的解决方案;谢谢你!我需要的是一种播放音效的方法当事件发生时,可能每秒播放 5-10 次。我宁愿让我的程序确定何时播放剪辑,因为它的时间可能会有所不同,而不是简单地设置剪辑循环。我可以进一步讨论我的尝试,并发布一些代码,但是(新手协议问题)这应该是一个单独的主题吗?
    • @Chap:“..这应该是一个单独的主题吗?”依靠。触发Clip 启动事件非常简单。这是这样做的example。看看你是怎么做的,如果你不能让它工作,那就开始一个新问题。 “谢谢你!”感谢在标记答案正确和投票方面得到了很好的表达。 ;)
    【解决方案3】:

    虽然我大量借鉴了@Andrew 的代码,但我确实不得不在这里和那里进行一些调整。以下是我的解决方案的演示,除了一个示例 .wav 文件之外,它是完整的。

    // Developed in Eclipse, YMMV regarding resource location.
    import java.net.URL;
    import javax.sound.sampled.AudioInputStream;
    import javax.sound.sampled.AudioSystem;
    import javax.sound.sampled.Clip;
    
    class ClipPlayer {
    
    public static void main(String[] args) {
        // First, instantiate ourselves so we can call demoSam which
        // needs to be able to do a wait().
        ClipPlayer cp = new ClipPlayer();
        // Now run the actual demo
        cp.demoSam();
    }
    
    private void demoSam() {
    
        /**
         * Construct a Sam, capable of playing the "Chook.wav", a 0.1 sec sound.
         * NOTE: it's very tricky debugging an incorrectly-located
         * resource file, and I'm unable to give a general rule
         * here.  But in this example, Chook.wav is expected to be in the same
         * directory as the .class file, and there is no surrounding
         * package (i.e. we're taking the default package name).  If you
         * are using a package, you may have to write "myPackage/Chook.wav"
         * instead.
         */
    
        Sam sam;
        try {
            sam = new Sam("Chook.wav"); // or whatever, but it has to be .wav
        }
        catch (Exception e) {
            say("Exception thrown by Sam: " + e.getMessage());
            System.exit(1); // scoot
            return; // get rid of warning about sam possib not init'd
        }
        int countDown = 20;
        do {
            say("Doing something requiring accompanying sound effect...");
            try {
                sam.playIt();
            }
            catch (Exception e) {
                say("Caught exception from playIt: " + e.getMessage());
                System.exit(1);
            }
    
            // Now wait a human-scale duration, like 1/8 second.  In
            // practice we may be processing, since the sound is playing
            // asynchronously.
    
            synchronized (this) {
                try {
                    wait(125); // wait 1/8 sec
                }
                catch (Exception e2) {
                    say("huh?");
                }
            }
        } while (--countDown > 0);
    
    }
    
    /**
     * 'Sam' is a class that implements one method, playIt(), that simply
     * plays the .wav file clip it was instantiated with.  Just using an
     * inner class here for simplicity of demo.
     */
    final class Sam {
    
        AudioInputStream ais;
        Clip             clip;
    
        /**
         * Constructor: prepare clip to be played. Do as much here as 
         * possible, to minimize the overhead of playing the clip, 
         * since I want to call the play() method 5-10 times a second.
         */
        Sam(String clipName) throws Exception {
    
            // Resource is in same directory as this source code.  
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            URL url = classLoader.getResource(clipName);
            ais = AudioSystem.getAudioInputStream(url);
            clip = AudioSystem.getClip();
            clip.open(ais);
        }
    
        /**
         * playIt(): Start the clip playing once, asynchronously, and exit. 
         */
        public void playIt() throws Exception {
            clip.setFramePosition(0);  // Must always rewind!
            clip.loop(0);
            clip.start();
        }
    }
    
    private static void say(String s) {
        System.out.println(s);
    }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-01
      • 2013-01-18
      相关资源
      最近更新 更多