Share via


피크 미터

최대 미터를 표시하는 Windows 애플리케이션을 지원하기 위해 EndpointVolume API 에는 IAudioMeterInformation 인터페이스가 포함되어 있습니다. 이 인터페이스는 오디오 엔드포인트 디바이스의 최대 미터를 나타냅니다. 렌더링 디바이스의 경우 최대 측정기에서 검색된 값은 이전 계량 기간 동안 출력 스트림에서 디바이스에 발생한 최대 샘플 값을 나타냅니다. 캡처 디바이스의 경우 최대 측정기에서 검색된 값은 디바이스의 입력 스트림에서 발생하는 최대 샘플 값을 나타냅니다.

IAudioMeterInformation 인터페이스의 메서드에서 가져온 피크 미터 값은 정규화된 범위에서 0.0에서 1.0까지의 부동 소수점 숫자입니다. 예를 들어 PCM 스트림에 16비트 샘플이 포함되어 있고 특정 계량 기간 동안의 최고 샘플 값이 —8914인 경우 최대 측정기에 의해 기록된 절대값은 8914이고 IAudioMeterInformation 인터페이스에서 보고한 정규화된 최대값은 8914/32768 = 0.272입니다.

오디오 엔드포인트 디바이스가 하드웨어에서 최대 측정기를 구현하는 경우 IAudioMeterInformation 인터페이스는 하드웨어 최대 측정기를 사용합니다. 그렇지 않으면 인터페이스는 소프트웨어에서 최대 측정기를 구현합니다.

디바이스에 하드웨어 피크 미터가 있는 경우 피크 미터는 공유 모드와 배타적 모드 모두에서 활성화됩니다. 디바이스에 하드웨어 피크 미터가 없는 경우 피크 미터는 공유 모드에서 활성화되지만 배타적 모드에서는 활성화되지 않습니다. 전용 모드에서 애플리케이션과 오디오 하드웨어는 오디오 데이터를 직접 교환하여 소프트웨어 최대 측정기(항상 최대값 0.0을 보고)를 무시합니다.

다음 C++ 코드 예제는 기본 렌더링 디바이스의 최대 측정기를 표시하는 Windows 애플리케이션입니다.

// Peakmeter.cpp -- WinMain and dialog box functions

#include <windows.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include "resource.h"

static BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
static void DrawPeakMeter(HWND, float);

// Timer ID and period (in milliseconds)
#define ID_TIMER  1
#define TIMER_PERIOD  125

#define EXIT_ON_ERROR(hr)  \
              if (FAILED(hr)) { goto Exit; }
#define SAFE_RELEASE(punk)  \
              if ((punk) != NULL)  \
                { (punk)->Release(); (punk) = NULL; }

//-----------------------------------------------------------
// WinMain -- Opens a dialog box that contains a peak meter.
//   The peak meter displays the peak sample value that plays
//   through the default rendering device.
//-----------------------------------------------------------
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpCmdLine,
                     int nCmdShow)
{
    HRESULT hr;
    IMMDeviceEnumerator *pEnumerator = NULL;
    IMMDevice *pDevice = NULL;
    IAudioMeterInformation *pMeterInfo = NULL;

    if (hPrevInstance)
    {
        return 0;
    }

    CoInitialize(NULL);

    // Get enumerator for audio endpoint devices.
    hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
                          NULL, CLSCTX_INPROC_SERVER,
                          __uuidof(IMMDeviceEnumerator),
                          (void**)&pEnumerator);
    EXIT_ON_ERROR(hr)

    // Get peak meter for default audio-rendering device.
    hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
    EXIT_ON_ERROR(hr)

    hr = pDevice->Activate(__uuidof(IAudioMeterInformation),
                           CLSCTX_ALL, NULL, (void**)&pMeterInfo);
    EXIT_ON_ERROR(hr)

    DialogBoxParam(hInstance, L"PEAKMETER", NULL, (DLGPROC)DlgProc, (LPARAM)pMeterInfo);

Exit:
    if (FAILED(hr))
    {
        MessageBox(NULL, TEXT("This program requires Windows Vista."),
                   TEXT("Error termination"), MB_OK);
    }
    SAFE_RELEASE(pEnumerator)
    SAFE_RELEASE(pDevice)
    SAFE_RELEASE(pMeterInfo)
    CoUninitialize();
    return 0;
}

//-----------------------------------------------------------
// DlgProc -- Dialog box procedure
//-----------------------------------------------------------

BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    static IAudioMeterInformation *pMeterInfo = NULL;
    static HWND hPeakMeter = NULL;
    static float peak = 0;
    HRESULT hr;

    switch (message)
    {
    case WM_INITDIALOG:
        pMeterInfo = (IAudioMeterInformation*)lParam;
        SetTimer(hDlg, ID_TIMER, TIMER_PERIOD, NULL);
        hPeakMeter = GetDlgItem(hDlg, IDC_PEAK_METER);
        return TRUE;

    case WM_COMMAND:
        switch ((int)LOWORD(wParam))
        {
        case IDCANCEL:
            KillTimer(hDlg, ID_TIMER);
            EndDialog(hDlg, TRUE);
            return TRUE;
        }
        break;

    case WM_TIMER:
        switch ((int)wParam)
        {
        case ID_TIMER:
            // Update the peak meter in the dialog box.
            hr = pMeterInfo->GetPeakValue(&peak);
            if (FAILED(hr))
            {
                MessageBox(hDlg, TEXT("The program will exit."),
                           TEXT("Fatal error"), MB_OK);
                KillTimer(hDlg, ID_TIMER);
                EndDialog(hDlg, TRUE);
                return TRUE;
            }
            DrawPeakMeter(hPeakMeter, peak);
            return TRUE;
        }
        break;

    case WM_PAINT:
        // Redraw the peak meter in the dialog box.
        ValidateRect(hPeakMeter, NULL);
        DrawPeakMeter(hPeakMeter, peak);
        break;
    }
    return FALSE;
}

//-----------------------------------------------------------
// DrawPeakMeter -- Draws the peak meter in the dialog box.
//-----------------------------------------------------------

void DrawPeakMeter(HWND hPeakMeter, float peak)
{
    HDC hdc;
    RECT rect;

    GetClientRect(hPeakMeter, &rect);
    hdc = GetDC(hPeakMeter);
    FillRect(hdc, &rect, (HBRUSH)(COLOR_3DSHADOW+1));
    rect.left++;
    rect.top++;
    rect.right = rect.left +
                 max(0, (LONG)(peak*(rect.right-rect.left)-1.5));
    rect.bottom--;
    FillRect(hdc, &rect, (HBRUSH)(COLOR_3DHIGHLIGHT+1));
    ReleaseDC(hPeakMeter, hdc);
}

앞의 코드 예제에서 WinMain 함수는 CoCreateInstance 함수를 호출하여 IMMDeviceEnumerator 인터페이스의 instance 만들고 IMMDeviceEnumerator::GetDefaultAudioEndpoint 메서드를 호출하여 기본 렌더링 디바이스의 IMMDevice 인터페이스를 가져옵니다. WinMain은IMMDevice::Activate 메서드를 호출하여 디바이스의 IAudioMeterInformation 인터페이스를 가져오고, 디바이스의 최대 측정기를 표시하는 대화 상자를 엽니다. WinMainCoCreateInstance에 대한 자세한 내용은 Windows SDK 설명서를 참조하세요. IMMDeviceEnumeratorIMMDevice에 대한 자세한 내용은 오디오 디바이스 열거를 참조하세요.

앞의 코드 예제에서 DlgProc 함수는 대화 상자에 최대 측정기를 표시합니다. WM_INITDIALOG 메시지를 처리하는 동안 DlgProc은 SetTimer 함수를 호출하여 정기적으로 WM_TIMER 메시지를 생성하는 타이머를 설정합니다. DlgProc은 WM_TIMER 메시지를 받으면 IAudioMeterInformation::GetPeakValue 를 호출하여 스트림에 대한 최신 피크 미터 판독값을 가져옵니다. 그런 다음 DlgProc은 DrawPeakMeter 함수를 호출하여 대화 상자에 업데이트된 피크 미터를 그립니다. SetTimer 및 WM_INITDIALOG 및 WM_TIMER 메시지에 대한 자세한 내용은 Windows SDK 설명서를 참조하세요.

이전 코드 예제를 쉽게 수정하여 기본 캡처 디바이스의 최대 측정기를 표시할 수 있습니다. WinMain 함수에서 IMMDeviceEnumerator::GetDefaultAudioEndpoint 호출에서 첫 번째 매개 변수의 값을 eRender에서 eCapture로 변경합니다.

다음 코드 예제는 이전 코드 예제에 나타나는 컨트롤을 정의하는 리소스 스크립트입니다.

// Peakmeter.rc -- Resource script

#include "resource.h"
#include "windows.h"

//
// Dialog
//
PEAKMETER DIALOGEX 0, 0, 150, 34
STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU | DS_SETFONT
CAPTION "Peak Meter"
FONT 8, "Arial Rounded MT Bold", 400, 0, 0x0
BEGIN
    CTEXT      "",IDC_PEAK_METER,34,14,82,5
    LTEXT      "Min",IDC_STATIC_MINVOL,10,12,20,12
    RTEXT      "Max",IDC_STATIC_MAXVOL,120,12,20,12
END

다음 코드 예제는 이전 코드 예제에 나타나는 컨트롤 식별자를 정의하는 리소스 헤더 파일입니다.

// Resource.h -- Control identifiers

#define IDC_STATIC_MINVOL      1001
#define IDC_STATIC_MAXVOL      1002
#define IDC_PEAK_METER         1003

볼륨 컨트롤