/* * Copyright (C) 2013-2015 たんらる */ package fourthline.mmlTools; import java.util.Objects; import fourthline.mmlTools.core.MMLTicks; import fourthline.mmlTools.core.TuningBase; import fourthline.mmlTools.core.UndefinedTickException; public final class MMLNoteEvent extends MMLEvent implements Cloneable { private static final long serialVersionUID = 4372538748155995529L; public static final int INIT_VOL = 8; public static final int MAX_VOL = 15; private int note; private int tick; private TuningBase tuningBase = null; private int velocity; private int indexOfMMLString[] = null; // { startIndex, endIndex } public MMLNoteEvent(int note, int tickLength, int tickOffset) { this(note, tickLength, tickOffset, INIT_VOL); } public MMLNoteEvent(int note, int tickLength, int tickOffset, int velocity) { super(tickOffset); if ( (velocity < 0) || (velocity > MAX_VOL) ) { throw new IllegalArgumentException("velocity "+velocity); } this.note = note; this.tick = tickLength; this.velocity = velocity; } public int getNote() { return this.note; } public void setNote(int note) { this.note = note; } public int getTick() { return this.tick; } public int getEndTick() { return getTickOffset() + getTick(); } public void setTick(int tick) { this.tick = tick; } public boolean isTuningNote() { return (tuningBase != null); } public TuningBase getTuningBase() { return tuningBase; } public void setTuningNote(TuningBase base) { this.tuningBase = base; } public int getVelocity() { return velocity; } public void setVelocity(int velocity) { if (velocity < 0) { velocity = 0; } else if (velocity > MAX_VOL) { velocity = MAX_VOL; } this.velocity = velocity; } public int[] getIndexOfMMLString() { return indexOfMMLString; } public void setIndexOfMMLString(int index[]) { this.indexOfMMLString = index; } @Override public String toString() { return "[Note] note: " + note + ", tick: " + tick + ", offset: " + getTickOffset() + ", velocity: " + velocity; } private static final String noteNameTable[] = { "c", "c+", "d", "d+", "e", "f", "f+", "g", "g+", "a", "a+", "b" }; private String getNoteName() throws UndefinedTickException { if (note == -1) { return "c-"; } return noteNameTable[ note%noteNameTable.length ]; } @Override public String toMMLString() throws UndefinedTickException { if ( (note < -1) || (note >= 108) ) { throw new UndefinedTickException("note = "+note); } String noteName = getNoteName(); MMLTicks mmlTick = new MMLTicks(noteName, tick); if (tuningBase != null) { return mmlTick.toMMLTextByBase(tuningBase); } else { return mmlTick.toMMLText(); } } public String toMMLString(MMLNoteEvent prevNoteEvent) throws UndefinedTickException { if ( (note < -1) || (note >= 108) ) { throw new UndefinedTickException("note = "+note); } StringBuilder sb = new StringBuilder(); // 前のノートとの差を見て、休符を挿入する. sb.append( createMMLSpaceString(prevNoteEvent) ); // 前のノートとのオクターブ差分をみて、オクターブ変化を挿入する. sb.append( changeOctaveinMMLString(prevNoteEvent.getOctave()) ); // 前のノートとの音量が違う場合、音量コマンドを挿入する. if (prevNoteEvent.getVelocity() != velocity) { sb.append("v"+velocity); } sb.append( toMMLString() ); return sb.toString(); } /** * 前のNoteEvent間にある休符のMML文字列を生成します. * @param prevNoteEvent * @return */ private String createMMLSpaceString(MMLNoteEvent prevNoteEvent) throws UndefinedTickException { int noteSpaceTick = getTickOffset() - prevNoteEvent.getEndTick(); if ( noteSpaceTick > 0 ) { MMLTicks mmlTick = new MMLTicks("r", noteSpaceTick, false); return mmlTick.toMMLText(); } return ""; } /** * ノートの高さにあわせて、MMLテキスト上でのオクターブ変更を行います. * @param prevOctave * @return */ public String changeOctaveinMMLString(int prevOctave) { String s = ""; final String increaseOctave = ">>>>>>>>"; final String decreaseOctave = "<<<<<<<<"; int changeOctave = prevOctave - getOctave(); if (changeOctave > 0) { s = decreaseOctave.substring(0, changeOctave); } else if (changeOctave < 0) { s = increaseOctave.substring(0, -changeOctave); } return s; } public int getOctave() { if (note < 0) { return 0; } return (note /12); } @Override public MMLNoteEvent clone() { try { return (MMLNoteEvent) super.clone(); } catch (CloneNotSupportedException e) { throw new AssertionError(e.getMessage()); } } @Override public boolean equals(Object obj) { if (!(obj instanceof MMLNoteEvent)) { return false; } MMLNoteEvent noteEvent = (MMLNoteEvent) obj; if ((this.tick == noteEvent.tick) && (this.note == noteEvent.note) && (this.velocity == noteEvent.velocity) && (this.tick == noteEvent.tick) && (super.equals(noteEvent)) && (Objects.equals(this.tuningBase, noteEvent.tuningBase))) { return true; } return false; } }