德尔福 - 获得波幅

时间:2014-09-22 05:55:29

标签: delphi waveout

我需要制作Delphi库/组件以获取当前播放的声音(它不播放我的应用程序,只是播放扬声器的一般声音)返回数据(左右声道的振幅) )。目前我通过麦克风扫描处理它。他正在寻找,我尝试了网上不同的VU表(Torry ......),但它们与Win7及更高版本不兼容。有人知道解决方案吗?感谢

2 个答案:

答案 0 :(得分:4)

不知道我是否理解正确,如果你的意思是如何获得默认播放设备的峰值电平,你可以试试这个:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Winapi.ActiveX, System.Win.ComObj, MMSystem,
  Vcl.ComCtrls, Vcl.ExtCtrls;

type
  EDATAFLOW = TOleEnum;
  EROLE = TOleEnum;

  IMMDevice = interface(IUnknown)
    ['{D666063F-1587-4E43-81F1-B948E807363F}']
    function Activate(const iid: TGUID; const dwClsCtx: UINT; const pActivationParams: PPropVariant; out ppInterface: IUnknown)
      : HRESULT; stdcall;
  end;

  IMMDeviceCollection = interface(IUnknown)
    ['{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}']
  end;

  IMMDeviceEnumerator = interface(IUnknown)
    ['{A95664D2-9614-4F35-A746-DE8DB63617E6}']
    function EnumAudioEndpoints(const dataFlow: EDATAFLOW; const dwStateMask: DWORD; out ppDevices: IMMDeviceCollection): HRESULT; stdcall;
    function GetDefaultAudioEndpoint(const dataFlow: EDATAFLOW; const role: EROLE; out ppEndpoint: IMMDevice): HRESULT; stdcall;
  end;

  IAudioMeterInformation = interface(IUnknown)
    ['{C02216F6-8C67-4B5B-9D00-D008E73E0064}']
    function GetPeakValue(out pfPeak: Single): HRESULT; stdcall;
    function GetMeteringChannelCount(out pnChannelCount: UINT): HRESULT; stdcall;
    function GetChannelsPeakValues(u32ChannelCount: UINT; out afPeakValues: pSingle): HRESULT; stdcall;
    function QueryHardwareSupport(out pdwHardwareSupportMask: UINT): HRESULT; stdcall;
  end;

  TForm1 = class(TForm)
    ProgressBar1: TProgressBar;
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

const
  IID_IMMDeviceEnumerator: TGUID = '{A95664D2-9614-4F35-A746-DE8DB63617E6}';
  CLASS_IMMDeviceEnumerator: TGUID = '{BCDE0395-E52F-467C-8E3D-C4579291692E}';
  IID_IAudioMeterInformation: TGUID = '{C02216F6-8C67-4B5B-9D00-D008E73E0064}';
  eRender = $00000000;
  eConsole = $00000000;

var
  Form1: TForm1;
  peak: IAudioMeterInformation = nil;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);

var
  device: IMMDevice;
  deviceEnumerator: IMMDeviceEnumerator;
begin
  Timer1.Enabled := False;
  ProgressBar1.Max := 65535; 
  CoCreateInstance(CLASS_IMMDeviceEnumerator, nil, CLSCTX_ALL, IID_IMMDeviceEnumerator, deviceEnumerator);
  deviceEnumerator.GetDefaultAudioEndpoint(eRender, eConsole, device);
  device.Activate(IID_IAudioMeterInformation, CLSCTX_ALL, nil, IUnknown(peak));
  Timer1.Enabled := true;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  Temp: Single;
begin
  peak.GetPeakValue(Temp);
  ProgressBar1.position := Round(Temp * 65535);
end;

end.

答案 1 :(得分:3)

据我所知,您无法直接查找。


Windows不会为您提供其他程序声音输出的信息。 既不是作为直接输入,也不是作为语音混音器的访问权限。此行为的原因是此类访问将绕过版权保护。 (您可以记录媒体播放器或媒体流程序的波形输出。)Windows通常不会为版权侵权提供 API 。这次我将假设你想要执行一些法律服从的(比如音量规范化应用程序),而我共享一个解决方案以绕过这个版权逻辑,但这个解决方案是不容易需要广泛的编程技能

因此,我意识到执行此类任务的唯一方法是创建您自己的虚拟音频设备,然后将其视为默认的波形输出设备。它可以记录接收到的音频数据,同时将其传送到您通常用于波形输出的音频设备。此解决方案的缺点是您必须编写声卡驱动程序 AFAIK Delphi 没有提供编写内核模式驱动程序的方法,因此您必须使用 C / C ++ 。您还必须使用WDK compiler

编写驱动程序并不容易。如果您选择这样做,installing MS Visual Studio (express)将是明智的(但不是必需的)选择。 WDK 包含大量example code个知识库文章,可以向您展示执行此操作的方法。用于您的目的的声卡驱动程序可以使用示例代码在大约10-12个工时内被黑客攻击。

p.s。:请不要忘记编写容易出错的代码!别忘了内核模式软件不能优雅地失败。在内核模式下,未处理的异常或缓冲区溢出可能导致 BSOD

相关问题