我有一个iOS / Objective-C程序,当按下按钮时,它使用单个音频单元播放生成的信号。我想添加以下功能:
a)首次按下该按钮时,会在某种数字数组中生成信号。
b)然后音频开始,渲染回调访问(和播放)生成的信号。
鉴于我目前的代码,我觉得这些添加只是几行,但我遇到了语法问题,要使用哪些变量类型,如何跟踪当前样本,等等。我已经包含了现在的相关代码:
按下按钮:
- (IBAction)startPressed:(id)sender {
[self setupAudioPlayer];
[self createSignal];
[self playAudio];
}
来自setupAudioPlayer的一行:
input.inputProcRefCon=&mySignal; // mySignal is an instance var
音频制作:
-(void)createSignal{
int beepLength=0.020*Fs; // Fs is sampling frequency
float beepFrequency=440; // Hz
// Declare some kind of numeric array "mySignal", which is an instance var.
mySignal=...?
// Generate audio signal (pure tone)
for (int i=1; i<=beepLength; i++) {
float t=i/Fs;
mySignal[i]=sinf(2*M_PI*beepFrequency*t);
}
}
渲染回调:
OSStatus RenderTone(
void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
const int channel1 = 0;
Float32 *buffer = (Float32 *)ioData->mBuffers[channel1].mData;
// This is where things get hazy
Float32 *mySignal=(Float32 *)inRefCon;
for (UInt32 frame = 0; frame < inNumberFrames; frame++)
{
buffer[frame]=mySignal[?];
}
return noErr;
}
所以,总结一下我的问题:如何定义mySignal?如何从RenderTone访问此实例变量(上面的'hazy'代码只是猜测)?如何在RenderTone中跟踪当前样本?这种方法还有什么遗漏/不知道的吗?
感谢阅读和任何帮助,非常感谢!
(我看过示例代码,它将对视图控制器实例的引用传递给渲染回调,然后以这种方式访问实例变量。但是,也许是错误的,我在别处读到这不是好形式,因为它可能对于具有如此严格的时序要求的回调而言,涉及太多的计算开销。)
答案 0 :(得分:1)
由于您是从代数函数生成帧,为什么不按照Matt Gallagher's example进行操作?简而言之:只需在render回调中移动函数,然后通过vc实例传输参数。
一般来说,您的选择仅限于将数据传递给具有预定义表单的回调。我可能是最后一个在Objective C中以良好形式提供建议的人,但是为数不多的选择之一是使用全局变量。
您可以将mySignal
数组(或其他频率)作为全局传递。不是最“优雅”的面向对象的解决方案,而是一个可以工作并避免所有O.O. frou-frou在头顶上。似乎只适合使用基于C的解决方案,因为渲染回调基于C函数。
至于“跟踪”,不太清楚你的意思,但在我自己的生成音调的工作中,我用语音长度初始化了remainingCycles
全局(帧周期=长度,以秒为单位* Fs
或sampleRate
无论你想要什么称呼它,并减少每次通过frame
循环;当数字达到零时,你就结束了音调。 (当然,您可以使用实例变量而不是全局变量。)
这可能违反了面向对象编码的规范,但在一天结束时,你只需要完成工作。