Java Midi音序器计时已关闭

问题描述

在过去的几天中,我一直在尝试用Java编写节拍器进行练习。我使用 javax.sound.midi 库对程序进行了简单的4/4 midi节拍。
我的主要问题是音序器似乎要播放第一个节拍时间。如果将序列设置为循环,则只会在第一个循环上发生。顺便说一句,如果我更改了轨道的bpm,它会在第一个循环后重置。
我还尝试了多个midi文件,以防万一我创建的midi文件出现问题,但我所有的测试都结果相同。
这是我处理midi播放的代码:

public class MidiHandler 
{
    private Sequencer sequencer;
    private Sequence seq;
    private float newTempoFactor;
    
    public MidiHandler()
    {
        try 
        {
            sequencer = MidiSystem.getSequencer();
            if (sequencer == null)
            {
                System.err.println("Sequencer not supported");
            }
            sequencer.open();
        } 
        catch (MidiUnavailableException ex) 
        {
            Logger.getLogger(MidiHandler.class.getName()).log(Level.SEVERE,null,ex);
        }
    }
    
    public void setAudioTrack(String filePath)
    {
        try 
        {
            seq= MidiSystem.getSequence(new File(filePath));
            sequencer.setSequence(seq);
        } 
        catch (InvalidMidiDataException | IOException ex) 
        {
            Logger.getLogger(MidiHandler.class.getName()).log(Level.SEVERE,ex);
        }
    }
    
    public void playTrack(float bpm) throws InterruptedException
    {
        try 
        { 
            seq=editEvents();//editEvents() method pushes all midi events 100 ticks forward
            sequencer.setSequence(seq);
        } 
        catch (InvalidMidiDataException ex) 
        {
            Logger.getLogger(MidiHandler.class.getName()).log(Level.SEVERE,ex);
        }
        sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
        sequencer.start();
        //sequencer.setTempoInBPM(bpm);
        newTempoFactor=bpm/120;
        sequencer.setTempoFactor(newTempoFactor);//Default tempo is 120bpm --> Tempo factor =1 

         

         sequencer.setLoopStartPoint(100);//Shift the loop start/end by 100 ticks
         sequencer.setLoopEndPoint(seq.getTickLength());
    }    

    public Sequence editEvents() 
    {
        Sequence seq= this.seq;
        try 
        {
            seq = MidiSystem.getSequence(new File("res//myTrack.mid"));
            for (Track track :  seq.getTracks()) 
            {
                for (int i=0; i < track.size(); i++) 
                { 
                    MidiEvent event = track.get(i);
                    event.setTick(event.getTick()+100);  
                }
            }
        } 
        catch (InvalidMidiDataException | IOException ex) 
        {
            Logger.getLogger(MidiHandler.class.getName()).log(Level.SEVERE,ex);
        }
        
        return seq;
    }

}

我的主班

public class main 
{
    public static void main(String[] args) 
    {
        try 
        {
            MidiHandler mh = new MidiHandler();
            mh.setAudioTrack("res//myTrack.mid");
            mh.playTrack(120f);
        } 
        catch (SecurityException | InterruptedException ex) 
        {
            Logger.getLogger(main.class.getName()).log(Level.SEVERE,ex);
        }
        
    }
}

解决方法

您的代码看起来还可以。

最初的节拍不定时通常是由于连接了Midi设备(在我的情况下,当我使用外部USB Midi声卡时)。如果可以,请尝试使用其他MidiDevice。

如果不能,解决方法是将创建的MidiEvents的所有Sequence移动4个节拍,然后使用Sequencer.setLoopEndPoint(long tick)Sequencer.setLoopStartPoint(long tick)进行循环从新的起点开始。

对于启动后的速度更改,这是一个JDK错误。解决方法是在Sequencer.setTempoInBPM()之后立即调用Sequencer.start()

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...