画一个示波器界面,显示麦克风采集到的声音数据
用一个示波器的BMP图做背景,在上面画出麦克风采集到的数据. 只是数据看起好奇怪。似乎只有密度变化,没有幅度变化。
升级到VS2022了,字符串处理又有些不同了。似乎更严格了。
程序 Wave.cpp
// WAVE.cpp : Defines the entry point for the application. // 画一个示波器界面,显示麦克风采集到的声音数据 // XGZ 2022-05-27 SZ #include "pch.h" #include "framework.h" #include "WAVE.h" #define MAX_LOADSTRING 100 // Global Variables: HINSTANCE hInst; // current instance WCHAR szTitle[MAX_LOADSTRING]; // The title bar text WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name // Forward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); //xgz========== #define IDC_EDIT 1001 #define IDC_BUTTON1 1002 #define IDC_BUTTON2 1003 #define IDC_BUTTON3 1004 #define IDC_BUTTON4 1005 #define IDC_BUTTON5 1006 #define IDC_BUTTON6 1007 HWND hWndEdit; HWND hWndButton1; HWND hWndButton2; HWND hWndButton3; HWND hWndButton4; HWND hWndButton5; HWND hWndButton6; int OnCreate(HWND, UINT, WPARAM, LPARAM); int OnSize(HWND, UINT, WPARAM, LPARAM); int OnPaint(HWND, UINT, WPARAM, LPARAM); int OnTimer(HWND, UINT, WPARAM, LPARAM); int OnButton1(HWND, UINT, WPARAM, LPARAM); int OnButton2(HWND, UINT, WPARAM, LPARAM); int OnButton3(HWND, UINT, WPARAM, LPARAM); int OnButton4(HWND, UINT, WPARAM, LPARAM); int OnButton5(HWND, UINT, WPARAM, LPARAM); int OnButton6(HWND, UINT, WPARAM, LPARAM); int PRINT(const TCHAR * fmt, ...) { TCHAR buffer[1024]; va_list argptr; int cnt; int iEditTextLength; HWND hWnd = hWndEdit; if (NULL == hWnd) return 0; va_start(argptr, fmt); cnt = wvsprintf(buffer, fmt, argptr); // not %f va_end(argptr); iEditTextLength = GetWindowTextLength(hWnd); if (iEditTextLength + cnt > 30000) // edit text max length is 30000 { SendMessage(hWnd, EM_SETSEL, 0, 10000); SendMessage(hWnd, WM_CLEAR, 0, 0); iEditTextLength = iEditTextLength - 10000; } SendMessage(hWnd, EM_SETSEL, iEditTextLength, iEditTextLength); SendMessage(hWnd, EM_REPLACESEL, 0, (LPARAM)buffer); return(cnt); } //==D Show=============== //#include <atlbase.h> //#include <dshow.h> //#pragma comment(lib,"Strmiids.lib") #include <atlstr.h> #include <Mmsystem.h> #pragma comment(lib,"Winmm.lib") HWND m_hWnd=NULL; DWORD datasize = 48000; char* pBuffer1 = NULL; //XGZ 2022-05-29 改成 unsigned char WAVEFORMATEX waveformat; HWAVEOUT hWaveOut; HWAVEIN hWaveIn; WAVEHDR m_pWaveHdr1; WAVEHDR m_pWaveHdr; int res; HBITMAP m_hBitmap_mem; HBITMAP m_hBitmap_mem0; HDC hdcmem; HDC hdcmem0; HDC m_hdc_mem; HDC m_hdc_mem0; HPEN hPen, hPenW; HBRUSH hBrush; int displayBK(HWND hWnd); int displayWave(HWND hWnd); int iStart = 0; VOID ThreadProc1(PVOID pData); int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: Place code here. // Initialize global strings LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadStringW(hInstance, IDC_WAVE, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WAVE)); MSG msg; // Main message loop: while (GetMessage(&msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int) msg.wParam; } ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEXW wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WAVE)); wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WAVE); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassExW(&wcex); } BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { hInst = hInstance; // Store instance handle in our global variable HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr); if (!hWnd) { return FALSE; } m_hWnd = hWnd; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_CREATE: OnCreate(hWnd, message, wParam, lParam); break; case WM_SIZE: OnSize(hWnd, message, wParam, lParam); break; case WM_PAINT: OnPaint(hWnd, message, wParam, lParam); break; case WM_TIMER: OnTimer(hWnd, message, wParam, lParam); break; case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDC_BUTTON1: OnButton1(hWnd, message, wParam, lParam); break; case IDC_BUTTON2: OnButton2(hWnd, message, wParam, lParam); break; case IDC_BUTTON3: OnButton3(hWnd, message, wParam, lParam); break; case IDC_BUTTON4: OnButton4(hWnd, message, wParam, lParam); break; case IDC_BUTTON5: OnButton5(hWnd, message, wParam, lParam); break; case IDC_BUTTON6: OnButton6(hWnd, message, wParam, lParam); break; case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // Message handler for about box. INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: 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; } int OnCreate(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { hWndEdit = CreateWindow(_T("edit"), NULL, WS_CHILD | WS_BORDER | WS_VISIBLE | ES_MULTILINE | WS_VSCROLL, 0, 0, 0, 0, hWnd, (HMENU)IDC_EDIT, hInst, NULL); hWndButton1 = CreateWindow(_T("button"), _T("1"), WS_CHILD | WS_VISIBLE | BS_FLAT, 0, 0, 0, 0, hWnd, (HMENU)IDC_BUTTON1, hInst, NULL); hWndButton2 = CreateWindow(_T("button"), _T("2"), WS_CHILD | WS_VISIBLE | BS_FLAT, 0, 0, 0, 0, hWnd, (HMENU)IDC_BUTTON2, hInst, NULL); hWndButton3 = CreateWindow(_T("button"), _T("3"), WS_CHILD | WS_VISIBLE | BS_FLAT, 0, 0, 0, 0, hWnd, (HMENU)IDC_BUTTON3, hInst, NULL); hWndButton4 = CreateWindow(_T("button"), _T("4"), WS_CHILD | WS_VISIBLE | BS_FLAT, 0, 0, 0, 0, hWnd, (HMENU)IDC_BUTTON4, hInst, NULL); hWndButton5 = CreateWindow(_T("button"), _T("5"), WS_CHILD | WS_VISIBLE | BS_FLAT, 0, 0, 0, 0, hWnd, (HMENU)IDC_BUTTON5, hInst, NULL); hWndButton6 = CreateWindow(_T("button"), _T("6"), WS_CHILD | WS_VISIBLE | BS_FLAT, 0, 0, 0, 0, hWnd, (HMENU)IDC_BUTTON6, hInst, NULL); displayBK(hWnd); SetTimer(hWnd, 1, 10000, NULL); //10s return 1; } //留一个状态条的位置 int OnSize(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int cxClient, cyClient; cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); MoveWindow(hWndEdit, 0, cyClient - 120, cxClient - 50, 100, TRUE); MoveWindow(hWndButton1, cxClient - 50, 0, 50, 20, TRUE); MoveWindow(hWndButton2, cxClient - 50, 20, 50, 20, TRUE); MoveWindow(hWndButton3, cxClient - 50, 40, 50, 20, TRUE); MoveWindow(hWndButton4, cxClient - 50, 60, 50, 20, TRUE); MoveWindow(hWndButton5, cxClient - 50, 80, 50, 20, TRUE); MoveWindow(hWndButton6, cxClient - 50, 100, 50, 20, TRUE); return DefWindowProc(hWnd, message, wParam, lParam); } int OnPaint(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; RECT rt; hdc = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rt); //DrawText(hdc, StatusText, strlen(StatusText), &rt, DT_LEFT|DT_BOTTOM|DT_SINGLELINE); EndPaint(hWnd, &ps); return 1; } int OnTimer(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { return 1; } int OnButton1(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PRINT(_T("\r\n OnButton1")); //display(hWnd); if (iStart == 0) { pBuffer1 = new char[datasize]; iStart = 1; _beginthread(ThreadProc1, 0, NULL); } else { iStart = 0; if (GlobalFree(GlobalHandle(m_pWaveHdr.lpData))) { PRINT(_T("\r\n Fail: GlobalFree")); } else { PRINT(_T("\r\n OK: GlobalFree")); return 0; } if (res == MMSYSERR_NOERROR) // 关闭录音设备 { if (waveInClose(hWaveIn) == MMSYSERR_NOERROR) { PRINT(_T("\r\n OK: waveInClose")); } else { PRINT(_T("\r\n Fail: waveInClose")); return 0; } } delete pBuffer1; pBuffer1 = NULL; } return 1; } int OnButton2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PRINT(_T("\r\n OnButton2")); return 1; } int OnButton3(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PRINT(_T("\r\n OnButton3")); return 1; } int OnButton4(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PRINT(_T("\r\n OnButton4 ")); return 1; } int OnButton5(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PRINT(_T("\r\n OnButton5 ")); return 1; } int OnButton6(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PRINT(_T("\r\n OnButton6 ")); return 1; } int displayBK(HWND hWnd) { double x, y; POINT pt; int i, j, k; HDC hdc = GetDC(hWnd); HANDLE hh = LoadImage(NULL, _T("wave.bmp"), IMAGE_BITMAP, 500, 350, LR_LOADFROMFILE); hdcmem = CreateCompatibleDC(hdc); SelectObject(hdcmem, hh); BitBlt(hdc, 0, 0, 500, 350, hdcmem, 0, 0, SRCCOPY); m_hBitmap_mem0 = CreateCompatibleBitmap(hdc, 400, 300); m_hdc_mem0 = CreateCompatibleDC(hdc); SelectObject(m_hdc_mem0, m_hBitmap_mem0); m_hBitmap_mem = CreateCompatibleBitmap(hdc, 400, 300); m_hdc_mem = CreateCompatibleDC(hdc); SelectObject(m_hdc_mem, m_hBitmap_mem); hBrush = (HBRUSH)GetStockObject(BLACK_BRUSH); SelectObject(m_hdc_mem0, hBrush); Rectangle(m_hdc_mem0, 0, 0, 400, 300); //BLACK_BRUSH SetBkMode(m_hdc_mem0, TRANSPARENT); hPen = CreatePen(PS_DOT, 1, RGB(100, 100, 100)); SelectObject(m_hdc_mem0, hPen); hPenW = CreatePen(PS_SOLID, 1, RGB(0, 255, 0)); SelectObject(m_hdc_mem, hPenW); for (i = 0; i < 300; i += 30) { MoveToEx(m_hdc_mem0, 0, i, &pt); LineTo(m_hdc_mem0, 400, i); } for (i = 0; i < 400; i += 30) { MoveToEx(m_hdc_mem0, i, 0, &pt); LineTo(m_hdc_mem0, i, 300); } return 1; } int displayWave(HWND hWnd) { double x, y; POINT pt; int i, j, k; HDC hdc = GetDC(hWnd); BitBlt(hdc, 0, 0, 500, 350, hdcmem, 0, 0, SRCCOPY); int dwNumber = m_pWaveHdr.dwBytesRecorded;
BitBlt(m_hdc_mem, 0, 0, 400, 300, m_hdc_mem0, 0, 0, SRCCOPY); MoveToEx(m_hdc_mem, 0, 0, &pt); for (i = 0; i < dwNumber; i++) { x = i; y = *(pBuffer1+i); j = y * 0.3 + 100; LineTo(m_hdc_mem, i, j); } BitBlt(hdc, 28, 30, 370, 180, m_hdc_mem, 0, 0, SRCCOPY); return 1; } int sample(HWND hWnd) { waveformat.wFormatTag = WAVE_FORMAT_PCM; waveformat.nChannels = 1; waveformat.nSamplesPerSec = 8000; waveformat.nBlockAlign = 1; waveformat.wBitsPerSample = 8; waveformat.cbSize = 0; waveformat.nAvgBytesPerSec = waveformat.nChannels * waveformat.nSamplesPerSec * waveformat.wBitsPerSample / 8; if (!waveInGetNumDevs()) { PRINT(_T("\r\n Fail waveInGetNumDevs ")); return 0; } int res = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveformat, (DWORD)NULL, 0L, CALLBACK_WINDOW); if (res != MMSYSERR_NOERROR) { PRINT(_T("\r\n Fail: waveInOpen,Error_Code = 0x%x"), res); return 0; } m_pWaveHdr.lpData = pBuffer1; memset(m_pWaveHdr.lpData, 0, datasize); m_pWaveHdr.dwBufferLength = datasize; m_pWaveHdr.dwBytesRecorded = 0; m_pWaveHdr.dwUser = 0; m_pWaveHdr.dwFlags = 0; m_pWaveHdr.dwLoops = 0; int resPrepare = waveInPrepareHeader(hWaveIn, &m_pWaveHdr, sizeof(WAVEHDR)); if (resPrepare != MMSYSERR_NOERROR) { PRINT(_T("\r\n Fail: waveInPrepareHeader,Error_Code = 0x%03X"), resPrepare); return 0; } resPrepare = waveInAddBuffer(hWaveIn, &m_pWaveHdr, sizeof(WAVEHDR)); if (resPrepare != MMSYSERR_NOERROR) { PRINT(_T("\r\n Fail:waveInAddBuffer,Error_Code = 0x%03X"), resPrepare); return 0; } if (!waveInStart(hWaveIn)) { //PRINT(_T("\r\n OK:waveInStart!")); } else { PRINT(_T("\r\n Fail:waveInStart!")); return 0; } Sleep(100); MMTIME mmt; mmt.wType = TIME_BYTES; if (!waveInGetPosition(hWaveIn, &mmt, sizeof(MMTIME))) { } else { PRINT(_T("\r\n Fail:waveInGetPosition!")); return 0; } if (mmt.wType != TIME_BYTES) { PRINT(_T("\r\n Fail:mmt.wType != TIME_BYTES")); return 0; } if (!waveInStop(hWaveIn)) { } else { PRINT(_T("\r\n Fail:waveInStop")); } if (waveInReset(hWaveIn)) { PRINT(_T("\r\n Fail:waveInReset")); return 0; } m_pWaveHdr.dwBytesRecorded = mmt.u.cb; DWORD NumToWrite = 0; DWORD dwNumber = 0; dwNumber = m_pWaveHdr.dwBytesRecorded; if (waveInUnprepareHeader(hWaveIn, &m_pWaveHdr, sizeof(WAVEHDR))) { PRINT(_T("\r\n Fail: waveInUnprepareHeader")); } else { return 0; } return 1; } VOID ThreadProc1(PVOID pData) { int dwNumber; PRINT(_T("\r\n ThreadProc1 Begin..")); while (iStart) { sample(m_hWnd); dwNumber = m_pWaveHdr.dwBytesRecorded; displayWave(m_hWnd); PRINT(_T(".")); } PRINT(_T("\r\n ThreadProc1 Exit.")); _endthread(); }
2022-05-29,今天终于把声音波形给画出来了。原因是:8位及以下采样,声音数据是用无符号数据记录的,应该定义成unsigned char。