Comment puis-je lire du son en Java?

Réponses:

133

J'ai écrit le code suivant qui fonctionne très bien. Mais je pense que cela ne fonctionne qu'avec le .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
la source
7
Pour éviter que Clip ne soit arrêté à un moment aléatoire, un LineListener est requis. Jetez un œil: stackoverflow.com/questions/577724/trouble-playing-wav-in-java/…
yanchenko
3
+1 pour une solution utilisant l'API publique. La création d'un nouveau thread n'est-elle pas inutile (redondante) cependant?
Jataro
4
Merci .. Est-ce redondant? J'en ai fait un nouveau fil pour pouvoir jouer à nouveau le son avant la fin du premier clip.
pek le
4
Je sais que clip.start () génère un nouveau thread, donc je suis presque sûr que ce n'est pas nécessaire.
Jataro
44
1) Le Threadn'est pas nécessaire. 2) Pour un bon exemple d'utilisation Clip, consultez les informations JavaSound. page . 3) Si une méthode nécessite un URL(ou File), donnez-lui un dang URL(ou File) plutôt que d'accepter un Stringqui en représente un. (Juste une «abeille personnelle dans mon bonnet».) 4) e.printStackTrace();fournit plus d'informations avec moins de frappe que System.err.println(e.getMessage());.
Andrew Thompson
18

Un mauvais exemple:

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
la source
13
java.sun.com/products/jdk/faq/faq-sun-packages.html Il existe des alternatives API publiques à l'utilisation de sun.audio.
McDowell
4
@GregHurlman Le paquet sun. * N'est-il pas fait pour ne pas être utilisé par les développeurs?
Tom Brito
36
Cet exemple provient d'un article de 1997 sur JavaWorld. Très obsolète, vous ne devez PAS utiliser les packages sun. *.
sproketboy
3
avez-vous déjà besoin de fermer "in"?
rogerdpack
6
+1 pour ne pas utiliser le soleil. * Packages. Ils ont des bugs étranges comme ne pas gérer les fichiers> 1 Mo et ne pas pouvoir lire un clip si le précédent n'est pas encore terminé, etc.
rogerdpack
10

Je ne voulais pas avoir autant de lignes de code juste pour jouer un simple son. Cela peut fonctionner si vous avez le package JavaFX (déjà inclus dans mon 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();
}

Remarque: vous devez initialiser JavaFX . Un moyen rapide de le faire est d'appeler le constructeur de JFXPanel () une fois dans votre application:

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

Pour jouer du son en java, vous pouvez vous référer au code suivant.

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
la source
7

Pour une raison quelconque, la réponse principale de wchargin me donnait une erreur de pointeur nul lorsque j'appelais this.getClass (). GetResourceAsStream ().

Ce qui a fonctionné pour moi était le suivant:

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

Et je jouerais le son avec:

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

sons / effets / mouton1.wav se trouvait dans le répertoire de base de mon projet dans Eclipse (donc pas dans le dossier src).

Andrew Jenkins
la source
bonjour Anrew, votre code a fonctionné pour moi, mais j'ai remarqué que l'exécution prend un peu plus de temps ... environ 1,5 sec.
getResourceAsStream()sera de retour nullsi la ressource ne se trouve pas, ou jeter l'exception si nameest null- pas un défaut de réponse supérieure si le chemin donné est pas valide
user85421
3

J'ai créé il y a quelque temps un framework de jeu pour travailler sur Android et Desktop, la partie bureau qui gère le son peut peut-être être utilisée comme source d'inspiration pour ce dont vous avez besoin.

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

Voici le code pour référence.

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
la source
Ce code peut stream.reset();entraîner une erreur en menant à Resetting to invalid mark. Que proposez-vous de faire pour résoudre ce problème?
driima
peut-être recréer le flux, voir stackoverflow.com/questions/18573767/…
hamilton.lima
1
En fait, j'ai résolu ce problème en utilisant raw.mark(raw.available()+1)après l'initialisation raw, puis dans la boucle while, puis en utilisant à la raw.reset()place de stream.reset(). Mon problème maintenant est que lorsqu'il s'agit de réinitialiser, il y a un écart entre les jeux. Je veux réaliser une boucle continue comme vous le faites Clip. Je ne l'utilise pas Clipcar la manipulation de contrôles tels que MASTER_GAIN a un retard notable d'environ 500 ms. Cela devrait probablement être sa propre question que je poserai plus tard.
driima
Pas un do { ... } while?
Andreas le
2

Il existe une alternative à l'importation des fichiers audio qui fonctionne à la fois dans les applets et les applications: convertissez les fichiers audio en fichiers .java et utilisez-les simplement dans votre code.

J'ai développé un outil qui rend ce processus beaucoup plus facile. Cela simplifie un peu l'API Java Sound.

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

Stephen Ware
la source
J'ai utilisé votre système pour créer une classe à partir d'un fichier wav, cependant, quand je fais my_wave.play (); il ne lit pas l'audio .. Y a-t-il un système audio que j'ai besoin d'initialiser ou quelque chose? ..
Nathan F.
ce serait vraiment cool si cela fonctionnait réellement. Lors de l'exécution de play (), l'obtention de la ligne audio échoue (exception "java.lang.IllegalArgumentException: Aucune interface de correspondance de ligne SourceDataLine prenant en charge le format PCM_UNSIGNED 44100,0 Hz, 16 bits, stéréo, 4 octets / image, petit-boutiste est pris en charge." N'est pas jeté). Triste.
phil294
2

Je suis surpris que personne n'ait suggéré d'utiliser Applet. Utilisez Applet . Vous devrez fournir le fichier audio du bip sous forme de wavfichier, mais cela fonctionne. J'ai essayé ceci sur 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
la source
2
Appletest obsolète à partir de Java 9.
Fre_d
0

Ce fil est assez ancien mais j'ai déterminé une option qui pourrait s'avérer utile.

Au lieu d'utiliser la AudioStreambibliothèque Java , vous pouvez utiliser un programme externe comme Windows Media Player ou VLC et l'exécuter avec une commande de console via 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();
}

Cela créera également un processus distinct qui peut être contrôlé par le programme.

p.destroy();

Bien sûr, cela prendra plus de temps à s'exécuter que d'utiliser une bibliothèque interne, mais il peut y avoir des programmes qui peuvent démarrer plus rapidement et éventuellement sans interface graphique étant donné certaines commandes de la console.

Si le temps presse, c'est utile.

Galen Nare
la source
4
Bien que je pense que c'est une solution objectivement mauvaise (en termes de fiabilité, d'efficacité et d'autres mesures similaires), c'est au moins une solution intéressante à laquelle je n'aurais pas pensé autrement!
Max von Hippel