Java 应用程序如何播放声音片段?

发布于 2024-11-16 05:55:23 字数 936 浏览 3 评论 0原文

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

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

我现在花了很多时间尝试播放简单的音效。令人难以置信的是,这是多么困难。我希望上面的代码能够工作。感谢您的任何帮助。

The following is a link to the most likely explanation I've seen, but I still have questions.

How can I play sound in Java?

I'll quote the code here:

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. Does this work in an application, as opposed to an Applet?
  2. The method Main.class.getResourceAsStream() seems to require import com.sun.tools.apt.Main; but I cannot find documentation for that, and I don't know what it does. For instance, is "/path/to/sounds/" absolute, or relative, and if the latter, relative to where?

I've spent many hours now trying to play a simple sound effect. It's unbelievable how difficult it is. I hope that the above code can be made to work. Thanks for any help.

Chap

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

凉城已无爱 2024-11-23 05:55:23
  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));

但您的方法也应该有效。

  1. That should work in an application.
  2. That line of code is most likely referencing the class that method is in. So that method was originally in class Main, if you put the method in class FooBar, you should change it to FooBar.class.getResourceAsStream().
  3. It is a relative path. It will look for the resource outside of every package. Example: Let's say the class that's running this piece of code is located at C:\Users\Jeffrey\bin\foo\bar\SoundPlayer.class and the class is in package foo.bar. This means that the ClassLoader will look for the resources inside the C:\Users\Jeffrey\bin\ folder. (In your case, it will look for the resource at C:\Users\Jeffrey\bin\path\to\sounds\ + url)

I always loaded sounds like this:

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

but your method should also work.

本宫微胖 2024-11-23 05:55:23

这是否可以在应用程序(而不是 Applet)中工作?

它适用于任何一种。

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

你从哪里得到这个想法的?我已经做了很多合理的例子,但从未听说过您不应该使用的类。

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

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

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

它相对于类路径的根。

..这有多困难,令人难以置信。

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


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

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

Does this work in an application, as opposed to an Applet?

It works in either.

The method Main.class.getResourceAsStream() seems to require import com.sun.tools.apt.Main;

Where did you get that idea? I've made plenty of sound examples, and never heard of that class that you should not be using.

..but I cannot find documentation for that,..

No, the com.sun classes are not only undocumented, but might change in the next micro-version.

..and I don't know what it does. For instance, is "/path/to/sounds/" absolute, or relative, and if the latter, relative to where?

It is relative to the root of the class-path.

..It's unbelievable how difficult it is.

Media handling in general, is tricky.


BTW - I'm not much impressed with the code on the linked thread. The Thread wrapper is unnecessary, as mentioned in several of the comments, even for playing multiple Clip instances simultaneously.

Instead see this code that I (wrote &) personally recommend.

ぃ弥猫深巷。 2024-11-23 05:55:23

尽管我大量借鉴了 @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);
}
}

Although I drew heavily from @Andrew's code, I did have to make some tweaks here and there. The following is a demo of my solution, complete except for a sample .wav file.

// 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);
}
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文