}
}
- /// <summary>
- /// デバッグ用
- /// </summary>
- public void tWaveBGM再生位置表示()
- {
- foreach ( CWAV wc in this.listWAV.Values )
- {
- if ( wc.rSound[ 0 ] != null && wc.rSound[ 0 ].n総演奏時間ms >= 5000 )
- {
- for ( int i = 0; i < nPolyphonicSounds; i++ )
- {
- if ( ( wc.rSound[ i ] != null ) && ( wc.rSound[ i ].b再生中 ) )
- {
- long n位置byte;
- double db位置ms;
- wc.rSound[ i ].t再生位置を取得する( out n位置byte, out db位置ms );
- Trace.TraceInformation( "再生位置: {0}, seek先={1}ms / {2}byte, 全音長={3}ms",
- Path.GetFileName( wc.rSound[ 0 ].strファイル名 ),
- db位置ms, n位置byte,
- wc.rSound[ 0 ].n総演奏時間ms
- );
- }
- }
- }
- }
- }
-
public void tWavの再生停止( int nWaveの内部番号 )
{
tWavの再生停止( nWaveの内部番号, false );
string str = string.IsNullOrEmpty(this.PATH_WAV) ? this.strフォルダ名 : this.PATH_WAV;
str = str + cwav.strファイル名;
- bool bIsDirectSound = ( CDTXMania.Sound管理.GetCurrentSoundDeviceType() == "DirectSound" );
+ bool bIsDirectSound = ( CDTXMania.Sound管理.GetCurrentSoundDeviceType() == ESoundDeviceType.DirectSound );
try
{
//try
#region [ 同時発音数を、チャンネルによって変える ]
int nPoly = nPolyphonicSounds;
- if ( CDTXMania.Sound管理.GetCurrentSoundDeviceType() != "DirectSound" ) // DShowでの再生の場合はミキシング負荷が高くないため、
+ if ( CDTXMania.Sound管理.GetCurrentSoundDeviceType() != ESoundDeviceType.DirectSound ) // DShowでの再生の場合はミキシング負荷が高くないため、
{ // チップのライフタイム管理を行わない
if ( cwav.bIsBassSound ) nPoly = (nPolyphonicSounds >= 2)? 2 : 1;
else if ( cwav.bIsGuitarSound ) nPoly = (nPolyphonicSounds >= 2)? 2 : 1;
else if ( cwav.bIsBGMSound) nPoly = 1;
}
if ( cwav.bIsBGMSound ) nPoly = 1;
- #endregion
+ #endregion
- // 残りはClone等で登録する
- //if ( bIsDirectSound ) // DShowでの再生の場合はCloneする
- //{
- // for ( int i = 1; i < nPoly; i++ )
- // {
- // cwav.rSound[ i ] = (CSound) cwav.rSound[ 0 ].Clone(); // #24007 2011.9.5 yyagi add: to accelerate loading chip sounds
- // // CDTXMania.Sound管理.tサウンドを登録する( cwav.rSound[ j ] );
- // }
- // for ( int i = nPoly; i < nPolyphonicSounds; i++ )
- // {
- // cwav.rSound[ i ] = null;
- // }
- //}
- //else // WASAPI/ASIO時は通常通り登録
- {
- for ( int i = 1; i < nPoly; i++ )
+ // 残りはClone等で登録する
+ if ( bIsDirectSound ) // DShowでの再生の場合はCloneする
+ {
+ for ( int i = 1; i < nPoly; i++ )
+ {
+ cwav.rSound[ i ] = (CSound) cwav.rSound[ 0 ].Clone(); // #24007 2011.9.5 yyagi add: to accelerate loading chip sounds
+ // CDTXMania.Sound管理.tサウンドを登録する( cwav.rSound[ j ] );
+ }
+ for ( int i = nPoly; i < nPolyphonicSounds; i++ )
+ {
+ cwav.rSound[ i ] = null;
+ }
+ }
+ else // WASAPI/ASIO時は通常通り登録
+ {
+ for ( int i = 1; i < nPoly; i++ )
{
try
{
/// </summary>
public void PlanToAddMixerChannel()
{
- if ( CDTXMania.Sound管理.GetCurrentSoundDeviceType() == "DirectSound" ) // DShowでの再生の場合はミキシング負荷が高くないため、
+ if ( CDTXMania.Sound管理.GetCurrentSoundDeviceType() == ESoundDeviceType.DirectSound ) // DShowでの再生の場合はミキシング負荷が高くないため、
{ // チップのライフタイム管理を行わない
return;
}
CDTXMania.Skin.tRemoveMixerAll(); // 効果音のストリームをミキサーから解除しておく
queueMixerSound = new Queue<stmixer>( 64 );
- bIsDirectSound = ( CDTXMania.Sound管理.GetCurrentSoundDeviceType() == "DirectSound" );
+ bIsDirectSound = ( CDTXMania.Sound管理.GetCurrentSoundDeviceType() == ESoundDeviceType.DirectSound );
bUseOSTimer = CDTXMania.ConfigIni.bUseOSTimer;
this.bPAUSE = false;
if ( CDTXMania.DTXVmode.Enabled )
#if !GPUFlushAfterPresent
actFlushGPU.On進行描画(); // Flush GPU // EndScene()~Present()間 (つまりVSync前) でFlush実行
#endif
- if ( Sound管理.GetCurrentSoundDeviceType() != "DirectSound" )
+ if ( Sound管理.GetCurrentSoundDeviceType() != ESoundDeviceType.DirectSound )
{
Sound管理.t再生中の処理をする(); // サウンドバッファの更新; 画面描画と同期させることで、スクロールをスムーズにする
}
);
//Sound管理 = FDK.CSound管理.Instance;
//Sound管理.t初期化( soundDeviceType, 0, 0, CDTXMania.ConfigIni.nASIODevice, base.Window.Handle );
+
ShowWindowTitleWithSoundType();
FDK.CSound管理.bIsTimeStretch = CDTXMania.ConfigIni.bTimeStretch;
public void ShowWindowTitleWithSoundType()
{
string delay = "";
- if ( Sound管理.GetCurrentSoundDeviceType() != "DirectSound" )
+ if ( Sound管理.GetCurrentSoundDeviceType() != ESoundDeviceType.DirectSound )
{
delay = "(" + Sound管理.GetSoundDelay() + "ms)";
}
- base.Window.Text = strWindowTitle + " (" + Sound管理.GetCurrentSoundDeviceType() + delay + ")";
+ base.Window.Text = strWindowTitle + " (" + Sound管理.GetCurrentSoundDeviceType().ToString() + delay + ")";
}
private void t終了処理()
public void tRemoveMixer()
{
- if ( CDTXMania.Sound管理.GetCurrentSoundDeviceType() != "DirectShow" )
+ if ( CDTXMania.Sound管理.GetCurrentSoundDeviceType() != ESoundDeviceType.DirectSound )
{
for ( int i = 0; i < 2; i++ )
{
{
get
{
- //プラットフォームの取得
- System.OperatingSystem os = System.Environment.OSVersion;
- if ( os.Platform != PlatformID.Win32NT ) // NT系でなければ、XP以前か、PC Windows系以外のOSのため、Vista以降ではない。よってfalseを返す。
- {
- return false;
- }
+ return bCheckOSVersion(6, 0);
+ }
+ }
+ /// <summary>
+ /// OSがVista以前ならfalse, Win7以降ならtrueを返す
+ /// </summary>
+ /// <returns></returns>
+ public static bool bIsWin7OrLater
+ {
+ get
+ {
+ return bCheckOSVersion(6, 1);
+ }
+ }
+ /// <summary>
+ /// OSがWin7以前ならfalse, Win8以降ならtrueを返す
+ /// </summary>
+ /// <returns></returns>
+ public static bool bIsWin8OrLater
+ {
+ get
+ {
+ return bCheckOSVersion(6, 2);
+ }
+ }
+ /// <summary>
+ /// OSがWin8.1以前ならfalse, Win10以降ならtrueを返す
+ /// </summary>
+ /// <returns></returns>
+ public static bool bIsWin10OrLater
+ {
+ get
+ {
+ return bCheckOSVersion(10, 0);
+ }
+ }
+
- if ( os.Version.Major >= 6 )
- {
- return true;
- }
- else
- {
- return false;
- }
+ /// <summary>
+ /// 指定のOSバージョン以上であればtrueを返す
+ /// </summary>
+ private static bool bCheckOSVersion(int major, int minor)
+ {
+ //プラットフォームの取得
+ System.OperatingSystem os = System.Environment.OSVersion;
+ if (os.Platform != PlatformID.Win32NT) // NT系でなければ、XP以前か、PC Windows系以外のOS。
+ {
+ return false;
+ }
+
+ if (os.Version.Major >= major && os.Version.Minor >= minor)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
}
}
}
{
return _nMasterVolume;
}
- //get
- //{
- // if ( SoundDeviceType == ESoundDeviceType.ExclusiveWASAPI || SoundDeviceType == ESoundDeviceType.ASIO )
- // {
- // return Bass.BASS_GetConfig(BASSConfig.BASS_CONFIG_GVOL_STREAM ) / 100;
- // }
- // else
- // {
- // return 100;
- // }
- //}
- //set
- //{
- // if ( SoundDeviceType == ESoundDeviceType.ExclusiveWASAPI )
- // {
- // // LINEARでなくWINDOWS(2)を使う必要があるが、exclusive時は使用不可、またデバイス側が対応してないと使用不可
- // bool b = BassWasapi.BASS_WASAPI_SetVolume( BASSWASAPIVolume.BASS_WASAPI_CURVE_LINEAR, value / 100.0f );
- // if ( !b )
- // {
- // BASSError be = Bass.BASS_ErrorGetCode();
- // Trace.TraceInformation( "WASAPI Master Volume Set Error: " + be.ToString() );
- // }
- // }
- //}
- //set
- //{
- // if ( SoundDeviceType == ESoundDeviceType.ExclusiveWASAPI || SoundDeviceType == ESoundDeviceType.ASIO )
- // {
- // bool b = Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_GVOL_STREAM, value * 100 );
- // if ( !b )
- // {
- // BASSError be = Bass.BASS_ErrorGetCode();
- // Trace.TraceInformation( "Master Volume Set Error: " + be.ToString() );
- // }
- // }
- //}
- //set
- //{
- // if ( SoundDeviceType == ESoundDeviceType.ExclusiveWASAPI || SoundDeviceType == ESoundDeviceType.ASIO )
- // {
- // var nodes = new BASS_MIXER_NODE[ 1 ] { new BASS_MIXER_NODE( 0, (float) value ) };
- // BassMix.BASS_Mixer_ChannelSetEnvelope( SoundDevice.hMixer, BASSMIXEnvelope.BASS_MIXER_ENV_VOL, nodes );
- // }
- //}
set
{
SoundDevice.nMasterVolume = value;
return f;
}
- public string GetCurrentSoundDeviceType()
+ public ESoundDeviceType GetCurrentSoundDeviceType()
{
- switch ( SoundDeviceType )
- {
- case ESoundDeviceType.ExclusiveWASAPI:
- case ESoundDeviceType.SharedWASAPI:
- return "WASAPI";
- case ESoundDeviceType.ASIO:
- return "ASIO";
- case ESoundDeviceType.DirectSound:
- return "DirectSound";
- default:
- return "Unknown";
- }
+ return SoundDeviceType;
}
public void AddMixer( CSound cs, double db再生速度, bool _b演奏終了後も再生が続くチップである )
CSound clone = (CSound) MemberwiseClone(); // これだけだとCY連打が途切れる&タイトルに戻る際にNullRef例外発生
this.DirectSound.DuplicateSoundBuffer( this.Buffer, out clone.Buffer );
- // CSound.listインスタンス.Add( this ); // インスタンスリストに登録。
- // 本来これを加えるべきだが、Add後Removeできなくなっている。Clone()の仕方の問題であろう。
+ CSound.listインスタンス.Add( clone ); // インスタンスリストに登録。
return clone;
}
{
this.e作成方法 = E作成方法.ファイルから;
this.strファイル名 = strファイル名;
+
if ( String.Compare( Path.GetExtension( strファイル名 ), ".xa", true ) == 0 ||
String.Compare( Path.GetExtension( strファイル名 ), ".mp3", true ) == 0 ||
String.Compare( Path.GetExtension( strファイル名 ), ".ogg", true ) == 0 ) // caselessで文字列比較
}
public void t再生位置を変更する( long n位置ms )
{
- if( this.bBASSサウンドである )
+ if ( this.bBASSサウンドである )
{
bool b = true;
try
{
b = BassMix.BASS_Mixer_ChannelSetPosition( this.hBassStream, Bass.BASS_ChannelSeconds2Bytes( this.hBassStream, n位置ms * this.db周波数倍率 * this.db再生速度 / 1000.0 ), BASSMode.BASS_POS_BYTES );
}
- catch( Exception e )
+ catch ( Exception e )
{
- Trace.TraceInformation( Path.GetFileName( this.strファイル名 ) + ": Seek error: " + e.ToString() + ": " + n位置ms + "ms" );
+ Trace.TraceInformation( Path.GetFileName( this.strファイル名 ) + ": Seek error: " + e.ToString() );
}
finally
{
if ( !b )
{
BASSError be = Bass.BASS_ErrorGetCode();
- Trace.TraceInformation( Path.GetFileName( this.strファイル名 ) + ": Seek error: " + be.ToString() + ": " + n位置ms + "MS" );
+ Trace.TraceInformation( Path.GetFileName( this.strファイル名 ) + ": Seek error: " + be.ToString() );
}
}
- //if ( this.n総演奏時間ms > 5000 )
- //{
- // Trace.TraceInformation( Path.GetFileName( this.strファイル名 ) + ": Seeked to " + n位置ms + "ms = " + Bass.BASS_ChannelSeconds2Bytes( this.hBassStream, n位置ms * this.db周波数倍率 * this.db再生速度 / 1000.0 ) );
- //}
}
else if( this.bDirectSoundである )
{
{
Trace.TraceError( "{0}: Seek error: {1}", Path.GetFileName( this.strファイル名 ), n位置ms, e.Message );
}
- //if ( this.n総演奏時間ms > 5000 )
- //{
- // Trace.TraceInformation( Path.GetFileName( this.strファイル名 ) + ": Seeked to " + n位置ms + "ms = " + n位置sample );
- //}
}
}
- /// <summary>
- /// デバッグ用
- /// </summary>
- /// <param name="n位置byte"></param>
- /// <param name="db位置ms"></param>
- public void t再生位置を取得する( out long n位置byte, out double db位置ms )
- {
- if ( this.bBASSサウンドである )
- {
- n位置byte = BassMix.BASS_Mixer_ChannelGetPosition( this.hBassStream );
- db位置ms = Bass.BASS_ChannelBytes2Seconds( this.hBassStream, n位置byte );
- }
- else if ( this.bDirectSoundである )
- {
- n位置byte = this.Buffer.CurrentPlayPosition;
- db位置ms = n位置byte / this.Buffer.Format.SamplesPerSecond / 0.001 / _db周波数倍率 / _db再生速度;
- }
- else
- {
- n位置byte = 0;
- db位置ms = 0.0;
- }
- }
-
public static void tすべてのサウンドを初期状態に戻す()
{
default:
break;
- }
+ }
#endregion
this.e作成方法 = E作成方法.ファイルから;
tBASSサウンドを作成する_ストリーム生成後の共通処理( hMixer );
}
-
/// <summary>
/// Decode "RIFF chunked Vorbis" to "raw wave"
/// because BASE.DLL has two problems for RIFF chunked Vorbis;
{
using ( var ws = new WaveStream( strファイル名 ) )
{
- if ( ws.Format.FormatTag == (WaveFormatTag) 0x6770 || // Ogg Vorbis Mode 2+
- ws.Format.FormatTag == (WaveFormatTag) 0x6771 ) // Ogg Vorbis Mode 3+
+ if ( ws.Format.FormatTag == ( WaveFormatTag ) 0x6770 || // Ogg Vorbis Mode 2+
+ ws.Format.FormatTag == ( WaveFormatTag ) 0x6771 ) // Ogg Vorbis Mode 3+
{
Trace.TraceInformation( Path.GetFileName( strファイル名 ) + ": RIFF chunked Vorbis. Decode to raw Wave first, to avoid BASS.DLL troubles" );
try
// DirectShowのデコードに失敗したら、次はACMでのデコードを試すことになるため、ここではエラーログを出さない。
// Trace.TraceWarning( "Warning: " + Path.GetFileName( strファイル名 ) + " : デコードに失敗しました。" );
}
- catch ( Exception )
+ catch ( Exception e )
{
Trace.TraceWarning( "Warning: " + Path.GetFileName( strファイル名 ) + " : 読み込みに失敗しました。" );
}
return bファイルにVorbisコンテナが含まれている;
}
-
private void tBASSサウンドを作成するXA( string strファイル名, int hMixer, BASSFlag flags )
{
int nPCMデータの先頭インデックス;
protected set;
}
-
- // マスターボリュームの制御コードは、WASAPI/ASIOで全く同じ。
public int nMasterVolume
{
get
}
else
{
- //Trace.TraceInformation( "ASIO Master Volume Get Success: " + (f音量 * 100) );
+ Trace.TraceInformation( "ASIO Master Volume Get Success: " + ( f音量 * 100 ) );
}
return (int) ( f音量 * 100 );
}
set
{
- bool b = Bass.BASS_ChannelSetAttribute( this.hMixer, BASSAttribute.BASS_ATTRIB_VOL, (float) ( value / 100.0 ) );
+ bool b = Bass.BASS_ChannelSetAttribute( this.hMixer, BASSAttribute.BASS_ATTRIB_VOL, (float) ( value / 100.0 ) );
+ //bool b = Bass.BASS_SetVolume( value / 100.0f );
if ( !b )
{
BASSError be = Bass.BASS_ErrorGetCode();
}
else
{
- // int n = this.nMasterVolume;
- // Trace.TraceInformation( "ASIO Master Volume Set Success: " + value );
+ //int n = this.nMasterVolume;
+ //Trace.TraceInformation( "ASIO Master Volume Set Success: " + value );
+
}
}
}
BassAsio.BASS_ASIO_Free();
Bass.BASS_Free();
this.bIsBASSFree = true;
- throw new Exception( string.Format( "BASSミキサ(mixing)の作成に失敗しました。[{0}]", err ) );
+ throw new Exception( string.Format( "BASSミキサの作成に失敗しました。[{0}]", err ) );
}
// BASS ミキサーの1秒あたりのバイト数を算出。
//long nミキサーの1サンプルあたりのバイト数 = /*mixerInfo.chans*/ 2 * nサンプルサイズbyte;
long nミキサーの1サンプルあたりのバイト数 = mixerInfo.chans * nサンプルサイズbyte;
this.nミキサーの1秒あたりのバイト数 = nミキサーの1サンプルあたりのバイト数 * mixerInfo.freq;
-
-
- // 単純に、hMixerの音量をMasterVolumeとして制御しても、
- // ChannelGetData()の内容には反映されない。
- // そのため、もう一段mixerを噛ませて、一段先のmixerからChannelGetData()することで、
- // hMixerの音量制御を反映させる。
- this.hMixer_DeviceOut = BassMix.BASS_Mixer_StreamCreate(
- (int) this.db周波数, this.n出力チャンネル数, flag );
- if ( this.hMixer_DeviceOut == 0 )
- {
- BASSError errcode = Bass.BASS_ErrorGetCode();
- BassAsio.BASS_ASIO_Free();
- Bass.BASS_Free();
- this.bIsBASSFree = true;
- throw new Exception( string.Format( "BASSミキサ(最終段)の作成に失敗しました。[{0}]", errcode ) );
- }
- {
- bool b1 = BassMix.BASS_Mixer_StreamAddChannel( this.hMixer_DeviceOut, this.hMixer, BASSFlag.BASS_DEFAULT );
- if ( !b1 )
+
+ // 単純に、hMixerの音量をMasterVolumeとして制御しても、
+ // ChannelGetData()の内容には反映されない。
+ // そのため、もう一段mixerを噛ませて、一段先のmixerからChannelGetData()することで、
+ // hMixerの音量制御を反映させる。
+ this.hMixer_DeviceOut = BassMix.BASS_Mixer_StreamCreate(
+ (int) this.db周波数, this.n出力チャンネル数, flag );
+ if ( this.hMixer_DeviceOut == 0 )
{
BASSError errcode = Bass.BASS_ErrorGetCode();
- BassAsio.BASS_ASIO_Free();
- Bass.BASS_Free();
- this.bIsBASSFree = true;
- throw new Exception( string.Format( "BASSミキサ(最終段とmixing)の接続に失敗しました。[{0}]", errcode ) );
- };
- }
-
-
+ BassAsio.BASS_ASIO_Free();
+ Bass.BASS_Free();
+ this.bIsBASSFree = true;
+ throw new Exception( string.Format( "BASSミキサ(最終段)の作成に失敗しました。[{0}]", errcode ) );
+ }
+ {
+ bool b1 = BassMix.BASS_Mixer_StreamAddChannel( this.hMixer_DeviceOut, this.hMixer, BASSFlag.BASS_DEFAULT );
+ if ( !b1 )
+ {
+ BASSError errcode = Bass.BASS_ErrorGetCode();
+ BassAsio.BASS_ASIO_Free();
+ Bass.BASS_Free();
+ this.bIsBASSFree = true;
+ throw new Exception( string.Format( "BASSミキサ(最終段とmixing)の接続に失敗しました。[{0}]", errcode ) );
+ };
+ }
+
+
// 出力を開始。
this.nバッファサイズsample = (int) ( n希望バッファサイズms * this.db周波数 / 1000.0 );
protected int hMixer = -1;
- protected int hMixer_DeviceOut = -1;
+ protected int hMixer_DeviceOut = -1;
protected int n出力チャンネル数 = 0;
protected double db周波数 = 0.0;
protected int nバッファサイズsample = 0;
using Un4seen.Bass;
using Un4seen.BassWasapi;
using Un4seen.Bass.AddOn.Mix;
+using Un4seen.Bass.Misc;
namespace FDK
{
{
// 初期化。
- Trace.TraceInformation( "BASS (WASAPI) の初期化を開始します。" );
+ Trace.TraceInformation( "BASS (WASAPI{0}) の初期化を開始します。", mode.ToString() );
this.e出力デバイス = ESoundDeviceType.Unknown;
this.n実出力遅延ms = 0;
Debug.Assert( Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0 ), // 0:BASSストリームの自動更新を行わない。(BASSWASAPIから行うため)
string.Format( "BASS_SetConfig() に失敗しました。[{0}", Bass.BASS_ErrorGetCode() ) );
+ #region [ デバッグ用: BASSデバイスのenumerateと、ログ出力 ]
+ //Trace.TraceInformation( "BASSデバイス一覧:" );
+ //int defDevice = -1;
+ //BASS_DEVICEINFO bdi;
+ //for ( int n = 0; ( bdi = Bass.BASS_GetDeviceInfo( n ) ) != null; n++ )
+ //{
+ // Trace.TraceInformation( "BASS Device #{0}: {1}: IsDefault={2}, flags={3}, type={4}",
+ // n,
+ // bdi.name,
+ // bdi.IsDefault, bdi.flags.ToString(), bdi.type,ToString()
+ // );
+
+ // //if ( bdi.IsDefault )
+ // //{
+ // // defDevice = n;
+ // // break;
+ // //}
+ //}
+ #endregion
// BASS の初期化。
- int nデバイス = 0; // 0:"no device" … BASS からはデバイスへアクセスさせない。アクセスは BASSWASAPI アドオンから行う。
- int n周波数 = 44100; // 仮決め。lデバイス(≠ドライバ)がネイティブに対応している周波数であれば何でもいい?ようだ。BASSWASAPIでデバイスの周波数は変えられる。いずれにしろBASSMXで自動的にリサンプリングされる。
- if( !Bass.BASS_Init( nデバイス, n周波数, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero ) )
- throw new Exception( string.Format( "BASS (WASAPI) の初期化に失敗しました。(BASS_Init)[{0}]", Bass.BASS_ErrorGetCode().ToString() ) );
+ int n周波数 = 44100; // 仮決め。lデバイス(≠ドライバ)がネイティブに対応している周波数であれば何でもいい?ようだ。BASSWASAPIでデバイスの周波数は変えられる。いずれにしろBASSMXで自動的にリサンプリングされる。
+ // BASS_Initは、WASAPI初期化の直前に行うよう変更。WASAPIのmix周波数を使って初期化することで、余計なリサンプリング処理を省き高速化するため。
+ //if( !Bass.BASS_Init( nデバイス, n周波数, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero ) )
+ // throw new Exception( string.Format( "BASS (WASAPI) の初期化に失敗しました。(BASS_Init)[{0}]", Bass.BASS_ErrorGetCode().ToString() ) );
- #region [ デバッグ用: WASAPIデバイスのenumerateと、ログ出力 ]
- // (デバッグ用)
- //Trace.TraceInformation( "WASAPIデバイス一覧:" );
- //int a, count = 0;
- //BASS_WASAPI_DEVICEINFO wasapiDevInfo;
- //for ( a = 0; ( wasapiDevInfo = BassWasapi.BASS_WASAPI_GetDeviceInfo( a ) ) != null; a++ )
- //{
- // if ( ( wasapiDevInfo.flags & BASSWASAPIDeviceInfo.BASS_DEVICE_INPUT ) == 0 // device is an output device (not input)
- // && ( wasapiDevInfo.flags & BASSWASAPIDeviceInfo.BASS_DEVICE_ENABLED ) != 0 ) // and it is enabled
- // {
- // Trace.TraceInformation( "WASAPI Device #{0}: {1}", a, wasapiDevInfo.name );
- // count++; // count it
- // }
- //}
+
+ #region [ デバッグ用: サウンドデバイスのenumerateと、ログ出力 ]
+ //(デバッグ用)
+ Trace.TraceInformation("サウンドデバイス一覧:");
+ int a, count = 0;
+ BASS_DEVICEINFO[] bassDevInfos = Bass.BASS_GetDeviceInfos();
+ for (a = 0; a < bassDevInfos.GetLength(0); a++)
+ {
+ {
+ Trace.TraceInformation("Sound Device #{0}: {1}: IsDefault={2}, isEnabled={3}, flags={4}, driver={5}",
+ a,
+ bassDevInfos[a].name,
+ bassDevInfos[a].IsDefault,
+ bassDevInfos[a].IsEnabled,
+ bassDevInfos[a].flags,
+ bassDevInfos[a].driver
+ );
+ count++; // count it
+ }
+ }
#endregion
// BASS WASAPI の初期化。
- nデバイス = -1;
n周波数 = 0; // デフォルトデバイスの周波数 (0="mix format" sample rate)
int nチャンネル数 = 0; // デフォルトデバイスのチャンネル数 (0="mix format" channels)
this.tWasapiProc = new WASAPIPROC( this.tWASAPI処理 ); // アンマネージに渡す delegate は、フィールドとして保持しておかないとGCでアドレスが変わってしまう。
}
if ( nDevNo != -1 )
{
+ Trace.TraceInformation("Start Bass_Init(device=0(fixed value: no sound), deviceInfo.mixfreq=" + deviceInfo.mixfreq +", BASS_DEVICE_DEFAULT, Zero)");
+ if ( !Bass.BASS_Init( 0, deviceInfo.mixfreq, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero ) ) // device = 0:"no device": BASS からはデバイスへアクセスさせない。アクセスは BASSWASAPI アドオンから行う。
+ throw new Exception( string.Format( "BASS (WASAPI{0}) の初期化に失敗しました。(BASS_Init)[{1}]", mode.ToString(), Bass.BASS_ErrorGetCode().ToString() ) );
+
// Trace.TraceInformation( "Selected Default WASAPI Device: {0}", deviceInfo.name );
// Trace.TraceInformation( "MinPeriod={0}, DefaultPeriod={1}", deviceInfo.minperiod, deviceInfo.defperiod );
- n更新間隔ms = (long) ( deviceInfo.minperiod * 1000 );
- if ( n希望バッファサイズms <= 0 || n希望バッファサイズms < n更新間隔ms + 1 )
+ if (FDK.COS.bIsWin10OrLater && n更新間隔ms < deviceInfo.minperiod * 1000)
+ {
+ n更新間隔ms = Convert.ToInt64((deviceInfo.minperiod + 0.0005) * 1000.0f); // Win10では、更新間隔がminperiod以下だと、確実にBASS_ERROR_UNKNOWN
+ }
+ if (n希望バッファサイズms <= 0 || n希望バッファサイズms < n更新間隔ms + 1)
{
- n希望バッファサイズms = n更新間隔ms + 1; // 2013.4.25 #31237 yyagi; バッファサイズ設定の完全自動化。更新間隔=バッファサイズにするとBASS_ERROR_UNKNOWNになるので+1する。
+ n希望バッファサイズms = n更新間隔ms + 1; // 2013.4.25 #31237 yyagi; バッファサイズ設定の完全自動化。更新間隔=バッファサイズにするとBASS_ERROR_UNKNOWNになるので+1する。
}
}
else
}
#endregion
-//Retry:
+ #region [ デバッグ用: WASAPIデバイスのenumerateと、ログ出力 ]
+ //(デバッグ用)
+ Trace.TraceInformation("WASAPIデバイス一覧:");
+ //int a, count = 0;
+ BASS_WASAPI_DEVICEINFO wasapiDevInfo;
+ for (a = 0; (wasapiDevInfo = BassWasapi.BASS_WASAPI_GetDeviceInfo(a)) != null; a++)
+ {
+ if ((wasapiDevInfo.flags & BASSWASAPIDeviceInfo.BASS_DEVICE_INPUT) == 0 // device is an output device (not input)
+ && (wasapiDevInfo.flags & BASSWASAPIDeviceInfo.BASS_DEVICE_ENABLED) != 0) // and it is enabled
+ {
+ Trace.TraceInformation("WASAPI Device #{0}: {1}: IsDefault={2}, defPeriod={3}s, minperiod={4}s, mixchans={5}, mixfreq={6}",
+ a,
+ wasapiDevInfo.name,
+ wasapiDevInfo.IsDefault, wasapiDevInfo.defperiod, wasapiDevInfo.minperiod, wasapiDevInfo.mixchans, wasapiDevInfo.mixfreq);
+ count++; // count it
+ }
+ }
+ #endregion
+
+ Retry:
var flags = ( mode == Eデバイスモード.排他 ) ? BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT | BASSWASAPIInit.BASS_WASAPI_EXCLUSIVE : BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT;
//var flags = ( mode == Eデバイスモード.排他 ) ? BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT | BASSWASAPIInit.BASS_WASAPI_EVENT | BASSWASAPIInit.BASS_WASAPI_EXCLUSIVE : BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT | BASSWASAPIInit.BASS_WASAPI_EVENT;
- if ( BassWasapi.BASS_WASAPI_Init( nデバイス, n周波数, nチャンネル数, flags, ( n希望バッファサイズms / 1000.0f ), ( n更新間隔ms / 1000.0f ), this.tWasapiProc, IntPtr.Zero ) )
+ // if ( COS.bIsWin7OrLater && CSound管理.bSoundUpdateByEventWASAPI )
+ // {
+ // flags |= BASSWASAPIInit.BASS_WASAPI_EVENT; // Win7以降の場合は、WASAPIをevent drivenで動作させてCPU負荷減、レイテインシ改善
+ // }
+ n周波数 = deviceInfo.mixfreq;
+ nチャンネル数 = deviceInfo.mixchans;
+ //n希望バッファサイズms = n更新間隔ms = 0;
+ Trace.TraceInformation("n希望バッファサイズms=" + n希望バッファサイズms);
+ Trace.TraceInformation("n更新間隔ms=" + n更新間隔ms);
+ float f希望バッファサイズsec = (n希望バッファサイズms > 0) ? (n希望バッファサイズms / 1000.0f) : deviceInfo.minperiod * 4;
+ float f更新間隔sec = (n更新間隔ms > 0)? (n更新間隔ms / 1000.0f) : deviceInfo.minperiod;
+ //f希望バッファサイズsec = 0.01f;
+ //f更新間隔sec = 0.003f;
+ Trace.TraceInformation("Start Bass_Wasapi_Init(device=" + nDevNo + ", freq=" + n周波数 + ", nchans=" + nチャンネル数 + ", flags=" + flags + "," +
+ " buffer=" + f希望バッファサイズsec + ", period=" + f更新間隔sec);
+ if (BassWasapi.BASS_WASAPI_Init(nDevNo, n周波数, nチャンネル数, flags, f希望バッファサイズsec, f更新間隔sec, this.tWasapiProc, IntPtr.Zero))
{
- if( mode == Eデバイスモード.排他 )
+ if ( mode == Eデバイスモード.排他 )
{
#region [ 排他モードで作成成功。]
//-----------------
this.n実バッファサイズms = (long) ( wasapiInfo.buflen * 1000.0f / n1秒のバイト数 );
this.n実出力遅延ms = 0; // 初期値はゼロ
Trace.TraceInformation( "使用デバイス: #" + nDevNo + " : " + deviceInfo.name + ", flags=" + deviceInfo.flags );
- Trace.TraceInformation( "BASS を初期化しました。(WASAPI排他モード, {0}Hz, {1}ch, フォーマット:{2}, バッファ{3}bytes [{4}ms(希望{5}ms)], 更新間隔{6}ms)",
+ Trace.TraceInformation("BASS を初期化しました。(WASAPI排他モード, {0}Hz, {1}ch, フォーマット:{2}, バッファ{3}bytes [{4}ms(希望{5}ms)], 更新間隔{6}ms)",
wasapiInfo.freq,
wasapiInfo.chans,
wasapiInfo.format.ToString(),
wasapiInfo.buflen,
n実バッファサイズms.ToString(),
- n希望バッファサイズms.ToString(),
- n更新間隔ms.ToString() );
+ (f希望バッファサイズsec * 1000).ToString(), //n希望バッファサイズms.ToString(),
+ (f更新間隔sec * 1000).ToString() //n更新間隔ms.ToString()
+ );
Trace.TraceInformation( "デバイスの最小更新時間={0}ms, 既定の更新時間={1}ms", deviceInfo.minperiod * 1000, deviceInfo.defperiod * 1000 );
this.bIsBASSFree = false;
//-----------------
#region [ 共有モードで作成成功。]
//-----------------
this.e出力デバイス = ESoundDeviceType.SharedWASAPI;
-
+
+ var wasapiInfo = BassWasapi.BASS_WASAPI_GetInfo();
+ int n1サンプルのバイト数 = 2 * wasapiInfo.chans; // default;
+ int n1秒のバイト数 = n1サンプルのバイト数 * wasapiInfo.freq;
+ this.n実バッファサイズms = (long)(wasapiInfo.buflen * 1000.0f / n1秒のバイト数);
this.n実出力遅延ms = 0; // 初期値はゼロ
var devInfo = BassWasapi.BASS_WASAPI_GetDeviceInfo( BassWasapi.BASS_WASAPI_GetDevice() ); // 共有モードの場合、更新間隔はデバイスのデフォルト値に固定される。
- Trace.TraceInformation( "BASS を初期化しました。(WASAPI共有モード, {0}ms, 更新間隔{1}ms)", n希望バッファサイズms, devInfo.defperiod * 1000.0f );
+ //Trace.TraceInformation( "BASS を初期化しました。(WASAPI共有モード, 希望バッファサイズ={0}ms, 更新間隔{1}ms)", n希望バッファサイズms, devInfo.defperiod * 1000.0f );
+ Trace.TraceInformation("使用デバイス: #" + nDevNo + " : " + deviceInfo.name + ", flags=" + deviceInfo.flags);
+ Trace.TraceInformation("BASS を初期化しました。(WASAPI共有モード, {0}Hz, {1}ch, フォーマット:{2}, バッファ{3}bytes [{4}ms(希望{5}ms)], 更新間隔{6}ms)",
+ wasapiInfo.freq,
+ wasapiInfo.chans,
+ wasapiInfo.format.ToString(),
+ wasapiInfo.buflen,
+ n実バッファサイズms.ToString(),
+ n希望バッファサイズms.ToString(),
+ n更新間隔ms.ToString());
+ Trace.TraceInformation("デバイスの最小更新時間={0}ms, 既定の更新時間={1}ms", deviceInfo.minperiod * 1000, deviceInfo.defperiod * 1000);
this.bIsBASSFree = false;
//-----------------
#endregion
}
}
#region [ #31737 WASAPI排他モードのみ利用可能とし、WASAPI共有モードは使用できないようにするために、WASAPI共有モードでの初期化フローを削除する。 ]
- //else if ( mode == Eデバイスモード.排他 )
- //{
- // Trace.TraceInformation("Failed to initialize setting BASS (WASAPI) mode [{0}]", Bass.BASS_ErrorGetCode().ToString() );
- // #region [ 排他モードに失敗したのなら共有モードでリトライ。]
- // //-----------------
- // mode = Eデバイスモード.共有;
- // goto Retry;
- // //-----------------
- // #endregion
- //}
+ else if (mode == Eデバイスモード.排他)
+ {
+ BASSError errcode = Bass.BASS_ErrorGetCode();
+ Trace.TraceInformation("Failed to initialize setting BASS_WASAPI_Init (WASAPI{0}): [{1}]", mode.ToString(), errcode);
+ #region [ 排他モードに失敗したのなら共有モードでリトライ。]
+ //-----------------
+ // mode = Eデバイスモード.共有;
+ // goto Retry;
+ //-----------------
+ Bass.BASS_Free();
+ this.bIsBASSFree = true;
+ throw new Exception(string.Format("BASS (WASAPI{0}) の初期化に失敗しました。(BASS_WASAPI_Init)[{1}]", mode.ToString(), errcode));
+ #endregion
+ }
#endregion
else
{
BASSError errcode = Bass.BASS_ErrorGetCode();
Bass.BASS_Free();
this.bIsBASSFree = true;
- throw new Exception( string.Format( "BASS (WASAPI) の初期化に失敗しました。(BASS_WASAPI_Init)[{0}]", errcode ) );
+ throw new Exception( string.Format( "BASS (WASAPI{0}) の初期化に失敗しました。(BASS_WASAPI_Init)[{1}]", mode.ToString(), errcode ) );
//-----------------
#endregion
}
+
// WASAPI出力と同じフォーマットを持つ BASS ミキサーを作成。
+ //Debug.Assert( Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_MIXER_BUFFER, 5 ), // バッファ量を最大量の5にする
+ // string.Format( "BASS_SetConfig(CONFIG_MIXER_BUFFER) に失敗しました。[{0}", Bass.BASS_ErrorGetCode() ) );
+
var info = BassWasapi.BASS_WASAPI_GetInfo();
this.hMixer = BassMix.BASS_Mixer_StreamCreate(
info.freq,
info.chans,
- BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE ); // デコードのみ=発声しない。WASAPIに出力されるだけ。
+ BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_POSEX ); // デコードのみ=発声しない。WASAPIに出力されるだけ。
if ( this.hMixer == 0 )
{
BASSError errcode = Bass.BASS_ErrorGetCode();
this.hMixer_DeviceOut = BassMix.BASS_Mixer_StreamCreate(
info.freq,
info.chans,
- BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE ); // デコードのみ=発声しない。WASAPIに出力されるだけ。
+ BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_POSEX ); // デコードのみ=発声しない。WASAPIに出力されるだけ。
if ( this.hMixer_DeviceOut == 0 )
{
BASSError errcode = Bass.BASS_ErrorGetCode();
}
+ //録音テスト
+ //w = new EncoderWAV( this.hMixer_DeviceOut );
+ //w.InputFile = null; //STDIN
+ //w.OutputFile = "test2.wav";
+ //w.Start( null, IntPtr.Zero, false );
+ // decode the stream (if not using a decoding channel, simply call "Bass.BASS_ChannelPlay" here)
+
// 出力を開始。
BassWasapi.BASS_WASAPI_Start();
}
protected void Dispose( bool bManagedDispose )
{
+ //if ( w != null )
+ //{
+ // w.Stop(); // finish
+ //}
this.e出力デバイス = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ)
if ( hMixer != -1 )
{
protected int hMixer = -1;
protected int hMixer_DeviceOut = -1;
+ protected int hMixer_Record = -1;
+ protected EncoderWAV w;
+ protected int stream;
protected WASAPIPROC tWasapiProc = null;
protected int tWASAPI処理( IntPtr buffer, int length, IntPtr user )