Share via


ピーク メーター

ピーク メーターを表示する Windows アプリケーションをサポートするために、EndpointVolume API には IAudioMeterInformation インターフェイスが含まれています。 このインターフェイスは、オーディオ エンドポイント デバイスのピークメーターを表します。 レンダリング デバイスの場合、ピーク メーターから取得された値は、前の測定期間中にデバイスへの出力ストリームで検出された最大サンプル値を表します。 キャプチャ デバイスの場合、ピーク メーターから取得される値は、デバイスからの入力ストリームで検出された最大サンプル値を表します。

IAudioMeterInformation インターフェイスのメソッドから取得されるピークメーターの値は、正規化された範囲の 0.0 から 1.0 までの浮動小数点数です。 たとえば、PCM ストリームに 16 ビット サンプルが含まれており、特定の測定期間中のピーク サンプル値が —8914 の場合、ピーク メーターによって記録される絶対値は 8914 で、IAudioMeterInformation インターフェイスによって報告される正規化されたピーク値は 8914/32768 = 0.272 になります。

オーディオ エンドポイント デバイスがハードウェアにピーク メーターを実装している場合、 IAudioMeterInformation インターフェイスはハードウェア ピーク メーターを使用します。 それ以外の場合、インターフェイスはソフトウェアでピーク メーターを実装します。

デバイスにハードウェア ピーク メーターがある場合、ピーク メーターは共有モードと排他モードの両方でアクティブになります。 デバイスにハードウェア ピーク メーターがない場合、ピーク メーターは共有モードではアクティブですが、排他モードではアクティブになりません。 排他モードでは、アプリケーションとオーディオ ハードウェアは、ソフトウェアのピーク メーター (常にピーク値 0.0 を報告) をバイパスして、オーディオ データを直接やり取りします。

以下に、既定のレンダリング デバイスのピーク メーターを表示する Windows アプリケーションの、C++ コードの例を示しています。

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

前のコード例では、WinMain 関数は CoCreateInstance 関数を呼び出して IMMDeviceEnumerator インターフェイスのインスタンスを作成し、IMMDeviceEnumerator::GetDefaultAudioEndpoint メソッドを呼び出して既定のレンダリング デバイスの IMMDevice インターフェイスを取得します。 WinMainIMMDevice::Activate メソッドを呼び出してデバイスの IAudioMeterInformation インターフェイスを取得し、ダイアログ ボックスを開いてデバイスのピーク メーターを表示します。 WinMainCoCreateInstance の詳細については、Windows SDK のドキュメントを参照してください。 IMMDeviceEnumeratorIMMDevice の詳細については、「オーディオ デバイスの列挙」を参照してください。

前のコード例では、DlgProc 関数でダイアログ ボックスにピーク メーターが表示されています。 WM_INITDIALOG メッセージの処理中に、DlgProc は SetTimer 関数を呼び出して、一定の時間間隔で WM_TIMER メッセージを生成するタイマーを設定します。 DlgProc は、WM_TIMER メッセージを受信すると、IAudioMeterInformation::GetPeakValue を呼び出して、ストリームの最新のピークメーターの読み取り値を取得します。 次に、DlgProc は DrawPeakMeter 関数を呼び出して、ダイアログ ボックスで更新されたピーク メーターを引き出します。 SetTimer と WM_INITDIALOG メッセージとWM_TIMER メッセージの詳細については、Windows SDK のドキュメントを参照してください。

前のコード例を簡単に変更して、既定のキャプチャ デバイスのピーク メーターを表示できます。 WinMain 関数で、IMMDeviceEnumerator::GetDefaultAudioEndpoint への呼び出しの最初のパラメーターの値を eRender から eCapture に変更します。

次のコード例は、前のコード例に表示されるコントロールを定義するリソース スクリプトです。

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

以下は、前のコード例で表示されるコントロール識別子を定義するリソース ヘッダー ファイルのコード例です。

// Resource.h -- Control identifiers

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

ボリューム コントロール