// // Copyright (c) 2013 _iTo_ // #include #include "resource.h" 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; } 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; } void idm_stop(HWND hWnd, HWAVEOUT hwo, WAVEHDR wh) { KillTimer(hWnd, IDC_TIMER); waveOutReset(hwo); waveOutUnprepareHeader(hwo, &wh, sizeof(WAVEHDR)); waveOutClose(hwo); } 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; } HFONT SetMyFont(LPCTSTR face, int h, int angle, int fnWeight) { HFONT hFont; hFont = CreateFont(h, //フォント高さ 0, //文字幅 angle, //テキストの角度 0, //ベースラインとx軸との角度 fnWeight, //フォントの重さ(太さ) FALSE, //イタリック体 FALSE, //アンダーライン FALSE, //打ち消し線 SHIFTJIS_CHARSET, //文字セット OUT_DEFAULT_PRECIS, //出力精度 CLIP_DEFAULT_PRECIS, //クリッピング精度 PROOF_QUALITY, //出力品質 FIXED_PITCH | FF_MODERN,//ピッチとファミリー face); //書体名 return hFont; } void scaleLine(HWND hWnd,RECT rect,HFONT hFont, int wBitsPerSample) { PAINTSTRUCT ps; HDC hdc; TCHAR str[16]; int dBlow=-192,dBmiddle=-96; if(wBitsPerSample == 16){ dBlow = -96; dBmiddle = -48; }else if(wBitsPerSample == 32){ dBlow = -192; dBmiddle = -96; } hdc = BeginPaint( hWnd, &ps); SelectObject(hdc, hFont); SetBkMode(hdc, TRANSPARENT); // 文字の背景色を後ろの色にする。(スケルトンになる) MoveToEx( hdc, rect.left, rect.bottom/2-CENTERSP+2 , NULL ); LineTo( hdc, rect.left, rect.bottom/2+CENTERSP-2 ); wsprintf(str, TEXT("%ddB"),dBlow); TextOut(hdc, rect.left+5 , rect.bottom/2-6 , str, strlen(str)); MoveToEx( hdc, rect.left+256, rect.bottom/2-CENTERSP+2 , NULL ); LineTo( hdc, rect.left+256, rect.bottom/2+CENTERSP-2 ); wsprintf(str, TEXT("%ddB"),dBmiddle); TextOut(hdc, rect.left+260 , rect.bottom/2-6 , str, strlen(str)); MoveToEx( hdc, rect.left+512, rect.bottom/2-CENTERSP+2 , NULL ); LineTo( hdc, rect.left+512, rect.bottom/2+CENTERSP-2 ); wsprintf(str, TEXT("%ddB"),0); TextOut(hdc, rect.left+515 , rect.bottom/2-6 , str, strlen(str)); EndPaint(hWnd , &ps); } LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { // ウインド HINSTANCE hInst; static HWND hWndLevelL; // Channel#1音声レベルウインド static HWND hWndLevelR; // Channel#2音声レベルウインド static RECT rect,rectL,rectR; // Bitmap HDC static HDC LhBmpDC; static HDC LlBmpDC; static HDC RhBmpDC; static HDC RlBmpDC; static HBITMAP hbmpLh = NULL; //ビットマップ static HBITMAP hbmpLl = NULL; //ビットマップ static HBITMAP hbmpRh = NULL; //ビットマップ static HBITMAP hbmpRl = NULL; //ビットマップ HDC hdc; PAINTSTRUCT ps; static HFONT hFont; // WAVEファイル HANDLE hFile; char szFileName[80] = {0}; static DWORD waveFsize = 0; static int pointLength; char *errmsg = NULL; // WAVEデータ static char *waveptr= (char *)NULL; // 波形の線 static long scaleSize; static DWORD lenge; long Llow,Rlow; long Lhi, Rhi; static int amplitude = 0; static HWAVEOUT hwo = NULL; static WAVEFORMATEX wf = {0}; static WAVEHDR wh = {0}; static MMTIME level_mmt = {0}; char tmpmsg[80] = {0}; static WORD wBytePerSample; static WORD wBytePerSamplex2; static DWORD Lhscale = 0; static DWORD Llscale = 0; static DWORD Rhscale = 0; static DWORD Rlscale = 0; OPENFILENAME ofn; char szFile[MAX_PATH]; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { 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_PLAY: lenge = waveOutOpen(&hwo, WAVE_MAPPER, &wf, 0, 0, CALLBACK_NULL); if (lenge == MMSYSERR_NOERROR) { wh.dwBufferLength = waveFsize-WAVEHEADER; wh.lpData = &waveptr[WAVEHEADER]; if(waveOutPrepareHeader(hwo, &wh, sizeof(WAVEHDR)) == MMSYSERR_NOERROR){ if(waveOutWrite(hwo, &wh, sizeof(WAVEHDR)) == MMSYSERR_NOERROR){ // 最大の振幅を、約511pxにする if(wf.wBitsPerSample == 16){ scaleSize=(0x1<<6); }else if(wf.wBitsPerSample == 32){ scaleSize=(0x1<<22); } amplitude = (wf.nAvgBytesPerSec/1000)*WTIME; pointLength = rectL.right - rectL.left; lenge = (waveFsize-WAVEHEADER) / pointLength / 2; SetTimer(hWnd,IDC_TIMER,WTIME,NULL); }else{ MessageBox(NULL, TEXT("音声出力に失敗しました。"), NULL, MB_ICONWARNING); SendMessage(hWnd, WM_DESTROY, 0, 0); } } }else if(lenge == WAVERR_BADFORMAT){ MessageBox(NULL, TEXT("デバイスドライバは、指定されたフォーマットをサポートしていない "), NULL, MB_ICONWARNING); SendMessage(hWnd, WM_DESTROY, 0, 0); }else{ MessageBox(NULL, TEXT("WAVEデバイスのオープンに失敗しました。"), NULL, MB_ICONWARNING); SendMessage(hWnd, WM_DESTROY, 0, 0); } break; case IDM_STOP: // 再生停止 idm_stop(hWnd, hwo, wh); // Levelを0にする Lhscale = 0; Llscale = 0; Rhscale = 0; Rlscale = 0; InvalidateRect(hWnd, NULL, FALSE); UpdateWindow(hWnd); break; default: break; } break; case WM_CREATE: 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)){ 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)); wBytePerSample = wf.wBitsPerSample/8; wBytePerSamplex2 = wBytePerSample*2; if((wf.wBitsPerSample == 16) || (wf.wBitsPerSample == 32)){ if(wf.wFormatTag != WAVE_FORMAT_PCM) 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{ hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE); GetClientRect(hWnd , &rect); // 左ウインド hWndLevelL = CreateWindowEx(WS_EX_STATICEDGE, "STATIC", "", WS_CHILD | WS_VISIBLE, rect.top, 0, rect.right, rect.bottom/2-CENTERSP, hWnd, (HMENU)89, hInst, NULL); // 右ウインド hWndLevelR = CreateWindowEx(WS_EX_STATICEDGE, "STATIC", "", WS_CHILD | WS_VISIBLE | SS_BITMAP, rect.top, rect.bottom/2+CENTERSP, rect.right, rect.bottom/2-1, hWnd, (HMENU)90, hInst, NULL); //BMP画像をリソースから読み込む hbmpLh = LoadBitmap(hInst, "LEVELH"); // 最大音LevelのBMP hbmpLl = LoadBitmap(hInst, "LEVELL"); // 最小音LevelのBMP hbmpRh = LoadBitmap(hInst, "LEVELH"); hbmpRl = LoadBitmap(hInst, "LEVELL"); // 左側描画用BMP用意 GetClientRect(hWndLevelL , &rectL); LhBmpDC = MakeBmpBord(hWndLevelL, rectL); SelectObject( LhBmpDC, hbmpLh ); LlBmpDC = MakeBmpBord(hWndLevelL, rectL); SelectObject( LlBmpDC, hbmpLl ); // 右側描画用BMP用意 GetClientRect(hWndLevelR , &rectR); RhBmpDC = MakeBmpBord(hWndLevelR, rectR); SelectObject( RhBmpDC, hbmpRh ); RlBmpDC = MakeBmpBord(hWndLevelR, rectR); SelectObject( RlBmpDC, hbmpRl ); hFont = SetMyFont(NULL/*(LPCTSTR)"arial black"*/, 12, 0, 700); InvalidateRect(hWnd, NULL, FALSE); UpdateWindow(hWnd); } break; case WM_TIMER: level_mmt.wType = TIME_BYTES; waveOutGetPosition(hwo, &level_mmt, sizeof(MMTIME)); // 左音Levelの最大/最小値を求める MaxMin(waveptr+amplitude, wf.wBitsPerSample, level_mmt.u.cb, amplitude, wBytePerSamplex2, &Llow, &Lhi); if(Lhi<0) Lhi *= -1; Lhscale = Lhi / scaleSize; if(Llow<0) Llow *= -1; Llscale = Llow / scaleSize; // 右音Levelの最大/最小値を求める MaxMin(waveptr+amplitude, wf.wBitsPerSample, level_mmt.u.cb+wBytePerSample, amplitude, wBytePerSamplex2, &Rlow, &Rhi); if(Rhi<0) Rhi *= -1; Rhscale = Rhi / scaleSize; if(Rlow<0) Rlow *= -1; Rlscale = Rlow / scaleSize; InvalidateRect(hWnd, NULL, FALSE); UpdateWindow(hWnd); break; case WM_SIZE: GetClientRect(hWnd , &rect); MoveWindow(hWndLevelL, rect.top, 0, rect.right, rect.bottom/2-CENTERSP, TRUE); MoveWindow(hWndLevelR, rect.top, rect.bottom/2+CENTERSP, rect.right, rect.bottom/2-1, TRUE); break; case WM_PAINT: if(LhBmpDC != (HDC)NULL){ // 左側描画 hdc = BeginPaint(hWndLevelL, &ps); BitBlt(hdc, rectL.left, rectL.top, rectL.right, rectL.bottom, LlBmpDC, MAXLEVEL- Llscale, rectL.top, SRCCOPY); BitBlt(hdc, rectL.left+Llscale-1, rectL.top, rectL.right, rectL.bottom, LhBmpDC, MAXLEVEL-(Lhscale-Llscale), rectL.top, SRCCOPY); EndPaint(hWndLevelL , &ps); } if(RhBmpDC != (HDC)NULL){ // 右側描画 hdc = BeginPaint(hWndLevelR, &ps); BitBlt(hdc, rectR.left, rectR.top, rectR.right, rectR.bottom, RlBmpDC, MAXLEVEL- Rlscale, rectR.top, SRCCOPY); BitBlt(hdc, rectR.left+Rlscale-1, rectR.top, rectR.right, rectR.bottom, RhBmpDC, MAXLEVEL-(Rhscale-Rlscale), rectR.top, SRCCOPY); EndPaint(hWndLevelR , &ps); } scaleLine(hWnd, rect, hFont, wf.wBitsPerSample); break; case WM_DESTROY: // 再生停止 idm_stop(hWnd, hwo, wh); // ビットマップ関連開放 DeleteDC(LhBmpDC); DeleteDC(LlBmpDC); DeleteDC(RhBmpDC); DeleteDC(RlBmpDC); DeleteObject( hbmpLh ); DeleteObject( hbmpLl ); DeleteObject( hbmpRh ); DeleteObject( hbmpRl ); // メモリ開放 if(waveptr != NULL) free(waveptr); // 終了処理 DestroyWindow(hWnd); PostQuitMessage(0); break; default: break; } return DefWindowProc(hWnd, msg, wp, lp); } 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)); // GetStockObject(coler); // ウインドの背景色 CreateSolidBrush(RGB(0,255,0x66))でもOK wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!RegisterClassEx(&wc)) return 0; HWND hWnd = CreateWindow(szClassName, "WaveLevel", //タイトルバー表示 WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 555, //幅 100+(CENTERSP*2), //高さ 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; }