Freigeben über


Spitzenmeter

Zur Unterstützung von Windows-Anwendungen, die Spitzenzähler anzeigen, enthält die EndpointVolume-API- eine IAudioMeterInformation- Schnittstelle. Diese Schnittstelle stellt einen Spitzenzähler auf einem Audioendpunktgerätdar. Bei einem Renderinggerät stellt der aus dem Spitzenzähler abgerufene Wert den maximalen Beispielwert im Ausgabedatenstrom während des vorherigen Messzeitraums auf das Gerät dar. Bei einem Aufnahmegerät stellt der aus dem Spitzenzähler abgerufene Wert den maximalen Stichprobenwert dar, der im Eingabedatenstrom des Geräts aufgetreten ist.

Die Spitzenzählerwerte, die aus den Methoden im IAudioMeterInformation Schnittstelle abgerufen werden, sind Gleitkommazahlen im normalisierten Bereich von 0,0 bis 1,0. Wenn z. B. ein PCM-Datenstrom 16-Bit-Stichproben enthält und der Höchstwert während eines bestimmten Messzeitraums "-8914" lautet, lautet der absolute Wert, der vom Spitzenzähler erfasst wird, 8914, und der vom IAudioMeterInformation Schnittstelle gemeldete Normalwert ist 8914/32768 = 0,272.

Wenn das Audioendpunktgerät den Spitzenzähler in der Hardware implementiert, verwendet die IAudioMeterInformation Schnittstelle den Hardware-Spitzenzähler. Andernfalls implementiert die Schnittstelle den Spitzenzähler in der Software.

Wenn ein Gerät über einen Hardware-Spitzenzähler verfügt, ist der Spitzenzähler sowohl im gemeinsam genutzten Modus als auch im exklusiven Modus aktiv. Wenn ein Gerät keine Hardware-Spitzenanzeige hat, ist der Spitzenzähler im gemeinsam genutzten Modus, aber nicht im exklusiven Modus aktiv. Im exklusiven Modus tauschen die Anwendung und die Audiohardware Audiodaten direkt aus und umgehen den Software-Peak-Meter (der immer einen Spitzenwert von 0,0 meldet).

Das folgende C++-Codebeispiel ist eine Windows-Anwendung, die einen Spitzenzähler für das Standardrenderinggerät anzeigt:

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

Im vorangehenden Codebeispiel ruft die WinMain--Funktion die CoCreateInstance-Funktion auf, um eine Instanz der IMMDeviceEnumerator--Schnittstelle zu erstellen, und ruft die IMMDeviceEnumerator::GetDefaultAudioEndpoint Methode auf, um die IMMDevice Schnittstelle des Standardrendergeräts abzurufen. WinMain ruft die IMMDevice::Activate-Methode auf, um die IAudioMeterInformation--Schnittstelle des Geräts abzurufen, und es öffnet ein Dialogfeld, um einen Spitzenzähler für das Gerät anzuzeigen. Weitere Informationen zu WinMain und CoCreateInstancefinden Sie in der Windows SDK-Dokumentation. Weitere Informationen zu IMMDeviceEnumerator und IMMDevice-finden Sie unter Enumerating Audio Devices.

Im vorherigen Codebeispiel zeigt die DlgProc-Funktion den Spitzenzähler im Dialogfeld an. Während der Verarbeitung der WM_INITDIALOG Nachricht ruft DlgProc die SetTimer--Funktion auf, um einen Timer einzurichten, der WM_TIMER Nachrichten in regelmäßigen Zeitintervallen generiert. Wenn DlgProc eine WM_TIMER Nachricht empfängt, ruft es IAudioMeterInformation::GetPeakValue auf, um den neuesten Spitzenzähler für den Datenstrom abzurufen. DlgProc ruft dann die DrawPeakMeter-Funktion auf, um den aktualisierten Spitzenzähler im Dialogfeld zu zeichnen. Weitere Informationen zu SetTimer- und den WM_INITDIALOG und WM_TIMER Meldungen finden Sie in der Windows SDK-Dokumentation.

Sie können das vorangehende Codebeispiel ganz einfach ändern, um einen Spitzenzähler für das Standardaufnahmegerät anzuzeigen. Ändern Sie im WinMain--Funktion den Wert des ersten Parameters im Aufruf des IMMDeviceEnumerator::GetDefaultAudioEndpoint von "eRender" in "eCapture".

Das folgende Codebeispiel ist das Ressourcenskript, das die Steuerelemente definiert, die im vorherigen Codebeispiel angezeigt werden:

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

Das folgende Codebeispiel ist die Ressourcenkopfdatei, die die Steuerelementbezeichner definiert, die in den vorherigen Codebeispielen angezeigt werden:

// Resource.h -- Control identifiers

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