代码之家  ›  专栏  ›  技术社区  ›  Jamie Keeling

Java MIDI轨迹中的注释之间的延迟错误

  •  1
  • Jamie Keeling  · 技术社区  · 14 年前

    从我的问题开始 here 我创建了一个列表,允许我将需要播放的笔记集合排队,然后将这些笔记按顺序添加到曲目中,以便一次播放。

    我将要在曲目中播放的笔记添加到临时列表中,如下所示:

    int pitch = jComboBoxPitch.getSelectedIndex();
    int velocity = ((Integer)jSpinnerVelocity.getValue());
    
    collection.add(new MIDIMessage(pitch,velocity));
    

    当用户添加了所有必要的注释后,按“播放”按钮:

    private void PlayMIDI()
        {
            try
            {
                Sequencer seq = MidiSystem.getSequencer();
                seq.open();
                Sequence sequence1 = new Sequence(Sequence.PPQ,16);
                Track track = sequence1.createTrack();
    
                Iterator itr = collection.iterator();
    
                int i = 0;
    
            while(itr.hasNext())
            {
                MIDIMessage msg = (MIDIMessage)itr.next();
    
                ShortMessage noteOnMsg = new ShortMessage();
                //Signal/Channel/Pitch/Velocity
                noteOnMsg.setMessage(ShortMessage.NOTE_ON, 0,msg.GetPitch(),msg.GetVelocity());
    
                ShortMessage noteOffMsg = new ShortMessage();
                //Signal/Channel/Pitch/Velocity
                noteOffMsg.setMessage(ShortMessage.NOTE_OFF,0,msg.GetPitch(),msg.GetVelocity());
    
                track.add(new MidiEvent(noteOnMsg,msg.GetDelay()));
                track.add(new MidiEvent(noteOffMsg,msg.GetDelay() + i));
    
                i++;
            }
    
            sequencer.setSequence(sequence);
            sequencer.setTempoInBPM(120);
            sequencer.setLoopCount(1);    
                seq.start();
            }
            catch(Exception e)
            {
    
            }
        }
    

    如您所见,我将遍历arraylist并将每个noteon/off添加到跟踪中。

    播放完曲目后,我注意到它只播放两个音符,与列表中的数量无关。

    我已经检查了临时收集和跟踪收集,它们似乎都有正确的数据。

    我添加事件和消息的方式是否错误?我只希望能够以记录的方式播放音符,并且每个音符之间应有合理的时间间隔。

    3 回复  |  直到 11 年前
        1
  •  2
  •   Nik Reiman    14 年前

    您似乎在向频道0添加留言,向频道1添加留言。我猜这并不是你真正想做的——把他们都安排在第一频道(即, 0 )

        2
  •  1
  •   Jamie Keeling    14 年前

    我设法解决了我遇到的问题,在看了我实现消息添加到曲目的方式之后,我发现每条消息添加得太近了,因此当每个音符播放时,下一个音符几乎立即播放。

    下面的代码显示了我如何修复它:

    int i = 0;
    
                while(itr.hasNext())
                {
                    MIDIMessage msg = (MIDIMessage)itr.next();
    
                    ShortMessage noteOnMsg = new ShortMessage();
                    //Signal/Channel/Pitch/Velocity
                    noteOnMsg.setMessage(ShortMessage.NOTE_ON, 0,msg.GetPitch(),msg.GetVelocity());
    
                    ShortMessage noteOffMsg = new ShortMessage();
                    //Signal/Channel/Pitch/Velocity
                    noteOffMsg.setMessage(ShortMessage.NOTE_OFF,0,msg.GetPitch(),msg.GetVelocity());
    
                    track.add(new MidiEvent(noteOnMsg,i));
                    i = i+50;
                    track.add(new MidiEvent(noteOffMsg,i));
                    i = i+50;
                }
    

    通过增加 五十 它确保所有的音符都有足够的空间在音轨上分开,因此音符可以正确播放。

        3
  •  1
  •   Devan Somaia    12 年前

    我知道几个月前有人问过这个问题,但我想做一些非常类似的事情。 我发现了同样的问题 sequencer.setLoopCount(1); 让我的音序器播放两次音符。

    通过删除这个,它只播放一次音符。希望这有帮助。