DirectX講座2回ではPlaySound関数でサウンドを鳴らしました
ただし、毎回ファイル読みこみを行わなければならないので処理が重い点と
複数同時にサウンド再生ができないのが最大の欠点でした

今回は複数同時にサウンド再生を行う前準備として
DirectSoundによるサウンド再生をやってみます
DirectSoundであらかじめサウンドファイルを読み込んでおけば高速に再生ができます
さらに シーク制御、ボリューム調整、ステレオサウンド、サウンドエフェクト、3Dサウンドなどの非常に多彩な制御もできます

DirectSoundはDirectXの一部なのでDirectXのパスの設定をプロジェクトに追加しなければ使えません
これは、Direct3Dと同じなのでDirectX講座7回のように
DirectXのプロパティシートをプロジェクトに追加します

DirectSoundでサウンド再生をするには
まず、 DirectSoundデバイスを作成しなければなりません
DirectSoundでサウンドを再生するには サウンド再生の対象となるウィンドウが必要になります
このためだけにウィンドウを作成してます

次にサウンドファイルであるWAVファイル(WAVEファイルともいう)を読み込みます

DirectSoundデバイスと読み込んだWAVファイルのフォーマット情報から プライマリバッファを作成し
プライマリバッファから セカンダリバッファを作成します。
プライマリバッファは複数のセカンダリバッファのサウンドをミキシングして(混ぜ合わせて)鳴らすこともできますが
セカンダリバッファ単体でもサウンドを鳴らすことができるので
セカンダリバッファを作成したらプライマリバッファは破棄してかまいません

セカンダリバッファを作成したら
読み込んだWAVファイルの音データをセカンダリバッファにコピーします
これでサウンドを鳴らす準備が整います

再生はセカンダリバッファのPlayメンバ関数で再生できます
停止はセカンダリバッファのStopメンバ関数で停止できます

DirectSoundの変数も使い終わったら後処理が必要です
セカンダリバッファを破棄する時は、その前に再生停止しなければならないことには注意します

今回使うファイルは次のようになってます。どぞー(-ω-)つ旦
filedirectsound.cpp
filebattle.wav
zipでほしい人はこちら
filedirectsound.zip

#define _CRT_SECURE_NO_WARNINGS

// DirectSoundに必要なヘッダーとライブラリ

#define DIRECTSOUND_VERSION 0x800	// DirectSoundのバージョン

#pragma comment(lib, "dsound.lib") 
#pragma comment(lib, "d3dxof.lib")
#pragma comment(lib, "dxguid.lib")

#include <comdef.h>
#include <dsound.h>
#include <tchar.h>
#include <d3d9.h>
#include <d3dx9.h>

////////////////////////////////////////

#include <Windows.h>
#include <vector>

// ウィンドウプロシージャ、ウィンドウに対するメッセージ処理を行う
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
	
	switch(msg){
		// ウィンドウが破棄されたとき
	case WM_DESTROY:
		PostQuitMessage(0);	// WM_QUITメッセージをメッセージキューに送る
		return 0;
	}
	// デフォルトのメッセージ処理を行う
	return DefWindowProc(hWnd, msg, wParam, lParam);
}

// WinMain関数(アプリケーションの開始関数)
// コンソールアプリケーションと違い、コンソールを開かない
int _stdcall WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
	////////////////////////////
	//	ウィンドウ作成
	////////////////////////////

	const TCHAR* WC_BASIC = _T("BASIC_WINDOW");
	// シンプルウィンドウクラス設定
	WNDCLASSEX wcex ={sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS,WndProc, 0,0,hInstance,
		(HICON)LoadImage(NULL,MAKEINTRESOURCE(IDI_APPLICATION),IMAGE_ICON,0,0,LR_DEFAULTSIZE | LR_SHARED),
		(HCURSOR)LoadImage(NULL,MAKEINTRESOURCE(IDC_ARROW),IMAGE_CURSOR,0,0,LR_DEFAULTSIZE | LR_SHARED), 
		(HBRUSH)GetStockObject(WHITE_BRUSH), NULL, WC_BASIC , NULL};

	// シンプルウィンドウクラス作成
	if(!RegisterClassEx(&wcex)) 
		return false;

	// ウィンドウ幅、高さはディスプレイに依存する。普通は4:3
	const int WINDOW_WIDTH = 640;
	const int WINDOW_HEIGHT = 480;
	// ウィンドウの作成
	HWND hWnd = CreateWindowEx(0,WC_BASIC,
		_T("Application"), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE,CW_USEDEFAULT,
		CW_USEDEFAULT,WINDOW_WIDTH,WINDOW_HEIGHT,NULL,NULL,hInstance,NULL);

	
	////////////////////////////////
	// DirectSoundデバイス作成
	////////////////////////////////

	IDirectSound8*	pDirectSound8 = NULL;	// DirectSoundデバイス
	
	// サウンドデバイス作成
	DirectSoundCreate8(NULL, &pDirectSound8, NULL);	
	// 協調レベルのセット(ここで音を鳴らすウィンドウを指定する必要がある)
	if (FAILED(pDirectSound8->SetCooperativeLevel(hWnd, DSSCL_PRIORITY)))
	{
		// 失敗
		return -1;
	}

	///////////////////////////////////////////////
	//	Waveファイル読込み
	///////////////////////////////////////////////

	const TCHAR*		FileName = _T("battle.wav");// 再生したいWaveファイル
	
	WAVEFORMATEX		WaveFormat;					// Waveフォーマット
	byte*			WaveData;					// 音の生データ
	int			DataSize;					// データサイズ

	// バイナリ読み込みモードで開く
	FILE* fp;
	if (!(fp = ::_tfopen(FileName, _T("rb") )))
		return false;

	char chunkId[5] = {};
	char tmp[5] = {};
	unsigned int chunkSize = 0;

	// RIFFチャンク読み込み
	fread(chunkId, sizeof(char) * 4, 1, fp);
	fread(&chunkSize, sizeof(unsigned int), 1, fp);
	fread(tmp, sizeof(char) * 4, 1, fp);
	if (strcmp(chunkId, "RIFF") || strcmp(tmp, "WAVE")){
		return -1;	// WAVファイルじゃない
	}

	// 子チャンク読み込み
	bool fmtchunk	= false;
	bool datachunk	= false;
	while (true)
	{
		fread(chunkId, sizeof(char) * 4, 1, fp);
		fread(&chunkSize, sizeof(unsigned int), 1, fp);
		if (!strcmp(chunkId, "fmt "))
		{
			if (chunkSize >= sizeof(WAVEFORMATEX))
			{
				fread(&WaveFormat, sizeof(WAVEFORMATEX), 1, fp);
				int diff = chunkSize - sizeof(WAVEFORMATEX);
				fseek(fp, diff, SEEK_CUR);
			}
			else
			{
				memset(&WaveFormat, 0, sizeof(WAVEFORMATEX));
				fread(&WaveFormat, chunkSize, 1, fp);
			}
			fmtchunk = true;
		}
		else if (!strcmp(chunkId, "data"))
		{
			// データサイズ確保
			DataSize = chunkSize;
			WaveData = new byte[chunkSize];
			// データ読み込み
			if (fread(WaveData, sizeof(byte), chunkSize, fp) != chunkSize)
			{
				fclose(fp);
				return -1;	// ファイルが壊れている
			}
			datachunk = true;
		}
		else
		{
			fseek(fp, chunkSize, SEEK_CUR);
		}

		if (fmtchunk && datachunk)
			break;

		// ファイルサイズチェックも行なった方がいいかも
	}

	fclose(fp);

	///////////////////ファイル読込みはここまで

	/////////////////////////////////
	//	セカンダリバッファの作成
	//	(読み込んだ音データをコピー)
	/////////////////////////////////

	IDirectSoundBuffer8*	pSecondaryBuffer;	// セカンダリバッファ
	DSBUFFERDESC			desc = {};			// セカンダリバッファ作成用設定
	
	// チャンネル数での分岐、モノラルは1チャンネル、ステレオは2チャンネル
	if(WaveFormat.nChannels == 1){
		desc.dwFlags =  DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY |
			DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_STATIC;	
		desc.guid3DAlgorithm = DS3DALG_NO_VIRTUALIZATION;
	}
	else{
		desc.dwFlags =  DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | 
			DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_CTRLPAN | DSBCAPS_STATIC;   
		// | DSBCAPS_CTRLFX;	エフェクトを追加すると Duplicate できない
		desc.guid3DAlgorithm = GUID_NULL;	
	}
	desc.dwSize	= sizeof(DSBUFFERDESC);
	desc.dwBufferBytes		= DataSize;			// 音データサイズ指定
	desc.lpwfxFormat		= &WaveFormat;		// フォーマット指定

	IDirectSoundBuffer*	pPrimaryBuffer = NULL;	// プライマリバッファ
	// プライマリバッファ作成
	pDirectSound8->CreateSoundBuffer(&desc,&pPrimaryBuffer,NULL);
	// プライマリバッファからセカンダリバッファ作成
	pPrimaryBuffer->QueryInterface(IID_IDirectSoundBuffer8, (void**)&pSecondaryBuffer);
	pPrimaryBuffer->Release();	// セカンダリバッファが作成できれば、プライマリバッファは破棄してかまわない

	unsigned char* block1		= NULL;
	unsigned char* block2		= NULL;
	unsigned long blockSize1	= 0;
	unsigned long blockSize2	= 0;
	// セカンダリバッファをロックしてデータ書き込み
	pSecondaryBuffer->Lock(0, DataSize, 
		(void**)&block1, &blockSize1, (void**)&block2, &blockSize2, DSBLOCK_ENTIREBUFFER); 
	// セカンダリバッファに音データコピー
	memcpy(block1, WaveData, DataSize);
	// セカンダリバッファロック解除
	pSecondaryBuffer->Unlock(block1, blockSize1, block2, 0);

	///////////////////////////////////////////
	// メッセージループ
	///////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
	// サウンド再生
	pSecondaryBuffer->Play(0,0,0);
	// ループ再生
	//pSecondaryBuffer->Play(0,0,DSBPLAY_LOOPING);
/////////////////////////////////////////////////////////////////////////////

	MSG msg = {}; 
	while(msg.message != WM_QUIT) {
		// アプリケーションに送られてくるメッセージをメッセージキューから取得する
		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
			DispatchMessage(&msg);	// アプリケーションの各ウィンドウプロシージャにメッセージを転送する
		}
		// メッセージ処理をしていないとき
		else{
		}
	}

	//////////////////////////////////////////
	
	pSecondaryBuffer->Stop();	// セカンダリバッファは破棄する前に再生停止すること

	// DirectXの変数は必ず後処理をすること
	pSecondaryBuffer->Release();
	delete[] WaveData;
	pDirectSound8->Release();

	return 0;
}

今回の実行結果はサウンド再生なので
サウンドが流れていたらうまくいってます

前:DirectX講座10回
次:DirectX講座12回

選択肢 投票
(^ω^)♪ 4  
わけがわからないよ 18  
もう、なにも怖くない 11  

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS