2011-01-13 2 views
3

Я создаю приложение, в котором пользователь может добавить несколько заметок MIDI в коллекцию, отсюда они могут нажать кнопку «Воспроизвести», и приложение будет проходить через каждую ноту и воспроизводить их через динамики ,Java MIDI Трек, воспроизводящий повторяющиеся заметки

Я создал класс MIDIMessage, в котором хранятся сведения о примечании, которое пользователь выбрал для добавления в список, причем данные хранятся в виде Pitch, Velocity, Delay и Channel.

Каждое из этих сообщений сохраняется в ArrayList с типом как MIDIMessage.

Затем я перехожу к итератору коллекции к объекту итератора и воспроизвожу звук, пока в коллекции еще нет элемента.

По какой-то причине, даже если я добавляю только одну ноту в коллекцию, всегда есть две ноты, играющие с одинаковой высотой, длиной и скоростью.

Также каждая нота играет одновременно, независимо от того, сколько из них присутствует в коллекции, я предположил, что между ними будет какая-то задержка.

Ниже приводится код, я использую в данный момент:

MIDIMessage:

package javatest; 

public class MIDIMessage 
{ 
    private int pitch; 
    private int velocity; 
    private int channel; 

    public MIDIMessage(int p, int v, int c) 
    { 
     pitch = p; 
     velocity = v; 
     channel = c; 
    } 

    public int GetPitch() 
    { 
     return this.pitch; 
    } 

    public int GetVelocity() 
    { 
     return this.velocity; 
    } 

    public int GetChannel() 
    { 
     return this.channel; 
    } 
} 

Добавление заметки к коллекции:

public void AddToList() 
    { 
     int channel = jComboBoxChannels.getSelectedIndex(); 
     int pitch = jComboBoxPitch.getSelectedIndex(); 
     int velocity = ((Integer)jSpinnerVelocity.getValue());  
     collection.add(new MIDIMessage(pitch,velocity,channel)); 
    } 

Игра ноты :

try 
     { 
      jButton1.setEnabled(false); 
      Sequencer sequencer = MidiSystem.getSequencer(); 
      sequencer.open(); 
      Sequence sequence = new Sequence(Sequence.PPQ,1); 
      Track track = sequence.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, msg.GetChannel(),msg.GetPitch(),msg.GetVelocity()); 

       ShortMessage noteOffMsg = new ShortMessage(); 
       //Signal/Channel/Pitch/Velocity 
       noteOffMsg.setMessage(ShortMessage.NOTE_OFF,msg.GetChannel(),msg.GetPitch(),msg.GetVelocity()); 

       track.add(new MidiEvent(noteOnMsg,0)); 
       track.add(new MidiEvent(noteOffMsg,1)); 
       //i = i+1; 
      } 

      sequencer.setSequence(sequence); 
      sequencer.setTempoInBPM(120); 
      sequencer.setLoopCount(1); 

      sequencer.start(); 

      Thread.sleep(1000); 
     } 

ответ

1

Я не знаю, почему ноты играются в два раза, но это определенно не так:

  track.add(new MidiEvent(noteOnMsg,0)); 
      track.add(new MidiEvent(noteOffMsg,1)); 

Как вы можете видеть here, MidiEvent состоит из сообщения и MIDI клеща. Вы всегда добавляете noteOnMsg по тику 0 и noteOffMsg по тику 1, что объясняет, почему для нескольких заметок все они воспроизводятся одновременно. Вы хотите сделать что-то вроде этого, вместо:

startTick = 0; 

while(itr.hasNext()) { 
    [...] 
    track.add(new MidiEvent(noteOnMsg,startTick)); 
    track.add(new MidiEvent(noteOffMsg,startTick + how_long_the_note_is_played)); 
    startTick += difference_between_this_note_and_the_next; 
    [...] 
} 

Я не уверен, что ваши delay средства, и если вы можете использовать его здесь, поэтому я использую описательные имена переменных вместо.

Обратите внимание, что вы должны будете использовать MIDI клещей здесь - если вы хотите конвертировать секунды MIDI клещей см this SO question (или, вернее, его ответ): [? Как долго один MIDI тик]

Формула: 60000/(BPM * PPQ) (миллисекунды).

+0

Прошу прощения, я не понимаю, как узнать, как долго играла нота, а другая между текущей записью и следующей? Также задержка была ошибкой, я был C/P-кодом из старого исходного файла. –

+0

Вы * определяете *, как долго воспроизводится нота и какая разница между текущей записью и следующей. Если вы хотите просто воспроизвести заметку каждый «бит», попробуйте использовать «Sequence.PPQ» для обеих переменных. – schnaader

+0

Что я пытаюсь сказать, я не понимаю, как бы я определил длину заметки, есть ли какой-то метод, который я могу использовать для получения длины одного ?. В качестве примера я заметил, что вы можете назвать новый MidiEvent (noteOnMsg, 1) .getTick); но я чувствую, что для его использования мне нужно будет создать MidiEvent отдельно, а затем добавить его на дорожку после, что позволит мне установить Tick на переменную. –

Смежные вопросы