如何产生变频连续音调?

10

我想生成并播放一个连续的声音,其中特定频率和幅度会随时间变化。我不想在声音之间有延迟。如何使用 Delphi 或 C++ Builder 实现这一点?


请查看waveOutXXX函数族 - Premature Optimization
2
由于您没有接受我的答案,我认为它并没有对您有所帮助。也许您可以解释一下为什么它没有对您有所帮助? - Andreas Rejbrand
2个回答

19
这个非常简单的例子应该能让你入门。
program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils, Windows, MMSystem;

type
  TWaveformSample = integer; // signed 32-bit; -2147483648..2147483647
  TWaveformSamples = packed array of TWaveformSample; // one channel

var
  Samples: TWaveformSamples;
  fmt: TWaveFormatEx;

procedure InitAudioSys;
begin
  with fmt do
  begin
    wFormatTag := WAVE_FORMAT_PCM;
    nChannels := 1;
    nSamplesPerSec := 44100;
    wBitsPerSample := 32;
    nAvgBytesPerSec := nChannels * nSamplesPerSec * wBitsPerSample div 8;
    nBlockAlign := nChannels * wBitsPerSample div 8;
    cbSize := 0;
  end;
end;
                                          // Hz                     // msec
procedure CreatePureSineTone(const AFreq: integer; const ADuration: integer;
  const AVolume: double { in [0, 1] });
var
  i: Integer;
  omega,
  dt, t: double;
  vol: double;
begin
  omega := 2*Pi*AFreq;
  dt := 1/fmt.nSamplesPerSec;
  t := 0;
  vol := MaxInt * AVolume;
  SetLength(Samples, Round((ADuration / 1000) * fmt.nSamplesPerSec));
  for i := 0 to high(Samples) do
  begin
    Samples[i] := round(vol*sin(omega*t));
    t := t + dt;
  end;
end;

procedure PlaySound;
var
  wo: integer;
  hdr: TWaveHdr;
begin

  if Length(samples) = 0 then
  begin
    Writeln('Error: No audio has been created yet.');
    Exit;
  end;

  if waveOutOpen(@wo, WAVE_MAPPER, @fmt, 0, 0, CALLBACK_NULL) = MMSYSERR_NOERROR then
    try

      ZeroMemory(@hdr, sizeof(hdr));
      with hdr do
      begin
        lpData := @samples[0];
        dwBufferLength := fmt.nChannels * Length(Samples) * sizeof(TWaveformSample);
        dwFlags := 0;
      end;

      waveOutPrepareHeader(wo, @hdr, sizeof(hdr));
      waveOutWrite(wo, @hdr, sizeof(hdr));
      sleep(500);

      while waveOutUnprepareHeader(wo, @hdr, sizeof(hdr)) = WAVERR_STILLPLAYING do
        sleep(100);

    finally
      waveOutClose(wo);
    end;


end;


begin

  try
    InitAudioSys;
    CreatePureSineTone(400, 1000, 0.7);
    PlaySound;
  except
    on E: Exception do
    begin
      Writeln(E.Classname, ': ', E.Message);
      Readln;
    end;
  end;

end.

请特别注意您所获得的简洁界面:
    InitAudioSys;
    CreatePureSineTone(400, 1000, 0.7);
    PlaySound;

这是一个不错的开始,但如何使其连续无间断或故障呢? - Mehmet Fide

1
通过使用WaveAudio库,可以生成连续的余弦波。
我本来想发布一些代码的,但是我不知道如何正确地做,所以我就不发了。
但是你只需要使用TLiveAudioPlayer,然后覆盖OnData事件即可。
如果没有消息泵,则还需将Async设置为true。
更新于2021年12月,我偶然发现了我的答案...所以我想更新一下,我在2009年左右使用了这个ASIO库,很棒的库!
我推荐Delphi使用ASIO库!

https://sourceforge.net/projects/delphiasiovst/

使用起来非常简单,不需要包含所有文件,从主文件开始添加其余文件,还可以看看示例。

最终就像OnSomeEvent/OnSomeBuffer一样容易

然后只需用浮点值填充一个数组即可。

记不住OnEvent的确切名称,但在示例中很容易找到。

另一件事是将某些组件设置为活动/启用状态,就这么简单。

ASIO的好处是延迟非常低,甚至可以降到50微秒或更低。

它需要一个适用于您的声音芯片的ASIO驱动程序。

ASIO = 音频流输入输出

由音频工程师设计的API!

可能没有比这更好的了!;)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接