ASIOを利用してWAVファイルを再生する
(その3)
ASIOではサウンド入出力バッファが空くと、ASIOドライバよりアプリケーションが事前に登録したコールバック関数が呼び出されます。
このコールバック関数でアプリケーション側は、出力チャンネルのデータフォーマットを取得して、次に出力するサウンドデータをストリームバッファに書き込みます。
ストリームバッファに書き込みが完了したら、ASIOドライバに対して出力データの書き込み完了を通知します。
サンプルコードを以下に示します。
/****************************************************************************/
/*!
* @brief データバッファの切り替え通知.
*
* @param [in] index バッファ番号.
* @param [in] processNow ASIOTrue = すぐに処理が可能.
*
* @retval なし.
*/
static void bufferSwitch( long index, ASIOBool processNow )
{
if( WavSize[0] > 0 || WavSize[1] > 0 ){
if( ReadCnt >= WavSize[ActivePage] ){
PostMessage( AppWnd, WM_USER, ActivePage, 0 );
ActivePage = (ActivePage + 1) & 1;
ReadCnt = 0;
}
}
BYTE* buf_l = (BYTE*)(BufInfo[0].buffers[index]);
BYTE* buf_r = (BYTE*)(BufInfo[1].buffers[index]);
//! チャンネル情報を取得する.
ASIOChannelInfo info;
info.channel = BufInfo[0].channelNum;
info.isInput = BufInfo[0].isInput;
ASIOGetChannelInfo( &info );
switch( info.type ){
case ASIOSTInt16LSB:
//! 16ビットオーディオの場合.
memset( buf_l, 0, BufSize * 2 );
memset( buf_r, 0, BufSize * 2 );
if( WavSize[ActivePage] > 0 ){
short* dst_l = (short*)buf_l;
short* dst_r = (short*)buf_r;
short* src = (short*)&(WavBuf[ActivePage][ReadCnt]);
DWORD limit = (WavSize[ActivePage] - ReadCnt) / 4;
if( limit > BufSize ){
limit = BufSize;
}
for( DWORD i = 0; i < limit; i++ ){
*(dst_l++) = *(src++);
*(dst_r++) = *(src++);
}
ReadCnt += (BufSize * 4);
}
break;
case ASIOSTInt24LSB:
//! 24ビットオーディオの場合.
memset( buf_l, 0, BufSize * 3 );
memset( buf_r, 0, BufSize * 3 );
if( WavSize[ActivePage] > 0 ){
BYTE* dst_l = buf_l;
BYTE* dst_r = buf_r;
BYTE* src = &(WavBuf[ActivePage][ReadCnt]);
DWORD limit = (WavSize[ActivePage] - ReadCnt) / 4;
if( limit > BufSize ){
limit = BufSize;
}
for( DWORD i = 0; i < limit; i++ ){
*(dst_l++) = 0x00;
*(dst_l++) = *(src++);
*(dst_l++) = *(src++);
*(dst_r++) = 0x00;
*(dst_r++) = *(src++);
*(dst_r++) = *(src++);
}
ReadCnt += (BufSize * 4);
}
break;
case ASIOSTInt32LSB:
//! 32ビットオーディオの場合.
memset( buf_l, 0, BufSize * 4 );
memset( buf_r, 0, BufSize * 4 );
if( WavSize[ActivePage] > 0 ){
short* dst_l = (short*)buf_l;
short* dst_r = (short*)buf_r;
short* src = (short*)&(WavBuf[ActivePage][ReadCnt]);
DWORD limit = (WavSize[ActivePage] - ReadCnt) / 4;
if( limit > BufSize ){
limit = BufSize;
}
for( DWORD i = 0; i < limit; i++ ){
*(dst_l++) = 0;
*(dst_l++) = *(src++);
*(dst_r++) = 0;
*(dst_r++) = *(src++);
}
ReadCnt += (BufSize * 4);
}
break;
case ASIOSTInt32LSB16:
case ASIOSTInt32LSB18:
case ASIOSTInt32LSB20:
case ASIOSTInt32LSB24:
case ASIOSTFloat32LSB:
case ASIOSTInt32MSB:
case ASIOSTInt32MSB16:
case ASIOSTInt32MSB18:
case ASIOSTInt32MSB20:
case ASIOSTInt32MSB24:
case ASIOSTFloat32MSB:
memset( buf_l, 0, BufSize * 4 );
memset( buf_r, 0, BufSize * 4 );
break;
case ASIOSTFloat64LSB:
case ASIOSTFloat64MSB:
memset( buf_l, 0, BufSize * 8 );
memset( buf_r, 0, BufSize * 8 );
break;
case ASIOSTInt16MSB:
memset( buf_l, 0, BufSize * 2 );
memset( buf_r, 0, BufSize * 2 );
break;
case ASIOSTInt24MSB:
memset( buf_l, 0, BufSize * 3 );
memset( buf_r, 0, BufSize * 3 );
break;
}
// ASIOOutputReady()をサポートしている場合、毎回ASIOOutputReady()を呼び出す.
ASIOOutputReady();
}
ASIOGetChannelInfo()を呼び出して、チャンネル情報を取得します。
ASIOError ASIOGetChannelInfo( ASIOChannelInfo* info )
引数 | 説明 |
---|---|
info |
チャンネル情報を格納するデータ(ASIOChannelInfo構造体)のポインタ |
戻り値がASE_OKであれば、チャンネル情報が取得できます。
メンバ名 | 説明 |
---|---|
channel | 問い合わせるチャンネル番号を指定します。 |
isInput |
問い合わせるチャンネルの入力/出力を次の値で指定します。 |
isActive |
問い合わせたチャンネルがアクティブかどうかを次の値で表します。 |
channelGroup | チャンネル・グループ番号。 |
type |
サンプルデータのフォーマットが以下の値で返されます。 |
name[32] | チャンネル名を示す文字列。 |
サウンド出力するデータをバッファにセットしたらASIOOutputReady()を呼び出して、アプリケーションで出力バッファへの処理が完了したことをドライバに通知します。
ASIOError ASIOOutputReady( void )
戻り値がASE_OKならば通知完了です。