#include #include #include #include #include #include #include #include #pragma warning( disable : 4996 ) // 無駄な警告を出さなくする #include #pragma warning( default : 4996 ) //メモリリークを調べるために必要。 #if _DEBUG #include #define new ::new( _NORMAL_BLOCK, __FILE__, __LINE__ ) #endif #define WINDOW_WIDTH (640) // ウィンドウの幅 #define WINDOW_HEIGHT (480) // ウィンドウの高さ #define WINDOW_X ((WINDOW_WIDTH + GetSystemMetrics( SM_CXSIZEFRAME )*2)) #define WINDOW_Y ((WINDOW_HEIGHT + GetSystemMetrics( SM_CYSIZEFRAME )*2 + GetSystemMetrics( SM_CYCAPTION ))) #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } HINSTANCE g_hInstance = NULL; // インスタンス・ハンドル HWND g_hWindow = NULL; // ウインドウ・ハンドル const int EVENT_NUM = 4; //イベント通知箇所の数 const DWORD BUF_SIZE = 3000000; //バッファのサイズ const DWORD UP_DATE_SIZE = BUF_SIZE / EVENT_NUM; //一度に更新するバッファのサイズ HANDLE g_Event[EVENT_NUM] = {NULL}; HANDLE g_Thread = NULL; unsigned int g_ThreadID = 0; char *g_pWaveData = NULL; LPDIRECT3D9 g_pD3D = NULL; // Direct3Dインタフェース LPDIRECT3DDEVICE9 g_pD3DDevice = NULL; // Direct3DDeviceインタフェース LPDIRECTSOUND8 g_SoundDevice = NULL; LPDIRECTSOUNDBUFFER g_Primary = NULL; LPDIRECTSOUNDBUFFER g_Secondary = NULL; // セカンダリサウンドバッファ LPDIRECTSOUNDBUFFER8 g_SecondaryBuf = NULL; LPDIRECTSOUNDNOTIFY8 g_Notify = NULL; int g_EventNum = 0; int g_NowEvent = 0; int g_ThreadFlag = 0; DWORD g_OffSet = BUF_SIZE; DWORD g_BufSize = 0; std::string g_FileName = "FunnyClown.wav"; // Waveファイルオープン関数 bool openWave( std::string t_FileName, WAVEFORMATEX &waveFormatEx, char** ppData, DWORD OffSet, DWORD loadSize) { if ( t_FileName.size() == 0 ) return false; HMMIO hMmio = NULL; MMIOINFO mmioInfo; // Waveファイルオープン memset( &mmioInfo, 0, sizeof(MMIOINFO) ); hMmio = mmioOpenA( (LPSTR)t_FileName.c_str(), &mmioInfo, MMIO_READ ); if( !hMmio ) return false; // ファイルオープン失敗 // RIFFチャンク検索 MMRESULT mmRes; MMCKINFO riffChunk; riffChunk.fccType = mmioFOURCC('W', 'A', 'V', 'E'); mmRes = mmioDescend( hMmio, &riffChunk, NULL, MMIO_FINDRIFF ); if( mmRes != MMSYSERR_NOERROR ) { mmioClose( hMmio, 0 ); return false; } // フォーマットチャンク検索 MMCKINFO formatChunk; formatChunk.ckid = mmioFOURCC('f', 'm', 't', ' '); mmRes = mmioDescend( hMmio, &formatChunk, &riffChunk, MMIO_FINDCHUNK ); if( mmRes != MMSYSERR_NOERROR ) { mmioClose( hMmio, 0 ); return false; } DWORD fmsize = formatChunk.cksize; DWORD size = mmioRead( hMmio, (HPSTR)&waveFormatEx, fmsize ); if( size != fmsize ) { mmioClose( hMmio, 0 ); return false; } mmioAscend( hMmio, &formatChunk, 0 ); // データチャンク検索 MMCKINFO dataChunk; dataChunk.ckid = mmioFOURCC('d', 'a', 't', 'a'); mmRes = mmioDescend( hMmio, &dataChunk, &riffChunk, MMIO_FINDCHUNK ); if( mmRes != MMSYSERR_NOERROR ) { mmioClose( hMmio, 0 ); return false; } g_BufSize = dataChunk.cksize; //固定の確保バッファよりも、必要なバッファが少なければ //ストリーミング再生しない。Waveファイル全部読み込む。 if(g_BufSize < loadSize){ if(*ppData == NULL){ *ppData = new char[g_BufSize]; } mmioRead( hMmio, (HPSTR)*ppData, g_BufSize ); return true; } if(*ppData == NULL){ *ppData = new char[ loadSize ]; } //もし、読み込み位置から指定バッファだけ読み込んだ場合、 //Waveデータの終端を越えてしまうのであれば(ループする場合は) if( OffSet + loadSize > g_BufSize){ DWORD dif = (OffSet + loadSize) - dataChunk.cksize; char* t_Data = new char[dif]; //最初に戻った部分を読む。 mmioRead( hMmio, (HPSTR)t_Data, dif ); //読み込み位置(OffSet)までシークする。 DWORD i = dif; if(OffSet > 0){ while(1){ if(i + loadSize < OffSet){ size = mmioRead( hMmio, (HPSTR)*ppData, loadSize ); i += loadSize; }else{ size = mmioRead( hMmio, (HPSTR)*ppData, OffSet - i ); break; } } } //データの最後の部分までを読む。 size = mmioRead( hMmio, (HPSTR)*ppData, dataChunk.cksize - OffSet ); //上記の処理で、バッファが以下の様に書き込まれているので、 //□の部分に、WAVEデータの先頭からの波形データを合体させる。 //■■■□□  ※ "■"は、[現在の読み込み位置〜音声データの最後]までのバッファ。 for(DWORD j = 0; j < dif; j++) { char t = t_Data[j]; DWORD t_Num = dataChunk.cksize - OffSet + j; (*ppData)[t_Num] = t; } delete[] t_Data; t_Data = NULL; }else{ //読み込み位置(OffSet)までシークする。 DWORD i = 0; if(OffSet > 0){ while(1){ if(i + loadSize < OffSet){ size = mmioRead( hMmio, (HPSTR)*ppData, loadSize ); i += loadSize; }else{ size = mmioRead( hMmio, (HPSTR)*ppData, OffSet - i ); break; } } } size = mmioRead( hMmio, (HPSTR)*ppData, loadSize ); } // ハンドルクローズ mmioClose( hMmio, 0 ); return true; } //----------------------------------------------------------------------------- // Name: MsgProc() // Desc: The window's message handler //----------------------------------------------------------------------------- LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { case WM_DESTROY: PostQuitMessage( 0 ); return 0; } return DefWindowProc( hWnd, msg, wParam, lParam ); } //----------------------------------------------------------------------------- // Name: InitApp() // Desc: Initialize Window //----------------------------------------------------------------------------- HRESULT InitApp(HINSTANCE hInstance) { g_hInstance = hInstance; WNDCLASSEX wcex ={sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, MsgProc, 0, 0, g_hInstance, NULL, NULL, (HBRUSH)(COLOR_WINDOW+1), NULL, L"D3D Tutorial", NULL}; if( !RegisterClassEx( &wcex )){ return DXTRACE_ERR(L"InitApp", GetLastError()); } // Create the application's window g_hWindow = CreateWindow( L"D3D Tutorial", L"ゲームプログラミング", WS_OVERLAPPEDWINDOW ^WS_THICKFRAME ^ WS_MAXIMIZEBOX ^ WS_MINIMIZEBOX, 100, 100, WINDOW_X, WINDOW_Y, NULL, NULL, wcex.hInstance, NULL ); if (g_hWindow == NULL) return DXTRACE_ERR(L"InitApp", GetLastError()); return S_OK; } unsigned int _stdcall ThreadFunc(void* t_pParam) { while(1){ if(WaitForSingleObject(g_Event[g_NowEvent], 1) == WAIT_OBJECT_0){ LPVOID lpvPtr1; DWORD dwBytes1; LPVOID lpvPtr2; DWORD dwBytes2; DWORD dwOffset = g_NowEvent*(UP_DATE_SIZE); DWORD dwSoundBytes = UP_DATE_SIZE; if (DS_OK == g_Secondary->Lock(dwOffset, dwSoundBytes, &lpvPtr1, &dwBytes1,&lpvPtr2, &dwBytes2, 0)) { WAVEFORMATEX wFmt; bool t = openWave( g_FileName, wFmt, &g_pWaveData, g_OffSet, UP_DATE_SIZE ); if(t == true){ //waveのデータをコピー memcpy( lpvPtr1, g_pWaveData, dwSoundBytes); } //アンロック g_Secondary->Unlock(lpvPtr1, dwOffset, NULL, 0); if(g_OffSet + UP_DATE_SIZE < g_BufSize){ //ループしない場合 g_OffSet += UP_DATE_SIZE; }else{ //ループする場合、読み込み位置をループさせる。 //バッファ:1000、一度に読み込むサイズ:300、読み込み位置:800 //上記の場合、次の読み込み位置 = 300 - (1000 - 800);→100、となる g_OffSet = UP_DATE_SIZE - (g_BufSize - g_OffSet); } } g_NowEvent = (g_NowEvent + 1) % EVENT_NUM; } if(g_ThreadFlag == 1){ //プログラムが終了するので、とりあえず再生を止めておく。 g_Secondary->Stop(); break; } } return(0); } //----------------------------------------------------------------------------- // Name: InitDirectX() // Desc: Initialize DirectX //----------------------------------------------------------------------------- HRESULT InitDirectX(void){ g_pD3D = Direct3DCreate9(D3D_SDK_VERSION); if(g_pD3D == NULL){ DXTRACE_MSG(L"DirectXDeviceの初期化に失敗しました"); return E_FAIL; } D3DDISPLAYMODE d3ddm; if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))) { DXTRACE_MSG(L"DirectX3DDeviceの初期化に失敗しました"); return E_FAIL; } D3DPRESENT_PARAMETERS d3dpp; ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; d3dpp.EnableAutoDepthStencil = TRUE; d3dpp.AutoDepthStencilFormat = D3DFMT_D16; HRESULT hr = g_pD3D->CreateDevice( D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,g_hWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp,&g_pD3DDevice); if(FAILED(hr)) { hr = g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,g_hWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp,&g_pD3DDevice); if(FAILED(hr)) { hr = g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_REF,g_hWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp,&g_pD3DDevice); if(FAILED(hr)){ DXTRACE_MSG(L"DirectX3DDeviceの初期化に失敗しました"); return E_FAIL; } } } //************* サウンドデバイス作成 ************* DirectSoundCreate8(NULL, &g_SoundDevice, NULL); g_SoundDevice->SetCooperativeLevel(g_hWindow, DSSCL_PRIORITY); //************* Waveファイルオープン ************* WAVEFORMATEX wFmt; DWORD waveSize = 0; if ( !openWave( g_FileName, wFmt, &g_pWaveData, 0, BUF_SIZE ) ){ return 0; } DSBUFFERDESC DSBufferDesc; DSBufferDesc.dwSize = sizeof(DSBUFFERDESC); DSBufferDesc.dwFlags = 0; if(g_BufSize < BUF_SIZE){ DSBufferDesc.dwBufferBytes = g_BufSize; }else{ DSBufferDesc.dwBufferBytes = BUF_SIZE; } DSBufferDesc.dwReserved = 0; DSBufferDesc.lpwfxFormat = &wFmt; DSBufferDesc.guid3DAlgorithm = GUID_NULL; DSBufferDesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 // 再生位置の取得をできるようにします | DSBCAPS_CTRLPOSITIONNOTIFY // 再生位置通知イベントを有効にします | DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS; // このフラグが無いと、非アクティブ状態になったとき再生が止まる //************ セカンダリバッファの作成 ************ if( FAILED(g_SoundDevice->CreateSoundBuffer(&DSBufferDesc, &g_Secondary, NULL)) ) { return -1; } if(g_BufSize > BUF_SIZE){ g_Secondary->QueryInterface( IID_IDirectSoundBuffer8, (void**)&g_SecondaryBuf ); g_SecondaryBuf->QueryInterface( IID_IDirectSoundNotify8, (LPVOID*)&g_Notify ); // イベントオブジェクトを作成する DSBPOSITIONNOTIFY t_PosNotify[EVENT_NUM]; for(int i = 0; i < EVENT_NUM; i++) { g_Event[i] = CreateEvent( NULL, FALSE, FALSE, NULL ); t_PosNotify[i].dwOffset = UP_DATE_SIZE * (i + 1); t_PosNotify[i].hEventNotify = g_Event[i]; } t_PosNotify[EVENT_NUM - 1].dwOffset = BUF_SIZE - 1; t_PosNotify[EVENT_NUM - 1].hEventNotify = g_Event[EVENT_NUM - 1]; g_Notify->SetNotificationPositions(EVENT_NUM, t_PosNotify); SAFE_RELEASE(g_Notify); } //************ バッファに音声データを書き込む ****** LPVOID lpBufLock = 0; //バッファをロックした時に得られるポインタ DWORD dwLength = 0; //バッファのサイズ if (DS_OK == g_Secondary->Lock(0, 0, &lpBufLock, &dwLength, NULL, NULL, DSBLOCK_ENTIREBUFFER)) { //waveのデータをコピー memcpy( lpBufLock, g_pWaveData, dwLength); //アンロック g_Secondary->Unlock(lpBufLock, dwLength, NULL, 0); } //************ プライマリバッファの作成 ************ DSBUFFERDESC dsbdesk; memset(&dsbdesk, 0, sizeof(DSBUFFERDESC)); dsbdesk.dwSize = sizeof(DSBUFFERDESC); dsbdesk.dwFlags = DSBCAPS_PRIMARYBUFFER // プライマリバッファを作る | DSBCAPS_CTRLVOLUME // ボリュームの変更を有効にする | DSBCAPS_CTRLPAN; // パンを有効にする if( FAILED(g_SoundDevice->CreateSoundBuffer(&dsbdesk, &g_Primary, NULL)) ) { return -1; } // プライマリバッファのフォーマットを指定する。 WAVEFORMATEX wfx; memset(&wfx, 0, sizeof(wfx)); wfx.wFormatTag = WAVE_FORMAT_PCM; // 形式(PCM) wfx.nChannels = 2; // チャンネル(2chステレオ) wfx.nSamplesPerSec = 44100; // サンプリングレート(44100Hz) wfx.wBitsPerSample = 16; // 量子化ビット(16bit) wfx.nBlockAlign = 4; // 1サンプリングあたりのバイト数(16bit×2ch) wfx.nAvgBytesPerSec = 176400; // 1秒あたりのバイト数(16bit×2ch×44100Hz) if( FAILED(g_Primary->SetFormat(&wfx)) ) { return -2; } //スレッド作成 g_Thread = (HANDLE)_beginthreadex( NULL, 0, ThreadFunc, NULL, 0, &g_ThreadID); //セットアップ レンダーステート g_pD3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); g_pD3DDevice->SetRenderState( D3DRS_DITHERENABLE, TRUE ); g_pD3DDevice->SetRenderState( D3DRS_ZENABLE, TRUE ); g_pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); g_pD3DDevice->SetRenderState( D3DRS_AMBIENT, 0x33333333 ); g_pD3DDevice->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE ); //ビュー行列作成 D3DXVECTOR3 vEyePt( 0.0f, 0.0f,-4.0f ); D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f ); D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f ); D3DXMATRIXA16 matView; D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec ); g_pD3DDevice->SetTransform( D3DTS_VIEW, &matView ); //射影行列作成 D3DXMATRIXA16 matProj; D3DXMatrixPerspectiveFovLH( &matProj, D3DXToRadian(90.0f), (float)640/480, 1.0f, 100.0f ); g_pD3DDevice->SetTransform( D3DTS_PROJECTION, &matProj ); return S_OK; } //----------------------------------------------------------------------------- // Name: Uninitialize() // Desc: UnInitialize DirectX //----------------------------------------------------------------------------- void Uninitialize(void) { g_ThreadFlag = 1; //スレッド終了まで待つ WaitForSingleObject(g_Thread, INFINITE); if(g_pWaveData != NULL){ delete[] g_pWaveData; g_pWaveData = NULL; } SAFE_RELEASE(g_Primary); SAFE_RELEASE(g_Secondary); SAFE_RELEASE(g_SecondaryBuf); SAFE_RELEASE(g_Notify); SAFE_RELEASE(g_SoundDevice); SAFE_RELEASE(g_pD3DDevice); SAFE_RELEASE(g_pD3D); CloseHandle(g_Thread); for(int i = 0; i < EVENT_NUM; i++){ CloseHandle(g_Event[i]); } } //----------------------------------------------------------------------------- // Name: WinMain() // Desc: The application's entry point //----------------------------------------------------------------------------- int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { #ifdef _DEBUG _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); #endif HRESULT hr; if(FAILED(hr = InitApp(hInstance))) { return(0); } // Initialize Direct3D if( SUCCEEDED(hr = InitDirectX()) ) { MSG msg; ZeroMemory( &msg, sizeof(msg) ); ShowWindow(g_hWindow, SW_SHOWDEFAULT); UpdateWindow(g_hWindow); D3DXMATRIX mat; D3DXMatrixIdentity(&mat); g_pD3DDevice->SetTransform(D3DTS_WORLD, &mat); // Enter the message loop while( msg.message!=WM_QUIT ) { if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); }else{ g_pD3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,60), 1.0f, 0 ); g_pD3DDevice->BeginScene(); if(GetKeyState(VK_RIGHT) < 0){ hr = g_Secondary->Play(0,0,DSBPLAY_LOOPING); } g_pD3DDevice->EndScene(); g_pD3DDevice->Present( NULL, NULL, NULL, NULL ); Sleep(1); } } } Uninitialize(); UnregisterClass( L"D3D Tutorial", g_hInstance ); return 0; }