AudioKit AKPlayer 在 AVAudioTime 方法中停止

AudioKit AKPlayer stop with at AVAudioTime method

在 AudioKit 中,AKPlayer 有这个方法:

@objc dynamic public func play(at audioTime: AVAudioTime?)

我想要相同的停止方法,因为我希望能够在用户点击停止按钮时随时停止播放器。我正在制作一个音乐应用程序,我需要在基于 BPM 等计算的 X 时间内停止声音

以下是我如何开始 AKPlayer:

drums.play(at: AVAudioTime.now() + timeToClosestBeatGrid)

我想要相同的 API 停止:

drums.stop(at: AVAudioTime.now() + timeToClosestBeatGrid) // this api doesnt exist :(((

我尝试通过设置来使用 endTime 属性 但它似乎没有做任何事情...

我该如何完成?

PS:我不是在寻找计时器解决方案,这是因为计时器不是 100% 准确的。我希望我的停止方法像播放方法一样 100% 准确

根据AudioKit文档,您可以尝试使用schedule(at:)方法:

You can call this to schedule playback in the future or the player will call it when play() is called to load the audio data

play() 方法之后,你应该用偏移量 AVAudioTime.now() + timeToClosestBeatGrid 声明这个 schedule(at:) 并指定 .dataPlayedBack 作为完成回调类型,因为这个完成被调用时(来自文档)...

The buffer or file has finished playing

现在(在完成块中)您可以调用 drums.stop()

但是...如果每当按下按钮时都应调用 .stop() 方法,为什么不使用某种形式的延迟(Timer 或 DispatchQueue)并将值 timeToClosestBeatGrid 作为偏移量?

在 AudioKit 中安排事件的最准确方法是使用 AKSequencer。音序器可以连接到回调工具,回调工具是将事件传递给用户定义函数的节点。

在您的情况下,您可以在希望播放器停止的时间添加一个事件。在您的回调函数中,您将停止播放器作为对该事件的响应。

这是应该做的事情的概述:

  1. 使用 AKSequencer's addTrack method. Connect this track to an AKCallbackInstrument. Please see 如何将 AKCallbackInstrument 连接到 AKSequencer 轨道来创建包含停止事件的轨道。
  2. 将停止事件添加到轨道,在您希望音乐停止的时间位置。由于您将自己使用回调函数解释事件,因此使用哪种类型的事件并不重要。您可以简单地使用 Note On.
  3. 在回调函数中,当收到该事件时停止播放器。

这就是您的回调函数的样子:

func stopCallback(status:UInt8, note:MIDINoteNumber, vel:MIDIVelocity) -> () {
    guard let status = AKMIDIStatus(byte: status),
        let type = status.type,
        type == .noteOn else { return }
    drums.stop()
}