com.rockhoppertech.music.scale.Scale.java Source code

Java tutorial

Introduction

Here is the source code for com.rockhoppertech.music.scale.Scale.java

Source

/**
 * 
 */
package com.rockhoppertech.music.scale;

/*
 * #%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.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

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

import com.google.common.collect.Lists;
import com.rockhoppertech.music.Interval;
import com.rockhoppertech.music.Pitch;
import com.rockhoppertech.music.PitchFactory;
import com.rockhoppertech.music.PitchFormat;
import com.rockhoppertech.music.chord.Chord;
import com.rockhoppertech.music.chord.RomanChordParser;
import com.rockhoppertech.music.midi.js.KeySignature;

//TODO add the Chord stuff back in

/**
 * 
 * @author <a href="mailto:gene@rockhoppertech.com">Gene De Lisa</a>
 * 
 */
public class Scale implements Cloneable {

    // property names
    public static final String NAME = "NAME";

    public static final String DESCRIPTION = "DESCRIPTION";
    public static final String INTERVALS = "INTERVALS";
    public static final String DESCENDING_INTERVALS = "DESCENDING_INTERVALS";
    public static final String SPELLING = "SPELLING";
    public static final String DEGREES = "DEGREES";
    private static Logger logger = LoggerFactory.getLogger(Scale.class);

    private String name;
    private int[] intervals;
    private int[] degrees;
    private String spelling;
    private String description;
    /**
     * e.g. melodic minor has a different descending form
     */
    private boolean descendingDifferent = false;
    private int[] descendingIntervals;

    private int octave;
    private String key = "C";
    private List<String> aliases = new ArrayList<String>();

    public Scale() {
        name = "Unset";
        spelling = "Unset";
        intervals = null;
        degrees = null;
        aliases = new ArrayList<String>();
        key = "C";
    }

    public Scale(final String name, final int[] intervals) {
        setName(name);
        this.intervals = Arrays.copyOf(intervals, intervals.length);
        degrees = Interval.intervalsToDegrees(this.intervals);
        spelling = Interval.spellScale(degrees);
    }

    /**
     * The XML helper calls this one iff spelling is not specified in the config
     * file.
     * 
     * @param name
     * @param intervals2
     * @param description
     */
    public Scale(final String name, final Integer[] intervals2, final String description) {
        setName(name);
        intervals = new int[intervals2.length];
        for (int i = 0; i < intervals2.length; i++) {
            intervals[i] = intervals2[i].intValue();
        }
        degrees = Interval.intervalsToDegrees(intervals);
        spelling = Interval.spellScale(degrees);
        this.description = description;

        // String s = String
        // .format("scale %s has intervals %s \n", name, ArrayUtils
        // .asString(intervals));
        // System.err.println(s);

    }

    /**
     * <p>
     * Construct a Scale from the name and spelling.
     * </p>
     * 
     * @param name
     *            the name to set
     * @param spelling
     *            the spelling to use
     */
    public Scale(final String name, final String spelling) {
        setName(name);
        this.spelling = spelling;
        intervals = Interval.getIntervalsFromSpelling(this.spelling);
        degrees = Interval.intervalsToDegrees(intervals);
    }

    @Override
    public Object clone() {
        Scale result = null;
        try {
            // copy the bitwise primitives
            result = (Scale) super.clone();
            if (spelling != null) {
                result.spelling = spelling;
            }
            if (name != null) {
                result.name = name;
            }
            if (description != null) {
                result.description = description;
            }
            result.aliases.addAll(aliases);

        } catch (final CloneNotSupportedException e) {
            logger.error(e.getLocalizedMessage(), e);
        }
        return result;
    }

    /**
     * Clone is evil.
     * 
     * @return a duplicate
     */
    public Scale duplicate() {
        Scale dupe = new Scale();
        dupe.name = this.name;
        dupe.spelling = this.spelling;
        dupe.description = this.description;
        dupe.aliases = Lists.newArrayList(this.aliases);
        dupe.degrees = Arrays.copyOf(this.degrees, this.degrees.length);
        dupe.descendingDifferent = this.descendingDifferent;
        if (this.descendingIntervals != null) {
            dupe.descendingIntervals = Arrays.copyOf(this.descendingIntervals, this.descendingIntervals.length);
        }
        dupe.intervals = Arrays.copyOf(this.intervals, this.intervals.length);
        dupe.key = this.key;
        dupe.keySignature = this.keySignature;
        dupe.octave = this.octave;
        return dupe;
    }

    /*
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (this.getClass() != obj.getClass()) {
            return false;
        }
        final Scale other = (Scale) obj;
        if (aliases == null) {
            if (other.aliases != null) {
                return false;
            }
        } else if (!aliases.equals(other.aliases)) {
            return false;
        }
        if (!Arrays.equals(degrees, other.degrees)) {
            return false;
        }
        if (descendingDifferent != other.descendingDifferent) {
            return false;
        }
        if (!Arrays.equals(descendingIntervals, other.descendingIntervals)) {
            return false;
        }
        if (description == null) {
            if (other.description != null) {
                return false;
            }
        } else if (!description.equals(other.description)) {
            return false;
        }
        if (!Arrays.equals(intervals, other.intervals)) {
            return false;
        }
        if (key == null) {
            if (other.key != null) {
                return false;
            }
        } else if (!key.equals(other.key)) {
            return false;
        }
        if (name == null) {
            if (other.name != null) {
                return false;
            }
        } else if (!name.equals(other.name)) {
            return false;
        }
        if (octave != other.octave) {
            return false;
        }
        if (spelling == null) {
            if (other.spelling != null) {
                return false;
            }
        } else if (!spelling.equals(other.spelling)) {
            return false;
        }
        return true;
    }

    public int getDegree(int index) {
        return degrees[index];
    }

    /**
     * @return the degrees
     */
    public int[] getDegrees() {
        return Arrays.copyOf(degrees, degrees.length);
    }

    /**
     * Omit the last interval. So, for major return c d e f g a b and not c d e
     * f b a b c6
     * 
     * @return the degrees without the root at the end
     */
    public int[] getDegreesWithinOctave() {
        int[] r = new int[degrees.length - 1];
        System.arraycopy(degrees, 0, r, 0, r.length);
        return r;
    }

    public List<Integer> getDegreesAsMIDINumbers() {
        return this.getDegreesAsMIDINumbers(key);
    }

    public List<Integer> getDegreesAsMIDINumbers(final String key) {
        final Pitch kp = PitchFactory.getPitch(key);
        final List<Integer> pitches = new ArrayList<Integer>();
        for (final int degree : degrees) {
            final Pitch p = PitchFactory.getPitch(degree + kp.getMidiNumber() % 12);
            pitches.add(p.getMidiNumber());
        }
        return pitches;
    }

    public List<Integer> getDegreesAsPitchClasses() {
        return this.getDegreesAsPitchClasses(key);
    }

    public List<Integer> getDegreesAsPitchClasses(final String key) {
        final Pitch kp = PitchFactory.getPitch(key);
        final List<Integer> pitches = new ArrayList<Integer>();
        for (final int degree : degrees) {
            final Pitch p = PitchFactory.getPitch(degree + kp.getMidiNumber() % 12);
            pitches.add(p.getMidiNumber() % 12);
        }
        return pitches;
    }

    public List<Pitch> getDegreesAsPitches() {
        final Pitch kp = PitchFactory.getPitch(key);
        final List<Pitch> pitches = new ArrayList<Pitch>();
        // TODO fix this spelling nonsense
        for (final int degree : degrees) {
            final Pitch p = PitchFactory.getPitch(degree + kp.getMidiNumber());
            if (keySignature != null) {
                String preferredSpelling = null;
                if (keySignature.getSf() < 0) {
                    preferredSpelling = PitchFormat.getPitchString(p, false);
                } else if (keySignature.getSf() > 0) {
                    preferredSpelling = PitchFormat.getPitchString(p, true);
                }
                p.setPreferredSpelling(preferredSpelling);
            }

            pitches.add(p);
        }
        return pitches;
    }

    public List<Pitch> getDegreesAsPitches(final String key) {
        final Pitch kp = PitchFactory.getPitch(key);
        final List<Pitch> pitches = new ArrayList<Pitch>();
        for (final int degree : degrees) {
            final Pitch p = PitchFactory.getPitch(degree + kp.getMidiNumber());
            pitches.add(p);
        }
        return pitches;
    }

    public String getDegreesAsPitchString() {
        final StringBuilder sb = new StringBuilder();
        for (int i = 0; i < degrees.length; i++) {
            final Pitch p = PitchFactory.getPitch(degrees[i]);
            sb.append(PitchFormat.getPitchString(p));
            if (i < degrees.length - 1) {
                sb.append(' ');
            }
        }
        // FIXME
        if (isDescendingDifferent()) {
            final int[] down = Interval.intervalsToDegrees(descendingIntervals);
            for (int i = 0; i < down.length; i++) {
                final Pitch p = PitchFactory.getPitch(down[i]);
                sb.append(PitchFormat.getPitchString(p));
                if (i < down.length - 1) {
                    sb.append(' ');
                }
            }
        }
        return sb.toString();
    }

    public String getDegreesAsString() {
        final StringBuilder sb = new StringBuilder();
        for (int i = 0; i < degrees.length; i++) {
            sb.append(degrees[i]);
            if (i < degrees.length - 1) {
                sb.append(' ');
            }
        }
        // FIXME
        if (isDescendingDifferent()) {
            final int[] down = Interval.intervalsToDegrees(descendingIntervals);
            for (int i = 0; i < down.length; i++) {
                sb.append(down[i]);
                if (i < down.length - 1) {
                    sb.append(' ');
                }
            }
        }
        return sb.toString();
    }

    /**
     * @return the descendingIntervals
     */
    public int[] getDescendingIntervals() {
        return Arrays.copyOf(descendingIntervals, descendingIntervals.length);
    }

    public String getDescendingIntervalsAsString() {
        if (descendingIntervals == null) {
            return "";
        }
        final StringBuilder sb = new StringBuilder();
        for (int i = 0; i < descendingIntervals.length; i++) {
            sb.append(descendingIntervals[i]);
            if (i < descendingIntervals.length - 1) {
                sb.append(' ');
            }
        }
        return sb.toString();
    }

    /**
     * @return the description
     */
    public String getDescription() {
        return description;
    }

    /**
     * @return the intervals
     */
    public int[] getIntervals() {
        final int[] copy = new int[intervals.length];
        System.arraycopy(intervals, 0, copy, 0, intervals.length);
        return copy;
    }

    public String getIntervalsAsString() {
        final StringBuilder sb = new StringBuilder();
        for (int i = 0; i < intervals.length; i++) {
            sb.append(intervals[i]);
            if (i < intervals.length - 1) {
                sb.append(' ');
            }
        }
        return sb.toString();
    }

    /**
     * @return the key
     */
    public String getKey() {
        return key;
    }

    /**
     * <p>
     * The number of degrees
     * </p>
     * 
     * @return the number of degrees
     */
    public int getLength() {
        return degrees.length;
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @return the octave
     */
    public int getOctave() {
        return octave;
    }

    /*
     * public String getRoman(final Chord chord) { return
     * this.getRoman(this.key, chord); }
     * 
     * public String getRoman(final String key, final Chord chord) { final
     * String sym = chord.getSymbol(); // String[] sa =
     * ChordFactory.getChordSymbols(this); // sym = sa[chord.getRoot() % 12];
     * final String s = String .format("%s%s", RomanChordParser
     * .pitchNameToRoman(this, PitchFormat .getPitchString(chord .getRoot()),
     * key), sym); return s; }
     * 
     * 
     * public String getRoman(final String key, final Chord chord, final boolean
     * omitSymbol) { final String sym = chord.getSymbol(); final String s =
     * String .format("%s%s", RomanChordParser .pitchNameToRoman(this,
     * PitchFormat .getPitchString(chord .getRoot()), key), omitSymbol ? "" :
     * sym); return s; }
     */
    /**
     * @return the spelling
     */
    public String getSpelling() {
        return spelling;
    }

    /*
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((aliases == null) ? 0 : aliases.hashCode());
        result = prime * result + Arrays.hashCode(degrees);
        result = prime * result + (descendingDifferent ? 1231 : 1237);
        result = prime * result + Arrays.hashCode(descendingIntervals);
        result = prime * result + ((description == null) ? 0 : description.hashCode());
        result = prime * result + Arrays.hashCode(intervals);
        result = prime * result + ((key == null) ? 0 : key.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result + octave;
        result = prime * result + ((spelling == null) ? 0 : spelling.hashCode());
        return result;
    }

    /**
     * @return the descendingDifferent
     */
    public boolean isDescendingDifferent() {
        return descendingDifferent;
    }

    public boolean isDiatonic(int p) {
        List<Integer> pcs = this.getDegreesAsPitchClasses(key);
        logger.debug("pcs {}", pcs);
        int pitchClass = p % 12;
        return pcs.contains(pitchClass);

        //        p = p % 12;
        //        final int[] degrees = getDegrees();
        //        if (ArrayUtils.contains(degrees,
        //                p)) {
        //            return true;
        //        }
        //        return false;
    }

    public int pitchToDegree(final String pitch) {
        return this.pitchToDegree(key, pitch);
    }

    public int pitchToDegree(final String key, final String pitch) {
        // Pitch kp = PitchFactory.getPitch(key);
        final Pitch p = PitchFactory.getPitch(pitch);
        final List<Pitch> pits = this.getDegreesAsPitches(key);
        String msg = null;
        int degree = 0;

        if (pits.contains(p)) {
            degree = pits.indexOf(p);
            degree++; // music is not zero based
            msg = String.format("contains at index/degree=%d", degree);
            Scale.logger.debug(msg);
            return degree;
        }

        for (int i = 0; i < pits.size(); i++) {
            final Pitch cp = pits.get(i);
            if (cp.getMidiNumber() == p.getMidiNumber() + 1) {
                msg = String.format("raised at index=%d", i);
                Scale.logger.debug(msg);
                return i;
            }
        }

        // for (int i = 0; i < this.degrees.length; i++) {
        // if(this.degrees[i] + kp.getMidiNumber() == p.getMidiNumber()) {
        // degree = 0;
        // break;
        // }
        // }
        return degree;
    }

    /**
     * @param degrees
     *            the degrees to set
     */
    public void setDegrees(final int[] degrees) {
        this.degrees = Arrays.copyOf(degrees, degrees.length);
        spelling = Interval.spellScale(this.degrees);
        intervals = Interval.getIntervalsFromSpelling(spelling);
    }

    /**
     * @param descendingDifferent
     *            the descendingDifferent to set
     */
    public void setDescendingDifferent(final boolean descendingDifferent) {
        this.descendingDifferent = descendingDifferent;
    }

    /**
     * @param descendingIntervals
     *            the descendingIntervals to set
     */
    public void setDescendingIntervals(final int[] descendingIntervals) {
        this.descendingIntervals = Arrays.copyOf(descendingIntervals, descendingIntervals.length);
        // append to this.degrees too? nah

        setDescendingDifferent(true);
    }

    /**
     * <p>
     * </p>
     * 
     * @param dintervals
     */
    public void setDescendingIntervals(final Integer[] dintervals) {
        final int[] a = new int[dintervals.length];
        for (int i = 0; i < a.length; i++) {
            a[i] = dintervals[i].intValue();
        }
        this.setDescendingIntervals(a);
    }

    /**
     * @param description
     *            the description to set
     */
    public void setDescription(final String description) {
        this.description = description;
    }

    /**
     * @param intervals
     *            the intervals to set
     */
    public void setIntervals(final int[] intervals) {
        this.intervals = Arrays.copyOf(intervals, intervals.length);
        degrees = Interval.intervalsToDegrees(this.intervals);
        spelling = Interval.spellScale(degrees);
    }

    /**
     * Pitch names without the octave. C, D, E, F# etc.
     * 
     * @param key
     *            the key to set
     */
    public void setKey(final String key) {
        this.key = key;
        if (getName().equals("Major")) {
            keySignature = KeySignature.get(key, KeySignature.MAJOR);
        } else if (getName().equals("Harmonic Minor")) {
            keySignature = KeySignature.get(key, KeySignature.MINOR);
        }
    }

    private KeySignature keySignature;

    /**
     * Works only if the Scale's name is "Major" or "Minor". Throws an
     * IllegalArgumentException if not.
     * <p>
     * Also sets this.key.
     * 
     * @param keySignature
     *            the key signature
     */
    public void setKeySignature(KeySignature keySignature) {
        if (getName().equals("Major") || getName().equals("Harmonic Minor")) {
            this.keySignature = keySignature;
            this.key = PitchFormat.getInstance().format(this.keySignature.getRoot()).trim();
            logger.debug("this key={}", this.key);
        } else {
            throw new IllegalArgumentException();
        }
    }

    public KeySignature getKeySignature() {
        return keySignature;
    }

    /**
     * make the introspector happy.
     * 
     * @param length
     */
    public void setLength(final int length) {
        final int[] a = new int[length];
        System.arraycopy(degrees, 0, a, 0, a.length);
        degrees = a;
    }

    /**
     * @param name
     *            the name to set
     */
    public void setName(final String name) {
        if (name.contains(",")) {
            Scanner s = new Scanner(name);
            s.useDelimiter(",");
            this.name = s.next();
            while (s.hasNext()) {
                aliases.add(s.next());
            }
            s.close();
        } else {
            this.name = name;
        }
    }

    /**
     * <p>
     * Set the octave.
     * 
     * 
     * @param octave
     *            an octave
     */
    public void setOctave(final int octave) {
        this.octave = octave;
    }

    /**
     * @param spelling
     *            the spelling to set
     */
    public void setSpelling(final String spelling) {
        this.spelling = spelling;
        // this.intervals = Interval.getIntervalsFromSpelling(this.spelling);
        // this.degrees = Interval.intervalsToDegrees(this.intervals);
    }

    /*
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        final String ls = System.getProperty("line.separator");
        final StringBuilder sb = new StringBuilder(this.getClass().getName()).append(ls);
        sb.append(" name=").append(name).append(ls);
        sb.append(" description=").append(description).append(ls);
        sb.append(" key=").append(key).append(ls);
        sb.append(" oct=").append(octave).append(ls);
        sb.append(" spelling=").append(spelling).append(ls);
        sb.append(" intervals=").append(getIntervalsAsString()).append(ls);
        sb.append(" degrees=").append(getDegreesAsString()).append(ls);
        sb.append(" degAsPit=").append(getDegreesAsPitchString());
        sb.append(" isdescending=").append(isDescendingDifferent()).append(ls);
        if (isDescendingDifferent()) {
            sb.append(" descending=").append(getDescendingIntervalsAsString()).append(ls);
        }

        return sb.toString();
    }

    public boolean contains(final Chord chord) {
        return this.contains(this.key, chord);
    }

    public boolean contains(final String key, final Chord chord) {
        boolean result = true;
        final int[] chordPits = chord.getPitchClasses();
        final List<Integer> pits = this.getDegreesAsPitchClasses(key);

        logger.info(String.format("key: '%s'", key));
        logger.info(String.format("chord pits: '%s'", ArrayUtils.toString(chordPits)));
        logger.info(String.format("scale: '%s'", pits));

        for (final int cp : chordPits) {
            if (pits.contains(cp) == false) {
                result = false;
                if (Scale.logger.isInfoEnabled()) {
                    Scale.logger.info(String.format("does not contain chord pit %d", cp));
                }
                break;
            }
        }

        logger.info(String.format("returning %b", result));

        return result;
    }

    public String getRoman(final Chord chord) {
        return this.getRoman(this.key, chord);
    }

    public String getRoman(final String key, final Chord chord) {
        final String sym = chord.getSymbol();
        // String[] sa = ChordFactory.getChordSymbols(this);
        // sym = sa[chord.getRoot() % 12];
        final String s = String.format("%s%s",
                RomanChordParser.pitchNameToRoman(this, PitchFormat.getPitchString(chord.getRoot()), key), sym);
        return s;
    }

    /**
     * 
     * @param key
     * @param chord
     * @param omitSymbol
     * @return the Roman representation
     */
    public String getRoman(final String key, final Chord chord, final boolean omitSymbol) {
        final String sym = chord.getSymbol();
        final String s = String.format("%s%s",
                RomanChordParser.pitchNameToRoman(this, PitchFormat.getPitchString(chord.getRoot()), key),
                omitSymbol ? "" : sym);
        return s;
    }

    /**
     * @return the aliases
     */
    public List<String> getAliases() {
        return aliases;
    }

    /**
     * @param aliases
     *            the aliases to set
     */
    public void setAliases(List<String> aliases) {
        this.aliases = aliases;
    }

}
/*
    
 */

// static Map<String, Scale> scales = new HashMap<String, Scale>();
//
// public static final int[] CHROMATIC = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
// };
// public static final int[] MAJOR = { 2, 2, 1, 2, 2, 2, 1 };
// public static final int[] HARMONIC_MINOR = { 2, 1, 2, 2, 1, 3, 1 };
// public static final int[] MELODIC_MINOR = { 2, 1, 2, 2, 1, 2, 2 };
// public static final int[] OCTATONIC = { 2, 1, 2, 1, 2, 1, 2, 1 };
//
// public static final int[] BLUES_SCALE = { 3, 2, 1, 1, 3, 2 };
//
// public static final int[] WHOLE_TONE = { 2, 2, 2, 2, 2 };
//
// public static final int[] MESSIAEN_MODE1 = WHOLE_TONE;
// public static final int[] MESSIAEN_MODE2 = OCTATONIC;
// public static final int[] MESSIAEN_MODE3 = { 2, 1, 1, 2, 1, 1 };
// public static final int[] MESSIAEN_MODE4_1 = { 1, 1, 3, 1, 1, 1, 3, 1 };
// public static final int[] MESSIAEN_MODE4_2 = { 1, 4, 1, 1, 4, 1 };
// public static final int[] MESSIAEN_MODE4_3 = { 2, 2, 1, 1, 2, 2, 1, 1 };
// public static final int[] MESSIAEN_MODE4_4 = { 1, 1, 1, 2, 1, 1, 1, 1, 2,
// 1 };
//
// public static final int[] IONIAN = MAJOR;
// public static final int[] DORIAN = { 2, 1, 2, 2, 2, 1, 2 };
// public static final int[] PHRYGIAN = { 1, 2, 2, 2, 1, 2, 2 };
// public static final int[] LYDIAN = { 2, 2, 2, 1, 2, 2, 1 };
// public static final int[] MIXOLYDIAN = { 2, 2, 1, 2, 2, 1, 2 };
// public static final int[] AEOLIAN = { 2, 1, 2, 2, 1, 2, 2 };
// public static final int[] LOCRIAN = { 1, 2, 2, 1, 2, 2, 2 };
//
// public static final int[] IONIAN_PENTATONIC = { 2, 2, 3, 2, 3 };
// public static final int[] DORIAN_PENTATONIC = { 2, 1, 4, 2, 3 };
// public static final int[] PHRYGIAN_PENTATONIC = { 1, 2, 4, 1, 4 };
// public static final int[] LYDIAN_PENTATONIC = { 2, 2, 3, 2, 3 };
// public static final int[] MIXOLYDIAN_PENTATONIC = { 2, 2, 3, 2, 3 };
// public static final int[] AEOLIAN_PENTATONIC = { 2, 1, 4, 1, 4 };
// public static final int[] LOCRIAN_PENTATONIC = { 1, 2, 3, 2, 4 };
//
// public static final int[] JAPANESE = { 2, 1, 4, 1, 4 };
// public static final int[] GYPSY = { 1, 3, 1, 2, 1, 3, 1 };
// public static final int[] NEAPOLITAN = { 1, 2, 2, 2, 2, 2, 1 };
// public static final int[] NEAPOLITAN_MINOR = { 1, 2, 2, 2, 1, 3, 1 };
// public static final int[] PELOG = { 1, 2, 4, 1 };
// public static final int[] ROMANIAN_MINOR = { 2, 1, 3, 1, 2, 1, 2 };
// public static final int[] DOUBLE_HARMONIC = { 1, 2, 1, 2, 1, 3, 1 };
// public static final int[] HUNGARIAN_MINOR = { 2, 1, 3, 1, 1, 3, 1 };
// public static final int[] ARABIAN = { 2, 1, 2, 1, 1, 1, 2, 1 };
// public static final int[] PROMETHEUS = { 2, 2, 2, 4, 2 };
// public static final int[] SCRIABIN = { 1, 3, 3, 2, 3 };
// public static final int[] EGYPTIAN = { 2, 3, 2, 3, 2 };
// public static final int[] ENIGMATIC = { 1, 3, 2, 2, 2, 1, 1 };
// public static final int[] ORIENTAL = { 1, 3, 1, 1, 2, 2, 2 };
/*
 * Hindustan Ritusen Arabian Leading Whole Tone Lydian Minor Iwato Piongio
 * Hirajoshi Kumoi Chinese
 */