【问题标题】:Error waveOutOpen when play wav more times [delphi]多次播放 wav 时出现错误 waveOutOpen [delphi]
【发布时间】:2015-11-25 14:32:48
【问题描述】:

我从互联网上找到代码,首先我播放波形文件并没有问题,然后我播放 wav 更多次并在 48 次出现错误。我知道来自 waveOutOpen 函数的错误。

这是我的代码:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation
uses MMSystem;

{$R *.dfm}


var

  buf: Array of byte;
  wh: TWaveHdr;
  hOut: HWAVEOUT;
  fmt: TWaveFormatEx;
  count: integer;


function GetWaveFmtData(path: string; var fmt: TWaveFormatEx ): Boolean;
var
  hFile: HMMIO;
  ckiRIFF,ckiFmt,ckiData: TMMCKInfo;
begin
  Result := False;
  hFile := mmioOpen(PChar(path), nil, MMIO_READ);
  if hFile = 0 then Exit;

  ZeroMemory(@ckiRIFF, SizeOf(TMMCKInfo));
  ZeroMemory(@ckiFmt, SizeOf(TMMCKInfo));
  ZeroMemory(@ckiData, SizeOf(TMMCKInfo));

  ckiRIFF.fccType := mmioStringToFOURCC('WAVE', 0);
  ckiFmt.ckid := mmioStringToFOURCC('fmt', 0);
  ckiData.ckid := mmioStringToFOURCC('data', 0);

  ZeroMemory(@fmt, SizeOf(TWaveFormatEx));

  mmioDescend(hFile, @ckiRIFF, nil, MMIO_FINDRIFF);

  if (ckiRIFF.ckid = FOURCC_RIFF) and (ckiRIFF.fccType = mmioStringToFOURCC('WAVE',0)) and
  (mmioDescend(hFile, @ckiFmt, @ckiRIFF, MMIO_FINDCHUNK) = MMSYSERR_NOERROR) and
  (mmioRead(hFile, @fmt, ckiFmt.cksize) = ckiFmt.cksize) and
  (mmioAscend(hFile, @ckiFmt, 0) = MMSYSERR_NOERROR) and
  (mmioDescend(hFile, @ckiData, @ckiRIFF, MMIO_FINDCHUNK) = MMSYSERR_NOERROR) then
  begin
  SetLength(buf, ckiData.cksize);
  Result := (mmioRead(hFile, PAnsiChar(buf), ckiData.cksize) = ckiData.cksize);
  end;

  mmioClose(hFile, 0);
end;


Procedure CallBack(
  hwo :HWAVEOUT;
  uMsg :UINT ;
  dwInstance :DWORD;
  dwParam1 :DWORD;
  dwParam2 :DWORD
);stdcall;
begin
  {Need check the message here but for now lets just make sure
   that we get called }
  ShowMessage('WaveOut');
end;



procedure TForm1.Button1Click(Sender: TObject);
const
  path = 'fire.wav';

begin

  GetWaveFmtData(path, fmt);

  wh.lpData := PAnsiChar(buf);
  wh.dwBufferLength := Length(buf);
  wh.dwBytesRecorded := 0;
  wh.dwUser := 0;
  wh.dwFlags := 0;
  wh.dwLoops := 1;
  wh.lpNext := nil;
  wh.reserved := 0;

  //waveOutClose(hOut);

  if waveOutOpen(@hOut, WAVE_MAPPER, @fmt, DWORD(@CallBack),
  Handle,WAVE_MAPPED and CALLBACK_FUNCTION) = MMSYSERR_NOERROR then
  begin
    count:=count+1;
    Edit1.Text:=IntToStr(count);
  end;

  waveOutPrepareHeader(hOut, @wh, SizeOf(TWaveHdr));
  waveOutWrite(hOut, @wh, SizeOf(TWaveHdr));

end;

end.

顺便说一下,回调函数不起作用,请任何人帮助我! 这里是Full code. 对不起我的英语。

【问题讨论】:

  • 你是说你从波函数中得到错误 42 吗?使用waveOutGetErrorText()将错误码转换成字符串。
  • 我想说的是,当播放音频 48 次时,它将被禁用并且没有声音。虽然我想永远播放声音,直到我想关闭它。
  • 我有一些播放wav文件的经验,回拨不可靠。我有回调在某些机器上工作,而不是在其他机器上工作,有时在同一台机器上工作,而不是在其他机器上工作。最后,我不得不求助于安全第一的方法来读取标题,查看它应该播放多长时间,并在稍长一点的时间后触发计时器以确保文件已关闭。可怕而令人沮丧,但 100% 可靠。
  • 谢谢。所以用 wavout 播放 wav 对我来说没有效果,因为应用程序可能同时播放多个音频等等。例如:游戏应用程序。我的目的是同时从流或数组中播放多个音频。

标签: delphi winapi delphi-7 delphi-xe


【解决方案1】:

期望能够同时播放无限多条消息是不合理的。大概每条消息都是 MP3 或 MP4,因此尽管解码比编码更快,但它们不会无限快。然后必须将得到的波形样本相加在一起,确保没有结果数字溢出,这在最坏的情况下会导致严重的失真或在最好的情况下会导致削波。这一切都需要时间。还有内存方面的考虑,但时间更可能是一个因素。因此,驱动程序可能会限制它在任何时候可以播放的声音数量,以便能够足够快且不失真地播放声音。如果没有,那么很可能存在溢出问题。

大多数音频传统上是 24 位立体声(48 位),因此基于 64 位技术的驱动程序在合并后可能会开始出现溢出问题,最好的情况是大约 40 个样本。基于 32 位的驱动程序可能会很快遇到问题。

【讨论】:

  • 谢谢 Dsm。目前我使用 DSpack 组件而不是 wavout。一切都对我有好处,但是这个组件似乎无法播放 Memorystream 中的音频。
猜你喜欢
  • 2012-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
相关资源
最近更新 更多