0

私はJavaでカードゲームをしています。カードの上にマウスを置くたびに効果音を鳴らしたい。しかし同時に、カードは「ポップアップ」します。

ただし、run()メソッドで実装しようとすると、動作が遅くなります。つまり、カードが音が出ない場合ほど速くポップアップしません。

run(int effect)したがって、andという別のメソッドを作成しまし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();

 }
}

アイデアは、.wavファイルがプリロードされたクラスに2つのSourceDataLine属性を持つことです。

問題は、わずかな遅れがあることです

4

3 に答える 3

1

本当に読みにくいので、私はあなたのコードを徹底的に調べていません。あなたがすべき

  • 「コードサンプル」ボタンを使用して
  • コードを例に減らします。この例には、問題を理解するために必要な最小限のコードのみが含まれています。

しかし、私が理解していることから、あなたのアプローチは必要以上に複雑です。こちらをご覧ください: Javaのより高度なオーディオコントロール

それはあなたのすべての問題を説明しているわけではありませんが、すでにあなたのコードをかなり減らすはずです。また、このコードははるかに高速に動作するはずです。したがって、マルチスレッドで作業しない場合でも、ラグの問題はそのように解消される可能性があります。

于 2010-11-08T16:45:56.817 に答える
1

あなたのクラスは、組み込みClipクラスの機能を複製しているようです。代わりに標準バージョンの使用を検討してください。

チュートリアル:

于 2011-05-20T12:31:45.960 に答える
0

SoundEFfectsクラスにThreadを拡張させることで解決しました

次に、メインのJavaクラスのSoundEffectsクラスを使用して新しいスレッドを作成し、実行します。

したがって、マウスオーバーするたびに、スレッドが実行されます。

誰かが問題を理解しようとして時間を費やした場合は申し訳ありません。ありがとう!

于 2010-11-08T14:06:37.833 に答える