Вызов MusicDeviceMIDIEvent из потока рендеринга аудиоустройства

Я одного не понимаю в MusicDeviceMIDIEvent. В каждом отдельном примере, который я когда-либо видел (искал примеры Github и Apple), он всегда использовался из основного потока. Теперь, чтобы использовать параметр смещения образца, в документации указано:

inOffsetSampleFrame: если вы планируете событие MIDI из потока рендеринга аудиоустройства, то вы можете указать смещение сэмпла, которое аудиоустройство может применить при применении этого события в его следующем рендере аудиоустройства. Это позволяет вам запланировать для семпла время, когда применяется MIDI-команда, и это особенно важно при запуске новых нот. Если вы не планируете в потоке рендеринга аудиоустройства, вам следует установить это значение на 0

Тем не менее, даже в самом простом случае, когда у вас есть только аудиоблок сэмплера и модуль io, как вы можете запланировать MIDI-события из потока рендеринга аудиоустройства, поскольку сэмплер не допускает обратный вызов рендеринга, и даже если бы он (или если вы используете обратный вызов io только для подключения), это будет выглядеть хакерским, поскольку обратный вызов рендеринга не предназначен для планирования MIDI-событий?

Как правильно вызвать эту функцию из потока рендеринга аудиоустройства?


person Valentin Radu    schedule 21.10.2017    source источник


Ответы (1)


Обратный вызов renderNotify - идеальное место для планирования из потока рендеринга. Вы даже можете установить renderNotify на самом MusicDevice. Вот как это может выглядеть на AUSampler.

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

В этом примере я передал семплер в качестве ссылки через аргумент inRefCon, и я просто отправляю примечание (144), чтобы отметить 64 каждые 44100 выборок, но в приложении вы должны передать структуру 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;
}
person dave234    schedule 21.10.2017
comment
Спасибо! Я тоже нашел эту функцию. Определенно, рендер notify (в предварительном рендеринге), а не обратный вызов - подходящее место для этого. Спасибо еще раз! - person Valentin Radu; 22.10.2017