Fork of Poseidon providing Bukkit #1060 to older Beta versions (b1.0-b1.7.3)
1package org.bukkit;
2
3import java.util.HashMap;
4import java.util.Map;
5
6/**
7 * A note class to store a specific note.
8 */
9public class Note {
10
11 /**
12 * An enum holding tones.
13 */
14 public enum Tone {
15 F((byte) -0x1, true), G((byte) 0x1, true), A((byte) 0x3, true), B((byte) 0x5, false), C((byte) 0x6, true), D((byte) 0x8, true), E((byte) 0xA, false);
16
17 private final boolean sharpable;
18 private final byte id;
19 private static final Map<Byte, Note.Tone> tones = new HashMap<Byte, Note.Tone>();
20 /**
21 * The number of tones including sharped tones.
22 */
23 public static final byte TONES_COUNT;
24
25 private Tone(byte id, boolean sharpable) {
26 this.id = id;
27 this.sharpable = sharpable;
28 }
29
30 /**
31 * Returns the not sharped id of this tone.
32 *
33 * @return the not sharped id of this tone.
34 */
35 public byte getId() {
36 return getId(false);
37 }
38
39 /**
40 * Returns the id of this tone. These method allows to return the
41 * sharped id of the tone. If the tone couldn't be sharped it always
42 * return the not sharped id of this tone.
43 *
44 * @param sharped Set to true to return the sharped id.
45 * @return the id of this tone.
46 */
47 public byte getId(boolean sharped) {
48 byte tempId = (byte) (sharped && sharpable ? id + 1 : id);
49
50 while (tempId < 0) {
51 tempId += TONES_COUNT;
52 }
53 return (byte) (tempId % TONES_COUNT);
54 }
55
56 /**
57 * Returns if this tone could be sharped.
58 *
59 * @return if this tone could be sharped.
60 */
61 public boolean isSharpable() {
62 return sharpable;
63 }
64
65 /**
66 * Returns if this tone id is the sharped id of the tone.
67 *
68 * @param id the id of the tone.
69 * @return if the tone id is the sharped id of the tone.
70 * @throws IllegalArgumentException if neither the tone nor the semitone have the id.
71 */
72 public boolean isSharped(byte id) {
73 if (id == getId(false)) {
74 return false;
75 } else if (id == getId(true)) {
76 return true;
77 } else {
78 // The id isn't matching to the tone!
79 throw new IllegalArgumentException("The id isn't matching to the tone.");
80 }
81 }
82
83 /**
84 * Returns the tone to id. Also returning the semitones.
85 *
86 * @param id the id of the tone.
87 * @return the tone to id.
88 */
89 public static Tone getToneById(byte id) {
90 return tones.get(id);
91 }
92
93 static {
94 byte lowest = F.id;
95 byte highest = F.id;
96 for (Tone tone : Tone.values()) {
97 byte id = tone.id;
98 tones.put(id, tone);
99 if (id < lowest) {
100 lowest = id;
101 }
102 if (tone.isSharpable()) {
103 id++;
104 tones.put(id, tone);
105 }
106 if (id > highest) {
107 highest = id;
108 }
109 }
110
111 TONES_COUNT = (byte) (highest - lowest + 1);
112 tones.put((byte) (TONES_COUNT - 1), F);
113 }
114 }
115
116 private final byte note;
117
118 /**
119 * Creates a new note.
120 *
121 * @param note Internal note id. {@link #getId()} always return this value.
122 * The value has to be in the interval [0; 24].
123 */
124 public Note(byte note) {
125 if (note < 0 || note > 24) {
126 throw new IllegalArgumentException("The note value has to be between 0 and 24.");
127 }
128 this.note = note;
129 }
130
131 /**
132 * Creates a new note.
133 *
134 * @param octave The octave where the note is in. Has to be 0 - 2.
135 * @param note The tone within the octave. If the octave is 2 the note has to
136 * be F#.
137 * @param sharped Set it the tone is sharped (e.g. for F#).
138 */
139 public Note(byte octave, Tone note, boolean sharped) {
140 if (sharped && !note.isSharpable()) {
141 throw new IllegalArgumentException("This tone could not be sharped.");
142 }
143 if (octave < 0 || octave > 2 || (octave == 2 && !(note == Tone.F && sharped))) {
144 throw new IllegalArgumentException("Tone and octave have to be between F#0 and F#2");
145 }
146 this.note = (byte) (octave * Tone.TONES_COUNT + note.getId(sharped));
147 }
148
149 /**
150 * Returns the internal id of this note.
151 *
152 * @return the internal id of this note.
153 */
154 public byte getId() {
155 return note;
156 }
157
158 /**
159 * Returns the octave of this note.
160 *
161 * @return the octave of this note.
162 */
163 public int getOctave() {
164 return note / Tone.TONES_COUNT;
165 }
166
167 private byte getToneByte() {
168 return (byte) (note % Tone.TONES_COUNT);
169 }
170
171 /**
172 * Returns the tone of this note.
173 *
174 * @return the tone of this note.
175 */
176 public Tone getTone() {
177 return Tone.getToneById(getToneByte());
178 }
179
180 /**
181 * Returns if this note is sharped.
182 *
183 * @return if this note is sharped.
184 */
185 public boolean isSharped() {
186 byte note = getToneByte();
187 return Tone.getToneById(note).isSharped(note);
188 }
189
190}