2014-04-02 100 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播放器,當我想在完成時重複播放同一首歌曲時,這種方法非常相似。