2011-06-17 89 views
1

以下是我看到的最有可能的解釋的鏈接,但我仍然有疑問。Java應用程序如何播放聲音片段?

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. 這是否工作在一個應用程序,而不是一個小程序?
  2. Main.class.getResourceAsStream()方法似乎需要import com.sun.tools.apt.Main;但我找不到這方面的文檔,我不知道它是什麼。例如,「/ path/to/sounds /」是絕對的,還是相對的,如果是後者,相對於哪裏?

我花了好幾個小時試圖發揮簡單的音效。令人難以置信的是它有多難。我希望上面的代碼可以工作。謝謝你的幫助。

回答

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); 
} 
} 
1

這是否工作在一個應用程序,而不是一個小程序?

它可以工作。

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

你從哪裏得到這個想法?我已經做了大量的聲音例子,從來沒有聽說過你不應該使用的那個類。

..但我無法找到該文件,..

沒有,com.sun類不僅無證,但在接下來的微型版本可能會改變。

..我不知道它在做什麼。例如,「/ path/to/sounds /」是絕對的,還是相對的,如果是後者,相對於哪裏?

它是相對於類路徑的根。

..難以置信,它有多難。

媒體處理一般來說很棘手。


順便說一句 - 我對鏈接線程上的代碼印象不深。 Thread包裝是不必要的,如幾個評論中所提到的,即使是同時播放多個Clip實例也是如此。

取而代之的是我個人推薦的&的this code

+0

有趣的是:你的最後一行是'JOptionPane.showMessageDialog(null,「Close to end ..」);'。如果不存在,聲音剪輯會在程序關閉後立即停止播放。我想知道@Chap是否知道這一點。 – toto2

+0

對不起,格式不好,不知道如何實現報價塊。或者就此而言,新線路grrr。 Main.class.getResourceAsStream()方法似乎需要導入com.sun.tools.apt.Main; 你從哪裏得到這個想法?我已經做了大量的聲音例子,從來沒有聽說過你不應該使用的那個類。 是的 - 這是由NetBeans或Eclipse的「清理導入」所提出的。 – Chap

+0

@toto:不,但我很快就明白了:-) @andrew:感謝您的代碼。我想我可以將它與其他建議一起用於定位「本地」音頻文件資源。 – Chap

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:\用戶\傑弗裏\ BIN \路徑\爲\聲音\ +網址)

我總是加載的聲音是這樣的:

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

但你的方法也應該工作。

+1

關於#2,您應該確實使該方法非靜態,然後使用getClass()。 – Dave

+0

感謝您將** Main.class **部分識別爲紅色鯡魚,併爲** getResourceAsStream()**提供幫助。 – Chap