OSDN Git Service

#xxxxx 音源ファイルが0byteだったときにmp3パーサを通ると例外発生していたのを修正。
[dtxmania/dtxmania.git] / FDK / コード / 03.サウンド / Cmp3.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Runtime.InteropServices;
5 using System.IO;
6 using System.Diagnostics;
7 using System.Threading;
8 using Un4seen.Bass;
9 using Un4seen.Bass.Misc;
10
11
12 namespace FDK
13 {
14         public unsafe class Cmp3 : SoundDecoder
15         {
16                 private int stream_in = -1;
17                 private bool bBASS_Already_Init = false;
18
19                 public override int Open( string filename )
20                 {
21                         bBASS_Already_Init = !Bass.BASS_Init(0, 48000, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero);
22                         // WASAPI/ASIO使用時は(BASS_ERROR_ALREADYとなって)falseが返るので、覚えておく。
23                         // 後でCmp3.Close()時にBASSを終了させないようにするため。
24
25                         stream_in = Bass.BASS_StreamCreateFile(filename, 0, 0, BASSFlag.BASS_DEFAULT | BASSFlag.BASS_STREAM_DECODE);
26                         if (stream_in == 0)
27                         {
28                                 BASSError be = Bass.BASS_ErrorGetCode();
29                                 Trace.TraceInformation("Cmp3: StreamCreateFile error: " + be.ToString());
30                                 return 0;
31                         }
32                         nTotalPCMSize = Bass.BASS_ChannelGetLength(stream_in);
33
34                         #region [ Getting WAVEFORMEX info ]
35                         var chinfo = Bass.BASS_ChannelGetInfo(stream_in);
36                         wfx = new CWin32.WAVEFORMATEX(
37                                 (ushort)1,                                                              // wFormatTag
38                                 (ushort)chinfo.chans,                                   // nChannels
39                                 (uint)chinfo.freq,                                              // nSamplesPerSec
40                                 (uint)(chinfo.freq * 2 * chinfo.chans), // nAvgBytesPerSec
41                                 (ushort)(2 * chinfo.chans),                             // nBlockAlign
42                                 16,                                                                             // wBitsPerSample
43                                 0                                                                               // cbSize                               
44                         );
45                         #endregion
46
47                         //string fn = Path.GetFileName(filename); 
48                         //Trace.TraceInformation("filename=" + fn + ", size=(decode): " + wavdata.Length + ", channelgetlength=" + _TotalPCMSize2 + ", " + _TotalPCMSize) ;
49
50                         return 0;
51                 }
52
53                 public override int Decode(ref byte[] Dest, long offset)
54                 {
55                         #region [ decode ]
56                         int LEN = 65536;
57                         byte[] data = new byte[LEN]; // 2 x 16-bit and length in is bytes
58                         long len = 0;
59                         long p = 0;
60                         do
61                         {
62                                 len = Bass.BASS_ChannelGetData(stream_in, data, LEN);
63                                 if (len < 0)
64                                 {
65                                         BASSError be = Bass.BASS_ErrorGetCode();
66                                         Trace.TraceInformation("Cmp3: BASS_ChannelGetData Error: " + be.ToString());
67                                 }
68                                 if (p + len > nTotalPCMSize)
69                                 {
70                                         len = nTotalPCMSize - p;
71                                 }
72                                 Array.Copy(data, 0, Dest, p, len);
73                                 p += len;
74                         } while (p < nTotalPCMSize);
75                         #endregion
76
77 //SaveWav(filename, Dest);
78
79                         data = null;
80                         return 0;
81                 }
82
83                 public override void Close()
84                 {
85                         if (!bBASS_Already_Init)
86                         {
87                                 Bass.BASS_StreamFree(stream_in);
88                                 Bass.BASS_Free();
89                         }
90                 }
91
92                 /// <summary>
93                 /// save wav file (for debugging)
94                 /// </summary>
95                 /// <param name="filename">input mp3/xa filename</param>
96                 private void SaveWav(string filename, byte[] Dest)
97                 {
98                         string outfile = Path.GetFileName(filename);
99                         var fs = new FileStream(outfile + ".wav", FileMode.Create);
100                         var st = new BinaryWriter(fs);
101
102                         st.Write(new byte[] { 0x52, 0x49, 0x46, 0x46 });      // 'RIFF'
103                         st.Write((int)(nTotalPCMSize + 44 - 8));            // RIFF chunk size
104                         st.Write(new byte[] { 0x57, 0x41, 0x56, 0x45 });      // 'WAVE'
105                         st.Write(new byte[] { 0x66, 0x6D, 0x74, 0x20 });      // 'fmt '
106                         st.Write(new byte[] { 0x10, 0x00, 0x00, 0x00 });      // chunk size 16bytes
107                         st.Write(new byte[] { 0x01, 0x00 }, 0, 2);                  // formatTag 0001 PCM
108                         st.Write((short)wfx.nChannels);                              // channels
109                         st.Write((int)wfx.nSamplesPerSec);                             // samples per sec
110                         st.Write((int)wfx.nAvgBytesPerSec);          // avg bytesper sec
111                         st.Write((short)wfx.nBlockAlign);                        // blockalign = 16bit * mono/stereo
112                         st.Write((short)wfx.wBitsPerSample);                  // bitspersample = 16bits
113
114                         st.Write(new byte[] { 0x64, 0x61, 0x74, 0x61 });      // 'data'
115                         st.Write((int) nTotalPCMSize);      // datasize 
116                         
117                         st.Write(Dest);
118 Trace.TraceInformation($"wrote ({outfile}.wav) fsLength=" + fs.Length + ", TotalPCMSize=" + nTotalPCMSize + ", diff=" + (fs.Length - nTotalPCMSize));
119                         st.Dispose();
120                         fs.Dispose();
121                 }
122         }
123 }