2

我一直在一个项目中工作,我需要在 java 中操作 MIDI 文件中的每个乐器。然后我决定从序列中的每个轨道中获取每个 MIDI 事件并将其发送到接收器。之后,线程等待每个滴答声持续的时间,然后在下一个滴答声中再次执行此操作。问题是:乐器的声音以及它们的顺序变得非常混乱。我也尝试单独执行每个轨道,但它仍然一团糟!编码:

    Sequence    sequence        = MidiSystem.getSequence(new File(source));
    Synthesizer synth           = MidiSystem.getSynthesizer();

    //Gets a MidiMessage and send it to Synthesizer
    Receiver    rcv             = synth.getReceiver();

    //Contains all tracks and events from MIDI file
    Track[]     tracks          = sequence.getTracks();
    synth.open();

    //If there are tracks
    if(tracks != null)
    {
        //Verify the division type of the sequence (PPQ, SMPT)
        if(sequence.getDivisionType() == Sequence.PPQ)
        {
            int     ppq         = sequence.getResolution();
            //Do the math to get the time (in miliseconds) each tick takes 
            long    tickTime    = TicksToMiliseconds(BPM,ppq);
            //Returns the number of ticks from the longest track
            int     longestTrackTicks   = LongestTrackTicks(tracks);

            //Each iteration sends a new message to 'receiver'
            for(int tick = 0; tick < maiorTick ; tick++)
            {   
                //Iteration of each track
                for(int trackNumber = 0; trackNumber < tracks.length; trackNumber++)
                {
                    //If the number of ticks from a track isn't already finished
                    //continue
                    if(tick < tracks[trackNumber].size())
                    {
                        MidiEvent ev = tracks[trackNumber].get(tick);
                        rcv.send(ev.getMessage(),-1);
                    }
                }
                Thread.sleep(tickTime);
            }

        }
    }
    synth.close();
4

3 回答 3

1

正如 ntabee 所说,Track.get(n)返回ntrack 中的第 th 事件;要按时间获取事件,您必须手动比较事件的时间。

此外,Thread.sleep()不是很精确,并且可以等待比预期更长的时间。这些错误会加起来。


要实时更改 MIDI 消息,请告诉音序器播放您自己ReceiverReceiver.

于 2014-09-16T07:32:23.993 回答
0

至少,您的代码看起来 tickTime毫秒都会响起/关闭某些东西。时期。 track.get(tick)只返回tick轨道中的 -th 事件,而不是.时刻的事件tick。如果您的目标只是播放声音,Java 为其提供了高级 API,请参见http://www.jsresources.org/examples/midi_playback_and_recording.html

于 2014-09-16T03:13:12.410 回答
0

我决定使用音序器。我不知道,但是“开始”方法在一个新线程中运行,当它仍在运行时,我可以静音每个我想要的乐器,这正是我想要的。感谢您的回答!

于 2014-09-16T18:19:07.063 回答