protected override object AddNewCore() { ITempoData data1 = new TempoData(); base.Add(data1); return(data1); }
void ModificationEventTimes() { // 一時格納用(計算前の時間を保持したいため) var tempTempoList = new List <TempoData>(tempoList); // テンポイベント時間修正 for (int i = 1; i < tempoList.Count; i++) { TempoData tempo = tempoList[i]; int timeDifference = tempTempoList[i].eventTime - tempTempoList[i - 1].eventTime; tempo.eventTime = (int)(timeDifference * tempoList[i - 1].tick) + tempoList[i - 1].eventTime; tempoList[i] = tempo; } // ノーツイベント時間修正 for (int i = 0; i < noteList.Count; i++) { for (int j = tempoList.Count - 1; j >= 0; j--) { if (noteList[i].eventTime >= tempTempoList[j].eventTime) { NoteData note = noteList[i]; int timeDifference = noteList[i].eventTime - tempTempoList[j].eventTime; note.eventTime = (int)(timeDifference * tempTempoList[j].tick) + tempoList[j].eventTime; // 計算後のテンポ変更イベント時間+その時間 noteList[i] = note; break; } } } // Debug.Log("FinEventTIme"); }
protected override object AddNewCore() { ITempoData tempoData = new TempoData(); Add(tempoData); // Not necessary to hook up event handlers, base class calls InsertItem return(tempoData); }
public void EvaluateCues(List <Cue> cues, List <TempoData> tempoData) { this.length = TempoData.TickToMilliseconds(cues[cues.Count - 1].tick, tempoData) - TempoData.TickToMilliseconds(cues[0].tick, tempoData); if (cues.Count >= 15 && this.length > 30000f) { SplitCues(cues); CalculateSpacing(); CalculateDensity(); CalculateReadability(); difficultyRating = ((spacing + readability) / length) * 500f + (length / 100000f * lengthMultiplier); } else { difficultyRating = 0f; } }
void TrackDataAnalys(byte[] data, HeaderChunkData headerCH) { // Debug.Log(data.Length); uint CrTime = 0; // 現在の時間 [ ms ] byte statusByte = 0; // ステータスバイト bool[] longFlags = new bool[128]; // ロングノーツ用フラグ for (int i = 0; i < data.Length;) { // Debug.Log(i); bool Fintrack = false; uint deltaTime = 0; while (true) { var tmp = data[i++]; // 下位7bitを格納 deltaTime |= (tmp & (uint)0x7f); // 最上位1bitが0ならデータ終了 if ((tmp & 0x80) == 0) { break; } // 次の下位7bit用にビット移動 deltaTime = deltaTime << 7; } // 現在の時間にデルタタイムを足す CrTime += deltaTime; /* ランニングステータスチェック */ if (data[i] >= 0x80) { statusByte = data[i++]; // ステータスバイト保存 } //else:ランニングステータス適応(前回のステータスバイトを使いまわす) // ステータスバイト後のデータ保存用 byte dataByte0, dataByte1; // byte dataByte2, dataByte3; if (statusByte >= 0x80 && statusByte <= 0xef) { switch (statusByte & 0xf0) { /* チャンネルメッセージ */ // ノートオフ case 0x80: dataByte0 = data[i++]; // どのキーが離されたか // ベロシティ値 dataByte1 = data[i++]; // 前のレーンがロングノーツなら if (longFlags[dataByte0]) { // ロング終点ノート情報生成 var note = new NoteData(); note.eventTime = (int)CrTime; note.laneIndex = (int)dataByte0; note.type = NoteType.LongEnd; // リストにつっこむ noteList.Add(note); // ロングノーツフラグ解除 longFlags[note.laneIndex] = false; } break; case 0x90: // ノートオン(ノートオフが呼ばれるまでは押しっぱなし扱い) // どのキーが押されたか dataByte0 = data[i++]; // ベロシティ値という名の音の強さ。ノートオフメッセージの代わりにここで0を送ってくるタイプもある dataByte1 = data[i++]; { // ノート情報生成 var note = new NoteData(); note.eventTime = (int)CrTime; note.laneIndex = (int)dataByte0; note.type = NoteType.Normal; // 独自でやっている。ベロシティ値が最大のときのみロングの始点とする if (dataByte1 == 127) { note.type = NoteType.LongStart; // ロングノーツフラグセット longFlags[note.laneIndex] = true; } // ノートオフイベントではなく、ベロシティ値0をノートオフとして保存する形式もあるので対応 if (dataByte1 == 0) { // 同じレーンで前回がロングノーツ始点なら if (longFlags[note.laneIndex]) { note.type = NoteType.LongEnd; // ロングノーツフラグ解除 longFlags[note.laneIndex] = false; } } // リストにつっこむ noteList.Add(note); } break; case 0xa0: // ポリフォニック キープレッシャー(鍵盤楽器で、キーを押した状態でさらに押し込んだ際に、その圧力に応じて送信される) i += 2; // 使わないのでスルー break; case 0xb0: // コントロールチェンジ(音量、音質など様々な要素を制御するための命令) // コントロールする番号 dataByte0 = data[i++]; // 設定する値 dataByte1 = data[i++]; // ※0x00-0x77までがコントロールチェンジで、それ以上はチャンネルモードメッセージとして処理する if (dataByte0 < 0x78) { // コントロールチェンジ } else { // チャンネルモードメッセージは一律データバイトを2つ使用している // チャンネルモードメッセージ switch (dataByte0) { case 0x78: // オールサウンドオフ // 該当するチャンネルの発音中の音を直ちに消音する。後述のオールノートオフより強制力が強い。 break; case 0x79: // リセットオールコントローラ // 該当するチャンネルの全種類のコントロール値を初期化する。 break; case 0x7a: // ローカルコントロール // オフ:鍵盤を弾くとMIDIメッセージは送信されるがピアノ自体から音は出ない // オン:鍵盤を弾くと音源から音が出る(基本こっち) break; case 0x7b: // オールノートオフ // 該当するチャンネルの発音中の音すべてに対してノートオフ命令を出す break; /* MIDIモード設定 */ // オムニのオン・オフとモノ・ポリモードを組み合わせて4種類のモードがある case 0x7c: // オムニモードオフ break; case 0x7d: // オムニモードオン break; case 0x7e: // モノモードオン break; case 0x7f: // モノモードオン break; } } break; case 0xc0: // プログラムチェンジ(音色を変える命令) i += 1; break; case 0xd0: // チャンネルプレッシャー(概ねポリフォニック キープレッシャーと同じだが、違いはそのチャンネルの全ノートナンバーに対して有効となる) i += 1; break; case 0xe0: // ピッチベンド(ウォェーンウェューンの表現で使う) i += 2; // ボルテのつまみみたいなのを実装する場合、ここの値が役立つかも break; } } /* システムエクスクルーシブ (SysEx) イベント*/ else if (statusByte == 0x70 || statusByte == 0x7f) { byte dataLength = data[i++]; i += dataLength; } /* メタイベント*/ else if (statusByte == 0xff) { // メタイベントの番号 byte metaEventID = data[i++]; // データ長 byte dataLength = data[i++]; switch (metaEventID) { case 0x00: // シーケンスメッセージ i += dataLength; break; case 0x01: // テキストイベント i += dataLength; break; case 0x02: // 著作権表示 i += dataLength; break; case 0x03: // シーケンス/トラック名 i += dataLength; break; case 0x04: // 楽器名 i += dataLength; break; case 0x05: // 歌詞 i += dataLength; break; case 0x06: // マーカー i += dataLength; break; case 0x07: // キューポイント i += dataLength; break; case 0x20: // MIDIチャンネルプリフィクス i += dataLength; break; case 0x21: // MIDIポートプリフィックス i += dataLength; break; case 0x2f: // トラック終了 i += dataLength; Fintrack = true; // ここでループを抜けても良い break; case 0x51: // テンポ変更 { // テンポ変更情報リストに格納する var tempoData = new TempoData(); tempoData.eventTime = (int)CrTime; // 4分音符の長さをマイクロ秒単位で格納されている uint tempo = 0; tempo |= data[i++]; tempo <<= 8; tempo |= data[i++]; tempo <<= 8; tempo |= data[i++]; // BPM割り出し tempoData.bpm = 60000000 / (float)tempo; // 小数点第1で切り捨て処理(10にすると第一位、100にすると第2位まで切り捨てられる) tempoData.bpm = Mathf.Floor(tempoData.bpm * 10) / 10; // tick値割り出し tempoData.tick = (60 / tempoData.bpm / headerCH.division * 1000); // リストにつっこむ tempoList.Add(tempoData); } break; case 0x54: // SMTPEオフセット i += dataLength; break; case 0x58: // 拍子 i += dataLength; // 小節線を表示させるなら使えるかも break; case 0x59: // 調号 i += dataLength; break; case 0x7f: // シーケンサ固有メタイベント i += dataLength; break; } } if (Fintrack) { break; } } // Debug.Log("FinAnalyz"); }
//midi / メタ イベント抽出用メソッド //主にデルタタイム、ノート番号、テンポの変化を見て配列に格納する private void TrackDataAnalaysis(byte[] data) { uint currentTime = 0; byte statusByte = 0; bool[] longFlags = new bool[128]; for (int i = 0; i < data.Length;) { uint deltaTime = 0; while (true) { //デルタタイムの抽出 byte tmp = data[i++]; deltaTime |= tmp & (uint)0x7f; if ((tmp & 0x80) == 0) { break; } deltaTime = deltaTime << 7; } currentTime = deltaTime; if (data[i] < 0x80) { //ランニングステータス } else { statusByte = data[i++]; } byte dataByte0, dataByte1; if (statusByte >= 0x80 && statusByte <= 0xef) { switch (statusByte & 0xf0) { //ノートオフ case 0x80: dataByte0 = data[i++]; dataByte1 = data[i++]; if (longFlags[dataByte0]) { NoteData note = new NoteData(); note.eventTime = (int)currentTime; note.laneIndex = (int)dataByte0; note.type = NoteType.Off; if (harmony == 0x00) { PianoNoteList.Add(note); } else if (harmony == 0x1D || harmony == 0x1E) { GuitarNoteList.Add(note); } longFlags[note.laneIndex] = false; } break; //ノートオン case 0x90: dataByte0 = data[i++]; dataByte1 = data[i++]; { NoteData note = new NoteData(); note.eventTime = (int)currentTime; note.laneIndex = (int)dataByte0; note.type = NoteType.On; longFlags[note.laneIndex] = true; if (dataByte1 == 0) { if (longFlags[note.laneIndex]) { note.type = NoteType.Off; longFlags[note.laneIndex] = false; } } if (harmony == 0x00) { PianoNoteList.Add(note); } else if (harmony == 0x1D || harmony == 0x1E) { GuitarNoteList.Add(note); } } break; //これ以降はインクリメント用 case 0xa0: i += 2; break; case 0xb0: dataByte0 = data[i++]; dataByte1 = data[i++]; if (dataByte0 < 0x78) { } else { switch (dataByte0) { case 0x78: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: break; } } break; case 0xc0: dataByte0 = data[i++]; harmony = dataByte0; break; case 0xd0: i += 1; break; case 0xe0: i += 2; break; } } //SysExイベント用、インクリメントオンリー else if (statusByte == 0x70 || statusByte == 0x7f) { byte dataLength = data[i++]; i += dataLength; } //メタイベント用 else if (statusByte == 0xff) { byte metaEventID = data[i++]; byte dataLength = data[i++]; switch (metaEventID) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x20: case 0x21: case 0x2f: case 0x54: case 0x58: case 0x59: case 0x7f: i += dataLength; break; //テンポ情報を格納 case 0x51: { TempoData tempoData = new TempoData(); tempoData.eventTime = (int)currentTime; uint tempo = 0; tempo |= data[i++]; tempo <<= 8; tempo |= data[i++]; tempo <<= 8; tempo |= data[i++]; tempoData.bpm = 60000000 / (float)tempo; tempoData.bpm = (float)(Math.Floor(tempoData.bpm * 10) / 10); tempoList.Add(tempoData); } break; } } } }
void TrackDataAnalys(byte[] data, HeaderChunkData headerCH) { // Debug.Log(data.Length); uint CrTime = 0; byte statusByte = 0; bool[] longFlags = new bool[128]; for (int i = 0; i < data.Length;) { // Debug.Log(i); bool Fintrack = false; uint deltaTime = 0; while (true) { var tmp = data[i++]; deltaTime |= (tmp & (uint)0x7f); if ((tmp & 0x80) == 0) { break; } deltaTime = deltaTime << 7; } // 現在の時間にデルタタイムを足す CrTime += deltaTime; if (data[i] >= 0x80) { statusByte = data[i++]; } //else:ランニングステータス適応(前回のステータスバイトを使いまわす) // ステータスバイト後のデータ保存用 byte dataByte0, dataByte1; // byte dataByte2, dataByte3; if (statusByte >= 0x80 && statusByte <= 0xef) { switch (statusByte & 0xf0) { /* チャンネルメッセージ */ // ノートオフ case 0x80: dataByte0 = data[i++]; dataByte1 = data[i++]; if (longFlags[dataByte0]) { var note = new NoteData(); note.eventTime = (int)CrTime; note.laneIndex = (int)dataByte0; note.type = NoteType.LongEnd; // リストにつっこむ noteList.Add(note); longFlags[note.laneIndex] = false; } break; // ノートオン(ノートオフが呼ばれるまでは押しっぱなし扱い) case 0x90: // どのキーが押されたか dataByte0 = data[i++]; dataByte1 = data[i++]; { // ノート情報生成 var note = new NoteData(); note.eventTime = (int)CrTime; note.laneIndex = (int)dataByte0; note.type = NoteType.Normal; if (dataByte1 == 127) { note.type = NoteType.LongStart; longFlags[note.laneIndex] = true; } // ノートオフイベントではなく、ベロシティ値0をノートオフとして保存する形式もあるので対応 if (dataByte1 == 0) { // 同じレーンで前回がロングノーツ始点なら if (longFlags[note.laneIndex]) { note.type = NoteType.LongEnd; longFlags[note.laneIndex] = false; } } // リストにつっこむ noteList.Add(note); } break; case 0xa0: i += 2; // 使わないのでスルー break; case 0xb0: dataByte0 = data[i++]; dataByte1 = data[i++]; // ※0x00-0x77までがコントロールチェンジで、それ以上はチャンネルモードメッセージとして処理する if (dataByte0 < 0x78) { // コントロールチェンジ } else { switch (dataByte0) { case 0x78: break; case 0x79: break; case 0x7a: break; case 0x7b: break; // オムニモードオフ case 0x7c: break; // オムニモードオン case 0x7d: break; // モノモードオン case 0x7e: break; // モノモードオン case 0x7f: break; } } break; case 0xc0: i += 1; break; case 0xd0: i += 1; break; case 0xe0: i += 2; break; } } else if (statusByte == 0x70 || statusByte == 0x7f) { byte dataLength = data[i++]; i += dataLength; } else if (statusByte == 0xff) { // メタイベント byte metaEventID = data[i++]; byte dataLength = data[i++]; switch (metaEventID) { // シーケンスメッセージ case 0x00: i += dataLength; break; // テキストイベント case 0x01: i += dataLength; break; // 著作権表示 case 0x02: i += dataLength; break; // シーケンス/トラック名 case 0x03: i += dataLength; break; // 楽器名 case 0x04: i += dataLength; break; // 歌詞 case 0x05: i += dataLength; break; // マーカー case 0x06: i += dataLength; break; // キューポイント case 0x07: i += dataLength; break; // MIDIチャンネルプリフィクス case 0x20: i += dataLength; break; // MIDIポートプリフィックス case 0x21: i += dataLength; break; // トラック終了 case 0x2f: i += dataLength; Fintrack = true; // ここでループを抜ける break; // テンポ変更 case 0x51: { // テンポ変更情報リストに格納する var tempoData = new TempoData(); tempoData.eventTime = (int)CrTime; // 4分音符の長さをマイクロ秒単位で格納されている uint tempo = 0; tempo |= data[i++]; tempo <<= 8; tempo |= data[i++]; tempo <<= 8; tempo |= data[i++]; // BPM割り出し tempoData.bpm = 60000000 / (float)tempo; // 小数点第1で切り捨て処理(10にすると第一位、100にすると第2位まで切り捨てられる) tempoData.bpm = Mathf.Floor(tempoData.bpm * 10) / 10; // tick値割り出し tempoData.tick = (60 / tempoData.bpm / headerCH.division * 1000); // リストにつっこむ tempoList.Add(tempoData); } break; // SMTPEオフセット case 0x54: i += dataLength; break; // 拍子 case 0x58: // 小節線を表示させるなら使えるかも i += dataLength; break; // 調号 case 0x59: i += dataLength; break; // シーケンサ固有メタイベント case 0x7f: i += dataLength; break; } } if (Fintrack) { break; } } // Debug.Log("FinAnalyz"); }