OSDN Git Service

リファクタリング(Chord#set()、Chord#clear()を外部から使う箇所を減らした)
authorAkiyoshi Kamide <kamide@yk.rim.or.jp>
Fri, 30 Dec 2016 04:03:45 +0000 (13:03 +0900)
committerAkiyoshi Kamide <kamide@yk.rim.or.jp>
Fri, 30 Dec 2016 04:03:45 +0000 (13:03 +0900)
src/camidion/chordhelper/ChordHelperApplet.java
src/camidion/chordhelper/chordmatrix/ChordMatrix.java
src/camidion/chordhelper/music/Chord.java
src/camidion/chordhelper/music/ChordProgression.java

index 015702c..72e5f9f 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.20161229.1";
+               public static final String      VERSION = "Ver.20161230.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/";
index a32f77c..fe9fc91 100644 (file)
@@ -22,6 +22,7 @@ import java.awt.event.MouseMotionListener;
 import java.awt.event.MouseWheelEvent;
 import java.awt.event.MouseWheelListener;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import javax.swing.JComponent;
@@ -589,27 +590,19 @@ public class ChordMatrix extends JPanel
        public void mouseExited(MouseEvent e) { }
        public void mouseClicked(MouseEvent e) { }
        public void mouseDragged(MouseEvent e) {
-               Component obj = e.getComponent();
-               if( obj instanceof ChordLabel ) {
-                       ChordLabel labelDraggedFrom = (ChordLabel)obj;
-                       Component obj2 = this.getComponentAt(
+               Component draggedFrom = e.getComponent();
+               if( draggedFrom instanceof ChordLabel ) {
+                       ChordLabel labelDraggedFrom = (ChordLabel)draggedFrom;
+                       Component draggedTo = getComponentAt(
                                labelDraggedFrom.getX() + e.getX(),
                                labelDraggedFrom.getY() + e.getY()
                        );
-                       if( obj2 == this ) {
-                               // Entered gap between chord buttons - do nothing
-                               return;
-                       }
-                       ChordLabel labelDraggedTo = ((obj2 instanceof ChordLabel) ? (ChordLabel)obj2 : null);
+                       if( draggedTo == this ) return; // Entered to gap between chord buttons
+                       ChordLabel labelDraggedTo = ((draggedTo instanceof ChordLabel) ? (ChordLabel)draggedTo : null);
                        if( labelDraggedTo == labelDraggedFrom ) {
-                               // Returned to original chord button
-                               destinationChordLabel = null;
-                               return;
-                       }
-                       if( destinationChordLabel != null ) {
-                               // Already touched another chord button
-                               return;
+                               destinationChordLabel = null; return;
                        }
+                       if( destinationChordLabel != null ) return;
                        Chord chord = labelDraggedFrom.chord.clone();
                        if( labelDraggedFrom.isMinor ) {
                                if( labelDraggedTo == null ) { // Out of chord buttons
@@ -691,23 +684,19 @@ public class ChordMatrix extends JPanel
                        setSelectedChord(chord);
                        destinationChordLabel = (labelDraggedTo == null ? labelDraggedFrom : labelDraggedTo ) ;
                }
-               else if( obj instanceof KeySignatureLabel ) {
-                       KeySignatureLabel l_src = (KeySignatureLabel)obj;
-                       Component obj2 = this.getComponentAt(
-                               l_src.getX() + e.getX(),
-                               l_src.getY() + e.getY()
+               else if( draggedFrom instanceof KeySignatureLabel ) {
+                       KeySignatureLabel keyDraggedFrom = (KeySignatureLabel)draggedFrom;
+                       Component draggedTo = getComponentAt(
+                               keyDraggedFrom.getX() + e.getX(),
+                               keyDraggedFrom.getY() + e.getY()
                        );
-                       if( !(obj2 instanceof KeySignatureLabel) ) {
-                               return;
-                       }
-                       KeySignatureLabel l_dst = (KeySignatureLabel)obj2;
-                       int v = l_dst.co5Value;
+                       if( !(draggedTo instanceof KeySignatureLabel) ) return;
+                       KeySignatureLabel keyDraggedTo = (KeySignatureLabel)draggedTo;
+                       int v = keyDraggedTo.co5Value;
                        if( (e.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0 ) {
-                               setKeySignature( new Key(Music.oppositeCo5(v)) );
-                       }
-                       else {
-                               setKeySignature( new Key(v) );
+                               v = Music.oppositeCo5(v);
                        }
+                       setKeySignature(new Key(v));
                        repaint();
                }
        }
@@ -796,31 +785,31 @@ public class ChordMatrix extends JPanel
                        setKeySignature(new Key(Music.transposeCo5(keyCo5, 1)));
                        return;
                }
-               if( i < 0 ) // No key char found
-                       return;
+               if( i < 0 ) return; // No key char found
                if( iCol < 0 ) iCol += 12; else if( iCol > N_COLUMNS ) iCol -= 12;
                cl = chordLabels[iCol + N_COLUMNS * iRow];
-               chord = cl.chord.clone();
+               List<Chord.Interval> intervals = new ArrayList<Chord.Interval>(Arrays.asList(cl.chord.intervals()));
                if( shiftPressed ) {
-                       chord.set(Chord.Interval.SEVENTH);
+                       if( ! intervals.contains(Chord.Interval.SEVENTH) ) {
+                               intervals.add(Chord.Interval.SEVENTH);
+                       }
                }
-               // specify by previous key
                else if( pcKeyNextShift7 == null ) {
-                       chord.clear(Chord.Interval.SEVENTH);
-               }
-               else {
-                       chord.set(pcKeyNextShift7);
+                       intervals.remove(Chord.Interval.SEVENTH);
                }
+               else intervals.add(pcKeyNextShift7);
                if( e.isAltDown() ) {
                        if( cl.isSus4 ) {
-                               chord.set(Chord.Interval.MAJOR); // To cancel sus4
-                               chord.set(Chord.Interval.SHARP5);
-                       }
-                       else {
-                               chord.set(Chord.Interval.FLAT5);
+                               intervals.remove(Chord.Interval.SUS4);
+                               intervals.add(Chord.Interval.SHARP5);
                        }
+                       else intervals.add(Chord.Interval.FLAT5);
+               }
+               if( e.isControlDown() ) {
+                       // TODO: ^Hなど、ここに到達する前に特殊な keyChar がやってきてしまうことがある
+                       intervals.add(Chord.Interval.NINTH);
                }
-               if( e.isControlDown() ) chord.set(Chord.Interval.NINTH);
+               chord = new Chord(cl.chord, intervals);
                if( selectedChordLabel != null ) clear();
                (selectedChordLabel = cl).setSelection(true);
                setSelectedChord(chord);
index 52a2372..d5267cf 100644 (file)
@@ -188,12 +188,9 @@ public class Chord implements Cloneable {
        };
 
        /**
-        * 現在有効な構成音(ルート、ベースは除く)の音程(初期値はメジャーコードの構成音)
+        * 現在有効な構成音(ルート、ベースは除く)の音程
         */
-       private Map<OffsetIndex, Interval> offsets = new HashMap<OffsetIndex, Interval>() {
-               private void set(Interval itv) { put(itv.getChromaticOffsetIndex(), itv); }
-               { set(Interval.MAJOR); set(Interval.PARFECT5); }
-       };
+       private Map<OffsetIndex, Interval> offsets;
        /**
         * このコードのルート音
         */
@@ -206,77 +203,100 @@ public class Chord implements Cloneable {
        /**
         * 指定されたルート音と構成音を持つコードを構築します。
         * @param root ルート音(ベース音としても使う)
-        * @param itvs その他の構成音の音程
+        * @param intervals その他の構成音の音程(長三度、完全五度は指定しなくてもデフォルトで設定されます)
         */
-       public Chord(NoteSymbol root, Interval... itvs) { this(root, root, itvs); }
+       public Chord(NoteSymbol root, Interval... intervals) {
+               this(root, root, intervals);
+       }
        /**
-        * 指定されたルート音、ベース音、構成音(可変個数)を持つコードを構築します。
+        * 指定されたルート音、ベース音、構成音を持つコードを構築します。
         * @param root ルート音
         * @param bass ベース音
-        * @param itvs その他の構成音の音程
+        * @param intervals その他の構成音の音程(長三度、完全五度は指定しなくてもデフォルトで設定されます)
         */
-       public Chord(NoteSymbol root, NoteSymbol bass, Interval... itvs) {
-               this(root, bass, Arrays.asList(itvs));
+       public Chord(NoteSymbol root, NoteSymbol bass, Interval... intervals) {
+               this(root, bass, Arrays.asList(intervals));
        }
        /**
-        * 指定されたルート音、ベース音、構成音(コレクション)を持つコードを構築します。
+        * 指定されたルート音、ベース音、構成音を持つコードを構築します。
         * @param root ルート音
         * @param bass ベース音
-        * @param itvs その他の構成音の音程
+        * @param intervals その他の構成音の音程(長三度、完全五度は指定しなくてもデフォルトで設定されます)
         */
-       public Chord(NoteSymbol root, NoteSymbol bass, Collection<Interval> itvs) {
+       public Chord(NoteSymbol root, NoteSymbol bass, Collection<Interval> intervals) {
                rootNoteSymbol = root;
                bassNoteSymbol = bass;
-               for(Interval itv : itvs) if(itv != null) set(itv);
+               offsets = new HashMap<>();
+               set(Interval.MAJOR);
+               set(Interval.PARFECT5);
+               set(intervals);
        }
        /**
-        * 元のコードの構成音の一部を変更した新しいコードを構築します。
+        * 元のコードのルート音、ベース音以外の構成音の一部を変更した新しいコードを構築します。
         * @param chord 元のコード
-        * @param itvs ルート音、ベース音を除いた、変更したい構成音の音程
+        * @param intervals 変更したい構成音の音程(ルート音、ベース音を除く)
+        * @throws NullPointerException 元のコードにnullが指定された場合
         */
-       public Chord(Chord original, Interval... itvs) {
-               this(original.rootNoteSymbol, original.bassNoteSymbol);
+       public Chord(Chord original, Interval... intervals) {
+               this(original, Arrays.asList(intervals));
+       }
+       /**
+        * 元のコードのルート音、ベース音以外の構成音の一部を変更した新しいコードを構築します。
+        * @param chord 元のコード
+        * @param intervals 変更したい構成音の音程(ルート音、ベース音を除く)
+        * @throws NullPointerException 元のコードにnullが指定された場合
+        */
+       public Chord(Chord original, Collection<Interval> intervals) {
+               rootNoteSymbol = original.rootNoteSymbol;
+               bassNoteSymbol = original.bassNoteSymbol;
                offsets = new HashMap<>(original.offsets);
-               for(Interval itv : itvs) if(itv != null) set(itv);
+               set(intervals);
        }
        /**
         * 指定された調と同名のコードを構築します。
         * @param key 調
+        * @throws NullPointerException 調にnullが指定された場合
         */
        public Chord(Key key) {
-               int keyCo5 = key.toCo5();
-               if( key.majorMinor() == Key.MajorMinor.MINOR ) {
+               offsets = new HashMap<>(); set(Interval.PARFECT5);
+               int keyCo5 = key.toCo5(); if( key.majorMinor() == Key.MajorMinor.MINOR ) {
                        keyCo5 += 3; set(Interval.MINOR);
-               }
+               } else set(Interval.MAJOR);
                bassNoteSymbol = rootNoteSymbol = new NoteSymbol(keyCo5);
        }
        /**
-        * コード名の文字列からコードを構築します。
-        * @param chordSymbol コード名の文字列
+        * コード名からコードを構築します。
+        * @param chordSymbol コード名
+        * @throws NullPointerException コード名にnullが指定された場合
         */
        public Chord(String chordSymbol) {
+               offsets = new HashMap<>();
+               set(Interval.MAJOR);
+               set(Interval.PARFECT5);
                //
-               // 分数コードの分子と分母に分ける
-               String parts[] = chordSymbol.trim().split("(/|on)");
-               if( parts.length == 0 ) return;
-               //
-               // ルート音とベース音を設定
-               rootNoteSymbol = new NoteSymbol(parts[0]);
-               if( parts.length > 1 && ! parts[0].equals(parts[1]) ) {
-                       bassNoteSymbol = new NoteSymbol(parts[1]);
+               // 分数コードの分子と分母に分け、先頭の音名を取り込む
+               String rootOnBass[] = chordSymbol.trim().split("(/|on)");
+               if( rootOnBass.length == 0 ) {
+                       bassNoteSymbol = rootNoteSymbol = new NoteSymbol();
+                       return;
+               }
+               rootNoteSymbol = new NoteSymbol(rootOnBass[0]);
+               if( rootOnBass.length > 1 && ! rootOnBass[0].equals(rootOnBass[1]) ) {
+                       // 分子(ルート音)と異なる分母(ベース音)が指定されていた場合
+                       bassNoteSymbol = new NoteSymbol(rootOnBass[1]);
                } else {
                        bassNoteSymbol = rootNoteSymbol;
                }
-               // 先頭の音名はもういらないので削除
-               String suffix = parts[0].replaceFirst("^[A-G][#bx]*","");
+               // 先頭の音名はもういらないので削除し、サフィックスだけ残す
+               String suffix = rootOnBass[0].replaceFirst("^[A-G][#bx]*","");
                //
-               // () があれば、その中身を取り出す
-               String suffixParts[] = suffix.split("[\\(\\)]");
-               if( suffixParts.length == 0 ) return;
+               // ()の中と外に分ける
+               String suffixWithParen[] = suffix.split("[\\(\\)]");
+               if( suffixWithParen.length == 0 ) return;
                String suffixParen = "";
-               if( suffixParts.length > 1 ) {
-                       suffixParen = suffixParts[1];
-                       suffix = suffixParts[0];
+               if( suffixWithParen.length > 1 ) {
+                       suffixParen = suffixWithParen[1];
+                       suffix = suffixWithParen[0];
                }
                // +5 -5 aug dim
                if( suffix.matches(".*(\\+5|aug|#5).*") ) set(Interval.FLAT5);
@@ -287,8 +307,10 @@ public class Chord implements Cloneable {
                else if( suffix.matches(".*(6|dim[79]).*") ) set(Interval.SIXTH);
                else if( suffix.matches(".*7.*") ) set(Interval.SEVENTH);
                //
-               // minor sus4  (maj7 と間違えないように比較しつつ、mmaj7も解釈させる)
-               if( suffix.matches(".*m.*") && ! suffix.matches(".*ma.*") || suffix.matches(".*mma.*") ) set(Interval.MINOR);
+               // minor sus4  (m と maj7 を間違えないよう比較しつつ、mmaj7 も認識させる)
+               if( suffix.matches(".*m.*") && ! suffix.matches(".*ma.*") || suffix.matches(".*mma.*") ) {
+                       set(Interval.MINOR);
+               }
                else if( suffix.matches(".*sus4.*") ) set(Interval.SUS4);
                //
                // 9th の判定
@@ -345,6 +367,7 @@ public class Chord implements Cloneable {
         * コードの同一性を判定します。ルート音、ベース音の異名同音は異なるものとみなされます。
         * @param anObject 比較対象
         * @return 等しければtrue
+        * @see #equalsEnharmonically(Chord)
         */
        @Override
        public boolean equals(Object anObject) {
@@ -363,6 +386,7 @@ public class Chord implements Cloneable {
         * ルート音、ベース音の異名同音を同じとみなしたうえで、コードの同一性を判定します。
         * @param another 比較対象のコード
         * @return 等しければtrue
+        * @see #equals(Object)
         */
        public boolean equalsEnharmonically(Chord another) {
                if( another == this ) return true;
@@ -551,10 +575,17 @@ public class Chord implements Cloneable {
        }
        /**
         * 指定した音程の構成音を設定します。
-        * @param itv 設定する音程
+        * @param interval 設定する音程
+        */
+       public void set(Interval interval) {
+               offsets.put(interval.getChromaticOffsetIndex(), interval);
+       }
+       /**
+        * 指定した複数の音程の構成音を設定します。
+        * @param intervals 設定する音程
         */
-       public void set(Interval itv) {
-               offsets.put(itv.getChromaticOffsetIndex(), itv);
+       protected void set(Collection<Interval> intervals) {
+               for(Interval itv : intervals) if(itv != null) set(itv);
        }
        /**
         * 指定した音程の構成音をクリアします。
index 71ab49c..9ebca40 100644 (file)
@@ -1,5 +1,7 @@
 package camidion.chordhelper.music;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Vector;
 import java.util.regex.Pattern;
 
@@ -187,12 +189,12 @@ public class ChordProgression {
                key = new Key(keyCo5, Key.MajorMinor.MAJOR);
                lines = new Vector<Line>();
                Line line = new Line();
-               boolean is_end;
+               boolean isEnd;
                Chord chord, prevChord = new Chord(new NoteSymbol(keyCo5));
                int co5Offset, prevCo5Offset;
                double r;
                for( int mp=0; mp<measureLength; mp++ ) {
-                       is_end = (mp == 0 || mp == measureLength - 1); // 最初または最後の小節かを覚えておく
+                       isEnd = (mp == 0 || mp == measureLength - 1); // 最初または最後の小節かを覚えておく
                        Measure measure = new Measure();
                        ChordStroke lastChordStroke = null;
                        for( int i=0; i<timeSignatureUpper; i++ ) {
@@ -207,7 +209,7 @@ public class ChordProgression {
                                }
                                co5Offset = 0;
                                prevCo5Offset = prevChord.rootNoteSymbol().toCo5() - keyCo5;
-                               if( ! is_end ) {
+                               if( ! isEnd ) {
                                        //
                                        // 最初または最後の小節は常にトニックにする。
                                        // 完全五度ずつ下がる進行を基本としつつ、時々そうでない進行も出現するようにする。
@@ -225,56 +227,58 @@ public class ChordProgression {
                                                } while( co5Offset == prevCo5Offset );
                                        }
                                }
-                               chord = new Chord(new NoteSymbol(keyCo5 + co5Offset));
+                               NoteSymbol rootNote = new NoteSymbol(keyCo5 + co5Offset);
+                               List<Chord.Interval> intervals = new ArrayList<>();
                                switch(co5Offset) {
                                // ルート音ごとに、7th などの付加や、メジャーマイナー反転を行う確率を決める
                                case 5: // VII
                                        if( Math.random() < 0.5 ) {
                                                // m7-5
-                                               chord.set(Chord.Interval.MINOR);
-                                               chord.set(Chord.Interval.FLAT5);
+                                               intervals.add(Chord.Interval.MINOR);
+                                               intervals.add(Chord.Interval.FLAT5);
                                        }
                                        if( Math.random() < 0.8 )
-                                               chord.set(Chord.Interval.SEVENTH);
+                                               intervals.add(Chord.Interval.SEVENTH);
                                        break;
                                case 4: // Secondary dominant (III)
                                        if( prevCo5Offset == 5 ) {
                                                // ルートが長7度→長3度の進行のとき、反転確率を上げる。
                                                // (ハ長調でいう Bm7-5 の次に E7 を出現しやすくする)
-                                               if( Math.random() < 0.2 ) chord.set(Chord.Interval.MINOR);
+                                               if( Math.random() < 0.2 ) intervals.add(Chord.Interval.MINOR);
                                        }
                                        else {
-                                               if( Math.random() < 0.8 ) chord.set(Chord.Interval.MINOR);
+                                               if( Math.random() < 0.8 ) intervals.add(Chord.Interval.MINOR);
                                        }
-                                       if( Math.random() < 0.7 ) chord.set(Chord.Interval.SEVENTH);
+                                       if( Math.random() < 0.7 ) intervals.add(Chord.Interval.SEVENTH);
                                        break;
                                case 3: // VI
-                                       if( Math.random() < 0.8 ) chord.set(Chord.Interval.MINOR);
-                                       if( Math.random() < 0.7 ) chord.set(Chord.Interval.SEVENTH);
+                                       if( Math.random() < 0.8 ) intervals.add(Chord.Interval.MINOR);
+                                       if( Math.random() < 0.7 ) intervals.add(Chord.Interval.SEVENTH);
                                        break;
                                case 2: // II
-                                       if( Math.random() < 0.8 ) chord.set(Chord.Interval.MINOR);
-                                       if( Math.random() < 0.7 ) chord.set(Chord.Interval.SEVENTH);
+                                       if( Math.random() < 0.8 ) intervals.add(Chord.Interval.MINOR);
+                                       if( Math.random() < 0.7 ) intervals.add(Chord.Interval.SEVENTH);
                                        break;
                                case 1: // Dominant (V)
-                                       if( Math.random() < 0.1 ) chord.set(Chord.Interval.MINOR);
-                                       if( Math.random() < 0.3 ) chord.set(Chord.Interval.SEVENTH);
-                                       if( Math.random() < 0.2 ) chord.set(Chord.Interval.NINTH);
+                                       if( Math.random() < 0.1 ) intervals.add(Chord.Interval.MINOR);
+                                       if( Math.random() < 0.3 ) intervals.add(Chord.Interval.SEVENTH);
+                                       if( Math.random() < 0.2 ) intervals.add(Chord.Interval.NINTH);
                                        break;
                                case 0: // Tonic(ここでマイナーで終わるとさみしいので setMinorThird() はしない)
-                                       if( Math.random() < 0.2 ) chord.set(Chord.Interval.MAJOR_SEVENTH);
-                                       if( Math.random() < 0.2 ) chord.set(Chord.Interval.NINTH);
+                                       if( Math.random() < 0.2 ) intervals.add(Chord.Interval.MAJOR_SEVENTH);
+                                       if( Math.random() < 0.2 ) intervals.add(Chord.Interval.NINTH);
                                        break;
                                case -1: // Sub-dominant (IV)
                                        if( Math.random() < 0.1 ) {
-                                               chord.set(Chord.Interval.MINOR);
-                                               if( Math.random() < 0.3 ) chord.set(Chord.Interval.SEVENTH);
+                                               intervals.add(Chord.Interval.MINOR);
+                                               if( Math.random() < 0.3 ) intervals.add(Chord.Interval.SEVENTH);
                                        }
                                        else
-                                               if( Math.random() < 0.2 ) chord.set(Chord.Interval.MAJOR_SEVENTH);
-                                       if( Math.random() < 0.2 ) chord.set(Chord.Interval.NINTH);
+                                               if( Math.random() < 0.2 ) intervals.add(Chord.Interval.MAJOR_SEVENTH);
+                                       if( Math.random() < 0.2 ) intervals.add(Chord.Interval.NINTH);
                                        break;
                                }
+                               chord = new Chord(rootNote, rootNote, intervals);
                                measure.add( lastChordStroke = new ChordStroke(chord) );
                                prevChord = chord;
                        }