0

我有一个 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 访问这个实例变量(我上面的“模糊”代码只是一个猜测)?如何在 RenderTone 中跟踪当前样本?这种方法还有什么遗漏/不可靠的吗?

感谢您的阅读和任何帮助,非常感谢!

(我已经看到将视图控制器实例的引用传递给渲染回调的示例代码,然后以这种方式访问​​实例变量。但是,也许错误地,我在其他地方读到这不是好的形式,因为它可能涉及太多具有如此严格的时序要求的回调的计算开销。)

4

1 回答 1

1

既然您是从代数函数生成帧,为什么不简单地按照Matt Gallagher 的示例进行操作?简而言之:只需在渲染回调中移动函数并通过 vc 实例传递参数。

一般来说,您的选择仅限于将数据传递给具有预定义形式的回调。我可能是最后一个在 Objective C 中建议良好形式的人,但少数选择之一是使用全局变量。

您可以将mySignal数组(或频率)作为全局传递。不是最“优雅”的面向对象解决方案,而是一种可以工作并避免所有 OO frou-frou 开销的解决方案。似乎只适合使用基于 C 的解决方案,因为渲染回调是基于 C 函数的。

至于“跟踪”,不太清楚你的意思,但在我自己的生成音调的工作中,我已经remainingCycles用音调长度初始化了一个全局(以帧周期=以秒为单位的长度*FssampleRate任何你想称之为的)并减少每次通过frame循环;当数字达到零时,您结束音调。(当然,您可以使用实例变量而不是全局变量。)

也许这违反了面向对象编码的规范,但归根结底,您只需要完成工作即可。

于 2013-05-16T16:32:40.357 回答