Medidores de pico

Para admitir aplicaciones Windows que muestran medidores de pico, la API EndpointVolume incluye una interfaz IAudioMeterInformation . Esta interfaz representa un medidor máximo en un dispositivo de punto de conexión de audio. Para un dispositivo de representación, el valor recuperado del medidor máximo representa el valor máximo de ejemplo encontrado en el flujo de salida al dispositivo durante el período de medición anterior. Para un dispositivo de captura, el valor recuperado del medidor máximo representa el valor de ejemplo máximo encontrado en el flujo de entrada del dispositivo.

Los valores de medidor máximo obtenidos de los métodos de la interfaz IAudioMeterInformation son números de punto flotante en el intervalo normalizado de 0,0 a 1,0. Por ejemplo, si una secuencia PCM contiene muestras de 16 bits y el valor máximo de la muestra durante un período de medición determinado es —8914, el valor absoluto registrado por el medidor máximo es 8914 y el valor máximo normalizado notificado por la interfaz IAudioMeterInformation es 8914/32768 = 0,272.

Si el dispositivo de punto de conexión de audio implementa el medidor máximo en hardware, la interfaz IAudioMeterInformation usa el medidor máximo de hardware. De lo contrario, la interfaz implementa el medidor máximo en el software.

Si un dispositivo tiene un medidor máximo de hardware, el medidor máximo está activo tanto en modo compartido como en modo exclusivo. Si un dispositivo carece de medidor máximo de hardware, el medidor máximo está activo en modo compartido, pero no en modo exclusivo. En modo exclusivo, la aplicación y el hardware de audio intercambian datos de audio directamente, pasando el medidor máximo de software (que siempre informa de un valor máximo de 0,0).

El siguiente ejemplo de código de C++ es una aplicación de Windows que muestra un medidor máximo para el dispositivo de representación predeterminado:

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

En el ejemplo de código anterior, la función WinMain llama a la función CoCreateInstance para crear una instancia de la interfaz IMMDeviceEnumerator y llama al método IMMDeviceEnumerator::GetDefaultAudioEndpoint para obtener la interfaz IMMDevice del dispositivo de representación predeterminado. WinMain llama al método IMMDevice::Activate para obtener la interfaz IAudioMeterInformation del dispositivo y abre un cuadro de diálogo para mostrar un medidor máximo para el dispositivo. Para obtener más información sobre WinMain y CoCreateInstance, consulte la documentación de Windows SDK. Para obtener más información sobre IMMDeviceEnumerator e IMMDevice, vea Enumerar dispositivos de audio.

En el ejemplo de código anterior, la función DlgProc muestra el medidor máximo en el cuadro de diálogo. Durante el procesamiento del mensaje de WM_INITDIALOG, DlgProc llama a la función SetTimer para configurar un temporizador que generará WM_TIMER mensajes a intervalos de tiempo regulares. Cuando DlgProc recibe un mensaje de WM_TIMER, llama a IAudioMeterInformation::GetPeakValue para obtener la lectura más reciente del medidor máximo de la secuencia. DlgProc llama a la función DrawPeakMeter para dibujar el medidor máximo actualizado en el cuadro de diálogo. Para obtener más información sobre SetTimer y los mensajes WM_INITDIALOG y WM_TIMER, consulte la documentación de Windows SDK.

Puede modificar fácilmente el ejemplo de código anterior para mostrar un medidor máximo para el dispositivo de captura predeterminado. En la función WinMain , cambie el valor del primer parámetro de la llamada a IMMDeviceEnumerator::GetDefaultAudioEndpoint de eRender a eCapture.

El ejemplo de código siguiente es el script de recursos que define los controles que aparecen en el ejemplo 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

El ejemplo de código siguiente es el archivo de encabezado de recursos que define los identificadores de control que aparecen en los ejemplos 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 volumen