Delphi中捕获音频函数OnWaveIn的使用小记

   2023-02-09 学习力0
核心提示:    说明,并非给别人看,只是为了防止自己忘记,所以没有写说明与注释之类的,不好意思了。     上次有个朋友叫我帮忙写一个小程序,用处比较怪。显示图片,并开始计时,当测试者说出图像内容的时候(无需识别具体的语音内容),停止计时。这样循环显
    说明,并非给别人看,只是为了防止自己忘记,所以没有写说明与注释之类的,不好意思了。

     上次有个朋友叫我帮忙写一个小程序,用处比较怪。显示图片,并开始计时,当测试者说出图像内容的时候(无需识别具体的语音内容),停止计时。这样循环显示一系列图片,并记录从显示图片,到发出声音的这段时间。据说是研究语言学使用的。于是用Delphi写了一个小程序,其中记录声音,过滤噪音,判断是否发出声音的程序如下:

unit SoundCap_Unit;

interface

uses
    Windows, Messages, MMSystem, Classes, SysUtils, Math, Forms, Controls;

Const
  BufferTime : Real 
= 120;  // 每次0.120秒   0.120 * 1000

type

  TData8 
= array [0..127] of byte;
  PData8 
= ^TData8;
  TData16 
= array [0..127] of smallint;
  PData16 
= ^TData16;
  TPointArr 
= array [0..127] of TPoint;
  PPointArr 
= ^TPointArr;


  TShowProgressEvent 
= procedure (Sender: TObject; Position: Integer) of object;
  TCaptureEvent 
= procedure (Sender: TObject; passTime : Integer) of Object;
  TShowTimeEvent 
= procedure (Sender : TObject; Time : Integer) of Object;

  TSoundCap 
= Class(TCustomControl)

  
private
    FOnShowTime : TShowTimeEvent;
    FOnShowProgress : TShowProgressEvent;
    FOnCapture : TCaptureEvent;

    function GetMidValue(i : Integer) : Integer;  
//计算中值
  protected

    procedure DoShowTime;
//(Time : Integer); dynamic;
    procedure DoShowProgress(position : Integer); dynamic;
    procedure DoCapture(passTime : DWORD ); dynamic;

  
public

    FilterValve : Integer; 
//音频过滤的阀值

    isCapture : 
boolean ;

    
//constructor Create(AOwner: TComponent); overload;
    constructor Create(handle : THandle); //overload;
    destructor Destroy; override;

    procedure OpenCapture(handle : THandle);
    procedure CloseCapture;

    procedure OnWaveIn(var Msg: TMessage); message MM_WIM_DATA;
    procedure StartCap;
    procedure StopCap;
    property OnShowTime: TShowTimeEvent read FOnShowTime write FOnShowTime;
    property OnShowProgress: TShowProgressEvent read FOnShowProgress write FOnShowProgress;
    property OnCapture: TCaptureEvent read FOnCapture write FOnCapture;

  end;


implementation

{ TSoundCap }


var
  WaveIn: hWaveIn;
  hBuf: THandle;
  BufHead: TWaveHdr;
  bufsize: integer;
  Bits16: 
boolean;
  p: PPointArr;
  p2 : PPointArr;
  stop: 
boolean = false;

  StartTime : DWORD ;
  Count : integer 
= 0;

constructor TSoundCap.Create(Handle : THandle);
//(AOwner: TComponent);
begin
//  ParentWindow := AOwner;
  Inherited Create(nil);
  ParentWindow :
= handle;
  isCapture :
= false;
  FilterValve :
= 3;
end;

destructor TSoundCap.Destroy;
begin

  inherited;
  CloseCapture;
end;

//触发捕获音频事件
procedure TSoundCap.DoCapture(passTime : DWORD );
var
  EndTime : DWORD ;
begin
  EndTime :
= GetTickCount;
  
if Assigned(FOnCapture) then FOnCapture(Self, EndTime - StartTime - passTime);
end;

//显示音频强度
procedure TSoundCap.DoShowProgress(position: Integer);
begin
  
if Assigned(FOnShowProgress) then FOnShowProgress(Self, position);
end;

//显示时间
procedure TSoundCap.DoShowTime;//(Time : Integer);
var
  EndTime : DWORD ;
begin
  EndTime :
= GetTickCount;
  
if Assigned(FOnShowTime) then FOnShowTime(Self, EndTime - StartTime);
end;


//中值过滤
function TSoundCap.GetMidValue(i: Integer): Integer;
var
  v0,v1,v2 : integer;
  h : integer;
  mid : integer;
begin
  h :
= 100;
  v0 :
= p^[i-2].Y;
  v1 :
= p^[i-1].Y;
  v2 :
= p^[i].Y;

  mid :
= (v0 + v1 + v2) div 3;
  
if abs(abs(mid) - v1) > FilterValve  then
    Result :
= mid
  Else 
if abs(mid - h/2< FilterValve then
    Result :
= 0
  Else
    Result :
= v1;
end;


//处理Wave数据采集
procedure TSoundCap.OnWaveIn(var Msg: TMessage);
var
  data8 : PData8;
  i, x, y : integer;

  StartPos, EndPos, SCount : integer;
  passTime , MaxValue , tmp : Integer;
  dtime : DWORD;
begin
    
//DoCapture(0);

    MaxValue :
= 0;
    Data8 :
= PData8(PWaveHdr(Msg.lParam)^.lpData);

    
//将Buffer中采集的数据存入 P 中
    for i := 0 to BufSize - 1 do
    Begin

      x :
= i;
      y :
= Round(abs(data8^[i] - 128* 100 / 128); //data8^[i] 为 128 - 256 之间
      p^[i] := Point(x, y);

      
//计算滤波后的值 , 滤波之后的数据存入 P2 中
      if (i > 1) and (i < BufSize )  then
      Begin
        p2
^[i] := Point(p^[i].X, GetMidValue(i));
      end;

      
//p2^[i] := GetMidValue(x,y,i);
      
//Inc(count,data8^[i]);
      
//count := count + Round(abs(data8^[i] - 128) * 100 / 128);
      
//ShowProgress(Round(count / BufSize));

      tmp :
= Round(abs(data8^[i] - 128* 100 / 128);
      
if tmp > MaxValue Then
        MaxValue :
= tmp;
      
//count := count + tmp;

    End;


    p2
^[0] := Point(p^[0].X, GetMidValue(2));
    p2
^[1] := Point(p^[0].X, GetMidValue(2));

  
//Caption := IntToStr(count div BufSize);

  
//不需要绘画音频曲线
  {
  with PaintBox1.Canvas 
do begin
    Brush.Color :
= clBlack;
    Pen.Color :
= clGreen;

    FillRect(ClipRect);
    Polyline(Slice(p
^, BufSize));
  end;

  with PaintBox2.Canvas 
do begin
    Brush.Color :
= clBlack;
    Pen.Color :
= clGreen;

    FillRect(ClipRect);
    Polyline(Slice(p2
^, BufSize));
  end;
  }

  
//判断是否有超出域值的数据
  StartPos := 0;
  EndPos :
= 0;
  SCount :
= 0;
  
for I := 0 to BufSize - 1 do
  begin
    
if abs(p2^[i].Y ) > FilterValve  then
    Begin
      
if StartPos = 0 then
        StartPos :
= i;
      Inc(SCount);
    end Else 
if StartPos = 0  then
        p
^[i].Y :=  0;//h div 2;

    
if (SCount > 20) then
      
if (EndPos = 0) then
        EndPos :
= Min((StartPos + BufSize div 2 ) , BufSize - 1)
      Else 
if EndPos < i then
        p
^[i].Y := 0;//h div 2;

  end;

  {
  
if (SCount > 20) and isCapture then
  with PaintBox3.Canvas 
do begin
    Brush.Color :
= clBlack;
    Pen.Color :
= clGreen;

    FillRect(ClipRect);
    Polyline(Slice(p
^, BufSize));
    isCapture :
= false;
    Timer1.Enabled :
= true;
    passTime :
= Round(StartPos * BufferTime / BufSize);
    RecordTime(passTime);
  end; }

  
//Show Time
  If isCapture  Then DoShowTime();

  
//SCount := 100;
  
//StartPos := 0;
  
//如果有音频超出阀值,并且正在捕捉,则记录具体时间
  dtime := GetTickCount - StartTime;
  
//如果说 dtime < 120 , 则这个Buffer不是现在的缓冲内容
  if (SCount > 20) and isCapture and (dtime > 120 + 90) then
  Begin
    isCapture :
= false;
    
//Timer1.Enabled := true;
    passTime := Round((BufSize - StartPos) * BufferTime / BufSize) + 90;
    DoCapture(passTime);
  End;

  
if stop then WaveInAddBuffer(WaveIn, PWaveHdr(Msg.lParam),
      SizeOf(TWaveHdr))
    
else stop := true;

  DoShowProgress(MaxValue);
  
//DoCapture(0);
end;

//打开音频捕捉
procedure TSoundCap.OpenCapture(handle : THandle);
var
  header: TWaveFormatEx;
  BufLen: word;
  buf: pointer;
begin
  BufSize :
= 3 * 500 + 100;//TrackBar1.Position * 500 + 100;
  Bits16 := false;//CheckBox1.Checked;
  with header do begin
    wFormatTag :
= WAVE_FORMAT_PCM;
    nChannels :
= 1;
    nSamplesPerSec :
= 22050;
    wBitsPerSample :
= integer(Bits16) * 8 + 8;
    nBlockAlign :
= nChannels * (wBitsPerSample div 8 );
    nAvgBytesPerSec :
= nSamplesPerSec * nBlockAlign;
    cbSize :
= 0;
  end;

  WaveInOpen(Addr(WaveIn), WAVE_MAPPER, addr(header),
              self.Handle , 
0, CALLBACK_WINDOW);
  BufLen :
= header.nBlockAlign * BufSize;
  hBuf :
= GlobalAlloc(GMEM_MOVEABLE and GMEM_SHARE, BufLen);
  Buf :
= GlobalLock(hBuf);
  with BufHead 
do begin
    lpData :
= Buf;
    dwBufferLength :
= BufLen;
    dwFlags :
= WHDR_BEGINLOOP;
  end;
  WaveInPrepareHeader(WaveIn, Addr(BufHead), sizeof(BufHead));
  WaveInAddBuffer(WaveIn, addr(BufHead), sizeof(BufHead));
  GetMem(p, BufSize 
* sizeof(TPoint));
  GetMem(p2, BufSize 
* sizeof(TPoint));

  stop :
= true;
  WaveInStart(WaveIn);
  StartTime :
= GetTickCount;
end;

//关闭音频捕捉
procedure TSoundCap.CloseCapture;
begin
  
if stop = false then Exit;
  stop :
= false;
  
while not stop do Application.ProcessMessages;
  
//while not stop do sleep
  stop := false;
  WaveInReset(WaveIn);
  WaveInUnPrepareHeader(WaveIn, addr(BufHead), sizeof(BufHead));
  WaveInClose(WaveIn);
  GlobalUnlock(hBuf);
  GlobalFree(hBuf);
  FreeMem(p, BufSize 
* sizeof(TPoint));
  FreeMem(p2, BufSize 
* sizeof(TPoint));
end;

//开始监视捕捉, 并显示时间
procedure TSoundCap.StartCap;
begin
  isCapture :
= true;
  StartTime :
= GetTickCount;
end;

//停止监视音频捕捉
procedure TSoundCap.StopCap;
begin
  isCapture :
= false;
end;

end.


具体调用:

  SoundCap := TSoundCap.Create(self.Handle);
  SoundCap.OnShowProgress :
= OnSoundPosition;
  SoundCap.OnShowTime :
= OnShowTime;
  SoundCap.OnCapture :
= OnCapture;
  Delphi中捕获音频函数OnWaveIn的使用小记
  Delphi中捕获音频函数OnWaveIn的使用小记
  SoundCap.OpenCapture(MainForm.Handle);

  Delphi中捕获音频函数OnWaveIn的使用小记..
  SoundCap.CloseCapture;




 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • Delphi中的消息处理机制 delphi 方法
    每一个VCL都有一内在的消息处理机制,其基本点就是构件类接收到某些消息并把它们发送给适当的处理方法,如果没有特定的处理方法,则调用缺省的消息处理句柄。    其中mainwndproc是定义在Twincontrol类中的一个静态方法,不能被重载(Override)。它不直接处
    02-09
  • Delphi XE6 通过JavaScript API调用百度地图
    Delphi XE6 通过JavaScript API调用百度地图
    参考昨天的内容,有朋友还是问如何调用百度地图,也是,谁让咱都在国内呢,没办法,你懂的。 首先去申请个Key,然后看一下百度JavaScript的第一个例子:http://developer.baidu.com/map/jsdemo.htm下一步,就是把例子中的代码,移动TWebBrower中。 unit Unit
    02-09
  • Delphi编译/链接过程 delphi编程案例
    Delphi编译/链接过程 delphi编程案例
    下面展示了Delphi是怎样编译源文件,并且把它们链接起来,最终形成可执行文件。当Delphi编译项目(Project)时,将编译项目源文件、窗体单元和其他相关单元,在这个过程中将会发生好几件事情:首先,Object Pascal编译器把项目单元编译为二进制对象文件,然后
    02-09
  • Delphi CompilerVersion Constant / Compiler C
    http://delphi.wikia.com/wiki/CompilerVersion_Constant The CompilerVersion constant identifies the internal version number of the Delphi compiler.It is defined in the System unit and may be referenced either in code just as any other consta
    02-09
  • Delphi revelations #1 – kbmMW Smart client
    Delphi 启示 #1 – kbmMW Smart client on NextGen (Android) – 作用域问题以更高级的方式使用kbmMW smart client,在Android设备上,我遇到了问题。通过继承TInvokeableVariantType,kbmMW smart client可以使用Delphi支持的特殊类型的自定义Variant,从而可
    02-09
  • Delphi 调用DLL外部函数时的指针参数
    某项目需要调用设备厂家提供的DLL的函数,厂家给了一个VB的例子,有个参数是ByRef pBuffer As Single。于是在Delphi中用buffer:array of single代替:function func(buffer:array of single;count:integer):integer;far;stdcall;external 'func.dll';调用后bu
    02-09
  • 《zw版·Halcon-delphi系列原创教程》 Halcon分
    《zw版·Halcon-delphi系列原创教程》 Halcon分类函数012,polygon,多边形为方便阅读,在不影响说明的前提下,笔者对函数进行了简化::: 用符号“**”,替换:“procedure”:: 用大写字母“X”,替换:“IHUntypedObjectX”:: 省略了字符:“const”、“OleVa
    02-09
  • 最简单的delphi启动画面(转)
    首先做一窗体,然后将BorderStyle的属性设为bsnone,放image控件,align设为alclient 然后将主程序的修改为 uses Windows, Forms, Unit1 in 'Unit1.pas' {Form1}, Unit2 in 'Unit2.pas' {Form2}; {$ R *.res} begin Application.Initialize; Form2:=TForm2.Cre
    02-09
  • Delphi备忘三:TCollection的使用,用Stream保
     代码unit ufrmGetFunctionDefine;interfaceuses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,TypInfo,  Dialogs,ufrmStockBaseCalc, StdCtrls, ComCtrls,uQEFuncManager,uWnDataSet,uDataService;type  T
    02-09
  • Delphi Dcp 和BPL的解释
    dcp = delphi compiled package,是 package 编译时跟 bpl 一起产生出来的,记录着 package 中公开的 class、procedure、function、variable、const.... 等等的名称和相对位址。package英文翻译过来就是“包”。如果 某个控件包 A 引用了 控件包 B,当 控件包
    02-09
点击排行