Condividi tramite


Metri di picco

Per supportare le applicazioni Windows che visualizzano i contatori di picco, l'API EndpointVolume include un'interfaccia IAudioMeterInformation. Questa interfaccia rappresenta un misuratore di picco in un dispositivo endpoint audio. Per un dispositivo di rendering, il valore recuperato dal contatore di picco rappresenta il valore di campione massimo rilevato nel flusso di output nel dispositivo durante il periodo di misurazione precedente. Per un dispositivo di acquisizione, il valore recuperato dal contatore di picco rappresenta il valore massimo di campione rilevato nel flusso di input dal dispositivo.

I valori del contatore di picco ottenuti dai metodi nell'interfaccia IAudioMeterInformation sono numeri a virgola mobile nell'intervallo normalizzato compreso tra 0,0 e 1,0. Ad esempio, se un flusso PCM contiene campioni a 16 bit e il valore di campione di picco durante un determinato periodo di misurazione è -8914, il valore assoluto registrato dal contatore di picco è 8914 e il valore di picco normalizzato segnalato dall'interfaccia IAudioMeterInformation è 8914/32768 = 0,272.

Se il dispositivo endpoint audio implementa il misuratore di picco nell'hardware, l'interfaccia IAudioMeterInformation usa il contatore di picco hardware. In caso contrario, l'interfaccia implementa il contatore di picco nel software.

Se un dispositivo ha un contatore di picco hardware, il contatore di picco è attivo sia in modalità condivisa che in modalità esclusiva. Se un dispositivo non dispone del contatore di picco hardware, il contatore di picco è attivo in modalità condivisa, ma non in modalità esclusiva. In modalità esclusiva, l'applicazione e l'hardware audio scambiano direttamente i dati audio, ignorando il contatore di picco software (che segnala sempre un valore di picco pari a 0,0).

L'esempio di codice C++ seguente è un'applicazione Windows che visualizza un contatore di picco per il dispositivo di rendering predefinito:

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

Nell'esempio di codice precedente, la funzione WinMain chiama la funzione CoCreateInstance per creare un'istanza dell'interfaccia IMMDeviceEnumerator e chiama il metodo IMMDeviceEnumerator::GetDefaultAudioEndpoint per ottenere l'interfaccia IMMDevice del dispositivo di rendering predefinito. WinMain chiama il metodo IMMDevice::Activate per ottenere l'interfaccia IAudioMeterInformation del dispositivo e apre una finestra di dialogo per visualizzare un indicatore di picco per il dispositivo. Per altre informazioni su WinMain e CoCreateInstance, vedere la documentazione di Windows SDK. Per altre informazioni su IMMDeviceEnumerator e IMMDevice, vedere Enumerazione di dispositivi audio.

Nell'esempio di codice precedente la funzione DlgProc visualizza il misuratore di picco nella finestra di dialogo. Durante l'elaborazione del messaggio di WM_INITDIALOG, DlgProc chiama la funzione SetTimer per configurare un timer che genererà WM_TIMER messaggi a intervalli di tempo regolari. Quando DlgProc riceve un messaggio WM_TIMER, chiama IAudioMeterInformation::GetPeakValue per ottenere la lettura più recente del contatore di picco per il flusso. DlgProc chiama quindi la funzione DrawPeakMeter per disegnare il contatore di picco aggiornato nella finestra di dialogo. Per altre informazioni su SetTimer e i messaggi WM_INITDIALOG e WM_TIMER, vedere la documentazione di Windows SDK.

È possibile modificare facilmente l'esempio di codice precedente per visualizzare un misuratore di picco per il dispositivo di acquisizione predefinito. Nella funzione WinMain modificare il valore del primo parametro nella chiamata a IMMDeviceEnumerator::GetDefaultAudioEndpoint da eRender a eCapture.

L'esempio di codice seguente è lo script di risorsa che definisce i controlli visualizzati nell'esempio di codice precedente:

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

L'esempio di codice seguente è il file di intestazione di risorsa che definisce gli identificatori di controllo visualizzati negli esempi di codice precedenti:

// Resource.h -- Control identifiers

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

Controlli volume