Java 将音效与其他计时器动作同步

Java 将音效与其他计时器动作同步,java,swing,timer,Java,Swing,Timer,我有一个计时器,它应该以1秒的间隔启动各种动作。这是一个相当简单的想法,模拟5秒倒计时(字面上)。开始时,会更新JLabel以将其文本设置为“5”。同时,播放一个小mp3声音文件,播放用户在屏幕上看到的数字。然后,一秒钟后,文本变为“4”,并播放不同的mp3播放数字4。等等,直到我们到达零 这一切都是可行的,但我无法让视频更新与音频部分精确同步。mp3似乎总是在屏幕更新之前播放一点点。起初,我认为我只需要在每首mp3的开头加上一点额外的静音,然后反复尝试,直到事情同步为止。但是,无论我为每一个m

我有一个计时器,它应该以1秒的间隔启动各种动作。这是一个相当简单的想法,模拟5秒倒计时(字面上)。开始时,会更新JLabel以将其文本设置为“5”。同时,播放一个小mp3声音文件,播放用户在屏幕上看到的数字。然后,一秒钟后,文本变为“4”,并播放不同的mp3播放数字4。等等,直到我们到达零

这一切都是可行的,但我无法让视频更新与音频部分精确同步。mp3似乎总是在屏幕更新之前播放一点点。起初,我认为我只需要在每首mp3的开头加上一点额外的静音,然后反复尝试,直到事情同步为止。但是,无论我为每一个mp3预先设置了多少静音,在屏幕更新之前,我仍然能听到音频。所有这些变化都是每次“一秒钟”更新之间的延迟

无论如何,这是我正在使用的代码。有人能帮我同步吗?也许我需要第二个计时器?我不知道那会怎样。提前谢谢

class Countdown extends JFrame implements ActionListener {

    private Timer countdownTimer = new Timer(1000, this);
    int countdownSeconds;
    MyJFrame myFrame;

    public Countdown(MyJFrame thisFrame) {

        int countdownSeconds = 5;
        countdownTimer.start();
        myFrame = thisFrame;
    }

    @Override
    public void actionPerformed(ActionEvent e) {

            if (countdownSeconds == 0) {
                myFrame.updateCountdown(myFrame, "Go");
                SoundEffect.play("launch.mp3");
                countdownTimer.stop();
            } else {
                myFrame.updateCountdown(myFrame, Integer.toString(countdownSeconds));
                if (countdownSeconds == 5) {SoundEffect.play("five.mp3");}
                if (countdownSeconds == 4) {SoundEffect.play("four.mp3");}
                if (countdownSeconds == 3) {SoundEffect.play("three.mp3");}
                if (countdownSeconds == 2) {SoundEffect.play("two.mp3");}
                if (countdownSeconds == 1) {SoundEffect.play("one.mp3");}
                countdownSeconds--;
            }
        }
    }

public void updateCountdown(MyJFrame thisFrame, String numSec) {
    lblCountdown.setText(numSec);
}



import java.io.FileInputStream;
import javazoom.jl.player.Player;

public class SoundEffect {

    public static void play(String mp3File) {
        try {
            FileInputStream mp3_file = new FileInputStream(mp3File);
            Player mp3 = new Player(mp3_file);
            mp3.play();
        }
        catch(Exception e) {
            System.out.println(e);
        }
    }
}

我非常怀疑您是否能够完美地同步这些数据,但我可以解释为什么当前的方法不起作用

必须在事件分派线程上更新Swing组件,就像使用
计时器一样。更新标签文本时,它将在事件调度线程上安排重新绘制。注意单词schedule,不要执行

但是,事件调度线程当前正忙于播放您的声音,因此只有在您调用
mp3.play()
之后,才会执行实际的
repaint
操作


现在,您可以(如果允许,不确定播放MP3的线程规则)尝试在不同的
线程上播放MP3(例如,使用辅助非摆动计时器)。但是,由于您无法完全控制实际重新绘制的时间,并且只能控制重新绘制的计划时间,因此视觉和听觉更新仍然可能不同步。

问题的主要部分归结为:

if (countdownSeconds == 5) {SoundEffect.play("five.mp3");}
…导致

public class SoundEffect {

    public static void play(String mp3File) {
        try {
            FileInputStream mp3_file = new FileInputStream(mp3File);
            Player mp3 = new Player(mp3_file);
            mp3.play();
        }
        catch(Exception e) {
            System.out.println(e);
        }
    }
}
哇!现在不是加载剪辑的时候


相反,它们应该在计时器启动之前加载。我认为文件I/O是(可察觉的)延迟或延迟的真正原因。

是的,我担心这可能是答案。奇怪的是,我不能在mp3的开头加上十分之一秒或十分之二的静音,让它看起来好像是同步的。但我明白你的意思。我想我会去掉声音,不再折磨自己了。谢谢@usr55410您确定mp3.play()
在mp3播放结束之前返回吗。如果没有,这将解释为什么你不能在“怀疑你是否能够完美地同步这些”之前添加任何沉默。这可以通过使用它来完成,它可以提供低至千分之一秒的进度。此操作似乎使用的是JMF播放器,..可以将时间缩短到。@AndrewThompson,即使您只知道何时计划重新绘制,而不知道何时实际执行?仔细查看代码后,我怀疑真正的问题是“文件I/O”。。