簡體   English   中英

Java Midi 音序器定時關閉

[英]Java Midi sequencer timing is off

這幾天一直在嘗試在Java中編寫一個節拍器進行練習。 我制作了一個簡單的 4/4 midi 節拍,該程序使用javax.sound.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, null, 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, null, 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, null, ex);
        }
        
        return seq;
    }

}

我的主 class

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, null, ex);
        }
        
    }
}

您的代碼看起來不錯。

不定時的初始節拍通常是由於連接的 Midi 設備(在我的情況下,當我使用外部 USB Midi 聲卡時)。 如果可以,請嘗試使用不同的 MidiDevice。

如果不能,解決方法是將創建的Sequence的所有MidiEvents移動 4 個節拍,然后使用Sequencer.setLoopEndPoint(long tick)Sequencer.setLoopStartPoint(long tick)使循環從新的起點開始。

對於開始后的節奏變化,這是一個 JDK 錯誤。 解決方法是在Sequencer.setTempoInBPM() Sequencer.start()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM