• R/O
  • HTTP
  • SSH
  • HTTPS

CsWin10Desktop3: Commit

Visual C# 7.0, Windows10 Desktop App


Commit MetaInfo

Revisión8b2234ac2e453bf67f53a44d5236bcc0c105556c (tree)
Tiempo2017-10-16 20:01:07
Autorくまかみ工房 <kumakamikoubou@gmai...>
Commiterくまかみ工房

Log Message

XA形式サウンドファイルに対応。

xadec.dll をプロジェクトに追加。
「_EncodedWaveData」を「_DecodedWaveData」に訂正。

Cambiar Resumen

Diferencia

--- a/FDK/FDK.csproj
+++ b/FDK/FDK.csproj
@@ -140,6 +140,8 @@
140140 <Compile Include="メディア\サウンド\WASAPI\Sound.cs" />
141141 <Compile Include="メディア\サウンド\WASAPI\SoundDevice.cs" />
142142 <Compile Include="メディア\サウンド\WASAPI\SoundTimer.cs" />
143+ <Compile Include="メディア\サウンド\WASAPI\XaResampledWaveSource.cs" />
144+ <Compile Include="メディア\サウンド\WASAPI\XAWaveSource.cs" />
143145 <Compile Include="メディア\テクスチャ.cs" />
144146 <Compile Include="メディア\テクスチャフォント.cs" />
145147 <Compile Include="メディア\ビットマップ付きテクスチャ.cs" />
@@ -168,5 +170,10 @@
168170 <ItemGroup>
169171 <None Include="packages.config" />
170172 </ItemGroup>
173+ <ItemGroup>
174+ <None Include="xadec.dll">
175+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
176+ </None>
177+ </ItemGroup>
171178 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
172179 </Project>
\ No newline at end of file
Binary files /dev/null and b/FDK/xadec.dll differ
--- a/FDK/メディア/サウンド/WASAPI/MediaFoundationWaveSource.cs
+++ b/FDK/メディア/サウンド/WASAPI/MediaFoundationWaveSource.cs
@@ -33,7 +33,7 @@ namespace FDK.メディア.サウンド.WASAPI
3333 /// デコード後のオーディオデータのすべての長さ[byte]。
3434 /// </summary>
3535 public long Length
36- => this._EncodedWaveData.Length;
36+ => this._DecodedWaveData.Length;
3737
3838 /// <summary>
3939 /// 現在の再生位置[byte]。
@@ -51,8 +51,10 @@ namespace FDK.メディア.サウンド.WASAPI
5151 /// コンストラクタ。
5252 /// 指定されたファイルを指定されたフォーマットでデコードし、内部にオンメモリで保管する。
5353 /// </summary>
54- public MediaFoundationWaveSource( string path, WaveFormat deviceFormat )
54+ public MediaFoundationWaveSource( string ファイルパス, WaveFormat deviceFormat )
5555 {
56+ var path = Folder.絶対パスに含まれるフォルダ変数を展開して返す( ファイルパス );
57+
5658 this.WaveFormat = new WaveFormat(
5759 deviceFormat.SampleRate, // 指定されたレート
5860 32, // 32bit 固定
@@ -128,7 +130,7 @@ namespace FDK.メディア.サウンド.WASAPI
128130 }
129131
130132 // (4) ストリームの内容を byte 配列に出力する。
131- this._EncodedWaveData = waveStream.ToArray();
133+ this._DecodedWaveData = waveStream.ToArray();
132134 }
133135 }
134136
@@ -137,7 +139,7 @@ namespace FDK.メディア.サウンド.WASAPI
137139 /// </summary>
138140 public void Dispose()
139141 {
140- this._EncodedWaveData = null;
142+ this._DecodedWaveData = null;
141143 FDKUtilities.解放する( ref this._MediaType );
142144 }
143145
@@ -151,7 +153,7 @@ namespace FDK.メディア.サウンド.WASAPI
151153 public int Read( byte[] buffer, int offset, int count )
152154 {
153155 // ※ 音がめちゃくちゃになるとうざいので、このメソッド内では例外を出さないこと。
154- if( ( null == this._EncodedWaveData ) || ( null == buffer ) )
156+ if( ( null == this._DecodedWaveData ) || ( null == buffer ) )
155157 return 0;
156158
157159 long 読み込み可能な最大count = ( this.Length - this._Position );
@@ -161,7 +163,7 @@ namespace FDK.メディア.サウンド.WASAPI
161163 if( 0 < count )
162164 {
163165 Buffer.BlockCopy(
164- src: this._EncodedWaveData,
166+ src: this._DecodedWaveData,
165167 srcOffset: (int) this._Position,
166168 dst: buffer,
167169 dstOffset: offset,
@@ -174,7 +176,7 @@ namespace FDK.メディア.サウンド.WASAPI
174176 }
175177
176178 private MFMediaType _MediaType = null;
177- private byte[] _EncodedWaveData = null;
179+ private byte[] _DecodedWaveData = null;
178180 private long _Position = 0;
179181 }
180182 }
--- a/FDK/メディア/サウンド/WASAPI/NVorbisResampledWaveSource.cs
+++ b/FDK/メディア/サウンド/WASAPI/NVorbisResampledWaveSource.cs
@@ -30,7 +30,7 @@ namespace FDK.メディア.サウンド.WASAPI
3030 /// デコード後のオーディオデータのすべての長さ[byte]。
3131 /// </summary>
3232 public long Length
33- => this._EncodedWaveData.Length;
33+ => this._DecodedWaveData.Length;
3434
3535 /// <summary>
3636 /// 現在の再生位置[byte]。
@@ -63,8 +63,8 @@ namespace FDK.メディア.サウンド.WASAPI
6363 // resampler.Length はサンプル単位ではなくフレーム単位。
6464 var サイズbyte = resampler.Length * resampler.WaveFormat.Channels; // 実際のサイズはチャンネル倍ある。
6565
66- this._EncodedWaveData = new byte[ サイズbyte ];
67- resampler.Read( this._EncodedWaveData, 0, (int) サイズbyte ); // でもこっちはバイト単位。
66+ this._DecodedWaveData = new byte[ サイズbyte ];
67+ resampler.Read( this._DecodedWaveData, 0, (int) サイズbyte ); // でもこっちはバイト単位。
6868 }
6969 }
7070
@@ -78,7 +78,7 @@ namespace FDK.メディア.サウンド.WASAPI
7878 public int Read( byte[] buffer, int offset, int count )
7979 {
8080 // ※ 音がめちゃくちゃになるとうざいので、このメソッド内では例外を出さないこと。
81- if( ( null == this._EncodedWaveData ) || ( null == buffer ) )
81+ if( ( null == this._DecodedWaveData ) || ( null == buffer ) )
8282 return 0;
8383
8484 long 読み込み可能な最大count = ( this.Length - this._Position );
@@ -88,7 +88,7 @@ namespace FDK.メディア.サウンド.WASAPI
8888 if( 0 < count )
8989 {
9090 Buffer.BlockCopy(
91- src: this._EncodedWaveData,
91+ src: this._DecodedWaveData,
9292 srcOffset: (int) this._Position,
9393 dst: buffer,
9494 dstOffset: offset,
@@ -105,10 +105,10 @@ namespace FDK.メディア.サウンド.WASAPI
105105 /// </summary>
106106 public void Dispose()
107107 {
108- this._EncodedWaveData = null;
108+ this._DecodedWaveData = null;
109109 }
110110
111- private byte[] _EncodedWaveData = null;
111+ private byte[] _DecodedWaveData = null;
112112 private long _Position = 0;
113113 }
114114 }
--- a/FDK/メディア/サウンド/WASAPI/NVorbisSampleSource.cs
+++ b/FDK/メディア/サウンド/WASAPI/NVorbisSampleSource.cs
@@ -9,7 +9,7 @@ using NVorbis;
99 namespace FDK.メディア.サウンド.WASAPI
1010 {
1111 /// <summary>
12- /// 指定されたメディアファイル(動画, 音楽)を Vorbis としてデコードして、CSCore.IWaveSource オブジェクトを生成する。
12+ /// 指定されたメディアファイル(動画, 音楽)を Vorbis としてデコードして、CSCore.ISampleSource オブジェクトを生成する。
1313 /// リサンプラーなし版。
1414 /// 参照:<seealso cref="https://cscore.codeplex.com/SourceControl/latest#Samples/NVorbisIntegration/Program.cs"/>
1515 /// </summary>
--- a/FDK/メディア/サウンド/WASAPI/SampleSourceFactory.cs
+++ b/FDK/メディア/サウンド/WASAPI/SampleSourceFactory.cs
@@ -17,34 +17,41 @@ namespace FDK.メディア.サウンド.WASAPI
1717 public static ISampleSource Create( SoundDevice device, string ファイルパス )
1818 {
1919 var path = Folder.絶対パスに含まれるフォルダ変数を展開して返す( ファイルパス );
20+ var ext = Path.GetExtension( path ).ToLower();
2021
2122 #region " NVorbis を試みる "
2223 //----------------
23- try
24+ if( ".ogg" == ext )
2425 {
25- using( var audioStream = new FileStream( path, FileMode.Open ) )
26+ try
2627 {
27- return new NVorbisResampledWaveSource( audioStream, device.WaveFormat )
28- .ToSampleSource();
28+ using( var audioStream = new FileStream( path, FileMode.Open ) )
29+ {
30+ return new NVorbisResampledWaveSource( audioStream, device.WaveFormat )
31+ .ToSampleSource();
32+ }
33+ }
34+ catch
35+ {
36+ // ダメだったので次へ。
2937 }
30- }
31- catch
32- {
33- // ダメだったので次へ。
3438 }
3539 //----------------
3640 #endregion
3741
38- #region " CSCore を試みる "
42+ #region " XA を試みる "
3943 //----------------
40- try
44+ if( ".xa" == ext )
4145 {
42- // 対応できるフォーマットは MediaFoundation とダブるので、こちらの実装は不要かも。
43- //return new CSCoreSampleSource( path );
44- }
45- catch
46- {
47- // ダメだったので次へ。
46+ try
47+ {
48+ return new XaResampledWaveSource( path, device.WaveFormat )
49+ .ToSampleSource();
50+ }
51+ catch
52+ {
53+ // ダメだったので次へ。
54+ }
4855 }
4956 //----------------
5057 #endregion
--- /dev/null
+++ b/FDK/メディア/サウンド/WASAPI/XAWaveSource.cs
@@ -0,0 +1,260 @@
1+using System;
2+using System.Collections.Generic;
3+using System.Diagnostics;
4+using System.IO;
5+using System.Linq;
6+using System.Runtime.InteropServices;
7+using CSCore;
8+using CSCore.DSP;
9+
10+namespace FDK.メディア.サウンド.WASAPI
11+{
12+ /// <summary>
13+ /// 指定されたメディアファイルを XA としてデコードして、CSCore.IWaveSource オブジェクトを生成する。
14+ /// リサンプラーなし版。
15+ /// </summary>
16+ unsafe class XAWaveSource : IWaveSource
17+ {
18+ public bool CanSeek => true; // オンメモリなので常にサポートする。
19+
20+ public WaveFormat WaveFormat
21+ {
22+ get;
23+ protected set;
24+ } = null;
25+
26+ /// <summary>
27+ /// デコード後のオーディオデータのすべての長さ[byte]。
28+ /// </summary>
29+ public long Length
30+ => this._DecodedWaveData.Length;
31+
32+ /// <summary>
33+ /// 現在の再生位置[byte]。
34+ /// </summary>
35+ public long Position
36+ {
37+ get
38+ => this._Position;
39+ set
40+ => this._Position = FDKUtilities.位置をブロック境界単位にそろえて返す( value, this.WaveFormat.BlockAlign );
41+ }
42+
43+ /// <summary>
44+ /// コンストラクタ。
45+ /// 指定されたファイルを指定されたフォーマットでデコードし、内部にオンメモリで保管する。
46+ /// </summary>
47+ public XAWaveSource( string ファイルパス, WaveFormat deviceFormat )
48+ {
49+ var path = Folder.絶対パスに含まれるフォルダ変数を展開して返す( ファイルパス );
50+
51+ var xaheader = new XAHEADER();
52+ var srcBuf = (byte[]) null;
53+
54+ #region " XAHEADER と XAデータ を読み込みむ。"
55+ //----------------
56+ using( var br = new BinaryReader( new FileStream( path, FileMode.Open ) ) )
57+ {
58+ xaheader.id = br.ReadUInt32();
59+ xaheader.nDataLen = br.ReadUInt32();
60+ xaheader.nSamples = br.ReadUInt32();
61+ xaheader.nSamplesPerSec = br.ReadUInt16();
62+ xaheader.nBits = br.ReadByte();
63+ xaheader.nChannels = br.ReadByte();
64+ xaheader.nLoopPtr = br.ReadUInt32();
65+ xaheader.befL = new short[ 2 ];
66+ xaheader.befL[ 0 ] = br.ReadInt16();
67+ xaheader.befL[ 1 ] = br.ReadInt16();
68+ xaheader.befR = new short[ 2 ];
69+ xaheader.befR[ 0 ] = br.ReadInt16();
70+ xaheader.befR[ 1 ] = br.ReadInt16();
71+ xaheader.pad = new byte[ 4 ];
72+ xaheader.pad = br.ReadBytes( 4 );
73+
74+ srcBuf = br.ReadBytes( (int) xaheader.nDataLen );
75+ }
76+ //----------------
77+ #endregion
78+
79+ var waveformatex = new WAVEFORMATEX();
80+ var handlePtr = IntPtr.Zero;
81+
82+ #region " XAファイルをオープンし、Waveフォーマットとハンドルを取得。"
83+ //----------------
84+ handlePtr = xaDecodeOpen( ref xaheader, out waveformatex );
85+
86+ if( null == handlePtr || IntPtr.Zero == handlePtr )
87+ throw new Exception( $"xaDecodeOpen に失敗しました。[{ファイルパス}]" );
88+ //----------------
89+ #endregion
90+
91+ #region " Waveフォーマットを WaveFormat プロパティに設定。"
92+ //----------------
93+ if( 0 == waveformatex.cbSize )
94+ {
95+ this.WaveFormat = new WaveFormat(
96+ (int) waveformatex.nSamplesPerSec,
97+ (int) waveformatex.wBitsPerSample,
98+ (int) waveformatex.nChannels,
99+ (AudioEncoding) waveformatex.wFormatTag );
100+ }
101+ else
102+ {
103+ var msg = $"デコード後のフォーマットが WAVEFORMATEX 型になる XA には未対応です。[{ファイルパス}]";
104+ Log.ERROR( msg );
105+ throw new Exception( msg );
106+ }
107+ //----------------
108+ #endregion
109+
110+ #region " デコード後のPCMサイズ[byte]を取得し、バッファを確保する。"
111+ //----------------
112+ if( !( xaDecodeSize( handlePtr, xaheader.nDataLen, out uint decodedWaveDataLength ) ) )
113+ {
114+ var msg = $"xaDecodeSize に失敗しました。[{ファイルパス}]";
115+ Log.ERROR( msg );
116+ throw new Exception( msg );
117+ }
118+ this._DecodedWaveData = new byte[ decodedWaveDataLength ];
119+ //----------------
120+ #endregion
121+
122+ #region " デコードする。"
123+ //----------------
124+ unsafe
125+ {
126+ fixed ( byte* pXaBuf = srcBuf )
127+ fixed ( byte* pPcmBuf = this._DecodedWaveData )
128+ {
129+ var xastreamheader = new XASTREAMHEADER() {
130+ pSrc = pXaBuf,
131+ nSrcLen = xaheader.nDataLen,
132+ nSrcUsed = 0,
133+ pDst = pPcmBuf,
134+ nDstLen = decodedWaveDataLength,
135+ nDstUsed = 0,
136+ };
137+ if( !( xaDecodeConvert( handlePtr, ref xastreamheader ) ) )
138+ {
139+ var msg = $"xaDecodeConvert に失敗しました。[{ファイルパス}]";
140+ Log.ERROR( msg );
141+ throw new Exception( msg );
142+ }
143+ }
144+ }
145+ //----------------
146+ #endregion
147+
148+ #region " XAファイルを閉じる。"
149+ //----------------
150+ if( !( xaDecodeClose( handlePtr ) ) )
151+ {
152+ var msg = $"xaDecodeClose に失敗しました。[{ファイルパス}]";
153+ Log.ERROR( msg );
154+ throw new Exception( msg );
155+ }
156+ //----------------
157+ #endregion
158+ }
159+
160+ /// <summary>
161+ /// 解放する。
162+ /// </summary>
163+ public void Dispose()
164+ {
165+ this._DecodedWaveData = null;
166+ }
167+
168+ /// <summary>
169+ /// 連続したデータを読み込み、<see cref="Position"/> を読み込んだ数だけ進める。
170+ /// </summary>
171+ /// <param name="buffer">読み込んだデータを格納するための配列。</param>
172+ /// <param name="offset"><paramref name="buffer"/> に格納を始める位置。</param>
173+ /// <param name="count">読み込む最大のデータ数。</param>
174+ /// <returns><paramref name="buffer"/> に読み込んだデータの総数。</returns>
175+ public int Read( byte[] buffer, int offset, int count )
176+ {
177+ // ※ 音がめちゃくちゃになるとうざいので、このメソッド内では例外を出さないこと。
178+ if( ( null == this._DecodedWaveData ) || ( null == buffer ) )
179+ return 0;
180+
181+ long 読み込み可能な最大count = ( this.Length - this._Position );
182+ if( count > 読み込み可能な最大count )
183+ count = (int) 読み込み可能な最大count;
184+
185+ if( 0 < count )
186+ {
187+ Buffer.BlockCopy(
188+ src: this._DecodedWaveData,
189+ srcOffset: (int) this._Position,
190+ dst: buffer,
191+ dstOffset: offset,
192+ count: count );
193+
194+ this._Position += count;
195+ }
196+
197+ return count;
198+ }
199+
200+ private byte[] _DecodedWaveData = null;
201+ private long _Position = 0;
202+
203+ #region " Win32(xsdec.dll) "
204+ //----------------
205+ [StructLayout( LayoutKind.Sequential )]
206+ public struct WAVEFORMATEX
207+ {
208+ public ushort wFormatTag;
209+ public ushort nChannels;
210+ public uint nSamplesPerSec;
211+ public uint nAvgBytesPerSec;
212+ public ushort nBlockAlign;
213+ public ushort wBitsPerSample;
214+ public ushort cbSize;
215+ }
216+
217+ [StructLayout( LayoutKind.Sequential )]
218+ public struct XASTREAMHEADER
219+ {
220+ public byte* pSrc;
221+ public uint nSrcLen;
222+ public uint nSrcUsed;
223+ public byte* pDst;
224+ public uint nDstLen;
225+ public uint nDstUsed;
226+ }
227+
228+ [StructLayout( LayoutKind.Sequential )]
229+ public struct XAHEADER
230+ {
231+ public uint id;
232+ public uint nDataLen;
233+ public uint nSamples;
234+ public ushort nSamplesPerSec;
235+ public byte nBits;
236+ public byte nChannels;
237+ public uint nLoopPtr;
238+ [MarshalAs( UnmanagedType.ByValArray, SizeConst = 2 )]
239+ public short[] befL;
240+ [MarshalAs( UnmanagedType.ByValArray, SizeConst = 2 )]
241+ public short[] befR;
242+ [MarshalAs( UnmanagedType.ByValArray, SizeConst = 4 )]
243+ public byte[] pad;
244+ }
245+
246+ [DllImport( "xadec.dll", EntryPoint = "xaDecodeOpen", CallingConvention = CallingConvention.Cdecl )]
247+ public extern static IntPtr xaDecodeOpen( ref XAHEADER pxah, out WAVEFORMATEX pwfx );
248+
249+ [DllImport( "xadec.dll", EntryPoint = "xaDecodeClose", CallingConvention = CallingConvention.Cdecl )]
250+ public extern static bool xaDecodeClose( IntPtr hxas );
251+
252+ [DllImport( "xadec.dll", EntryPoint = "xaDecodeSize", CallingConvention = CallingConvention.Cdecl )]
253+ public extern static bool xaDecodeSize( IntPtr hxas, uint slen, out uint pdlen );
254+
255+ [DllImport( "xadec.dll", EntryPoint = "xaDecodeConvert", CallingConvention = CallingConvention.Cdecl )]
256+ public extern static bool xaDecodeConvert( IntPtr hxas, ref XASTREAMHEADER psh );
257+ //----------------
258+ #endregion
259+ }
260+}
--- /dev/null
+++ b/FDK/メディア/サウンド/WASAPI/XaResampledWaveSource.cs
@@ -0,0 +1,111 @@
1+using System;
2+using System.Collections.Generic;
3+using System.Diagnostics;
4+using System.Linq;
5+using CSCore;
6+using CSCore.DSP;
7+
8+namespace FDK.メディア.サウンド.WASAPI
9+{
10+ /// <summary>
11+ /// 指定されたメディアファイルを XA としてデコードして、CSCore.IWaveSource オブジェクトを生成する。
12+ /// リサンプラーあり版。
13+ /// </summary>
14+ class XaResampledWaveSource : IWaveSource
15+ {
16+ public bool CanSeek => true; // オンメモリなので常にサポートできる。
17+
18+ /// <summary>
19+ /// デコード&リサンプル後のオーディオデータのフォーマット。
20+ /// </summary>
21+ public WaveFormat WaveFormat
22+ {
23+ get;
24+ protected set;
25+ } = null;
26+
27+ /// <summary>
28+ /// デコード後のオーディオデータのすべての長さ[byte]。
29+ /// </summary>
30+ public long Length
31+ => this._DecodedWaveData.Length;
32+
33+ /// <summary>
34+ /// 現在の再生位置[byte]。
35+ /// </summary>
36+ public long Position
37+ {
38+ get
39+ => this._Position;
40+ set
41+ => this._Position = FDKUtilities.位置をブロック境界単位にそろえて返す( value, this.WaveFormat.BlockAlign );
42+ }
43+
44+ /// <summary>
45+ /// コンストラクタ。
46+ /// 指定されたXAファイルを指定されたフォーマットでデコードし、内部にオンメモリで保管する。
47+ /// </summary>
48+ public XaResampledWaveSource( string ファイルパス, WaveFormat deviceFormat )
49+ {
50+ this.WaveFormat = new WaveFormat(
51+ deviceFormat.SampleRate,
52+ 32,
53+ deviceFormat.Channels,
54+ AudioEncoding.IeeeFloat );
55+
56+ // リサンプルなし版で生成して、それを this.WaveFormat に合わせてリサンプルしたデータ(byte[])を保管する。
57+ using( var xaSource = new XAWaveSource( ファイルパス, deviceFormat ) )
58+ using( var resampler = new DmoResampler( xaSource, this.WaveFormat ) )
59+ {
60+ // resampler.Length はサンプル単位ではなくフレーム単位。
61+ var サイズbyte = resampler.Length * resampler.WaveFormat.Channels; // 実際のサイズはチャンネル倍ある。
62+
63+ this._DecodedWaveData = new byte[ サイズbyte ];
64+ resampler.Read( this._DecodedWaveData, 0, (int) サイズbyte ); // でもこっちはバイト単位。
65+ }
66+ }
67+
68+ /// <summary>
69+ /// 連続したデータを読み込み、<see cref="Position"/> を読み込んだ数だけ進める。
70+ /// </summary>
71+ /// <param name="buffer">読み込んだデータを格納するための配列。</param>
72+ /// <param name="offset"><paramref name="buffer"/> に格納を始める位置。</param>
73+ /// <param name="count">読み込む最大のデータ数。</param>
74+ /// <returns><paramref name="buffer"/> に読み込んだデータの総数。</returns>
75+ public int Read( byte[] buffer, int offset, int count )
76+ {
77+ // ※ 音がめちゃくちゃになるとうざいので、このメソッド内では例外を出さないこと。
78+ if( ( null == this._DecodedWaveData ) || ( null == buffer ) )
79+ return 0;
80+
81+ long 読み込み可能な最大count = ( this.Length - this._Position );
82+ if( count > 読み込み可能な最大count )
83+ count = (int) 読み込み可能な最大count;
84+
85+ if( 0 < count )
86+ {
87+ Buffer.BlockCopy(
88+ src: this._DecodedWaveData,
89+ srcOffset: (int) this._Position,
90+ dst: buffer,
91+ dstOffset: offset,
92+ count: count );
93+
94+ this._Position += count;
95+ }
96+
97+ return count;
98+ }
99+
100+ /// <summary>
101+ /// 解放する。
102+ /// </summary>
103+ public void Dispose()
104+ {
105+ this._DecodedWaveData = null;
106+ }
107+
108+ private byte[] _DecodedWaveData = null;
109+ private long _Position = 0;
110+ }
111+}
Show on old repository browser