如何生成不同频率的连续音调?

发布于 2024-12-09 05:31:33 字数 80 浏览 0 评论 0原文

我想生成并播放具有随时间变化的特定频率和幅度的连续声音。我不想声音之间有延迟。我如何使用 Delphi 或 C++ Builder 来做到这一点?

I want to generate and play a continuous sound with specific frequencies and amplitudes that change over time. I don't want to have a delay between sounds. How can I do this with Delphi or C++ Builder?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

南汐寒笙箫 2024-12-16 05:31:33

这个非常简单的示例应该可以帮助您入门。

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;

This very simple example should get you started.

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.

Notice in particular the neat interface you get:

    InitAudioSys;
    CreatePureSineTone(400, 1000, 0.7);
    PlaySound;
软甜啾 2024-12-16 05:31:33

通过使用 WaveAudio 库,可以生成连续的余弦波。

我本来想发布一些代码,但我不知道如何正确地做到这一点,所以我不会。

但您需要做的就是使用 TLiveAudioPlayer,然后覆盖 OnData 事件。

如果没有消息泵,请将 Async 设置为 true。

  • 2021 年 12 月更新,我只是偶然发现了我的答案...所以我想更新它,我在 2009 年使用了这个 ASIO 库,我想后来,下面很棒的库:*

我会推荐 Delphi 的 ASIO 库!

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

使用这个非常简单,不是所有文件必须包含在内,从主要部分开始,然后从那里添加其余部分,另请参阅示例。

最终,它就像 OnSomeEvent/OnSomeBuffer 一样简单

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

不记得 OnEvent 的确切名称,但您可以在示例中轻松找到它。

另一件要做的事情是将某些组件设置为 active/true ,瞧。

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

它确实需要您的声音芯片的 ASIO 驱动程序。

音频流输入输出

ASIO=音频工程师设计的

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

By using WaveAudio library it's possible to generate a continous cosinus wave.

I was gonna post some code but I can't figure out how to do it properly so I won't.

But all you need to do is use TLiveAudioPlayer and then override the OnData event.

And also set Async to true if there is no message pump.

  • Update in dec 2021, I just came across my answer by chance... so I would like to update it, I used this ASIO library in 2009 I think and later, great library below:*

I would recommend ASIO library for Delphi !

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

Using this is super easy, not all files have to be included, start with the main one and add the rest from there, also see the examples.

Ultimately it's as easy as OnSomeEvent/OnSomeBuffer

and then simply filling an array with floating point values.

Don't remember the exact name of the OnEvent but you'll find it easily in the examples.

Another thing to do is set some component to active/true and voila.

The nice thing about ASIO is very low latency, it's even possible to get it down to 50 microseconds or even lower.

It does require an ASIO driver for your sound chip.

ASIO = audio stream input output

API designed by audio engineers !

It probably doesn't get any better than this ! ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文