Làm cách nào để phát âm thanh trong Java?


Câu trả lời:


133

Tôi đã viết mã sau đây hoạt động tốt. Nhưng tôi nghĩ rằng nó chỉ hoạt động với .wavđịnh dạng.

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
Để tránh Clip bị tắt vào thời gian ngẫu nhiên, cần có LineListener. Có một cái nhìn: stackoverflow.com/questions/577724/trouble-playing-wav-in-java/
mẹo

3
+1 cho giải pháp sử dụng API công khai. Không tạo ra một chủ đề mới không cần thiết (dư thừa)?
Jataro

4
Thanx .. Có dư thừa không? Tôi đã biến nó thành một chủ đề mới để tôi có thể phát lại âm thanh trước khi clip đầu tiên kết thúc.
pek

4
Tôi biết clip.start () sinh ra một chủ đề mới, vì vậy tôi khá chắc chắn rằng nó không cần thiết.
Jataro

44
1) Không Threadcần thiết. 2) Để biết ví dụ hay về việc sử dụng Clip, hãy xem thông tin JavaSound. trang . 3) Nếu một phương thức yêu cầu URL(hoặc File) cung cấp cho nó một dang URL(hoặc File) thay vì chấp nhận một phương Stringthức đại diện cho một phương thức. (Chỉ là một 'con ong trong nắp ca-pô của tôi'.) 4) e.printStackTrace();cung cấp nhiều thông tin hơn với ít lần gõ hơn System.err.println(e.getMessage());.
Andrew Thompson

18

Một ví dụ tồi:

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 Có các lựa chọn thay thế API công khai để sử dụng sun.audio.
McDowell

4
@GregHurlman Không phải là mặt trời. * Gói được tạo ra không được sử dụng bởi các nhà phát triển của chúng tôi?
Tom Brito

36
Ví dụ này xuất phát từ một bài viết JavaWorld năm 1997. Cách hết hạn, Bạn KHÔNG nên sử dụng gói mặt trời. *.
sproketboy

3
Bạn có bao giờ cần phải đóng "trong"?
rogerdpack

6
+1 vì không sử dụng gói mặt trời. *. Chúng có các lỗi kỳ lạ như không xử lý tệp> 1MB và không thể phát một clip nếu trước đó chưa kết thúc, v.v.
rogerdpack

10

Tôi không muốn có quá nhiều dòng mã chỉ để phát ra một âm thanh chết tiệt đơn giản. Điều này có thể hoạt động nếu bạn có gói JavaFX (đã được bao gồm trong jdk 8 của tôi).

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

Lưu ý: Bạn cần khởi tạo JavaFX . Một cách nhanh chóng để làm điều đó, là gọi hàm tạo của JFXPanel () một lần trong ứng dụng của bạn:

static{
    JFXPanel fxPanel = new JFXPanel();
}

8

Để phát âm thanh trong java, bạn có thể tham khảo đoạn mã sau.

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

Vì bất kỳ lý do gì, câu trả lời hàng đầu của wchargein đã khiến tôi gặp lỗi con trỏ null khi tôi gọi this.getClass (). GetResourceAsStream ().

Những gì làm việc cho tôi là như sau:

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

Và tôi sẽ chơi âm thanh với:

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

âm thanh / hiệu ứng / lamb1.wav được đặt trong thư mục cơ sở của dự án của tôi trong Eclipse (vì vậy không nằm trong thư mục src).


xin chào Anrew, mã của bạn đã làm việc cho tôi, nhưng tôi nhận thấy rằng cần thêm một chút thời gian để thực hiện ... khoảng 1,5 giây.

getResourceAsStream()sẽ trở lại nullnếu tài nguyên không được tìm thấy, hoặc ném ngoại lệ nếu namenull- không phải là một lỗi của câu trả lời đầu nếu con đường cho không có giá trị
user85421

3

Tôi đã tạo ra một khung trò chơi trước đây để hoạt động trên Android và Máy tính để bàn, phần máy tính để bàn xử lý âm thanh có thể được sử dụng làm nguồn cảm hứng cho những gì bạn cần.

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

Đây là mã để tham khảo.

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

}

Mã này có thể lỗi stream.reset();dẫn đến Resetting to invalid mark. Bạn đề nghị làm gì để khắc phục điều này?
Driima

có thể tạo lại luồng, xem stackoverflow.com/questions/18573767/
trộm

1
Tôi thực sự đã giải quyết điều này bằng cách sử dụng raw.mark(raw.available()+1)sau khi khởi tạo rawvà sau đó trong vòng lặp while, và sau đó sử dụng raw.reset()thay vì stream.reset(). Vấn đề của tôi bây giờ là khi nó xuất hiện để thiết lập lại, có một khoảng cách giữa các lần phát. Tôi muốn đạt được một vòng lặp liên tục như bạn nhận được với Clip. Tôi không sử dụng Clipvì thao tác điều khiển như MASTER_GAIN có độ trễ đáng chú ý là ~ 500ms. Đây có lẽ nên là câu hỏi của riêng nó mà tôi sẽ đi xung quanh để hỏi sau.
Driima

Không phải là một do { ... } while?
Andreas

2

Có một cách khác để nhập tệp âm thanh hoạt động trong cả ứng dụng và ứng dụng: chuyển đổi tệp âm thanh thành tệp .java và chỉ cần sử dụng chúng trong mã của bạn.

Tôi đã phát triển một công cụ giúp cho quá trình này dễ dàng hơn nhiều. Nó đơn giản hóa API âm thanh Java một chút.

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


Tôi đã sử dụng hệ thống của bạn để tạo một lớp từ tệp wav, Tuy nhiên, khi tôi làm my_wave.play (); nó không phát âm thanh .. Có hệ thống âm thanh nào tôi cần khởi tạo hay gì không? ..
Nathan F.

Điều này sẽ thực sự tuyệt vời nếu nó thực sự hoạt động. Khi chạy play (), get Line Line không thành công (ngoại trừ "java.lang.IllegalArgumentException: Không hỗ trợ giao diện phù hợp với dòng SourceDataLine định dạng hỗ trợ PCM_UNSIGNED 44100.0 Hz, 16 bit, âm thanh nổi, 4 byte / khung hình, đầu cuối nhỏ được hỗ trợ." ném). Buồn.
phil294

2

Tôi ngạc nhiên không ai đề nghị sử dụng Applet. Sử dụng Applet . Bạn sẽ phải cung cấp tệp âm thanh tiếng bíp dưới dạng wavtệp nhưng nó hoạt động. Tôi đã thử điều này trên 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
Appletkhông được dùng nữa kể từ Java 9.
Fre_d

0

Chủ đề này khá cũ nhưng tôi đã xác định một tùy chọn có thể chứng minh hữu ích.

Thay vì sử dụng AudioStreamthư viện Java, bạn có thể sử dụng một chương trình bên ngoài như Windows Media Player hoặc VLC và chạy nó bằng lệnh console thông qua 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();
}

Điều này cũng sẽ tạo ra một quy trình riêng biệt có thể được điều khiển chương trình.

p.destroy();

Tất nhiên điều này sẽ mất nhiều thời gian để thực thi hơn so với sử dụng thư viện nội bộ nhưng có thể có các chương trình có thể khởi động nhanh hơn và có thể không có GUI được cung cấp một số lệnh điều khiển nhất định.

Nếu thời gian không phải là điều cốt yếu thì điều này rất hữu ích.


4
Mặc dù tôi nghĩ rằng đây là một giải pháp khách quan tồi tệ (về độ tin cậy, hiệu quả và các số liệu khác như vậy), nhưng ít nhất đó là một giải pháp thú vị mà tôi không nghĩ tới!
Max von Hippel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.