X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=FDK%2F%E3%82%B3%E3%83%BC%E3%83%89%2F03.%E3%82%B5%E3%82%A6%E3%83%B3%E3%83%89%2FCxa.cs;fp=FDK%2F%E3%82%B3%E3%83%BC%E3%83%89%2F03.%E3%82%B5%E3%82%A6%E3%83%B3%E3%83%89%2FCxa.cs;h=ee239fe046bd0599fda5c314fa4c312513af638d;hb=7bf3e650c7c6f5afac463ea6e288fcd3fad4387b;hp=0000000000000000000000000000000000000000;hpb=296446998eeba408353da55a275458b590e4ebf5;p=dtxmania%2Fdtxmania.git diff --git a/FDK/コード/03.サウンド/Cxa.cs b/FDK/コード/03.サウンド/Cxa.cs new file mode 100644 index 00000000..ee239fe0 --- /dev/null +++ b/FDK/コード/03.サウンド/Cxa.cs @@ -0,0 +1,380 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.IO; +using System.Diagnostics; +using System.Threading; + + +namespace FDK +{ + public unsafe class Cxa : SoundDecoder //, IDisposable + { + static byte[] FOURCC = Encoding.ASCII.GetBytes( "1DWK" ); // KWD1 の little endian + + #region [ XA用構造体の宣言 ] + [StructLayout(LayoutKind.Sequential)] + public struct XASTREAMHEADER { + public byte* pSrc; + public uint nSrcLen; + public uint nSrcUsed; + public byte* pDst; + public uint nDstLen; + public uint nDstUsed; + } + + [StructLayout( LayoutKind.Sequential )] + public struct XAHEADER + { + public uint id; + public uint nDataLen; + public uint nSamples; + public ushort nSamplesPerSec; + public byte nBits; + public byte nChannels; + public uint nLoopPtr; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public short[] befL; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public short[] befR; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] pad; + } + #endregion + + #region [ xadec.dllとのリンク ] + [DllImport( "xadec.dll", EntryPoint = "xaDecodeOpen", CallingConvention = CallingConvention.Cdecl )] + public extern static IntPtr xaDecodeOpen( ref XAHEADER pxah, out FDK.CWin32.WAVEFORMATEX pwfx ); + [DllImport( "xadec.dll", EntryPoint = "xaDecodeClose", CallingConvention = CallingConvention.Cdecl )] + public extern static bool xaDecodeClose( IntPtr hxas ); + [DllImport( "xadec.dll", EntryPoint = "xaDecodeSize", CallingConvention = CallingConvention.Cdecl )] + public extern static bool xaDecodeSize( IntPtr hxas, uint slen, out uint pdlen ); + [DllImport( "xadec.dll", EntryPoint = "xaDecodeConvert", CallingConvention = CallingConvention.Cdecl )] + public extern static bool xaDecodeConvert( IntPtr hxas, ref XASTREAMHEADER psh ); + #endregion + + public XAHEADER xaheader; + public XASTREAMHEADER xastreamheader; + public CWin32.WAVEFORMATEX waveformatex; + + private string filename; + private byte[] srcBuf = null; + private int nHandle = -1; + + public override int Open( string filename ) + { + this.filename = filename; + + #region [ XAヘッダと、XAデータの読み出し ] + xaheader = new XAHEADER(); + using ( FileStream fs = new FileStream( filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ) ) // FileShare を付けとかないと、Close() 後もロックがかかる?? + { + using ( BinaryReader br = new BinaryReader( fs ) ) + { + xaheader.id = br.ReadUInt32(); + xaheader.nDataLen = br.ReadUInt32(); + xaheader.nSamples = br.ReadUInt32(); + xaheader.nSamplesPerSec = br.ReadUInt16(); + xaheader.nBits = br.ReadByte(); + xaheader.nChannels = br.ReadByte(); + xaheader.nLoopPtr = br.ReadUInt32(); + + xaheader.befL = new short[ 2 ]; + xaheader.befR = new short[ 2 ]; + xaheader.pad = new byte[ 4 ]; + + xaheader.befL[ 0 ] = br.ReadInt16(); + xaheader.befL[ 1 ] = br.ReadInt16(); + xaheader.befR[ 0 ] = br.ReadInt16(); + xaheader.befR[ 1 ] = br.ReadInt16(); + xaheader.pad = br.ReadBytes( 4 ); + + srcBuf = new byte[ xaheader.nDataLen ]; + srcBuf = br.ReadBytes( (int) xaheader.nDataLen ); + } + } + //string xaid = Encoding.ASCII.GetString( xah.id ); + #region [ デバッグ表示 ] + //Debug.WriteLine( "**XAHEADER**" ); + //Debug.WriteLine( "id= " + xaheader.id.ToString( "X8" ) ); + //Debug.WriteLine( "nDataLen= " + xaheader.nDataLen.ToString( "X8" ) ); + //Debug.WriteLine( "nSamples= " + xaheader.nSamples.ToString( "X8" ) ); + //Debug.WriteLine( "nSamplesPerSec= " + xaheader.nSamplesPerSec.ToString( "X4" ) ); + //Debug.WriteLine( "nBits= " + xaheader.nBits.ToString( "X2" ) ); + //Debug.WriteLine( "nChannels= " + xaheader.nChannels.ToString( "X2" ) ); + //Debug.WriteLine( "nLoopPtr= " + xaheader.nLoopPtr.ToString( "X8" ) ); + //Debug.WriteLine( "befL[0]= " + xaheader.befL[ 0 ].ToString( "X4" ) ); + //Debug.WriteLine( "befL[1]= " + xaheader.befL[ 1 ].ToString( "X4" ) ); + //Debug.WriteLine( "befR[0]= " + xaheader.befR[ 0 ].ToString( "X4" ) ); + //Debug.WriteLine( "befR[1]= " + xaheader.befR[ 1 ].ToString( "X4" ) ); + #endregion + #endregion + + IntPtr hxas; + + #region [ WAVEFORMEX情報の取得 ] + waveformatex = new CWin32.WAVEFORMATEX(); + hxas = xaDecodeOpen( ref xaheader, out waveformatex ); + if ( hxas == null ) + { + Trace.TraceError( "Error: xa: Open(): xaDecodeOpen(): " + Path.GetFileName( filename ) ); + return -1; + } + + #region [ デバッグ表示 ] + //Debug.WriteLine( "**WAVEFORMATEX**" ); + //Debug.WriteLine( "wFormatTag= " + waveformatex.wFormatTag.ToString( "X4" ) ); + //Debug.WriteLine( "nChannels = " + waveformatex.nChannels.ToString( "X4" ) ); + //Debug.WriteLine( "nSamplesPerSec= " + waveformatex.nSamplesPerSec.ToString( "X8" ) ); + //Debug.WriteLine( "nAvgBytesPerSec= " + waveformatex.nAvgBytesPerSec.ToString( "X8" ) ); + //Debug.WriteLine( "nBlockAlign= " + waveformatex.nBlockAlign.ToString( "X4" ) ); + //Debug.WriteLine( "wBitsPerSample= " + waveformatex.wBitsPerSample.ToString( "X4" ) ); + //Debug.WriteLine( "cbSize= " + waveformatex.cbSize.ToString( "X4" ) ); + #endregion + #endregion + + this.nHandle = (int) hxas; + return (int) hxas; + } + public override int GetFormat( int nHandle, ref CWin32.WAVEFORMATEX wfx ) + { + #region [ WAVEFORMATEX構造体の手動コピー ] + wfx.nAvgBytesPerSec = waveformatex.nAvgBytesPerSec; + wfx.wBitsPerSample = waveformatex.wBitsPerSample; + wfx.nBlockAlign = waveformatex.nBlockAlign; + wfx.nChannels = waveformatex.nChannels; + wfx.wFormatTag = waveformatex.wFormatTag; + wfx.nSamplesPerSec = waveformatex.nSamplesPerSec; + + return 0; + #endregion + } + public override uint GetTotalPCMSize( int nHandle ) + { + #region [ データ長の取得 ] + uint dlen; + xaDecodeSize( (IntPtr) nHandle, xaheader.nDataLen, out dlen ); + #region [ デバッグ表示 ] + //Debug.WriteLine( "**INTERNAL VALUE**" ); + //Debug.WriteLine( "dlen= " + dlen ); + #endregion + #endregion + + return dlen; + } + public override int Seek( int nHandle, uint dwPosition ) + { + return 0; + } + public override int Decode( int nHandle, IntPtr pDest, uint szDestSize, int bLoop ) + { + #region [ xaデータのデコード ] + xastreamheader = new XASTREAMHEADER(); + unsafe + { + fixed ( byte* pXaBuf = srcBuf ) + { + byte* pWavBuf = (byte*) pDest; + + xastreamheader.pSrc = pXaBuf; + xastreamheader.nSrcLen = xaheader.nDataLen; + xastreamheader.nSrcUsed = 0; + xastreamheader.pDst = pWavBuf; + xastreamheader.nDstLen = szDestSize; + xastreamheader.nDstUsed = 0; + if ( !xaDecodeConvert( (IntPtr) nHandle, ref xastreamheader ) ) + { + Trace.TraceError( "Error: xaDecodeConvert(): " + Path.GetFileName( filename ) ); + return -1; + } + } + } + #region [ デバッグ表示 ] + //Debug.WriteLine( "**XASTREAMHEADER**" ); + //Debug.WriteLine( "nSrcLen= " + xastreamheader.nSrcLen ); + //Debug.WriteLine( "nSrcUsed= " + xastreamheader.nSrcUsed ); + //Debug.WriteLine( "nDstLen= " + xastreamheader.nDstLen ); + //Debug.WriteLine( "nDstUsed= " + xastreamheader.nDstUsed ); + #endregion + #endregion + + return 0; + } + public override void Close( int nHandle ) + { + #region [ xaファイルのクローズ ] + if ( !xaDecodeClose( (IntPtr) nHandle ) ) + { + Trace.TraceError( "Error: xaDecodeClose(): " + Path.GetFileName( filename ) ); + } + srcBuf = null; + #endregion + } + + + + //#region [ IDisposable 実装 ] + ////----------------- + //private bool bDispose完了済み = false; + //public void Dispose() + //{ + // if ( !this.bDispose完了済み ) + // { + // if ( srcBuf != null ) + // { + // srcBuf = null; + // } + // if ( dstBuf != null ) + // { + // dstBuf = null; + // } + + // if ( this.nHandle >= 0 ) + // { + // this.Close( this.nHandle ); + // this.nHandle = -1; + // } + // this.bDispose完了済み = true; + // } + //} + ////----------------- + //#endregion + +#if false + /// + /// xaファイルを読み込んで、wavにdecodeする + /// + /// xaファイル名 + /// wavファイルが格納されるバッファ + /// + public bool Decode( string filename, out byte[] wavBuf ) + { + // Debug.WriteLine( "xa: Decode: " + Path.GetFileName( filename ) ); + + #region [ XAヘッダと、XAデータの読み出し ] + xaheader = new XAHEADER(); + byte[] xaBuf; + using ( FileStream fs = new FileStream( filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ) ) // FileShare を付けとかないと、Close() 後もロックがかかる?? + { + using ( BinaryReader br = new BinaryReader( fs ) ) + { + xaheader.id = br.ReadUInt32(); + xaheader.nDataLen = br.ReadUInt32(); + xaheader.nSamples = br.ReadUInt32(); + xaheader.nSamplesPerSec = br.ReadUInt16(); + xaheader.nBits = br.ReadByte(); + xaheader.nChannels = br.ReadByte(); + xaheader.nLoopPtr = br.ReadUInt32(); + + xaheader.befL = new short[ 2 ]; + xaheader.befR = new short[ 2 ]; + xaheader.pad = new byte[ 4 ]; + + xaheader.befL[ 0 ] = br.ReadInt16(); + xaheader.befL[ 1 ] = br.ReadInt16(); + xaheader.befR[ 0 ] = br.ReadInt16(); + xaheader.befR[ 1 ] = br.ReadInt16(); + xaheader.pad = br.ReadBytes( 4 ); + + xaBuf = new byte[ xaheader.nDataLen ]; + xaBuf = br.ReadBytes( (int) xaheader.nDataLen ); + } + } + //string xaid = Encoding.ASCII.GetString( xah.id ); + #region [ デバッグ表示 ] + //Debug.WriteLine( "**XAHEADER**" ); + //Debug.WriteLine( "id= " + xaheader.id.ToString( "X8" ) ); + //Debug.WriteLine( "nDataLen= " + xaheader.nDataLen.ToString( "X8" ) ); + //Debug.WriteLine( "nSamples= " + xaheader.nSamples.ToString( "X8" ) ); + //Debug.WriteLine( "nSamplesPerSec= " + xaheader.nSamplesPerSec.ToString( "X4" ) ); + //Debug.WriteLine( "nBits= " + xaheader.nBits.ToString( "X2" ) ); + //Debug.WriteLine( "nChannels= " + xaheader.nChannels.ToString( "X2" ) ); + //Debug.WriteLine( "nLoopPtr= " + xaheader.nLoopPtr.ToString( "X8" ) ); + //Debug.WriteLine( "befL[0]= " + xaheader.befL[ 0 ].ToString( "X4" ) ); + //Debug.WriteLine( "befL[1]= " + xaheader.befL[ 1 ].ToString( "X4" ) ); + //Debug.WriteLine( "befR[0]= " + xaheader.befR[ 0 ].ToString( "X4" ) ); + //Debug.WriteLine( "befR[1]= " + xaheader.befR[ 1 ].ToString( "X4" ) ); + #endregion + #endregion + + object lockobj = new object(); + lock ( lockobj ) // スレッドセーフじゃないかも知れないので、念のため + { + #region [ WAVEFORMEX情報の取得 ] + waveformatex = new CWin32.WAVEFORMATEX(); + IntPtr hxas = xaDecodeOpen( ref xaheader, out waveformatex ); + if ( hxas == null ) + { + Trace.TraceError( "Error: xaDecodeOpen(): " + Path.GetFileName( filename ) ); + wavBuf = null; + return false; + } + + #region [ デバッグ表示 ] + //Debug.WriteLine( "**WAVEFORMATEX**" ); + //Debug.WriteLine( "wFormatTag= " + waveformatex.wFormatTag.ToString( "X4" ) ); + //Debug.WriteLine( "nChannels = " + waveformatex.nChannels.ToString( "X4" ) ); + //Debug.WriteLine( "nSamplesPerSec= " + waveformatex.nSamplesPerSec.ToString( "X8" ) ); + //Debug.WriteLine( "nAvgBytesPerSec= " + waveformatex.nAvgBytesPerSec.ToString( "X8" ) ); + //Debug.WriteLine( "nBlockAlign= " + waveformatex.nBlockAlign.ToString( "X4" ) ); + //Debug.WriteLine( "wBitsPerSample= " + waveformatex.wBitsPerSample.ToString( "X4" ) ); + //Debug.WriteLine( "cbSize= " + waveformatex.cbSize.ToString( "X4" ) ); + #endregion + #endregion + + #region [ データ長の取得 ] + uint dlen; + xaDecodeSize( hxas, xaheader.nDataLen, out dlen ); + #region [ デバッグ表示 ] + //Debug.WriteLine( "**INTERNAL VALUE**" ); + //Debug.WriteLine( "dlen= " + dlen ); + #endregion + #endregion + + #region [ xaデータのデコード ] + wavBuf = new byte[ dlen ]; + xastreamheader = new XASTREAMHEADER(); + + unsafe + { + fixed ( byte* pXaBuf = xaBuf, pWavBuf = wavBuf ) + { + xastreamheader.pSrc = pXaBuf; + xastreamheader.nSrcLen = xaheader.nDataLen; + xastreamheader.nSrcUsed = 0; + xastreamheader.pDst = pWavBuf; + xastreamheader.nDstLen = dlen; + xastreamheader.nDstUsed = 0; + bool b = xaDecodeConvert( hxas, ref xastreamheader ); + if ( !b ) + { + Trace.TraceError( "Error: xaDecodeConvert(): " + Path.GetFileName( filename ) ); + wavBuf = null; + return false; + } + } + } + #region [ デバッグ表示 ] + //Debug.WriteLine( "**XASTREAMHEADER**" ); + //Debug.WriteLine( "nSrcLen= " + xastreamheader.nSrcLen ); + //Debug.WriteLine( "nSrcUsed= " + xastreamheader.nSrcUsed ); + //Debug.WriteLine( "nDstLen= " + xastreamheader.nDstLen ); + //Debug.WriteLine( "nDstUsed= " + xastreamheader.nDstUsed ); + #endregion + #endregion + + #region [ xaファイルのクローズ ] + bool bb = xaDecodeClose( hxas ); + if ( !bb ) + { + Trace.TraceError( "Error: xaDecodeClose(): " + Path.GetFileName( filename ) ); + } + #endregion + } + + return true; + } +#endif + } +}