OSDN Git Service

#30333 [DTXC]
[dtxmania/dtxmania.git] / DTXCreatorプロジェクト / コード / 07.MIDIインポート / CMIDI.cs
1 using System;\r
2 using System.Collections.Generic;\r
3 using System.Linq;\r
4 using System.Text;\r
5 using System.Threading.Tasks;\r
6 using System.Windows.Forms;\r
7 using System.IO;\r
8 using System.Drawing;\r
9 using System.Diagnostics;\r
10 using DTXCreator.WAV_BMP_AVI;\r
11 \r
12 namespace DTXCreator.MIDIインポート\r
13 {\r
14     internal class CMIDI\r
15     {\r
16         public string strファイル名;\r
17         public byte[] byMIDIバイナリ;\r
18         public bool bMIDIファイル;\r
19         public List<CMIDIトラック> lMIDIトラック;\r
20         public List<CMIDIイベント> lMIDIイベント;\r
21         public float f先頭BPM;\r
22         public string strTimeSignature;\r
23         public int[] nドラム各ノート数;\r
24         public int n分解能;\r
25         public Cメインフォーム formメインフォーム;\r
26                 public List<CMIDIイベント> lMIDIWAV;\r
27                 public int n重複チップ数;\r
28                 public int [] lチャンネル毎のノート数1to16;\r
29                 public DataGridView dgvチャンネル一覧;\r
30                 public bool[] bドラムチャンネルと思われる;\r
31 \r
32         public int dトラック数\r
33         {\r
34             get\r
35             {\r
36                 return lMIDIトラック.Count;\r
37             }\r
38         }\r
39 \r
40         public CMIDI( string _strファイル名 )\r
41         {\r
42             this.strファイル名 = _strファイル名;\r
43             this.byMIDIバイナリ = File.ReadAllBytes( this.strファイル名 );\r
44             this.bMIDIファイル = ( strBin2BinStr(this.byMIDIバイナリ, 0, 4) == "4D 54 68 64" );\r
45             this.lMIDIトラック = new List<CMIDIトラック>();\r
46             this.lMIDIイベント = new List<CMIDIイベント>();\r
47             this.nドラム各ノート数 = new int[256];\r
48                         this.lMIDIWAV = new List<CMIDIイベント>();\r
49                         this.f先頭BPM = 0.0f;\r
50                         this.n重複チップ数 = 0;\r
51                         this.lチャンネル毎のノート数1to16 = new int[17];\r
52                         this.dgvチャンネル一覧 = null;\r
53                         this.bドラムチャンネルと思われる = new bool[ 16 * 4 ];\r
54                         this.bドラムチャンネルと思われる[ 10 - 1 ] = true;\r
55                 }\r
56 \r
57         // 解析処理 全バイナリを見てMTrkだけ抜き取る\r
58         public void tMIDIを解析する()\r
59         {\r
60             // MThdが存在しなければ解析処理を行わない\r
61             if ( !bMIDIファイル ) return;\r
62                         this.lMIDIWAV = new List<CMIDIイベント>();\r
63 \r
64                         this.n分解能 = nBin2Int( this.byMIDIバイナリ, 12, 2 );\r
65 \r
66             for ( int i = 0; i<this.byMIDIバイナリ.Length; i++ )\r
67             {\r
68                 // MTrkがあればトラックを追加する\r
69                 if ( strBin2BinStr(this.byMIDIバイナリ, i, 4) == "4D 54 72 6B" )\r
70                 {\r
71                                         int track_size = nBin2Int( this.byMIDIバイナリ, i + 4, 4 );\r
72                     byte[] data_track = new byte[track_size + 8 + 8];   // 大きめに取りました\r
73                     Array.Copy( this.byMIDIバイナリ, i, data_track, 0, nBin2Int( this.byMIDIバイナリ, i+4, 4 ) + 8 );\r
74                     this.lMIDIトラック.Add( new CMIDIトラック( this, this.dトラック数, data_track ) );\r
75                     this.lMIDIトラック[this.lMIDIトラック.Count-1].tトラックチャンクを走査する();\r
76                 }\r
77             }\r
78         }\r
79                 \r
80                 /// <summary>\r
81                 /// dgv割り当て一覧で設定した値に応じて、各レーンへ振り分ける\r
82                 /// </summary>\r
83         public void tMIDIチップをレーンに割り当てる( DataGridView dgv割り当て一覧 )\r
84         {\r
85                         // MIDIイベントがひとつでもあるなら処理する\r
86                         if ( this.lMIDIイベント.Count == 0 ) return;\r
87 \r
88                         #region [ 振り分け ]\r
89                         foreach ( CMIDIイベント vMIDIイベント in this.lMIDIイベント )\r
90                         {\r
91                                 foreach (DataGridViewRow dgvr in dgv割り当て一覧.Rows)\r
92                                 {\r
93                                         if (vMIDIイベント.nキー == (int)dgvr.Cells["MIDI_Key"].Value )\r
94                                         {\r
95                                                 if ( (string)dgvr.Cells["DTX_Lane"].Value != "* Disuse *" )\r
96                                                 {\r
97                                                         vMIDIイベント.nレーン番号 = this.formメインフォーム.mgr譜面管理者.nレーン名に対応するレーン番号を返す( (string)dgvr.Cells["DTX_Lane"].Value );\r
98                                                         vMIDIイベント.strコメント = (string)dgvr.Cells["Comment"].Value;\r
99                                                         vMIDIイベント.b裏チャンネル = (bool)dgvr.Cells["BackCH"].Value;\r
100                                                         vMIDIイベント.b入力 = true;\r
101                                                 }\r
102                                                 else\r
103                                                 {\r
104                                                         vMIDIイベント.nレーン番号 = 0;\r
105                                                         vMIDIイベント.strコメント = "";\r
106                                                         vMIDIイベント.b裏チャンネル = false;\r
107                                                         vMIDIイベント.b入力 = false;\r
108                                                 }\r
109                                                 if ( vMIDIイベント.eイベントタイプ == CMIDIイベント.Eイベントタイプ.BPM  ||\r
110                                                          vMIDIイベント.eイベントタイプ == CMIDIイベント.Eイベントタイプ.BarLen )\r
111                                                 {\r
112                                                         vMIDIイベント.b入力 = true;\r
113                                                 }\r
114                                         }\r
115                                 }\r
116                         }\r
117                         #endregion\r
118 \r
119                         #region [ WAVリスト化する ]\r
120                         this.lMIDIWAV = new List<CMIDIイベント>();\r
121 \r
122                         foreach ( CMIDIイベント vMIDIイベント in this.lMIDIイベント )\r
123                         {\r
124                                 // WAVリストで、同じ内容(キーとベロシティ)が無ければ挿入する\r
125                                 bool bMIDIWAV_AddFlag = true;\r
126                                 foreach ( CMIDIイベント vMIDIWAV in this.lMIDIWAV )\r
127                                 {\r
128                                         if ( vMIDIWAV.strWAV重複チェック == vMIDIイベント.strWAV重複チェック )\r
129                                         {\r
130                                                 bMIDIWAV_AddFlag = false;\r
131                                                 break;\r
132                                         }\r
133                                 }\r
134                                 if (bMIDIWAV_AddFlag)\r
135                                 {\r
136                                         this.lMIDIWAV.Add( vMIDIイベント );\r
137                                 }\r
138                         }\r
139                         #endregion\r
140                         \r
141                         #region [ キーが違うが同時刻で同じレーンに配置予定のチップを数える ]\r
142                         this.n重複チップ数 = 0;\r
143                         foreach ( CMIDIイベント v1 in this.lMIDIイベント )\r
144                         {\r
145                                 foreach ( CMIDIイベント v2 in this.lMIDIイベント )\r
146                                 {\r
147                                         if ( v1.nキー != v2.nキー && v1.nレーン番号 == v2.nレーン番号 && v1.n時間 == v2.n時間 )\r
148                                         {\r
149                                                 this.n重複チップ数 ++;\r
150                                         }\r
151                                 }\r
152                         }\r
153                         this.n重複チップ数 /= 2;\r
154                         #endregion\r
155         }\r
156 \r
157 \r
158         // バイナリの指定のバイト数分を、"FF FF FF..."の形で出力する\r
159         static public string strBin2BinStr( byte[] byバイナリ, int d開始バイト, int dバイト数 )\r
160         {\r
161             string str文字列 = "";\r
162 \r
163             if ( dバイト数 <= 0 ) return "";\r
164 \r
165             for (int i = d開始バイト; i < d開始バイト + dバイト数; i++)\r
166             {\r
167                 if ( i >= byバイナリ.Length ) break;\r
168                 str文字列 += byバイナリ[i].ToString("X2") + " ";\r
169             }\r
170 \r
171             return str文字列.Substring( 0, str文字列.Length-1 );\r
172         }\r
173         \r
174         // バイナリの指定のバイト数分を、文字列に変換して出力する\r
175         static public string strBin2Str( byte[] byバイナリ, int d開始バイト, int dバイト数 )\r
176         {\r
177             string str文字列 = "";\r
178 \r
179             if ( dバイト数 <= 0 ) return "";\r
180 \r
181                         byte[] by出力 = new byte[ dバイト数 + 1 ];\r
182 \r
183             for (int i = d開始バイト; i < d開始バイト + dバイト数; i++)\r
184             {\r
185                 if ( i >= byバイナリ.Length ) break;\r
186                 by出力[i-d開始バイト] = byバイナリ[i];\r
187             }\r
188 \r
189                         if ( by出力[ 0 ] == 0 ) str文字列 = "";\r
190 \r
191                         System.Text.Encoding enc = GetCode( by出力 );                 //System.Text.Encoding.Default; //GetEncoding( "shift_jis" );\r
192                         if ( enc == null )\r
193                         {\r
194                                 enc = System.Text.Encoding.Unicode;\r
195                         }\r
196                         str文字列 = enc.GetString( by出力 );\r
197 \r
198             return str文字列.Trim('\0');\r
199         }\r
200         \r
201         // バイナリの指定のバイト数分を、数値に変換して出力する\r
202         static public int nBin2Int( byte[] byバイナリ, int d開始バイト, int dバイト数 )\r
203         {\r
204             int d数値 = 0;\r
205 \r
206             if ( dバイト数 <= 0 ) return 0;\r
207 \r
208             for (int i = d開始バイト; i < d開始バイト + dバイト数; i++)\r
209             {\r
210                 if ( i >= byバイナリ.Length ) break;\r
211                 d数値 += byバイナリ[i] * (int)Math.Pow( 256, dバイト数 - ( i - d開始バイト ) - 1 );\r
212             }\r
213 \r
214             return d数値;\r
215         }\r
216 \r
217                 /// <summary>\r
218                 /// 文字コードを判別する\r
219                 /// </summary>\r
220                 /// <remarks>\r
221                 /// http://dobon.net/vb/dotnet/string/detectcode.html を少し修正したもの。\r
222                 /// Jcode.pmのgetcodeメソッドを移植したものです。\r
223                 /// Jcode.pm(http://openlab.ring.gr.jp/Jcode/index-j.html)\r
224                 /// Jcode.pmのCopyright: Copyright 1999-2005 Dan Kogai\r
225                 /// </remarks>\r
226                 /// <param name="bytes">文字コードを調べるデータ</param>\r
227                 /// <returns>適当と思われるEncodingオブジェクト。\r
228                 /// 判断できなかった時はnull。</returns>\r
229                 public static System.Text.Encoding GetCode( byte[] bytes )\r
230                 {\r
231                         const byte bEscape = 0x1B;\r
232                         const byte bAt = 0x40;\r
233                         const byte bDollar = 0x24;\r
234                         const byte bAnd = 0x26;\r
235                         const byte bOpen = 0x28;    //'('\r
236                         const byte bB = 0x42;\r
237                         const byte bD = 0x44;\r
238                         const byte bJ = 0x4A;\r
239                         const byte bI = 0x49;\r
240 \r
241                         int len = bytes.Length;\r
242                         if (bytes[ len - 1 ] == 0x00 )\r
243                         {\r
244                                 --len;\r
245                         }\r
246                         byte b1, b2, b3, b4;\r
247 \r
248                         bool ascii = true;\r
249                         for ( int i = 0; i < len; i++ )\r
250                         {\r
251                                 b1 = bytes[ i ];\r
252                                 if ( !( b1 >= 0x20 && b1 <= 0x7E ) )\r
253                                 {\r
254                                         ascii = false;\r
255                                         break;\r
256                                 }\r
257                         }\r
258                         if ( ascii )\r
259                         {\r
260                                 return System.Text.Encoding.ASCII;\r
261                         }\r
262 \r
263                         //Encode::is_utf8 は無視\r
264 \r
265                         bool isBinary = false;\r
266                         for ( int i = 0; i < len; i++ )\r
267                         {\r
268                                 b1 = bytes[ i ];\r
269                                 if ( b1 <= 0x06 || b1 == 0x7F || b1 == 0xFF )\r
270                                 {\r
271                                         //'binary'\r
272                                         isBinary = true;\r
273                                         if ( b1 == 0x00 && i < len - 1 && bytes[ i + 1 ] <= 0x7F )\r
274                                         {\r
275                                                 //smells like raw unicode\r
276                                                 return System.Text.Encoding.Unicode;\r
277                                         }\r
278                                 }\r
279                         }\r
280                         if ( isBinary )\r
281                         {\r
282                                 return null;\r
283                         }\r
284 \r
285                         //not Japanese\r
286                         bool notJapanese = true;\r
287                         for ( int i = 0; i < len; i++ )\r
288                         {\r
289                                 b1 = bytes[ i ];\r
290                                 if ( b1 == bEscape || 0x80 <= b1 )\r
291                                 {\r
292                                         notJapanese = false;\r
293                                         break;\r
294                                 }\r
295                         }\r
296                         if ( notJapanese )\r
297                         {\r
298                                 return System.Text.Encoding.ASCII;\r
299                         }\r
300 \r
301                         for ( int i = 0; i < len - 2; i++ )\r
302                         {\r
303                                 b1 = bytes[ i ];\r
304                                 b2 = bytes[ i + 1 ];\r
305                                 b3 = bytes[ i + 2 ];\r
306 \r
307                                 if ( b1 == bEscape )\r
308                                 {\r
309                                         if ( b2 == bDollar && b3 == bAt )\r
310                                         {\r
311                                                 //JIS_0208 1978\r
312                                                 //JIS\r
313                                                 return System.Text.Encoding.GetEncoding( 50220 );\r
314                                         }\r
315                                         else if ( b2 == bDollar && b3 == bB )\r
316                                         {\r
317                                                 //JIS_0208 1983\r
318                                                 //JIS\r
319                                                 return System.Text.Encoding.GetEncoding( 50220 );\r
320                                         }\r
321                                         else if ( b2 == bOpen && ( b3 == bB || b3 == bJ ) )\r
322                                         {\r
323                                                 //JIS_ASC\r
324                                                 //JIS\r
325                                                 return System.Text.Encoding.GetEncoding( 50220 );\r
326                                         }\r
327                                         else if ( b2 == bOpen && b3 == bI )\r
328                                         {\r
329                                                 //JIS_KANA\r
330                                                 //JIS\r
331                                                 return System.Text.Encoding.GetEncoding( 50220 );\r
332                                         }\r
333                                         if ( i < len - 3 )\r
334                                         {\r
335                                                 b4 = bytes[ i + 3 ];\r
336                                                 if ( b2 == bDollar && b3 == bOpen && b4 == bD )\r
337                                                 {\r
338                                                         //JIS_0212\r
339                                                         //JIS\r
340                                                         return System.Text.Encoding.GetEncoding( 50220 );\r
341                                                 }\r
342                                                 if ( i < len - 5 &&\r
343                                                         b2 == bAnd && b3 == bAt && b4 == bEscape &&\r
344                                                         bytes[ i + 4 ] == bDollar && bytes[ i + 5 ] == bB )\r
345                                                 {\r
346                                                         //JIS_0208 1990\r
347                                                         //JIS\r
348                                                         return System.Text.Encoding.GetEncoding( 50220 );\r
349                                                 }\r
350                                         }\r
351                                 }\r
352                         }\r
353 \r
354                         //should be euc|sjis|utf8\r
355                         //use of (?:) by Hiroki Ohzaki <ohzaki@iod.ricoh.co.jp>\r
356                         int sjis = 0;\r
357                         int euc = 0;\r
358                         int utf8 = 0;\r
359                         for ( int i = 0; i < len - 1; i++ )\r
360                         {\r
361                                 b1 = bytes[ i ];\r
362                                 b2 = bytes[ i + 1 ];\r
363                                 if ( ( ( 0x81 <= b1 && b1 <= 0x9F ) || ( 0xE0 <= b1 && b1 <= 0xFC ) ) &&\r
364                                         ( ( 0x40 <= b2 && b2 <= 0x7E ) || ( 0x80 <= b2 && b2 <= 0xFC ) ) )\r
365                                 {\r
366                                         //SJIS_C\r
367                                         sjis += 2;\r
368                                         i++;\r
369                                 }\r
370                         }\r
371                         for ( int i = 0; i < len - 1; i++ )\r
372                         {\r
373                                 b1 = bytes[ i ];\r
374                                 b2 = bytes[ i + 1 ];\r
375                                 if ( ( ( 0xA1 <= b1 && b1 <= 0xFE ) && ( 0xA1 <= b2 && b2 <= 0xFE ) ) ||\r
376                                         ( b1 == 0x8E && ( 0xA1 <= b2 && b2 <= 0xDF ) ) )\r
377                                 {\r
378                                         //EUC_C\r
379                                         //EUC_KANA\r
380                                         euc += 2;\r
381                                         i++;\r
382                                 }\r
383                                 else if ( i < len - 2 )\r
384                                 {\r
385                                         b3 = bytes[ i + 2 ];\r
386                                         if ( b1 == 0x8F && ( 0xA1 <= b2 && b2 <= 0xFE ) &&\r
387                                                 ( 0xA1 <= b3 && b3 <= 0xFE ) )\r
388                                         {\r
389                                                 //EUC_0212\r
390                                                 euc += 3;\r
391                                                 i += 2;\r
392                                         }\r
393                                 }\r
394                         }\r
395                         for ( int i = 0; i < len - 1; i++ )\r
396                         {\r
397                                 b1 = bytes[ i ];\r
398                                 b2 = bytes[ i + 1 ];\r
399                                 if ( ( 0xC0 <= b1 && b1 <= 0xDF ) && ( 0x80 <= b2 && b2 <= 0xBF ) )\r
400                                 {\r
401                                         //UTF8\r
402                                         utf8 += 2;\r
403                                         i++;\r
404                                 }\r
405                                 else if ( i < len - 2 )\r
406                                 {\r
407                                         b3 = bytes[ i + 2 ];\r
408                                         if ( ( 0xE0 <= b1 && b1 <= 0xEF ) && ( 0x80 <= b2 && b2 <= 0xBF ) &&\r
409                                                 ( 0x80 <= b3 && b3 <= 0xBF ) )\r
410                                         {\r
411                                                 //UTF8\r
412                                                 utf8 += 3;\r
413                                                 i += 2;\r
414                                         }\r
415                                 }\r
416                         }\r
417                         //M. Takahashi's suggestion\r
418                         //utf8 += utf8 / 2;\r
419 \r
420                         //Debug.WriteLine(\r
421                         //      string.Format( "sjis = {0}, euc = {1}, utf8 = {2}", sjis, euc, utf8 ) );\r
422                         if ( euc > sjis && euc > utf8 )\r
423                         {\r
424                                 //EUC\r
425                                 return System.Text.Encoding.GetEncoding( 51932 );\r
426                         }\r
427                         else if ( sjis > euc && sjis > utf8 )\r
428                         {\r
429                                 //SJIS\r
430                                 return System.Text.Encoding.GetEncoding( 932 );\r
431                         }\r
432                         else if ( utf8 > euc && utf8 > sjis )\r
433                         {\r
434                                 //UTF8\r
435                                 return System.Text.Encoding.UTF8;\r
436                         }\r
437 \r
438                         return null;\r
439                 }\r
440         }\r
441 \r
442 }\r