sw.WriteLine( "VSyncWait={0}", this.b垂直帰線待ちを行う ? 1 : 0 );\r
sw.WriteLine();\r
\r
- sw.WriteLine( "; サウンド出力方式(0=ACM, 1=ASIO, 2=WASAPI)" );\r
- sw.WriteLine( "; WASAPIはVista以降のOSで使用可能。" );\r
- sw.WriteLine( "; WASAPIã\81\8c使ç\94¨ä¸\8då\8f¯ã\81ªã\82\89ASIOã\81«、ASIOが使用不可ならACMを使用します。" );\r
+ sw.WriteLine( "; サウンド出力方式(0=ACM(って今はまだDirectShowですが), 1=ASIO, 2=WASAPI)" );\r
+ sw.WriteLine( "; WASAPIはVista以降のOSで使用可能。推奨方式はWASAPI。" );\r
+ sw.WriteLine( "; WASAPIã\81\8c使ç\94¨ä¸\8då\8f¯ã\81ªã\82\89ASIOã\82\92、ASIOが使用不可ならACMを使用します。" );\r
sw.WriteLine( "; Sound device type(0=ACM, 1=ASIO, 2=WASAPI)" );\r
sw.WriteLine( "; WASAPI can use on Vista or later OSs." );\r
sw.WriteLine( "; If WASAPI is not available, DTXMania try to use ASIO. If ASIO can't be used, ACM is used." );\r
#endregion\r
#region [ Sound管理 の初期化 ]\r
//---------------------\r
- Trace.TraceInformation( "DirectSound の初期化を行います。" );\r
+ Trace.TraceInformation( "サウンドデバイスの初期化を行います。" );\r
Trace.Indent();\r
try\r
{ \r
break;\r
}\r
Sound管理 = new CSound管理( base.Window.Handle, soundDeviceType );\r
- Trace.TraceInformation( "DirectSound の初期化を完了しました。" );\r
+ Trace.TraceInformation( "サウンドデバイスの初期化を完了しました。" );\r
}\r
catch (Exception e)\r
{\r
<Optimize>true</Optimize>\r
</PropertyGroup>\r
<ItemGroup>\r
- <Reference Include="Bass.Net, Version=2.4.8.0, Culture=neutral, PublicKeyToken=b7566c273e6ef480, processorArchitecture=MSIL">\r
+ <Reference Include="Bass.Net, Version=2.4.9.1, Culture=neutral, PublicKeyToken=b7566c273e6ef480, processorArchitecture=MSIL">\r
<SpecificVersion>False</SpecificVersion>\r
<HintPath>..\実行時フォルダ\Bass.Net.dll</HintPath>\r
</Reference>\r
<Compile Include="コード\02.入力\E入力デバイス種別.cs" />\r
<Compile Include="コード\02.入力\IInputDevice.cs" />\r
<Compile Include="コード\02.入力\STInputEvent.cs" />\r
+ <Compile Include="コード\03.サウンド\Cogg.cs" />\r
<Compile Include="コード\03.サウンド\CSound.cs" />\r
<Compile Include="コード\03.サウンド\CSoundDeviceASIO.cs" />\r
<Compile Include="コード\03.サウンド\CSoundDeviceDirectSound.cs" />\r
<Compile Include="コード\03.サウンド\CSoundTimer.cs" />\r
<Compile Include="コード\03.サウンド\Cxa.cs" />\r
<Compile Include="コード\03.サウンド\ESoundDeviceType.cs" />\r
+ <Compile Include="コード\03.サウンド\SoundDecoder.cs" />\r
<Compile Include="コード\03.サウンド\ISoundDevice.cs" />\r
<Compile Include="コード\04.グラフィック\BitmapUtil.cs" />\r
<Compile Include="コード\04.グラフィック\CAero.cs" />\r
SoundDevice = null; // ユーザ依存\r
rc演奏用タイマ = null; // Global.Bass 依存(つまりユーザ依存)\r
\r
- //SoundDeviceType = soundDeviceType;\r
- //SoundDeviceType = ESoundDeviceType.DirectSound;\r
- //SoundDeviceType = ESoundDeviceType.ExclusiveWASAPI;\r
- //SoundDeviceType = ESoundDeviceType.ASIO;\r
-\r
ESoundDeviceType[] ESoundDeviceTypes = new ESoundDeviceType[ 4 ]\r
{\r
ESoundDeviceType.ExclusiveWASAPI,\r
}\r
catch ( Exception e )\r
{\r
+ Trace.TraceInformation( e.Message );\r
if ( ESoundDeviceTypes[ n初期デバイス ] == ESoundDeviceType.Unknown )\r
{\r
throw new Exception( string.Format( "サウンドデバイスの初期化に失敗しました。" ) );\r
this.e作成方法 = E作成方法.ファイルから;\r
this.strファイル名 = strファイル名;\r
\r
- if ( String.Compare( Path.GetExtension( strファイル名 ), ".xa", true ) == 0 ) // caselessで文字列比較\r
+ if ( String.Compare( Path.GetExtension( strファイル名 ), ".xa", true ) == 0 ||\r
+ String.Compare( Path.GetExtension( strファイル名 ), ".ogg", true ) == 0 ) // caselessで文字列比較\r
{\r
- tDirectSoundサウンドを作成するXA( strファイル名, DirectSound );\r
+ tDirectSoundサウンドを作成するXAOGG( strファイル名, DirectSound );\r
return;\r
}\r
\r
\r
this.tDirectSoundサウンドを作成する( byArrWAVファイルイメージ, DirectSound );\r
}\r
- public void tDirectSoundサウンドを作成するXA( string strファイル名, DirectSound DirectSound )\r
+ public void tDirectSoundサウンドを作成するXAOGG( string strファイル名, DirectSound DirectSound )\r
{\r
this.e作成方法 = E作成方法.ファイルから;\r
this.strファイル名 = strファイル名;\r
\r
- Cxa xa = new Cxa();\r
- xa.Decode( strファイル名, out this.byArrWAVファイルイメージ );\r
+\r
+\r
+ \r
+// Cxa xa = new Cxa();\r
+// xa.Decode( strファイル名, out this.byArrWAVファイルイメージ );\r
\r
WaveFormat wfx = new WaveFormat();\r
int nPCMデータの先頭インデックス = 0;\r
- int nPCMサイズbyte = (int) ( xa.xaheader.nSamples * xa.xaheader.nChannels * 2 ); // nBytes = Bass.BASS_ChannelGetLength( this.hBassStream );\r
+// int nPCMサイズbyte = (int) ( xa.xaheader.nSamples * xa.xaheader.nChannels * 2 ); // nBytes = Bass.BASS_ChannelGetLength( this.hBassStream );\r
\r
- wfx.AverageBytesPerSecond = (int) xa.waveformatex.nAvgBytesPerSec;\r
- wfx.BitsPerSample = (short) xa.waveformatex.wBitsPerSample;\r
- wfx.BlockAlignment = (short) xa.waveformatex.nBlockAlign;\r
- wfx.Channels = (short) xa.waveformatex.nChannels;\r
+ int nPCMサイズbyte;\r
+ CWin32.WAVEFORMATEX cw32wfx;\r
+ tオンメモリ方式でデコードする( strファイル名, out this.byArrWAVファイルイメージ,\r
+ out nPCMデータの先頭インデックス, out nPCMサイズbyte, out cw32wfx );\r
+\r
+ wfx.AverageBytesPerSecond = (int) cw32wfx.nAvgBytesPerSec;\r
+ wfx.BitsPerSample = (short) cw32wfx.wBitsPerSample;\r
+ wfx.BlockAlignment = (short) cw32wfx.nBlockAlign;\r
+ wfx.Channels = (short) cw32wfx.nChannels;\r
wfx.FormatTag = WaveFormatTag.Pcm; // xa.waveformatex.wFormatTag;\r
- wfx.SamplesPerSecond = (int) xa.waveformatex.nSamplesPerSec;\r
+ wfx.SamplesPerSecond = (int) cw32wfx.nSamplesPerSec;\r
+\r
\r
\r
// セカンダリバッファを作成し、PCMデータを書き込む。\r
\r
// DTXMania用に追加\r
n総演奏時間ms = (int) ( ( (double) nPCMサイズbyte ) / ( this.Buffer.Format.AverageBytesPerSecond * 0.001 ) );\r
+ nBytes = nPCMサイズbyte;\r
\r
// 作成完了。\r
\r
if( this.bBASSサウンドである )\r
{\r
//Debug.WriteLine( "再生中?: " + System.IO.Path.GetFileName(this.strファイル名) + " status=" + BassMix.BASS_Mixer_ChannelIsActive( this.hBassStream ) + " current=" + BassMix.BASS_Mixer_ChannelGetPosition( this.hBassStream ) + " nBytes=" + nBytes );\r
- BassMix.BASS_Mixer_ChannelPlay( this.hBassStream );\r
+ bool b = BassMix.BASS_Mixer_ChannelPlay( this.hBassStream );\r
+ if ( !b )\r
+ {\r
+Debug.WriteLine( "再生しようとしたが、Mixerに登録されていなかった: " + Path.GetFileName( this.strファイル名 ) );\r
+//Debug.WriteLine( "ErrCode= " +Bass.BASS_ErrorGetCode() );\r
+\r
+ bool bb = tBASSサウンドをミキサーに追加する(false);\r
+ if ( !bb )\r
+ {\r
+Debug.WriteLine( "Mixerへの登録に失敗: " + Path.GetFileName( this.strファイル名 ) + ": " + Bass.BASS_ErrorGetCode() );\r
+ }\r
+ else\r
+ {\r
+Debug.WriteLine( "Mixerへの登録に成功: " + Path.GetFileName( this.strファイル名 ) + ": " + Bass.BASS_ErrorGetCode() );\r
+ }\r
+// bool bbb = BassMix.BASS_Mixer_ChannelPlay( this.hBassStream );\r
+// if ( !bbb )\r
+// {\r
+//Debug.WriteLine( "更に再生に失敗 : " + Path.GetFileName( this.strファイル名 ) );\r
+//Debug.WriteLine( "ErrCode= " +Bass.BASS_ErrorGetCode() );\r
+// }\r
+// else\r
+// {\r
+//Debug.WriteLine( "再生成功(ミキサー追加後) : " + Path.GetFileName( this.strファイル名 ) );\r
+// }\r
+ }\r
+ else\r
+ {\r
+Debug.WriteLine( "再生成功 : " + Path.GetFileName( this.strファイル名 ) );\r
+ }\r
}\r
else if( this.bDirectSoundである )\r
{\r
{\r
if( this.bBASSサウンドである )\r
{\r
-//Debug.WriteLine( "停止: " + System.IO.Path.GetFileName( this.strファイル名 ) + " status=" + BassMix.BASS_Mixer_ChannelIsActive( this.hBassStream ) + " current=" + BassMix.BASS_Mixer_ChannelGetPosition( this.hBassStream ) + " nBytes=" + nBytes );\r
+Debug.WriteLine( "停止: " + System.IO.Path.GetFileName( this.strファイル名 ) + " status=" + BassMix.BASS_Mixer_ChannelIsActive( this.hBassStream ) + " current=" + BassMix.BASS_Mixer_ChannelGetPosition( this.hBassStream ) + " nBytes=" + nBytes );\r
BassMix.BASS_Mixer_ChannelPause( this.hBassStream );\r
+\r
+//tBASSサウンドをミキサーから削除する();\r
}\r
else if( this.bDirectSoundである )\r
{\r
protected GCHandle hGC;\r
protected int hBassStream = -1; // ASIO, WASAPI 用\r
protected SecondarySoundBuffer Buffer = null; // DirectSound 用\r
+ protected int hMixer = -1; // 設計壊してゴメン Mixerに後で登録するときに使う\r
//-----------------\r
#endregion\r
\r
nBytes = Bass.BASS_ChannelGetLength( this.hBassStream );\r
double seconds = Bass.BASS_ChannelBytes2Seconds( this.hBassStream, nBytes );\r
this.n総演奏時間ms = (int) ( seconds * 1000 );\r
+ this.pos = 0;\r
+ this.hMixer = hMixer;\r
}\r
private void tBASSサウンドを作成する( byte[] byArrWAVファイルイメージ, int hMixer, BASSFlag flags )\r
{\r
nBytes = Bass.BASS_ChannelGetLength( this.hBassStream );\r
double seconds = Bass.BASS_ChannelBytes2Seconds( this.hBassStream, nBytes );\r
this.n総演奏時間ms = (int) ( seconds * 1000 );\r
+ this.pos = 0;\r
+ this.hMixer = hMixer;\r
}\r
private void tBASSサウンドを作成するXA( string strファイル名, int hMixer, BASSFlag flags )\r
{\r
- Cxa xa = new Cxa();\r
- xa.Decode( strファイル名, out this.byArrWAVファイルイメージ );\r
+ int nPCMデータの先頭インデックス;\r
+ CWin32.WAVEFORMATEX wfx;\r
+ int totalPCMSize;\r
+\r
+ tオンメモリ方式でデコードする( strファイル名, out this.byArrWAVファイルイメージ,\r
+ out nPCMデータの先頭インデックス, out totalPCMSize, out wfx );\r
+\r
+ nBytes = totalPCMSize;\r
\r
this.e作成方法 = E作成方法.WAVファイルイメージから;\r
+ this.strファイル名 = strファイル名; \r
this.hGC = GCHandle.Alloc( this.byArrWAVファイルイメージ, GCHandleType.Pinned ); // byte[] をピン留め\r
\r
\r
\r
// BASSファイルストリームを作成。\r
\r
- this.hBassStream = Bass.BASS_StreamCreate( xa.xaheader.nSamplesPerSec, xa.xaheader.nChannels, BASSFlag.BASS_STREAM_DECODE, _myStreamCreate, IntPtr.Zero );\r
+ //this.hBassStream = Bass.BASS_StreamCreate( xa.xaheader.nSamplesPerSec, xa.xaheader.nChannels, BASSFlag.BASS_STREAM_DECODE, _myStreamCreate, IntPtr.Zero );\r
+ this.hBassStream = Bass.BASS_StreamCreate( (int)wfx.nSamplesPerSec, (int)wfx.nChannels, BASSFlag.BASS_STREAM_DECODE, _myStreamCreate, IntPtr.Zero );\r
if ( this.hBassStream == 0 )\r
{\r
hGC.Free();\r
BASSError err = Bass.BASS_ErrorGetCode();\r
-Debug.WriteLine( "BASS_SampleCreate: " + err );\r
throw new Exception( "サウンドストリームの生成に失敗しました。(BASS_SampleCreate: " + err + ")" );\r
}\r
\r
// ミキサーにBASSファイルストリームを追加。\r
\r
- BassMix.BASS_Mixer_StreamAddChannel( hMixer, this.hBassStream, BASSFlag.BASS_SPEAKER_FRONT | BASSFlag.BASS_MIXER_PAUSE | BASSFlag.BASS_MIXER_NORAMPIN );\r
-\r
+ bool b = BassMix.BASS_Mixer_StreamAddChannel( hMixer, this.hBassStream, BASSFlag.BASS_SPEAKER_FRONT | BASSFlag.BASS_MIXER_PAUSE | BASSFlag.BASS_MIXER_NORAMPIN );\r
+ if ( !b )\r
+ {\r
+ hGC.Free();\r
+ BASSError err = Bass.BASS_ErrorGetCode();\r
+ throw new Exception( "サウンドストリームの生成に失敗しました。(BASS_Mixer_StreamAddChannel: " + err + ")" );\r
+ }\r
// インスタンスリストに登録。\r
\r
CSound.listインスタンス.Add( this );\r
\r
// nBytesとn総演奏時間の取得; DTXMania用に追加。\r
- nBytes = (int) ( xa.xaheader.nSamples * xa.xaheader.nChannels * 2 ); // nBytes = Bass.BASS_ChannelGetLength( this.hBassStream );\r
+ //nBytes = (int) ( xa.xaheader.nSamples * xa.xaheader.nChannels * 2 ); // nBytes = Bass.BASS_ChannelGetLength( this.hBassStream );\r
+ //nBytes = Bass.BASS_ChannelGetLength( this.hBassStream );\r
+ //if ( nBytes < 0 )\r
+ //{\r
+ // hGC.Free();\r
+ // BASSError err = Bass.BASS_ErrorGetCode();\r
+ // throw new Exception( "サウンドストリームの生成に失敗しました。(BASS_ChannelGetLength: " + err + ")" );\r
+ //}\r
+ //nBytes = (int) this.byArrWAVファイルイメージ.Length;\r
+\r
double seconds = Bass.BASS_ChannelBytes2Seconds( this.hBassStream, nBytes );\r
this.n総演奏時間ms = (int) ( seconds * 1000 );\r
+ this.pos = 0;\r
+ this.hMixer = hMixer;\r
}\r
//-----------------\r
\r
}\r
return bytesread;\r
}\r
+\r
+\r
+ public bool tBASSサウンドをミキサーに追加する()\r
+ {\r
+ return tBASSサウンドをミキサーに追加する( true );\r
+ }\r
+ \r
+ /// <summary>\r
+ /// \r
+ /// </summary>\r
+ /// <param name="pause">falseなら、追加と同時に再生する</param>\r
+ /// <returns></returns>\r
+ public bool tBASSサウンドをミキサーに追加する( bool pause )\r
+ {\r
+ BASSFlag bf = BASSFlag.BASS_SPEAKER_FRONT | BASSFlag.BASS_MIXER_NORAMPIN;\r
+ if ( pause )\r
+ {\r
+ bf |= BASSFlag.BASS_MIXER_PAUSE;\r
+ }\r
+ return BassMix.BASS_Mixer_StreamAddChannel( this.hMixer, this.hBassStream, bf );\r
+ }\r
+ public bool tBASSサウンドをミキサーから削除する()\r
+ {\r
+ return BassMix.BASS_Mixer_ChannelRemove( this.hBassStream );\r
+ }\r
+\r
+\r
+ public void tオンメモリ方式でデコードする( string strファイル名, out byte[] buffer,\r
+ out int nPCMデータの先頭インデックス, out int totalPCMSize, out CWin32.WAVEFORMATEX wfx )\r
+ {\r
+ nPCMデータの先頭インデックス = 0;\r
+ //int nPCMサイズbyte = (int) ( xa.xaheader.nSamples * xa.xaheader.nChannels * 2 ); // nBytes = Bass.BASS_ChannelGetLength( this.hBassStream );\r
+\r
+ SoundDecoder sounddecoder;\r
+\r
+ if ( String.Compare( Path.GetExtension( strファイル名 ), ".xa", true ) == 0 )\r
+ {\r
+ sounddecoder = new Cxa();\r
+ }\r
+ else if ( String.Compare( Path.GetExtension( strファイル名 ), ".ogg", true ) == 0 )\r
+ {\r
+ sounddecoder = new Cogg();\r
+ }\r
+ else\r
+ {\r
+ throw new NotImplementedException();\r
+ }\r
+\r
+ int nHandle = sounddecoder.Open( strファイル名 );\r
+ if ( nHandle < 0 )\r
+ {\r
+ throw new Exception( string.Format( "Open() に失敗しました。({0})({1})", nHandle, strファイル名 ) );\r
+ }\r
+ wfx = new CWin32.WAVEFORMATEX();\r
+ if ( sounddecoder.GetFormat( nHandle, ref wfx ) < 0 )\r
+ {\r
+ sounddecoder.Close( nHandle );\r
+ throw new Exception( string.Format( "GetFormat() に失敗しました。({0})", strファイル名 ) );\r
+ }\r
+ //totalPCMSize = (int) sounddecoder.nTotalPCMSize; // tデコード後のサイズを調べる()で既に取得済みの値を流用する。ms単位の高速化だが、チップ音がたくさんあると塵積で結構効果がある\r
+ totalPCMSize = (int) sounddecoder.GetTotalPCMSize( nHandle );\r
+ if ( totalPCMSize == 0 )\r
+ {\r
+ sounddecoder.Close( nHandle );\r
+ throw new Exception( string.Format( "GetTotalPCMSize() に失敗しました。({0})", strファイル名 ) );\r
+ }\r
+ totalPCMSize += ( ( totalPCMSize % 2 ) != 0 ) ? 1 : 0;\r
+ buffer = new byte[ totalPCMSize ];\r
+ GCHandle handle = GCHandle.Alloc( buffer, GCHandleType.Pinned );\r
+ try\r
+ {\r
+ if ( sounddecoder.Decode( nHandle, handle.AddrOfPinnedObject(), (uint) totalPCMSize, 0 ) < 0 )\r
+ {\r
+ buffer = null;\r
+ throw new Exception( string.Format( "デコードに失敗しました。({0})", strファイル名 ) );\r
+ }\r
+ }\r
+ finally\r
+ {\r
+ handle.Free();\r
+ sounddecoder.Close( nHandle );\r
+ }\r
+ sounddecoder = null;\r
+ }\r
+\r
#endregion\r
}\r
}\r
// ASIO 出力チャンネルの初期化。\r
\r
this.tAsioProc = new ASIOPROC( this.tAsio処理 ); // アンマネージに渡す delegate は、フィールドとして保持しておかないとGCでアドレスが変わってしまう。\r
- BassAsio.BASS_ASIO_ChannelEnable( false, 0, this.tAsioProc, IntPtr.Zero ); // 出力チャンネル0 の有効化。\r
+ if ( !BassAsio.BASS_ASIO_ChannelEnable( false, 0, this.tAsioProc, IntPtr.Zero ) ) // 出力チャンネル0 の有効化。\r
+ {\r
+ #region [ ASIO 出力チャンネルの初期化に失敗。]\r
+ //-----------------\r
+ Bass.BASS_Free();\r
+ throw new Exception( string.Format( "Failed BASS_ASIO_ChannelEnable() [{0}]", BassAsio.BASS_ASIO_ErrorGetCode().ToString() ) );\r
+ //-----------------\r
+ #endregion\r
+ }\r
//for( int i = 1; i < this.n出力チャンネル数; i++ )\r
// BassAsio.BASS_ASIO_ChannelJoin( false, i, 0 );\r
- BassAsio.BASS_ASIO_ChannelJoin( false, 1, 0 ); // 出力チャンネル1をチャンネル0 とグループ化。(ステレオ限定)\r
- BassAsio.BASS_ASIO_ChannelSetFormat( false, 0, this.fmtASIOチャンネルフォーマット ); // 出力チャンネル0のフォーマット\r
+ if (!BassAsio.BASS_ASIO_ChannelJoin( false, 1, 0 )) // 出力チャンネル1をチャンネル0 とグループ化。(ステレオ限定)\r
+ {\r
+ #region [ 初期化に失敗。]\r
+ //-----------------\r
+ Bass.BASS_Free();\r
+ throw new Exception( string.Format( "Failed BASS_ASIO_ChannelJoin() [{0}]", BassAsio.BASS_ASIO_ErrorGetCode().ToString() ) );\r
+ //-----------------\r
+ #endregion\r
+ }\r
+ if ( !BassAsio.BASS_ASIO_ChannelSetFormat( false, 0, this.fmtASIOチャンネルフォーマット ) ) // 出力チャンネル0のフォーマット\r
+ {\r
+ #region [ ASIO 出力チャンネルの初期化に失敗。]\r
+ //-----------------\r
+ Bass.BASS_Free();\r
+ throw new Exception( string.Format( "Failed BASS_ASIO_ChannelSetFormat() [{0}]", BassAsio.BASS_ASIO_ErrorGetCode().ToString() ) );\r
+ //-----------------\r
+ #endregion\r
+ }\r
\r
\r
// ASIO 出力と同じフォーマットを持つ BASS ミキサーを作成。\r
// 出力を開始。\r
\r
this.nバッファサイズsample = (int) ( nバッファサイズms * this.db周波数 / 1000.0 );\r
- BassAsio.BASS_ASIO_Start( this.nバッファサイズsample ); // 範囲外の値を指定した場合は自動的にデフォルト値に設定される。\r
-\r
- int n遅延sample = BassAsio.BASS_ASIO_GetLatency( false ); // この関数は BASS_ASIO_Start() 後にしか呼び出せない。\r
- this.n実出力遅延ms = (long) ( n遅延sample * 1000.0f / this.db周波数 );\r
- Trace.TraceInformation( "ASIO デバイス出力開始:バッファ{0}sample [{1}ms(希望{2}ms)]", n遅延sample, this.n実出力遅延ms, nバッファサイズms );\r
+ if ( !BassAsio.BASS_ASIO_Start( this.nバッファサイズsample ) ) // 範囲外の値を指定した場合は自動的にデフォルト値に設定される。\r
+ {\r
+ Bass.BASS_Free();\r
+ throw new Exception( "ASIO デバイス出力開始に失敗しました。" + BassAsio.BASS_ASIO_ErrorGetCode().ToString() );\r
+ }\r
+ else\r
+ {\r
+ int n遅延sample = BassAsio.BASS_ASIO_GetLatency( false ); // この関数は BASS_ASIO_Start() 後にしか呼び出せない。\r
+ this.n実出力遅延ms = (long) ( n遅延sample * 1000.0f / this.db周波数 );\r
+ Trace.TraceInformation( "ASIO デバイス出力開始:バッファ{0}sample [{1}ms(希望{2}ms)]", n遅延sample, this.n実出力遅延ms, nバッファサイズms );\r
+ }\r
}\r
\r
public CSound tサウンドを作成する( string strファイル名 )\r
--- /dev/null
+using System;\r
+using System.Collections.Generic;\r
+using System.Text;\r
+using System.Runtime.InteropServices;\r
+using System.IO;\r
+using System.Diagnostics;\r
+using System.Threading;\r
+\r
+\r
+namespace FDK\r
+{\r
+ public unsafe class Cogg : SoundDecoder\r
+ {\r
+ static byte[] FOURCC = Encoding.ASCII.GetBytes( "SggO" ); // OggS の little endian\r
+\r
+\r
+ #region [ SoundDecoder.dll インポート(ogg 関連)]\r
+ //-----------------\r
+ [DllImport( "SoundDecoder.dll" )]\r
+ private static extern void oggClose( int nHandle );\r
+ [DllImport( "SoundDecoder.dll" )]\r
+ private static extern int oggDecode( int nHandle, IntPtr pDest, uint szDestSize, int bLoop );\r
+ [DllImport( "SoundDecoder.dll" )]\r
+ private static extern int oggGetFormat( int nHandle, ref CWin32.WAVEFORMATEX wfx );\r
+ [DllImport( "SoundDecoder.dll" )]\r
+ private static extern uint oggGetTotalPCMSize( int nHandle );\r
+ [DllImport( "SoundDecoder.dll" )]\r
+ private static extern int oggOpen( string fileName );\r
+ [DllImport( "SoundDecoder.dll" )]\r
+ private static extern int oggSeek( int nHandle, uint dwPosition );\r
+ //-----------------\r
+ #endregion\r
+\r
+\r
+ public override int Open( string filename )\r
+ {\r
+ return oggOpen( filename );\r
+ }\r
+ public override int GetFormat( int nHandle, ref CWin32.WAVEFORMATEX wfx )\r
+ {\r
+ return oggGetFormat( nHandle, ref wfx );\r
+ }\r
+ public override uint GetTotalPCMSize( int nHandle )\r
+ {\r
+ return oggGetTotalPCMSize( nHandle );\r
+ }\r
+ public override int Seek( int nHandle, uint dwPosition )\r
+ {\r
+ return oggSeek( nHandle, dwPosition );\r
+ }\r
+ public override int Decode( int nHandle, IntPtr pDest, uint szDestSize, int bLoop )\r
+ {\r
+ return oggDecode( nHandle, pDest, szDestSize, bLoop );\r
+ }\r
+\r
+ public override void Close( int nHandle )\r
+ {\r
+ oggClose( nHandle );\r
+ }\r
+\r
+ }\r
+}\r
\r
namespace FDK\r
{\r
- public unsafe class Cxa\r
+ public unsafe class Cxa : SoundDecoder //, IDisposable\r
{\r
- static byte[] _XAID = Encoding.ASCII.GetBytes( "1DWK" ); // KWD1 の little endian\r
+ static byte[] FOURCC = Encoding.ASCII.GetBytes( "1DWK" ); // KWD1 の little endian\r
\r
#region [ XA用構造体の宣言 ]\r
[StructLayout(LayoutKind.Sequential)]\r
public XASTREAMHEADER xastreamheader;\r
public CWin32.WAVEFORMATEX waveformatex;\r
\r
+ private string filename;\r
+ private byte[] srcBuf = null, dstBuf = null;\r
+ private int nHandle = -1;\r
+\r
+ public override int Open( string filename )\r
+ {\r
+ this.filename = filename;\r
+\r
+ #region [ XAヘッダと、XAデータの読み出し ]\r
+ xaheader = new XAHEADER();\r
+ using ( FileStream fs = new FileStream( filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ) ) // FileShare を付けとかないと、Close() 後もロックがかかる??\r
+ {\r
+ using ( BinaryReader br = new BinaryReader( fs ) )\r
+ {\r
+ xaheader.id = br.ReadUInt32();\r
+ xaheader.nDataLen = br.ReadUInt32();\r
+ xaheader.nSamples = br.ReadUInt32();\r
+ xaheader.nSamplesPerSec = br.ReadUInt16();\r
+ xaheader.nBits = br.ReadByte();\r
+ xaheader.nChannels = br.ReadByte();\r
+ xaheader.nLoopPtr = br.ReadUInt32();\r
+\r
+ xaheader.befL = new short[ 2 ];\r
+ xaheader.befR = new short[ 2 ];\r
+ xaheader.pad = new byte[ 4 ];\r
+\r
+ xaheader.befL[ 0 ] = br.ReadInt16();\r
+ xaheader.befL[ 1 ] = br.ReadInt16();\r
+ xaheader.befR[ 0 ] = br.ReadInt16();\r
+ xaheader.befR[ 1 ] = br.ReadInt16();\r
+ xaheader.pad = br.ReadBytes( 4 );\r
+\r
+ srcBuf = new byte[ xaheader.nDataLen ];\r
+ srcBuf = br.ReadBytes( (int) xaheader.nDataLen );\r
+ }\r
+ }\r
+ //string xaid = Encoding.ASCII.GetString( xah.id );\r
+ #region [ デバッグ表示 ]\r
+ //Debug.WriteLine( "**XAHEADER**" );\r
+ //Debug.WriteLine( "id= " + xaheader.id.ToString( "X8" ) );\r
+ //Debug.WriteLine( "nDataLen= " + xaheader.nDataLen.ToString( "X8" ) );\r
+ //Debug.WriteLine( "nSamples= " + xaheader.nSamples.ToString( "X8" ) );\r
+ //Debug.WriteLine( "nSamplesPerSec= " + xaheader.nSamplesPerSec.ToString( "X4" ) );\r
+ //Debug.WriteLine( "nBits= " + xaheader.nBits.ToString( "X2" ) );\r
+ //Debug.WriteLine( "nChannels= " + xaheader.nChannels.ToString( "X2" ) );\r
+ //Debug.WriteLine( "nLoopPtr= " + xaheader.nLoopPtr.ToString( "X8" ) );\r
+ //Debug.WriteLine( "befL[0]= " + xaheader.befL[ 0 ].ToString( "X4" ) );\r
+ //Debug.WriteLine( "befL[1]= " + xaheader.befL[ 1 ].ToString( "X4" ) );\r
+ //Debug.WriteLine( "befR[0]= " + xaheader.befR[ 0 ].ToString( "X4" ) );\r
+ //Debug.WriteLine( "befR[1]= " + xaheader.befR[ 1 ].ToString( "X4" ) );\r
+ #endregion\r
+ #endregion\r
+\r
+ IntPtr hxas;\r
+\r
+ #region [ WAVEFORMEX情報の取得 ]\r
+ waveformatex = new CWin32.WAVEFORMATEX();\r
+ hxas = xaDecodeOpen( ref xaheader, out waveformatex );\r
+ if ( hxas == null )\r
+ {\r
+ Trace.TraceError( "Error: xa: Open(): xaDecodeOpen(): " + Path.GetFileName( filename ) );\r
+ dstBuf = null;\r
+ return -1;\r
+ }\r
+\r
+ #region [ デバッグ表示 ]\r
+ //Debug.WriteLine( "**WAVEFORMATEX**" );\r
+ //Debug.WriteLine( "wFormatTag= " + waveformatex.wFormatTag.ToString( "X4" ) );\r
+ //Debug.WriteLine( "nChannels = " + waveformatex.nChannels.ToString( "X4" ) );\r
+ //Debug.WriteLine( "nSamplesPerSec= " + waveformatex.nSamplesPerSec.ToString( "X8" ) );\r
+ //Debug.WriteLine( "nAvgBytesPerSec= " + waveformatex.nAvgBytesPerSec.ToString( "X8" ) );\r
+ //Debug.WriteLine( "nBlockAlign= " + waveformatex.nBlockAlign.ToString( "X4" ) );\r
+ //Debug.WriteLine( "wBitsPerSample= " + waveformatex.wBitsPerSample.ToString( "X4" ) );\r
+ //Debug.WriteLine( "cbSize= " + waveformatex.cbSize.ToString( "X4" ) );\r
+ #endregion\r
+ #endregion\r
+\r
+ this.nHandle = (int) hxas;\r
+ return (int) hxas;\r
+ }\r
+ public override int GetFormat( int nHandle, ref CWin32.WAVEFORMATEX wfx )\r
+ {\r
+ #region [ WAVEFORMATEX構造体の手動コピー ]\r
+ wfx.nAvgBytesPerSec = waveformatex.nAvgBytesPerSec;\r
+ wfx.wBitsPerSample = waveformatex.wBitsPerSample;\r
+ wfx.nBlockAlign = waveformatex.nBlockAlign;\r
+ wfx.nChannels = waveformatex.nChannels;\r
+ wfx.wFormatTag = waveformatex.wFormatTag;\r
+ wfx.nSamplesPerSec = waveformatex.nSamplesPerSec;\r
+\r
+ return 0;\r
+ #endregion\r
+ }\r
+ public override uint GetTotalPCMSize( int nHandle )\r
+ {\r
+ #region [ データ長の取得 ]\r
+ uint dlen;\r
+ xaDecodeSize( (IntPtr) nHandle, xaheader.nDataLen, out dlen );\r
+ #region [ デバッグ表示 ]\r
+ //Debug.WriteLine( "**INTERNAL VALUE**" );\r
+ //Debug.WriteLine( "dlen= " + dlen );\r
+ #endregion\r
+ #endregion\r
+\r
+ return dlen;\r
+ }\r
+ public override int Seek( int nHandle, uint dwPosition )\r
+ {\r
+ return 0;\r
+ }\r
+ public override int Decode( int nHandle, IntPtr pDest, uint szDestSize, int bLoop )\r
+ {\r
+ #region [ xaデータのデコード ]\r
+ xastreamheader = new XASTREAMHEADER();\r
+ bool b;\r
+ unsafe\r
+ {\r
+ fixed ( byte* pXaBuf = srcBuf )\r
+ {\r
+ byte* pWavBuf = (byte*) pDest;\r
+\r
+ xastreamheader.pSrc = pXaBuf;\r
+ xastreamheader.nSrcLen = xaheader.nDataLen;\r
+ xastreamheader.nSrcUsed = 0;\r
+ xastreamheader.pDst = pWavBuf;\r
+ xastreamheader.nDstLen = szDestSize;\r
+ xastreamheader.nDstUsed = 0;\r
+ b = xaDecodeConvert( (IntPtr) nHandle, ref xastreamheader );\r
+ if ( !b )\r
+ {\r
+ Trace.TraceError( "Error: xaDecodeConvert(): " + Path.GetFileName( filename ) );\r
+ dstBuf = null;\r
+ return -1;\r
+ }\r
+ }\r
+ }\r
+ #region [ デバッグ表示 ]\r
+ //Debug.WriteLine( "**XASTREAMHEADER**" );\r
+ //Debug.WriteLine( "nSrcLen= " + xastreamheader.nSrcLen );\r
+ //Debug.WriteLine( "nSrcUsed= " + xastreamheader.nSrcUsed );\r
+ //Debug.WriteLine( "nDstLen= " + xastreamheader.nDstLen );\r
+ //Debug.WriteLine( "nDstUsed= " + xastreamheader.nDstUsed );\r
+ #endregion\r
+ #endregion\r
+\r
+ return b? 0 : -1;\r
+ }\r
+\r
+ public override void Close( int nHandle )\r
+ {\r
+ #region [ xaファイルのクローズ ]\r
+ bool bb = xaDecodeClose( (IntPtr) nHandle );\r
+ if ( !bb )\r
+ {\r
+ Trace.TraceError( "Error: xaDecodeClose(): " + Path.GetFileName( filename ) );\r
+ }\r
+ #endregion\r
+ }\r
+\r
+\r
+\r
+ //#region [ IDisposable 実装 ]\r
+ ////-----------------\r
+ //private bool bDispose完了済み = false;\r
+ //public void Dispose()\r
+ //{\r
+ // if ( !this.bDispose完了済み )\r
+ // {\r
+ // if ( srcBuf != null )\r
+ // {\r
+ // srcBuf = null;\r
+ // }\r
+ // if ( dstBuf != null )\r
+ // {\r
+ // dstBuf = null;\r
+ // }\r
+\r
+ // if ( this.nHandle >= 0 )\r
+ // {\r
+ // this.Close( this.nHandle );\r
+ // this.nHandle = -1;\r
+ // }\r
+ // this.bDispose完了済み = true;\r
+ // }\r
+ //}\r
+ ////-----------------\r
+ //#endregion\r
+\r
+#if false\r
/// <summary>\r
/// xaファイルを読み込んで、wavにdecodeする\r
/// </summary>\r
\r
return true;\r
}\r
+#endif\r
}\r
}\r
--- /dev/null
+using System;\r
+using System.Collections.Generic;\r
+using System.Text;\r
+using System.Diagnostics;\r
+\r
+namespace FDK\r
+{\r
+ /// <summary>\r
+ /// xa,oggデコード用の基底クラス\r
+ /// </summary>\r
+ public abstract class SoundDecoder //: IDisposable\r
+ {\r
+ public abstract int Open( string filename );\r
+ public abstract int GetFormat( int nHandle, ref CWin32.WAVEFORMATEX wfx );\r
+ public abstract uint GetTotalPCMSize( int nHandle );\r
+ public abstract int Seek( int nHandle, uint dwPosition );\r
+ public abstract int Decode( int nHandle, IntPtr pDest, uint szDestSize, int bLoop );\r
+ public abstract void Close( int nHandle );\r
+ }\r
+}\r