Пиковые метры

Для поддержки приложений Windows, отображающих пиковые метры, API EndpointVolume включает интерфейс 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, и вызывает метод IMMDeviceEnumerator::GetDefaultAudioEndpoint для получения интерфейса IMMDevice устройства отрисовки по умолчанию. WinMain вызывает метод IMMDevice::Activate, чтобы получить интерфейс IAudioMeterInformation устройства, и откроется диалоговое окно для отображения пикового измерения для устройства. Дополнительные сведения о WinMain и CoCreateInstance см. в документации по пакету SDK для Windows. Дополнительные сведения об IMMDeviceEnumerator и IMMDevice см. в разделе "Перечисление аудиоустройств".

В предыдущем примере кода функция DlgProc отображает пиковый метр в диалоговом окне. Во время обработки сообщения WM_INITDIALOG DlgProc вызывает функцию SetTimer для настройки таймера, который будет создавать сообщения WM_TIMER через регулярные интервалы времени. Когда DlgProc получает сообщение WM_TIMER, он вызывает IAudioMeterInformation::GetPeakValue , чтобы получить последнее чтение пикового измерения для потока. Затем DlgProc вызывает функцию DrawPeakMeter для рисования обновленного пикового измерения в диалоговом окне. Дополнительные сведения о SetTimer и сообщениях WM_INITDIALOG и WM_TIMER см. в документации по пакету SDK для Windows.

Вы можете легко изменить предыдущий пример кода, чтобы отобразить пиковый метр для устройства записи по умолчанию. В функции 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

Элементы управления томами