zoukankan      html  css  js  c++  java
  • win api 音频可视化

      暂时记录,改天有时间再完善。。。其实写好好久了,但以前的代码丢了,重新写一遍。。

      原理和 python 的一样,获取输入设备,然后把数据读取到 buffer 中,在绘制出来。

      这里要注意两点:

        1. waveformat 结构的参数都要填写正确才能打开设备,wavehdr结构必须先初始化才能调用准备函数,官方文档里都有解释。

        2. 读取出来的数据是无符号字符类型(0~255),以及 window 坐标是以左上角为基准,所以,要正确展示波形需要注意下。

      做了一些修改:

    #include "framework.h"
    #include "audio_analysis.h"
    
    #define MAX_LOADSTRING 100
    #define RATE 44100
    #define AUBUFF 2048
    #define PIPE 2
    
    
    HINSTANCE hInst;                                // 当前实例
    WCHAR szTitle[MAX_LOADSTRING];                  // 标题栏文本
    WCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口类名
    WAVEFORMATEX waveformat;
    WAVEHDR wavehdr;
    HWAVEOUT hWaveOut;
    HWAVEIN hWaveIn;
    HWND hBtn;
    WCHAR szFilter[] = L"ALL Files (*.*)*.*";
    WCHAR szButton[] = L"播放";
    BYTE waveBuffer[RATE * PIPE];
    signed char audioData[AUBUFF];
    BOOL playing = TRUE;
    INT audioSum = 0;
    
    
    ATOM                MyRegisterClass(HINSTANCE hInstance);
    BOOL                InitInstance(HINSTANCE, int);
    LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
    INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
    
    
    int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                         _In_opt_ HINSTANCE hPrevInstance,
                         _In_ LPWSTR    lpCmdLine,
                         _In_ int       nCmdShow)
    {
        UNREFERENCED_PARAMETER(hPrevInstance);
        UNREFERENCED_PARAMETER(lpCmdLine);
    
        // TODO: 在此处放置代码。
    
        // 初始化全局字符串
        LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
        LoadStringW(hInstance, IDC_AUDIOANALYSIS, szWindowClass, MAX_LOADSTRING);
        MyRegisterClass(hInstance);
    
        // 执行应用程序初始化:
        if (!InitInstance (hInstance, nCmdShow))
        {
            return FALSE;
        }
    
        HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_AUDIOANALYSIS));
    
        MSG msg;
    
        // 主消息循环:
        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_AUDIOANALYSIS));
        wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
        wcex.hbrBackground  = CreateSolidBrush(RGB(0, 0, 0));
        wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_AUDIOANALYSIS);
        wcex.lpszClassName  = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    
        return RegisterClassExW(&wcex);
    }
    
    
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
       hInst = hInstance; // 将实例句柄存储在全局变量中
    
       HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
    
       if (!hWnd)
       {
          return FALSE;
       }
    
       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);
    
       return TRUE;
    }
    
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
    	case WM_CREATE:
    		{
    			HDC hdc = GetDC(hWnd);
    			RECT rect;
    			TEXTMETRIC textMetric;
    
    			GetTextMetrics(hdc, &textMetric);
    			GetClientRect(hWnd, &rect);
    
    			int rWidth = rect.right - rect.left,
    				cxChar = textMetric.tmAveCharWidth,
    				cyChar = textMetric.tmHeight + textMetric.tmExternalLeading,
    				bWidth = 10 * cxChar,
    				bHeight = 8 * cyChar / 4;
    
    			hBtn = CreateWindow(TEXT("button"), szButton,
    				WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
    				rWidth / 2 - bWidth / 2, cyChar, bWidth, bHeight,
    				hWnd, (HMENU)MAKEINTRESOURCE(IDM_BUTTON),
    				((LPCREATESTRUCT)lParam)->hInstance, NULL);
    
    			waveformat.cbSize = 0;
    			waveformat.nAvgBytesPerSec = RATE * 4;
    			waveformat.nBlockAlign = 4;
    			waveformat.nChannels = PIPE;
    			waveformat.nSamplesPerSec = RATE;
    			waveformat.wBitsPerSample = 16;
    			waveformat.wFormatTag = WAVE_FORMAT_PCM;
    			UINT rst = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveformat, (DWORD)hWnd, 0, CALLBACK_WINDOW);
    			if (rst != MMSYSERR_NOERROR)
    			{
    				MessageBox(hWnd, L"Could not find suitable input device",
    					L"Error Message", MB_ICONSTOP | MB_OK);
    				DestroyWindow(hWnd);
    				break;
    			}
    		}
    		break;
        case WM_COMMAND:
            {
                int wmId = LOWORD(wParam);
                switch (wmId)
                {
    			case IDM_OPEN:
    				{
    					OPENFILENAME ofn;
    					WCHAR szFile[MAX_PATH];
    
    					ZeroMemory(&ofn, sizeof(ofn));
    					ofn.hwndOwner = hWnd;
    					ofn.lStructSize = sizeof(ofn);
    					ofn.lpstrFilter = szFilter;
    					ofn.nMaxFile = _MAX_PATH;
    					ofn.lpstrFile = szFile;
    					ofn.lpstrFile[0] = '';
    					ofn.nFilterIndex = 1;
    					ofn.lpstrFileTitle = NULL;
    					ofn.nMaxFileTitle = 0;
    					ofn.lpstrInitialDir = NULL;
    					ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
    					if (GetOpenFileName(&ofn) == TRUE)
    					{
    						WCHAR wComd[MAX_PATH];
    						_stprintf_s(wComd, TEXT("open cdaudio!%s"), szFile);
    						mciSendString(wComd, NULL, 0, 0);
    						_stprintf_s(wComd, TEXT("play cdaudio!%s"), szFile);
    						mciSendString(wComd, NULL, 0, 0);
    					}
    					else
    					{
    						MessageBoxW(NULL, TEXT("打开文件失败"), TEXT("错误"), MB_OK);
    					}
    				}
    				break;
    			case IDM_BUTTON:
    				{
    					if (playing == TRUE)
    					{
    						playing = FALSE;
    						waveInStop(hWaveIn);
    						SetWindowText(hBtn, TEXT("播放"));
    					}
    					else
    					{
    						playing = TRUE;
    						waveInStart(hWaveIn);
    						SetWindowText(hBtn, TEXT("暂停"));
    					}
    				}
    				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_PAINT:
            {
                PAINTSTRUCT ps;
                HDC hdc = BeginPaint(hWnd, &ps);
    			RECT rect;
    			TEXTMETRIC textMetric;
    
    			GetTextMetrics(hdc, &textMetric);
    			GetClientRect(hWnd, &rect);
    
    			int rWidth = rect.right - rect.left,
    				rHeight = rect.bottom - rect.top,
    				cxChar = textMetric.tmAveCharWidth,
    				cyChar = textMetric.tmHeight + textMetric.tmExternalLeading,
    				bWidth = 10 * cxChar,
    				bHeight = 8 * cyChar / 4,
    				waveAxis = rHeight / 2;
    
    			SetWindowPos(hBtn, HWND_TOP, rWidth / 2 - bWidth / 2,
    				cyChar, bWidth, bHeight, SWP_SHOWWINDOW | SWP_NOREDRAW);
    			HGDIOBJ hPen = SelectObject(hdc, GetStockObject(DC_PEN));
    			SetDCPenColor(hdc, RGB(0, 245, 0));
    			for (int i = 0; i < rWidth - 1; i++)
    			{
    				MoveToEx(hdc, 1 + 4 * i, audioData[i] + waveAxis, NULL);
    				LineTo(hdc, 1 + 4 * (i + 1), audioData[i + 1] + waveAxis);
    			}
    			SelectObject(hdc, hPen);
    			DeleteObject(hPen);
                EndPaint(hWnd, &ps);
            }
            break;
    	case MM_WIM_OPEN:
    		{
    			ZeroMemory(&wavehdr, sizeof(wavehdr));
    			ZeroMemory(waveBuffer, sizeof(waveBuffer));
    			wavehdr.lpData = (LPSTR)waveBuffer;
    			wavehdr.dwBufferLength = sizeof(waveBuffer);
    			wavehdr.dwFlags = 0;
    			wavehdr.dwLoops = 0;
    			wavehdr.dwUser = 0;
    			if (waveInPrepareHeader(hWaveIn, &wavehdr, sizeof(wavehdr)) != MMSYSERR_NOERROR)
    			{
    				MessageBox(hWnd, L"Could not prepare wave header",
    					L"Warning Message", MB_ICONWARNING | MB_OK);
    				waveInClose(hWaveIn);
    				break;
    			}
    			if (waveInStart(hWaveIn) != MMSYSERR_NOERROR)
    			{
    				MessageBox(hWnd, L"Could not start input device",
    					L"Warning Message", MB_ICONWARNING | MB_OK);
    				waveInClose(hWaveIn);
    				break;
    			}
    			if (waveInAddBuffer(hWaveIn, &wavehdr, sizeof(wavehdr)) != MMSYSERR_NOERROR)
    			{
    				MessageBox(hWnd, L"Could not add buffer",
    					L"Warning Message", MB_ICONWARNING | MB_OK);
    				waveInClose(hWaveIn);
    				break;
    			}
    			SetWindowText(hBtn, TEXT("暂停"));
    		}
    		break;
    	case MM_WIM_DATA:
    		{
    			RECT rect;
    			GetClientRect(hWnd, &rect);
    			int width = rect.right - rect.left;
    
    			for (int i = 0; i < width; i++)
    				audioData[i] = wavehdr.lpData[i + audioSum];
    			audioSum += 4;
    
    			RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE);
    			HBRUSH wb = (HBRUSH)GetStockObject(BLACK_BRUSH);
    			RECT r = rect;
    			HDC hdc = GetDC(hWnd);
    			r.top += 56;
    			FillRect(hdc, &r, wb);
    			ReleaseDC(hWnd, hdc);
    			if (audioSum > RATE * PIPE)
    			{
    				audioSum = 0;
    				ZeroMemory(waveBuffer, sizeof(waveBuffer));
    			}
    			waveInAddBuffer(hWaveIn, &wavehdr, sizeof(wavehdr));
    		}
    		break;
    	case MM_WIM_CLOSE:
    		{
    			playing = FALSE;
    		}
    		break;
        case WM_DESTROY:
    		{
    			if (playing)
    			{
    				waveInStop(hWaveIn);
    				waveInClose(hWaveIn);
    			}
    			PostQuitMessage(0);
    		}
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
    
    
    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;
    }
    

      截图:

      原截图:

  • 相关阅读:
    【洛谷P1330】封锁阳光大学
    【洛谷P1087】FBI树
    hdu 4504(动态规划)
    hdu 4503(数学,概率)
    hdu 5400(思路题)
    hdu 5701(区间查询思路题)
    hdu 4502(DP)
    hdu 1401(单广各种卡的搜索题||双广秒速)
    hdu 1258(DFS)
    hdu 1254(搜索题)
  • 原文地址:https://www.cnblogs.com/darkchii/p/11872839.html
Copyright © 2011-2022 走看看