開発環境 Microsoft Visual C++ 2010 Express (SP1)
実行環境 Microsoft Windows XP Home Edition (SP3)
プロジェクトの種類 Win32 プロジェクト
プロジェクト名 FreqMod
アプリケーションの種類 Windows アプリケーション
追加のオプション 空のプロジェクト
文字セット Unicode

参考

FreqMod.cpp
// FreqMod FM音源の原理
 
#pragma comment(lib, "winmm")
 
#define _USE_MATH_DEFINES
 
#include <Windows.h>
#include <tchar.h>
#include <math.h>
 
#define SAFE_FREE(p)	if (p) { free(p); p = NULL; }
#define APP_NAME	TEXT("FreqMod")
#define SAMPLING_RATE	44100
#define A		0x3f	// キャリア振幅
#define C		220	// キャリア周波数
#define B		100	// 変調指数
#define M		440	// モジュレータ周波数
 
// 関数プロトタイプ宣言
void Trace(LPCTSTR format, ...);
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void OnCreate(HWND hWnd);
void OnSize(HWND hWnd, WPARAM wParam, LPARAM lParam);
void OnHScroll(HWND hWnd, WPARAM wParam);
void OnPaint(HWND hWnd);
void OnChar(HWND hWnd, WPARAM wParam, LPARAM lParam);
void Play(HWND hWnd);
void OnWomOpen(void);
void OnWomDone(HWND hWnd);
 
// 外部変数
SCROLLINFO siHorz;
BYTE waveformData[SAMPLING_RATE];
HWAVEOUT hwo;
WAVEHDR wh;
HCURSOR hCursor = NULL;
 
//==============================================================================
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
{
	for (int i = 0; i < SAMPLING_RATE; i++) {
		double t = i / (double)SAMPLING_RATE;
		double FMt = A * sin((2 * M_PI * C * t) + B * sin(2 * M_PI * M * t));
		waveformData[i] = BYTE(128 + FMt);
	}
 
	// ウィンドウクラスの登録
	WNDCLASSEX wcx;
	ZeroMemory(&wcx, sizeof wcx);
	wcx.cbSize		= sizeof wcx;
	wcx.style		= CS_HREDRAW | CS_VREDRAW;
	wcx.lpfnWndProc		= WndProc;
	wcx.hInstance		= hInstance;
	wcx.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcx.hbrBackground	= (HBRUSH)(COLOR_WINDOW + 1);
	wcx.lpszClassName	= APP_NAME;
	if (RegisterClassEx(&wcx) == 0) {
		return 0;
	}
 
	// ウィンドウの作成
	HWND hWnd = CreateWindow(
		APP_NAME, APP_NAME,
		WS_OVERLAPPEDWINDOW | WS_HSCROLL,
		CW_USEDEFAULT, 0,
		CW_USEDEFAULT, 0,
		NULL, NULL, hInstance, NULL);
	if (hWnd == NULL) {
		return 0;
	}
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);
 
	// メッセージループ
	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
 
void Trace(LPCTSTR format, ...)
{
	va_list arg_ptr;
	TCHAR buffer[256];
	int size;
 
	va_start(arg_ptr, format);
	size = _vsntprintf_s(buffer, _countof(buffer), _TRUNCATE, format, arg_ptr);
	va_end(arg_ptr);
	OutputDebugString(buffer);
	if (size < 0) {
		OutputDebugString(_T("...\n"));
	}
}
 
//------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg) {
	case MM_WOM_OPEN:
		OnWomOpen();
		return 0;
	case MM_WOM_DONE:
		OnWomDone(hWnd);
		return 0;
	case WM_PAINT:
		OnPaint(hWnd);
		return 0;
	case WM_HSCROLL:
		OnHScroll(hWnd, wParam);
		return 0;
	case WM_SIZE:
		OnSize(hWnd, wParam, lParam);
		return 0;
	case WM_CHAR:
		OnChar(hWnd, wParam, lParam);
		return 0;
	case WM_CREATE:
		OnCreate(hWnd);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
 
void OnCreate(HWND hWnd)
{
	RECT rc;
	GetClientRect(hWnd, &rc);
 
	siHorz.cbSize	= sizeof siHorz;
	siHorz.fMask	= SIF_RANGE | SIF_PAGE | SIF_POS | SIF_DISABLENOSCROLL;
	siHorz.nMin	= 0;
	siHorz.nMax	= SAMPLING_RATE - 1;
	siHorz.nPage	= rc.right;
	siHorz.nPos	= 0;
	SetScrollInfo(hWnd, SB_HORZ, &siHorz, FALSE);
}
 
void OnSize(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	if (wParam == SIZE_MINIMIZED) return;
 
	siHorz.nPage	= LOWORD(lParam);
	int nPosMax	= max(siHorz.nMax - (int)siHorz.nPage + 1, 0);
	siHorz.nPos	= min(siHorz.nPos, nPosMax);
	SetScrollInfo(hWnd, SB_HORZ, &siHorz, TRUE);
}
 
void OnHScroll(HWND hWnd, WPARAM wParam)
{
	int nPos = siHorz.nPos;
 
	switch (LOWORD(wParam)) {
	case SB_LINEUP:
		nPos -= 10;
		break;
	case SB_LINEDOWN:
		nPos += 10;
		break;
	case SB_PAGEUP:
		nPos -= siHorz.nPage;
		break;
	case SB_PAGEDOWN:
		nPos += siHorz.nPage;
		break;
	case SB_THUMBTRACK:
		SCROLLINFO si;
		si.cbSize	= sizeof si;
		si.fMask	= SIF_TRACKPOS;
		if (GetScrollInfo(hWnd, SB_HORZ, &si) != 0) {
			nPos = si.nTrackPos;
		}
		break;
	}
 
	int nPosMax = max(siHorz.nMax - (int)siHorz.nPage + 1, 0);
	nPos = min(nPos, nPosMax);
	nPos = max(nPos, 0);
	if (nPos == siHorz.nPos) return;
 
	ScrollWindowEx(hWnd, siHorz.nPos - nPos, 0,
		NULL, NULL, NULL, NULL, SW_INVALIDATE | SW_ERASE);
	siHorz.nPos = nPos;
	SetScrollInfo(hWnd, SB_HORZ, &siHorz, TRUE);
	UpdateWindow(hWnd);
}
 
void OnPaint(HWND hWnd)
{
	PAINTSTRUCT ps;
	HDC hdc = BeginPaint(hWnd, &ps);
 
	RECT rc;
	GetClientRect(hWnd, &rc);
//	Trace(_T("OnPaint %d %d\n"), ps.rcPaint.left, ps.rcPaint.right);
 
	// waveform
	HPEN pen = CreatePen(PS_SOLID, 0, RGB(0,0,255));
	HGDIOBJ penOld = SelectObject(hdc, pen);
	for (int x = ps.rcPaint.left; x < ps.rcPaint.right; x++) {
		size_t i = siHorz.nPos + x;
		if (SAMPLING_RATE <= i) break;
		MoveToEx(hdc, x, rc.bottom / 2, NULL);
		LineTo(hdc, x, rc.bottom * (255 - waveformData[i]) / 256);
	}
	SelectObject(hdc, penOld);
	DeleteObject(pen);
 
	EndPaint(hWnd, &ps);
}
 
void OnChar(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	Trace(_T("OnChar %x %x\n"), wParam, lParam);
 
	switch (wParam) {
	case VK_ESCAPE:
		DestroyWindow(hWnd);
		break;
	case 'p':
		Play(hWnd);
		break;
	}
}
 
void Play(HWND hWnd)
{
	if (hCursor) return;
 
	WAVEFORMATEX wf;
	wf.wFormatTag		= WAVE_FORMAT_PCM;
	wf.wBitsPerSample	= 8;
	wf.nChannels		= 1;
	wf.nSamplesPerSec	= SAMPLING_RATE;
	wf.nBlockAlign		= (wf.wBitsPerSample / 8) * wf.nChannels;
	wf.nAvgBytesPerSec	= wf.nSamplesPerSec * wf.nBlockAlign;
	wf.cbSize		= 0;
	MMRESULT mmr = waveOutOpen(&hwo, WAVE_MAPPER, &wf, (DWORD_PTR)hWnd, 0, CALLBACK_WINDOW);
	if (mmr != MMSYSERR_NOERROR) {
		Trace(_T("waveOutOpen\n"));
		return;
	}
 
	HCURSOR hWait = LoadCursor(NULL, IDC_WAIT);
	hCursor = SetCursor(hWait);
	SetClassLong(hWnd, GCL_HCURSOR, (LONG)hWait);
}
 
void OnWomOpen(void)
{
	wh.lpData		= (LPSTR)waveformData;
	wh.dwBufferLength	= SAMPLING_RATE;
	wh.dwBytesRecorded	= 0;
	wh.dwUser		= 0;
	wh.dwFlags		= 0;
	wh.dwLoops		= 0;
	wh.lpNext		= NULL;
	wh.reserved		= 0;
	MMRESULT mmr = waveOutPrepareHeader(hwo, &wh, sizeof wh);
	if (mmr != MMSYSERR_NOERROR) {
		Trace(_T("waveOutPrepareHeader\n"));
		return;
	}
 
	wh.dwFlags		|= WHDR_BEGINLOOP | WHDR_ENDLOOP;
	wh.dwLoops		= 1;
	mmr = waveOutWrite(hwo, &wh, sizeof wh);
	if (mmr != MMSYSERR_NOERROR) {
		Trace(_T("waveOutWrite\n"));
	}
}
 
void OnWomDone(HWND hWnd)
{
	Trace(_T("OnWomDone\n"));
	waveOutReset(hwo);
	waveOutUnprepareHeader(hwo, &wh, sizeof wh);
	waveOutClose(hwo);
 
	SetCursor(hCursor);
	SetClassLong(hWnd, GCL_HCURSOR, (LONG)hCursor);
	hCursor = NULL;
}
 
最終更新:2013年02月20日 08:48