2014-04-02 102 views
0

我在网上发现了一个工作Sound类,我正在使用它在我正在制作的游戏中播放声音。然而,我想继续播放这个文件,所以我决定只使用一个Swing Timer并且它可以工作,唯一的问题是我的游戏窗口冻结,甚至不会让你在不使用任务管理器的情况下退出。线程循环冻结游戏窗口

你可以看看它并告诉我我哪里出了错?顺便说一句main只是我的Sound类的对象变量,而maindelay就是我的int延迟。

public static void loopSound(){ 
    Timer maintime = new Timer(maindelay, new ActionListener(){ 

     public void actionPerformed(ActionEvent e){ 
      main.run(); 
     } 
    }); 
    maintime.start(); 
} 

Sound类,我发现:

public class Sound extends Thread { 

    private String filename; 

    private Position curPosition; 

    private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb 

    enum Position { 
     LEFT, RIGHT, NORMAL 
    }; 

    public Sound(String wavfile) { 
     filename = wavfile; 
     curPosition = Position.NORMAL; 
    } 

    public Sound(String wavfile, Position p) { 
     filename = wavfile; 
     curPosition = p; 
    } 

    public void run() { 

     File soundFile = new File(filename); 
     if (!soundFile.exists()) { 
      System.err.println("Wave file not found: " + filename); 
      return; 
     } 

     AudioInputStream audioInputStream = null; 
     try { 
      audioInputStream = AudioSystem.getAudioInputStream(soundFile); 
     } catch (UnsupportedAudioFileException e1) { 
      e1.printStackTrace(); 
      return; 
     } catch (IOException e1) { 
      e1.printStackTrace(); 
      return; 
     } 

     AudioFormat format = audioInputStream.getFormat(); 
     SourceDataLine auline = null; 
     DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); 

     try { 
      auline = (SourceDataLine) AudioSystem.getLine(info); 
      auline.open(format); 
     } catch (LineUnavailableException e) { 
      e.printStackTrace(); 
      return; 
     } catch (Exception e) { 
      e.printStackTrace(); 
      return; 
     } 

     if (auline.isControlSupported(FloatControl.Type.PAN)) { 
      FloatControl pan = (FloatControl) auline 
        .getControl(FloatControl.Type.PAN); 
      if (curPosition == Position.RIGHT) 
       pan.setValue(1.0f); 
      else if (curPosition == Position.LEFT) 
       pan.setValue(-1.0f); 
     } 

     auline.start(); 
     int nBytesRead = 0; 
     byte[] abData = new byte[EXTERNAL_BUFFER_SIZE]; 

     try { 
      while (nBytesRead != -1) { 
       nBytesRead = audioInputStream.read(abData, 0, abData.length); 
       if (nBytesRead >= 0) 
        auline.write(abData, 0, nBytesRead); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
      return; 
     } finally { 
      auline.drain(); 
      auline.close(); 
     } 

    } 
} 
+0

什么是maindelay? –

+0

这是一个int,我发起它等于1000 – user3471511

回答

0

我最后再猜测的声音超过1秒。您传递给Timer的整数以毫秒为单位。在我看来,你创造的声音比他们可以播放的更快,这会堵塞你的应用程序并阻止UI(因此“冻结”)。

我认为使用计时器是重复播放声音的错误方法。您需要修改声音文件。

// as Sound 
class RepeatSound { 
    ... 
    public void run() { 
     // modify this condition to something meaningful 
     while (true) { 
      // as original Sound.run() in here 
      ... 
     } 
    } 
    ... 
} 

并致电RepeatSound.start()。您需要必须更改while(true)退出您的应用程序,例如。在窗口关闭后使其while (myFrame.visible())停止播放。

0

一些提示来解决问题:

  • Swing Timer API指出,一个计时器会默认重复通知它的听众。这意味着你有一个由这个计时器引起的无限循环。见isRepeats() javadoc。
  • 因此,在每次迭代中,创建播放歌曲的新线程根本不正确。
  • 但是,由于您在摆动组件和播放的歌曲之间没有任何交互,所以实际上并不需要Swing定时器。只需在与EDT(Event Dispatch Thread)不同的线程中运行你的Song类,它应该是好的。

不过,我想连续播放文件...

至于我可以SourceDataLine接口(API)从Line接口,它允许您添加LineListener s到听LineEvent延伸见秒。在说完所有这些之后,您可以添加一个侦听器,以便在停止时重新启动数据线。我会说这看起来应该是这样的:

public class Sound extends Thread { 

    ... 

    public void run() 
     ... 
     auline.addLineListener(new LineListener() { 
      @Override 
      public void update(LineEvent e) { 
       if(e.getType() == LineEvent.Type.STOP && e.getLine().isOpen()) { 
        e.getLine().start(); 
       } 
      } 
     }); 
     auline.start(); 
     ... 
    } 
    ... 
} 

注:我真的不有足够的时间与此API来播放,所以它的给你测试,如果它的工作原理。不过,我使用Java Mobile Media API为我的手机制作了MP3播放器,当我想在完成时重复播放同一首歌曲时,这种方法非常相似。