尖峰計量
為了支持顯示尖峰計量的 Windows 應用程式,EndpointVolume API 包含 IAudioMeterInformation 介面。 此介面代表音訊端點裝置上的尖峰計量。 針對轉譯裝置,從尖峰計量擷取的值代表在前一個計量期間,輸出數據流中遇到的最大樣本值。 針對擷取裝置,從尖峰計量擷取的值代表從裝置輸入數據流中遇到的最大樣本值。
從 IAudioMeterInformation 介面中方法取得的尖峰計量值是標準化範圍從 0.0 到 1.0 的浮點數。 例如,如果 PCM 數據流包含 16 位樣本,而特定計量期間的尖峰樣本值為 - 8914,則尖峰計量所記錄的絕對值為 8914,而 IAudioMeterInformation 介面所報告的標準化尖峰值為 8914/32768 = 0.272。
如果音訊端點裝置在硬體中實作尖峰計量, IAudioMeterInformation 介面會使用硬體尖峰計量。 否則,介面會在軟體中實作尖峰計量。
如果裝置有硬體尖峰計量,尖峰計量在共用模式和獨佔模式中都處於作用中狀態。 如果裝置缺少硬體尖峰計量,尖峰計量會處於共用模式,但不處於獨佔模式。 在獨佔模式中,應用程式和音訊硬體會直接交換音訊數據,略過軟體尖峰計量(一律會報告尖峰值為0.0)。
下列 C++ 程式代碼範例是顯示預設轉譯裝置尖峰計量的 Windows 應用程式:
// 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 介面。 WinMain 會 呼叫 IMMDevice::Activate 方法來取得裝置的 IAudioMeterInformation 介面,並開啟對話框以顯示裝置的尖峰計量。 如需 WinMain 和 CoCreateInstance 的詳細資訊,請參閱 Windows SDK 檔。 如需 IMMDeviceEnumerator 和 IMMDevice 的詳細資訊,請參閱列舉音訊裝置。
在上述程式代碼範例中,DlgProc 函式會在對話框中顯示尖峰計量。 在處理WM_INITDIALOG訊息期間,DlgProc 會呼叫 SetTimer 函式來設定定時器,以定期產生WM_TIMER訊息。 當 DlgProc 收到WM_TIMER訊息時,它會呼叫 IAudioMeterInformation::GetPeakValue 來取得數據流的最新尖峰計量讀數。 DlgProc 接著會呼叫 DrawPeakMeter 函式,以在對話框中繪製更新的尖峰計量。 如需 SetTimer 和WM_INITDIALOG和WM_TIMER訊息的詳細資訊,請參閱 Windows SDK 檔。
您可以輕鬆地修改上述程式代碼範例,以顯示預設擷取裝置的尖峰計量。 在 WinMain 函式中,將呼叫中第一個參數的值從 eRender 變更為 eCapture。IMMDeviceEnumerator::GetDefaultAudioEndpoint。
下列程式代碼範例是資源腳本,可定義上述程式代碼範例中顯示的控件:
// 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
相關主題