Como posso tocar som em Java?

Respostas:

133

Eu escrevi o seguinte código que funciona bem. Mas acho que só funciona com .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
fonte
7
Para evitar que o Clip seja desligado aleatoriamente, é necessário um LineListener. Dê uma olhada: stackoverflow.com/questions/577724/trouble-playing-wav-in-java/...
Yanchenko
3
+1 para uma solução que usa a API pública. Porém, a criação de um novo thread é desnecessária (redundante)?
Jataro
4
Thanx .. É redundante? Transformei em um novo tópico para poder reproduzir o som novamente antes do término do primeiro clipe.
pek 29/07/09
4
Eu sei que clip.start () gera um novo thread, por isso tenho certeza de que é desnecessário.
Jataro
44
1) O Threadé desnecessário. 2) Para um bom exemplo de uso Clip, consulte as informações do JavaSound. página . 3) Se um método requer um URL(ou File), dê a ele um dang URL(ou File) em vez de aceitar um Stringque represente um. (Apenas uma 'abelha no meu chapéu'.) 4) e.printStackTrace();fornece mais informações com menos digitação do que System.err.println(e.getMessage());.
Andrew Thompson
18

Um mau exemplo:

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
fonte
13
java.sun.com/products/jdk/faq/faq-sun-packages.html Existem alternativas públicas da API ao uso do sun.audio.
23409 McDowell
4
@GregHurlman O pacote sun. * Não foi feito para não ser usado pelos desenvolvedores?
Tom Brito
36
Este exemplo vem de um artigo do JavaWorld de 1997. Muito desatualizado, você NÃO deve usar pacotes sun. *.
Sproketboy
3
você precisa fechar "in"?
Rogerdpack
6
+1 por não usar o sol. * Pacotes. Eles têm bugs estranhos como não lidar com arquivos> 1MB e não ser capaz de jogar um clipe se o anterior não terminou ainda, etc.
rogerdpack
10

Eu não queria ter tantas linhas de código apenas para tocar um som maldito simples. Isso pode funcionar se você tiver o pacote JavaFX (já incluído no meu 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: Você precisa inicializar o JavaFX . Uma maneira rápida de fazer isso é chamar o construtor de JFXPanel () uma vez no seu aplicativo:

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

Para reproduzir som em java, você pode consultar o código a seguir.

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

Por qualquer motivo, a resposta principal do wchargin estava me dando um erro de ponteiro nulo quando eu estava chamando this.getClass (). GetResourceAsStream ().

O que funcionou para mim foi o seguinte:

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

E eu tocava o som com:

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

sounds / effects / sheep1.wav estava localizado no diretório base do meu projeto no Eclipse (portanto, não dentro da pasta src).

Andrew Jenkins
fonte
Olá Anrew, seu código funcionou para mim, mas notei que leva um pouco de tempo extra na execução ... cerca de 1,5 seg.
getResourceAsStream()retornará nullse o recurso não for encontrado ou lançará a exceção se namefor null- não é uma falha da resposta principal se o caminho especificado não for válido
user85421
3

Eu criei uma estrutura de jogo há algum tempo para trabalhar no Android e no Desktop, a parte da área de trabalho que manipula o som pode ser usada como inspiração para o que você precisa.

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

Aqui está o código para referência.

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
fonte
Esse código pode ter erro ao stream.reset();levar a Resetting to invalid mark. O que você propõe fazer para corrigir isso?
driima 10/01
talvez recrie o fluxo, consulte stackoverflow.com/questions/18573767/…
hamilton.lima
1
Na verdade, eu resolvi isso usando raw.mark(raw.available()+1)depois de inicializar rawe depois no loop while e usando em raw.reset()vez de stream.reset(). Meu problema agora é que, quando se trata de redefinir, há uma lacuna entre as jogadas. Eu quero alcançar um loop contínuo como você obtém Clip. Não estou usando Clipporque manipular controles como MASTER_GAIN tem um atraso notável de ~ 500ms. Provavelmente, essa deve ser a sua própria pergunta, que vou fazer mais tarde.
driima 10/01
Não é do { ... } while?
Andreas
2

Existe uma alternativa para importar os arquivos de som que funcionam em applets e aplicativos: converta os arquivos de áudio em arquivos .java e simplesmente use-os no seu código.

Eu desenvolvi uma ferramenta que facilita muito esse processo. Simplifica bastante a API Java Sound.

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

Stephen Ware
fonte
Eu usei seu sistema para criar uma classe a partir de um arquivo wav, no entanto, quando eu faço my_wave.play (); não reproduzir o áudio .. Existe um sistema de áudio que eu preciso para inicializar ou algo assim ..?
Nathan F.
isso seria muito legal se realmente funcionasse. Ao executar o play (), a linha de áudio get falha (exceção "java.lang.IllegalArgumentException: Nenhuma interface de correspondência de linha SourceDataLine suporta o formato PCM_UNSIGNED 44100.0 Hz, 16 bits, estéreo, 4 bytes / quadro, little-endian é suportado." jogado). Triste.
phil294
2

Estou surpreso que ninguém tenha sugerido o uso do Applet. Use Applet . Você precisará fornecer o arquivo de áudio como um wavarquivo, mas ele funciona. Eu tentei isso no 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
fonte
2
Appletfoi descontinuado a partir do Java 9.
Fre_d
0

Este tópico é bastante antigo, mas eu determinei uma opção que pode ser útil.

Em vez de usar a AudioStreambiblioteca Java , você pode usar um programa externo como o Windows Media Player ou VLC e executá-lo com um comando do console por meio do 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();
}

Isso também criará um processo separado que pode ser controlado no programa.

p.destroy();

É claro que isso levará mais tempo para ser executado do que o uso de uma biblioteca interna, mas pode haver programas que podem ser iniciados mais rapidamente e possivelmente sem uma GUI, devido a determinados comandos do console.

Se o tempo não é essencial, isso é útil.

Galen Nare
fonte
4
Embora eu ache que essa seja uma solução objetivamente ruim (em termos de confiabilidade, eficiência e outras métricas), é pelo menos uma solução interessante em que eu não pensaria!
Max von Hippel