Bagikan melalui


Meter Puncak

Untuk mendukung aplikasi Windows yang menampilkan pengukur puncak, API EndpointVolume menyertakan antarmuka IAudioMeterInformation. Antarmuka ini mewakili pengukur puncak pada perangkat titik akhir audio. Untuk perangkat penyajian, nilai yang diambil dari meteran puncak mewakili nilai sampel maksimum yang ditemui dalam aliran output ke perangkat selama periode pengukuran sebelumnya. Untuk perangkat penangkapan, nilai yang diambil dari meteran puncak mewakili nilai sampel maksimum yang ditemui dalam aliran input dari perangkat.

Nilai meter puncak yang diperoleh dari metode di antarmuka IAudioMeterInformation adalah angka floating-point dalam rentang yang dinormalisasi dari 0,0 hingga 1,0. Misalnya, jika aliran PCM berisi sampel 16-bit, dan nilai sampel puncak selama periode pengukuran tertentu adalah —8914, maka nilai absolut yang dicatat oleh meter puncak adalah 8914, dan nilai puncak yang dinormalisasi yang dilaporkan oleh antarmuka IAudioMeterInformation adalah 8914/32768 = 0,272.

Jika perangkat titik akhir audio mengimplementasikan pengukur puncak dalam perangkat keras, antarmuka IAudioMeterInformation menggunakan pengukur puncak perangkat keras. Jika tidak, antarmuka mengimplementasikan pengukur puncak dalam perangkat lunak.

Jika perangkat memiliki pengukur puncak perangkat keras, meteran puncak aktif baik dalam mode bersama maupun dalam mode eksklusif. Jika perangkat tidak memiliki meteran puncak perangkat keras, meteran puncak aktif dalam mode bersama, tetapi tidak dalam mode eksklusif. Dalam mode eksklusif, aplikasi dan perangkat keras audio bertukar data audio secara langsung, melewati pengukur puncak perangkat lunak (yang selalu melaporkan nilai puncak 0,0).

Contoh kode C++ berikut adalah aplikasi Windows yang menampilkan pengukur puncak untuk perangkat penyajian default:

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

Dalam contoh kode sebelumnya, fungsi WinMain memanggil fungsi CoCreateInstance untuk membuat instans antarmuka IMMDeviceEnumerator, dan memanggil metode IMMDeviceEnumerator::GetDefaultAudioEndpoint untuk mendapatkan antarmuka IMMDevice dari perangkat penyajian default. WinMain memanggil metode IMMDevice::Activate untuk mendapatkan antarmuka IAudioMeterInformation perangkat, dan membuka kotak dialog untuk menampilkan pengukur puncak untuk perangkat. Untuk informasi selengkapnya tentang WinMain dan CoCreateInstance, lihat dokumentasi Windows SDK. Untuk informasi selengkapnya tentang IMMDeviceEnumerator dan IMMDevice, lihat Menghitung Perangkat Audio.

Dalam contoh kode sebelumnya, fungsi DlgProc menampilkan pengukur puncak dalam kotak dialog. Selama pemrosesan pesan WM_INITDIALOG, DlgProc memanggil fungsi SetTimer untuk menyiapkan timer yang akan menghasilkan pesan WM_TIMER pada interval waktu reguler. Ketika DlgProc menerima pesan WM_TIMER, DlgProc memanggil IAudioMeterInformation::GetPeakValue untuk mendapatkan pembacaan meter puncak terbaru untuk aliran. DlgProc kemudian memanggil fungsi DrawPeakMeter untuk menggambar pengukur puncak yang diperbarui dalam kotak dialog. Untuk informasi selengkapnya tentang SetTimer dan pesan WM_INITDIALOG dan WM_TIMER, lihat dokumentasi Windows SDK.

Anda dapat dengan mudah memodifikasi contoh kode sebelumnya untuk menampilkan meteran puncak untuk perangkat penangkapan default. Dalam fungsi WinMain, ubah nilai parameter pertama dalam panggilan ke IMMDeviceEnumerator::GetDefaultAudioEndpoint dari eRender ke eCapture.

Contoh kode berikut adalah skrip sumber daya yang menentukan kontrol yang muncul dalam contoh kode sebelumnya:

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

Contoh kode berikut adalah file header sumber daya yang menentukan pengidentifikasi kontrol yang muncul dalam contoh kode sebelumnya:

// Resource.h -- Control identifiers

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

Kontrol Volume