OSDN Git Service

#38865 xadec.dll の代わりに、libbjxa.dll を採用。
[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 int nHandle = -1;
21                 private bjxa.Decoder bjxa = new bjxa.Decoder();
22                 private bjxa.Format format = null;
23                 private FileStream fs;
24
25                 public override int Open(string filename)
26                 {
27                         this.filename = filename;
28
29                         #region [ Reading XA headers, then store it ]
30                         fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);   // Need to set FileShare flag, to avoid locking after Closer()
31                         format = bjxa.ReadHeader(fs);
32                         //string xaid = Encoding.ASCII.GetString( xah.id );
33
34                         #region [ Debug info ]
35                         //Debug.WriteLine( "**XAHEADER**" );
36                         //Debug.WriteLine( "id=             " + xaheader.id.ToString( "X8" ) );
37                         //Debug.WriteLine( "nDataLen=       " + xaheader.nDataLen.ToString( "X8" ) );
38                         //Debug.WriteLine( "nSamples=       " + xaheader.nSamples.ToString( "X8" ) );
39                         //Debug.WriteLine( "nSamplesPerSec= " + xaheader.nSamplesPerSec.ToString( "X4" ) );
40                         //Debug.WriteLine( "nBits=          " + xaheader.nBits.ToString( "X2" ) );
41                         //Debug.WriteLine( "nChannels=      " + xaheader.nChannels.ToString( "X2" ) );
42                         //Debug.WriteLine( "nLoopPtr=       " + xaheader.nLoopPtr.ToString( "X8" ) );
43                         //Debug.WriteLine( "befL[0]=        " + xaheader.befL[ 0 ].ToString( "X4" ) );
44                         //Debug.WriteLine( "befL[1]=        " + xaheader.befL[ 1 ].ToString( "X4" ) );
45                         //Debug.WriteLine( "befR[0]=        " + xaheader.befR[ 0 ].ToString( "X4" ) );
46                         //Debug.WriteLine( "befR[1]=        " + xaheader.befR[ 1 ].ToString( "X4" ) );
47                         #endregion
48                         #endregion
49
50
51                         #region [ Getting WAVEFORMEX info ]
52                         waveformatex = new CWin32.WAVEFORMATEX();
53
54                         waveformatex.wFormatTag = (ushort)format.WaveFormatPcm;
55                         waveformatex.nChannels = (ushort)format.Channels;
56                         waveformatex.nSamplesPerSec = format.SamplesRate;
57                         waveformatex.nAvgBytesPerSec = format.WaveByteRate;
58                         waveformatex.nBlockAlign = (ushort)format.WaveBlockAlign;
59                         waveformatex.wBitsPerSample = (ushort)format.SampleBits;
60                         waveformatex.cbSize = 0;
61
62                         #region [ Debug info ]
63                         //Debug.WriteLine( "**WAVEFORMATEX**" );
64                         //Debug.WriteLine( "wFormatTag=      " + waveformatex.wFormatTag.ToString( "X4" ) );
65                         //Debug.WriteLine( "nChannels =      " + waveformatex.nChannels.ToString( "X4" ) );
66                         //Debug.WriteLine( "nSamplesPerSec=  " + waveformatex.nSamplesPerSec.ToString( "X8" ) );
67                         //Debug.WriteLine( "nAvgBytesPerSec= " + waveformatex.nAvgBytesPerSec.ToString( "X8" ) );
68                         //Debug.WriteLine( "nBlockAlign=     " + waveformatex.nBlockAlign.ToString( "X4" ) );
69                         //Debug.WriteLine( "wBitsPerSample=  " + waveformatex.wBitsPerSample.ToString( "X4" ) );
70                         //Debug.WriteLine( "cbSize=          " + waveformatex.cbSize.ToString( "X4" ) );
71                         #endregion
72                         #endregion
73
74                         return 0x7FFFFFFF;  // Anyway, return non-zero value
75                 }
76                 public override int GetFormat(int nHandle, ref CWin32.WAVEFORMATEX wfx)
77                 {
78                         #region [ Copying WAVEFORMATEX structure data ]
79                         wfx.nAvgBytesPerSec = waveformatex.nAvgBytesPerSec;
80                         wfx.wBitsPerSample = waveformatex.wBitsPerSample;
81                         wfx.nBlockAlign = waveformatex.nBlockAlign;
82                         wfx.nChannels = waveformatex.nChannels;
83                         wfx.wFormatTag = waveformatex.wFormatTag;
84                         wfx.nSamplesPerSec = waveformatex.nSamplesPerSec;
85
86                         return 0;
87                         #endregion
88                 }
89                 public override uint GetTotalPCMSize(int nHandle)
90                 {
91                         #region [ Getting PCM length ]
92                         uint dlen = (uint)format.DataLengthPcm;
93                         #region [ Debug info ]
94                         //Debug.WriteLine( "**INTERNAL VALUE**" );
95                         //Debug.WriteLine( "dlen=          " + dlen );
96                         #endregion
97                         #endregion
98
99                         return dlen;
100                 }
101                 public override int Seek(int nHandle, uint dwPosition)
102                 {
103                         return 0;
104                 }
105                 public override int Decode(int nHandle, IntPtr pDest, uint szDestSize, int bLoop)
106                 {
107                         #region [ Decodig xa data ]
108                         srcBuf = new byte[format.Blocks * format.BlockSizeXa];
109                         var pcmbuf = new short[format.Blocks * format.BlockSizePcm];
110
111                         if (fs.Read(srcBuf, 0, srcBuf.Length) != srcBuf.Length)
112                         {
113                                 string s = Path.GetFileName(filename);
114                                 throw new Exception( $"Failed to load xa data: {s}");
115                         }
116                         int ret = bjxa.Decode(srcBuf, pcmbuf, out long pcmBufLength);
117
118                         Marshal.Copy(pcmbuf, 0, pDest, (int)format.DataLengthPcm/2);
119
120                         #region [ alternative copy way ]
121                         // if you can't use Marshal.Copy, try this.
122                         //unsafe
123                         //{
124                         //      short* pWavBuf = (short*)pDest;
125                         //      for (int i = 0; i < format.DataLengthPcm/2; i++)
126                         //      {
127                         //              *pWavBuf++ = pcmbuf[i];
128                         //      }
129                         //}
130                         #endregion
131
132                         //string shortpath = Path.GetFileName(filename);
133                         //Trace.TraceInformation($"libbjxa: decode succeeded: {shortpath} = {szDestSize}");
134
135                         srcBuf = null;
136                         pcmbuf = null;
137
138                         #region [ Debug info ]
139                         //Debug.WriteLine( "**XASTREAMHEADER**" );
140                         //Debug.WriteLine( "nSrcLen=  " + xastreamheader.nSrcLen );
141                         //Debug.WriteLine( "nSrcUsed= " + xastreamheader.nSrcUsed );
142                         //Debug.WriteLine( "nDstLen=  " + xastreamheader.nDstLen );
143                         //Debug.WriteLine( "nDstUsed= " + xastreamheader.nDstUsed );
144                         #endregion
145                         #endregion
146
147                         return 0;
148                 }
149                 public override void Close(int nHandle)
150                 {
151                         fs.Close();
152                 }
153
154
155
156                 #region [ IDisposable implementatitons ]
157                 //-----------------
158                 private bool bDisposed = false;
159
160                 // Public implementation of Dispose pattern callable by consumers.
161                 public void Dispose()
162                 {
163                         Dispose(true);
164                         GC.SuppressFinalize(this);
165                 }
166
167                 // Protected implementation of Dispose pattern.
168                 protected virtual void Dispose(bool disposing)
169                 {
170                         if (this.bDisposed)
171                                 return;
172
173                         if (srcBuf != null) srcBuf = null;
174                         if (bjxa != null) bjxa = null;
175
176                         if (disposing)
177                         {
178                                 fs.Dispose();
179                         }
180
181                         this.bDisposed = true;
182                 }
183
184                 //-----------------
185                 #endregion
186         }
187 }