Java Metronome Timer()不一致

时间:2014-11-28 18:54:27

标签: java timer

public void playMet(){
        int tempo = Integer.parseInt(met_speed.getText());
        tempo = tempo/60;
        int delay = tempo*1000;
        new Timer(delay, new ActionListener(){

            public void actionPerformed(ActionEvent e){
                if(Play.isSelected()){
                    System.out.println("beep");
                    playSound("Click1.wav");
                }
            }
            }).start();
    }

这是我班级的代码。它从JTextField / 60 * 1000中获取值,这是发出蜂鸣声时的毫秒值。我只使用System.out.println(“beep”)测试了它;线路并且工作正常,但是当我实际播放声音时,它会延迟或跳过或加倍声音。

playSound():

public void playSound(String filename){
        try
        {
            Clip clip = AudioSystem.getClip();
            clip.open(AudioSystem.getAudioInputStream(new File(filename)));
            clip.start();
        }
        catch (Exception exc)
        {
            exc.printStackTrace(System.out);
        }
    }

我不确定这里到底发生了什么,有什么建议吗?

编辑:

public void playMet(){
        int tempo = Integer.parseInt(met_speed.getText());
        tempo = tempo/60;
        int delay = tempo*1000;
        try
        {
            Clip clip = AudioSystem.getClip();
            clip.open(AudioSystem.getAudioInputStream(new File("Click1.wav")));
            clip.start();
        }
        catch (Exception exc)
        {
            exc.printStackTrace(System.out);
        }
        new Timer(delay, new ActionListener(){

            public void actionPerformed(ActionEvent e){
                if(Play.isSelected()){
                    System.out.println("beep");
                    clip.start();
                }
            }
            }).start();
    }

编辑2:尝试了不同的方法

    public void playMet(){
        int tempo = Integer.parseInt(met_speed.getText());
        tempo = tempo/60;
        int delay = tempo*1000; 

        if(Play.isSelected()){
        try
        {
             FileInputStream in = new FileInputStream(new File("Click1.wav"));

             AudioStream as = new AudioStream(in);
             AudioPlayer.player.start(as);

             Thread.sleep(tempo*1000);

         } catch (Exception e)
         {
             JOptionPane.showMessageDialog(null, e);
         }
        playMet();
        } 
        else
            System.out.println("not playing");
        }

不是它以正确的速度一致地播放,但它会冻结并且播放按钮无法切换。

如果我将playMet()移到最后它可以工作但只播放一次。如果我做了一段时间而不是if循环,它会像上面的代码一样冻结。

2 个答案:

答案 0 :(得分:0)

大部分工作都可以提前完成。尝试在计时器启动之前构建剪辑,只需要

clip.start();

在事件处理程序中。尝试

public void playMet(){
    int tempo = Integer.parseInt(met_speed.getText());
    tempo = tempo/60;
    int delay = tempo*1000;
    try
    {
        final Clip clip = AudioSystem.getClip();
        clip.open(AudioSystem.getAudioInputStream(new File("Click1.wav")));
        new Timer(delay, new ActionListener(){

          public void actionPerformed(ActionEvent e){
            if(Play.isSelected()){
                System.out.println("beep");
                clip.start();
            }
          }
        }).start();
    }
    catch (Exception exc)
    {
        exc.printStackTrace(System.out);
    }

}

答案 1 :(得分:0)

定时器限制你给它的速度,但是如果代码执行时间太长,那么定时器开始有点不同步导致延迟,或者有时它会加速并执行多个循环快速接班。

唯一真正的解决方案是让你的循环中的代码运行得更快,根据我获得音频剪辑和打开它的经验是非常昂贵的操作,所以尝试在循环之外做那些。

编辑:如何在循环外打开它的一个例子

public void playMet(){
    int tempo = Integer.parseInt(met_speed.getText());
    tempo = tempo/60;
    int delay = tempo*1000;
    try {
        Clip clip = AudioSystem.getClip();
        clip.open(AudioSystem.getAudioInputStream(new File(filename)));

    }
    catch (Exception exc) {
        exc.printStackTrace(System.out);
    }
    new Timer(delay, new ActionListener(){

        public void actionPerformed(ActionEvent e){
            if(Play.isSelected()){
                System.out.println("beep");
                clip.start();
            }
        }
        }).start();
    }

但是我相信这会迫使你宣称剪辑是最终的,另一种方法是:

public Class {
private boolean firstTimeThrough;
public void playMet(){
    int tempo = Integer.parseInt(met_speed.getText());
    tempo = tempo/60;
    int delay = tempo*1000;
    firstTimeThrough = true;
    new Timer(delay, new ActionListener(){

        public void actionPerformed(ActionEvent e){
            if(Play.isSelected()){
                if(firstTimeThrough){
                try {
                   Clip clip = AudioSystem.getClip();
                   clip.open(AudioSystem.getAudioInputStream(new File(filename)));
                   firstTimeThrough = false;
                   }
                   catch (Exception exc) {
                   exc.printStackTrace(System.out);
                   }
                }
                System.out.println("beep");
                clip.start();
            }
        }
        }).start();
    }