「C言語/C++/WaveGraph3」の編集履歴(バックアップ)一覧はこちら

C言語/C++/WaveGraph3 - (2013/02/06 (水) 09:33:24) の1つ前との変更点

追加された行は緑色になります。

削除された行は赤色になります。

|開発環境|Microsoft Visual C++ 2010 Express (SP1)| |実行環境|Microsoft Windows XP Home Edition (SP3)| |プロジェクトの種類|Win32 プロジェクト| |プロジェクト名|WaveGraph| |アプリケーションの種類|Windows アプリケーション| |追加のオプション|空のプロジェクト| |文字セット|Unicode| Waveファイル(PCM 11.025kHz 8bit mono)を想定。 WaveGraph.cpp #highlight(cpp){{ // WaveGraph3 Waveファイルグラフ表示(自己相関) #pragma comment(lib, "winmm") #define _USE_MATH_DEFINES #include <Windows.h> #include <tchar.h> #include <math.h> #include <vector> using namespace std; typedef struct { int pos; int waveLen; int noteNum; double vol; } Wave; typedef vector<Wave> VWave; #define SAFE_FREE(p) if (p) { free(p); p = NULL; } #define NORM(b) ((b - 128.0) / 128) #define A4 69 #define APP_NAME TEXT("WaveGraph") // 関数プロトタイプ宣言 void Trace(LPCTSTR format, ...); BOOL Load(LPTSTR pszFileName); BOOL ReadWaveFile(LPTSTR pszFileName); BOOL AnalyzeWave(void); double Volume(int pos, int wl); 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); // 音階 LPCTSTR scale[] = {L"C",L"C#",L"D",L"D#",L"E",L"F",L"F#",L"G",L"G#",L"A",L"A#",L"B"}; // 外部変数 SCROLLINFO siHorz; DWORD sampleLength; PBYTE waveformData = NULL; WAVEFORMATEX wfx; VWave vWave; DWORD sampleLength2; PBYTE waveformData2 = NULL; HWAVEOUT hwo; WAVEHDR wh; HCURSOR hCursor = NULL; //============================================================================== 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 = 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")); } } BOOL Load(LPTSTR pszFileName) { if (ReadWaveFile(pszFileName) == FALSE) { return FALSE; } AnalyzeWave(); return TRUE; } BOOL ReadWaveFile(LPTSTR pszFileName) { MMRESULT mmr; sampleLength = 0; SAFE_FREE(waveformData) // 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; } sampleLength = ckSub.cksize; waveformData = (PBYTE)malloc(ckSub.cksize); if (waveformData == NULL) { return FALSE; } read = mmioRead(hmmio, (HPSTR)waveformData, ckSub.cksize); if (read != ckSub.cksize) { return FALSE; } mmioAscend(hmmio, &ckSub, 0); // RIFFチャンク mmioAscend(hmmio, &ckParent, 0); // Close mmioClose(hmmio, 0); return TRUE; } BOOL AnalyzeWave(void) { for (int pos = 0; pos <= (int)sampleLength - 200 * 2; ) { // 11,025Hz / 55Hz = 200.45 double r = -1; int waveLen; for (int wl = 12; wl <= 200; wl++) { double sum = 0; for (int i = 0; i < wl; i++) { sum += NORM(waveformData[pos + i]) * NORM(waveformData[pos + wl + i]); } sum /= wl; sum *= 1 + 0.1 * log(200.0 / wl) / log(2.0); // 倍音抑制バイアス if (r < sum) { r = sum; waveLen = wl; } } double freq = (double)wfx.nSamplesPerSec / waveLen; double d = A4 + 12 * log(freq / 440) / log(2.0); Wave wave; wave.pos = pos; wave.waveLen = waveLen; wave.noteNum = int(d + 0.5); wave.vol = Volume(pos, waveLen); vWave.push_back(wave); pos += waveLen; } sampleLength2 = 0; for (VWave::iterator it = vWave.begin(); it != vWave.end(); it++) { sampleLength2 += it->waveLen; } waveformData2 = (PBYTE)malloc(sampleLength2); int pos = 0; for (VWave::iterator it = vWave.begin(); it != vWave.end(); it++) { for (int i = 0; i < it->waveLen; i++) { double t = i / (double)it->waveLen; double y = t < 0.5 ? 1 : -1; // double y = sin(2 * M_PI * t); waveformData2[pos + i] = BYTE(128 + 127 * it->vol * y); } pos += it->waveLen; } return TRUE; } // 音量 double Volume(int pos, int wl) { double sum = 0; for (int i = 0; i < wl; i++) { sum += abs(NORM(waveformData[pos + i])); } return sum / wl; } //------------------------------------------------------------------------------ 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: SAFE_FREE(waveformData) SAFE_FREE(waveformData2) 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 = sampleLength - 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 (sampleLength <= i) break; MoveToEx(hdc, x, rc.bottom / 2, NULL); LineTo(hdc, x, rc.bottom * (255 - waveformData[i]) / 256); } SelectObject(hdc, penOld); DeleteObject(pen); // waveform2 pen = CreatePen(PS_SOLID, 0, RGB(0,255,0)); penOld = SelectObject(hdc, pen); for (int x = ps.rcPaint.left; x < ps.rcPaint.right; x++) { size_t i = siHorz.nPos + x; if (sampleLength2 <= i) break; int y = rc.bottom * (255 - waveformData2[i]) / 256; MoveToEx(hdc, x, y, NULL); LineTo(hdc, x, y + 1); } SelectObject(hdc, penOld); DeleteObject(pen); // waveLen pen = CreatePen(PS_SOLID, 0, RGB(255,0,0)); penOld = SelectObject(hdc, pen); for (VWave::iterator it = vWave.begin(); it != vWave.end(); it++) { int x = it->pos - siHorz.nPos; if (x + it->waveLen < 0 || rc.right <= x) continue; MoveToEx(hdc, x, 0, NULL); LineTo(hdc, x, rc.bottom); TCHAR buf[4+1]; _stprintf_s(buf, _T("%d"), it->waveLen); TextOut(hdc, x, 0, buf, _tcslen(buf)); _stprintf_s(buf, _T("%s%d"), scale[it->noteNum % 12], it->noteNum / 12 - 1); TextOut(hdc, x, 16, buf, _tcslen(buf)); } 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 = wfx.nSamplesPerSec; 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)waveformData2; wh.dwBufferLength = sampleLength2; 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; } }}
|開発環境|Microsoft Visual C++ 2010 Express (SP1)| |実行環境|Microsoft Windows XP Home Edition (SP3)| |プロジェクトの種類|Win32 プロジェクト| |プロジェクト名|WaveGraph| |アプリケーションの種類|Windows アプリケーション| |追加のオプション|空のプロジェクト| |文字セット|Unicode| Waveファイル(PCM 11.025kHz 8bit mono)を想定。 WaveGraph.cpp #highlight(cpp){{ // WaveGraph3 Waveファイルグラフ表示(自己相関) #pragma comment(lib, "winmm") #define _USE_MATH_DEFINES #include <Windows.h> #include <tchar.h> #include <math.h> #include <vector> using namespace std; typedef struct { int pos; int waveLen; int noteNum; double vol; } Wave; typedef vector<Wave> VWave; #define SAFE_FREE(p) if (p) { free(p); p = NULL; } #define NORM(b) ((b - 128.0) / 128) #define log2(x) (log(x) / log(2.0)) #define A4 69 #define APP_NAME TEXT("WaveGraph") // 関数プロトタイプ宣言 void Trace(LPCTSTR format, ...); BOOL Load(LPTSTR pszFileName); BOOL ReadWaveFile(LPTSTR pszFileName); BOOL AnalyzeWave(void); double Volume(int pos, int wl); 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); // 音階 LPCTSTR scale[] = {L"C",L"C#",L"D",L"D#",L"E",L"F",L"F#",L"G",L"G#",L"A",L"A#",L"B"}; // 外部変数 SCROLLINFO siHorz; DWORD sampleLength; PBYTE waveformData = NULL; WAVEFORMATEX wfx; VWave vWave; DWORD sampleLength2; PBYTE waveformData2 = NULL; HWAVEOUT hwo; WAVEHDR wh; HCURSOR hCursor = NULL; //============================================================================== 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 = 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")); } } BOOL Load(LPTSTR pszFileName) { if (ReadWaveFile(pszFileName) == FALSE) { return FALSE; } AnalyzeWave(); return TRUE; } BOOL ReadWaveFile(LPTSTR pszFileName) { MMRESULT mmr; sampleLength = 0; SAFE_FREE(waveformData) // 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; } sampleLength = ckSub.cksize; waveformData = (PBYTE)malloc(ckSub.cksize); if (waveformData == NULL) { return FALSE; } read = mmioRead(hmmio, (HPSTR)waveformData, ckSub.cksize); if (read != ckSub.cksize) { return FALSE; } mmioAscend(hmmio, &ckSub, 0); // RIFFチャンク mmioAscend(hmmio, &ckParent, 0); // Close mmioClose(hmmio, 0); return TRUE; } BOOL AnalyzeWave(void) { for (int pos = 0; pos <= (int)sampleLength - 200 * 2; ) { // 11,025Hz / 55Hz = 200.45 double r = -1; int waveLen; for (int wl = 12; wl <= 200; wl++) { double sum = 0; for (int i = 0; i < wl; i++) { sum += NORM(waveformData[pos + i]) * NORM(waveformData[pos + wl + i]); } sum /= wl; // 倍音抑制バイアス // sum *= 1 + 0.1 * log(200.0 / wl) / log(2.0); sum *= pow(1.1, log2((double)200 / wl)); if (r < sum) { r = sum; waveLen = wl; } } double freq = (double)wfx.nSamplesPerSec / waveLen; double d = A4 + 12 * log2(freq / 440); Wave wave; wave.pos = pos; wave.waveLen = waveLen; wave.noteNum = int(d + 0.5); wave.vol = Volume(pos, waveLen); vWave.push_back(wave); pos += waveLen; } sampleLength2 = 0; for (VWave::iterator it = vWave.begin(); it != vWave.end(); it++) { sampleLength2 += it->waveLen; } waveformData2 = (PBYTE)malloc(sampleLength2); int pos = 0; for (VWave::iterator it = vWave.begin(); it != vWave.end(); it++) { for (int i = 0; i < it->waveLen; i++) { double t = i / (double)it->waveLen; double y = t < 0.5 ? 1 : -1; // double y = sin(2 * M_PI * t); waveformData2[pos + i] = BYTE(128 + 127 * it->vol * y); } pos += it->waveLen; } return TRUE; } // 音量 double Volume(int pos, int wl) { double sum = 0; for (int i = 0; i < wl; i++) { sum += abs(NORM(waveformData[pos + i])); } return sum / wl; } //------------------------------------------------------------------------------ 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: SAFE_FREE(waveformData) SAFE_FREE(waveformData2) 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 = sampleLength - 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 (sampleLength <= i) break; MoveToEx(hdc, x, rc.bottom / 2, NULL); LineTo(hdc, x, rc.bottom * (255 - waveformData[i]) / 256); } SelectObject(hdc, penOld); DeleteObject(pen); // waveform2 pen = CreatePen(PS_SOLID, 0, RGB(0,255,0)); penOld = SelectObject(hdc, pen); for (int x = ps.rcPaint.left; x < ps.rcPaint.right; x++) { size_t i = siHorz.nPos + x; if (sampleLength2 <= i) break; int y = rc.bottom * (255 - waveformData2[i]) / 256; MoveToEx(hdc, x, y, NULL); LineTo(hdc, x, y + 1); } SelectObject(hdc, penOld); DeleteObject(pen); // waveLen pen = CreatePen(PS_SOLID, 0, RGB(255,0,0)); penOld = SelectObject(hdc, pen); for (VWave::iterator it = vWave.begin(); it != vWave.end(); it++) { int x = it->pos - siHorz.nPos; if (x + it->waveLen < 0 || rc.right <= x) continue; MoveToEx(hdc, x, 0, NULL); LineTo(hdc, x, rc.bottom); TCHAR buf[4+1]; _stprintf_s(buf, _T("%d"), it->waveLen); TextOut(hdc, x, 0, buf, _tcslen(buf)); _stprintf_s(buf, _T("%s%d"), scale[it->noteNum % 12], it->noteNum / 12 - 1); TextOut(hdc, x, 16, buf, _tcslen(buf)); } 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 = wfx.nSamplesPerSec; 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)waveformData2; wh.dwBufferLength = sampleLength2; 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; } }}

表示オプション

横に並べて表示:
変化行の前後のみ表示: