// // Copyright (c) 2013 _iTo_ // #include #include "resource.h" #define WAVEHEADER 44 typedef union ShortData{ unsigned char c[2]; short s; }SHORTDATA; typedef union LongData{ unsigned char c[4]; short s; long l; }LONGDATA; void MaxMin(char *rowdata, WORD BitsPerSample, DWORD dw, DWORD lenge, int offset, long *low, long *hi) { SHORTDATA sdata; LONGDATA ldata; long s; for(int lp=0; lp < lenge;lp+=offset,dw+=offset){ if(BitsPerSample==16){ sdata.c[0] = rowdata[dw]; sdata.c[1] = rowdata[dw+1]; s = sdata.s; if(lp==0){*low=*hi=s;} }else if(BitsPerSample==32){ ldata.c[0] = rowdata[dw]; ldata.c[1] = rowdata[dw+1]; ldata.c[2] = rowdata[dw+2]; ldata.c[3] = rowdata[dw+3]; s = ldata.l;//>>16; if(lp==0){*low=*hi=s;} } if(s < *low) *low = s; if(s > *hi) *hi = s; } // 表示画面は座標が上から下に数が増える為、振幅値を+−逆にする。 *low *= -1; *hi *= -1; } boolean OpenFile(HWND hWnd, char *szFileName) { OPENFILENAME ofn; char szFile[MAX_PATH]; boolean ret = true; memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.lpstrFilter = "wavファイル(*.wav)\0*.wav\0\0"; ofn.lpstrFile = szFileName; ofn.lpstrFileTitle = szFile; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrTitle = "Waveファイルを選択"; if(GetOpenFileName(&ofn) == 0) ret = false; return ret; } HDC MakeBmpBord(HWND hWnd,RECT rect) { HDC hBmpDC; HDC hdcbmp; HBITMAP hBitmap; HBRUSH hBrush; hdcbmp=GetDC(hWnd); hBitmap=CreateCompatibleBitmap(hdcbmp,rect.right,rect.bottom); hBmpDC=CreateCompatibleDC(hdcbmp); ReleaseDC(hWnd,hdcbmp); SelectObject(hBmpDC,hBitmap); DeleteObject(hBitmap); // 背景色 hBrush= CreateSolidBrush(RGB(0xa0,0xa0,0xa0)); SelectObject(hBmpDC,hBrush); Rectangle( hBmpDC, rect.left-1, rect.top-1, rect.right+1, rect.bottom+1 ); return hBmpDC; } INT_PTR CALLBACK About(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { RECT pRect,rect; UNREFERENCED_PARAMETER(lParam); switch (uMsg){ case WM_INITDIALOG: GetWindowRect(GetParent(hDlg) , (LPRECT)&pRect); // メインウインドの表示位置取得 GetClientRect(GetParent(hDlg) , &rect); // 〃 のウインドサイズ取得 SetWindowPos(hDlg, NULL, pRect.left+(rect.right/2)-100, pRect.top+(rect.bottom/2)-30, 0, 0, SWP_NOSIZE|SWP_NOZORDER); return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL){ EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; } LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { // ウインド HINSTANCE hInst; static HWND hWndPlotL; // Channel#1音声レベルウインド static HWND hWndPlotR; // Channel#2音声レベルウインド RECT rect,rectL,rectR; // ちらつき防止 HDC LhBmpDC; HDC RhBmpDC; PAINTSTRUCT ps; HDC hdc; HPEN hPen; // WAVEファイル HANDLE hFile; char szFileName[80] = {0}; static DWORD waveFsize = 0; int i,j,pointLength; char *errmsg = NULL; // WAVEデータ static char *waveptr= (char *)NULL; static WAVEFORMATEX wf = {0}; // 波形の線 static POINT *pointL = (POINT *)NULL; static POINT *pointR = (POINT *)NULL; static long scaleSize; DWORD lenge; long Llow,Rlow; long Lhi, Rhi; OPENFILENAME ofn; char szFile[MAX_PATH]; switch (uMsg) { case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_ABOUT: DialogBox((HINSTANCE)GetWindowLong( hWnd , GWL_HINSTANCE ), MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, (DLGPROC)About); break; case IDM_END: SendMessage(hWnd, WM_DESTROY, 0, 0); break; case IDM_OPEN: if(pointL != NULL) free(pointL); if(pointR != NULL) free(pointR); if(waveptr != NULL) free(waveptr); memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.lpstrFilter = "wavファイル(*.wav)\0*.wav\0\0"; // "All files(*.*)\0*.*\0\0"; ofn.lpstrFile = szFileName; ofn.lpstrFileTitle = szFile; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrTitle = "Waveファイルを選択"; if(GetOpenFileName(&ofn)/*OpenFile(hWnd,szFileName)*/){ hFile = CreateFile( szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( hFile != INVALID_HANDLE_VALUE ){ waveFsize = GetFileSize(hFile , NULL); waveptr = (char *)calloc(waveFsize, 2); if(waveptr != NULL){ ReadFile( hFile, waveptr, waveFsize, &waveFsize, NULL ); if(strncmp(&waveptr[8],"WAVE",4)==NULL){ CopyMemory(&wf,&waveptr[20],sizeof(WAVEFORMATEX)); if((wf.wBitsPerSample == 16) || (wf.wBitsPerSample == 32)){ if(wf.wFormatTag == WAVE_FORMAT_PCM){ pointL = (POINT *)calloc(waveFsize/wf.nChannels, sizeof(POINT)); pointR = (POINT *)calloc(waveFsize/wf.nChannels, sizeof(POINT)); if(pointL==NULL || pointR==NULL) errmsg = "波形表示バッファが確保できませんでした。"; }else errmsg = "PCM形式ファイルではありません。"; }else errmsg = "サポートされていないサンプリングです。"; }else errmsg = "WAVEファイルではありません。"; }else errmsg = "WAVEデータバッファが確保できませんでした。"; CloseHandle(hFile); }else errmsg = "ファイルのハンドル確保に失敗しました。"; }else errmsg = "ファイル選択に失敗しました。"; if(errmsg != NULL){ MessageBox(NULL, TEXT(errmsg), NULL, MB_ICONWARNING); SendMessage(hWnd, WM_DESTROY, 0, 0); }else{ InvalidateRect(hWnd, NULL, FALSE); UpdateWindow(hWnd); } break; default: break; } break; case WM_CREATE: hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE); GetClientRect(hWnd , &rect); // 左ウインド hWndPlotL = CreateWindowEx(WS_EX_STATICEDGE, "STATIC", "", WS_CHILD | WS_VISIBLE, rect.top, 0, rect.right, rect.bottom/2-1, hWnd, (HMENU)89, hInst, NULL); // 右ウインド hWndPlotR = CreateWindowEx(WS_EX_STATICEDGE, "STATIC", "", WS_CHILD | WS_VISIBLE | SS_BITMAP, rect.top, rect.bottom/2+1, rect.right, rect.bottom/2-1, hWnd, (HMENU)90, hInst, NULL); break; case WM_SIZE: GetClientRect(hWnd , &rect); MoveWindow(hWndPlotL, rect.top, 0, rect.right, rect.bottom/2-1, TRUE); MoveWindow(hWndPlotR, rect.top, rect.bottom/2+1, rect.right, rect.bottom/2-1, TRUE); break; case WM_PAINT: // 描画用BMP用意 GetClientRect(hWndPlotL , &rectL); LhBmpDC = MakeBmpBord(hWndPlotL, rectL); // 左 BMP GetClientRect(hWndPlotR , &rectR); RhBmpDC = MakeBmpBord(hWndPlotR, rectR); // 右 BMP // ペン用意 hPen = CreatePen(PS_SOLID, 1, RGB(0x32,0x32,0xc8)); // 振幅値をY座標の幅に縮尺 if(wf.wBitsPerSample == 16) scaleSize=(0x1<<9); else if(wf.wBitsPerSample == 32) scaleSize=(0x1<<25); // 波形作成 if(wf.nChannels == 1){ SelectObject(LhBmpDC,hPen); pointLength = rectL.right - rectL.left; lenge = (waveFsize-WAVEHEADER) / pointLength;// * 2; // x2はhiとlowのPOINT分 for(i=0,j=WAVEHEADER; i < pointLength*2 ;i++,j+=lenge){ MaxMin(waveptr, wf.wBitsPerSample, j, lenge, wf.wBitsPerSample/8*2, &Llow, &Lhi); pointL[i].x = i; pointL[i].y = (Lhi / scaleSize)+rectL.bottom/2; i++; pointL[i].x = i-1; pointL[i].y = (Llow/ scaleSize)+rectL.bottom/2; } Polyline(LhBmpDC , pointL , i); // 右は直線を引いておく SelectObject(RhBmpDC,hPen); pointLength = rectR.right - rectR.left; for(i=0,j=WAVEHEADER; i < pointLength ;i++){ pointR[i].x = i; pointR[i].y = rectR.bottom/2; } Polyline(RhBmpDC , pointR , i); }else if(wf.nChannels == 2){ SelectObject(LhBmpDC,hPen); SelectObject(RhBmpDC,hPen); pointLength = rectL.right - rectL.left; lenge = (waveFsize-WAVEHEADER) / pointLength * 2; // x2はhiとlowのPOINT分 for(i=0,j=WAVEHEADER; i < pointLength*2 ;i++,j+=lenge){ MaxMin(waveptr, wf.wBitsPerSample, j, lenge, wf.wBitsPerSample/8*2, &Llow, &Lhi); MaxMin(waveptr, wf.wBitsPerSample, j+4, lenge, wf.wBitsPerSample/8*2, &Rlow, &Rhi); pointL[i].x = pointR[i].x = i; pointL[i].y = (Lhi / scaleSize)+rectL.bottom/2; pointR[i].y = (Rhi / scaleSize)+rectR.bottom/2; i++; pointL[i].x = pointR[i].x = i-1; pointL[i].y = (Llow/ scaleSize)+rectL.bottom/2; pointR[i].y = (Rlow/ scaleSize)+rectR.bottom/2; } Polyline(LhBmpDC , pointL , i); Polyline(RhBmpDC , pointR , i); } // 描画 if(LhBmpDC != (HDC)NULL){ hdc = BeginPaint(hWndPlotL, &ps); BitBlt(hdc,rectL.left,rectL.top,rectL.right,rectL.bottom,LhBmpDC,rectL.left,rectL.top,SRCCOPY); EndPaint(hWndPlotL , &ps); } if(RhBmpDC != (HDC)NULL){ hdc = BeginPaint(hWndPlotR, &ps); BitBlt(hdc,rectR.left,rectR.top,rectR.right,rectR.bottom,RhBmpDC,rectR.left,rectR.top,SRCCOPY); EndPaint(hWndPlotL , &ps); } DeleteDC(LhBmpDC); DeleteDC(RhBmpDC); break; case WM_DESTROY: if(pointL != NULL) free(pointL); if(pointR != NULL) free(pointR); if(waveptr != NULL) free(waveptr); DestroyWindow(hWnd); PostQuitMessage(0); break; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { char szClassName[] = "WaveCreate"; //ウィンドウクラス MSG msg; WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; //インスタンス wc.hIcon = LoadIcon(NULL , IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0xf0,0xf0,0xf0)); //ウインドの背景色 wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!RegisterClassEx(&wc)) return 0; HWND hWnd = CreateWindow(szClassName, "WaveCreate", //タイトルバー表示 WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 1000, //幅 400, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInstance, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }