#include <math.h>
#include <windows.h>
#include <dsound.h>
#include <d3dx9.h>

#pragma comment(lib, "dsound")
#pragma comment(lib, "dxguid")

// ½ÇÆÐÇßÀ» °æ¿ì, ¿¹¿Ü¸¦ ¹ß»ý½ÃÅ²´Ù.
void assert(HRESULT hr)
{
	if (FAILED(hr))
		throw hr;
}

int main(int argc, char* argv[])
{
	HWND hWnd = GetConsoleWindow();
	LPDIRECTSOUND8 pDS8 = NULL;
	LPDIRECTSOUNDBUFFER8 pDSBSin = NULL;

	WAVEFORMATEX fmt;
	fmt.wFormatTag = WAVE_FORMAT_PCM; // PCM
	fmt.nChannels = 1; // ¸ð³ë
	fmt.nSamplesPerSec = 44100; // 44.1KHz
	fmt.wBitsPerSample = 16; // 16ºñÆ®
	fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; // ÇÑ½Ã°£´ÜÀ§´ç ¹ÙÀÌÆ®¼ö
	fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; // ÃÊ´ç ¹ÙÀÌÆ®¼ö
	fmt.cbSize = 0; // ¿©ºÐ µ¥ÀÌÅÍ ¾øÀ½

	__try
	{
		// DirectSound8 °´Ã¼ »ý¼º
		assert(DirectSoundCreate8(NULL, &pDS8, NULL));
		// ..
		assert(pDS8->SetCooperativeLevel(hWnd, DSSCL_PRIORITY));

		DSBUFFERDESC desc;
		desc.dwSize = sizeof(DSBUFFERDESC);
		desc.dwFlags = 0;
		desc.dwBufferBytes = fmt.nAvgBytesPerSec; // 1ÃÊ ±æÀÌ ¹öÆÛ·Î ¸¸µç´Ù..
		desc.dwReserved = 0;
		desc.lpwfxFormat = &fmt;
		desc.guid3DAlgorithm = GUID_NULL;
		
		// ¹öÆÛ »ý¼º
		LPDIRECTSOUNDBUFFER pDSB;
		assert(pDS8->CreateSoundBuffer(&desc, &pDSB, NULL));
		// DS 8¹öÀü ÀÎÅÍÆäÀÌ½º¸¦ °¡Á®¿Â´Ù.
		assert(pDSB->QueryInterface(IID_IDirectSoundBuffer8, (LPVOID*)&pDSBSin));
		// 1¹öÀü°ÍÀº ÇØÁ¦
		assert(pDSB->Release());

		WORD* pAudio;
		DWORD dwSize;
		assert(pDSBSin->Lock(0, 0, (LPVOID*)&pAudio, &dwSize, NULL, NULL, DSBLOCK_ENTIREBUFFER));

		// ¿©·¯°¡Áö ÁÖÆÄ¼öÀÇ »çÀÎÆÄ¸¦ ¸¸µç´Ù.
		float freq[] = { 400.0f, 200.0f, 100.0f, 50.0f };
		// °¢ »çÀÎÆÄÀÇ °è¼ö
		float k[] = { 1.0f, 0.5f, 0.3f, 0.9f };

		int blocks = dwSize / 2;
		int funcs = sizeof(freq) / sizeof(freq[0]);

		// sin ÇÔ¼ö¿¡ ¾Ë¸Â´Â ÇüÅÂ·Î º¯°æ
		// (2 * PI) / sps => 1Hz ÀÌ±â ¶§¹®¿¡
		// ¾Õ¼­ ¼³Á¤ÇÑ °ªÀÇ ÁÖÆÄ¼ö¸¦ °®´Â »çÀÎÆÄ°¡ µÈ´Ù.
		for (int i = 0; i < funcs; i++)
			freq[i] *= 2 * D3DX_PI / fmt.nSamplesPerSec;

		for (int i = 0; i < blocks; i++)
		{
			float v = 0;
			// ÇÔ¼ö ÇÕ¼º
			for (int j = 0; j < funcs; j++)
				v += cosf(freq[j] * i) * k[j];
			// ¹üÀ§¸¦ ³ÑÁö ¾Êµµ·Ï ÇÔ.
			if (v > 1.0f) v = 1.0f;
			else if (v < -1.0f) v= -1.0f;
			// 16ºñÆ®¿¡ ¸Â°Ô.
			pAudio[i] = (WORD)((v + 1.0f) * 0.5f * 0xFFFF);
		}
		assert(pDSBSin->Unlock((LPVOID)pAudio, dwSize, NULL, 0));

		// ¹Ýº¹Àç»ýÇØ º»´Ù.
		assert(pDSBSin->Play(0, 0, DSBPLAY_LOOPING));
		// ÀÔ·ÂÇÒ¶§±îÁö ´ë±â
		MessageBox(NULL, TEXT("111"), NULL, MB_OK);
	}
	__finally
	{
		// º°µµ ¿¹¿Ü Ã³¸® ¾øÀÌ, »ý¼ºµÈ °´Ã¼¸¸ ÇØÁ¦ÇÑ´Ù.
		if (pDSBSin)
		{
			pDSBSin->Stop();
			pDSBSin->Release();
		}
		if (pDS8)
			pDS8->Release();
	}
}

