Compartilhar via


Medidores de Pico

Para oferecer suporte a aplicativos do Windows que exibem medidores de pico, a API EndpointVolume inclui uma interface IAudioMeterInformation. Essa interface representa um medidor de pico em um dispositivo de ponto de extremidade de áudio. Para um dispositivo de renderização, o valor recuperado do medidor de pico representa o valor máximo de amostra encontrado no fluxo de saída para o dispositivo durante o período de medição anterior. Para um dispositivo de captura, o valor recuperado do medidor de pico representa o valor máximo de amostra encontrado no fluxo de entrada do dispositivo.

Os valores do medidor de pico obtidos dos métodos na interface IAudioMeterInformation são números de ponto flutuante na faixa normalizada de 0,0 a 1,0. Por exemplo, se um fluxo PCM contiver amostras de 16 bits e o valor de amostra de pico durante um período de medição específico for —8914, o valor absoluto registrado pelo medidor de pico será 8914 e o valor de pico normalizado relatado pela interface IAudioMeterInformation será 8914/32768 = 0,272.

Se o dispositivo de ponto de extremidade de áudio implementa o medidor de pico no hardware, a interface IAudioMeterInformation usa o medidor de pico de hardware. Caso contrário, a interface implementa o medidor de pico no software.

Se um dispositivo tiver um medidor de pico de hardware, o medidor de pico estará ativo no modo compartilhado e no modo exclusivo. Se um dispositivo não tiver medidor de pico de hardware, o medidor de pico estará ativo no modo compartilhado, mas não no modo exclusivo. No modo exclusivo, o aplicativo e o hardware de áudio trocam dados de áudio diretamente, ignorando o medidor de pico do software (que sempre informa um valor de pico de 0,0).

O exemplo de código C++ a seguir é um aplicativo do Windows que exibe um medidor de pico para o dispositivo de renderização padrão:

// 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);
}

No exemplo de código anterior, a função WinMain chama a função CoCreateInstance para criar uma instância da interface IMMDeviceEnumerator e chama o método IMMDeviceEnumerator::GetDefaultAudioEndpoint para obter a interface IMMDevice do dispositivo de renderização padrão. WinMain chama o método IMMDevice::Activate para obter a interface IAudioMeterInformation do dispositivo e abre uma caixa de diálogo para exibir um medidor de pico para o dispositivo. Para obter mais informações sobre WinMain e CoCreateInstance, consulte a documentação do SDK do Windows. Para obter mais informações sobre IMMDeviceEnumerator e IMMDevice, consulte Enumerando dispositivos de áudio.

No exemplo de código anterior, a função DlgProc exibe o medidor de pico na caixa de diálogo. Durante o processamento da mensagem WM_INITDIALOG, o DlgProc chama a função SetTimer para configurar um temporizador que gerará WM_TIMER mensagens em intervalos de tempo regulares. Quando o DlgProc recebe uma mensagem de WM_TIMER, ele chama IAudioMeterInformation::GetPeakValue para obter a leitura mais recente do medidor de pico para o fluxo. Em seguida, DlgProc chama a função DrawPeakMeter para desenhar o medidor de pico atualizado na caixa de diálogo. Para obter mais informações sobre SetTimer e as mensagens WM_INITDIALOG e WM_TIMER, consulte a documentação do SDK do Windows.

Você pode modificar facilmente o exemplo de código anterior para exibir um medidor de pico para o dispositivo de captura padrão. Na função WinMain, altere o valor do primeiro parâmetro na chamada para IMMDeviceEnumerator::GetDefaultAudioEndpoint de eRender para eCapture.

O exemplo de código a seguir é o script de recurso que define os controles que aparecem no exemplo de código anterior:

// 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

O exemplo de código a seguir é o arquivo de cabeçalho de recurso que define os identificadores de controle que aparecem nos exemplos de código anteriores:

// Resource.h -- Control identifiers

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

Controles de volume