OSDN Git Service

#28822 SoundDecoder.dll を削除。DirectSound使用時、mp3とoggはbass.libを使ってデコードするように変更した。
[dtxmania/dtxmania.git] / FDK / コード / 03.サウンド / Cxa.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
9
10 namespace FDK
11 {
12         public unsafe class Cxa : SoundDecoder    //, IDisposable
13         {
14                 //static byte[] FOURCC = Encoding.ASCII.GetBytes("1DWK"); // KWD1 (little endian)
15
16                 public CWin32.WAVEFORMATEX waveformatex;
17
18                 private string filename;
19                 private byte[] srcBuf = null;
20                 private short[] pcmbuf = null;
21
22                 //private int nHandle = -1;
23                 private bjxa.Decoder bjxa = new bjxa.Decoder();
24                 private bjxa.Format format = null;
25                 private FileStream fs;
26
27                 public override int Open(string filename)
28                 {
29                         this.filename = filename;
30
31                         #region [ Reading XA headers, then store it ]
32                         fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);   // Need to set FileShare flag, to avoid locking after Closer()
33                         format = bjxa.ReadHeader(fs);
34                         //string xaid = Encoding.ASCII.GetString( xah.id );
35
36                         #region [ Debug info ]
37                         //Debug.WriteLine( "**XAHEADER**" );
38                         //Debug.WriteLine( "id=             " + xaheader.id.ToString( "X8" ) );
39                         //Debug.WriteLine( "nDataLen=       " + xaheader.nDataLen.ToString( "X8" ) );
40                         //Debug.WriteLine( "nSamples=       " + xaheader.nSamples.ToString( "X8" ) );
41                         //Debug.WriteLine( "nSamplesPerSec= " + xaheader.nSamplesPerSec.ToString( "X4" ) );
42                         //Debug.WriteLine( "nBits=          " + xaheader.nBits.ToString( "X2" ) );
43                         //Debug.WriteLine( "nChannels=      " + xaheader.nChannels.ToString( "X2" ) );
44                         //Debug.WriteLine( "nLoopPtr=       " + xaheader.nLoopPtr.ToString( "X8" ) );
45                         //Debug.WriteLine( "befL[0]=        " + xaheader.befL[ 0 ].ToString( "X4" ) );
46                         //Debug.WriteLine( "befL[1]=        " + xaheader.befL[ 1 ].ToString( "X4" ) );
47                         //Debug.WriteLine( "befR[0]=        " + xaheader.befR[ 0 ].ToString( "X4" ) );
48                         //Debug.WriteLine( "befR[1]=        " + xaheader.befR[ 1 ].ToString( "X4" ) );
49                         #endregion
50                         #endregion
51
52
53                         #region [ Getting WAVEFORMEX info ]
54                         waveformatex = new CWin32.WAVEFORMATEX();
55
56                         waveformatex.wFormatTag = (ushort)format.WaveFormatPcm;
57                         waveformatex.nChannels = (ushort)format.Channels;
58                         waveformatex.nSamplesPerSec = format.SamplesRate;
59                         waveformatex.nAvgBytesPerSec = format.WaveByteRate;
60                         waveformatex.nBlockAlign = (ushort)format.WaveBlockAlign;
61                         waveformatex.wBitsPerSample = (ushort)format.SampleBits;
62                         waveformatex.cbSize = 0;
63
64                         #region [ Debug info ]
65                         //Debug.WriteLine( "**WAVEFORMATEX**" );
66                         //Debug.WriteLine( "wFormatTag=      " + waveformatex.wFormatTag.ToString( "X4" ) );
67                         //Debug.WriteLine( "nChannels =      " + waveformatex.nChannels.ToString( "X4" ) );
68                         //Debug.WriteLine( "nSamplesPerSec=  " + waveformatex.nSamplesPerSec.ToString( "X8" ) );
69                         //Debug.WriteLine( "nAvgBytesPerSec= " + waveformatex.nAvgBytesPerSec.ToString( "X8" ) );
70                         //Debug.WriteLine( "nBlockAlign=     " + waveformatex.nBlockAlign.ToString( "X4" ) );
71                         //Debug.WriteLine( "wBitsPerSample=  " + waveformatex.wBitsPerSample.ToString( "X4" ) );
72                         //Debug.WriteLine( "cbSize=          " + waveformatex.cbSize.ToString( "X4" ) );
73                         #endregion
74                         #endregion
75
76                         return 0x7FFFFFFF;  // Anyway, return non-zero value
77                 }
78                 public override int GetFormat(int nHandle, ref CWin32.WAVEFORMATEX wfx)
79                 {
80                         #region [ Copying WAVEFORMATEX structure data ]
81                         wfx.nAvgBytesPerSec = waveformatex.nAvgBytesPerSec;
82                         wfx.wBitsPerSample = waveformatex.wBitsPerSample;
83                         wfx.nBlockAlign = waveformatex.nBlockAlign;
84                         wfx.nChannels = waveformatex.nChannels;
85                         wfx.wFormatTag = waveformatex.wFormatTag;
86                         wfx.nSamplesPerSec = waveformatex.nSamplesPerSec;
87
88                         return 0;
89                         #endregion
90                 }
91                 public override uint GetTotalPCMSize(int nHandle)
92                 {
93                         #region [ Getting PCM length ]
94                         uint dlen = (uint)format.DataLengthPcm;
95                         #region [ Debug info ]
96                         //Debug.WriteLine( "**INTERNAL VALUE**" );
97                         //Debug.WriteLine( "dlen=          " + dlen );
98                         #endregion
99                         #endregion
100
101                         return dlen;
102                 }
103                 public override int Seek(int nHandle, uint dwPosition)
104                 {
105                         return 0;
106                 }
107                 public override int Decode(int nHandle, IntPtr pDest, uint szDestSize, int bLoop)
108                 {
109                         #region [ Decodig xa data ]
110                         srcBuf = new byte[format.Blocks * format.BlockSizeXa];
111                         pcmbuf = new short[format.Blocks * format.BlockSizePcm];
112
113                         if (fs.Read(srcBuf, 0, srcBuf.Length) != srcBuf.Length)
114                         {
115                                 string s = Path.GetFileName(filename);
116                                 throw new Exception( $"Failed to load xa data: {s}");
117                         }
118                         int ret = bjxa.Decode(srcBuf, pcmbuf, out long pcmBufLength);
119
120                         Marshal.Copy(pcmbuf, 0, pDest, (int)format.DataLengthPcm/2);
121
122                         #region [ alternative copy way ]
123                         // if you can't use Marshal.Copy, try this.
124                         //unsafe
125                         //{
126                         //      short* pWavBuf = (short*)pDest;
127                         //      for (int i = 0; i < format.DataLengthPcm/2; i++)
128                         //      {
129                         //              *pWavBuf++ = pcmbuf[i];
130                         //      }
131                         //}
132                         #endregion
133
134                         //string shortpath = Path.GetFileName(filename);
135                         //Trace.TraceInformation($"libbjxa: decode succeeded: {shortpath} = {szDestSize}");
136
137 //SaveWav(filename);
138
139                         pcmbuf = null;
140
141                         #region [ Debug info ]
142                         //Debug.WriteLine( "**XASTREAMHEADER**" );
143                         //Debug.WriteLine( "nSrcLen=  " + xastreamheader.nSrcLen );
144                         //Debug.WriteLine( "nSrcUsed= " + xastreamheader.nSrcUsed );
145                         //Debug.WriteLine( "nDstLen=  " + xastreamheader.nDstLen );
146                         //Debug.WriteLine( "nDstUsed= " + xastreamheader.nDstUsed );
147                         #endregion
148                         #endregion
149
150                         return 0;
151                 }
152                 public override void Close(int nHandle)
153                 {
154                         srcBuf = null;
155                         fs.Close();
156                 }
157
158
159
160
161                 private void SaveWav(string filename)
162                 {
163                         long _TotalPCMSize = (uint)format.DataLengthPcm;
164                         CWin32.WAVEFORMATEX _wfx = waveformatex;
165
166                         string outfile = Path.GetFileName(filename);
167                         var fs2 = new FileStream(outfile + ".wav", FileMode.Create);
168                         var st = new BinaryWriter(fs2);
169
170                         st.Write(new byte[] { 0x52, 0x49, 0x46, 0x46 }, 0, 4);      // 'RIFF'
171                         st.Write((int)_TotalPCMSize + 44 - 8);      // filesize - 8 [byte];今は不明なので後で上書きする。
172                         st.Write(new byte[] { 0x57, 0x41, 0x56, 0x45 }, 0, 4);      // 'WAVE'
173                         st.Write(new byte[] { 0x66, 0x6D, 0x74, 0x20 }, 0, 4);      // 'fmt '
174                         st.Write(new byte[] { 0x10, 0x00, 0x00, 0x00 }, 0, 4);      // chunk size 16bytes
175                         st.Write(new byte[] { 0x01, 0x00 }, 0, 2);                  // formatTag 0001 PCM
176                         st.Write((short)_wfx.nChannels);                              // channels
177                         st.Write((int)_wfx.nSamplesPerSec);                             // samples per sec
178                         st.Write((int)_wfx.nAvgBytesPerSec);          // avg bytesper sec
179                         st.Write((short)_wfx.nBlockAlign);                        // blockalign = 16bit * mono/stereo
180                         st.Write((short)_wfx.wBitsPerSample);                  // bitspersample = 16bits
181
182                         st.Write(new byte[] { 0x64, 0x61, 0x74, 0x61 }, 0, 4);      // 'data'
183                         st.Write((int)_TotalPCMSize);      // datasize 
184
185
186                         //var pcmbuf = new short[format.Blocks * format.BlockSizePcm];
187                         //if (fs.Read(srcBuf, 0, srcBuf.Length) != srcBuf.Length)
188                         //{
189                         //      string s = Path.GetFileName(filename);
190                         //      throw new Exception($"Failed to load xa data: {s}");
191                         //}
192                         //int ret = bjxa.Decode(srcBuf, pcmbuf, out long pcmBufLength);
193
194                         int shortsize = (int)(format.Blocks * format.BlockSizePcm);
195                         var pcmbuf_bytes = new byte[shortsize * 2];
196                         for (int i = 0; i < shortsize; i++)
197                         {
198                                 var b = BitConverter.GetBytes(pcmbuf[i]);
199                                 pcmbuf_bytes[i * 2] = b[0];
200                                 pcmbuf_bytes[i * 2 + 1] = b[1];
201                         }
202                         st.Write(pcmbuf_bytes);
203                         Trace.TraceInformation($"wrote ({outfile}.wav) " + fs2.Length);
204                         st.Dispose();
205                         fs2.Dispose();
206                 }
207
208                 #region [ IDisposable implementatitons ]
209                 //-----------------
210                 private bool bDisposed = false;
211
212                 // Public implementation of Dispose pattern callable by consumers.
213                 public void Dispose()
214                 {
215                         Dispose(true);
216                         GC.SuppressFinalize(this);
217                 }
218
219                 // Protected implementation of Dispose pattern.
220                 protected virtual void Dispose(bool disposing)
221                 {
222                         if (this.bDisposed)
223                                 return;
224
225                         if (srcBuf != null) srcBuf = null;
226                         if (bjxa != null) bjxa = null;
227
228                         if (disposing)
229                         {
230                                 fs.Dispose();
231                         }
232
233                         this.bDisposed = true;
234                 }
235
236                 //-----------------
237                 #endregion
238         }
239 }