OSDN Git Service

リファクタリング
authorAkiyoshi Kamide <kamide@yk.rim.or.jp>
Sun, 18 Dec 2016 16:23:36 +0000 (01:23 +0900)
committerAkiyoshi Kamide <kamide@yk.rim.or.jp>
Sun, 18 Dec 2016 16:23:36 +0000 (01:23 +0900)
12 files changed:
src/camidion/chordhelper/ChordHelperApplet.java
src/camidion/chordhelper/chordmatrix/ChordMatrix.java
src/camidion/chordhelper/midieditor/KeySignatureLabel.java
src/camidion/chordhelper/midieditor/KeySignatureSelecter.java
src/camidion/chordhelper/midieditor/MidiMessageForm.java
src/camidion/chordhelper/music/Chord.java
src/camidion/chordhelper/music/ChordProgression.java
src/camidion/chordhelper/music/Key.java
src/camidion/chordhelper/music/MIDISpec.java
src/camidion/chordhelper/music/NoteSymbol.java
src/camidion/chordhelper/music/NoteSymbolLanguage.java [deleted file]
src/camidion/chordhelper/pianokeyboard/MidiKeyboardPanel.java

index 0344c93..8a182ae 100644 (file)
@@ -283,7 +283,7 @@ public class ChordHelperApplet extends JApplet {
         */
        public static class VersionInfo {
                public static final String      NAME = "MIDI Chord Helper";
-               public static final String      VERSION = "Ver.20161211.1";
+               public static final String      VERSION = "Ver.20161218.1";
                public static final String      COPYRIGHT = "Copyright (C) 2004-2016";
                public static final String      AUTHER = "@きよし - Akiyoshi Kamide";
                public static final String      URL = "http://www.yk.rim.or.jp/~kamide/music/chordhelper/";
@@ -421,7 +421,7 @@ public class ChordHelperApplet extends JApplet {
                        addChordMatrixListener(new ChordMatrixListener(){
                                public void keySignatureChanged() {
                                        Key capoKey = getKeySignatureCapo();
-                                       keyboardPanel.keySelecter.setKey(capoKey);
+                                       keyboardPanel.keySelecter.setSelectedKey(capoKey);
                                        keyboardPanel.keyboardCenterPanel.keyboard.setKeySignature(capoKey);
                                }
                                public void chordChanged() { chordOn(); }
@@ -454,7 +454,7 @@ public class ChordHelperApplet extends JApplet {
                        keySelecter.keysigCombobox.addActionListener(new ActionListener() {
                                @Override
                                public void actionPerformed(ActionEvent e) {
-                                       Key key = keySelecter.getKey();
+                                       Key key = keySelecter.getSelectedKey();
                                        key.transpose( - chordMatrix.capoSelecter.getCapo() );
                                        chordMatrix.setKeySignature(key);
                                }
index 70ba611..61ba1a6 100644 (file)
@@ -37,7 +37,6 @@ import camidion.chordhelper.music.Chord;
 import camidion.chordhelper.music.Key;
 import camidion.chordhelper.music.Music;
 import camidion.chordhelper.music.NoteSymbol;
-import camidion.chordhelper.music.NoteSymbolLanguage;
 
 /**
  * MIDI Chord Helper 用のコードボタンマトリクス
@@ -174,7 +173,7 @@ public class ChordMatrix extends JPanel
                        }
                        else {
                                tip += key.signatureDescription() + " " +
-                                       key.toStringIn(NoteSymbolLanguage.IN_JAPANESE);
+                                       key.toStringIn(NoteSymbol.Language.IN_JAPANESE);
                                if( v == 0 ) {
                                        setIcon(new ButtonIcon(ButtonIcon.NATURAL_ICON));
                                }
index 27cb202..8fc3238 100644 (file)
@@ -3,7 +3,7 @@ package camidion.chordhelper.midieditor;
 import javax.swing.JLabel;
 
 import camidion.chordhelper.music.Key;
-import camidion.chordhelper.music.NoteSymbolLanguage;
+import camidion.chordhelper.music.NoteSymbol;
 
 /**
  * 調表示ラベル
@@ -22,8 +22,8 @@ public class KeySignatureLabel extends JLabel {
                }
                setText( "key:" + key.toString() );
                setToolTipText(
-                       "Key: " + key.toStringIn(NoteSymbolLanguage.NAME)
-                       + " "  + key.toStringIn(NoteSymbolLanguage.IN_JAPANESE)
+                       "Key: " + key.toStringIn(NoteSymbol.Language.NAME)
+                       + " "  + key.toStringIn(NoteSymbol.Language.IN_JAPANESE)
                        + " (" + key.signatureDescription() + ")"
                );
                setEnabled(true);
index aa4b013..89e82b9 100644 (file)
@@ -9,7 +9,7 @@ import javax.swing.JLabel;
 import javax.swing.JPanel;
 
 import camidion.chordhelper.music.Key;
-import camidion.chordhelper.music.NoteSymbolLanguage;
+import camidion.chordhelper.music.NoteSymbol;
 
 /**
  * 調性選択
@@ -21,9 +21,7 @@ public class KeySignatureSelecter extends JPanel implements ActionListener {
                        Key key;
                        for( int i = -7 ; i <= 7 ; i++ ) {
                                str = (key = new Key(i)).toString();
-                               if( i != 0 ) {
-                                       str = key.signature() + " : " + str ;
-                               }
+                               if( i != 0 ) str = key.signature() + " : " + str ;
                                addItem(str);
                        }
                        setMaximumRowCount(15);
@@ -31,45 +29,43 @@ public class KeySignatureSelecter extends JPanel implements ActionListener {
        };
        JCheckBox minorCheckbox = null;
 
-       public KeySignatureSelecter() { this(true); }
-       public KeySignatureSelecter(boolean useMinorCheckbox) {
+       public KeySignatureSelecter() { this(null); }
+       public KeySignatureSelecter(Key key) {
                add(new JLabel("Key:"));
                add(keysigCombobox);
-               if(useMinorCheckbox) {
+               if(key != null && key.majorMinor() != Key.MajorMinor.MAJOR_OR_MINOR) {
                        add( minorCheckbox = new JCheckBox("minor") );
                        minorCheckbox.addActionListener(this);
                }
                keysigCombobox.addActionListener(this);
-               clear();
+               setSelectedKey(key);
        }
+
        public void actionPerformed(ActionEvent e) { updateToolTipText(); }
        private void updateToolTipText() {
-               Key key = getKey();
+               Key key = getSelectedKey();
                keysigCombobox.setToolTipText(
-                       "Key: " + key.toStringIn( NoteSymbolLanguage.NAME )
-                       + " "  + key.toStringIn( NoteSymbolLanguage.IN_JAPANESE )
+                       "Key: " + key.toStringIn( NoteSymbol.Language.NAME )
+                       + " "  + key.toStringIn( NoteSymbol.Language.IN_JAPANESE )
                        + " (" + key.signatureDescription() + ")"
                );
        }
-       public void clear() { setKey(new Key("C")); }
-       public void setKey( Key key ) {
-               if( key == null ) { clear(); return; }
-               keysigCombobox.setSelectedIndex( key.toCo5() + 7 );
-               if( minorCheckbox == null ) return;
-               minorCheckbox.setSelected(key.majorMinor() == Key.MajorMinor.MINOR);
+
+       public void setSelectedKey(Key key) {
+               if( key == null ) key = new Key("C");
+               keysigCombobox.setSelectedIndex(key.toCo5() + 7);
+               setMajorMinor(key.majorMinor());
        }
-       public Key getKey() {
-               Key.MajorMinor majorMinor = (
-                       minorCheckbox == null ? Key.MajorMinor.MAJOR_OR_MINOR :
-                       isMinor() ? Key.MajorMinor.MINOR :
-                       Key.MajorMinor.MAJOR
-               );
-               return new Key(getKeyCo5(),majorMinor);
+       public Key getSelectedKey() {
+               return new Key(keysigCombobox.getSelectedIndex() - 7, getMajorMinor());
        }
-       public int getKeyCo5() {
-               return keysigCombobox.getSelectedIndex() - 7;
+
+       private void setMajorMinor(Key.MajorMinor majorMinor) {
+               if( minorCheckbox == null || majorMinor == Key.MajorMinor.MAJOR_OR_MINOR ) return;
+               minorCheckbox.setSelected(majorMinor == Key.MajorMinor.MINOR);
        }
-       public boolean isMinor() {
-               return minorCheckbox != null && minorCheckbox.isSelected();
+       private Key.MajorMinor getMajorMinor() {
+               return minorCheckbox == null ? Key.MajorMinor.MAJOR_OR_MINOR :
+                       minorCheckbox.isSelected() ? Key.MajorMinor.MINOR : Key.MajorMinor.MAJOR;
        }
 }
\ No newline at end of file
index 099bd1c..8a63b8b 100644 (file)
@@ -234,19 +234,19 @@ public class MidiMessageForm extends JPanel implements ActionListener {
        /**
         * 調号選択
         */
-       private KeySignatureSelecter keysigSelecter = new KeySignatureSelecter() {
+       private KeySignatureSelecter keysigSelecter = new KeySignatureSelecter(new Key("C")) {
                {
                        keysigCombobox.addActionListener(
                                new ActionListener() {
                                        public void actionPerformed(ActionEvent e) {
-                                               dataText.setValue(getKey().getBytes());
+                                               dataText.setValue(getSelectedKey().getBytes());
                                        }
                                }
                        );
                        minorCheckbox.addItemListener(
                                new ItemListener() {
                                        public void itemStateChanged(ItemEvent e) {
-                                               dataText.setValue(getKey().getBytes());
+                                               dataText.setValue(getSelectedKey().getBytes());
                                        }
                                }
                        );
@@ -295,7 +295,7 @@ public class MidiMessageForm extends JPanel implements ActionListener {
                                switch( data1 ) { // Data type -> Selecter
                                case 0x51: dataText.setValue(tempoSelecter.getTempoByteArray()); break;
                                case 0x58: dataText.setValue(timesigSelecter.getByteArray()); break;
-                               case 0x59: dataText.setValue(keysigSelecter.getKey().getBytes()); break;
+                               case 0x59: dataText.setValue(keysigSelecter.getSelectedKey().getBytes()); break;
                                default: break;
                                }
                        }
@@ -464,9 +464,7 @@ public class MidiMessageForm extends JPanel implements ActionListener {
                        byte data[] = dataText.getBytes();
                        if( data == null ) return null;
                        try {
-                               msg.setMessage(
-                                               (int)(msgStatus & 0xFF), data, data.length
-                                               );
+                               msg.setMessage((int)(msgStatus & 0xFF), data, data.length);
                        } catch( InvalidMidiDataException e ) {
                                e.printStackTrace();
                                return null;
@@ -474,20 +472,16 @@ public class MidiMessageForm extends JPanel implements ActionListener {
                        return (MidiMessage)msg;
                }
                ShortMessage msg = new ShortMessage();
-               int msg_data1 = data1Text.getValue();
-               if( msg_data1 < 0 ) msg_data1 = 0;
-               int msg_data2 = data2Text.getValue();
-               if( msg_data2 < 0 ) msg_data2 = 0;
+               int msgData1 = data1Text.getValue();
+               if( msgData1 < 0 ) msgData1 = 0;
+               int msgData2 = data2Text.getValue();
+               if( msgData2 < 0 ) msgData2 = 0;
                try {
-                       if( MIDISpec.isChannelMessage( msgStatus ) ) {
-                               msg.setMessage(
-                                       (msgStatus & 0xF0),
-                                       channelText.getSelectedChannel(),
-                                       msg_data1, msg_data2
-                               );
+                       if( MIDISpec.isChannelMessage(msgStatus) ) {
+                               msg.setMessage((msgStatus & 0xF0), channelText.getSelectedChannel(), msgData1, msgData2);
                        }
                        else {
-                               msg.setMessage( msgStatus, msg_data1, msg_data2 );
+                               msg.setMessage(msgStatus, msgData1, msgData2);
                        }
                } catch( InvalidMidiDataException e ) {
                        e.printStackTrace();
@@ -527,7 +521,7 @@ public class MidiMessageForm extends JPanel implements ActionListener {
                        switch(msgType) {
                        case 0x51: tempoSelecter.setTempo(data); break;
                        case 0x58: timesigSelecter.setValue(data[0], data[1]); break;
-                       case 0x59: keysigSelecter.setKey(new Key(data)); break;
+                       case 0x59: keysigSelecter.setSelectedKey(new Key(data)); break;
                        default: break;
                        }
                        if( MIDISpec.hasMetaMessageText(msgType) ) {
index 9baff14..d9ad853 100644 (file)
@@ -526,9 +526,9 @@ public class Chord implements Cloneable {
         * @return コードの説明(英語)
         */
        public String toName() {
-               String name = rootNoteSymbol.toStringIn(NoteSymbolLanguage.NAME) + nameSuffix() ;
+               String name = rootNoteSymbol.toStringIn(NoteSymbol.Language.NAME) + nameSuffix() ;
                if( ! rootNoteSymbol.equals(bassNoteSymbol) ) {
-                       name += " on " + bassNoteSymbol.toStringIn(NoteSymbolLanguage.NAME);
+                       name += " on " + bassNoteSymbol.toStringIn(NoteSymbol.Language.NAME);
                }
                return name;
        }
index b46723e..a917eab 100644 (file)
@@ -350,7 +350,7 @@ public class ChordProgression {
 
        // Major/minor 切り替え
        public void toggleKeyMajorMinor() {
-               key = key.relativeKey();
+               key = key.createRelativeKey();
        }
 
        // コード進行の移調
@@ -361,13 +361,13 @@ public class ChordProgression {
                                        Object element = measure.get(i);
                                        if( element instanceof ChordStroke ) {
                                                ChordStroke cs = (ChordStroke)element;
-                                               Chord new_chord = cs.chord.clone();
+                                               Chord newChord = cs.chord.clone();
                                                //
                                                // キーが未設定のときは、最初のコードから推測して設定
-                                               if( key == null ) key = new Key( new_chord );
+                                               if( key == null ) key = new Key(newChord);
                                                //
-                                               new_chord.transpose( chromaticOffset, key );
-                                               measure.set( i, new ChordStroke( new_chord, cs.beat_length ) );
+                                               newChord.transpose( chromaticOffset, key );
+                                               measure.set(i, new ChordStroke(newChord, cs.beat_length));
                                        }
                                }
                        }
index 5b29c5c..224c900 100644 (file)
@@ -7,16 +7,23 @@ package camidion.chordhelper.music;
  * <p>内部的には次の値を持っています。</p>
  * <ul>
  * <li>五度圏インデックス値。これは調号の♯の数(♭の数は負数)と同じです。</li>
- * <li>メジャー/マイナーの区別(無指定ありの3値)</li>
+ * <li>メジャー/マイナーの区別、区別なしの3値({@link MajorMinor}で定義)</li>
  * </ul>
  * <p>これらの値はMIDIのメタメッセージにある調号のパラメータに対応します。
  * </p>
  */
 public class Key implements Cloneable {
        /**
-        * ã\83¡ã\82¸ã\83£ã\83¼ã\81¨ã\83\9eã\82¤ã\83\8aã\83¼ã\81®ã\81©ã\81¡ã\82\89ã\81\8bã\81\82ã\82\8bã\81\84ã\81¯ä¸¡æ\96¹ã\81§ã\81\82ã\82\8bã\81\93ã\81¨ã\82\92示ã\81\99å\9e\8b
+        * ã\82­ã\83¼æ\8c\87å®\9aï¼\88ã\83¡ã\82¸ã\83£ã\83¼ï¼\8fã\83\9eã\82¤ã\83\8aã\83¼ï¼\8f両æ\96¹ï¼\89
         */
        public enum MajorMinor {
+               /**
+                * メジャーまたはマイナー(区別なし)
+                */
+               MAJOR_OR_MINOR {
+                       @Override
+                       public boolean includes(MajorMinor mm) { return true; }
+               },
                /** メジャーキー(長調) */
                MAJOR {
                        @Override
@@ -26,48 +33,49 @@ public class Key implements Cloneable {
                MINOR {
                        @Override
                        public MajorMinor opposite() { return MAJOR; }
-               },
-               /** メジャーまたはマイナー */
-               MAJOR_OR_MINOR;
-
+               };
                /** 反対の調を返します。 */
                public MajorMinor opposite() { return this; }
+               /**
+                * この値が、引数で指定されたメジャー/マイナーを含んだ意味であるときにtrueを返します。
+                * */
+               public boolean includes(MajorMinor mm) { return equals(mm); }
        }
        /**
         * この調の五度圏インデックス値
         */
        private int co5;
        /**
-        * メジャー・マイナーの種別
+        * メジャー・マイナーの種別(null不可:コンストラクタでの初期化必須)
         */
        private MajorMinor majorMinor;
        /**
-        * 調号が空のキー(ハ長調またはイ短調)を構築します。
-        */
-       public Key() { }
-       /**
-        * 指定の五度圏インデックス値を持つ調を、
-        * メジャーとマイナーを指定せずに構築します。
-        *
-        * @param co5 五度圏インデックス値
+        * 調号が空(C/Am ハ長調またはイ短調)のキーを、メジャーとマイナーを指定せずに構築します。
         */
-       public Key(int co5) { setKey(co5, MajorMinor.MAJOR_OR_MINOR); }
+       public Key() {
+               majorMinor = MajorMinor.MAJOR_OR_MINOR;
+       }
        /**
-        * 指定の五度圏インデックス値を持つ、
-        * メジャー/マイナーを指定した調を構築します。
+        * 指定の五度圏インデックス値を持つ調を、メジャーとマイナーを指定せずに構築します。
         *
         * @param co5 五度圏インデックス値
-        * @param majorMinor {@link #MAJOR}、{@link #MINOR}、{@link #MAJOR_OR_MINOR} のいずれか
         */
-       public Key(int co5, MajorMinor majorMinor) { setKey(co5, majorMinor); }
+       public Key(int co5) {
+               this.co5 = co5;
+               majorMinor = MajorMinor.MAJOR_OR_MINOR;
+               normalize();
+       }
        /**
-        * 指定の五度圏インデックス値を持つ、
-        * メジャー/マイナーの明確な調を構築します。
+        * 指定の五度圏インデックス値を持つ、メジャー/マイナーを指定した調を構築します。
         *
         * @param co5 五度圏インデックス値
-        * @param isMinor true:マイナー、false:メジャー
+        * @param majorMinor メジャー/マイナー指定
         */
-       public Key(int co5, boolean isMinor) { setKey(co5, isMinor); }
+       public Key(int co5, MajorMinor majorMinor) {
+               this.co5 = co5;
+               this.majorMinor = majorMinor;
+               normalize();
+       }
        /**
         * MIDIの調データ(メタメッセージ2byte)から調を構築します。
         * @param midiData MIDIの調データ
@@ -79,16 +87,20 @@ public class Key implements Cloneable {
         * @throw IllegalArgumentException 引数が空文字列の場合、または音名で始まっていない場合
         */
        public Key(String keySymbol) throws IllegalArgumentException {
-               boolean isMinor = keySymbol.matches(".*m");
-               setKey((new NoteSymbol(keySymbol)).toCo5ForKey(isMinor), isMinor);
+               co5 = NoteSymbol.co5OfSymbol(keySymbol);
+               if( keySymbol.matches(".*m") ) { majorMinor = MajorMinor.MINOR; co5 -= 3; }
+               else majorMinor = MajorMinor.MAJOR;
+               normalize();
        }
        /**
         * 指定されたコードと同名の調を構築します。
         * @param chord コード(和音)
         */
        public Key(Chord chord) {
-               boolean isMinor = chord.isSet(Chord.Interval.MINOR);
-               setKey(chord.rootNoteSymbol().toCo5ForKey(isMinor), isMinor);
+               co5 = chord.rootNoteSymbol().toCo5();
+               if( chord.isSet(Chord.Interval.MINOR) ) { majorMinor = MajorMinor.MINOR; co5 -= 3; }
+               else majorMinor = MajorMinor.MAJOR;
+               normalize();
        }
        @Override
        public Key clone() { return new Key(co5, majorMinor); }
@@ -97,30 +109,20 @@ public class Key implements Cloneable {
                if( this == anObject ) return true;
                if( anObject instanceof Key ) {
                        Key another = (Key) anObject;
-                       return
-                               co5 == another.toCo5() &&
-                               majorMinor == another.majorMinor() ;
+                       return co5 == another.toCo5() && majorMinor == another.majorMinor();
                }
                return false;
        }
        @Override
-       public int hashCode() { return majorMinor.ordinal() * 256 + co5 ; }
-       private void setKey(int co5, boolean isMinor) {
-               setKey( co5, isMinor ? MajorMinor.MINOR : MajorMinor.MAJOR );
-       }
-       private void setKey(int co5, MajorMinor majorMinor) {
-               this.co5 = co5;
-               this.majorMinor = majorMinor;
-               normalize();
-       }
+       public int hashCode() { return majorMinor.ordinal() * 64 + co5 ; }
        /**
-        * MIDIの調データ(メタメッセージ2byte)を設定します。
+        * この調にMIDIの調データ(メタメッセージ2byte)を設定し、{@link #normalize()}で正規化します。
         * @param data MIDIの調データ
         */
-       public void setBytes( byte[] data ) {
-               byte sharpFlat = data.length > 0 ? data[0] : 0;
-               byte isMinor = data.length > 1 ? data[1] : 0;
-               setKey( (int)sharpFlat, isMinor==1 );
+       public void setBytes(byte[] data) {
+               co5 = data.length > 0 ? (int)data[0] : 0;
+               majorMinor = (data.length > 1 && data[1] == 1) ? MajorMinor.MINOR : MajorMinor.MAJOR ;
+               normalize();
        }
        /**
         * MIDIの調データ(メタメッセージ2byte)を生成して返します。
@@ -148,7 +150,7 @@ public class Key implements Cloneable {
         */
        public int relativeDo() { return NoteSymbol.majorCo5ToNoteNumber(co5); }
        /**
-        * この調のルート音を返します。
+        * ã\81\93ã\81®èª¿ã\81®ã\83«ã\83¼ã\83\88é\9f³ã\82\92表ã\81\99ã\83\8eã\83¼ã\83\88ç\95ªå\8f·ï¼\88ã\82ªã\82¯ã\82¿ã\83¼ã\83\96æ\8a\9cã\81\8dï¼\89ã\82\92è¿\94ã\81\97ã\81¾ã\81\99ã\80\82
         * メジャーキーの場合は相対ド、
         * マイナーキーの場合は相対ラの音階です。
         *
@@ -194,56 +196,48 @@ public class Key implements Cloneable {
         */
        public void normalize() {
                if( co5 < -7 || co5 > 7 ) {
-                       co5 = Music.mod12( co5 );
+                       co5 = Music.mod12(co5);
                        if( co5 > 6 ) co5 -= Music.SEMITONES_PER_OCTAVE;
                }
        }
        /**
         * 平行調を生成して返します。
         * これは元の調と同じ調号を持つ、メジャーとマイナーが異なる調です。
-        *
-        * <p>メジャーとマイナーの区別が不明な場合、クローンを生成したのと同じことになります。
-        * </p>
-        *
+        * メジャーとマイナーの区別が不明な場合、クローンを生成したのと同じことになります。
         * @return 平行調
         */
-       public Key relativeKey() { return new Key(co5, majorMinor.opposite()); }
+       public Key createRelativeKey() { return new Key(co5, majorMinor.opposite()); }
        /**
         * 同主調を生成して返します。
         * これは元の調とルート音が同じで、メジャーとマイナーが異なる調です。
-        *
-        * <p>メジャーとマイナーの区別が不明な場合、クローンを生成したのと同じことになります。
-        * 元の調の♭、♯の数が5個以上の場合、
-        * 7♭~7♯の範囲をはみ出すことがあります(正規化は行われません)。
-        * </p>
-        *
+        * メジャーとマイナーの区別が不明な場合、クローンを生成したのと同じことになります。
         * @return 同主調
         */
-       public Key parallelKey() {
+       public Key createParallelKey() {
+               int newCo5 = co5;
                switch( majorMinor ) {
-               case MAJOR: return new Key( co5-3, MajorMinor.MINOR );
-               case MINOR: return new Key( co5+3, MajorMinor.MAJOR );
-               default: return new Key(co5);
+               case MAJOR: newCo5 -= 3; break;
+               case MINOR: newCo5 += 3; break;
+               default: break;
                }
+               return new Key(newCo5, majorMinor.opposite());
        }
        /**
         * 五度圏で真裏にあたる調を生成して返します。
         * @return 五度圏で真裏にあたる調
         */
-       public Key oppositeKey() { return new Key(Music.oppositeCo5(co5), majorMinor); }
+       public Key createOppositeKey() { return new Key(Music.oppositeCo5(co5), majorMinor); }
        /**
         * この調の文字列表現を C、Am のような形式で返します。
         * @return この調の文字列表現
         */
        @Override
-       public String toString() { return toStringIn(NoteSymbolLanguage.SYMBOL); }
+       public String toString() { return toStringIn(NoteSymbol.Language.SYMBOL); }
        /**
         * この調の文字列表現を、指定された形式で返します。
         * @return この調の文字列表現
         */
-       public String toStringIn(NoteSymbolLanguage language) {
-               return language.keyStringOf(new NoteSymbol(co5), majorMinor);
-       }
+       public String toStringIn(NoteSymbol.Language language) { return language.stringOf(this); }
        /**
         * 調号を表す半角文字列を返します。
         * 正規化された状態において最大2文字になるよう調整されます。
index 0e0cb65..d470ac4 100644 (file)
@@ -851,7 +851,7 @@ public class MIDISpec {
                                if( msgdata.length == 2 ) {
                                        Key key = new Key(msgdata);
                                        str += ": " + key.signatureDescription();
-                                       str += " (" + key.toStringIn(NoteSymbolLanguage.NAME) + ")";
+                                       str += " (" + key.toStringIn(NoteSymbol.Language.NAME) + ")";
                                        break;
                                }
                                str += ": Size not 2 byte : data=(";
index e9570fc..a8fda20 100644 (file)
@@ -1,5 +1,9 @@
 package camidion.chordhelper.music;
 
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
 /**
  * 音名(オクターブ抜き)を表すクラスです。値は不変です。
  *
@@ -13,8 +17,129 @@ package camidion.chordhelper.music;
  * </p>
  */
 public class NoteSymbol implements Cloneable {
-       private static final int INDEX_OF_A = NoteSymbolLanguage.SYMBOL.indexOf("A");
-       private static final int INDEX_OF_C = NoteSymbolLanguage.SYMBOL.indexOf("C");
+       private static final int INDEX_OF_A = Language.SYMBOL.indexOf("A");
+       private static final int INDEX_OF_C = Language.SYMBOL.indexOf("C");
+       /**
+        * 音階や調を表すシンボルの言語モードによる違いを定義します。
+        * <p>音名には、下記のような五度圏順のインデックス値(0~34)が割り当てられます。
+        * <pre>Fbb=0, Cbb=1, .. Bb=13, F=14, C=15, .. B=20, F#=21, C#=22, .. B#=27, Fx=28, .. Bx=34</pre>
+        */
+       public static enum Language {
+               /**
+                * 記号表記(Bb, F#)
+                */
+               SYMBOL(Arrays.asList("bb","b","","#","x"),"","m"),
+               /**
+                * 英名表記(B flat, F sharp)
+                */
+               NAME(Arrays.asList(" double flat"," flat",""," sharp"," double sharp")," major"," minor"),
+               /**
+                * 日本名表記(変ロ, 嬰ヘ)
+                */
+               IN_JAPANESE(Arrays.asList("重変","変","","嬰","重嬰"),"長調","短調");
+               //
+               private Language(List<String> sharpFlatList, String major, String minor) {
+                       if( (this.sharpFlatList = sharpFlatList).contains("変") ) {
+                               this.notes = "ヘハトニイホロ";
+                               this.majorMinorDelimiter = "/";
+                       } else {
+                               this.notes = "FCGDAEB";
+                               this.majorMinorDelimiter = " / ";
+                       }
+                       this.major = major;
+                       this.minor = minor;
+               }
+               /**
+                * ♭や♯の表記を、半音下がる数が多いほうから順に並べたリスト
+                */
+               private List<String> sharpFlatList;
+               /**
+                * 引数の先頭にある、♭や♯などの変化記号のインデックス(0~4)を返します。
+                * <p>変化記号がない場合、2 を返します。それ以外は次の値を返します。</p>
+                * <ul>
+                * <li>ダブルシャープ:4</li>
+                * <li>シャープ:3</li>
+                * <li>フラット:1</li>
+                * <li>ダブルフラット:0</li>
+                * </ul>
+                * @param s 変化記号で始まる文字列
+                * @return インデックス
+                */
+               private int sharpFlatIndexOf(String s) {
+                       int index = 0;
+                       for( String sharpFlat : sharpFlatList ) {
+                               if( ! sharpFlat.isEmpty() && s.startsWith(sharpFlat) ) return index;
+                               index++;
+                       }
+                       return 2;
+               }
+               /**
+                * 音名を五度圏順で並べた7文字
+                */
+               private String notes;
+               /**
+                * インデックス値に該当する音名を返します。
+                * @param index インデックス値(定義は{@link Language}参照)
+                * @return 音名(例:Bb、B flat、変ロ)
+                * @throws IndexOutOfBoundsException インデックス値が範囲を外れている場合
+                */
+               private String stringOf(int index) {
+                       int sharpFlatIndex = index / 7;
+                       char note = notes.charAt(index - sharpFlatIndex * 7);
+                       String sharpFlat = sharpFlatList.get(sharpFlatIndex);
+                       return this == IN_JAPANESE ? sharpFlat + note : note + sharpFlat;
+               }
+               /**
+                * 音名に対するインデックス値を返します。
+                * 音名は通常、英大文字(ABCDEFG)ですが、英小文字(abcdefg)も認識します。
+                * 日本語名(イロハニホヘト)はサポートしていません。
+                *
+                * @param noteSymbol 音名で始まる文字列
+                * @return インデックス値(定義は{@link Language}参照)
+                * @throws UnsupportedOperationException このオブジェクトが {@link #IN_JAPANESE} の場合
+                * @throws NullPointerException 引数がnullの場合
+                * @throws IllegalArgumentException 引数が空文字列の場合、または音名で始まっていない場合
+                */
+               private int indexOf(String noteSymbol) {
+                       if( this == IN_JAPANESE ) throw new UnsupportedOperationException();
+                       Objects.requireNonNull(noteSymbol,"Musical note symbol must not be null");
+                       String trimmed = noteSymbol.trim();
+                       if( trimmed.isEmpty() ) throw new IllegalArgumentException("Empty musical note symbol");
+                       int noteIndex = notes.indexOf(Character.toUpperCase(trimmed.charAt(0)));
+                       if( noteIndex < 0 ) throw new IllegalArgumentException(
+                                       "Unknown musical note symbol ["+noteSymbol+"] not in ["+notes+"]");
+                       return 7 * sharpFlatIndexOf(trimmed.substring(1)) + noteIndex;
+               }
+               /**
+                * メジャーを表す文字列
+                */
+               private String major;
+               /**
+                * マイナーを表す文字列
+                */
+               private String minor;
+               /**
+                * メジャーとマイナーを併記する場合の区切り文字
+                */
+               private String majorMinorDelimiter;
+               /**
+                * 調の文字列表現を返します。メジャー/マイナーの区別がない場合、両方の表現を返します。
+                * @param majorCo5 調の五度圏の値(0 == C/Am)
+                * @param majorMinor メジャー/マイナーの区別
+                * @return 調の文字列表現
+                */
+               public String stringOf(Key key) {
+                       String s = "";
+                       int co5 = key.toCo5();
+                       Key.MajorMinor majorMinor = key.majorMinor();
+                       if( majorMinor.includes(Key.MajorMinor.MAJOR) ) {
+                               s = stringOf(co5 + INDEX_OF_C) + major;
+                               if( ! majorMinor.includes(Key.MajorMinor.MINOR) ) return s;
+                               s += majorMinorDelimiter;
+                       }
+                       return s + stringOf(co5 + INDEX_OF_A) + minor;
+               }
+       }
        /** メジャーキー基準の五度圏インデックス値 */
        private int majorCo5;
        /** ノート番号(0~11) */
@@ -33,9 +158,7 @@ public class NoteSymbol implements Cloneable {
         * @param noteSymbol 音名の文字列
         * @throws IllegalArgumentException 引数が空文字列の場合、または音名で始まっていない場合
         */
-       public NoteSymbol(String noteSymbol) {
-               this(NoteSymbolLanguage.SYMBOL.indexOf(noteSymbol) - INDEX_OF_C);
-       }
+       public NoteSymbol(String noteSymbol) { this(co5OfSymbol(noteSymbol)); }
        @Override
        protected NoteSymbol clone() { return new NoteSymbol(majorCo5); }
        /**
@@ -75,17 +198,6 @@ public class NoteSymbol implements Cloneable {
         */
        public int toCo5() { return majorCo5; }
        /**
-        * メジャー/マイナーキーに対応する五度圏インデックス値を返します。
-        * <p>マイナーの場合、メジャー基準の五度圏インデックス値から3が差し引かれます。
-        * 例えば、C major の場合は調号が0個なのに対し、C minor のときは調号の♭が3個に増えますが、
-        * 3を差し引くことによってこのズレが補正されます。
-        * </p>
-        *
-        * @param isMinor マイナーのときtrue
-        * @return 五度圏インデックス値
-        */
-       public int toCo5ForKey(boolean isMinor) { return isMinor ? majorCo5 - 3 : majorCo5; }
-       /**
         * ノート番号(0~11)を返します。
         * <p>これはMIDIノート番号からオクターブ情報を抜いた値と同じです。
         * 五度圏インデックス値をノート番号に変換した場合、
@@ -100,23 +212,23 @@ public class NoteSymbol implements Cloneable {
         * @return この音階の文字列表現
         */
        @Override
-       public String toString() { return toStringIn(NoteSymbolLanguage.SYMBOL); }
+       public String toString() { return toStringIn(Language.SYMBOL); }
        /**
-        * 指定した言語モードにおける文字列表現を返します。
+        * この音階の文字列表現を、引数で指定された言語モードで返します。
         * @param language 言語モード
         * @return 文字列表現
         */
-       public String toStringIn(NoteSymbolLanguage language) {
+       public String toStringIn(Language language) {
                return language.stringOf(majorCo5 + INDEX_OF_C);
        }
        /**
-        * 指定した言語モードにおける、マイナーキー用の文字列表現を返します。
-        * マイナーキー用の文字列では、例えば五度圏インデックスが0の場合、Cの代わりにAを返します。
-        * @param language 言語モード
-        * @return 文字列表現
+        * 引数で指定された音名のメジャーキー基準の五度圏インデックスを返します。
+        * @param noteSymbol 音名の文字列
+        * @return メジャーキー基準の五度圏インデックス
+        * @throws IllegalArgumentException 引数が空文字列の場合、または音名で始まっていない場合
         */
-       public String toMinorKeyRootStringIn(NoteSymbolLanguage language) {
-               return language.stringOf(majorCo5 + INDEX_OF_A);
+       public static int co5OfSymbol(String noteSymbol) {
+               return Language.SYMBOL.indexOf(noteSymbol) - INDEX_OF_C;
        }
        /**
         * 指定の最大文字数の範囲で、MIDIノート番号が示す音名を返します。
diff --git a/src/camidion/chordhelper/music/NoteSymbolLanguage.java b/src/camidion/chordhelper/music/NoteSymbolLanguage.java
deleted file mode 100644 (file)
index ef2cb91..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-package camidion.chordhelper.music;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * 音階や調を表すシンボルの言語モードによる違いを定義します。
- * <p>音名には、下記のような五度圏順のインデックス値(0~34)が割り当てられます。
- * <pre>Fbb=0, Cbb=1, .. Bb=13, F=14, C=15, .. B=20, F#=21, C#=22, .. B#=27, Fx=28, .. Bx=34</pre>
- */
-public enum NoteSymbolLanguage {
-       /**
-        * 記号表記(Bb, F#)
-        */
-       SYMBOL(Arrays.asList("bb","b","","#","x"),"","m"),
-       /**
-        * 英名表記(B flat, F sharp)
-        */
-       NAME(Arrays.asList(" double flat"," flat",""," sharp"," double sharp")," major"," minor"),
-       /**
-        * 日本名表記(変ロ, 嬰ヘ)
-        */
-       IN_JAPANESE(Arrays.asList("重変","変","","嬰","重嬰"),"長調","短調");
-       //
-       private NoteSymbolLanguage(List<String> sharpFlatList, String major, String minor) {
-               if( (this.sharpFlatList = sharpFlatList).contains("変") ) {
-                       this.notes = "ヘハトニイホロ";
-                       this.majorMinorDelimiter = "/";
-               } else {
-                       this.notes = "FCGDAEB";
-                       this.majorMinorDelimiter = " / ";
-               }
-               this.major = major;
-               this.minor = minor;
-       }
-       /**
-        * ♭や♯の表記を、半音下がる数が多いほうから順に並べたリスト
-        */
-       private List<String> sharpFlatList;
-       /**
-        * 引数の先頭にある、♭や♯などの変化記号のインデックス(0~4)を返します。
-        * <p>変化記号がない場合、2 を返します。それ以外は次の値を返します。</p>
-        * <ul>
-        * <li>ダブルシャープ:4</li>
-        * <li>シャープ:3</li>
-        * <li>フラット:1</li>
-        * <li>ダブルフラット:0</li>
-        * </ul>
-        * @param s 変化記号で始まる文字列
-        * @return インデックス
-        */
-       private int sharpFlatIndexOf(String s) {
-               int index = 0;
-               for( String sharpFlat : sharpFlatList ) {
-                       if( ! sharpFlat.isEmpty() && s.startsWith(sharpFlat) ) return index;
-                       index++;
-               }
-               return 2;
-       }
-       /**
-        * 音名を五度圏順で並べた7文字
-        */
-       private String notes;
-       /**
-        * インデックス値に該当する音名を返します。
-        * @param index インデックス値(定義は{@link NoteSymbolLanguage}参照)
-        * @return 音名(例:Bb、B flat、変ロ)
-        * @throws IndexOutOfBoundsException インデックス値が範囲を外れている場合
-        */
-       public String stringOf(int index) {
-               int sharpFlatIndex = index / 7;
-               char note = notes.charAt(index - sharpFlatIndex * 7);
-               String sharpFlat = sharpFlatList.get(sharpFlatIndex);
-               return this == IN_JAPANESE ? sharpFlat + note : note + sharpFlat;
-       }
-       /**
-        * 音名に対するインデックス値を返します。
-        * 音名は通常、英大文字(ABCDEFG)ですが、英小文字(abcdefg)も認識します。
-        * 日本語名(イロハニホヘト)はサポートしていません。
-        *
-        * @param noteSymbol 音名で始まる文字列
-        * @return インデックス値(定義は{@link NoteSymbolLanguage}参照)
-        * @throws UnsupportedOperationException このオブジェクトが {@link #IN_JAPANESE} の場合
-        * @throws NullPointerException 引数がnullの場合
-        * @throws IllegalArgumentException 引数が空文字列の場合、または音名で始まっていない場合
-        */
-       public int indexOf(String noteSymbol) {
-               if( this == IN_JAPANESE ) throw new UnsupportedOperationException();
-               Objects.requireNonNull(noteSymbol,"Musical note symbol must not be null");
-               String trimmed = noteSymbol.trim();
-               if( trimmed.isEmpty() ) throw new IllegalArgumentException("Empty musical note symbol");
-               int noteIndex = notes.indexOf(Character.toUpperCase(trimmed.charAt(0)));
-               if( noteIndex < 0 ) throw new IllegalArgumentException(
-                               "Unknown musical note symbol ["+noteSymbol+"] not in ["+notes+"]");
-               return 7 * sharpFlatIndexOf(trimmed.substring(1)) + noteIndex;
-       }
-       /**
-        * メジャーを表す文字列
-        */
-       private String major;
-       /**
-        * マイナーを表す文字列
-        */
-       private String minor;
-       /**
-        * メジャーとマイナーを併記する場合の区切り文字
-        */
-       private String majorMinorDelimiter;
-       /**
-        * 調の文字列表現を返します。メジャー/マイナーの区別が不明な場合、両方の表現を返します。
-        * @param note 音名
-        * @param majorMinor 負数:マイナー 0:不明 正数:メジャー
-        * @return 調の文字列表現
-        */
-       public String keyStringOf(NoteSymbol note, Key.MajorMinor majorMinor) {
-               String s = "";
-               if( majorMinor == Key.MajorMinor.MAJOR || majorMinor == Key.MajorMinor.MAJOR_OR_MINOR ) {
-                       s = note.toStringIn(this) + major;
-                       if( majorMinor == Key.MajorMinor.MAJOR ) return s;
-                       s += majorMinorDelimiter;
-               }
-               return s + note.toMinorKeyRootStringIn(this) + minor;
-       }
-}
index 397aae5..552c620 100644 (file)
@@ -50,10 +50,8 @@ public class MidiKeyboardPanel extends JPanel {
                        {
                                setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
                                add( Box.createHorizontalStrut(5) );
-                               add(velocitySelecter = new VelocitySelecter(
-                                       keyboardCenterPanel.keyboard.velocityModel)
-                               );
-                               add(keySelecter = new KeySignatureSelecter(false));
+                               add(velocitySelecter = new VelocitySelecter(keyboardCenterPanel.keyboard.velocityModel));
+                               add(keySelecter = new KeySignatureSelecter());
                                add( keyboardCenterPanel.keyboard.chordDisplay );
                                add( Box.createHorizontalStrut(5) );
                        }