ฉันจะเล่นเสียงใน Java ได้อย่างไร


173

ฉันต้องการเล่นไฟล์เสียงในโปรแกรมของฉัน ฉันควรมองที่ไหน


1
ลองดูที่คลาสนี้: github.com/dberm22/DBoard/blob/master/src/com/dberm22/utils/ ...... คุณสามารถเรียกมันได้ด้วย (เธรดใหม่ (ใหม่ MediaPlayer (PATHTOFILE)) start ();
dberm22

คำตอบ:


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/…
yanchenko

3
+1 สำหรับโซลูชันที่ใช้ API สาธารณะ การสร้างเธรดใหม่นั้นไม่จำเป็น (ซ้ำซ้อน) หรือไม่?
Jataro

4
ขอบคุณ .. มันซ้ำซ้อนไหม? ฉันสร้างมันเป็นเธรดใหม่เพื่อให้ฉันสามารถเล่นเสียงได้อีกครั้งก่อนที่คลิปแรกจะจบ
pek

4
ฉันรู้ว่า clip.start () วางไข่เธรดใหม่ดังนั้นฉันค่อนข้างมั่นใจว่าไม่จำเป็น
Jataro

44
1) Threadไม่จำเป็น 2) เพื่อเป็นตัวอย่างที่ดีในการใช้Clipงานโปรดดูข้อมูล JavaSound หน้า 3) หากวิธีการนั้นต้องการURL(หรือFile) ให้มันเป็น Dang URL(หรือFile) แทนที่จะยอมรับวิธีStringนั้นแทน (เพียงแค่ 'ผึ้งในฝากระโปรงของฉันส่วนบุคคล.) 4) ให้ข้อมูลเพิ่มเติมกับการพิมพ์น้อยกว่าe.printStackTrace(); System.err.println(e.getMessage());
Andrew Thompson

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 สาธารณะสำหรับการใช้ sun.audio
McDowell

4
@GregHurlman ไม่ได้เป็นอาทิตย์ * แพคเกจที่สร้างขึ้นเพื่อไม่ให้ผู้พัฒนาของเราใช้?
Tom Brito

36
ตัวอย่างนี้มาจากบทความ 1997 JavaWorld ล้าสมัยคุณไม่ควรใช้ครีมกันแดด * แพ็คเกจ
sproketboy

3
คุณจำเป็นต้องปิด "ใน" หรือไม่?
rogerdpack

6
+1 สำหรับการไม่ใช้ดวงอาทิตย์ * แพ็คเกจ พวกเขามีข้อบกพร่องแปลกเหมือนไม่ได้จัดการกับไฟล์> 1MB และไม่สามารถที่จะเล่นเป็นหนึ่งในคลิปถ้าก่อนหน้านี้ได้ยังไม่เสร็จ ฯลฯ
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

สำหรับการเล่นเสียงในภาษาจาวาคุณสามารถดูรหัสต่อไปนี้

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

sounds / effects / sheep1.wav ตั้งอยู่ในไดเรกทอรีฐานของโครงการของฉันใน Eclipse (ดังนั้นไม่ควรอยู่ในโฟลเดอร์ src)


สวัสดี Anrew รหัสของคุณใช้งานได้สำหรับฉัน แต่ฉันสังเกตว่าต้องใช้เวลาเล็กน้อยในการดำเนินการ ... ประมาณ 1,5 วินาที

getResourceAsStream()จะกลับมาnullหากไม่พบทรัพยากรหรือโยนข้อยกเว้นถ้าnameเป็นnull- ไม่ใช่ความผิดของคำตอบสูงสุดหากเส้นทางที่กำหนดไม่ถูกต้อง
user85421

3

ฉันสร้างกรอบเกมขึ้นเมื่อไม่นานมานี้เพื่อทำงานบน Android และเดสก์ท็อปส่วนเดสก์ท็อปที่จัดการกับเสียงอาจใช้เป็นแรงบันดาลใจในสิ่งที่คุณต้องการ

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)หลังจาก initialising rawและจากนั้นในขณะที่ห่วงแล้วใช้แทนraw.reset() stream.reset()ปัญหาของฉันตอนนี้คือเมื่อมันมาถึงการตั้งค่าใหม่มีช่องว่างระหว่างการเล่น Clipฉันต้องการที่จะประสบความสำเร็จในวงอย่างต่อเนื่องเช่นที่คุณได้รับ ฉันไม่ได้ใช้Clipเพราะการควบคุมการควบคุมเช่น MASTER_GAIN มีความล่าช้าอย่างเห็นได้ชัด ~ 500ms นี่อาจเป็นคำถามของตัวเองที่ฉันจะถามต่อไป
driima

ไม่ใช่do { ... } whileหรือ
Andreas

2

มีทางเลือกอื่นในการนำเข้าไฟล์เสียงที่ใช้งานได้ทั้งในแอพเพล็ตและแอพพลิเคชั่น: แปลงไฟล์เสียงเป็นไฟล์. java และใช้ในรหัสของคุณ

ฉันได้พัฒนาเครื่องมือที่ทำให้กระบวนการนี้ง่ายขึ้นมาก มันทำให้ Java Sound API ง่ายขึ้นเล็กน้อย

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


ฉันใช้ระบบของคุณเพื่อสร้างคลาสจากไฟล์ wav อย่างไรก็ตามเมื่อฉันทำ my_wave.play (); มันไม่เล่นเสียง .. มีระบบเสียงที่ฉันต้องเริ่มต้นหรืออะไรนะ?
นาธานเอฟ

มันจะเจ๋งจริงๆถ้ามันใช้งานได้จริง เมื่อเรียกใช้ play () การรับสายสัญญาณเสียงล้มเหลว (ยกเว้น "java.lang.IllegalArgumentException: ไม่มีส่วนต่อประสานที่ตรงกับบรรทัด SourceDataLine รองรับรูปแบบ PCM_UNSIGNED 44100.0 Hz, 16 บิต, สเตอริโอ, 4 ไบต์ / เฟรม, เอนด์ - เอนเดรียไม่สนับสนุน" โยน) เสียใจ
phil294

2

ฉันประหลาดใจที่ไม่มีใครแนะนำให้ใช้แอปเพล็ต ใช้ 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();

แน่นอนว่าการดำเนินการจะใช้เวลานานกว่าการใช้ไลบรารีภายใน แต่อาจมีโปรแกรมที่สามารถเริ่มทำงานได้เร็วขึ้นและอาจไม่มี GUI ที่ให้คำสั่งคอนโซลบางอย่าง

หากเวลาไม่เป็นสาระสำคัญนี่จะเป็นประโยชน์


4
แม้ว่าฉันคิดว่านี่เป็นวิธีการแก้ปัญหาที่ไม่ดีนัก (ในแง่ของความน่าเชื่อถือประสิทธิภาพและตัวชี้วัดอื่น ๆ ) แต่อย่างน้อยก็น่าสนใจอย่างหนึ่งที่ฉันไม่คิดอย่างอื่น!
Max von Hippel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.