PortAudio:通过调用函数播放多个生成的声音

Posted

技术标签:

【中文标题】PortAudio:通过调用函数播放多个生成的声音【英文标题】:PortAudio: Play multiple generated sounds by calling function 【发布时间】:2017-12-10 15:17:59 【问题描述】:

大约一周前,我开始使用 PortAudio 库。我已经检查了大多数教程/测试示例,但还没有看到我需要的解决方案。我正在制作简单的音序器——我已经在钢琴卷轴上绘制了声音块,但现在我需要以某种方式让它听起来。我想知道是否有可能让它像这样工作:

运行一个播放一个声音的方法, 将声音的频率和持续时间作为该方法的参数, 播放多个声音(即同时三个声音,调用三个方法)。

在示例文件中,它看起来更复杂。当我想播放多个正弦波时,我必须合并所有这些波,然后将这些数据提供给流式传输。

也许有人有更好的解决方案来解决这个问题?

【问题讨论】:

大多数音频设备不支持同时播放多个文件,因此您必须创建一个简单的混音器才能做到这一点。只要您的文件具有相同的采样率,这相当简单。即使您没有指定它,您似乎也想创建一个音调发生器。同样,网上有很多资源,请查看它们。不熟悉 PortAudio 是否支持其中任何一个。 是的,我想创建音调发生器,它将产生正弦波、方波、三角波和锯齿波。我不知道如何用用户定义的频率制作这些波,并同时播放很多声音。 到目前为止您尝试过什么?创建一个简单的音源应用程序并不难。 我有类似这个例子的东西。已经做了一些研究并且知道如何改变频率和多种音调,但仍然试图让它像我上面发布的那样。 (这里是生成正弦波示例的链接:link) PortAudio 无法为您提供帮助,但我可以编写一个简单的 C++ 函数来生成正弦波并接受频率和持续时间作为参数。这样,您将能够理解的不仅仅是使用库(尽管我并不是说使用库有什么问题) 【参考方案1】:

我只是给你一个简单的例子(sine wave)然后你可以创建你感兴趣的其他类型的波。需要的输入参数是

采样率(例如 8000、16000 等) 振幅(实际值取决于输出格式,但最好将值设置在 0-1 范围内并将它们转换为任何格式 你喜欢/需要) 频率(表示为采样率的一部分) 持续时间(以秒为单位)

音调数据(样本)的缓冲区长度由tone duration(以秒为单位)乘以sampling rate 确定。

创建正弦波的实际代码可能如下所示

//global variables
const float PI = 3.141593;
const unsigned samplingRate = 8000;
const float amp = 0.8;

float *GenerateTone(float frequency, unsigned duration, unsigned &bufferLen)

     const float freq = frequency/samplingRate; //(e.g 440 / 8000 = 0,055)

     bufferLen = samplingRate * duration;

     float *buffer = new float[bufferLen]

     for(int i = 0; i < bufferLen; i++ )

        buffer[i] = amp * sin(2 * PI*freq  * ((float)i)/samplingRate);

        
    return buffer;
   

你可以像这样调用这个函数

unsigned len;
float *pTone = GenerateTone(440, 1, len);//len is an out parameter
...
delete [] pTone; //deallocatone memory when you no longer need it

在 C++ 中,您还可以使用std::vector 来存储样本。这样您就不必担心内存分配/释放。

std::vector<float> v; //make vector global  
const float PI = 3.141593;
const unsigned samplingRate = 8000;
const float amp = 0.8;

void GenerateTone(float frequency, unsigned duration)

  const amp = 0.8f;

  const float freq = frequency/samplingRate; 

  const unsigned len = samplingRate * duration; 
  for(int i = 0; i < len; i++ )
        v.push_back(amp * sin(2*PI*freq  * ((float)i)/sampleRate));


您也可以将幅度作为参数传递,但在上面的示例中,幅度是硬编码的。另请参阅 (https://en.wikipedia.org/wiki/Triangle_wave, https://en.wikipedia.org/wiki/Square_wave)

【讨论】:

【参考方案2】:

上述程序是一种快速生成音频的方法。 小修正: 而不是

const float freq = frequency/samplingRate; 

应该是: const float freq = frequency; // 即。将频率直接传递到 sin()

【讨论】:

以上是关于PortAudio:通过调用函数播放多个生成的声音的主要内容,如果未能解决你的问题,请参考以下文章

停止播放通过 SoundEffect.FromStream 调用的声音

WKwebview,js调用用Swift函数播放声音

在 portaudio 中管理频道

AS3 加色合成。播放多个生成的声音

如何在win32编程中,在同一个窗口下播放多个音乐

如何通过 javascript/html5 播放 wav 音频字节数组?