Compteurs de pointe

Pour prendre en charge les applications Windows qui affichent des compteurs de pointe, l’API EndpointVolume inclut une interface IAudioMeterInformation . Cette interface représente un compteur de pointe sur un appareil de point de terminaison audio. Pour un appareil de rendu, la valeur récupérée à partir du compteur de pointe représente la valeur d’exemple maximale rencontrée dans le flux de sortie vers l’appareil au cours de la période de contrôle précédente. Pour un appareil de capture, la valeur récupérée à partir du compteur de pointe représente la valeur d’exemple maximale rencontrée dans le flux d’entrée de l’appareil.

Les valeurs de compteur de pointe obtenues à partir des méthodes de l’interface IAudioMeterInformation sont des nombres à virgule flottante dans la plage normalisée comprise entre 0,0 et 1,0. Par exemple, si un flux PCM contient des échantillons 16 bits et que la valeur maximale de l’échantillon pendant une période de mesure particulière est 8914, la valeur absolue enregistrée par le compteur de pointe est 8914, et la valeur de pointe normalisée signalée par l’interface IAudioMeterInformation est 8914/32768 = 0,272.

Si le périphérique de point de terminaison audio implémente le compteur de pointe dans le matériel, l’interface IAudioMeterInformation utilise le compteur de pointe matériel. Sinon, l’interface implémente le compteur de pointe dans le logiciel.

Si un appareil dispose d’un compteur de pointe matériel, le compteur de pointe est actif à la fois en mode partagé et en mode exclusif. Si un appareil n’a pas de compteur de pointe matériel, le compteur de pointe est actif en mode partagé, mais pas en mode exclusif. En mode exclusif, l’application et le matériel audio échangent directement des données audio, en contournant le compteur de pointe logiciel (qui indique toujours une valeur de pointe de 0,0).

L’exemple de code C++ suivant est une application Windows qui affiche un compteur de pointe pour le périphérique de rendu par défaut :

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

Dans l’exemple de code précédent, la fonction WinMain appelle la fonction CoCreateInstance pour créer un instance de l’interface IMMDeviceEnumerator et appelle la méthode IMMDeviceEnumerator::GetDefaultAudioEndpoint pour obtenir l’interface IMMDevice du périphérique de rendu par défaut. WinMain appelle la méthode IMMDevice::Activate pour obtenir l’interface IAudioMeterInformation de l’appareil et ouvre une boîte de dialogue pour afficher un compteur de pointe pour l’appareil. Pour plus d’informations sur WinMain et CoCreateInstance, consultez la documentation du Kit de développement logiciel (SDK) Windows. Pour plus d’informations sur IMMDeviceEnumerator et IMMDevice, consultez Énumération de périphériques audio.

Dans l’exemple de code précédent, la fonction DlgProc affiche le compteur de pointe dans la boîte de dialogue. Pendant le traitement du message WM_INITDIALOG, DlgProc appelle la fonction SetTimer pour configurer un minuteur qui générera des messages WM_TIMER à intervalles réguliers. Lorsque DlgProc reçoit un message WM_TIMER, il appelle IAudioMeterInformation::GetPeakValue pour obtenir la dernière lecture de compteur de pointe pour le flux. DlgProc appelle ensuite la fonction DrawPeakMeter pour dessiner le compteur de pointe mis à jour dans la boîte de dialogue. Pour plus d’informations sur SetTimer et les messages WM_INITDIALOG et WM_TIMER, consultez la documentation du Kit de développement logiciel (SDK) Windows.

Vous pouvez facilement modifier l’exemple de code précédent pour afficher un compteur de pointe pour l’appareil de capture par défaut. Dans la fonction WinMain , remplacez la valeur du premier paramètre de l’appel par IMMDeviceEnumerator::GetDefaultAudioEndpoint d’eRender en eCapture.

L’exemple de code suivant est le script de ressource qui définit les contrôles qui apparaissent dans l’exemple de code précédent :

// 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’exemple de code suivant est le fichier d’en-tête de ressource qui définit les identificateurs de contrôle qui apparaissent dans les exemples de code précédents :

// Resource.h -- Control identifiers

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

Contrôles de volume