如何在“采样准确”的时间安排MIDI事件?

问题描述 投票:0回答:2

我正在尝试在iOS上构建音序器应用。 Apple Developer网站上有一个示例,可以使音频单元重复播放,这里:

https://developer.apple.com/documentation/audiotoolbox/incorporating_audio_effects_and_instruments

在示例代码中,有一个文件“ SimplePlayEngine.swift”,带有一个类“ InstrumentPlayer”,用于处理将MIDI事件发送到选定的音频单元。它产生一个带有循环的线程,该循环遍历刻度。它通过调用音频单元的AUScheduleMIDIEventBlock发送MIDI Note On消息,使线程休眠一小段时间,发送Note Off,然后重复。

这里是删节版:

DispatchQueue.global(qos: .default).async {
    ...
    while self.isPlaying {
        // cbytes is set to MIDI Note On message
        ...
        self.audioUnit.scheduleMIDIEventBlock!(AUEventSampleTimeImmediate, 0, 3, cbytes)
        usleep(useconds_t(0.2 * 1e6))
        ...
        // cbytes is now MIDI Note Off message
        self.noteBlock(AUEventSampleTimeImmediate, 0, 3, cbytes)
        ...
    }
    ...
}

这对于演示来说已经足够好了,但是它没有强制严格的计时,因为事件将在线程唤醒时进行安排。

如何修改它以在具有采样精确定时的特定速度下播放音阶?

我的假设是,我需要一种方法,使合成器音频单元在每次渲染之前具有要渲染的帧数的代码中的回调。然后,我可以每隔“ x”帧安排一次MIDI事件。您可以向scheduleMIDIEventBlock的第一个参数添加一个最大为缓冲区大小的偏移量,因此我可以使用该偏移量将事件安排在给定的渲染周期中的正确帧处。

我尝试使用audioUnit.token(byAddingRenderObserver: AURenderObserver),但是即使应用发出声音,也从未调用过我给它的回调。该方法听起来像是AudioUnitAddRenderNotify的Swift版本,从我在这里阅读的内容来看,这听起来像我需要做的-https://stackoverflow.com/a/46869149/11924045。怎么不叫它呢?甚至有可能使用Swift来使这个“样本准确”,还是我需要为此使用C?

我在正确的轨道上吗?感谢您的帮助!

我正在尝试在iOS上构建音序器应用。 Apple Developer网站上有一个示例,可以使音频单元重复播放,这里:https://developer.apple.com/documentation / ...

ios avfoundation audiounit audiotoolbox auv3
2个回答
0
投票

采样精确定时通常需要使用RemoteIO音频单元,并使用C代码在每个音频回调块中的所需采样位置手动插入采样。


0
投票

您走在正确的轨道上。可以在渲染回调中以采样精度安排MIDI事件:

© www.soinside.com 2019 - 2024. All rights reserved.