¿Cómo puedo reproducir sonido en Java?

Respuestas:

133

Escribí el siguiente código que funciona bien. Pero creo que solo funciona con .wavformato.

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
fuente
77
Para evitar que Clip se cierre al azar, se requiere un LineListener. Echa un vistazo: stackoverflow.com/questions/577724/trouble-playing-wav-in-java/…
yanchenko
3
+1 para una solución que utiliza la API pública. Sin embargo, ¿no es innecesario crear un nuevo hilo (redundante)?
Jataro
44
Gracias ... ¿Es redundante? Lo convertí en un nuevo hilo para poder reproducir el sonido nuevamente antes de que termine el primer clip.
pek
44
Sé que clip.start () genera un nuevo hilo, así que estoy bastante seguro de que es innecesario.
Jataro
44
1) El Threades innecesario. 2) Para ver un buen ejemplo de uso Clip, consulte la información de JavaSound. la página . 3) Si un método requiere un URL(o File) dele un dang URL(o File) en lugar de aceptar un Stringque representa uno. (Solo una 'abeja en mi capó' personal). 4) e.printStackTrace();proporciona más información con menos tipeo que System.err.println(e.getMessage());.
Andrew Thompson
18

Un mal ejemplo:

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
fuente
13
java.sun.com/products/jdk/faq/faq-sun-packages.html Existen alternativas API públicas para usar sun.audio.
McDowell el
44
@GregHurlman ¿No está hecho el paquete sun. * Para que los desarrolladores no lo usemos?
Tom Brito
36
Este ejemplo proviene de un artículo de JavaWorld de 1997. Muy desactualizado, NO debe usar paquetes sun. *.
sproketboy
3
¿alguna vez necesitas cerrar "en"?
rogerdpack
66
+1 por no usar el sol. * Paquetes. Tienen bichos raros como no manejar archivos> 1 MB y no ser capaz de reproducir un clip si el anterior no ha terminado todavía, etc
rogerdpack
10

No quería tener tantas líneas de código solo para reproducir un simple sonido. Esto puede funcionar si tiene el paquete JavaFX (ya incluido en mi 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();
}

Aviso: debe inicializar JavaFX . Una forma rápida de hacerlo es llamar al constructor de JFXPanel () una vez en su aplicación:

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

Para reproducir sonido en java, puede consultar el siguiente código.

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

Por alguna razón, la respuesta principal de wchargin me estaba dando un error de puntero nulo cuando estaba llamando this.getClass (). GetResourceAsStream ().

Lo que funcionó para mí fue lo siguiente:

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

Y tocaría el sonido con:

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

sounds / effects / sheep1.wav estaba ubicado en el directorio base de mi proyecto en Eclipse (no dentro de la carpeta src).

Andrew Jenkins
fuente
hola Anrew, tu código funcionó para mí, pero noté que toma un poco más de tiempo en ejecución ... aproximadamente 1,5 segundos.
getResourceAsStream()regresará nullsi no se encuentra el recurso, o arrojará la excepción si namees null- no es un error de respuesta superior si la ruta dada no es válida
user85421
3

Creé un marco de juego hace algún tiempo para trabajar en Android y escritorio, la parte de escritorio que maneja el sonido puede usarse como inspiración para lo que necesitas.

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

Aquí está el código de referencia.

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
fuente
Este código puede dar error al stream.reset();conducir a Resetting to invalid mark. ¿Qué propones hacer para solucionar esto?
driima
quizás recrear la transmisión, ver stackoverflow.com/questions/18573767/…
hamilton.lima
1
De hecho, resolví esto usando raw.mark(raw.available()+1)después de inicializar rawy luego en el ciclo while, y luego usando en raw.reset()lugar de stream.reset(). Mi problema ahora es que cuando se trata de reiniciar, hay una brecha entre las jugadas. Quiero lograr un ciclo continuo como el que tienes Clip. No estoy usando Clipporque manipular controles como MASTER_GAIN tiene un retraso notable de ~ 500ms. Probablemente esta debería ser su propia pregunta que voy a preguntar más tarde.
driima
No es un do { ... } while?
Andreas
2

Existe una alternativa a la importación de archivos de sonido que funciona tanto en applets como en aplicaciones: convierta los archivos de audio en archivos .java y simplemente utilícelos en su código.

He desarrollado una herramienta que hace que este proceso sea mucho más fácil. Simplifica bastante la API de Java Sound.

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

Stephen Ware
fuente
Usé su sistema para crear una clase a partir de un archivo wav. Sin embargo, cuando hago my_wave.play (); no reproduce el audio .. ¿Hay un sistema de audio que necesito inicializar o algo así? ..
Nathan F.
Esto sería realmente genial si realmente funcionara. Al ejecutar play (), la línea de audio get falla (excepción "java.lang.IllegalArgumentException: no hay interfaz de coincidencia de línea. Formato de soporte SourceDataLine PCM_UNSIGNED 44100.0 Hz, 16 bit, estéreo, 4 bytes / frame, little-endian es compatible". arrojado). Triste.
phil294
2

Me sorprende que nadie sugirió usar Applet. Uso Applet . Tendrá que proporcionar el archivo de audio de pitido como un wavarchivo, pero funciona. Intenté esto en 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
fuente
2
Appletestá en desuso desde Java 9.
Fre_d
0

Este hilo es bastante antiguo, pero he determinado una opción que podría resultar útil.

En lugar de usar la AudioStreambiblioteca Java , puede usar un programa externo como Windows Media Player o VLC y ejecutarlo con un comando de consola a través de 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();
}

Esto también creará un proceso separado que puede controlarse en el programa.

p.destroy();

Por supuesto, esto llevará más tiempo de ejecución que el uso de una biblioteca interna, pero puede haber programas que puedan iniciarse más rápido y posiblemente sin una GUI dada ciertos comandos de consola.

Si el tiempo no es esencial, entonces esto es útil.

Galen Nare
fuente
44
Aunque creo que esta es una solución objetivamente mala (en términos de confiabilidad, eficiencia y otras métricas similares), ¡es al menos una solución interesante en la que de otra manera no habría pensado!
Max von Hippel