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

时间:2017-10-21 21:42:56

标签: ios audio core-audio coremidi

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

  

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

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

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

1 个答案:

答案 0 :(得分:3)

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

OSStatus status = AudioUnitAddRenderNotify(sampler, renderNotify, sampler);

在这个例子中,我通过inRefCon参数传递了sampler作为引用,并且每44100个样本只发送一个note-on(144)到64,但在应用程序中你将ac结构传递给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;
}