//
//    バッファ切り替えによる音階演奏
//
//         2001/ 5/31 宍戸 輝光
//

#include <windows.h>
#include <math.h>

HINSTANCE hInst;

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HWND hwMain;

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
                    PSTR szCmdLine,int iCmdShow){

	MSG  msg;
	WNDCLASSEX wndclass;

	// ウインドウクラス設定
	wndclass.cbSize        = sizeof(wndclass);
	wndclass.style         = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc   = WndProc;
	wndclass.cbClsExtra    = 0;
	wndclass.cbWndExtra    = 0;
	wndclass.hInstance     = hInstance;
	wndclass.hIcon         = LoadIcon(hInstance,"APP_ICON");
	wndclass.hCursor       = LoadCursor(NULL,IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
	wndclass.lpszMenuName  = NULL;
	wndclass.lpszClassName = "CWindow";
	wndclass.hIconSm       = NULL;

	RegisterClassEx(&wndclass); /* ウインドウクラス登録 */

	hwMain = CreateWindow("CWindow","音階演奏",
	  WS_OVERLAPPEDWINDOW | WS_VISIBLE,CW_USEDEFAULT,CW_USEDEFAULT,
	  280,120,NULL,NULL,hInstance,NULL);

	while (GetMessage(&msg,NULL,0,0)) { /* メッセージループ */

		TranslateMessage(&msg);
		DispatchMessage(&msg);

	}

	return msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {

	static BYTE lpBuf[8][8000];
	static HWAVEOUT hWOut;
	static WAVEHDR wh;
	static WAVEFORMATEX wf;
	static int i,j,n,l,pl[]={0,2,4,5,7,9,11,12};
	static double lfRate,lfFreq[13];

	switch (iMsg) {

	case WM_CREATE:

		n=0;

		/* 半音一つの倍率 */
		lfRate=pow(2,1.0/12.0);

		/* オクターブ4のドの周波数 */
		lfFreq[0]=220*lfRate*lfRate*lfRate;

		for (i=1;i<13;i++)
			lfFreq[i]=lfFreq[i-1]*lfRate;

		for (i=0;i<8;i++) {

			/* 音の波長計算 */
			l=(int)(8000.0/lfFreq[pl[i]]);

			for (j=0;j<8000;j++) { /* 波形データ作成 */

				if ((j % l)<l/2)
					lpBuf[i][j]=192;
				else
					lpBuf[i][j]=64;

			}

		}

		wf.wFormatTag=WAVE_FORMAT_PCM ;
		wf.nChannels=1;
		wf.nSamplesPerSec=8000;
		wf.nAvgBytesPerSec=8000;
		wf.nBlockAlign=1 ;
		wf.wBitsPerSample=8 ;
		wf.cbSize=0 ;

		/* デバイスオープン */
		waveOutOpen(&hWOut,WAVE_MAPPER,&wf,(DWORD)hwnd,0,CALLBACK_WINDOW);

		wh.lpData=lpBuf[0];
		wh.dwBufferLength=8000;
		wh.dwBytesRecorded=0;
		wh.dwUser=0;
		wh.dwFlags=0;
		wh.dwLoops=1;
		wh.lpNext=NULL ;
		wh.reserved=0 ;

		/* オクターブ4のドを出力 */
		waveOutPrepareHeader(hWOut,&wh,sizeof(WAVEHDR));
		waveOutWrite(hWOut,&wh,sizeof(WAVEHDR));
                    
		return 0;

	case MM_WOM_DONE: /* 再生終了 */

		if (n==7) { /* 音階をすべて再生したらデバイスクローズ */

			waveOutClose(hWOut);

			return 0;

		}

		n++; /* 再生バッファのインデックス更新 */

		waveOutUnprepareHeader(hWOut,&wh,sizeof(WAVEHDR));

		/* 再生バッファのアドレス更新 */
		wh.lpData=lpBuf[n];

		/* 新しいバッファのアドレスで再生開始 */
		waveOutPrepareHeader(hWOut,&wh,sizeof(WAVEHDR));
		waveOutWrite(hWOut,&wh,sizeof(WAVEHDR));

		return 0 ;

	case MM_WOM_CLOSE: /* デバイスクローズ */

		waveOutUnprepareHeader(hWOut,&wh,sizeof(WAVEHDR));

		return 0;

	case WM_DESTROY : // 終了処理

		PostQuitMessage(0);

		return 0;

	}

	return DefWindowProc(hwnd,iMsg,wParam,lParam);

}