Bagaimana saya bisa memutar suara di Jawa?

Jawaban:

133

Saya menulis kode berikut yang berfungsi dengan baik. Tapi saya pikir ini hanya berfungsi dengan .wavformat.

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();
}
pek
sumber
7
Untuk menghindari Klip yang ditutup secara acak, LineListener diperlukan. Lihat: stackoverflow.com/questions/577724/trouble-playing-wav-in-java/…
yanchenko
3
+1 untuk solusi yang menggunakan API publik. Bukankah membuat utas baru tidak perlu (berlebihan)?
Jataro
4
Terima kasih .. Apakah itu berlebihan? Saya membuatnya menjadi utas baru sehingga saya bisa memainkan suara lagi sebelum klip pertama berakhir.
pek
4
Saya tahu clip.start () memunculkan thread baru, jadi saya cukup yakin itu tidak perlu.
Jataro
44
1) Tidak Threadperlu. 2) Untuk contoh penggunaan yang baik Clip, lihat info JavaSound. halaman . 3) Jika suatu metode membutuhkan URL(atau File) memberinya dang URL(atau File) daripada menerima Stringyang mewakili satu. (Hanya 'bee in my bonnet' pribadi.) 4) e.printStackTrace();memberikan lebih banyak informasi dengan lebih sedikit mengetik daripada System.err.println(e.getMessage());.
Andrew Thompson
18

Contoh buruk:

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); 
Greg Hurlman
sumber
13
java.sun.com/products/jdk/faq/faq-sun-packages.html Ada alternatif API publik untuk menggunakan sun.audio.
McDowell
4
@GregHurlman Bukankah matahari. * Paket dibuat agar tidak digunakan oleh kami pengembang?
Tom Brito
36
Contoh ini berasal dari artikel JavaWorld 1997. Jalan keluar dari tanggal, Anda TIDAK boleh menggunakan paket sun. *.
sproketboy
3
apakah Anda perlu menutup "dalam"?
rogerdpack
6
+1 untuk tidak menggunakan matahari. * Paket. Mereka memiliki bug aneh seperti tidak menangani file> 1MB dan tidak dapat memutar satu klip jika sebelumnya belum selesai, dll.
rogerdpack
10

Saya tidak ingin memiliki begitu banyak baris kode hanya untuk memainkan suara yang sederhana. Ini dapat bekerja jika Anda memiliki paket JavaFX (sudah termasuk dalam jdk 8 saya).

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

Perhatikan: Anda perlu menginisialisasi JavaFX . Cara cepat untuk melakukan itu, adalah memanggil konstruktor JFXPanel () sekali di aplikasi Anda:

static{
    JFXPanel fxPanel = new JFXPanel();
}
Cyril Duchon-Doris
sumber
8

Untuk memainkan suara dalam java, Anda dapat merujuk ke kode berikut.

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

Untuk alasan apa pun, jawaban teratas oleh wchargin memberi saya kesalahan pointer nol ketika saya memanggil this.getClass (). GetResourceAsStream ().

Apa yang berhasil bagi saya adalah sebagai berikut:

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

Dan saya akan memainkan suaranya dengan:

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

sounds / effects / sheep1.wav terletak di direktori dasar proyek saya di Eclipse (jadi tidak di dalam folder src).

Andrew Jenkins
sumber
halo Anrew, kode Anda berfungsi untuk saya, tetapi saya perhatikan bahwa membutuhkan sedikit waktu ekstra dalam eksekusi ... sekitar 1,5 detik.
getResourceAsStream()akan kembali nulljika sumber daya tidak ditemukan, atau melempar pengecualian jika nameini null- bukan kesalahan dari jawaban atas jika jalan yang diberikan tidak valid
user85421
3

Saya membuat kerangka permainan beberapa waktu lalu untuk bekerja di Android dan Desktop, bagian desktop yang menangani suara mungkin dapat digunakan sebagai inspirasi untuk apa yang Anda butuhkan.

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

Ini adalah kode untuk referensi.

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

}
hamilton.lima
sumber
Kode ini mungkin salah saat stream.reset();mengarah ke Resetting to invalid mark. Apa yang ingin Anda lakukan untuk memperbaikinya?
driima
mungkin membuat ulang aliran, lihat stackoverflow.com/questions/18573767/…
hamilton.lima
1
Saya benar-benar menyelesaikan ini dengan menggunakan raw.mark(raw.available()+1)setelah menginisialisasi rawdan kemudian di loop sementara, dan kemudian menggunakan raw.reset()bukan stream.reset(). Masalah saya sekarang adalah bahwa ketika datang untuk mengatur ulang, ada celah di antara permainan. Saya ingin mencapai lingkaran berkelanjutan seperti yang Anda dapatkan Clip. Saya tidak menggunakan Clipkarena memanipulasi kontrol seperti MASTER_GAIN mengalami keterlambatan ~ 500 ms. Ini mungkin pertanyaan tersendiri yang akan saya tanyakan nanti.
driima
Bukan do { ... } while?
Andreas
2

Ada alternatif untuk mengimpor file suara yang berfungsi baik di applet maupun aplikasi: konversikan file audio menjadi file .java dan cukup gunakan dalam kode Anda.

Saya telah mengembangkan alat yang membuat proses ini jauh lebih mudah. Ini menyederhanakan Java Sound API sedikit.

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

Stephen Ware
sumber
Saya menggunakan sistem Anda untuk membuat kelas dari file wav, Namun, Ketika saya melakukan my_wave.play (); itu tidak memutar audio .. Apakah ada sistem audio yang perlu saya inisialisasi atau sesuatu?
Nathan F.
ini akan sangat keren jika itu benar-benar berfungsi. Saat menjalankan play (), get Audio Line gagal (kecuali "java.lang.IllegalArgumentException: Tidak ada antarmuka pencocokan baris, format pendukung SourceDataLine, PCM_UNSIGNED 44100.0 Hz, 16 bit, stereo, 4 byte / bingkai, little-endian didukung." terlempar). Sedih.
phil294
2

Saya terkejut tidak ada yang menyarankan menggunakan Applet. Gunakan Applet . Anda harus menyediakan file audio bip sebagai wavfile, tetapi itu berfungsi. Saya mencoba ini di 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
Nav
sumber
2
Appletsudah tidak digunakan lagi pada Java 9.
Fre_d
0

Utas ini agak lama tetapi saya telah menentukan opsi yang bisa berguna.

Alih-alih menggunakan AudioStreamperpustakaan Java Anda bisa menggunakan program eksternal seperti Windows Media Player atau VLC dan menjalankannya dengan perintah konsol melalui 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();
}

Ini juga akan membuat proses terpisah yang bisa dikontrol programnya.

p.destroy();

Tentu saja ini akan memakan waktu lebih lama untuk dieksekusi daripada menggunakan perpustakaan internal tetapi mungkin ada program yang dapat memulai lebih cepat dan mungkin tanpa GUI yang diberikan perintah konsol tertentu.

Jika waktu bukan dari esensi maka ini berguna.

Galen Nare
sumber
4
Meskipun saya pikir ini adalah solusi yang buruk secara objektif (dalam hal keandalan, efisiensi, dan metrik lain semacam itu), itu setidaknya yang menarik yang tidak akan saya pikirkan sebelumnya!
Max von Hippel