com.rockhoppertech.music.Pitch.java Source code

Java tutorial

Introduction

Here is the source code for com.rockhoppertech.music.Pitch.java

Source

package com.rockhoppertech.music;

/*
 * #%L
 * Rocky Music Core
 * %%
 * Copyright (C) 1996 - 2013 Rockhopper Technologies
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

import java.io.Serializable;
import java.util.Comparator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>
 * A representation of musical frequency (Pitch).
 * <p>
 * <p>
 * Internally represented by a midi number. The frequency is calculated based on
 * the MIDI number.
 * </p>
 * 
 * See http://en.wikipedia.org/wiki/Scientific_pitch_notation
 * 
 * For MusicXML, Common Lisp Music and others the octave is "off" by 1. In MIDI
 * middle c is C5, for them it is C4.
 * 
 * <p>
 * For equal temperament you should use the PitchFactory to obtain instances a
 * la the GoF Flyweight design pattern. (Most likely you will have zillions of
 * instances of Pitch in your program. The Flyweight helps this problem).
 * </p>
 * 
 * 
 * @author <a href="http://genedelisa.com/">Gene De Lisa</a>
 * @version 1.0 Mon Aug 10, 1998
 * @see com.rockhoppertech.music.PitchFactory
 * @see com.rockhoppertech.music.PitchFormat
 */

public class Pitch implements Serializable, Comparable<Pitch> {
    /**
     * 
     */
    private static final long serialVersionUID = -4983186242989608159L;
    private static final Logger logger = LoggerFactory.getLogger(Pitch.class);

    /**
     * The main datum.
     */
    private int midiNumber;

    private String preferredSpelling;

    private short cents;
    /**
     * Equal temperament frequency for the midiNumber
     */
    private double frequency;

    /**
     * 0 if not microtonal
     */
    private short pitchBend;

    /**
     * middle c or 261.6255653005986 hz Used to calculate the frequency.
     */
    public static final double REF_PITCH = 220d * Math.pow(2d, (3d / 12d));

    /**
     * <p>
     * Use the PitchFactory to get an instance instead. Use this only in special
     * circumstances
     * </p>
     * <p>
     * Midi number will be 0.
     * </p>
     */
    public Pitch() {
        this(0);
    }

    /**
     * <p>
     * Use the PitchFactory to get an instance instead. Use this only in special
     * circumstances
     * </p>
     * <p>
     * Can use a constant.
     * <p>
     * 
     * {@code
     * new Pitch(Pitch.C5);
    * }
     * 
     * @param n
     *            the midi number to use. 60 is middle c.
     */
    public Pitch(int n) {
        if (n < 0 || n > 127) {
            throw new IllegalArgumentException("MIDI number out of range " + n);
        }
        midiNumber = n;
        // this.frequency = Pitch.midiFq(this.midiNumber);
        frequency = PitchFactory.EQUAL_TEMPERAMENT.get(midiNumber);
        this.preferredSpelling = PitchFormat.getInstance().format(n);
        logger.debug("spelling '{}'", this.preferredSpelling);
    }

    /**
     * <p>
     * Use the PitchFactory to get an instance instead. Use this only in special
     * circumstances
     * </p>
     * <p>
     * Parses a string representation of the pitch using PitchFormat. Also sets
     * the frequency.
     * </p>
     * 
     * {@link com.rockhoppertech.music.PitchFormat}
     * 
     * @param s
     *            String the pitch string like c#5
     */
    public Pitch(String s) {
        midiNumber = PitchFormat.stringToMidiNumber(s);
        frequency = PitchFactory.EQUAL_TEMPERAMENT.get(midiNumber);
        this.preferredSpelling = s;
    }

    /**
     * @return the internal midi number
     */
    public int getMidiNumber() {
        return midiNumber;
    }

    /**
     * Sets the midi number and frequency.
     * 
     * @param n
     *            the midi number
     */
    public void setMidiNumber(int n) {
        midiNumber = n;
        frequency = PitchFactory.EQUAL_TEMPERAMENT.get(midiNumber);
    }

    /**
     * Describe <code>getFrequency</code> method here.
     * 
     * @return a <code>double</code> value
     */
    public double getFrequency() {
        return frequency;
    }

    /**
     * <p>
     * <code>transpose</code> pitch up or down by the specified number of minor
     * seconds (half steps). Can use constants.
     * </p>
     * <p>
     * This uses the PitchFactory to return the appropriate instance. The object
     * that is the receiver of this message is not affected in any way.
     * </p>
     * {@code
     * p.transpose(Pitch.TRITONE);
     * p.transpose(Pitch.MAJOR_SEVENTH);
    * }
     * 
     * @param minorSeconds
     *            The value added with the receiver's midinumber. Can be
     *            negative to transpose down.
     * @return the transposed Pitch
     */
    public Pitch transpose(int minorSeconds) {
        int n = midiNumber + minorSeconds;
        Pitch p = PitchFactory.getPitch(n);
        logger.debug(String.format("transposed to %d", n));
        return p;
    }

    /*
     * <p>If you want to use a JSpinner list model and you don't want to write a
     * spinner editor, just return the pitch name here.
     * 
     * </p>
     * 
     * @see toProlixString() for a longer version
     * 
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return PitchFormat.getInstance().format(this);
    }

    public String toProlixString() {
        StringBuilder sb = new StringBuilder();
        sb.append("Pitch[");
        sb.append("midiNumber=").append(midiNumber);
        sb.append(" frequency=").append(frequency);
        sb.append(" cents=").append(cents);
        sb.append(" pitchBend=").append(pitchBend);
        sb.append("]");
        return sb.toString();
    }

    /**
     * Check to see if the pitch is diatonic or not.
     * 
     * @param num
     *            The midi number
     * @return whether it is an accidental
     */
    public static boolean isAccidental(int num) {
        boolean r = false;
        switch (num % 12) {
        case 1:
        case 3:
        case 6:
        case 8:
        case 10:
            r = true;
            break;
        default:
            r = false;
            break;
        }
        return r;
    }

    public final static int REGEX_FLAGS = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.CANON_EQ;

    public static boolean isSharp(String pitchName) {
        String sharpNoteNameRegexp = "([A-G])(#|s|x)";
        Pattern pattern = Pattern.compile(sharpNoteNameRegexp, REGEX_FLAGS);
        Matcher match = pattern.matcher(pitchName);
        if (match.matches()) {
            logger.debug("{} matches", pitchName);
            return true;
        }
        return false;
    }

    public static boolean isFlat(String pitchName) {
        String flatNoteNameRegexp = "([A-G])(-|b|f)";
        Pattern pattern = Pattern.compile(flatNoteNameRegexp, REGEX_FLAGS);
        Matcher match = pattern.matcher(pitchName);
        if (match.matches()) {
            logger.debug("{} matches", pitchName);
            return true;
        }
        return false;
    }

    /**
     * <p>
     * Calculate frequency of a pitch class/octave pair.
     * </p>
     * 
     * @param pitch
     *            the pitch class
     * @param oct
     *            the octave. 6.0 is middle C's octave
     * @return the frequency
     */
    public static double midiFq(double pitch, double oct) {
        return (REF_PITCH * Math.pow(2d, (oct - 5d)) * Math.pow(2d, (pitch / 12d)));
    }

    /**
     * Calculate equal tempered frequency of a midi note. The PitchFactory
     * contains a cached table of Equal Temp. pitches. so use that instead of
     * this method.
     * 
     * Called by {@code PitchFactory} when calculating {@code EQUAL_TEMPERAMENT}
     * .
     * 
     * <pre>
     * {@code
    * frequency = PitchFactory.EQUAL_TEMPERAMENT.get(this.midiNumber);
    * }
    * </pre>
     * 
     * @param midiNoteNumber
     *            an <code>int</code> value
     * @return the frequency
     */
    public static double midiFq(int midiNoteNumber) {
        int pitch = midiNoteNumber / 12;
        int oct = midiNoteNumber % 12;
        double dp = pitch - 5d;
        double doct = oct / 12d;
        return (REF_PITCH * Math.pow(2d, dp) * Math.pow(2d, doct));
    }

    /*
     * <p>Uses the MIDI number for natural ordering. </p>
     * 
     * @see java.lang.Comparable#compareTo(java.lang.Object)
     */
    @Override
    public int compareTo(Pitch other) {

        int val = 0;
        if (getMidiNumber() == other.getMidiNumber()) {
            val = 0;
        } else if (getMidiNumber() < other.getMidiNumber()) {
            val = -1;
        } else {
            val = 1;
        }
        return val;
    }

    public enum P {
        C0(0), CS0(1), DF0(1), D0(2), DS0(3), EF0(3), E0(4), F0(5), FS0(6), GF0(6), G0(7), GS0(8), AF0(8), A0(
                9), AS0(10), BF0(10), B0(11),

        C1(12), CS1(13), DF1(13), D1(14), DS1(15), EF1(15), E1(16), F1(17), FS1(18), GF1(18), G1(19), GS1(20), AF1(
                20), A1(21), AS1(22), BF1(22), B1(23),

        C2(24), CS2(25), DF2(25), D2(26), DS2(27), EF2(27), E2(28), F2(29), FS2(30), GF2(30), G2(31), GS2(32), AF2(
                32), A2(33), AS2(34), BF2(34), B2(35),

        C3(36), CS3(37), DF3(37), D3(38), DS3(39), EF3(39), E3(40), F3(41), FS3(42), GF3(42), G3(43), GS3(44), AF3(
                44), A3(45), AS3(46), BF3(46), B3(47),

        C4(48), CS4(49), DF4(49), D4(50), DS4(51), EF4(51), E4(52), F4(53), FS4(54), GF4(54), G4(55), GS4(56), AF4(
                56), A4(57), AS4(58), BF4(58), B4(59),

        C5(60), MIDDLE_C(60), CS5(61), DF5(61), D5(62), DS5(63), EF5(63), E5(64), F5(65), FS5(66), GF5(66), G5(
                67), GS5(68), AF5(68), A5(69), AS5(70), BF5(70), B5(71),

        C6(72), CS6(73), DF6(73), D6(74), DS6(75), EF6(75), E6(76), F6(77), FS6(78), GF6(78), G6(79), GS6(80), AF6(
                80), A6(81), AS6(82), BF6(82), B6(83),

        C7(84), CS7(85), DF7(85), D7(86), DS7(87), EF7(87), E7(88), F7(89), FS7(90), GF7(90), G7(91), GS7(92), AF7(
                92), A7(93), AS7(94), BF7(94), B7(95),

        C8(96), CS8(97), DF8(97), D8(98), DS8(99), EF8(99), E8(100), F8(101), FS8(102), GF8(102), G8(103), GS8(
                104), AF8(104), A8(105), AS8(106), BF8(106), B8(107),

        C9(108), CS9(109), DF9(109), D9(110), DS9(111), EF9(111), E9(112), F9(113), FS9(114), GF9(114), G9(
                115), GS9(116), AF9(116), A9(117), AS9(118), BF9(118), B9(119),

        C10(120), CS10(121), DF10(121), D10(122), DS10(123), EF10(123), E10(124), F10(125), FS10(126), GF10(
                126), G10(127);

        private int value;

        private P(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }

        public void setValue(int value) {
            this.value = value;
        }

        // all this nonsense just to change middle C from C5 to something else
        // like C4
        // TODO would be better if the Pitch class itself were an enum instad of
        // class?
        private void plus(int amt) {
            value += amt;
        }

        public void add12() {
            P[] a = Pitch.P.class.getEnumConstants();
            for (P p : a) {
                p.plus(12);
            }
        }

        private void minus(int amt) {
            value -= amt;
        }

        public void sub12() {
            P[] a = Pitch.P.class.getEnumConstants();
            for (P p : a) {
                p.minus(12);
            }
        }
    }

    public static final int C0 = 0;
    public static final int CS0 = 1;
    public static final int DF0 = 1;
    public static final int D0 = 2;
    public static final int DS0 = 3;
    public static final int EF0 = 3;
    public static final int E0 = 4;
    public static final int F0 = 5;
    public static final int FS0 = 6;
    public static final int GF0 = 6;
    public static final int G0 = 7;
    public static final int GS0 = 8;
    public static final int AF0 = 8;
    public static final int A0 = 9;
    public static final int AS0 = 10;
    public static final int BF0 = 10;
    public static final int B0 = 11;

    public static final int C1 = 12;
    public static final int CS1 = 13;
    public static final int DF1 = 13;
    public static final int D1 = 14;
    public static final int DS1 = 15;
    public static final int EF1 = 15;
    public static final int E1 = 16;
    public static final int F1 = 17;
    public static final int FS1 = 18;
    public static final int GF1 = 18;
    public static final int G1 = 19;
    public static final int GS1 = 20;
    public static final int AF1 = 20;
    public static final int A1 = 21;
    public static final int AS1 = 22;
    public static final int BF1 = 22;
    public static final int B1 = 23;

    public static final int C2 = 24;
    public static final int CS2 = 25;
    public static final int DF2 = 25;
    public static final int D2 = 26;
    public static final int DS2 = 27;
    public static final int EF2 = 27;
    public static final int E2 = 28;
    public static final int F2 = 29;
    public static final int FS2 = 30;
    public static final int GF2 = 30;
    public static final int G2 = 31;
    public static final int GS2 = 32;
    public static final int AF2 = 32;
    public static final int A2 = 33;
    public static final int AS2 = 34;
    public static final int BF2 = 34;
    public static final int B2 = 35;

    public static final int C3 = 36;
    public static final int CS3 = 37;
    public static final int DF3 = 37;
    public static final int D3 = 38;
    public static final int DS3 = 39;
    public static final int EF3 = 39;
    public static final int E3 = 40;
    public static final int F3 = 41;
    public static final int FS3 = 42;
    public static final int GF3 = 42;
    public static final int G3 = 43;
    public static final int GS3 = 44;
    public static final int AF3 = 44;
    public static final int A3 = 45;
    public static final int AS3 = 46;
    public static final int BF3 = 46;
    public static final int B3 = 47;

    public static final int C4 = 48;
    public static final int CS4 = 49;
    public static final int DF4 = 49;
    public static final int D4 = 50;
    public static final int DS4 = 51;
    public static final int EF4 = 51;
    public static final int E4 = 52;
    public static final int F4 = 53;
    public static final int FS4 = 54;
    public static final int GF4 = 54;
    public static final int G4 = 55;
    public static final int GS4 = 56;
    public static final int AF4 = 56;
    public static final int A4 = 57;
    public static final int AS4 = 58;
    public static final int BF4 = 58;
    public static final int B4 = 59;

    public static final int C5 = 60;
    public static final int MIDDLE_C = 60;
    public static final int CS5 = 61;
    public static final int DF5 = 61;
    public static final int D5 = 62;
    public static final int DS5 = 63;
    public static final int EF5 = 63;
    public static final int E5 = 64;
    public static final int F5 = 65;
    public static final int FS5 = 66;
    public static final int GF5 = 66;
    public static final int G5 = 67;
    public static final int GS5 = 68;
    public static final int AF5 = 68;
    public static final int A5 = 69;
    public static final int AS5 = 70;
    public static final int BF5 = 70;
    public static final int B5 = 71;

    public static final int C6 = 72;
    public static final int CS6 = 73;
    public static final int DF6 = 73;
    public static final int D6 = 74;
    public static final int DS6 = 75;
    public static final int EF6 = 75;
    public static final int E6 = 76;
    public static final int F6 = 77;
    public static final int FS6 = 78;
    public static final int GF6 = 78;
    public static final int G6 = 79;
    public static final int GS6 = 80;
    public static final int AF6 = 80;
    public static final int A6 = 81;
    public static final int AS6 = 82;
    public static final int BF6 = 82;
    public static final int B6 = 83;

    public static final int C7 = 84;
    public static final int CS7 = 85;
    public static final int DF7 = 85;
    public static final int D7 = 86;
    public static final int DS7 = 87;
    public static final int EF7 = 87;
    public static final int E7 = 88;
    public static final int F7 = 89;
    public static final int FS7 = 90;
    public static final int GF7 = 90;
    public static final int G7 = 91;
    public static final int GS7 = 92;
    public static final int AF7 = 92;
    public static final int A7 = 93;
    public static final int AS7 = 94;
    public static final int BF7 = 94;
    public static final int B7 = 95;

    public static final int C8 = 96;
    public static final int CS8 = 97;
    public static final int DF8 = 97;
    public static final int D8 = 98;
    public static final int DS8 = 99;
    public static final int EF8 = 99;
    public static final int E8 = 100;
    public static final int F8 = 101;
    public static final int FS8 = 102;
    public static final int GF8 = 102;
    public static final int G8 = 103;
    public static final int GS8 = 104;
    public static final int AF8 = 104;
    public static final int A8 = 105;
    public static final int AS8 = 106;
    public static final int BF8 = 106;
    public static final int B8 = 107;

    public static final int C9 = 108;
    public static final int CS9 = 109;
    public static final int DF9 = 109;
    public static final int D9 = 110;
    public static final int DS9 = 111;
    public static final int EF9 = 111;
    public static final int E9 = 112;
    public static final int F9 = 113;
    public static final int FS9 = 114;
    public static final int GF9 = 114;
    public static final int G9 = 115;
    public static final int GS9 = 116;
    public static final int AF9 = 116;
    public static final int A9 = 117;
    public static final int AS9 = 118;
    public static final int BF9 = 118;
    public static final int B9 = 119;

    public static final int C10 = 120;
    public static final int CS10 = 121;
    public static final int DF10 = 121;
    public static final int D10 = 122;
    public static final int DS10 = 123;
    public static final int EF10 = 123;
    public static final int E10 = 124;
    public static final int F10 = 125;
    public static final int FS10 = 126;
    public static final int GF10 = 126;
    public static final int G10 = 127;

    public static final int MIN = C0;
    public static final int MAX = G10;

    public static final int MINOR_SECOND = 1;
    public static final int MAJOR_SECOND = 2;
    public static final int MINOR_THIRD = 3;
    public static final int MAJOR_THIRD = 4;
    public static final int PERFECT_FOURTH = 5;
    public static final int TRITONE = 6;
    public static final int PERFECT_FIFTH = 7;
    public static final int MINOR_SIXTH = 8;
    public static final int MAJOR_SIXTH = 9;
    public static final int MINOR_SEVENTH = 10;
    public static final int MAJOR_SEVENTH = 11;
    public static final int OCTAVE = 12;

    /*
     * <p>See Effective Java. </p>
     * 
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = PRIME * result + midiNumber;
        return result;
    }

    /*
     * <p>Compares just MIDI number. </p>
     * 
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Pitch other = (Pitch) obj;
        if (midiNumber != other.midiNumber) {
            return false;
        }
        return true;
    }

    /**
     * @return the cents
     */
    public short getCents() {
        return cents;
    }

    /**
     * @param cents
     *            the cents to set
     */
    public void setCents(short cents) {
        this.cents = cents;
    }

    /**
     * @param frequency
     *            the frequency to set
     */
    public void setFrequency(double frequency) {
        this.frequency = frequency;
    }

    public short getPitchBend() {
        return pitchBend;
    }

    public void setPitchBend(short pitchBend) {
        this.pitchBend = pitchBend;
    }

    public int getPitchClass() {
        return midiNumber % 12;
    }

    public Set<String> getSynonyms() {
        return Pitch.getSynonyms(midiNumber);
    }

    /**
     * 
     * Here is a JUnit example. <code>
     * assertThat(somePitch.getSynonymsForPitchClass(), hasItem("Db"));
     * </code>
     * 
     * @return a {@code Set} of synonyms
     */
    public Set<String> getSynonymsForPitchClass() {
        return Pitch.getSynonyms(midiNumber % 12);
    }

    public static Set<String> getSynonyms(int midiNumber) {
        Set<String> syn = new TreeSet<String>();
        for (Map.Entry<String, Integer> entry : nameMap.entrySet()) {
            if (entry.getValue() == midiNumber) {
                // don't really feel like writing custom JUnit matchers
                String key = entry.getKey();
                syn.add(key);
                syn.add(key.toLowerCase(Locale.ENGLISH));
                syn.add(key.toUpperCase(Locale.ENGLISH));
                syn.add(StringUtils.capitalize(key.toLowerCase(Locale.ENGLISH)));
            }
        }
        return syn;
    }

    // this is the fastest and easiest. a pain to set up but now its set up.
    public static final Map<String, Integer> nameMap = new TreeMap<String, Integer>();
    static {
        nameMap.put("C", 0);
        nameMap.put("CS", 1);
        nameMap.put("Cs", 1);
        nameMap.put("C#", 1);
        nameMap.put("DF", 1);
        nameMap.put("Df", 1);
        nameMap.put("DB", 1);
        nameMap.put("D", 2);
        nameMap.put("DS", 3);
        nameMap.put("Ds", 3);
        nameMap.put("D#", 3);
        nameMap.put("EF", 3);
        nameMap.put("Ef", 3);
        nameMap.put("EB", 3);
        nameMap.put("E", 4);
        nameMap.put("F", 5);
        nameMap.put("FS", 6);
        nameMap.put("Fs", 6);
        nameMap.put("F#", 6);
        nameMap.put("GF", 6);
        nameMap.put("Gf", 6);
        nameMap.put("GB", 6);
        nameMap.put("G", 7);
        nameMap.put("GS", 8);
        nameMap.put("Gs", 8);
        nameMap.put("G#", 8);
        nameMap.put("AF", 8);
        nameMap.put("Af", 8);
        nameMap.put("AB", 8);
        nameMap.put("A", 9);
        nameMap.put("AS", 10);
        nameMap.put("As", 10);
        nameMap.put("A#", 10);
        nameMap.put("BF", 10);
        nameMap.put("Bf", 10);
        nameMap.put("BB", 10);
        nameMap.put("B", 11);
        nameMap.put("CB", 11);
        nameMap.put("CF", 11);
        nameMap.put("Cf", 11);

        nameMap.put("C0", 0);
        nameMap.put("CS0", 1);
        nameMap.put("C#0", 1);
        nameMap.put("DF0", 1);
        nameMap.put("Df0", 1);
        nameMap.put("DB0", 1);
        nameMap.put("D0", 2);
        nameMap.put("DS0", 3);
        nameMap.put("D#0", 3);
        nameMap.put("EF0", 3);
        nameMap.put("Ef0", 3);
        nameMap.put("EB0", 3);
        nameMap.put("E0", 4);
        nameMap.put("F0", 5);
        nameMap.put("FS0", 6);
        nameMap.put("F#0", 6);
        nameMap.put("GF0", 6);
        nameMap.put("Gf0", 6);
        nameMap.put("GB0", 6);
        nameMap.put("G0", 7);
        nameMap.put("GS0", 8);
        nameMap.put("G#0", 8);
        nameMap.put("AF0", 8);
        nameMap.put("Af0", 8);
        nameMap.put("AB0", 8);
        nameMap.put("A0", 9);
        nameMap.put("AS0", 10);
        nameMap.put("A#0", 10);
        nameMap.put("BF0", 10);
        nameMap.put("Bf0", 10);
        nameMap.put("BB0", 10);
        nameMap.put("B0", 11);

        nameMap.put("CF1", 11);
        nameMap.put("Cf1", 11);
        nameMap.put("CB1", 11);
        nameMap.put("C1", 12);
        nameMap.put("CS1", 13);
        nameMap.put("C#1", 13);
        nameMap.put("DF1", 13);
        nameMap.put("DB1", 13);
        nameMap.put("D1", 14);
        nameMap.put("DS1", 15);
        nameMap.put("D#1", 15);
        nameMap.put("EF1", 15);
        nameMap.put("EB1", 15);
        nameMap.put("E1", 16);
        nameMap.put("F1", 17);
        nameMap.put("FS1", 18);
        nameMap.put("F#1", 18);
        nameMap.put("GF1", 18);
        nameMap.put("GB1", 18);
        nameMap.put("G1", 19);
        nameMap.put("GS1", 20);
        nameMap.put("G#1", 20);
        nameMap.put("AF1", 20);
        nameMap.put("AB1", 20);
        nameMap.put("A1", 21);
        nameMap.put("AS1", 22);
        nameMap.put("A#1", 22);
        nameMap.put("BF1", 22);
        nameMap.put("BB1", 22);
        nameMap.put("B1", 23);

        nameMap.put("CF2", 23);
        nameMap.put("Cf2", 23);
        nameMap.put("CB2", 23);
        nameMap.put("C2", 24);
        nameMap.put("CS2", 25);
        nameMap.put("C#2", 25);
        nameMap.put("DF2", 25);
        nameMap.put("DB2", 25);
        nameMap.put("D2", 26);
        nameMap.put("DS2", 27);
        nameMap.put("D#2", 27);
        nameMap.put("EF2", 27);
        nameMap.put("EB2", 27);
        nameMap.put("E2", 28);
        nameMap.put("F2", 29);
        nameMap.put("FS2", 30);
        nameMap.put("F#2", 30);
        nameMap.put("GF2", 30);
        nameMap.put("GB2", 30);
        nameMap.put("G2", 31);
        nameMap.put("GS2", 32);
        nameMap.put("G#2", 32);
        nameMap.put("AF2", 32);
        nameMap.put("AB2", 32);
        nameMap.put("A2", 33);
        nameMap.put("AS2", 34);
        nameMap.put("A#2", 34);
        nameMap.put("BF2", 34);
        nameMap.put("BB2", 34);
        nameMap.put("B2", 35);

        nameMap.put("CF3", 35);
        nameMap.put("Cf3", 35);
        nameMap.put("CB3", 35);
        nameMap.put("C3", 36);
        nameMap.put("CS3", 37);
        nameMap.put("C#3", 37);
        nameMap.put("DF3", 37);
        nameMap.put("DB3", 37);
        nameMap.put("D3", 38);
        nameMap.put("DS3", 39);
        nameMap.put("D#3", 39);
        nameMap.put("EF3", 39);
        nameMap.put("EB3", 39);
        nameMap.put("E3", 40);
        nameMap.put("F3", 41);
        nameMap.put("FS3", 42);
        nameMap.put("F#3", 42);
        nameMap.put("GF3", 42);
        nameMap.put("GB3", 42);
        nameMap.put("G3", 43);
        nameMap.put("GS3", 44);
        nameMap.put("G#3", 44);
        nameMap.put("AF3", 44);
        nameMap.put("AB3", 44);
        nameMap.put("A3", 45);
        nameMap.put("AS3", 46);
        nameMap.put("A#3", 46);
        nameMap.put("BF3", 46);
        nameMap.put("BB3", 46);
        nameMap.put("B3", 47);

        nameMap.put("CF4", 47);
        nameMap.put("Cf4", 47);
        nameMap.put("CB4", 47);
        nameMap.put("C4", 48);
        nameMap.put("CS4", 49);
        nameMap.put("C#4", 49);
        nameMap.put("DF4", 49);
        nameMap.put("Df4", 49);
        nameMap.put("DB4", 49);
        nameMap.put("D4", 50);
        nameMap.put("DS4", 51);
        nameMap.put("D#4", 51);
        nameMap.put("EF4", 51);
        nameMap.put("Ef4", 51);
        nameMap.put("EB4", 51);
        nameMap.put("E4", 52);
        nameMap.put("F4", 53);
        nameMap.put("FS4", 54);
        nameMap.put("F#4", 54);
        nameMap.put("GF4", 54);
        nameMap.put("Gf4", 54);
        nameMap.put("GB4", 54);
        nameMap.put("G4", 55);
        nameMap.put("GS4", 56);
        nameMap.put("G#4", 56);
        nameMap.put("AF4", 56);
        nameMap.put("Af4", 56);
        nameMap.put("AB4", 56);
        nameMap.put("A4", 57);
        nameMap.put("AS4", 58);
        nameMap.put("A#4", 58);
        nameMap.put("BF4", 58);
        nameMap.put("Bf4", 58);
        nameMap.put("BB4", 58);
        nameMap.put("B4", 59);

        // changed PitchFactory.getPitchByName to lookup in uppercase
        // so the lc versions are not needed
        nameMap.put("CF5", B4);
        nameMap.put("Cf5", B4);
        nameMap.put("CB5", B4);
        nameMap.put("C5", C5);
        nameMap.put("C#5", CS5);
        nameMap.put("CS5", CS5);
        nameMap.put("DF5", CS5);
        nameMap.put("Df5", CS5);
        nameMap.put("DB5", CS5);
        nameMap.put("D5", D5);
        nameMap.put("DS5", 63);
        nameMap.put("D#5", 63);
        nameMap.put("EF5", 63);
        nameMap.put("Ef5", 63);
        nameMap.put("EB5", 63);
        nameMap.put("E5", 64);
        nameMap.put("F5", 65);
        nameMap.put("FS5", 66);
        nameMap.put("F#5", 66);
        nameMap.put("GF5", 66);
        nameMap.put("Gf5", 66);
        nameMap.put("GB5", 66);
        nameMap.put("G5", 67);
        nameMap.put("GS5", 68);
        nameMap.put("G#5", 68);
        nameMap.put("AF5", 68);
        nameMap.put("Af5", 68);
        nameMap.put("AB5", 68);
        nameMap.put("A5", 69);
        nameMap.put("AS5", 70);
        nameMap.put("A#5", 70);
        nameMap.put("BF5", 70);
        nameMap.put("Bf5", 70);
        nameMap.put("BB5", 70);
        nameMap.put("B5", 71);

        nameMap.put("CF6", 71);
        nameMap.put("Cf6", 71);
        nameMap.put("CB6", 71);
        nameMap.put("C6", 72);
        nameMap.put("CS6", 73);
        nameMap.put("C#6", 73);
        nameMap.put("DF6", 73);
        nameMap.put("Df6", 73);
        nameMap.put("DB6", 73);
        nameMap.put("D6", 74);
        nameMap.put("DS6", 75);
        nameMap.put("D#6", 75);
        nameMap.put("EF6", 75);
        nameMap.put("Ef6", 75);
        nameMap.put("EB6", 75);
        nameMap.put("E6", 76);
        nameMap.put("F6", 77);
        nameMap.put("FS6", 78);
        nameMap.put("F#6", 78);
        nameMap.put("GF6", 78);
        nameMap.put("Gf6", 78);
        nameMap.put("GB6", 78);
        nameMap.put("G6", 79);
        nameMap.put("GS6", 80);
        nameMap.put("G#6", 80);
        nameMap.put("AF6", 80);
        nameMap.put("Af6", 80);
        nameMap.put("AB6", 80);
        nameMap.put("A6", 81);
        nameMap.put("AS6", 82);
        nameMap.put("A#6", 82);
        nameMap.put("BF6", 82);
        nameMap.put("Bf6", 82);
        nameMap.put("BB6", 82);
        nameMap.put("B6", 83);

        nameMap.put("CF7", 83);
        nameMap.put("Cf7", 83);
        nameMap.put("CB7", 83);
        nameMap.put("C7", 84);
        nameMap.put("CS7", 85);
        nameMap.put("C#7", 85);
        nameMap.put("DF7", 85);
        nameMap.put("Df7", 85);
        nameMap.put("DB7", 85);
        nameMap.put("D7", 86);
        nameMap.put("DS7", 87);
        nameMap.put("D#7", 87);
        nameMap.put("EF7", 87);
        nameMap.put("Ef7", 87);
        nameMap.put("EB7", 87);
        nameMap.put("E7", 88);
        nameMap.put("F7", 89);
        nameMap.put("FS7", 90);
        nameMap.put("F#7", 90);
        nameMap.put("GF7", 90);
        nameMap.put("Gf7", 90);
        nameMap.put("GB7", 90);
        nameMap.put("G7", 91);
        nameMap.put("GS7", 92);
        nameMap.put("G#7", 92);
        nameMap.put("AF7", 92);
        nameMap.put("Af7", 92);
        nameMap.put("AB7", 92);
        nameMap.put("A7", 93);
        nameMap.put("AS7", 94);
        nameMap.put("A#7", 94);
        nameMap.put("BF7", 94);
        nameMap.put("Bf7", 94);
        nameMap.put("BB7", 94);
        nameMap.put("B7", 95);

        nameMap.put("CF8", 95);
        nameMap.put("Cf8", 95);
        nameMap.put("CB8", 95);
        nameMap.put("C8", 96);
        nameMap.put("CS8", 97);
        nameMap.put("C#8", 97);
        nameMap.put("DF8", 97);
        nameMap.put("Df8", 97);
        nameMap.put("DB8", 97);
        nameMap.put("D8", 98);
        nameMap.put("DS8", 99);
        nameMap.put("D#8", 99);
        nameMap.put("EF8", 99);
        nameMap.put("Ef8", 99);
        nameMap.put("EB8", 99);
        nameMap.put("E8", 100);
        nameMap.put("F8", 101);
        nameMap.put("FS8", 102);
        nameMap.put("F#8", 102);
        nameMap.put("GF8", 102);
        nameMap.put("Gf8", 102);
        nameMap.put("GB8", 102);
        nameMap.put("G8", 103);
        nameMap.put("GS8", 104);
        nameMap.put("G#8", 104);
        nameMap.put("AF8", 104);
        nameMap.put("Af8", 104);
        nameMap.put("AB8", 104);
        nameMap.put("A8", 105);
        nameMap.put("AS8", 106);
        nameMap.put("A#8", 106);
        nameMap.put("BF8", 106);
        nameMap.put("Bf8", 106);
        nameMap.put("BB8", 106);
        nameMap.put("B8", 107);

        nameMap.put("CF9", 107);
        nameMap.put("Cf9", 107);
        nameMap.put("CB9", 107);
        nameMap.put("C9", 108);
        nameMap.put("CS9", 109);
        nameMap.put("C#9", 109);
        nameMap.put("DF9", 109);
        nameMap.put("Df9", 109);
        nameMap.put("DB9", 109);
        nameMap.put("D9", 110);
        nameMap.put("DS9", 111);
        nameMap.put("D#9", 111);
        nameMap.put("EF9", 111);
        nameMap.put("Ef9", 111);
        nameMap.put("EB9", 111);
        nameMap.put("E9", 112);
        nameMap.put("F9", 113);
        nameMap.put("FS9", 114);
        nameMap.put("F#9", 114);
        nameMap.put("GF9", 114);
        nameMap.put("GB9", 114);
        nameMap.put("G9", 115);
        nameMap.put("GS9", 116);
        nameMap.put("G#9", 116);
        nameMap.put("AF9", 116);
        nameMap.put("Af9", 116);
        nameMap.put("AB9", 116);
        nameMap.put("A9", 117);
        nameMap.put("AS9", 118);
        nameMap.put("A#9", 118);
        nameMap.put("BF9", 118);
        nameMap.put("Bf9", 118);
        nameMap.put("BB9", 118);
        nameMap.put("B9", 119);

        nameMap.put("CF10", 119);
        nameMap.put("Cf10", 119);
        nameMap.put("CB10", 119);
        nameMap.put("C10", 120);
        nameMap.put("CS10", 121);
        nameMap.put("C#10", 121);
        nameMap.put("DF10", 121);
        nameMap.put("Df10", 121);
        nameMap.put("DB10", 121);
        nameMap.put("D10", 122);
        nameMap.put("DS10", 123);
        nameMap.put("D#10", 123);
        nameMap.put("EF10", 123);
        nameMap.put("Ef10", 123);
        nameMap.put("EB10", 123);
        nameMap.put("E10", 124);
        nameMap.put("F10", 125);
        nameMap.put("FS10", 126);
        nameMap.put("F#10", 126);
        nameMap.put("GF10", 126);
        nameMap.put("Gf10", 126);
        nameMap.put("GB10", 126);
        nameMap.put("G10", 127);
    }

    public static final PitchClassComparator pitchClassComparator = new PitchClassComparator();

    public static final class PitchClassComparator implements Comparator<Pitch>, Serializable {
        /**
        * 
        */
        private static final long serialVersionUID = 4929792298044867022L;

        @Override
        public int compare(Pitch o1, Pitch o2) {
            int val = 0;
            if (o1.getPitchClass() == o2.getPitchClass()) {
                val = 0;
            } else if (o1.getPitchClass() < o2.getPitchClass()) {
                val = -1;
            } else {
                val = 1;
            }
            return val;
        }
    }

    /**
     * @return the preferredSpelling
     */
    public String getPreferredSpelling() {
        if (preferredSpelling == null || preferredSpelling.equals("") || preferredSpelling.equals("null")) {
            logger.debug("preferred spelling empty for pitch {}", this.midiNumber);
            preferredSpelling = PitchFormat.getInstance().format(this.midiNumber);
        }

        return preferredSpelling;
    }

    /**
     * @param preferredSpelling
     *            the preferredSpelling to set
     */
    public void setPreferredSpelling(String preferredSpelling) {
        this.preferredSpelling = preferredSpelling;
    };

}

/*
 * History:
 * 
 * $Log$
 * 
 * This version: $Revision$ Last modified: $Date$ Last modified by: $Author$
 */