2010-11-08 127 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

它并没有解释你所有的问题,但应该已经相当多地减少了你的代码。此外,这个代码应该更快。所以,即使你不会使用多线程,你的滞后问题也可能会消失。