2010-11-08 83 views
0

我在java中有一個紙牌遊戲。 我想在每當我mouseOver卡時發揮音效。但與此同時,這張卡片將「彈出」。預加載SourceDataLine以減少延遲

但是,當我試圖通過run()方法來實現它時,它會變得遲緩,也就是說,卡片沒有彈出聲音那樣快。

因此我創建了另一種方法run(int effect)reloadLine(SourceDataLine line, int effect)

reloadLine(line,effect)類似於run(),只是我刪除在末尾drain()close(),並將其移動到run(int effect)

下面是我的SoundEffects.java類:

package nusMonopolyDealGUI; 

import javax.media.*; 
import java.io.File; 
import java.io.IOException; 
import java.net.URL; 
import java.util.ArrayList; 
import java.util.Scanner; 

import javax.sound.sampled.AudioFormat; 
import javax.sound.sampled.AudioInputStream; 
import javax.sound.sampled.AudioSystem; 
import javax.sound.sampled.Clip; 
import javax.sound.sampled.DataLine; 
import javax.sound.sampled.LineUnavailableException; 
import javax.sound.sampled.SourceDataLine; 
import javax.swing.JOptionPane; 

public class SoundEffects implements Runnable 
{ 
private static final int EXTERNAL_BUFFER_SIZE = 128000; 

private static int BUTTON_CLICK = 0; 
private final int MOUSE_OVER_CARD = 1; 
private final int MOUSE_CLICK_CARD = 2; 

private static int activeSoundEffect; 

private static SourceDataLine lineOverCard = null; 
private static SourceDataLine lineClickCard = null; 

private static ArrayList<SourceDataLine> sound; 
private static ArrayList<String> soundEffects; 

// CONSTRUCTOR // 
public SoundEffects(){ 
    soundEffects = new ArrayList<String>(); 
    populateSoundEffects(); 
} 

private void populateSoundEffects() { 

    try{ 
    Scanner scanner = new Scanner(new File("soundEffectsList.txt")); 
    while(scanner.hasNextLine()){ 
    String line = scanner.nextLine(); 
    soundEffects.add(line); 
    } 
    scanner.close(); 
    } 
    catch (IOException exp){ 
    System.out.println("soundList.txt not found!"); 
    } 
    //update soundEffects ArrayList with paths names of type D:\the\directory\path\... 
    for (int i = 0; i <soundEffects.size(); i ++){ 
    String path = soundEffects.get(i); 
    URL pathURL = getClass().getResource("/music/" + path + ".wav"); 
    String pathString = pathURL.toString(); 
    String properPathString = pathString.replace("file:/", ""); 
    soundEffects.set(i, properPathString); 

    } 
    //fill up the class attribute lines first for fast playback 
    reloadLine(lineOverCard, MOUSE_OVER_CARD); 
    reloadLine(lineClickCard, MOUSE_CLICK_CARD); 
} 

// METHODS // 

public void setActiveSound(int i){ 
    activeSoundEffect = i; 
} 

public void run(int effect){ 

    switch(effect){ 

    case MOUSE_OVER_CARD: 
    System.out.println("lineopen: "+ lineOverCard.isOpen()); 
    if (!lineOverCard.isActive()){ 
    lineOverCard.drain(); 
    lineOverCard.close(); 
    } 
    reloadLine(lineOverCard, MOUSE_OVER_CARD); 
    break; 

    case MOUSE_CLICK_CARD: 
    lineClickCard.drain(); 
    lineClickCard.close(); 
    reloadLine(lineClickCard, MOUSE_CLICK_CARD); 
    break; 
    } 
} 

//reload the line to reduce waiting time to load the line from buffer. 
public void reloadLine(SourceDataLine line, int effect){ 

    /* 
    * create an abstract object File to represent the directory of the .wav file. 
    */ 
    String filename = soundEffects.get(effect); 
    System.out.println("first time here"); 
    File soundFile = new File(filename); 
    System.out.println(filename); 

    /* create an AudioInputStream and give it the .wav file 
    * @exception: dump the stack trace and exit the system. 
    */ 

    AudioInputStream audioInputStream = null; 
    try 
    { 
    audioInputStream = AudioSystem.getAudioInputStream(soundFile); 
    } 
    catch (Exception e) 
    { 
    e.printStackTrace(); 
    System.exit(1); 
    } 

    /* 
    * get info on the .wav file 
    * this info is used by Java Sound to get a compatible Line 
    */ 
    AudioFormat audioFormat = audioInputStream.getFormat(); 

    /* 
    * Create a SourceDataLine (used to generally play an audio file) 
    * Create an DataLine.Info object to be passed into the SourceDataLine 
    * so it will fetch the compatible line (getLine(info)) to use. 
    */ 
    //line = null; 
    DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat); 

    try 
    { 
    line = (SourceDataLine) AudioSystem.getLine(info); 
    line.open(audioFormat); //need to open a line before inputting audio input 
    } 
    catch (LineUnavailableException e) 
    { 
    e.printStackTrace(); 
    System.exit(1); 
    } 
    catch (Exception e) 
    { 
    e.printStackTrace(); 
    System.exit(1); 
    } 

    line.start(); 

    /* 
    * Line is ready to pass audio input. 
    * We write the audio data (.wav) into the line 
    * 1) read data from audioInputStream into a BUFFER 
    * 2) write from BUFFER to Line 
    * 3) we loop 
    * audioInputStream ---> BUFFER ---> Line 
    * until we reeach the end of audioInputStream 
    * indicated by a -1 from the read method of the audioInputStream (ie. audioInputStream.read(arg0, arg1, arg2)) 
    */ 
    int nBytesRead = 0; 
    byte[] abData = new byte[EXTERNAL_BUFFER_SIZE]; 

    while (nBytesRead != -1) 
    { 
    try 
    { 
    nBytesRead = audioInputStream.read(abData, 0, abData.length); 
    } 
    catch (IOException e) 
    { 
    e.printStackTrace(); 
    } 
    if (nBytesRead >= 0) 
    { 
    int nBytesWritten = line.write(abData, 0, nBytesRead); 
    } 
    } 
} 


public void run() 
{ 

    /* 
    * create an abstract object File to represent the directory of the .wav file. 
    */ 
    String filename = soundEffects.get(activeSoundEffect); 
    File soundFile = new File(filename); 


    /* create an AudioInputStream and give it the .wav file 
    * @exception: dump the stack trace and exit the system. 
    */ 

    AudioInputStream audioInputStream = null; 
    try 
    { 
    audioInputStream = AudioSystem.getAudioInputStream(soundFile); 
    } 
    catch (Exception e) 
    { 
    e.printStackTrace(); 
    System.exit(1); 
    } 

    /* 
    * get info on the .wav file 
    * this info is used by Java Sound to get a compatible Line 
    */ 
    AudioFormat audioFormat = audioInputStream.getFormat(); 

    /* 
    * Create a SourceDataLine (used to generally play an audio file) 
    * Create an DataLine.Info object to be passed into the SourceDataLine 
    * so it will fetch the compatible line (getLine(info)) to use. 
    */ 
    SourceDataLine line = null; 
    DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat); 

    try 
    { 
    line = (SourceDataLine) AudioSystem.getLine(info); 
    line.open(audioFormat); //need to open a line before inputting audio input 
    } 
    catch (LineUnavailableException e) 
    { 
    e.printStackTrace(); 
    System.exit(1); 
    } 
    catch (Exception e) 
    { 
    e.printStackTrace(); 
    System.exit(1); 
    } 

    line.start(); 

    /* 
    * Line is ready to pass audio input. 
    * We write the audio data (.wav) into the line 
    * 1) read data from audioInputStream into a BUFFER 
    * 2) write from BUFFER to Line 
    * 3) we loop 
    * audioInputStream ---> BUFFER ---> Line 
    * until we reeach the end of audioInputStream 
    * indicated by a -1 from the read method of the audioInputStream (ie. audioInputStream.read(arg0, arg1, arg2)) 
    */ 
    int nBytesRead = 0; 
    byte[] abData = new byte[EXTERNAL_BUFFER_SIZE]; 

    while (nBytesRead != -1) 
    { 
    try 
    { 
    nBytesRead = audioInputStream.read(abData, 0, abData.length); 
    } 
    catch (IOException e) 
    { 
    e.printStackTrace(); 
    } 
    if (nBytesRead >= 0) 
    { 
    int nBytesWritten = line.write(abData, 0, nBytesRead); 
    } 
    } 

    /* 
    * after filling the line, we drain it 
    * ie. play the data in the line 
    */ 
    line.drain(); 

    //close the line after playing. 
    line.close(); 

} 
} 

的想法是有兩個的SourceDataLine屬性與.wav文件預裝類。

的問題是,有輕微的滯後

回答

0

我解決它通過讓擴展Thread

然後創建一個新的線程同時在SoundEffects類在我的主Java類SoundEFfects類,並運行它。

因此,每當它鼠標懸停,它將運行線程。

對不起,如果有人花時間試圖找出問題。謝謝!

1

我沒有徹底查看你的代碼,因爲它很難閱讀。你應該

  • 使用「代碼示例」按鈕,
  • 代碼減少一個例子,只包括瞭解問題所需的最少代碼。

但是從我的理解你的方法比需要更復雜。看看這裏: More Advanced Audio Controls in Java

它並沒有解釋你所有的問題,但應該已經相當多地減少了你的代碼。此外,這個代碼應該更快。所以,即使你不會使用多線程,你的滯後問題也可能會消失。