/*
* Created on 06 August 2005
*
* Copyright (c) 2005 Peter Johan Salomonsen (http://www.petersalomonsen.com)
* 2007 PJL added some comparators
*
* http://www.frinika.com
*
* This file is part of Frinika.
*
* Frinika is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* Frinika is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Frinika; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.frinika.sequencer.model;
import java.util.Comparator;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiEvent;
import javax.sound.midi.ShortMessage;
import com.frinika.sequencer.FrinikaTrackWrapper;
import com.frinika.sequencer.gui.virtualkeyboard.VirtualKeyboard;
/**
*
* @author Peter Johan Salomonsen
*
*/
public class NoteEvent extends ChannelEvent {
final static public Comparator<NoteEvent> noteComparator= new NoteComparator();
final static public StartComparator startComparator= new StartComparator();
final static public EndComparator endComparator= new EndComparator();
private static final long serialVersionUID = 1L;
transient MidiEvent startEvent;
transient MidiEvent endEvent;
int note;
int velocity;
long duration;
boolean valid = false;
/**
* Constructor for creating a note event. For registering the new note event in the track use FrinikaTrackWrapper.add(MultiEvent evt)
* @param track
* @param startTick
* @param note
* @param velocity
* @param channel
* @param duration
* @deprecated
*/
public NoteEvent(FrinikaTrackWrapper track, long startTick, int note, int velocity, int channel, long duration)
{
super(track, startTick);
this.note = note;
this.velocity = velocity;
this.channel = channel;
this.duration = duration;
}
/**
*
* @param group
* @param startTick
* @param note
* @param velocity
* @param channel
* @param duration
*/
public NoteEvent(MidiPart part, long startTick, int note, int velocity, int channel, long duration)
{
super(part, startTick);
this.note = note;
this.velocity = velocity;
this.channel = channel;
this.duration = duration;
}
/**
* The process generating the NoteEvent should first supply it start event,
* and when ready the end event - to form a complete Note event
* @param startEvent
*
*/
NoteEvent(MidiPart part, MidiEvent startEvent)
{
super(part,startEvent.getTick());
this.startEvent = startEvent;
ShortMessage shm = (ShortMessage)startEvent.getMessage();
note = shm.getData1();
velocity = shm.getData2();
channel = shm.getChannel();
startTick = startEvent.getTick();
}
public void setEndEvent(MidiEvent endEvent) {
this.endEvent = endEvent;
duration = endEvent.getTick()-startTick;
if (duration < 0 ) {
System.out.println(" NEGATIVE LENGTH NOTE FIXED");
duration=0;
endEvent.setTick(startEvent.getTick());
}
valid = true;
}
public long getEndTick() {
return startTick+duration;
}
public int getNote()
{
return note;
}
public String getNoteName()
{
return VirtualKeyboard.getNoteString(note);
}
public void setNote(int note)
{
if (this.note == note ) return;
this.note = note;
}
public int getVelocity()
{
return velocity;
}
public void setVelocity(int velocity)
{
this.velocity = velocity;
}
/**
* @return Returns the duration.
*/
public long getDuration() {
return duration;
}
/**
* @param duration The duration to set.
*/
public void setDuration(long duration) {
if (duration < 0 ) {
System.out.println(" Sorry but I won't make a note negative length ");
duration=0;
return;
}
this.duration = duration;
}
@SuppressWarnings("deprecation") void commitRemoveImpl() // Jens, renamed to be able to handle notification of CommitListeners in MultiEvent, see MultiEvent.commitXxx()
{
if (zombie) {
try {
throw new Exception(" Attempt to remove a zombie note from the track ");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (startEvent == null) {
try {
throw new Exception(" Attempt to remove a note with null start from the track ");
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println(" You can ignore this exception . . . . ");
e.printStackTrace();
}
} else {
getTrack().remove(startEvent);
}
if (endEvent == null) {
try {
throw new Exception(" Attempt to remove a note with null end from the track ");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
getTrack().remove(endEvent);
}
zombie=true;
}
@SuppressWarnings("deprecation")
public void commitAddImpl() // Jens, renamed to be able to handle notification of CommitListeners in MultiEvent, see MultiEvent.commitXxx()
{
if (part.lane == null) return;
try
{
ShortMessage shm = new ShortMessage();
shm.setMessage(ShortMessage.NOTE_ON,channel,note,velocity);
startEvent = new MidiEvent(shm,startTick);
getTrack().add(startEvent);
shm = new ShortMessage();
shm.setMessage(ShortMessage.NOTE_ON,channel,note,0);
endEvent = new MidiEvent(shm,startTick+duration);
getTrack().add(endEvent);
} catch(InvalidMidiDataException e)
{
e.printStackTrace();
}
zombie=false;
}
public void restoreFromClone(EditHistoryRecordable object) {
NoteEvent note = (NoteEvent)object;
this.part = note.part;
this.startTick = note.startTick;
this.velocity = note.velocity;
this.channel = note.channel;
this.duration = note.duration;
this.note = note.note;
}
/*
* (non-Javadoc)
* @see com.frinika.sequencer.model.MultiEvent#setValue(int)
*/
public void setValue(int val) {
this.velocity=val;
}
public int getValue() {
return velocity;
}
public long rightTickForMove() {
return startTick+duration;
}
public boolean isDrumHit() {
return duration == 0;
}
/**
* PJL HACK NOT DO NOT USE
*
*/
public void validate() {
if (endEvent == null) {
System.err.println("Fixing null end event" );
ShortMessage shm=new ShortMessage();
try {
shm.setMessage(ShortMessage.NOTE_ON,channel,note,0);
} catch (InvalidMidiDataException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
duration=0;
endEvent=new MidiEvent(shm,startTick);
}
}
/**
*
* Utility comparators for sorted sets. Notes are never equaly unless they are the same object.
*
* @author pjl
*
*/
static public class StartComparator implements Comparator<NoteEvent> {
public int compare(NoteEvent o1, NoteEvent o2) {
if (o1.startTick > o2.startTick) return 1;
if (o1.startTick < o2.startTick) return -1;
if (o1.startTick + o1.duration> o2.startTick+ o2.duration) return 1;
if (o1.startTick + o1.duration< o2.startTick+ o2.duration) return -1;
if (o1.note > o2.note) return 1;
if (o1.note < o2.note) return -1;
// if (o1.part.colorID > o2.part.colorID) return 1;
// if (o1.part.colorID < o2.part.colorID) return -1;
return o1.compareTo(o2); // it should never come to this ?
}
}
static public class EndComparator implements Comparator<NoteEvent> {
public int compare(NoteEvent o1, NoteEvent o2) {
if (o1.startTick + o1.duration> o2.startTick+ o2.duration) return 1;
if (o1.startTick + o1.duration< o2.startTick+ o2.duration) return -1;
if (o1.startTick > o2.startTick) return 1;
if (o1.startTick < o2.startTick) return -1;
if (o1.note > o2.note) return 1;
if (o1.note < o2.note) return -1;
// if (o1.part.colorID > o2.part.colorID) return 1;
// if (o1.part.colorID < o2.part.colorID) return -1;
return o1.compareTo(o2); // it should never come to this ?
}
}
static public class NoteComparator implements Comparator<NoteEvent> {
public int compare(NoteEvent o1, NoteEvent o2) {
if (o1.note > o2.note) return 1;
if (o1.note < o2.note) return -1;
if (o1.startTick > o2.startTick) return 1;
if (o1.startTick < o2.startTick) return -1;
if (o1.startTick + o1.duration> o2.startTick+ o2.duration) return 1;
if (o1.startTick + o1.duration< o2.startTick+ o2.duration) return -1;
// if (o1.part.colorID > o2.part.colorID) return 1;
// if (o1.part.colorID < o2.part.colorID) return -1;
return o1.compareTo(o2); // it should never come to this ?
}
}
}