如何将从轨道1中提取的速度应用到MIDI文件的其他轨道?

时间:2017-05-31 06:30:29

标签: java audio midi javasound

我正试图从midi文件的第一首曲目中提取旋律的速度,并将其应用到包含音符事件的其余曲目。

基本上我一直在尝试在每次播放固定时间间隔的Thread.sleep()消息之后替换noteOn()方法。因此,我失去了整个赛道的节奏。

我成功地从之前提出的问题How does Midi TEMPO message apply to other tracks?中提取了第一首曲目的速度信息,但无法将其应用于其他曲目。

是否有特定功能可以做到这一点?我试过搜索但找不到。

这是我的代码供参考。

      int trackNumber = 0;

     for (Track track :  sequence.getTracks()) {

        trackNumber++;           
        System.out.println();
        for (int i=0; i < track.size(); i++) { 

            MidiEvent event = track.get(i);
            MidiMessage message = event.getMessage();

            if (message instanceof MetaMessage) {

             MetaMessage mm = (MetaMessage) message;
             if(mm.getType()==SET_TEMPO){ 

               byte[] data = mm.getData();
               int tempo = (data[0] & 0xff) << 16 | (data[1] & 0xff) << 8 | (data[2] & 0xff);
               int bpm = 60000000 / tempo;
             }
            }

           if (message instanceof ShortMessage) {
                ShortMessage sm = (ShortMessage) message;
                if (sm.getCommand() == NOTE_ON) {

                    int key = sm.getData1();
                    int velocity = sm.getData2();                    
                    channels[0].noteOn(key,velocity);
                    Thread.sleep(280);//Pays all the note for fixed duration    
                } 
                else if (sm.getCommand() == NOTE_OFF) {

                    int key = sm.getData1();
                    int velocity = sm.getData2();
                    channels[0].noteOff(key);

                } 
            }
        }

        System.out.println();
    }
 }

1 个答案:

答案 0 :(得分:1)

多个曲目中的事件同时发生,因此您无法单独处理曲目。

你必须

  • 将所有事件放入单个列表中,并按时间戳对它们进行排序(但要确保具有相同时间戳的事件保持其顺序,因此请使用稳定的排序算法);或
  • 每个曲目都有一个当前位置,在确定下一个曲目时,在所有曲目中搜索具有最小时间戳的尚未使用的事件。

请注意,播放期间速度可能会发生变化,因此单个bpm值不足以满足要求。请参阅How to correctly convert MIDI ticks to milliseconds?How can I parse a tempo of midi using Java?