/* * JFugue - API for Music Programming * Copyright (C) 2003-2008 David Koelle * * http://www.jfugue.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ package org.jfugue; /** * Contains all information necessary for a musical note, including pitch, * duration, attack velocity, and decay velocity. * * <p> * Most of these settings have defaults. The default octave is 5. The default * duration is a quarter note. The default attack and decay velocities are 64. * </p> * * @author David Koelle * @version 2.0.1 */ public final class Note implements JFugueElement { private byte value = 0; private long duration = 0; private double decimalDuration = 0.0; private boolean isStartOfTie = false; private boolean isEndOfTie = false; private byte attackVelocity = DEFAULT_VELOCITY; private byte decayVelocity = DEFAULT_VELOCITY; private boolean rest = false; private byte type = 0; private boolean accompanyingNotes = false; /** * Instantiates a new Note object. */ public Note() { this.value = 0; this.duration = 0; this.type = 0; } /** * Instantiates a new Note object with the given note value. This * constructor should only be called in cases where the duration of the note * is not important (for example, when specifying a root note for a * IntervalNotation) * * @param value * the numeric value of the note. C5 is 60. */ public Note(byte value) { this(value, 1); } /** * Instantiates a new Note object with the given note value and duration. * * @param value * the numeric value of the note. C5 is 60. * @param duration * the duration of the note, as milliseconds. */ public Note(byte value, long duration) { this.value = value; this.duration = duration; } /** * Instantiates a new Note object with the given note value and duration. * * @param value * the numeric value of the note. C5 is 60. * @param duration * the duration of the note, as a decimal fraction of a whole * note. */ public Note(byte value, double decimalDuration) { this.value = value; this.decimalDuration = decimalDuration; } /** * Instantiates a new Note object with the given note value, duration, and * attack and decay velocities. * * @param value * the numeric value of the note. C5 is 60. * @param duration * the duration of the note. */ public Note(byte value, long duration, byte attackVelocity, byte decayVelocity) { this.value = value; this.duration = duration; this.attackVelocity = attackVelocity; this.decayVelocity = decayVelocity; } /** * Instantiates a new Note object with the given note value, duration, and * attack and decay velocities. * * @param value * the numeric value of the note. C5 is 60. * @param duration * the duration of the note. */ public Note(byte value, double decimalDuration, byte attackVelocity, byte decayVelocity) { this.value = value; this.decimalDuration = decimalDuration; this.attackVelocity = attackVelocity; this.decayVelocity = decayVelocity; } /** * Indicates whether this Note object actually represents a rest. * * @param rest * indicates whether this note is rest */ public void setRest(boolean rest) { this.rest = rest; } /** * Returns whether this Note object actually represents a rest. * * @return whether this note is a rest */ public boolean isRest() { return this.rest; } /** * Sets the numeric value of this note. C5 is 60. * * @param value * the value of the note */ public void setValue(byte value) { this.value = value; } /** * Returns the numeric value of this note. C5 is 60. * * @return the value of this note */ public byte getValue() { return this.value; } /** * Sets the duration of this note. * * @param duration * the duration of this note */ public void setDuration(long duration) { this.duration = duration; } /** * Returns the duration of this note. * * @return the duration of this note */ public long getDuration() { return this.duration; } /** * Sets the decimal fraction value for the duration. * * @param number * the decimal fraction for the duration */ public void setDecimalDuration(double duration) { this.decimalDuration = duration; } /** * Returns the decimal fraction value for the duration. * * @return the decimal fraction value for the duration */ public double getDecimalDuration() { return this.decimalDuration; } /** * Indicates whether this note has a tie to some future note. * * @param tied * true if the note is tied, false if not */ public void setStartOfTie(boolean startOfTie) { this.isStartOfTie = startOfTie; } /** * Returns whether this note has a tie to some future note. * * @return true is the note is tied, false if not */ public boolean isStartOfTie() { return this.isStartOfTie; } /** * Indicates whether this note is tied to some past note. * * @param tied * true if the note is tied, false if not */ public void setEndOfTie(boolean endOfTie) { this.isEndOfTie = endOfTie; } /** * Returns whether this note is tied to some past note. * * @return true is the note is tied, false if not */ public boolean isEndOfTie() { return this.isEndOfTie; } /** * Sets the attack velocity for this note. * * @param velocity * the attack velocity */ public void setAttackVelocity(byte velocity) { this.attackVelocity = velocity; } /** * Returns the attack velocity for this note. * * @return the attack velocity */ public byte getAttackVelocity() { return this.attackVelocity; } /** * Sets the decay velocity for this note. * * @param velocity * the decay velocity */ public void setDecayVelocity(byte velocity) { this.decayVelocity = velocity; } /** * Returns the decay velocity for this note. * * @return the decay velocity */ public byte getDecayVelocity() { return this.decayVelocity; } /** * Sets whether this Note will have other Notes (sequential or parallel) * associated with it. * * @param accompanying */ public void setHasAccompanyingNotes(boolean accompanying) { this.accompanyingNotes = accompanying; } /** * Returns whether this Note will have other Notes (sequential or parallel) * associated with it. */ public boolean hasAccompanyingNotes() { return this.accompanyingNotes; } /** * Sets the note type - either First, Sequential, or Parallel. * * @param type * the note type */ public void setType(byte type) { this.type = type; } /** * Returns the note type - either First, Sequential, or Parallel. * * @return the note type */ public byte getType() { return this.type; } /** Indicates that this note is the first note in the token. */ public static final byte FIRST = 0; /** * Indicates that this note immediately follows a previous note in the same * token. */ public static final byte SEQUENTIAL = 1; /** * Indicates that this note is played at the same time as a previous note in * the same token. */ public static final byte PARALLEL = 2; /** Default value for attack and decay velocity. */ public static final byte DEFAULT_VELOCITY = 64; /** * Returns the Music String representing this element and all of its * settings. For a Note object, the Music String is a note, expressed as * either a letter, <code>note</code>, or a bracketed number, * <code>[<i>note-value</i>], * and a duration, expressed as either a letter, <code>duration</code>, or a * slash followed by a numeric duration, * <code>/<i>decimal-duration</i></code><br /> * If either the attack or decay velocity is set to a value besides the * default, <code>a<i>velocity</i></code> and/or * <code>d<i>velocity</i></code> will be added to the string. If this note * is to be played in sequence or in parallel to another note, a * <code>+</code> or <code>_</code> character will be added as appropriate. * * @return the Music String for this element */ @Override public String getMusicString() { StringBuffer buffy = new StringBuffer(); // If this is a Sequential note or a Parallel note, include that // information. if (SEQUENTIAL == this.type) { buffy.append("_"); } else if (PARALLEL == this.type) { buffy.append("+"); } // Add the note value and duration value // buffy.append("["); // buffy.append(this.value); // buffy.append("]/"); // buffy.append(this.decimalDuration); buffy.append(Note.getStringForNote(this.value, this.decimalDuration)); if (this.attackVelocity != DEFAULT_VELOCITY) { buffy.append("a"); buffy.append(this.attackVelocity); } if (this.decayVelocity != DEFAULT_VELOCITY) { buffy.append("d"); buffy.append(this.decayVelocity); } return buffy.toString(); } /** * Returns verification string in this format: Note: value={#}, * duration={#}, startTie={T|F}, endTie={T|F}, attack={#}, decay={#}, * isFirst={T|F}, isParallel={T|F}, isSequential={T|F} * * @version 4.0 */ @Override public String getVerifyString() { StringBuffer buffy = new StringBuffer(); buffy.append("Note: value="); buffy.append(getValue()); buffy.append(", duration="); buffy.append(getDecimalDuration()); buffy.append(", startTie="); buffy.append(isStartOfTie() ? "T" : "F"); buffy.append(", endTie="); buffy.append(isEndOfTie() ? "T" : "F"); buffy.append(", attack="); buffy.append(getAttackVelocity()); buffy.append(", decay="); buffy.append(getDecayVelocity()); buffy.append(", isFirst="); buffy.append(getType() == FIRST ? "T" : "F"); buffy.append(", isParallel="); buffy.append(getType() == PARALLEL ? "T" : "F"); buffy.append(", isSequential="); buffy.append(getType() == SEQUENTIAL ? "T" : "F"); return buffy.toString(); } public static String createVerifyString(int value, double duration) { return createVerifyString(value, duration, false, false, (byte) 64, (byte) 64, true, false, false); } public static String createVerifyString(int value, double duration, boolean startTie, boolean endTie) { return createVerifyString(value, duration, startTie, endTie, (byte) 64, (byte) 64, true, false, false); } public static String createVerifyString(int value, double duration, int attack, int decay) { return createVerifyString(value, duration, false, false, attack, decay, true, false, false); } public static String createVerifyString(int value, double duration, boolean isFirst, boolean isParallel, boolean isSequential) { return createVerifyString(value, duration, false, false, (byte) 64, (byte) 64, isFirst, isParallel, isSequential); } public static String createVerifyString(int value, double duration, boolean startTie, boolean endTie, int attack, int decay, boolean isFirst, boolean isParallel, boolean isSequential) { StringBuffer buffy = new StringBuffer(); buffy.append("Note: value="); buffy.append(value); buffy.append(", duration="); buffy.append(duration); buffy.append(", startTie="); buffy.append(startTie ? "T" : "F"); buffy.append(", endTie="); buffy.append(endTie ? "T" : "F"); buffy.append(", attack="); buffy.append(attack); buffy.append(", decay="); buffy.append(decay); buffy.append(", isFirst="); buffy.append(isFirst ? "T" : "F"); buffy.append(", isParallel="); buffy.append(isParallel ? "T" : "F"); buffy.append(", isSequential="); buffy.append(isSequential ? "T" : "F"); return buffy.toString(); } /** * Easily create compound note verification strings, like: Note: value=60, * duration=1.0, startTie=F, endTie=F, attack=64, decay=64, isFirst=T, * isParallel=F, isSequential=F; Note: value=63, duration=0.0, startTie=F, * endTie=F, attack=64, decay=64, isFirst=F, isParallel=T, isSequential=F */ public static String createCompoundVerifyString(String... strings) { StringBuffer buffy = new StringBuffer(); for (String string : strings) { buffy.append(string); buffy.append("; "); } return buffy.toString().substring(0, buffy.toString().length() - 2); } /** * Returns a MusicString representation of the given MIDI note value and * duration -- which indicates a note and an octave. * * @param noteValue * this MIDI note value, like 60 * @param decimalDuration * the duration of this note, like 0.5 * @return a MusicString value, like C5h */ public static String getStringForNote(byte noteValue, double decimalDuration) { StringBuffer buffy = new StringBuffer(); buffy.append(getStringForNote(noteValue)); buffy.append(getStringForDuration(decimalDuration)); return buffy.toString(); } /** * Returns the frequency, in Hertz, for the given note value. For example, * the frequency for A5 (MIDI note 69) is 440.0 * * @param noteValue * @return */ public static double getFrequencyForNote(int noteValue) { double freq = 0.0; double freq0 = 8.1757989156; for (double d = 0; d <= noteValue; d++) { freq = freq0 * Math.pow(2.0, d / 12.0); } // Truncate to 4 significant digits double retVal = Math.rint(freq * 10000.0) / 10000.0; return retVal; } /** * Returns a MusicString representation of the given MIDI note value -- * which indicates a note and an octave. * * @param noteValue * this MIDI note value, like 60 * @return a MusicString value, like C5 */ public static String getStringForNote(byte noteValue) { int note = noteValue % 12; int octave = noteValue / 12; StringBuffer buffy = new StringBuffer(); buffy.append(NOTES[note]); buffy.append(octave); return buffy.toString(); } /** * Returns a MusicString representation of a decimal duration. This code * currently only converts single duration values representing whole, half, * quarter, eighth, etc. durations; and dotted durations associated with * those durations (such as "h.", equal to 0.75). This method does not * convert combined durations (for example, "hi" for 0.625) or anything * greater than a duration of 1.0 (for example, "wwww" for 4.0). For these * values, the original decimal duration is returned in a string, prepended * with a "/" to make the returned value a valid MusicString duration * indicator. * * @param decimalDuration * The decimal value of the duration to convert * @return a MusicString fragment representing the duration */ public static String getStringForDuration(double decimalDuration) { if (decimalDuration == 1.0) { return "w"; } else if (decimalDuration == 0.75) { return "h."; } else if (decimalDuration == 0.5) { return "h"; } else if (decimalDuration == 0.375) { return "q."; } else if (decimalDuration == 0.25) { return "q"; } else if (decimalDuration == 0.1875) { return "i."; } else if (decimalDuration == 0.125) { return "i"; } else if (decimalDuration == 0.09375) { return "s."; } else if (decimalDuration == 0.0625) { return "s"; } else if (decimalDuration == 0.046875) { return "t."; } else if (decimalDuration == 0.03125) { return "t"; } else if (decimalDuration == 0.0234375) { return "x."; } else if (decimalDuration == 0.015625) { return "x"; } else if (decimalDuration == 0.01171875) { return "o."; } else if (decimalDuration == 0.0078125) { return "o"; } else { return "/" + decimalDuration; } } /** * Returns the decimal duration that is equal to the given MusicString * representation. This code currently only converts single duration values * representing whole, half, quarter, eighth, etc. durations; and dotted * durations associated with those durations (such as "h.", equal to 0.75). * This method does not convert combined durations (for example, "hi" for * 0.625) or anything greater than a duration of 1.0 (for example, "wwww" * for 4.0). For these values, the original decimal duration is returned in * a string, prepended with a "/" to make the returned value a valid * MusicString duration indicator. * * @param stringDuration * The MusicString duration character (or dotted character) * @return a decimal value representing the duration, expressed as a * fraction of a whole note */ public static double getDecimalForDuration(String stringDuration) { String stringDuration2 = stringDuration.toLowerCase(); if (stringDuration2.equals("w")) { return 1.0; } else if (stringDuration2.equals("h.")) { return 0.75; } else if (stringDuration2.equals("h")) { return 0.5; } else if (stringDuration2.equals("q.")) { return 0.375; } else if (stringDuration2.equals("q")) { return 0.25; } else if (stringDuration2.equals("i.")) { return 0.1875; } else if (stringDuration2.equals("i")) { return 0.125; } else if (stringDuration2.equals("s.")) { return 0.09375; } else if (stringDuration2.equals("s")) { return 0.0625; } else if (stringDuration2.equals("t.")) { return 0.046875; } else if (stringDuration2.equals("t")) { return 0.03125; } else if (stringDuration2.equals("x.")) { return 0.0234375; } else if (stringDuration2.equals("x")) { return 0.015625; } else if (stringDuration2.equals("o.")) { return 0.01171875; } else if (stringDuration2.equals("o")) { return 0.0078125; } else { return 0.0; } } public static final String[] NOTES = new String[] { "C", "C#", "D", "Eb", "E", "F", "F#", "G", "G#", "A", "Bb", "B" }; public static final byte ACOUSTIC_BASS_DRUM = 35; public static final byte BASS_DRUM = 36; public static final byte SIDE_STICK = 37; public static final byte ACOUSTIC_SNARE = 38; public static final byte HAND_CLAP = 39; public static final byte ELECTRIC_SNARE = 40; public static final byte LOW_FLOOR_TOM = 41; public static final byte CLOSED_HI_HAT = 42; public static final byte HIGH_FLOOR_TOM = 43; public static final byte PEDAL_HI_HAT = 44; public static final byte LOW_TOM = 45; public static final byte OPEN_HI_HAT = 46; public static final byte LOW_MID_TOM = 47; public static final byte HI_MID_TOM = 48; public static final byte CRASH_CYMBAL_1 = 49; public static final byte HIGH_TOM = 50; public static final byte RIDE_CYMBAL_1 = 51; public static final byte CHINESE_CYMBAL = 52; public static final byte RIDE_BELL = 53; public static final byte TAMBOURINE = 54; public static final byte SPLASH_CYMBAL = 55; public static final byte COWBELL = 56; public static final byte CRASH_CYMBAL_2 = 57; public static final byte VIBRASLAP = 58; public static final byte RIDE_CYMBAL_2 = 59; public static final byte HI_BONGO = 60; public static final byte LOW_BONGO = 61; public static final byte MUTE_HI_CONGA = 62; public static final byte OPEN_HI_CONGA = 63; public static final byte LOW_CONGA = 64; public static final byte HIGH_TIMBALE = 65; public static final byte LOW_TIMBALE = 66; public static final byte HIGH_AGOGO = 67; public static final byte LOW_AGOGO = 68; public static final byte CABASA = 69; public static final byte MARACAS = 70; public static final byte SHORT_WHISTLE = 71; public static final byte LONG_WHISTLE = 72; public static final byte SHORT_GUIRO = 73; public static final byte LONG_GUIRO = 74; public static final byte CLAVES = 75; public static final byte HI_WOOD_BLOCK = 76; public static final byte LOW_WOOD_BLOCK = 77; public static final byte MUTE_CUICA = 78; public static final byte OPEN_CUICA = 79; public static final byte MUTE_TRIANGLE = 80; public static final byte OPEN_TRIANGLE = 81; } /* * * Here's a handy chart from http://www.borg.com/~jglatt/tutr/notefreq.htm * * MIDI MIDI MIDI Note Frequency Note Frequency Note Frequency C 0 8.1757989156 * 12 16.3515978313 24 32.7031956626 Db 1 8.6619572180 13 17.3239144361 25 * 34.6478288721 D 2 9.1770239974 14 18.3540479948 26 36.7080959897 Eb 3 * 9.7227182413 15 19.4454364826 27 38.8908729653 E 4 10.3008611535 16 * 20.6017223071 28 41.2034446141 F 5 10.9133822323 17 21.8267644646 29 * 43.6535289291 Gb 6 11.5623257097 18 23.1246514195 30 46.2493028390 G 7 * 12.2498573744 19 24.4997147489 31 48.9994294977 Ab 8 12.9782717994 20 * 25.9565435987 32 51.9130871975 A 9 13.7500000000 21 27.5000000000 33 * 55.0000000000 Bb 10 14.5676175474 22 29.1352350949 34 58.2704701898 B 11 * 15.4338531643 23 30.8677063285 35 61.7354126570 * * C 36 65.4063913251 48 130.8127826503 60 261.6255653006 Db 37 69.2956577442 49 * 138.5913154884 61 277.1826309769 D 38 73.4161919794 50 146.8323839587 62 * 293.6647679174 Eb 39 77.7817459305 51 155.5634918610 63 311.1269837221 E 40 * 82.4068892282 52 164.8137784564 64 329.6275569129 F 41 87.3070578583 53 * 174.6141157165 65 349.2282314330 Gb 42 92.4986056779 54 184.9972113558 66 * 369.9944227116 G 43 97.9988589954 55 195.9977179909 67 391.9954359817 Ab 44 * 103.8261743950 56 207.6523487900 68 415.3046975799 A 45 110.0000000000 57 * 220.0000000000 69 440.0000000000 Bb 46 116.5409403795 58 233.0818807590 70 * 466.1637615181 B 47 123.4708253140 59 246.9416506281 71 493.8833012561 * * C 72 523.2511306012 84 1046.5022612024 96 2093.0045224048 Db 73 * 554.3652619537 85 1108.7305239075 97 2217.4610478150 D 74 587.3295358348 86 * 1174.6590716696 98 2349.3181433393 Eb 75 622.2539674442 87 1244.5079348883 99 * 2489.0158697766 E 76 659.2551138257 88 1318.5102276515 100 2637.0204553030 F * 77 698.4564628660 89 1396.9129257320 101 2793.8258514640 Gb 78 739.9888454233 * 90 1479.9776908465 102 2959.9553816931 G 79 783.9908719635 91 1567.9817439270 * 103 3135.9634878540 Ab 80 830.6093951599 92 1661.2187903198 104 * 3322.4375806396 A 81 880.0000000000 93 1760.0000000000 105 3520.0000000000 Bb * 82 932.3275230362 94 1864.6550460724 106 3729.3100921447 B 83 987.7666025122 * 95 1975.5332050245 107 3951.0664100490 * * C 108 4186.0090448096 120 8372.0180896192 Db 109 4434.9220956300 121 * 8869.8441912599 D 110 4698.6362866785 122 9397.2725733570 Eb 111 * 4978.0317395533 123 9956.0634791066 E 112 5274.0409106059 124 * 10548.0818212118 F 113 5587.6517029281 125 11175.3034058561 Gb 114 * 5919.9107633862 126 11839.8215267723 G 115 6271.9269757080 127 * 12543.8539514160 Ab 116 6644.8751612791 A 117 7040.0000000000 Bb 118 * 7458.6201842894 B 119 7902.1328200980 * * Note: Middle C is note #60. Frequency is in Hertz. * * */