如何用Java播放声音?


Answers:


137

我写了下面的代码,效果很好。但我认为它仅适用于.wav格式。

public static synchronized void playSound(final String url) {
  new Thread(new Runnable() {
  // The wrapper thread is unnecessary, unless it blocks on the
  // Clip finishing; see comments.
    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();
}

7
为了避免Clip在随机时间关闭,需要使用LineListener。看看:stackoverflow.com/questions/577724/trouble-playing-wav-in-java / ...
yanchenko

3
+1表示使用公共API的解决方案。创建新线程不是不必要的吗(冗余)?
加塔罗,2009年

4
谢谢..是否多余?我进入了一个新线程,以便可以在第一个剪辑结束之前再次播放声音。
佩克

4
我知道clip.start()会产生一个新线程,所以我很确定这是不必要的。
雅太郎

45
1)Thread不必要。2)有关使用的一个很好的示例Clip,请参阅JavaSound信息。页面。3)如果一个方法需要一个URL(或File),则给它一个当当URL(或File),而不是接受String表示一个的。(仅是个人的“我的帽子里的蜜蜂”。)4)e.printStackTrace();与相比,使用更少的输入即可提供更多的信息System.err.println(e.getMessage());
安德鲁·汤普森

18

一个不好的例子:

import  sun.audio.*;    //import the sun.audio package
import  java.io.*;

//** add this into your application code as appropriate
// Open an input stream  to the audio file.
InputStream in = new FileInputStream(Filename);

// Create an AudioStream object from the input stream.
AudioStream as = new AudioStream(in);         

// Use the static class member "player" from class AudioPlayer to play
// clip.
AudioPlayer.player.start(as);            

// Similarly, to stop the audio.
AudioPlayer.player.stop(as); 

13
java.sun.com/products/jdk/faq/faq-sun-packages.html有一些公共的API可以替代使用sun.audio。
McDowell 2009年

4
@GregHurlman sun。*软件包不被美国开发人员所使用吗?
汤姆·布里托

36
该示例来自1997年JavaWorld的一篇文章。过时了,您不应该使用sun。*软件包。
sproketboy 2010年

3
您是否需要关闭“中”?
rogerdpack 2010年

6
+1(表示使用sun。*软件包)。他们的莫名其妙的错误如不处理文件> 1MB,不能够起到一个剪辑如果先前尚未结束,等等
rogerdpack

10

我不想有那么多行代码只是为了播放简单的声音。如果您具有JavaFX软件包(已经包含在我的jdk 8中),则可以使用此方法。

private static void playSound(String sound){
    // cl is the ClassLoader for the current class, ie. CurrentClass.class.getClassLoader();
    URL file = cl.getResource(sound);
    final Media media = new Media(file.toString());
    final MediaPlayer mediaPlayer = new MediaPlayer(media);
    mediaPlayer.play();
}

注意:您需要初始化JavaFX。一种快速的方法是在您的应用中一次调用JFXPanel()的构造函数:

static{
    JFXPanel fxPanel = new JFXPanel();
}

8

要在Java中播放声音,可以参考以下代码。

import java.io.*;
import java.net.URL;
import javax.sound.sampled.*;
import javax.swing.*;

// To play sound using Clip, the process need to be alive.
// Hence, we use a Swing application.
public class SoundClipTest extends JFrame {

   public SoundClipTest() {
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      this.setTitle("Test Sound Clip");
      this.setSize(300, 200);
      this.setVisible(true);

      try {
         // Open an audio input stream.
         URL url = this.getClass().getClassLoader().getResource("gameover.wav");
         AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
         // Get a sound clip resource.
         Clip clip = AudioSystem.getClip();
         // Open audio clip and load samples from the audio input stream.
         clip.open(audioIn);
         clip.start();
      } catch (UnsupportedAudioFileException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      } catch (LineUnavailableException e) {
         e.printStackTrace();
      }
   }

   public static void main(String[] args) {
      new SoundClipTest();
   }
}

7

无论出于何种原因,当我调用this.getClass()。getResourceAsStream()时,wchargin的最高答案是给我一个空指针错误。

对我有用的是:

void playSound(String soundFile) {
    File f = new File("./" + soundFile);
    AudioInputStream audioIn = AudioSystem.getAudioInputStream(f.toURI().toURL());  
    Clip clip = AudioSystem.getClip();
    clip.open(audioIn);
    clip.start();
}

我会用以下声音播放声音:

 playSound("sounds/effects/sheep1.wav");

sounds / effects / sheep1.wav位于Eclipse中我项目的基本目录中(因此不在src文件夹中)。


您好Anrew,您的代码对我有用,但是我注意到执行需要花费一些额外的时间...大约1.5秒。

getResourceAsStream()将返回null如果资源没有找到,或者抛出异常,如果namenull-顶端回答的不是错,如果给出的路径是无效的
user85421

3

不久前,我创建了一个游戏框架以在Android和Desktop上工作,处理声音的桌面部分可能会启发您所需的灵感。

https://github.com/hamilton-lima/jaga/blob/master/jaga%20desktop/src-desktop/com/athanazio/jaga/desktop/sound/Sound.java

这是参考代码。

package com.athanazio.jaga.desktop.sound;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

public class Sound {

    AudioInputStream in;

    AudioFormat decodedFormat;

    AudioInputStream din;

    AudioFormat baseFormat;

    SourceDataLine line;

    private boolean loop;

    private BufferedInputStream stream;

    // private ByteArrayInputStream stream;

    /**
     * recreate the stream
     * 
     */
    public void reset() {
        try {
            stream.reset();
            in = AudioSystem.getAudioInputStream(stream);
            din = AudioSystem.getAudioInputStream(decodedFormat, in);
            line = getLine(decodedFormat);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void close() {
        try {
            line.close();
            din.close();
            in.close();
        } catch (IOException e) {
        }
    }

    Sound(String filename, boolean loop) {
        this(filename);
        this.loop = loop;
    }

    Sound(String filename) {
        this.loop = false;
        try {
            InputStream raw = Object.class.getResourceAsStream(filename);
            stream = new BufferedInputStream(raw);

            // ByteArrayOutputStream out = new ByteArrayOutputStream();
            // byte[] buffer = new byte[1024];
            // int read = raw.read(buffer);
            // while( read > 0 ) {
            // out.write(buffer, 0, read);
            // read = raw.read(buffer);
            // }
            // stream = new ByteArrayInputStream(out.toByteArray());

            in = AudioSystem.getAudioInputStream(stream);
            din = null;

            if (in != null) {
                baseFormat = in.getFormat();

                decodedFormat = new AudioFormat(
                        AudioFormat.Encoding.PCM_SIGNED, baseFormat
                                .getSampleRate(), 16, baseFormat.getChannels(),
                        baseFormat.getChannels() * 2, baseFormat
                                .getSampleRate(), false);

                din = AudioSystem.getAudioInputStream(decodedFormat, in);
                line = getLine(decodedFormat);
            }
        } catch (UnsupportedAudioFileException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }
    }

    private SourceDataLine getLine(AudioFormat audioFormat)
            throws LineUnavailableException {
        SourceDataLine res = null;
        DataLine.Info info = new DataLine.Info(SourceDataLine.class,
                audioFormat);
        res = (SourceDataLine) AudioSystem.getLine(info);
        res.open(audioFormat);
        return res;
    }

    public void play() {

        try {
            boolean firstTime = true;
            while (firstTime || loop) {

                firstTime = false;
                byte[] data = new byte[4096];

                if (line != null) {

                    line.start();
                    int nBytesRead = 0;

                    while (nBytesRead != -1) {
                        nBytesRead = din.read(data, 0, data.length);
                        if (nBytesRead != -1)
                            line.write(data, 0, nBytesRead);
                    }

                    line.drain();
                    line.stop();
                    line.close();

                    reset();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

此代码可能会stream.reset();导致导致错误Resetting to invalid mark。您打算怎么做才能解决此问题?
driima


1
我实际上通过raw.mark(raw.available()+1)在初始化之后使用raw,然后在while循环中,然后使用raw.reset()代替代替来解决此问题stream.reset()。我现在的问题是,当重置时,播放之间存在间隙。我想实现与您一样的连续循环Clip。我Clip之所以没有使用,是因为诸如MASTER_GAIN之类的控件具有明显的〜500ms的延迟。这可能应该是我自己的问题,稍后我会再问。
driima

不是do { ... } while吗?
安德烈亚斯(Andreas)讨厌审查制度

2

除了导入在applet和应用程序中都可以使用的声音文件外,还有一种替代方法:将音频文件转换为.java文件,然后在代码中简单地使用它们。

我开发了一种工具,可以使此过程更加轻松。它大大简化了Java Sound API。

http://stephengware.com/projects/soundtoclass/


我使用您的系统从wav文件创建一个类,但是,当我执行my_wave.play();时,它不播放音频。.是否有需要初始化的音频系统或其他内容?..
Nathan F.

如果确实有效,这将非常酷。运行play()时,获取音频线路失败(异常“ java.lang.IllegalArgumentException:没有任何线路匹配接口SourceDataLine支持格式PCM_UNSIGNED 44100.0 Hz,16位,立体声,4字节/帧,支持小端)。”抛出)。伤心。
phil294 2014年

2

我很惊讶没有人建议使用Applet。使用 Applet。您必须将蜂鸣声音频文件作为wav文件提供,但是它可以工作。我在Ubuntu上尝试过:

package javaapplication2;

import java.applet.Applet;
import java.applet.AudioClip;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

public class JavaApplication2 {

    public static void main(String[] args) throws MalformedURLException {
        File file = new File("/path/to/your/sounds/beep3.wav");
        URL url = null;
        if (file.canRead()) {url = file.toURI().toURL();}
        System.out.println(url);
        AudioClip clip = Applet.newAudioClip(url);
        clip.play();
        System.out.println("should've played by now");
    }
}
//beep3.wav was available from: http://www.pacdv.com/sounds/interface_sound_effects/beep-3.wav

2
Applet从Java 9开始不推荐使用
。– Fre_d

0

这个线程很旧,但是我确定了一个可能有用的选项。

AudioStream可以使用Windows Media Player或VLC之类的外部程序来代替Java库,并通过Java使用控制台命令运行它。

String command = "\"C:/Program Files (x86)/Windows Media Player/wmplayer.exe\" \"C:/song.mp3\"";
try {
    Process p = Runtime.getRuntime().exec(command);
catch (IOException e) {
    e.printStackTrace();
}

这还将创建一个单独的过程,该过程可以通过该程序进行控制。

p.destroy();

当然,与使用内部库相比,这将花费更多的时间来执行,但是可能有些程序可以启动得更快,并且在没有特定控制台命令的情况下可能没有GUI。

如果时间不是关键,那么这将很有用。


4
尽管我认为这是一个客观上不好的解决方案(就可靠性,效率和其他类似指标而言),但这至少是我从未想到过的有趣的解决方案!
Max von Hippel,

0

这个对我有用。简单变体

public void makeSound(){
    File lol = new File("somesound.wav");
    

    try{
        Clip clip = AudioSystem.getClip();
        clip.open(AudioSystem.getAudioInputStream(lol));
        clip.start();
    } catch (Exception e){
        e.printStackTrace();
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.