Public Class MIDITrack Protected ChunkType As New List(Of Byte) From {&H4D, &H54, &H72, &H6B} Protected DataLength As New List(Of Byte) From {0, 0, 0, 0} Protected Data As List(Of Byte) Protected Footer As New List(Of Byte) From {0, &HFF, &H2F, 0} Public Notes As New List(Of MidiEvent) ''' <summary> ''' 音符を追加します。音符は楽譜の先頭から追加していきます。 ''' </summary> ''' <param name="note">音階</param> ''' <param name="octave">オクターブ。中央のオクターブは3です。</param> ''' <param name="tick">発音時間。</param> ''' <remarks></remarks> Public Sub AddNote(ByVal note As Notes, ByVal octave As Integer, ByVal tick As Integer) Dim thisNote As New MidiEvent(note, octave, tick) Notes.Add(thisNote) End Sub ''' <summary> ''' 音符情報をMIDI形式に変換してDataプロパティに格納します。 ''' </summary> Protected Overridable Sub GenerateData() Const NoteOn As Byte = &H7F Const NoteOff As Byte = &H0 Data = New List(Of Byte) For Each note As MidiEvent In Notes Data.Add(&H0) 'まずは 0秒後に Data.Add(&H90) 'チャンネル1で Data.Add(note.Note + ((note.Octave - 3) * 12)) 'この音階を Data.Add(NoteOn) 'ならし Data.Add(note.Tick) 'Tick時間後に Data.Add(note.Note + ((note.Octave - 3) * 12)) 'この音階を Data.Add(NoteOff) '停止する Next End Sub ''' <summary> ''' フッター4バイトを含むデータ部の長さを4バイトの領域に記録する。 ''' </summary> Private Sub CalculateLength() 'もっと簡単な方法があると思うが眠たい…。 '非効率だがこれでも機能的にはOKなはず。 Dim length As Integer = Data.Count + 4 DataLength(3) = length Mod 256 length = length >> 8 DataLength(2) = length Mod 256 length = length >> 8 DataLength(1) = length Mod 256 length = length >> 8 DataLength(0) = length End Sub ''' <summary> ''' このトラックが表すすべてのデータをバイト型の配列で表現する。 ''' </summary> Public Overridable Function ToList() As List(Of Byte) GenerateData() calculatelength() Dim all As New List(Of Byte) all.AddRange(ChunkType) all.AddRange(DataLength) all.AddRange(Data) all.AddRange(Footer) Return all End Function End Class ''' <summary> ''' テンポ調整用トラック。固定で120にしています。 ''' プロパティで可変にするのがよく、さらに任意のタイミングでテンポを切り替えられるようにするとベストです。 ''' </summary> Public Class ConductorTrack Inherits MIDITrack Protected Overrides Sub GenerateData() Data = New List(Of Byte) From {0, &HFF, &H51, 3, 7, &HA1, &H20} End Sub End Class ''' <summary>音符を表します。</summary> Public Class MidiEvent ''' <summary>音階</summary> Public Note As Notes ''' <summary>オクターブ</summary> Public Octave As Integer ''' <summary>発音時間(長さ)</summary> Public Tick As Integer ''' <summary> ''' 音符を作ります。 ''' </summary> ''' <param name="note">音階</param> ''' <param name="octave">オクターブ。中央のオクターブは3です。</param> ''' <param name="tick">発音時間。</param> ''' <remarks></remarks> Public Sub New(ByVal note As Notes, ByVal octave As Integer, ByVal tick As Integer) Me.Note = note Me.Octave = octave Me.Tick = tick End Sub End Class ''' <summary>音階を表します。</summary> Public Enum Notes As Byte ''' <summary>ド</summary> C = &H3C ''' <summary>ド#</summary> Cs = &H3D ''' <summary>レ</summary> D = &H3E ''' <summary>レ#</summary> Ds = &H3F ''' <summary>ミ</summary> E = &H40 ''' <summary>ファ</summary> F = &H41 ''' <summary>ファ#</summary> Fs = &H42 ''' <summary>ソ</summary> G = &H43 ''' <summary>ソ#</summary> Gs = &H44 ''' <summary>ラ</summary> A = &H45 ''' <summary>ラ#</summary> [As] = &H46 ''' <summary>シ</summary> B = &H47 End Enum