ASIOを利用してWAVファイルを再生する
(その2)
ダイアログの[再生]ボタンを押されたときに、WAVファイルの再生を開始します。
- WAVファイルがオープンされていない場合、WAVファイルをオープンします。
- サウンド出力を行うASIOドライバをロードします。
- ASIOドライバをオープンします。
- ASIOデバイスが使用する出力バッファを確保します。
- 最後にASIOでのサウンド出力を開始します。
サンプルコードを以下に示します。
/****************************************************************************/
/*!
* @brief WAVファイルを再生する.
*
* @param [in] hDlg ダイアログのウインドウ・ハンドル.
*
* @retval TRUE = OK. / FALSE = NG.
*/
static BOOL PlaySoundOutput( HWND hDlg )
{
//! WAVファイルをオープンしていない場合、オープンする.
if( !IsOpenWaveFile() ){
//! -1.ダイアログから再生するWAVファイル名を取得する.
GetWindowText( GetDlgItem( hDlg, IDC_FILENAME ), FileName, sizeof(FileName) - 1 );
//! -2.再生するWAVファイル名をオープンする.
if( !ReadOpenWaveFile( FileName ) ){
MessageBox( hDlg, _T("ファイルをオープンできません"), _T("WAVファイルの再生"), MB_OK );
return FALSE;
}
WaveEnd = FALSE;
EndDelay = 0;
}
if( !AppWnd ){
//! オープンしたWAVファイルのオーディオ・フィーマットを取得する.
WAVEFORMATEX wf;
GetAudioFormat( &wf );
//! サウンド出力デバイスをオープンする.
UINT num = ComboBox_GetCurSel( GetDlgItem( hDlg, IDC_OUTPUT_DEVICE ) );
if( OpenSoundOutDevice( hDlg, num, &wf ) ){
//! WAVファイルの読み込み用バッファを確保する.
if( !DataBuff ){
DataSize = BufSize * sizeof(WORD) * 32;
DataBuff = new BYTE[DataSize];
}
//! WAVEファイルを読み込む.
WavBuf[0] = DataBuff;
WavBuf[1] = &DataBuff[DataSize >> 1];
WavSize[0] = ReadWaveFile( WavBuf[0], DataSize >> 1 );
WavSize[1] = ReadWaveFile( WavBuf[1], DataSize >> 1 );
ActivePage = 0;
ReadCnt = 0;
}
AppWnd = hDlg;
}
//! サウンド出力を開始する.
ASIOStart();
EnableWindow( GetDlgItem( hDlg, IDC_PLAY ), FALSE );
EnableWindow( GetDlgItem( hDlg, IDC_PAUSE ), TRUE );
EnableWindow( GetDlgItem( hDlg, IDC_STOP ), TRUE );
EnableWindow( GetDlgItem( hDlg, IDC_FILENAME ), FALSE );
EnableWindow( GetDlgItem( hDlg, IDC_FILE_SELECT ), FALSE );
EnableWindow( GetDlgItem( hDlg, IDC_OUTPUT_DEVICE ), FALSE );
return TRUE;
}
/****************************************************************************/
/*!
* @brief ASIOドライバをオープンする.
*
* @param [in] hDlg ダイアログのウインドウ・ハンドル.
* @param [in] num オープンするデバイス番号.
* @param [in] wf 再生するWAVファイルのオーディオ情報構造体のポインタ.
*
* @retval なし.
*/
static BOOL OpenSoundOutDevice( HWND hDlg, UINT num, WAVEFORMATEX* wf )
{
if( num >= DevCnt ){
return FALSE;
}
//! オープンするドライバをロードする.
asioDrivers->loadDriver( DevName[num] );
do {
//! ASIOデバイスをオープンする.
ASIODriverInfo info;
memset( &info, 0, sizeof(info) );
info.asioVersion = 0;
info.sysRef = hDlg;
if( ASIOInit( &info ) != ASE_OK ){
break;
}
//! 作成可能なバッファサイズを取得する.
long minimum;
long maximum;
long preferred;
long granularity;
if( ASIOGetBufferSize( &minimum, &maximum, &preferred, &granularity ) != ASE_OK ){
break;
}
//! バッファ情報を格納する領域を初期化する.
long i = 0;
memset( BufInfo, 0, sizeof(BufInfo) );
for( ; i < 2; i++ ){
BufInfo[i].isInput = ASIOFalse;
BufInfo[i].channelNum = i;
}
BufSize = preferred;
//! 使用するチャンネルのデータバッファを確保する.
static ASIOCallbacks cb;
cb.bufferSwitch = &bufferSwitch;
cb.sampleRateDidChange = NULL;
cb.asioMessage = NULL;
cb.bufferSwitchTimeInfo = NULL;
ASIOCreateBuffers( BufInfo, i, BufSize, &cb );
//! サンプルレートを設定する.
ASIOSetSampleRate( wf->nSamplesPerSec );
return TRUE;
}while( FALSE );
CloseSoundOutputDevice();
return FALSE;
}
asioDrivers::loadDriver()を呼び出して、使用するASIOドライバをロードします。
bool asioDrivers::loadDriver( char* name )
引数 | 説明 |
---|---|
name |
ロードするASIOドライバ名のポインタ。 |
戻り値がtrueならば、ドライバのロードは成功です。
ASIOInit()を呼び出して、使用するASIOドライバをオープンします。
ASIOError ASIOInit( ASIODriverInfo* info )
引数 | 説明 |
---|---|
info | ドライバ情報を取得する構造体(ASIODriverInfo構造体)のポインタ。 |
戻り値がASE_OKならば、ドライバのオープンは成功です。
メンバ名 | 説明 |
---|---|
asioVersion | ホストバージョンを指定します。 |
driverVersion | 関数の戻りで、ドライバ・バージョンがセットされます。 |
name[32] | 関数の戻りで、ドライバ名の文字列がセットされます。 |
errorMessage[124] | 関数の戻りで、エラー内容を表す文字列がセットされます。 |
sysRef | アプリケーションのウインドウハンドルを指定します。 |
ASIOGetBufferSize()を呼び出して作成可能なストリームバッファのサイズを取得します。
ASIOError ASIOGetBufferSize(long *minSize,
long *maxSize,
long *preferredSize,
long *granularity);
引数 | 説明 |
---|---|
minSize | 最小バッファサイズを格納する領域のポインタ。 |
maxSize | 最大バッファサイズを格納する領域のポインタ。 |
preferredSize | 推奨バッファサイズを格納する領域のポインタ。 |
granularity |
ASIOGetBufferSize()からの戻り値がASE_OKであれば、バッファサイズの取得は成功です。
入出力が無い場合、戻り値がASE_NotPresentとなります。
ASIOCreateBuffers()を呼び出して各チャンネルで使用するデータバッファを確保します。
ASIOError ASIOCreateBuffers( ASIOBufferInfo *bufferInfos,
long numChannels,
long bufferSize,
ASIOCallbacks *callbacks)
引数 | 説明 |
---|---|
bufferInfos |
作成するバッファの設定を記述した構造体配列のポインタ。 |
numChannels | 使用するチャンネル数。(bufferInfosで指定した配列の個数。) |
bufferSize | 確保するバッファのサイズ。ASIOGetBufferSize()にて取得した範囲を超えないようにします。 |
callbacks | コールバック関数のポインタテーブル(ASIOCallbacks構造体)のポインタ。 |
戻り値がASE_OKであれば、データバッファの作成は成功です。
メンバ名 | 説明 |
---|---|
isInput |
使用するチャンネルの入力/出力を次の値で指定します。 |
channelNum | 使用するチャンネル番号を指定します。 |
buffers[2] | ドライバで確保したバッファのアドレスが格納されます。 |
メンバ名 | 説明 |
---|---|
bufferSwitch | データ入出力のコールバック。 |
sampleRateDidChange | サンプルレート変更時のコールバック。 |
asioMessage | ドライバからの要求を受け付けるコールバック。 |
bufferSwitchTimeInfo | データ入出力のコールバック (タイムコード付き)。 |
各コールバック関数は以下のとおりです。
bufferSwitch()は、ASIOドライバに対するデータ入出力を行うタイミングでコールバックされます。
void (*bufferSwitch)( long doubleBufferIndex, ASIOBool directProcess )
引数 | 説明 |
---|---|
doubleBufferIndex | 処理するバッファのインデックス番号。(0 または 1) |
directProcess |
- ASIOTrue |
sampleRateDidChange()は、デジタル入力等で、サンプルレートが現在のレートと変わったときにコールバックされます。
void (*sampleRateDidChange)( ASIOSampleRate sRate )
引数 | 説明 |
---|---|
sRate | 変更後のサンプルレート。(サンプルレートが不明な場合、0がセットされます。) |
asioMessage()は、ドライバからの要求を受け付けるコールバック関数です。
long (*asioMessage)( long selector, long value, void* message, double* opt )
引数 | 説明 |
---|---|
selector | |
value | セレクタに付随するパラメータ。 |
message | セレクタに付随するメッセージ・パラメータ。 |
opt | セレクタに付随するオプション・パラメータ。 |
戻り値はセレクタによって異なります。未サポートのセレクタの場合0を返します。
セレクタ・コード | 説明 |
---|---|
kAsioSelectorSupported |
アプリケーションが要求されたセレクタをサポートしているか調べます。 |
kAsioEngineVersion |
アプリケーションのASIOインプリメンテーション・バージョンを問い合わせます。 |
kAsioResetRequest |
ドライバからのリセット要求。 |
kAsioBufferSizeChange |
バッファサイズの変更が出来たことを通知します。 |
kAsioResyncRequest |
タイムスタンプが不正になるなど、同期が取れなくなったことによる、ドライバからのリセット要求。 |
kAsioLatenciesChanged |
ドライバがレイテンシを変更したことを通知します。 |
kAsioSupportsTimeInfo |
bufferSwitchTimeInfo()コールバックをサポートしているか問い合わせます。 |
kAsioSupportsTimeCode |
bufferSwitchTimeInfo()コールバックがタイムコードの読み込みをサポートしているか問い合わせます。 |
bufferSwitchTimeInfo()は、ASIOドライバに対するデータ入出力を行うタイミングでコールバックされます。
ドライバとアプリケーションで同期を取るために、タイムコードの受け渡しを行います。
ASIOTime* (*bufferSwitchTimeInfo)( ASIOTime* params,
long doubleBufferIndex,
ASIOBool directProcess )
引数 | 説明 |
---|---|
params | ASIOTime構造体のポインタ。 |
doubleBufferIndex | 処理するバッファのインデックス番号。(0 または 1) |
directProcess |
- ASIOTrue |
戻り値は、アプリケーションからドライバに通知するタイムコード(ASIOTime構造体)のポインタを返します。
メンバ名 | 説明 |
---|---|
reserved[4] | 未使用。(ALL 0) |
timeInfo | 時間情報(AsioTimeInfo構造体)。 |
timeCode | タイムコード(ASIOTimeCode構造体)。 |
メンバ名 | 説明 |
---|---|
speed | 再生速度 (1. = nominal) |
systemTime | システム時間(ナノ秒)。 |
samplePosition | ASIOStart()からのサンプル数。 |
sampleRate | サンプルレート。 |
flags |
- kSystemTimeValid |
メンバ名 | 説明 |
---|---|
speed | 再生速度の分数。 |
timeCodeSamples | タイムコード (サンプル数)。 |
flags |
- kTcValid |
future[64] | 未使用。(ALL 0) |
ASIOStart()を呼び出して、ASIOでのサウンド入出力を開始します。
ASIOError ASIOStart( void )
戻り値がASE_OKならば、サウンド出力が開始されます。