Calling MusicDeviceMIDIEvent from the audio unit's render thread

不羁岁月 提交于 2020-08-26 05:54:49

问题


There's one thing I don't understand about MusicDeviceMIDIEvent. In every single example I ever seen (searched Github and Apple examples) it was always used from the main thread. Now, in order to use the sample offset parameter the documentation states:

inOffsetSampleFrame: If you are scheduling the MIDI Event from the audio unit's render thread, then you can supply a sample offset that the audio unit may apply when applying that event in its next audio unit render. This allows you to schedule to the sample, the time when a MIDI command is applied and is particularly important when starting new notes. If you are not scheduling in the audio unit's render thread, then you should set this value to 0

Still, even in the most simple case, in which you only have a sampler audio unit and an io unit, how can you schedule MIDI events from the audio unit's render thread since the sampler doesn't allow a render callback and even if it would (or if you use the io's callback just to tap in), it would feel hackish, since the render callback is not intended for schedule MIDI events?

How does one correctly calls this function from the audio unit's render thread?


回答1:


A renderNotify callback is a perfect place to do scheduling from the render thread. You can even set the renderNotify on the MusicDevice itself. Here's what it might look like on an AUSampler.

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

In this example I passed the sampler in as a reference via the inRefCon argument, and am just sending a note-on(144) to note 64 every 44100 samples, but in an application you would pass in a c struct to inRefCon with a reference to your midi device, and all the values you need to do your scheduling. Note the checking of the render flag for pre-render.

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;
}


来源:https://stackoverflow.com/questions/46868416/calling-musicdevicemidievent-from-the-audio-units-render-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!