unit ACMOut;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ACMConvertor, MMSystem, MSACM;
type
EACMOut = class(Exception);
TBufferPlayedEvent = procedure(Sender : TObject; Header : PWaveHDR) of object;
TACMOut = class(TComponent)
private
{ Private declarations }
FActive : Boolean;
FNumBuffersLeft : Byte;
FBackBufferList : TList;
FNumBuffers : Byte;
FBufferList : TList;
FFormat : TACMWaveFormat;
FOnBufferPlayed : TBufferPlayedEvent;
FWaveOutHandle : HWaveOut;
FWindowHandle : HWnd;
function GetBufferCount: Integer;
protected
{ Protected declarations }
function NewHeader : PWaveHDR;
procedure DisposeHeader(Header : PWaveHDR);
procedure DoWaveDone(Header : PWaveHdr);
procedure WndProc(var Message : TMessage);
public
{ Public declarations }
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
procedure Close;
procedure Open(aFormat : TACMWaveFormat);
procedure Play(var Buffer; Size : Integer);
procedure RaiseException(const aMessage : String; Result : Integer); property Active : Boolean
read FActive;
property BufferCount : Integer
read GetBufferCount;
property Format : TACMWaveFormat
read FFormat;
property WindowHandle : HWnd
read FWindowHandle; published
{ Published declarations }
property NumBuffers : Byte
read FNumBuffers
write FNumBuffers;
property OnBufferPlayed : TBufferPlayedEvent
read FOnBufferPlayed
write FOnBufferPlayed;
end;procedure Register;implementationprocedure Register;
begin
RegisterComponents('Sound', [TACMOut]);
end;{ TACMOut }procedure TACMOut.Close;
var
X : Integer;
begin
if not Active then exit;
FActive := False;
WaveOutReset(FWaveOutHandle);
WaveOutClose(FWaveOutHandle);
FBackBufferList.Clear;
FWaveOutHandle := 0;
For X:=FBufferList.Count-1 downto 0 do DisposeHeader(PWaveHDR(FBufferList[X]));
end;constructor TACMOut.Create(AOwner: TComponent);
begin
inherited;
FBufferList := TList.Create;
FBackBufferList := TList.Create;
FActive := False;
FWindowHandle := AllocateHWND(WndProc);
FWaveOutHandle := 0;
FNumBuffers := 4;end;destructor TACMOut.Destroy;
begin
if Active then Close;
FBufferList.Free;
DeAllocateHWND(FWindowHandle);
FBackBufferList.Free;
inherited;
end;procedure TACMOut.DisposeHeader(Header: PWaveHDR);
var
X : Integer;
begin
X := FBufferList.IndexOf(Header);
if X < 0 then exit;
Freemem(header.lpData);
Freemem(header);
FBufferList.Delete(X);
end;procedure TACMOut.DoWaveDone(Header : PWaveHdr);
var
Res : Integer;
begin
if not Active then exit;
if Assigned(FOnBufferPlayed) then FOnBufferPlayed(Self, Header);
Res := WaveOutUnPrepareHeader(FWaveOutHandle, Header, SizeOf(TWaveHDR));
if Res <> 0 then RaiseException('WaveOut-UnprepareHeader',Res);
DisposeHeader(Header);
end;function TACMOut.GetBufferCount: Integer;
begin
Result := FBufferList.Count;
end;function TACMOut.NewHeader: PWaveHDR;
begin
GetMem(Result, SizeOf(TWaveHDR));
FBufferList.Add(Result);
end;procedure TACMOut.Open(aFormat: TACMWaveFormat);
var
Res : Integer;
Device : Integer;
Params : Integer;
begin
if Active then exit;
FWaveOutHandle := 0;
FNumBuffersLeft := FNumBuffers;
FFormat := aFormat; if FFormat.Format.wFormatTag = 1 then begin
Params := CALLBACK_WINDOW or WAVE_MAPPED;
Device := 0;
end else begin
Params := CALLBACK_WINDOW or WAVE_MAPPED;
Device := 0;
end;
Res := WaveOutOpen(@FWaveOutHandle,Device,@FFormat.Format,FWindowHandle,0, params);
if Res <> 0 then exit;
//RaiseException('WaveOutOpen',Res);
FActive := True;
end;procedure TACMOut.Play(var Buffer; Size: Integer);
var
TempHeader : PWaveHdr;
Data : Pointer;
Res : Integer;
X : Integer; procedure PlayHeader(Header : PWaveHDR);
begin
Res := WaveOutPrepareHeader(FWaveOutHandle,Header,SizeOf(TWaveHDR));
if Res <> 0 then RaiseException('WaveOut-PrepareHeader',Res); Res := WaveOutWrite(FWaveOutHandle, Header, SizeOf(TWaveHDR));
if Res <> 0 then RaiseException('WaveOut-Write',Res);
end;begin
if Size = 0 then exit;
if not active then exit;
TempHeader := NewHeader;
GetMem(Data, Size);
Move(Buffer,Data^,Size);
with TempHeader^ do begin
lpData := Data;
dwBufferLength := Size;
dwBytesRecorded :=0; //Was " := Size;" but not needed, and crashes some PC's
dwUser := 0;
dwFlags := 0;
dwLoops := 1;
end; if FNumBuffersLeft > 0 then begin
FBackBufferList.Add(TempHeader);
Dec(FNumBuffersLeft);
end else begin
for X:=0 to FBackBufferList.Count-1 do
PlayHeader(PWaveHDR(FBackBufferList[X]));
FBackBufferList.Clear;
PlayHeader(TempHeader);
end;
end;procedure TACMOut.RaiseException(const aMessage: String; Result: Integer);
begin
case Result of
ACMERR_NotPossible : Raise EACMOut.Create(aMessage + ' The requested operation cannot be performed.');
ACMERR_BUSY : Raise EACMOut.Create(aMessage + ' The conversion stream is already in use.');
ACMERR_UNPREPARED : Raise EACMOut.Create(aMessage + ' Cannot perform this action on a header that has not been prepared.');
MMSYSERR_InvalFlag : Raise EACMOut.Create(aMessage + ' At least one flag is invalid.');
MMSYSERR_InvalHandle : Raise EACMOut.Create(aMessage + ' The specified handle is invalid.');
MMSYSERR_InvalParam : Raise EACMOut.Create(aMessage + ' At least one parameter is invalid.');
MMSYSERR_NoMem : Raise EACMOut.Create(aMessage + ' The system is unable to allocate resources.');
MMSYSERR_NoDriver : Raise EACmOut.Create(aMessage + ' A suitable driver is not available to provide valid format selections.');
MMSYSERR_ALLOCATED : Raise EACMOut.Create(aMessage + ' The specified resource is already in use.');
MMSYSERR_BADDEVICEID : Raise EACMOut.Create(aMessage + ' The specified resource does not exist.');
WAVERR_BADFORMAT : Raise EACMOut.Create(aMessage + ' Unsupported audio format.');
WAVERR_SYNC : Raise EACMOut.Create(aMessage + ' The specified device does not support asynchronous operation.');
else
if Result <> 0 then
Raise EACMOut.Create(SysUtils.Format('%s raised an unknown error (code #%d)',[aMessage,Result]));
end;end;procedure TACMOut.WndProc(var Message: TMessage);
begin
case Message.Msg of
MM_WOM_DONE : DoWaveDone(PWaveHDR(Message.LParam));
end;
end;end.
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ACMConvertor, MMSystem, MSACM;
type
EACMOut = class(Exception);
TBufferPlayedEvent = procedure(Sender : TObject; Header : PWaveHDR) of object;
TACMOut = class(TComponent)
private
{ Private declarations }
FActive : Boolean;
FNumBuffersLeft : Byte;
FBackBufferList : TList;
FNumBuffers : Byte;
FBufferList : TList;
FFormat : TACMWaveFormat;
FOnBufferPlayed : TBufferPlayedEvent;
FWaveOutHandle : HWaveOut;
FWindowHandle : HWnd;
function GetBufferCount: Integer;
protected
{ Protected declarations }
function NewHeader : PWaveHDR;
procedure DisposeHeader(Header : PWaveHDR);
procedure DoWaveDone(Header : PWaveHdr);
procedure WndProc(var Message : TMessage);
public
{ Public declarations }
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
procedure Close;
procedure Open(aFormat : TACMWaveFormat);
procedure Play(var Buffer; Size : Integer);
procedure RaiseException(const aMessage : String; Result : Integer); property Active : Boolean
read FActive;
property BufferCount : Integer
read GetBufferCount;
property Format : TACMWaveFormat
read FFormat;
property WindowHandle : HWnd
read FWindowHandle; published
{ Published declarations }
property NumBuffers : Byte
read FNumBuffers
write FNumBuffers;
property OnBufferPlayed : TBufferPlayedEvent
read FOnBufferPlayed
write FOnBufferPlayed;
end;procedure Register;implementationprocedure Register;
begin
RegisterComponents('Sound', [TACMOut]);
end;{ TACMOut }procedure TACMOut.Close;
var
X : Integer;
begin
if not Active then exit;
FActive := False;
WaveOutReset(FWaveOutHandle);
WaveOutClose(FWaveOutHandle);
FBackBufferList.Clear;
FWaveOutHandle := 0;
For X:=FBufferList.Count-1 downto 0 do DisposeHeader(PWaveHDR(FBufferList[X]));
end;constructor TACMOut.Create(AOwner: TComponent);
begin
inherited;
FBufferList := TList.Create;
FBackBufferList := TList.Create;
FActive := False;
FWindowHandle := AllocateHWND(WndProc);
FWaveOutHandle := 0;
FNumBuffers := 4;end;destructor TACMOut.Destroy;
begin
if Active then Close;
FBufferList.Free;
DeAllocateHWND(FWindowHandle);
FBackBufferList.Free;
inherited;
end;procedure TACMOut.DisposeHeader(Header: PWaveHDR);
var
X : Integer;
begin
X := FBufferList.IndexOf(Header);
if X < 0 then exit;
Freemem(header.lpData);
Freemem(header);
FBufferList.Delete(X);
end;procedure TACMOut.DoWaveDone(Header : PWaveHdr);
var
Res : Integer;
begin
if not Active then exit;
if Assigned(FOnBufferPlayed) then FOnBufferPlayed(Self, Header);
Res := WaveOutUnPrepareHeader(FWaveOutHandle, Header, SizeOf(TWaveHDR));
if Res <> 0 then RaiseException('WaveOut-UnprepareHeader',Res);
DisposeHeader(Header);
end;function TACMOut.GetBufferCount: Integer;
begin
Result := FBufferList.Count;
end;function TACMOut.NewHeader: PWaveHDR;
begin
GetMem(Result, SizeOf(TWaveHDR));
FBufferList.Add(Result);
end;procedure TACMOut.Open(aFormat: TACMWaveFormat);
var
Res : Integer;
Device : Integer;
Params : Integer;
begin
if Active then exit;
FWaveOutHandle := 0;
FNumBuffersLeft := FNumBuffers;
FFormat := aFormat; if FFormat.Format.wFormatTag = 1 then begin
Params := CALLBACK_WINDOW or WAVE_MAPPED;
Device := 0;
end else begin
Params := CALLBACK_WINDOW or WAVE_MAPPED;
Device := 0;
end;
Res := WaveOutOpen(@FWaveOutHandle,Device,@FFormat.Format,FWindowHandle,0, params);
if Res <> 0 then exit;
//RaiseException('WaveOutOpen',Res);
FActive := True;
end;procedure TACMOut.Play(var Buffer; Size: Integer);
var
TempHeader : PWaveHdr;
Data : Pointer;
Res : Integer;
X : Integer; procedure PlayHeader(Header : PWaveHDR);
begin
Res := WaveOutPrepareHeader(FWaveOutHandle,Header,SizeOf(TWaveHDR));
if Res <> 0 then RaiseException('WaveOut-PrepareHeader',Res); Res := WaveOutWrite(FWaveOutHandle, Header, SizeOf(TWaveHDR));
if Res <> 0 then RaiseException('WaveOut-Write',Res);
end;begin
if Size = 0 then exit;
if not active then exit;
TempHeader := NewHeader;
GetMem(Data, Size);
Move(Buffer,Data^,Size);
with TempHeader^ do begin
lpData := Data;
dwBufferLength := Size;
dwBytesRecorded :=0; //Was " := Size;" but not needed, and crashes some PC's
dwUser := 0;
dwFlags := 0;
dwLoops := 1;
end; if FNumBuffersLeft > 0 then begin
FBackBufferList.Add(TempHeader);
Dec(FNumBuffersLeft);
end else begin
for X:=0 to FBackBufferList.Count-1 do
PlayHeader(PWaveHDR(FBackBufferList[X]));
FBackBufferList.Clear;
PlayHeader(TempHeader);
end;
end;procedure TACMOut.RaiseException(const aMessage: String; Result: Integer);
begin
case Result of
ACMERR_NotPossible : Raise EACMOut.Create(aMessage + ' The requested operation cannot be performed.');
ACMERR_BUSY : Raise EACMOut.Create(aMessage + ' The conversion stream is already in use.');
ACMERR_UNPREPARED : Raise EACMOut.Create(aMessage + ' Cannot perform this action on a header that has not been prepared.');
MMSYSERR_InvalFlag : Raise EACMOut.Create(aMessage + ' At least one flag is invalid.');
MMSYSERR_InvalHandle : Raise EACMOut.Create(aMessage + ' The specified handle is invalid.');
MMSYSERR_InvalParam : Raise EACMOut.Create(aMessage + ' At least one parameter is invalid.');
MMSYSERR_NoMem : Raise EACMOut.Create(aMessage + ' The system is unable to allocate resources.');
MMSYSERR_NoDriver : Raise EACmOut.Create(aMessage + ' A suitable driver is not available to provide valid format selections.');
MMSYSERR_ALLOCATED : Raise EACMOut.Create(aMessage + ' The specified resource is already in use.');
MMSYSERR_BADDEVICEID : Raise EACMOut.Create(aMessage + ' The specified resource does not exist.');
WAVERR_BADFORMAT : Raise EACMOut.Create(aMessage + ' Unsupported audio format.');
WAVERR_SYNC : Raise EACMOut.Create(aMessage + ' The specified device does not support asynchronous operation.');
else
if Result <> 0 then
Raise EACMOut.Create(SysUtils.Format('%s raised an unknown error (code #%d)',[aMessage,Result]));
end;end;procedure TACMOut.WndProc(var Message: TMessage);
begin
case Message.Msg of
MM_WOM_DONE : DoWaveDone(PWaveHDR(Message.LParam));
end;
end;end.
解决方案 »
- 各位高手我想问的是如何将Excel表里面设置成为DELPHI报表来使用
- 不知Delphi能否像VB那样实现此窗体
- 一个不错的网址导航网站!
- 300分求助,Delphi如果调用VC写的DLL来完成磁卡读写器的操作
- 小弟刚开始学Delphi,有没有经常在线的高手加我QQ:71910482~~~~~~~~~~~
- 这个网站的书价格最高才8折,全国免邮费,肯定是“当当书店”的劲敌,大家快注册啦
- 一个奇怪的问题?盼高手解决
- $ 300 -- 有没有人用过条形码打印控件TBarCode ? 他一定要有Delphi 开着才能运行(未注册!)
- 怎样做数据库的备分与还原,生成一个.bak文件
- 请问 Delphi 6 在文件系统方面有没有什么新功能?
- 请教各位:我该如何划线?
- DELPHI 中怎样利用DELPHI+nmstmp发EMAIL
TACMOut.Open(aFormat: TACMWaveFormat);
TACMOut.Play(var Buffer; Size: Integer);
TACMOut.Close;网上去找acmaudio控件
个人意见:
原单元中有几处小错
过程:procedure TACMOut.Open(aFormat: TACMWaveFormat);中作了一下改动
(播放gsm格式声音的问题,改一下就好了,对于pcm格式可正常使用,acmin单元中也应作相应改动)
WAVEHDR里面地buffer指针所指向的区域应该分配多大?我简单的分配为nAvgBytesPerSec可以否?昨天看了一天的资料,现在知道用MM_WOM_系列的消息了。
但是在MM_WOM_OPEN里面第一次使用waveOutWrite就出错。
不知道是指针问题还是调用函数出错。麻烦。
WaveOut(输出)那就想多大就多大,不超过内存即可。WaveOut:WaveOutOpen(FWaveID, 0, @FFormat, Handle, 0, CALLBACK_WINDOW or WAVE_MAPPED); //用这个Flag//对应的消息是:MM_WOM_DONE
//procedure WaveOutCallback(var msg: TMessage); message MM_WOM_DONE;
procedure TWaveOut.WaveOutCallback(var msg: TMessage);
var
Header: PWaveHdr;
begin
Header := PWaveHdr(msg.LParam);
try
if FActive then
begin
WaveOutUnPrepareHeader(FWaveID^, Header, SizeOf(TWaveHdr));
//再继续输出,就是增加输出Buffer
AutoPlayBuffer;
end;
finally
DeleteBuffer(Header); //删除/Free指针
end;
end;还有错误处理,只要调用对应的GetErrorText即可,不要用上面的raiseException(ErrorCode)函数了。function GetLen(S: string): Integer;
var
Len: Integer;
begin
Result := 1;
Len := Length(S);
while not (S[Result] = #0) and (Result < Len) do Inc(Result);
end;procedure TWaveOut.CheckError(Res: Integer);
var
S: string;
begin
if Res <> 0 then
begin
SetLength(S, MAXERRORLENGTH);
waveOutGetErrorText(Res, PChar(S), MAXERRORLENGTH);
//waveInGetErrorText(Res, PChar(S), MAXERRORLENGTH);
SetLength(msg, GetLen(msg));
raise EWaveException.Create(msg);
end;
end;Wave一般操作是:
New(WaveID); //var WaveID: PInteger;
WaveInOpen/WaveOutOpen打开这个WaveID,并为它提供消息回调
之后
WaveIn: 在回调函数中,进行录音数据处理(数据在消息的LParam, WParam中)
,因为在作存数据(Buffer),所以要增加一定的Buffer给它,waveInPrepareHeader-->waveInAddBuffer
然后就可能WaveInStart了。WaveOut简单,打开后就直接WaveOutPrepareHeader-->WaveOutWrite知道就这些。大概也就这样,不明再问。
看看那里面的TWaveOut类,给它一个Format: TWaveFormatEx,然后直接播放(PlayBack)试试