2012-12-04 26 views
2

我正在創建一個midi鋼琴卷編輯器。 Note類創建幷包含一個NOTE_ON對象和一個關聯的NOTE_OFF對象以及一個用戶在屏幕上操縱矩形,以操縱音符的音高,時間和持續時間。以下是此類的代碼減去矩形的代碼。我無法弄清楚爲什麼它不能正常工作。測試程序創建這些Note對象中的五個,並將它們顯示在鋼琴捲簾上,並且它們可以正常播放。矩形上下拖動時,更改音高的方法也可以正常工作。但是當我調用改變時間或持續時間的方法時,音符開始行爲不端。首先,他們在移動時不會播放他們被告知的內容,然後如果音符被拖動到彼此的頂部或者彼此之間,則移動的音符將阻止其下方的音符播放。以arg形式發送到這些方法的運動單位設置爲16,因此音符總是會捕捉到第16個節拍位置。任何人都可以發現我的代碼有問題嗎?爲什麼不會注意到MIDI時間的工作?

public class Note { 
MidiEvent noteOn; 
MidiEvent noteOff; 

private int channel; 
private int pitch; 
private int vel; 

// Constructor calls methods to create NOTE_ON, NOTE_OFF, and graphical rectangle 
public Note(MidiMessage on, long tickPos) { 
    noteOn = createNoteOn(on, tickPos); 
    ShortMessage shortMessage = (ShortMessage) on; 
    noteOff = createNoteOff(shortMessage.getChannel(), shortMessage.getData1(), tickPos); 
} 

public MidiEvent createNoteOn(MidiMessage on, long tickPos) { 
    noteOn = new MidiEvent(on, tickPos); 
    return noteOn; 
} 

public MidiEvent createNoteOff(int chan, int pitch, long tickPos) { 
    try { 
     noteOff = new MidiEvent(new ShortMessage(ShortMessage.NOTE_OFF, chan, pitch, 0), tickPos + 2); 
    } catch (InvalidMidiDataException e) { 
      e.printStackTrace(); 
    } 
    return noteOff; 
} 

// Method for moving musical pitch of this note up or down for both NOTE_ON and NOTE_OFF 
public void setPitch(int pitchUpOrDown) { 
    MidiMessage message = noteOn.getMessage(); 
    ShortMessage shortMessage = (ShortMessage) message; 
     channel = shortMessage.getChannel(); 
     pitch = shortMessage.getData1(); 
     vel = shortMessage.getData2(); 
     try { 
      shortMessage.setMessage(ShortMessage.NOTE_ON, channel, pitch + pitchUpOrDown, vel); 
     } catch (InvalidMidiDataException e) { 
      e.printStackTrace(); 
     } 
     message = noteOff.getMessage(); 
     shortMessage = (ShortMessage) message; 
     try { 
      shortMessage.setMessage(ShortMessage.NOTE_OFF, channel, pitch + pitchUpOrDown, 0); 
     } catch (InvalidMidiDataException e) { 
      e.printStackTrace(); 
     } 
} 

// Moves entire note without changing duration of note 
public void shiftLocation(int diff) { 
    noteOn.setTick(noteOn.getTick() + diff); 
    noteOff.setTick(noteOff.getTick() + diff); 
} 

// Moves start time of note while leaving end time in place, changes duration of note 
public void setStartTime(long start) { 
    noteOn.setTick(start); 
} 

// Moves end time of note while leaving start time in place, changes duration of note 
public void setDuration(int duration) { 
    noteOff.setTick(noteOff.getTick() + duration); 
} 

的MIDI音序器和合成器:

import javax.sound.midi.*; 

public class MusicEngine { 
Sequencer sequencer; 
Sequence sequence; 
Synthesizer synthesizer; 
Track track; 
MidiEvent event; 
// PPQ, or ticks per beat 
int ticksPerBeat = 16; 
int tempoBPM = 120; 

// Constructor 
public MusicEngine() {  
    createMidi(); 
} 

// Get sequencer and sequence and track 
public void createMidi() { 
    try { 
     sequencer = MidiSystem.getSequencer(); 
     if (sequencer == null) { 
      System.out.println("Cannot get a sequencer"); 
      System.exit(0); 
     } 
     sequencer.open(); 

     // If sequencer is not the same as synthesizer, link the two 
     // (required in J2SE 5.0) 
     if (!(sequencer instanceof Synthesizer)) { 
      System.out.println("Linking the sequencer to the synthesizer"); 
      synthesizer = MidiSystem.getSynthesizer(); 
      synthesizer.open(); 
      Receiver synthReceiver = synthesizer.getReceiver(); 
      Transmitter seqTransmitter = sequencer.getTransmitter(); 
      seqTransmitter.setReceiver(synthReceiver); 
     } else 
      synthesizer = (Synthesizer)sequencer; 
     sequence = new Sequence(Sequence.PPQ, ticksPerBeat); 
     track = sequence.createTrack(); 
     sequencer.setTempoInBPM(tempoBPM); 
    } catch(MidiUnavailableException e) { 
     System.out.println("No sequencer available"); 
     System.exit(0); 
    } catch(Exception e) { 
     e.printStackTrace(); 
     System.exit(0); 
    } 

} 

// Create an individual MIDI event 
public MidiEvent createEvent(int command, int channel, int one, int two, int tick) { 
    event = null; 
    try { 
     ShortMessage a = new ShortMessage(); 
     a.setMessage(command, channel, one, two); 
     event = new MidiEvent(a, tick); 
    } catch(InvalidMidiDataException e) { 
     e.printStackTrace(); 
    } 
    return event; 
} 

public void add(MidiEvent event) { 
    track.add(event); 
} 

public void playSong(int tempo) { 
    try { 
     sequencer.setSequence(sequence); 
    } 
    catch (InvalidMidiDataException e) { 
     e.printStackTrace(); 
    } 

    sequencer.start(); 
} 

public void stopSong() { 
    sequencer.stop(); 
} 
} 
+0

可能有助於發佈您用來播放序列的代碼嗎?另外,你可以首先將事情隔離爲一個簡單的測試案例,在這個例子中你用一對筆記創建一個軌道,改變一個筆記的時間/持續時間,然後播放序列? –

+0

我添加了合成器和音序器引擎。我必須離開一點。當我回來時,我會嘗試簡化代碼並從我更詳細的代碼中提取簡單的測試代碼。 –

回答

0

我可能會在這裏誤解你的代碼,但似乎你只增加你的setDuration()方法音符的長度。它不應該看起來像這樣嗎?

public void setDuration(int duration) { 
    noteOff.setTick(noteOn.getTick() + duration); 
} 
+0

是的,這就是這種方法的意圖:增加音符的長度。就在它上面是一個單獨的方法來實際移動音符(setStartTime)。我仍然致力於提供代碼的精簡形式,但我遇到了使代碼工作的問題。這是我第一個真正的項目,所以我懇求你的耐心,因爲我知道如何做這些事情。 –

相關問題