2012-12-04 3 views
2

미디 피아노 롤 편집기를 만들고 있습니다. Note 클래스는 노트의 피치, 타이밍 및 지속 시간을 조작하기 위해 사용자가 화면에서 조작하는 사각형뿐만 아니라 NOTE_ON 오브젝트 및 연관된 NOTE_OFF 오브젝트를 생성하여 포함합니다. 다음은이 클래스의 코드에서 사각형의 코드를 뺀 코드입니다. 왜 제대로 작동하지 않는지 알 수 없습니다. 테스트 프로그램은이 Note 오브젝트 중 다섯 개를 생성하여 피아노 롤 그리드에 표시하고 제대로 재생합니다. 직사각형을 위로 또는 아래로 끌 때 피치를 변경하는 방법이 제대로 작동합니다. 그러나 타이밍이나 지속 시간을 변경하는 메소드를 호출 할 때 노트가 잘못 작동하기 시작합니다. 우선, 그들은 움직일 때 말한 곳에서 연주하지 않으며, 그 위에 노트가 드래그되거나 서로 위로 뻗어 있다면, 움직이는 노트는 그 아래의 노트가 연주되는 것을 막을 것입니다. arg가 16으로 설정되어있을 때,이 방법으로 보내지는 운동 단위는 노트가 항상 16 번째 비트 위치로 스냅됩니다. 누구든지 내 코드에 문제가있는 부분을 찾아 낼 수 있습니까?왜 미디 노트 타이밍이 작동하지 않습니까?

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); 
} 

미디 시퀀서와 신디사이저 :

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)를 실제로 이동시키는 별도의 메소드가 있습니다. 나는 압축 된 형태의 코드를 제공하기 위해 노력하고 있지만, 코드가 작동하는 데 문제가 있습니다. 이것은 첫 번째 실제 프로젝트이므로 이러한 작업을 수행하는 방법을 파악할 때 인내심을 부탁드립니다. –