我正在使用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内容的结尾处停止播放,则可以使用AKCallbackInstrument来完成此操作,该AKCallbackInstrument由紧接在最后音符之后的MIDI事件触发。

关于audio - 在AKSequencer中演奏的第一音符已关闭,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52062316/

10-13 03:24