Як можна відтворювати звук на Java?


Відповіді:


133

Я написав наступний код, який прекрасно працює. Але я думаю, що це працює лише у .wavформаті.

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

7
Щоб уникнути закриття кліпу у випадковий час, потрібен LineListener. Подивіться: stackoverflow.com/questions/577724/trouble-playing-wav-in-java / ...
Янченко

3
+1 для рішення, яке використовує загальнодоступний API. Чи не створюється нова нитка непотрібною (зайвою)?
Джатаро

4
Дякую .. Це зайве? Я перетворив його на нову нитку, щоб знову відтворити звук до закінчення першого кліпу.
пек

4
Я знаю, що clip.start () породжує нову нитку, тому я майже впевнений, що це зайве.
Джатаро

44
1) Threadнепотрібне. 2) Для хорошого прикладу використання Clipдив. Інформацію про JavaSound. сторінки . 3) Якщо метод вимагає URL(або File) дати йому данг URL(або File), а не прийняти Stringте, що являє собою. (Просто особиста «бджола в моєму капелюшку».) 4) e.printStackTrace();надає більше інформації з меншим типом, ніж System.err.println(e.getMessage());.
Ендрю Томпсон

18

Поганий приклад:

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

13
java.sun.com/products/jdk/faq/faq-sun-packages.html Існують альтернативні варіанти використання API API для використання sun.audio.
McDowell

4
@GregHurlman Чи не сонце. * Пакет, який не використовуються розробниками?
Том Бріто

36
Цей приклад походить із статті JavaWorld 1997 року. Якщо ви застаріли, НЕ слід використовувати пакети. *.
sproketboy

3
вам коли-небудь потрібно закрити "в"?
rogerdpack

6
+1 за не користування пакетами. *. У них є дивні помилки, такі як не обробка файлів> 1 Мб та неможливість відтворення одного кліпу, якщо попередній ще не закінчений тощо.
rogerdpack

10

Я не хотів мати стільки рядків коду, щоб просто відтворити простий проклятий звук. Це може працювати, якщо у вас є пакет JavaFX (вже включений у мій 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();
}

Примітка. Вам потрібно ініціалізувати JavaFX . Швидкий спосіб зробити це - викликати конструктор JFXPanel () один раз у вашому додатку:

static{
    JFXPanel fxPanel = new JFXPanel();
}

8

Для відтворення звуку в Java ви можете звернутися до наступного коду.

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

7

З будь-якої причини, головна відповідь wchargin давала мені нульову помилку вказівника, коли я викликав this.getClass (). GetResourceAsStream ().

Для мене працювало таке:

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

І я грав би звук із:

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

звуки / ефекти / ov1.wav знаходився в базовому каталозі мого проекту в Eclipse (так, не в папці src).


привіт Енрю, твій код працював на мене, але я помітив, що потрібно трохи додаткового часу на виконання ... близько 1,5 сек.

getResourceAsStream()повернеться, nullякщо ресурс не знайдеться, або викине виняток, якщо nameє null- не помилка верхньої відповіді, якщо вказаний шлях недійсний
user85421

3

Я створив ігрову структуру десь тому, щоб працювати на Android і Desktop, настільна частина, яка обробляє звук, може бути використана як натхнення для того, що вам потрібно.

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

Ось код для довідок.

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

}

Цей код може помилка на stream.reset();провідних до Resetting to invalid mark. Що ви пропонуєте зробити, щоб це виправити?
driima

можливо, відтворіть потік, дивіться stackoverflow.com/questions/18573767/…
hamilton.lima

1
Я фактично вирішив це, використовуючи raw.mark(raw.available()+1)після ініціалізації, rawа потім у циклі час, а потім raw.reset()замість цього stream.reset(). Моя проблема зараз полягає в тому, що, коли йдеться про скидання, між розіграми виникає розрив. Я хочу досягти безперервного циклу, як ви отримуєте Clip. Я не використовую, Clipоскільки маніпулювання елементами керування, такими як MASTER_GAIN, має помітну затримку ~ 500 мс. Це, мабуть, має бути власне питання, яке я змушу поставити пізніше.
driima

Не є do { ... } while?
Андреас

2

Існує альтернатива імпорту звукових файлів, що працює як в аплетах, так і в додатках: перетворіть аудіофайли в .java-файли і просто використовуйте їх у своєму коді.

Я розробив інструмент, який значно полегшує цей процес. Це досить просто спрощує Java Sound API.

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


Я використовував вашу систему для створення класу з файлу wav. Однак, коли я виконую my_wave.play (); він не відтворює аудіо .. Чи є аудіосистема, яку мені потрібно ініціалізувати, чи щось? ..
Nathan F.

це було б дуже здорово, якби це насправді спрацювало. Під час запуску відтворення (), отримання аудіо рядка виходить з ладу (виняток "java.lang.IllegalArgumentException: Інтерфейс відповідності рядків SourceDataLine підтримує формат PCM_UNSIGNED 44100.0 Гц, 16 біт, стерео, 4 байти / кадр, підтримується маленький ендіан". кинутий). Сумно.
phil294

2

Я здивований, що ніхто не запропонував використовувати Applet. Використовуйте Applet . Вам доведеться надати звуковий файл звукового сигналу як wavфайл, але він працює. Я спробував це на 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

2
Appletзастаріло, як у Java 9.
Fre_d

0

Цей потік досить старий, але я визначив варіант, який може виявитися корисним.

Замість використання AudioStreamбібліотеки Java ви можете використовувати зовнішню програму, наприклад Windows Media Player або VLC, та запускати її за допомогою консольної команди через 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();
}

Це також створить окремий процес, яким можна керувати саме програмою.

p.destroy();

Звичайно, це займе більше часу, ніж використання внутрішньої бібліотеки, але можуть бути програми, які можуть запускатися швидше і, можливо, без графічного інтерфейсу, що дає певні команди консолі.

Якщо час не є сутнісним, то це корисно.


4
Хоча я думаю, що це об'єктивно погане рішення (з точки зору надійності, ефективності та інших подібних показників), воно, принаймні, цікаве, я б інакше не думав!
Макс фон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.