Jak mogę odtwarzać dźwięk w Javie?

Odpowiedzi:

133

Napisałem następujący kod, który działa dobrze. Ale myślę, że działa tylko z .wavformatem.

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
źródło
7
Aby uniknąć przypadkowego wyłączania klipu, wymagany jest LineListener. Zobacz: stackoverflow.com/questions/577724/trouble-playing-wav-in-java/…
yanchenko
3
+1 dla rozwiązania korzystającego z publicznego interfejsu API. Czy tworzenie nowego wątku nie jest jednak niepotrzebne (zbędne)?
Jataro
4
Dzięki… Czy to jest zbędne? Stworzyłem nowy wątek, więc mogę ponownie odtworzyć dźwięk przed zakończeniem pierwszego klipu.
pek
4
Wiem, że clip.start () tworzy nowy wątek, więc jestem prawie pewien, że jest to niepotrzebne.
Jataro
44
1) Nie Threadjest konieczne. 2) Aby Clipzapoznać się z dobrym przykładem użycia , zobacz informacje o JavaSound. stronę . 3) Jeśli metoda wymaga URL(lub File) daj jej dang URL(lub File) zamiast akceptować to, Stringco reprezentuje jeden. (Tylko osobista „pszczoła w mojej masce”.) 4) e.printStackTrace();dostarcza więcej informacji przy mniejszym wpisywaniu niż System.err.println(e.getMessage());.
Andrew Thompson,
18

Zły przykład:

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
źródło
13
java.sun.com/products/jdk/faq/faq-sun-packages.html Istnieją publiczne alternatywy API dla używania sun.audio.
McDowell
4
@GregHurlman Czy pakiet sun. * Nie jest przeznaczony do użytku przez nas, programistów?
Tom Brito
36
Ten przykład pochodzi z artykułu JavaWorld z 1997 roku. Wydaje się, że NIE WOLNO używać opakowań sun. *.
sproketboy
3
czy kiedykolwiek potrzebujesz zamknąć „w”?
rogerdpack
6
+1 za nie korzystanie z pakietów sun. *. Mają dziwne błędy, takie jak brak obsługi plików> 1 MB i niemożność odtworzenia jednego klipu, jeśli poprzedni jeszcze się nie skończył itp.
rogerdpack
10

Nie chciałem mieć tylu linijek kodu tylko po to, by odtworzyć prosty, cholerny dźwięk. To może zadziałać, jeśli masz pakiet JavaFX (już zawarty w moim 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();
}

Uwaga: Musisz zainicjować JavaFX . Szybkim sposobem na to jest wywołanie konstruktora JFXPanel () raz w aplikacji:

static{
    JFXPanel fxPanel = new JFXPanel();
}
Cyril Duchon-Doris
źródło
8

Aby odtworzyć dźwięk w Javie, możesz skorzystać z następującego kodu.

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
źródło
7

Z jakiegoś powodu górna odpowiedź wchargin dawała mi błąd wskaźnika zerowego, kiedy wywoływałem this.getClass (). GetResourceAsStream ().

U mnie zadziałało:

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

I grałbym dźwięk z:

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

sound / effects / sheep1.wav znajdował się w katalogu podstawowym mojego projektu w Eclipse (a więc nie w folderze src).

Andrew Jenkins
źródło
witaj Anrew, Twój kod działał dla mnie, ale zauważyłem, że wykonanie zajmuje trochę więcej czasu ... około 1,5 sekundy.
getResourceAsStream()zwróci, nulljeśli zasób nie zostanie znaleziony, lub wyrzuci wyjątek, jeśli tak namejest null- nie jest to błąd pierwszej odpowiedzi, jeśli podana ścieżka jest nieprawidłowa
user85421
3

Jakiś czas temu stworzyłem platformę do gier, aby pracować na urządzeniach z systemem Android i komputerach stacjonarnych. Część komputerowa obsługująca dźwięk może posłużyć jako inspiracja do tego, czego potrzebujesz.

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

Oto kod w celach informacyjnych.

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
źródło
Ten kod może powodować błąd przy stream.reset();prowadzeniu do Resetting to invalid mark. Co proponujesz zrobić, aby to naprawić?
driima
może odtworzyć strumień, patrz stackoverflow.com/questions/18573767/…
hamilton.lima
1
Naprawdę rozwiązałem to, używając raw.mark(raw.available()+1)po inicjalizacji, rawa następnie w pętli while, a następnie używając raw.reset()zamiast stream.reset(). Mój problem polega teraz na tym, że jeśli chodzi o resetowanie, między kolejnymi grami jest luka. Chcę uzyskać ciągłą pętlę, taką jak ty Clip. Nie używam, Clipponieważ manipulowanie kontrolkami, takimi jak MASTER_GAIN, ma zauważalne opóźnienie ~ 500 ms. Prawdopodobnie powinno to być własne pytanie, które zadam później.
driima
Nie do { ... } while?
Andreas
2

Istnieje alternatywa dla importowania plików dźwiękowych, która działa zarówno w apletach, jak i aplikacjach: przekonwertuj pliki audio na pliki .java i po prostu użyj ich w swoim kodzie.

Opracowałem narzędzie, które znacznie ułatwia ten proces. Znacznie upraszcza Java Sound API.

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

Stephen Ware
źródło
Użyłem twojego systemu do stworzenia klasy z pliku wav, jednak kiedy robię my_wave.play (); nie odtwarza dźwięku .. Czy jest jakiś system audio, który muszę zainicjować, czy coś? ..
Nathan F.
byłoby to naprawdę fajne, gdyby faktycznie działało. Podczas uruchamiania funkcji play () funkcja get Audio Line kończy się niepowodzeniem (wyjątek „java.lang.IllegalArgumentException: Brak dopasowania linii interfejsu SourceDataLine obsługującego format PCM_UNSIGNED 44100,0 Hz, 16 bitów, stereo, 4 bajty / ramkę, obsługa little-endian” nie jest rzucony). Smutny.
phil294,
2

Jestem zaskoczony, że nikt nie zasugerował używania Appleta. Użyj Applet . Będziesz musiał dostarczyć plik dźwiękowy jako wavplik, ale to działa. Próbowałem tego na 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
źródło
2
Appletjest przestarzałe od wersji Java 9
Fre_d
0

Ten wątek jest dość stary, ale wybrałem opcję, która może się okazać przydatna.

Zamiast korzystać z AudioStreambiblioteki Java, możesz użyć zewnętrznego programu, takiego jak Windows Media Player lub VLC, i uruchomić go za pomocą polecenia konsoli za pośrednictwem języka 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();
}

Stworzy to również oddzielny proces, którym można sterować w programie.

p.destroy();

Oczywiście wykonanie tego zajmie więcej czasu niż użycie wewnętrznej biblioteki, ale mogą istnieć programy, które mogą uruchamiać się szybciej i być może bez GUI przy pewnych poleceniach konsoli.

Jeśli czas nie jest najważniejszy, jest to przydatne.

Galen Nare
źródło
4
Chociaż uważam, że jest to obiektywnie złe rozwiązanie (pod względem niezawodności, wydajności i innych tego typu wskaźników), jest przynajmniej interesujące, o którym inaczej bym nie pomyślał!
Max von Hippel