【发布时间】:2016-04-30 22:59:56
【问题描述】:
我正在创建一个基于AUSampleraudio 单元的轻量级音序器。本质上,在每个“滴答”上,我都想执行一些操作。这里的核心技术是利用音频单元渲染回调来实现实时精确回调,并调用任意定义的进一步功能。基于这个特定的回调:
static OSStatus renderCallback (void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData){
SuperTimer *_superTimer = (__bridge SuperTimer*)inRefCon;
_superTimer->samplesSinceLastCall += inNumberFrames;
if (_superTimer->samplesSinceLastCall > 10000) {
_superTimer->tickMethod();
_superTimer->samplesSinceLastCall = 0;
}
return 0;
}
这是OSX 上默认输出音频单元的常规渲染回调。最终我应该用一个相对于当前缓冲区大小inNumberFrame 的数字替换硬编码的10000,但这有助于我对tickMethod() 的一致调用,这是一个定义为的块:
void (^tickMethod)(void);
以 44100kHZ 的采样率(硬件似乎默认为该采样率)及其 512 帧的缓冲区大小,我可以在每秒两次调用的块中选择定义的任何代码。 (虽然我现在不太关心这个值,并且可以用我想象的渲染函数中的相对值逻辑来修复)。
在 main 中,我实例化处理音频单元初始化和渲染的对象,并将一些代码分配给初始化程序中的块。
int main(int argc, const char * argv[]) {
Dispatch * dispatch = [[Dispatch alloc] init];
Sampler * sampler = [[Sampler alloc] init];
SuperTimer * time = [[SuperTimer alloc] initWithCompletion:^{
printf("test");
[dispatch sequencer];
}];
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1000, false);
}
我要求运行循环来延长我的应用程序的生命周期,瞧,我每秒两次将“测试”实时打印到控制台。然而,sequencer 方法调用立即引起了磨碎的失真声音,把我的邻居吵醒了。即使在最小音量设置下,扬声器发出的声音也非常可怕。
因此,我的问题是如何在不导致音频系统停止的情况下获得进入 Objective-C 领域的“入口点”?一件事是我需要立即发生样本命中,但我还需要进行数据更改(例如我的节拍计数等)。这些事情可能不完全实时发生,但至少在每个回调的时间范围内发生。
所以,我认为我需要跳出我的回调所在的实时线程,并在缓冲速率限制内将执行返回给它的调用者,并且可能在另一个线程上继续我的逻辑。但是,作为并发编程的 n00b,我不太确定如何以及是否应该尝试这种方法。
任何cmets或建议将不胜感激。
【问题讨论】:
标签: objective-c c audio real-time core-audio