*/
public static class VersionInfo {
public static final String NAME = "MIDI Chord Helper";
- public static final String VERSION = "Ver.20161123.1";
+ public static final String VERSION = "Ver.20161127.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/";
import camidion.chordhelper.music.Key;
import camidion.chordhelper.music.Music;
import camidion.chordhelper.music.NoteSymbol;
-import camidion.chordhelper.music.SymbolLanguage;
+import camidion.chordhelper.music.NoteSymbolLanguage;
/**
* MIDI Chord Helper 用のコードボタンマトリクス
}
else {
tip += key.signatureDescription() + " " +
- key.toStringIn(SymbolLanguage.IN_JAPANESE);
+ key.toStringIn(NoteSymbolLanguage.IN_JAPANESE);
if( v == 0 ) {
setIcon(new ButtonIcon(ButtonIcon.NATURAL_ICON));
}
import javax.swing.JLabel;
import camidion.chordhelper.music.Key;
-import camidion.chordhelper.music.SymbolLanguage;
+import camidion.chordhelper.music.NoteSymbolLanguage;
/**
* 調表示ラベル
}
setText( "key:" + key.toString() );
setToolTipText(
- "Key: " + key.toStringIn(SymbolLanguage.NAME)
- + " " + key.toStringIn(SymbolLanguage.IN_JAPANESE)
+ "Key: " + key.toStringIn(NoteSymbolLanguage.NAME)
+ + " " + key.toStringIn(NoteSymbolLanguage.IN_JAPANESE)
+ " (" + key.signatureDescription() + ")"
);
setEnabled(true);
import javax.swing.JPanel;
import camidion.chordhelper.music.Key;
-import camidion.chordhelper.music.SymbolLanguage;
+import camidion.chordhelper.music.NoteSymbolLanguage;
/**
* 調性選択
private void updateToolTipText() {
Key key = getKey();
keysigCombobox.setToolTipText(
- "Key: " + key.toStringIn( SymbolLanguage.NAME )
- + " " + key.toStringIn( SymbolLanguage.IN_JAPANESE )
+ "Key: " + key.toStringIn( NoteSymbolLanguage.NAME )
+ + " " + key.toStringIn( NoteSymbolLanguage.IN_JAPANESE )
+ " (" + key.signatureDescription() + ")"
);
}
* @return コードの説明(英語)
*/
public String toName() {
- String chord_name = rootNoteSymbol.toStringIn(SymbolLanguage.NAME) + nameSuffix() ;
+ String chord_name = rootNoteSymbol.toStringIn(NoteSymbolLanguage.NAME) + nameSuffix() ;
if( ! rootNoteSymbol.equals(bassNoteSymbol) ) {
- chord_name += " on " + bassNoteSymbol.toStringIn(SymbolLanguage.NAME);
+ chord_name += " on " + bassNoteSymbol.toStringIn(NoteSymbolLanguage.NAME);
}
return chord_name;
}
* @param co5 五度圏インデックス値
* @param majorMinor {@link #MAJOR}、{@link #MINOR}、{@link #MAJOR_OR_MINOR} のいずれか
*/
- public Key(int co5, int majorMinor) {
- setKey(co5, majorMinor);
- }
+ public Key(int co5, int majorMinor) { setKey(co5, majorMinor); }
/**
* 指定の五度圏インデックス値を持つ、
* メジャー/マイナーの明確な調を構築します。
* @param co5 五度圏インデックス値
* @param isMinor true:マイナー、false:メジャー
*/
- public Key(int co5, boolean isMinor) {
- setKey(co5, isMinor);
- }
+ public Key(int co5, boolean isMinor) { setKey(co5, isMinor); }
/**
* MIDIの調データ(メタメッセージ2byte)から調を構築します。
* @param midiData MIDIの調データ
*/
- public Key(byte midiData[]) {
- setBytes(midiData);
- }
+ public Key(byte midiData[]) { setBytes(midiData); }
/**
* C、Am のような文字列から調を構築します。
* @param keySymbol 調を表す文字列
setKey(chord.rootNoteSymbol().toCo5(isMinor), isMinor);
}
@Override
- public Key clone() {
- return new Key(co5, majorMinor);
- }
+ public Key clone() { return new Key(co5, majorMinor); }
@Override
public boolean equals(Object anObject) {
- if( this == anObject )
- return true;
+ if( this == anObject ) return true;
if( anObject instanceof Key ) {
Key another = (Key) anObject;
return
return false;
}
@Override
- public int hashCode() {
- return majorMinor * 256 + co5 ;
- }
+ public int hashCode() { return majorMinor * 256 + co5 ; }
private void setKey(int co5, boolean isMinor) {
setKey( co5, isMinor ? MINOR : MAJOR );
}
* 相対ドの音階を返します。
* @return 相対ドの音階(0~11)
*/
- public int relativeDo() {
- return NoteSymbol.toNoteNumber(co5);
- }
+ public int relativeDo() { return NoteSymbol.toNoteNumber(co5); }
/**
* この調のルート音を返します。
* メジャーキーの場合は相対ド、
* @param noteNumber ノート番号
* @return 指定されたノート番号がこのキーのスケールの構成音ならtrue
*/
- public boolean isOnScale(int noteNumber) {
- return Music.isOnScale(noteNumber, co5);
- }
+ public boolean isOnScale(int noteNumber) { return Music.isOnScale(noteNumber, co5); }
/**
* この調を、指定された半音オフセット値だけ移調します。
*
* </p>
*/
public void toggleEnharmonically() {
- if( co5 > 4 )
- co5 -= 12;
- else if( co5 < -4 )
- co5 += 12;
+ if( co5 > 4 ) co5 -= 12; else if( co5 < -4 ) co5 += 12;
}
/**
* この調を正規化します。
*
* @return 平行調
*/
- public Key relativeKey() {
- return new Key(co5, majorMinor * (-1));
- }
+ public Key relativeKey() { return new Key(co5, -majorMinor); }
/**
* 同主調を生成して返します。
* これは元の調とルート音が同じで、メジャーとマイナーが異なる調です。
* 五度圏で真裏にあたる調を生成して返します。
* @return 五度圏で真裏にあたる調
*/
- public Key oppositeKey() {
- return new Key(Music.oppositeCo5(co5), majorMinor);
- }
+ public Key oppositeKey() { return new Key(Music.oppositeCo5(co5), majorMinor); }
/**
* この調の文字列表現を C、Am のような形式で返します。
* @return この調の文字列表現
*/
@Override
- public String toString() {
- return toStringIn(SymbolLanguage.SYMBOL);
- }
+ public String toString() { return toStringIn(NoteSymbolLanguage.SYMBOL); }
/**
* この調の文字列表現を、指定された形式で返します。
* @return この調の文字列表現
*/
- public String toStringIn(SymbolLanguage language) {
- return language.keyOf(new NoteSymbol(co5), majorMinor);
+ public String toStringIn(NoteSymbolLanguage language) {
+ return language.keyStringOf(new NoteSymbol(co5), majorMinor);
}
/**
* 調号を表す半角文字列を返します。
if( msgdata.length == 2 ) {
Key key = new Key(msgdata);
str += ": " + key.signatureDescription();
- str += " (" + key.toStringIn(SymbolLanguage.NAME) + ")";
+ str += " (" + key.toStringIn(NoteSymbolLanguage.NAME) + ")";
break;
}
str += ": Size not 2 byte : data=(";
* </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");
/**
* メジャーキー基準の五度圏インデックス値
*/
* 指定の音名が空、またはA~Gの範囲を外れている場合
*/
public NoteSymbol(String noteSymbol) {
- this(SymbolLanguage.SYMBOL.majorCo5Of(noteSymbol.trim()));
+ this(NoteSymbolLanguage.SYMBOL.indexOf(noteSymbol) - INDEX_OF_C);
}
@Override
- protected NoteSymbol clone() {
- return new NoteSymbol(majorCo5);
- }
+ protected NoteSymbol clone() { return new NoteSymbol(majorCo5); }
/**
* この音階が指定されたオブジェクトと等しいか調べます。
*
*/
@Override
public boolean equals(Object anObject) {
- if( this == anObject )
- return true;
- if( anObject instanceof NoteSymbol ) {
- NoteSymbol another = (NoteSymbol) anObject;
- return majorCo5 == another.majorCo5;
- }
- return false;
+ if( this == anObject ) return true;
+ if( ! (anObject instanceof NoteSymbol) ) return false;
+ return majorCo5 == ((NoteSymbol)anObject).majorCo5;
}
/**
* この音階のハッシュコード値として、
* @param isMinor マイナーのときtrue
* @return 五度圏インデックス値
*/
- public int toCo5(boolean isMinor) {
- return isMinor ? majorCo5 - 3 : majorCo5;
- }
+ public int toCo5(boolean isMinor) { return isMinor ? majorCo5 - 3 : majorCo5; }
/**
* ノート番号(0~11)を返します。
* <p>これはMIDIノート番号からオクターブ情報を抜いた値と同じです。
* @return この音階の文字列表現
*/
@Override
- public String toString() {
- return toStringIn(SymbolLanguage.SYMBOL, false);
- }
+ public String toString() { return toStringIn(NoteSymbolLanguage.SYMBOL); }
/**
* 指定した言語モードにおける文字列表現を返します。
* @param language 言語モード
* @return 文字列表現
*/
- public String toStringIn(SymbolLanguage language) {
+ public String toStringIn(NoteSymbolLanguage language) {
return toStringIn(language, false);
}
/**
* @param isMinor マイナーのときtrue
* @return 文字列表現
*/
- public String toStringIn(SymbolLanguage language, boolean isMinor) {
- int co5index771 = majorCo5 + 15; // 0(Fbb) -> 7(Fb) -> 14(F) -> 15(C)
- if( isMinor ) co5index771 += 3; // 15(C) -> 18(Am)
- if( co5index771 < 0 || co5index771 >= 35 ) {
+ public String toStringIn(NoteSymbolLanguage language, boolean isMinor) {
+ int index = majorCo5 + (isMinor ? INDEX_OF_A : INDEX_OF_C);
+ if( index < 0 || index >= 35 ) {
// インデックスOB発生の恐れがある場合
// 調号 5b ~ 6# の範囲に収まるルート音となるような異名同音(enharmonic)に置き換える
- co5index771 = Music.mod12(co5index771); // returns 0(Fbb) ... 7(Fb) 8(Cb) 9(Gb) 10(Db) 11(Ab)
+ index = Music.mod12(index); // returns 0(Fbb) ... 7(Fb) 8(Cb) 9(Gb) 10(Db) 11(Ab)
if( isMinor ) {
// 18(Am)
- if( co5index771 == 0 )
- co5index771 += Music.SEMITONES_PER_OCTAVE * 2; // 0(Fbbm) -> 24(D#m 5#)
+ if( index == 0 )
+ index += Music.SEMITONES_PER_OCTAVE * 2; // 0(Fbbm) -> 24(D#m 5#)
else
- co5index771 += Music.SEMITONES_PER_OCTAVE; // 1(Cbbm) -> 13(Bbm 5b)
+ index += Music.SEMITONES_PER_OCTAVE; // 1(Cbbm) -> 13(Bbm 5b)
}
else {
// 15(C)
- if( co5index771 < 10 ) // 0(Fbb) -> 12(Eb 3b), 9(Gb) -> 21(F# 6#)
- co5index771 += Music.SEMITONES_PER_OCTAVE;
+ if( index < 10 ) // 0(Fbb) -> 12(Eb 3b), 9(Gb) -> 21(F# 6#)
+ index += Music.SEMITONES_PER_OCTAVE;
}
}
- return language.noteSymbolOf(co5index771);
+ return language.stringOf(index);
}
/**
* 指定の最大文字数の範囲で、MIDIノート番号が示す音名を返します。
+ * <p>白鍵の場合は A ~ G までの文字、黒鍵の場合は#と♭の両方の表現を返します。
+ * ただし、制限文字数の指定により#と♭の両方を返せないことがわかった場合、
+ * 五度圏のC/Amに近いキーでよく使われるほうの表記(C# Eb F# Ab Bb)だけを返します。
+ * </p>
* <p>ノート番号だけでは物理的な音階情報しか得られないため、
* 白鍵で#♭のついた音階表現(B#、Cb など)、
* ダブルシャープ、ダブルフラットを使った表現は返しません。
* </p>
- * <p>白鍵の場合は A ~ G までの文字、黒鍵の場合は#と♭の両方の表現を返します。
- * ただし、制限文字数の指定により、#と♭の両方を返せないことがわかった場合は、
- * 五度圏で値0(キー C / Am)からの距離が、メジャー、マイナーの両方を含めて
- * 近くにあるほうの表現(C# Eb F# Ab Bb)のみを返します。
- * </p>
- * @param noteNo MIDIノート番号
+ * @param noteNumber MIDIノート番号
* @param maxChars 最大文字数
* @return MIDIノート番号が示す音名
*/
- public static String noteNumberToSymbol(int noteNo, int maxChars) {
- int co5 = Music.mod12(Music.reverseCo5(noteNo));
- if( co5 == 11 ) {
- return (new NoteSymbol(-1)).toString();
- }
- else if( co5 >= 6 ) {
- if( maxChars >= 7 ) {
- return
- (new NoteSymbol(co5)).toString() + " / " +
- (new NoteSymbol(co5 - 12)).toString();
- }
- else {
- // String capacity not enough
- // Select only one note (sharped or flatted)
- return (new NoteSymbol(co5 - ((co5 >= 8) ? 12 : 0))).toString();
- }
- }
- else return (new NoteSymbol(co5)).toString();
+ public static String noteNumberToSymbol(int noteNumber, int maxChars) {
+ int co5 = Music.mod12(Music.reverseCo5(noteNumber));
+ if( co5 == 11 ) co5 -= Music.SEMITONES_PER_OCTAVE; // E# -> F
+ if( co5 < 6 ) return (new NoteSymbol(co5)).toString(); // F C G D A E B
+
+ if( maxChars >= "F# / Gb".length() ) return
+ (new NoteSymbol(co5)).toString() + " / " +
+ (new NoteSymbol(co5 - Music.SEMITONES_PER_OCTAVE)).toString();
+
+ if( co5 >= 8 ) co5 -= Music.SEMITONES_PER_OCTAVE; // G# -> Ab, D# -> Eb, A# -> Bb
+ return (new NoteSymbol(co5)).toString(); // C# Eb F# Ab Bb
}
/**
* 最大256文字の範囲で、MIDIノート番号が示す音名を返します。
--- /dev/null
+package camidion.chordhelper.music;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 音階シンボルの言語モードによる違いを定義します。
+ * <p>各音階にはインデックス値が割り当てられます。
+ * このインデックス値は、五度圏順で並んだ変化記号のない7音階(FCGDAEB)に対するインデックス値
+ * x (0~6) と、
+ * 変化記号(ダブルフラット、フラット、なし、シャープ、ダブルシャープ)に対するインデックス値
+ * y (0~4) に基づいて、次の式で計算されます。</p>
+ * <pre>インデックス値 = 5y + x</pre>
+ * <p>このインデックス値の範囲は下記のように 0~34 となります。</p>
+ * <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 List<String> sharpFlatList;
+ /**
+ * 音名を五度圏順で並べた7文字
+ */
+ private String notes;
+ /**
+ * メジャーを表す文字列
+ */
+ private String major;
+ /**
+ * マイナーを表す文字列
+ */
+ private String minor;
+ /**
+ * メジャーとマイナーを併記する場合の区切り文字
+ */
+ private String majorMinorDelimiter;
+
+ 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;
+ }
+ /**
+ * インデックス値に該当する音名を返します。
+ * @param index インデックス値(定義は{@link NoteSymbolLanguage}参照)
+ * @return 音名(例:Bb、B flat、変ロ)
+ * @throws IndexOutOfBoundsException インデックスが範囲を外れている場合
+ */
+ public String stringOf(int index) {
+ int sharpFlatIndex = index / 7; // 0 1 2 3 4
+ int noteSymbolIndex = index - sharpFlatIndex * 7; // 0 1 2 3 4 5 6
+ String note = notes.substring(noteSymbolIndex, noteSymbolIndex+1);
+ String sharpFlat = sharpFlatList.get(sharpFlatIndex);
+ return this == IN_JAPANESE ? sharpFlat + note : note + sharpFlat;
+ }
+ /**
+ * 調の文字列表現を返します。メジャー/マイナーの区別が不明な場合、両方の表現を返します。
+ * @param note 音名
+ * @param majorMinor -1:マイナー 0:不明 1:メジャー
+ * @return 調の文字列表現
+ */
+ public String keyStringOf(NoteSymbol note, int majorMinor) {
+ String majorString = note.toStringIn(this, false) + major;
+ if( majorMinor > 0 ) {
+ return majorString;
+ }
+ else {
+ String minorString = note.toStringIn(this, true) + minor;
+ return majorMinor < 0 ? minorString : majorString + majorMinorDelimiter + minorString ;
+ }
+ }
+ /**
+ * 音名の文字列(英字のみ)に対するインデックス値を返します。
+ * 音名は通常大文字ですが、小文字も認識します。
+ *
+ * @param noteSymbol 音名の文字列
+ * @return インデックス値(定義は{@link NoteSymbolLanguage}参照)
+ * @throws
+ * UnsupportedOperationException このオブジェクトが {@link #IN_JAPANESE} の場合
+ * @throws
+ * NullPointerException 指定された音名がnullの場合
+ * @throws
+ * IllegalArgumentException 指定された音名が空、または[A~G、a~g]の範囲を外れている場合
+ */
+ 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");
+ char prefix = trimmed.charAt(0);
+ int index = notes.indexOf(Character.toUpperCase(prefix));
+ if( index < 0 ) {
+ throw new IllegalArgumentException("Unknown musical note symbol ["+noteSymbol+"] not in ["+notes+"]");
+ }
+ String suffix = trimmed.substring(1);
+ for( String sf : sharpFlatList ) {
+ if( suffix.startsWith(sf) ) break; // bb が先にヒットするので b と間違える心配はない
+ index += 7;
+ }
+ return index;
+ }
+}
+++ /dev/null
-package camidion.chordhelper.music;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * シンボルの言語モード(音階、調など)
- */
-public enum SymbolLanguage {
- /**
- * シンボル表記(Bb, F#)
- */
- SYMBOL(Arrays.asList("bb","b","","#","x"),"FCGDAEB",false,"","m"," / "),
- /**
- * 英名表記(B flat, F sharp)
- */
- NAME(Arrays.asList(" double flat"," flat",""," sharp"," double sharp"),
- "FCGDAEB",false," major"," minor"," / "),
- /**
- * 日本名表記(変ロ, 嬰ヘ)
- */
- IN_JAPANESE(Arrays.asList("重変","変","","嬰","重嬰"),
- "ヘハトニイホロ",true,"長調","短調","/");
- /**
- * ♭や♯の表記を、半音下がる数が多いほうから順に並べたリスト
- */
- private List<String> sharpFlatList;
- /**
- * 音名を五度圏順で並べた文字列(必ず7文字でなければならない)
- */
- private String notes;
- /**
- * 変化記号が音名の前につく(true)か後ろにつく(false)か
- * <p>英語の場合は B♭ のように♭が後ろ、
- * 日本語の場合は「変ロ」のように「変」が前につくことを表します。
- * </p>
- */
- private boolean preSharpFlat;
- /**
- * メジャーを表す文字列
- */
- private String major;
- /**
- * マイナーを表す文字列
- */
- private String minor;
- /**
- * メジャーとマイナーを併記する場合の区切り文字
- */
- private String majorMinorDelimiter;
-
- private SymbolLanguage(List<String> sharpFlatList, String notes, boolean preSharpFlat,
- String major, String minor, String majorMinorDelimiter
- ) {
- this.sharpFlatList = sharpFlatList;
- this.notes = notes;
- this.preSharpFlat = preSharpFlat;
- this.major = major;
- this.minor = minor;
- this.majorMinorDelimiter = majorMinorDelimiter;
- }
- /**
- * 補正した五度圏インデックスに該当する音名を返します。
- * 負数を避けるため、C=0ではなく、+15した値、
- * すなわちFbb=0になるよう補正したインデックスを使います。
- * @param co5index771 補正した五度圏インデックス(範囲:0~34)
- * (Fbb=0, Cbb=1, .. F=14, C=15, .. F#=21, C#=22, .. B#=27, Fx=28, .. Bx=34)
- * @return 音名(例:Bb、B flat、変ロ)
- * @throws IndexOutOfBoundsException 補正した五度圏インデックスが範囲を外れている場合
- */
- public String noteSymbolOf(int co5index771) {
- int sharpFlatIndex = co5index771 / 7; // 0 1 2 3 4
- int noteSymbolIndex = co5index771 - sharpFlatIndex * 7; // 0 1 2 3 4 5 6
- String note = notes.substring(noteSymbolIndex, noteSymbolIndex+1);
- String sharpFlat = sharpFlatList.get(sharpFlatIndex);
- return preSharpFlat ? sharpFlat + note : note + sharpFlat;
- }
- /**
- * 調の文字列表現を返します。メジャー/マイナーの区別が不明な場合、両方の表現を返します。
- * @param note 音名
- * @param majorMinor -1:マイナー 0:不明 1:メジャー
- * @return 調の文字列表現
- */
- public String keyOf(NoteSymbol note, int majorMinor) {
- String majorString = note.toStringIn(this, false) + major;
- if( majorMinor > 0 ) {
- return majorString;
- }
- else {
- String minorString = note.toStringIn(this, true) + minor;
- return majorMinor < 0 ? minorString : majorString + majorMinorDelimiter + minorString ;
- }
- }
- /**
- * 音名の文字列を、メジャーキー基準の五度圏インデックス値に変換します。
- * 音名は通常大文字ですが、小文字も認識します。
- *
- * @param noteSymbol 音名の文字列
- * @return メジャーキー基準の五度圏インデックス値
- * @throws
- * IllegalArgumentException 指定された音名が空、または[A~G、a~g]の範囲を外れている場合
- * @throws
- * NullPointerException 指定された音名がnullの場合
- */
- public int majorCo5Of(String noteSymbol) {
- if( Objects.requireNonNull(noteSymbol,"Musical note symbol must not be null").isEmpty() ) {
- throw new IllegalArgumentException("Empty musical note symbol");
- }
- int co5 = notes.indexOf(Character.toUpperCase(noteSymbol.charAt(0)));
- if( co5 < 0 ) {
- throw new IllegalArgumentException("Unknown musical note symbol ["+noteSymbol+"] not in ["+notes+"]");
- }
- co5--;
- int offset = -14;
- for( String sharpFlat : sharpFlatList ) {
- if( ! sharpFlat.isEmpty() && noteSymbol.startsWith(sharpFlat,1) ) {
- // 変化記号を発見
- // bb のほうが b よりも先にマッチするので誤判定の心配なし
- co5 += offset;
- break;
- }
- offset += 7;
- }
- return co5;
- }
-}