1 package camidion.chordhelper.music;
6 public class MelodyTrackSpec extends AbstractNoteTrackSpec {
14 public int beatPattern = 0xFFFF;
16 * あとで音を出し続けるかどうかを表すビット列
18 public int continuousBeatPattern = 0xEEEE;
20 * ベース音を使う場合 true、それ以外のコード構成音を使う場合 false
22 public boolean isBass = false;
26 public boolean randomMelody = false;
30 public boolean randomLyric = false;
32 * 乱数歌詞をNSX-39(ポケット・ミク)対応の
33 * システムエクスクルーシブを使って出力するかどうか
35 public boolean nsx39 = false;
41 public MelodyTrackSpec(int ch, String name) {
43 range = new Range(Note.SEMITONES_PER_OCTAVE * 5, Note.SEMITONES_PER_OCTAVE * 6 );
46 * 音域を指定してメロディトラック仕様を構築
51 public MelodyTrackSpec(int ch, String name, Range range) {
59 public void addChords( ChordProgression cp ) {
64 // 音階ごとの生起確率を決める重みリスト(random_melody の場合)
65 int i, noteNumber, prevNoteNumber = 1;
66 int noteWeights[] = new int[range.maxNote - range.minNote];
69 if( key == null ) key = new Key("C");
71 for( ChordProgression.Line line : cp.lines ) { // 行単位の処理
72 for( ChordProgression.Measure measure : line ) { // 小節単位の処理
73 if( measure.ticks_per_beat == null )
75 ChordProgression.TickRange tickRange = measure.getRange();
76 boolean isNoteOn = false;
80 tick = startTickPos = tickRange.startTickPos, mask = 0x8000;
81 tick < tickRange.end_tick_pos;
82 tick += minNoteTicks, mask >>>= 1
85 Chord chord = measure.chordStrokeAt(tick).chord;
86 int notes[] = chord.toNoteArray(range, null);
89 if( Math.random() < 0.9 ) {
90 if( (beatPattern & mask) == 0 ) {
97 if( (beatPattern & mask) != 0 ) {
102 // 前回のビートで継続していなかったので、
103 // この地点で音を出し始めることにする。
107 if( Math.random() < 0.9 ) {
108 if( (continuousBeatPattern & mask) != 0 ) {
115 if( (continuousBeatPattern & mask) == 0 ) {
119 // このビートの終了tickで音を出し終わることにする。
123 for( i=0; i<noteWeights.length; i++ ) {
124 noteNumber = range.minNote + i;
125 int m12 = Note.mod12(noteNumber - chord.rootNoteSymbol().toNoteNumber());
127 if( chord.indexOf(noteNumber) >= 0 ) {
142 if( ! key.isOnScale( noteNumber ) ) {
147 // 乱高下軽減のため、前回との差によって確率を調整する
148 int diff = noteNumber - prevNoteNumber;
149 if( diff < 0 ) diff = -diff;
150 if( diff == 0 ) w /= 8;
151 else if( diff > 7 ) w = 0;
152 else if( diff > 4 ) w /= 8;
153 totalWeight += (noteWeights[i] = w);
156 noteNumber = range.invertedNoteOf(key.rootNoteNumber());
157 double r = Math.random();
159 for( i=0; i<noteWeights.length; i++ ) {
160 if( (totalWeight -= noteWeights[i]) < 0 ) {
161 noteNumber = range.minNote + i;
167 int index = (int)(Math.random() * MIDISpec.nsx39LyricElements.length);
169 // ポケット・ミク用システムエクスクルーシブ
170 byte nsx39SysEx[] = {
171 0x43, 0x79, 0x09, 0x11, 0x0A, 0x00, (byte)(index & 0x7F), (byte) 0xF7
173 addSysEx(nsx39SysEx, startTickPos);
176 addNote(startTickPos, tick + minNoteTicks, noteNumber, velocity);
178 addStringTo(0x05, MIDISpec.nsx39LyricElements[index], startTickPos);
182 addNote(startTickPos, tick + minNoteTicks, noteNumber, velocity);
184 prevNoteNumber = noteNumber;
188 int note = range.invertedNoteOf(chord.bassNoteSymbol().toNoteNumber());
189 addNote(startTickPos, tick + minNoteTicks, note, velocity);
193 for( int note : notes ) {
194 addNote(startTickPos, tick + minNoteTicks, note, velocity);