从音频单元的渲染线程调用 MusicDeviceMIDIEvent

Val*_*adu 1 audio core-audio ios coremidi

有一件事我不明白MusicDeviceMIDIEvent。在我见过的每个示例(搜索 Github 和 Apple 示例)中,它总是在主线程中使用。现在,为了使用示例偏移参数,文档说明:

inOffsetSampleFrame:如果您从音频单元的渲染线程调度 MIDI 事件,那么您可以提供一个样本偏移量,音频单元在其下一个音频单元渲染中应用该事件时可能会应用该偏移量。这允许您安排样本、应用 MIDI 命令的时间,这在开始新音符时尤为重要。如果您不是在音频单元的渲染线程中进行调度,则应将此值设置为 0

尽管如此,即使在最简单的情况下,您只有一个采样器音频单元和一个 io 单元,您如何从音频单元的渲染线程安排 MIDI 事件,因为采样器不允许渲染回调,即使它允许(或者,如果您使用 io 的回调只是为了点击),它会让人感觉很黑,因为渲染回调不是用于安排 MIDI 事件?

如何从音频单元的渲染线程正确调用此函数?

dav*_*234 5

renderNotify 回调是从渲染线程进行调度的理想场所。您甚至可以在 MusicDevice 本身上设置 renderNotify。这是它在 AUSampler 上的样子。

OSStatus status = AudioUnitAddRenderNotify(sampler, renderNotify, sampler);
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我通过 inRefCon 参数将采样器作为参考传入,并且我只是每 44100 个样本发送一个 note-on(144) 到 note 64,但在应用程序中,您将 ac struct 传递给 inRefCon 并引用您的 midi 设备,以及您进行调度所需的所有值。请注意检查预渲染的渲染标志。

static OSStatus renderNotify(void                         * inRefCon,
                             AudioUnitRenderActionFlags   * ioActionFlags,
                             const AudioTimeStamp         * inTimeStamp,
                             UInt32                       inBusNumber,
                             UInt32                       inNumberFrames,
                             AudioBufferList              * ioData) {

    AudioUnit sampler = inRefCon;
    if (ioActionFlags & kAudioUnitRenderAction_PreRender) {
        for (int i = 0; i < inNumberFrames; i++) {
            if (fmod(inTimeStamp->mSampleTime + i, 44000) == 0) {
                MusicDeviceMIDIEvent(sampler,144, 64, 127, i); // i is the offset from render start, so use it for offset argument.
            }
        }
    }

    return noErr;
}
Run Code Online (Sandbox Code Playgroud)