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

WaveGraph.cpp
// WaveGraph5 Waveファイルグラフ表示
 
#pragma comment(lib, "winmm")
 
#include <Windows.h>
#include <tchar.h>
 
#define SAFE_FREE(p)	if (p) { free(p); p = NULL; }
#define APP_NAME	TEXT("WaveGraph")
 
// 関数プロトタイプ宣言
void Trace(LPCTSTR format, ...);
BOOL Load(LPTSTR pszFileName);
BOOL ReadWaveFile(LPTSTR pszFileName);
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void ScrollInfo(HWND hWnd);
void OnDropFiles(HWND hWnd, WPARAM wParam);
void OnSize(HWND hWnd, WPARAM wParam, LPARAM lParam);
void OnHScroll(HWND hWnd, WPARAM wParam);
void OnPaint(HWND hWnd);
void PaintWaveform(HDC hdc, LONG top, LONG bottom, RECT rcPaint, int ch);
void SetTitle(HWND hWnd);
 
// 外部変数
SCROLLINFO siHorz;
PBYTE waveformData = NULL;
int waveformLen = 0;
WAVEFORMATEX wfx;
TCHAR szFileName[MAX_PATH];
 
//==============================================================================
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
{
	// プログラム引数
	LPTSTR lpCmdLine = GetCommandLine();
	int argc;
	LPTSTR *argv = CommandLineToArgvW(lpCmdLine, &argc);
	if (2 <= argc) {
		Load(argv[1]);
	}
 
	// ウィンドウクラスの登録
	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 = CreateWindowEx(
		WS_EX_ACCEPTFILES,
		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);
	SetTitle(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"));
	}
}
 
BOOL Load(LPTSTR pszFileName)
{
	BOOL br = ReadWaveFile(pszFileName);
	_tcscpy_s(szFileName, pszFileName);
	return br;
}
 
BOOL ReadWaveFile(LPTSTR pszFileName)
{
	MMRESULT mmr;
 
	SAFE_FREE(waveformData);
	waveformLen = 0;
 
	// Open
	HMMIO hmmio = mmioOpen(pszFileName, NULL, MMIO_READ);
	if (hmmio == NULL) {
		return FALSE;
	}
 
	// RIFFチャンク
	MMCKINFO ckParent;
	ckParent.fccType = mmioFOURCC('W','A','V','E');
	mmr = mmioDescend(hmmio, &ckParent, NULL, MMIO_FINDRIFF);
	if (mmr != MMSYSERR_NOERROR) {
		return FALSE;
	}
 
	// fmtチャンク
	MMCKINFO ckSub;
	ckSub.ckid = mmioFOURCC('f','m','t',' ');
	mmr = mmioDescend(hmmio, &ckSub, &ckParent, MMIO_FINDCHUNK);
	if (mmr != MMSYSERR_NOERROR) {
		return FALSE;
	}
 
	LONG read = mmioRead(hmmio, (HPSTR)&wfx, 16);
	if (read != 16) {
		return FALSE;
	}
 
	mmioAscend(hmmio, &ckSub, 0);
 
	// dataチャンク
	ckSub.ckid = mmioFOURCC('d','a','t','a');
	mmr = mmioDescend(hmmio, &ckSub, &ckParent, MMIO_FINDCHUNK);
	if (mmr != MMSYSERR_NOERROR) {
		return FALSE;
	}
 
	waveformData = (PBYTE)malloc(ckSub.cksize);
	if (waveformData == NULL) {
		return FALSE;
	}
 
	read = mmioRead(hmmio, (HPSTR)waveformData, ckSub.cksize);
	if (read != ckSub.cksize) {
		return FALSE;
	}
 
	waveformLen = ckSub.cksize / wfx.nBlockAlign;
 
	mmioAscend(hmmio, &ckSub, 0);
 
	// RIFFチャンク
	mmioAscend(hmmio, &ckParent, 0);
 
	// Close
	mmioClose(hmmio, 0);
 
	return TRUE;
}
 
//------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg) {
	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_DROPFILES:
		OnDropFiles(hWnd, wParam);
		DragFinish((HDROP)wParam);
		return 0;
	case WM_CREATE:
		ScrollInfo(hWnd);
		return 0;
	case WM_DESTROY:
		SAFE_FREE(waveformData);
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
 
void ScrollInfo(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	= waveformLen - 1;
	siHorz.nPage	= rc.right;
	siHorz.nPos	= 0;
	SetScrollInfo(hWnd, SB_HORZ, &siHorz, FALSE);
}
 
void OnDropFiles(HWND hWnd, WPARAM wParam)
{
	HDROP hDrop = (HDROP)wParam;
	TCHAR szFile[MAX_PATH];
	DragQueryFile(hDrop, 0, szFile, _countof(szFile));
	Load(szFile);
	SetTitle(hWnd);
	ScrollInfo(hWnd);
	InvalidateRect(hWnd, NULL, TRUE);
}
 
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);
 
	if (waveformData) {
		switch (wfx.nChannels) {
		case 1:
			PaintWaveform(hdc, rc.top, rc.bottom, ps.rcPaint, 0);
			break;
		case 2:
			LONG center = rc.bottom / 2;
			PaintWaveform(hdc, rc.top, center, ps.rcPaint, 0);
			PaintWaveform(hdc, center + 1, rc.bottom, ps.rcPaint, 1);
			MoveToEx(hdc, 0, center, NULL);
			LineTo(hdc, rc.right, center);
			break;
		}
	}
 
	EndPaint(hWnd, &ps);
}
 
void PaintWaveform(HDC hdc, LONG top, LONG bottom, RECT rcPaint, int ch)
{
	LONG height = bottom - top;
	HPEN pen = CreatePen(PS_SOLID, 0, RGB(0,0,255));
	HGDIOBJ penOld = SelectObject(hdc, pen);
	for (int x = rcPaint.left; x < rcPaint.right; x++) {
		int i = siHorz.nPos + x;
		if (waveformLen <= i) break;
		int y;
		if (wfx.wBitsPerSample == 8) {
			y = top + height * (255 - waveformData[wfx.nChannels * i + ch]) / 256;
		} else {
			y = top + height * (32767 - ((short*)waveformData)[wfx.nChannels * i + ch]) / 65536;
		}
		MoveToEx(hdc, x, top + height / 2, NULL);
		LineTo(hdc, x, y);
	}
	SelectObject(hdc, penOld);
	DeleteObject(pen);
}
 
void SetTitle(HWND hWnd)
{
	if (waveformData == NULL) {
		SetWindowText(hWnd, APP_NAME);
		return;
	}
	TCHAR str[512];
	_stprintf_s(str, _T("%s [%uHz %ubit %uch] - %s"),
		szFileName, wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels, APP_NAME);
	SetWindowText(hWnd, str);
}
 
最終更新:2013年02月16日 21:57