ページ 11

XAudio2を使ってWAVファイルを再生したい

Posted: 2013年5月13日(月) 20:56
by Terry
[1] 質問文
 [1.1] 行いたいこと
→XAudio2(Windowsの音声API)を使って、WAVファイルを再生したい。

 [1.2] どのように取り組んだか
http://princess-tiara.biz/directx/?chapter=19

上記のページを参考に(というかほぼ一緒です)作成しました。

コード:


#pragma comment(lib, "winmm.lib")

#include <windows.h>
#include <xaudio2.h>
#include <vector>
#include <cmath>
#include <iostream>
#include <time.h>
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <mmsystem.h>

//-----------------------------------------------------------------
//    Global Variables.
//-----------------------------------------------------------------

IXAudio2               *g_pXAudio2        = NULL;
IXAudio2MasteringVoice *g_pMasteringVoice = NULL;
IXAudio2SourceVoice    *g_pSourceVoice    = NULL;//音声ファイル1つにつき1つ用意する

#define fourccRIFF 'RIFF'
#define fourccDATA 'data'
#define fourccFMT 'fmt '
#define fourccWAVE 'WAVE'
#define fourccXWMA 'XWMA'
#define fourccDPDS 'dpds'


//-----------------------------------------------------------------
//    Prototypes.
//-----------------------------------------------------------------
HRESULT FindChunk( HANDLE , DWORD , DWORD* , DWORD* );
HRESULT ReadChunkData( HANDLE , void* , DWORD , DWORD );

//-----------------------------------------------------------------
//    Main.
//-----------------------------------------------------------------
int main(int argc, char** argv){



//音声処理

	HRESULT      hr;
	
	HANDLE               hFile;
	DWORD                dwChunkSize;
	DWORD                dwChunkPosition;
	DWORD                filetype;
	WAVEFORMATEXTENSIBLE wfx;
	XAUDIO2_BUFFER       buffer;
	BYTE                 *pDataBuffer;
	
	XAUDIO2_VOICE_STATE xa2state;
	

	//*********初期化***************
	CoInitializeEx( NULL , COINIT_MULTITHREADED );

	//**********XAudio2作成**************
	hr = XAudio2Create( &g_pXAudio2 , 0 ); //XAudioの作成
	if ( FAILED( hr ) ){
		CoUninitialize();
		return -1;
	}

	//**********マスタリングボイスの作成*************
    hr = g_pXAudio2->CreateMasteringVoice( &g_pMasteringVoice );
	if ( FAILED( hr ) ){
		if ( g_pXAudio2 ) g_pXAudio2->Release();
		CoUninitialize();
		return -1;
	}

	
	//*************読み込み部分***********************
	memset( &wfx , 0 , sizeof( WAVEFORMATEXTENSIBLE ) );
	memset( &buffer , 0 , sizeof( XAUDIO2_BUFFER ) );

	hFile = CreateFile( "flute1.wav", GENERIC_READ , FILE_SHARE_READ , NULL ,
                    OPEN_EXISTING , 0 , NULL );
	if ( hFile == INVALID_HANDLE_VALUE ){
		return HRESULT_FROM_WIN32( GetLastError() );
	}



	if ( SetFilePointer( hFile , 0 , NULL , FILE_BEGIN ) == INVALID_SET_FILE_POINTER ){
		return HRESULT_FROM_WIN32( GetLastError() );
	}

	// Check Wave File.
	hr = FindChunk( hFile , fourccRIFF , &dwChunkSize , &dwChunkPosition );
	if ( FAILED( hr ) ) return S_FALSE;


	hr = ReadChunkData( hFile , &filetype , sizeof( DWORD ) , dwChunkPosition );
	if ( FAILED( hr ) )	return S_FALSE; //①ここで読み込みが終わってしまう模様。
	if ( filetype != fourccWAVE ) return S_FALSE;

	// Get Format.
	hr = FindChunk( hFile , fourccFMT , &dwChunkSize , &dwChunkPosition );
	if ( FAILED( hr ) ) return S_FALSE;
	hr = ReadChunkData( hFile , &wfx , dwChunkSize , dwChunkPosition );
	if ( FAILED( hr ) ) return S_FALSE;

	// Load Sound.
	hr = FindChunk( hFile , fourccDATA , &dwChunkSize , &dwChunkPosition );
	if ( FAILED( hr ) ) return S_FALSE;
	pDataBuffer = (BYTE*)malloc( dwChunkSize );
	hr = ReadChunkData( hFile , pDataBuffer , dwChunkSize , dwChunkPosition );
	if ( FAILED( hr ) ) return S_FALSE;


	//************音声ファイルの設定*******************
	g_pXAudio2->CreateSourceVoice( &g_pSourceVoice , &(wfx.Format) );

	buffer.AudioBytes = dwChunkSize;//音声データのサイズ
	buffer.pAudioData = pDataBuffer;//音声データが入っているメモリ領域のアドレス
	buffer.Flags      = XAUDIO2_END_OF_STREAM;
	buffer.LoopCount  = XAUDIO2_LOOP_INFINITE;//繰り返しの再生回数

	g_pSourceVoice->SubmitSourceBuffer( &buffer );//ソースボイスの設定

	
	//************音声の再生*******************
	g_pSourceVoice->GetState( &xa2state );
	if ( xa2state.BuffersQueued != 0 ){
		g_pSourceVoice->Stop( 0 );
		g_pSourceVoice->FlushSourceBuffers();
		g_pSourceVoice->SubmitSourceBuffer( &buffer );
	}
	g_pSourceVoice->Start( 0 );
	
	Sleep( 5000 );

	//***********音声の停止*********************
	g_pSourceVoice->Stop( 0 );
	g_pSourceVoice->FlushSourceBuffers();
	g_pSourceVoice->SubmitSourceBuffer( &buffer );


	//**********終了処理*************
	g_pSourceVoice->Stop( 0 );
	g_pSourceVoice->DestroyVoice();
	free( pDataBuffer );
	g_pMasteringVoice->DestroyVoice();
	if ( g_pXAudio2 ) g_pXAudio2->Release();
	CoUninitialize();

  return 0;

}



//******************************************************************************
//    Find Chunk.
//******************************************************************************
HRESULT FindChunk( HANDLE hFile , DWORD forucc , DWORD *dwChunkSize , DWORD *dwChunkDataPosition )
{
	HRESULT hr;
	
	DWORD dwRead;
	DWORD dwChunkType;
	DWORD dwChunkDataSize;
	DWORD dwRIFFDataSize = 0;
	DWORD dwFileType;
	DWORD bytesRead = 0;
	DWORD dwOffset = 0;
	
	hr = S_OK;
	
	if ( SetFilePointer( hFile , 0 , NULL , FILE_BEGIN ) == INVALID_SET_FILE_POINTER )
		return HRESULT_FROM_WIN32( GetLastError() );
	
	while( hr == S_OK ){
		if ( ReadFile( hFile , &dwChunkType , sizeof( DWORD ) , &dwRead , NULL ) == 0 )
			hr = HRESULT_FROM_WIN32( GetLastError() );
		if ( ReadFile( hFile , &dwChunkDataSize , sizeof( DWORD ) , &dwRead , NULL )
		     == 0 )
			hr = HRESULT_FROM_WIN32( GetLastError() );
		switch( dwChunkType ){
			case fourccRIFF:
				dwRIFFDataSize  = dwChunkDataSize;
				dwChunkDataSize = 4;
				if ( ReadFile( hFile ,
				     &dwFileType , sizeof( DWORD ) , &dwRead , NULL ) == 0 )
					hr = HRESULT_FROM_WIN32( GetLastError() );
				break;
			default:
				if ( SetFilePointer( hFile ,
				     dwChunkDataSize , NULL , FILE_CURRENT )
				     == INVALID_SET_FILE_POINTER )
					return HRESULT_FROM_WIN32( GetLastError() );
		}
		dwOffset += sizeof( DWORD ) * 2;
		if ( dwChunkType == forucc ){
			*dwChunkSize         = dwChunkDataSize;
			*dwChunkDataPosition = dwOffset;
			return S_OK;
		}
		dwOffset += dwChunkDataSize;
		if ( bytesRead >= dwRIFFDataSize ) return S_FALSE;
	}
	
	return S_OK;
}



//******************************************************************************
//    Read Chunk Data.
//******************************************************************************
HRESULT ReadChunkData( HANDLE hFile , void *buffer , DWORD buffersize , DWORD bufferoffset )
{
	DWORD dwRead;
	if ( ReadFile( hFile , buffer , buffersize , &dwRead , NULL ) == 0 )
		return HRESULT_FROM_WIN32( GetLastError() );

	
	if ( SetFilePointer( hFile , bufferoffset , NULL , FILE_BEGIN )
	     == INVALID_SET_FILE_POINTER )
		return HRESULT_FROM_WIN32( GetLastError() );
	
	if ( ReadFile( hFile , buffer , buffersize , &dwRead , NULL ) == 0 )
		return HRESULT_FROM_WIN32( GetLastError() );
	
	return S_OK;
}

 [1.3] どのようなエラーやトラブルで困っているか

→エラーは出てないのですが、①(100行目)のところで、wavファイルの読み込みが終わってしまうため、再生できない。

 [1.4] 今何がわからないのか、知りたいのか

→上記の原因を知りたい。WAVファイルの置き場所は、実行ファイルのあるVCプロジェクトフォルダ内に置いてある。おそらく、WAVファイル(82行目flute1.wav)は読み込めているのだと思っている(読み込めない場合、100行より前の
if ( FAILED( hr ) ) return S_FALSE;
ではじかれるため。)。

[2] 環境  
 [2.1] OS : Windows, Linux等々
→OS:Windows7

 [2.2] コンパイラ名 : VC++ 2008EE, Borand C++, gcc等々
コンパイラ名→Microsoft Visual C++ 2008

[3] その他
 ・どの程度C言語を理解しているか
  ・if、for、while、ポインタなどの基本的なことは理解しているつもり。

 ・ライブラリを使っている場合は何を使っているか
    ・Microsoft DirectX SDK (June 2010)
    ・openCV(上記のプログラムには、まだ利用していないが、インクルードはしている)

以上、ご協力できる方よろしくお願いします。

Re: XAudio2を使ってWAVファイルを再生したい

Posted: 2013年5月13日(月) 23:35
by ISLe
ReadChunkData関数の最初にあるReadFileは何のためにあるのだろうと思いましたが、参考にしたというページのコードにはないものですね。

まずは参考にしたページに書かれたコードとしっかり見比べてみるのがよろしいかと思います。
むしろきちんとコピペしましょう。

Re: XAudio2を使ってWAVファイルを再生したい

Posted: 2013年5月15日(水) 17:35
by Terry
ISLe様、返信遅れて申し訳ありません。

コピペした結果、同じところで読み込めなくなりました。
現在、別の方法で検討中です。