我正在使用 AKSequencer 创建一系列由 AKMidiSampler 播放的音符。我的问题是,无论我做什么,在更高的速度下,第一个音符总是有一点延迟。
我试过预滚动序列,但无济于事。用 AKSampler 或 AKSamplePlayer 替换 AKMidiSampler(并使用回调轨道播放它们)也无济于事,尽管这让我认为问题可能出在音序器或我创建音符的方式上。
这是我正在做的一个例子(我试图让它尽可能简单):
import UIKit
import AudioKit
class ViewController: UIViewController {
let sequencer = AKSequencer()
let sampler = AKMIDISampler()
let callbackInst = AKCallbackInstrument()
var metronomeTrack : AKMusicTrack?
var callbackTrack : AKMusicTrack?
let numberOfBeats = 8
let tempo = 280.0
var startTime : TimeInterval = 0
override func viewDidLoad() {
super.viewDidLoad()
print("Begin setup.")
// Load .wav sample in AKMidiSampler
do {
try sampler.loadWav("tick")
} catch {
print("sampler.loadWav() failed")
}
// Create tracks for the sequencer and set midi outputs
metronomeTrack = sequencer.newTrack("metronomeTrack")
callbackTrack = sequencer.newTrack("callbackTrack")
metronomeTrack?.setMIDIOutput(sampler.midiIn)
callbackTrack?.setMIDIOutput(callbackInst.midiIn)
// Setup and start AudioKit
AudioKit.output = sampler
do {
try AudioKit.start()
} catch {
print("AudioKit.start() failed")
}
// Set sequencer tempo
sequencer.setTempo(tempo)
// Create the notes
var midiSequenceIndex = 0
for i in 0 ..< numberOfBeats {
// Add notes to tracks
metronomeTrack?.add(noteNumber: 60, velocity: 100, position: AKDuration(beats: Double(midiSequenceIndex)), duration: AKDuration(beats: 0.5))
callbackTrack?.add(noteNumber: MIDINoteNumber(midiSequenceIndex), velocity: 100, position: AKDuration(beats: Double(midiSequenceIndex)), duration: AKDuration(beats: 0.5))
print("Adding beat number \(i+1) at position: \(midiSequenceIndex)")
midiSequenceIndex += 1
}
// Set the callback
callbackInst.callback = {status, noteNumber, velocity in
if status == .noteOn {
let currentTime = Date().timeIntervalSinceReferenceDate
let noteDelay = currentTime - ( self.startTime + ( 60.0 / self.tempo ) * Double(noteNumber) )
print("Beat number: \(noteNumber) delay: \(noteDelay)")
} else if ( noteNumber == midiSequenceIndex - 1 ) && ( status == .noteOff) {
print("Sequence ended.\n")
self.toggleMetronomePlayback()
} else {return}
}
// Preroll the sequencer
sequencer.preroll()
print("Setup ended.\n")
}
@IBAction func playButtonPressed(_ sender: UIButton) {
toggleMetronomePlayback()
}
func toggleMetronomePlayback() {
if sequencer.isPlaying == false {
print("Playback started.")
startTime = Date().timeIntervalSinceReferenceDate
sequencer.play()
} else {
sequencer.stop()
sequencer.rewind()
}
}
}
有人能帮忙吗?谢谢。
最佳答案
正如 Aure 评论的那样,启动延迟是一个已知问题。即使有预卷,仍然存在明显的延迟,尤其是在较高节奏时。
但如果您使用的是循环序列,我发现您有时可以通过将序列的“起点”设置为最终 MIDI 事件之后但在循环长度内的位置来减轻延迟的明显程度。如果您能找到一个好的位置,则可以在它循环回您的内容之前消除延迟影响。
确保在需要之前调用 setTime()
(例如,在停止序列之后,而不是在准备播放时),因为 setTime()
调用本身可以引入大约 200 毫秒的不稳定。
编辑: 事后想想,您可以通过启用循环并使用任意长的序列长度在非循环序列上做同样的事情。如果您需要播放以在 MIDI 内容结束时停止,您可以使用由紧接在最后一个音符之后的 MIDI 事件触发的 AKCallbackInstrument 来实现。
关于audio - AKSequencer 中播放的第一个音符已关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52062316/