All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bukkit.Note Maven / Gradle / Ivy

package org.bukkit;

import com.google.common.collect.Maps;
import org.apache.commons.lang.Validate;

import java.util.Map;

/**
 * A note class to store a specific note.
 */
public class Note {

  private final byte note;

  /**
   * Creates a new note.
   *
   * @param note Internal note id. {@link #getId()} always return this
   *             value. The value has to be in the interval [0; 24].
   */
  public Note(int note) {
    Validate.isTrue(note >= 0 && note <= 24, "The note value has to be between 0 and 24.");

    this.note = (byte) note;
  }

  /**
   * Creates a new note.
   *
   * @param octave  The octave where the note is in. Has to be 0 - 2.
   * @param tone    The tone within the octave. If the octave is 2 the note has
   *                to be F#.
   * @param sharped Set if the tone is sharped (e.g. for F#).
   */
  public Note(int octave, Tone tone, boolean sharped) {
    if (sharped && !tone.isSharpable()) {
      tone = Tone.values()[tone.ordinal() + 1];
      sharped = false;
    }
    if (octave < 0 || octave > 2 || (octave == 2 && !(tone == Tone.F && sharped))) {
      throw new IllegalArgumentException("Tone and octave have to be between F#0 and F#2");
    }

    this.note = (byte) (octave * Tone.TONES_COUNT + tone.getId(sharped));
  }

  /**
   * Creates a new note for a flat tone, such as A-flat.
   *
   * @param octave The octave where the note is in. Has to be 0 - 1.
   * @param tone   The tone within the octave.
   * @return The new note.
   */
  public static Note flat(int octave, Tone tone) {
    Validate.isTrue(octave != 2, "Octave cannot be 2 for flats");
    tone = tone == Tone.G ? Tone.F : Tone.values()[tone.ordinal() - 1];
    return new Note(octave, tone, tone.isSharpable());
  }

  /**
   * Creates a new note for a sharp tone, such as A-sharp.
   *
   * @param octave The octave where the note is in. Has to be 0 - 2.
   * @param tone   The tone within the octave. If the octave is 2 the note has
   *               to be F#.
   * @return The new note.
   */
  public static Note sharp(int octave, Tone tone) {
    return new Note(octave, tone, true);
  }

  /**
   * Creates a new note for a natural tone, such as A-natural.
   *
   * @param octave The octave where the note is in. Has to be 0 - 1.
   * @param tone   The tone within the octave.
   * @return The new note.
   */
  public static Note natural(int octave, Tone tone) {
    Validate.isTrue(octave != 2, "Octave cannot be 2 for naturals");
    return new Note(octave, tone, false);
  }

  /**
   * @return The note a semitone above this one.
   */
  public Note sharped() {
    Validate.isTrue(note < 24, "This note cannot be sharped because it is the highest known note!");
    return new Note(note + 1);
  }

  /**
   * @return The note a semitone below this one.
   */
  public Note flattened() {
    Validate.isTrue(note > 0, "This note cannot be flattened because it is the lowest known note!");
    return new Note(note - 1);
  }

  /**
   * Returns the internal id of this note.
   *
   * @return the internal id of this note.
   * @deprecated Magic value
   */
  @Deprecated
  public byte getId() {
    return note;
  }

  /**
   * Returns the octave of this note.
   *
   * @return the octave of this note.
   */
  public int getOctave() {
    return note / Tone.TONES_COUNT;
  }

  private byte getToneByte() {
    return (byte) (note % Tone.TONES_COUNT);
  }

  /**
   * Returns the tone of this note.
   *
   * @return the tone of this note.
   */
  public Tone getTone() {
    return Tone.getById(getToneByte());
  }

  /**
   * Returns if this note is sharped.
   *
   * @return if this note is sharped.
   */
  public boolean isSharped() {
    byte note = getToneByte();
    return Tone.getById(note).isSharped(note);
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + note;
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    Note other = (Note) obj;
    return note == other.note;
  }

  @Override
  public String toString() {
    return "Note{" + getTone().toString() + (isSharped() ? "#" : "") + "}";
  }

  /**
   * An enum holding tones.
   */
  public enum Tone {
    G(0x1, true),
    A(0x3, true),
    B(0x5, false),
    C(0x6, true),
    D(0x8, true),
    E(0xA, false),
    F(0xB, true);

    /**
     * The number of tones including sharped tones.
     */
    public static final byte TONES_COUNT = 12;
    private static final Map BY_DATA = Maps.newHashMap();

    static {
      for (Tone tone : values()) {
        int id = tone.id % TONES_COUNT;
        BY_DATA.put((byte) id, tone);

        if (tone.isSharpable()) {
          id = (id + 1) % TONES_COUNT;
          BY_DATA.put((byte) id, tone);
        }
      }
    }

    private final boolean sharpable;
    private final byte id;

    Tone(int id, boolean sharpable) {
      this.id = (byte) (id % TONES_COUNT);
      this.sharpable = sharpable;
    }

    /**
     * Returns the tone to id. Also returning the semitones.
     *
     * @param id the id of the tone.
     * @return the tone to id.
     * @deprecated Magic value
     */
    @Deprecated
    public static Tone getById(byte id) {
      return BY_DATA.get(id);
    }

    /**
     * Returns the not sharped id of this tone.
     *
     * @return the not sharped id of this tone.
     * @deprecated Magic value
     */
    @Deprecated
    public byte getId() {
      return getId(false);
    }

    /**
     * Returns the id of this tone. These method allows to return the
     * sharped id of the tone. If the tone couldn't be sharped it always
     * return the not sharped id of this tone.
     *
     * @param sharped Set to true to return the sharped id.
     * @return the id of this tone.
     * @deprecated Magic value
     */
    @Deprecated
    public byte getId(boolean sharped) {
      byte id = (byte) (sharped && sharpable ? this.id + 1 : this.id);

      return (byte) (id % TONES_COUNT);
    }

    /**
     * Returns if this tone could be sharped.
     *
     * @return if this tone could be sharped.
     */
    public boolean isSharpable() {
      return sharpable;
    }

    /**
     * Returns if this tone id is the sharped id of the tone.
     *
     * @param id the id of the tone.
     * @return if the tone id is the sharped id of the tone.
     * @throws IllegalArgumentException if neither the tone nor the
     *                                  semitone have the id.
     * @deprecated Magic value
     */
    @Deprecated
    public boolean isSharped(byte id) {
      if (id == getId(false)) {
        return false;
      } else if (id == getId(true)) {
        return true;
      } else {
        // The id isn't matching to the tone!
        throw new IllegalArgumentException("The id isn't matching to the tone.");
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy