1

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

如何在 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/”是绝对的,还是相对的,如果是后者,相对于哪里?

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

第一章

4

3 回答 3

1

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

它适用于任何一个。

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

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

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

不,这些com.sun类不仅没有记录,而且在下一个微版本中可能会发生变化。

..我不知道它做了什么。例如,“/path/to/sounds/”是绝对的,还是相对的,如果是后者,相对于哪里?

它相对于类路径的根。

..令人难以置信这是多么困难。

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


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

相反,请参阅我(编写 &)个人推荐的这段代码。

于 2011-06-17T17:11:47.913 回答
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));

但你的方法也应该有效。

于 2011-06-17T17:15:32.290 回答
0

尽管我大量借鉴了@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);
}
}
于 2011-06-19T22:00:10.677 回答