Wie kann ich Sound in Java abspielen?

Antworten:

133

Ich habe den folgenden Code geschrieben, der gut funktioniert. Aber ich denke, es funktioniert nur mit .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
quelle
7
Um zu vermeiden, dass der Clip zufällig heruntergefahren wird, ist ein LineListener erforderlich. Schauen Sie mal
rein
3
+1 für eine Lösung, die die öffentliche API verwendet. Ist das Erstellen eines neuen Threads nicht unnötig (redundant)?
Jataro
4
Danke .. Ist es überflüssig? Ich habe es zu einem neuen Thread gemacht, damit ich den Sound wieder abspielen kann, bevor der erste Clip endet.
Pek
4
Ich weiß, dass clip.start () einen neuen Thread erzeugt, daher bin ich mir ziemlich sicher, dass dies nicht erforderlich ist.
Jataro
44
1) Das Threadist unnötig. 2) Ein gutes Beispiel für die Verwendung Clipfinden Sie in den JavaSound-Informationen. Seite . 3) Wenn eine Methode ein URL(oder File) erfordert, geben Sie ihr einen Dang URL(oder File), anstatt einen zu akzeptieren String, der einen darstellt. (Nur eine persönliche 'Biene in meiner Haube'.) 4) e.printStackTrace();liefert mehr Informationen mit weniger Eingabe als System.err.println(e.getMessage());.
Andrew Thompson
18

Ein schlechtes Beispiel:

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
quelle
13
java.sun.com/products/jdk/faq/faq-sun-packages.html Es gibt öffentliche API-Alternativen zur Verwendung von sun.audio.
McDowell
4
@ GregHurlman Ist nicht sun. * Paket gemacht, um nicht von uns Entwicklern verwendet zu werden?
Tom Brito
36
Dieses Beispiel stammt aus einem JavaWorld-Artikel von 1997. Veraltet, Sie sollten KEINE sun. * -Pakete verwenden.
Sproketboy
3
Müssen Sie jemals "in" schließen?
Rogerdpack
6
+1 für nicht mit Hilfe der Sonne. * Pakete. Sie haben seltsame Fehler wie das Nicht-Behandeln von Dateien> 1 MB und das Nicht-Abspielen eines Clips, wenn der vorherige noch nicht fertig ist usw.
Rogerdpack
10

Ich wollte nicht so viele Codezeilen haben, nur um einen einfachen verdammten Sound zu spielen. Dies kann funktionieren, wenn Sie das JavaFX-Paket haben (das bereits in meinem JDK 8 enthalten ist).

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

Hinweis: Sie müssen JavaFX initialisieren . Eine schnelle Möglichkeit, dies zu tun, besteht darin, den Konstruktor von JFXPanel () einmal in Ihrer App aufzurufen:

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

Informationen zum Abspielen von Sound in Java finden Sie im folgenden Code.

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
quelle
7

Aus irgendeinem Grund gab mir die Top-Antwort von wchargin einen Nullzeigerfehler, als ich this.getClass (). GetResourceAsStream () aufrief.

Was für mich funktioniert hat, war Folgendes:

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

Und ich würde den Sound spielen mit:

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

Sounds / Effects / Schaf1.wav befand sich im Basisverzeichnis meines Projekts in Eclipse (also nicht im Ordner src).

Andrew Jenkins
quelle
Hallo Anrew, dein Code hat bei mir funktioniert, aber mir ist aufgefallen, dass die Ausführung etwas länger dauert ... ungefähr 1,5 Sekunden.
getResourceAsStream()kehrt , nullwenn die Ressource nicht gefunden wird, oder die Ausnahme auslösen , wenn nameist null- kein Fehler der Top - Antwort , wenn der angegebene Pfad ist nicht gültig
user85421
3

Ich habe vor einiger Zeit ein Spiel-Framework für Android und Desktop erstellt. Der Desktop-Teil, der den Sound verarbeitet, kann möglicherweise als Inspiration für Ihre Anforderungen verwendet werden.

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

Hier ist der Code als Referenz.

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
quelle
Dieser Code kann beim stream.reset();Führen zu fehlerhaft sein Resetting to invalid mark. Was schlagen Sie vor, um dies zu beheben?
Driima
Erstellen Sie
hamilton.lima
1
Ich habe dies tatsächlich behoben, indem ich raw.mark(raw.available()+1)nach der Initialisierung rawund dann in der while-Schleife und dann raw.reset()anstelle von verwendet habe stream.reset(). Mein Problem ist jetzt, dass es beim Zurücksetzen eine Lücke zwischen den Spielen gibt. Ich möchte eine Endlosschleife erreichen, wie Sie sie erhalten Clip. Ich benutze es nicht, Clipweil das Manipulieren von Steuerelementen wie MASTER_GAIN eine merkliche Verzögerung von ~ 500 ms hat. Dies sollte wahrscheinlich eine eigene Frage sein, die ich später stellen werde.
Driima
Nicht ein do { ... } while?
Andreas
2

Es gibt eine Alternative zum Importieren der Audiodateien, die sowohl in Applets als auch in Anwendungen funktioniert: Konvertieren Sie die Audiodateien in Java-Dateien und verwenden Sie sie einfach in Ihrem Code.

Ich habe ein Tool entwickelt, das diesen Prozess erheblich vereinfacht. Dies vereinfacht die Java Sound API erheblich.

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

Stephen Ware
quelle
Ich habe Ihr System verwendet, um eine Klasse aus einer WAV-Datei zu erstellen. Wenn ich jedoch my_wave.play () mache; Es wird kein Audio abgespielt. Gibt es ein Audiosystem, das ich initialisieren muss oder so? ..
Nathan F.
Das wäre wirklich cool, wenn es tatsächlich funktionieren würde. Beim Ausführen von play () schlägt die get Audio Line fehl (Ausnahme "java.lang.IllegalArgumentException: Keine Line Matching-Schnittstelle SourceDataLine unterstützt das Format PCM_UNSIGNED 44100.0 Hz, 16 Bit, Stereo, 4 Byte / Frame, Little Endian wird nicht unterstützt." Wird nicht unterstützt geworfen). Traurig.
Phil294
2

Ich bin überrascht, dass niemand Applet vorgeschlagen hat. Verwenden Sie Applet . Sie müssen die Signalton-Audiodatei als wavDatei angeben, aber es funktioniert. Ich habe das unter Ubuntu versucht:

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
quelle
2
Appletist ab Java 9 veraltet.
Fre_d
0

Dieser Thread ist ziemlich alt, aber ich habe eine Option festgelegt, die sich als nützlich erweisen könnte.

Anstatt die Java- AudioStreamBibliothek zu verwenden, können Sie ein externes Programm wie Windows Media Player oder VLC verwenden und es mit einem Konsolenbefehl über Java ausführen.

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

Dadurch wird auch ein separater Prozess erstellt, der vom Programm gesteuert werden kann.

p.destroy();

Die Ausführung dauert natürlich länger als die Verwendung einer internen Bibliothek, aber es kann Programme geben, die bei bestimmten Konsolenbefehlen schneller und möglicherweise ohne GUI gestartet werden können.

Wenn die Zeit nicht entscheidend ist, ist dies nützlich.

Galen Nare
quelle
4
Obwohl ich denke, dass dies eine objektiv schlechte Lösung ist (in Bezug auf Zuverlässigkeit, Effizienz und andere solche Metriken), ist es zumindest eine interessante, an die ich sonst nicht gedacht hätte!
Max von Hippel