【发布时间】:2011-03-02 09:38:42
【问题描述】:
我是 CoreAudio 的新手,我想通过使用 CA 的扬声器输出具有给定频率和幅度的简单正弦波和方波。我不想使用声音文件,因为我想合成声音。
我需要做什么?你能给我一个例子或教程吗?谢谢。
【问题讨论】:
标签: objective-c cocoa waveform core-audio
我是 CoreAudio 的新手,我想通过使用 CA 的扬声器输出具有给定频率和幅度的简单正弦波和方波。我不想使用声音文件,因为我想合成声音。
我需要做什么?你能给我一个例子或教程吗?谢谢。
【问题讨论】:
标签: objective-c cocoa waveform core-audio
一般来说,您是音频编程的新手吗?作为起点,我会检查一下
http://www.audiosynth.com/sinewavedemo.html
这是传奇 James Harkins 的最小osx sinewave 实现。请注意,它根本不使用 CoreAudio。
如果您特别想为您的正弦波使用 CoreAudio,您需要创建一个输出单元(iphone 上的 RemoteIO,osx 上的 AUHAL)并提供一个输入回调,您几乎可以使用上面示例中的代码。看看
http://developer.apple.com/mac/library/technotes/tn2002/tn2091.html
CoreAudio 的好处主要是,用你的正弦波链接其他效果,为 Logic 等主机编写插件并为其提供接口,为可以链接在一起的插件编写一个主机(如 Logic)。
如果您不想编写插件或托管插件,那么 CoreAudio 可能实际上并不适合您。但是使用 CoreAudio 的好处之一是,一旦你的正弦波回调工作,很容易添加效果,或者将多个正弦混合在一起
为此,您需要将输出单元放在一个图表中,您可以在该图表中添加效果、混音器等。
这里有一些关于设置图表的帮助http://timbolstad.com/2010/03/16/core-audio-getting-started-pt2/
这并不像看起来那么难。 Apple 为许多事情(/Developer/Examples/CoreAudio/PublicUtility)提供了 C++ 辅助类,即使你不想使用 C++(你不必!)它们也可以成为 CoreAudio API 的有用指南。
【讨论】:
上一个答案有很多错误。我,传奇 :-) James McCartney,而不是 James Harkins 编写了 sinewavedemo,我还编写了 SuperCollider,这就是 audiosynth.com 网站的内容。我现在也在 Apple 工作,负责 CoreAudio。 sinewavedemo 使用 CoreAudio,因为它使用 CoreAudio.framework 中的 AudioHardware.h 作为播放声音的方式。
您不应该使用 sinewavedemo。这是非常古老的代码,它对音频硬件的缓冲区布局做出了危险的假设。现在播放您正在生成的声音最简单的方法是使用 AudioQueue,或者使用带有渲染回调集的输出音频单元。
【讨论】:
如果您不是实时执行此操作,则使用来自math.h 的sin() 函数不是一个坏主意。只需在播放时预先使用 sin() 填充所需的样本数,只需将其发送到音频缓冲区即可。如果您实时执行此操作,每次采样调用一次 sin() 可能会非常慢,使用插值波表查找方法要快得多,但生成的声音不会像频谱那样纯净。
【讨论】:
在没有文件的情况下,最好和最简单的方法是准备一个单周期缓冲区,其中包含一个波的周期(这在技术上称为波表)
在 CoreAudio 线程调用的播放函数中,用从波形缓冲区读取的样本填充输出缓冲区。
但是请注意,您很快就会遇到两个问题: - 对于正弦波,如果播放频率不是所需正弦频率的整数倍,如果你想获得良好的质量,你可能需要实现一个插值器。仅使用整数指针会产生很大程度的谐波噪声。
要获得良好的信号生成算法,请访问 musicdsp.org,这可能是最好的资源之一
【讨论】:
Addison-Wesley Professional (ISBN-10: 0- 321-63684-8):
这是一个相当新的出版物(2012 年),准确地解决了这个问题。这只是一个起点,但却是一个有价值的起点。
顺便说一句。在完成这个基础课程(涉及一些数学)之前,不要跳到图表。
关于示例代码,我经常使用一种快速有效的方法来处理预填充的正弦波查找表,该表的成员数与采样率一样多,对于 44100 Hz,该表的大小为 44100。换句话说,周期长度等于采样率。在许多情况下,这在速度和质量之间提供了可接受的折衷。您可以使用程序对其进行初始化。
如果您生成浮点样本(在 OSX 中是默认设置)并使用 math 函数,请使用 sinf() 而不是 (float)sin()。渲染回调的内部循环循环中的提升总是资源昂贵。常量的重复乘法也是如此,例如 2.0*M_PI,这在代码示例中很常见。
【讨论】: