AudioKit 的 AKAudioFile 是否总是一次读取整个音频文件?
Does AudioKit's AKAudioFile always read the entire audio file at once?
我的应用程序是 macOS 的音频播放器,使用 AVAudioEngine 框架在 Swift 3 中编写。
现在,我正在尝试利用 AudioKit 框架而不是直接使用 AVAudioEngine,因为它似乎是一个经过良好测试和信任的框架(AudioKit 3.7.1(不是 4.x),因为我仍在编码 Swift 3)
在我当前的音频播放器实现中(没有 AudioKit),我一次读取一小块音频数据(5 到 15 秒之间),原因很明显 - 在播放或在曲目内搜索时立即开始播放,并使内存占用量保持在合理的范围内。而且,我一直在内存中保留一个额外的 "look ahead" 缓冲区,以避免播放时出现间隙。
因此,如果我改用 AudioKit,我希望它也能做同样的事情 - 理想情况下,我可以指定要使用的缓冲区大小,它会读取给定大小的音频数据块。但是,它似乎总是一次读取整个文件。对于需要响应并保持合理内存占用的音频播放器应用程序来说,这是不可行的。
假设我播放了一个 3 小时的有声读物 MP3...将整个文件读入内存需要 5 到 10 秒。所以用户必须等待很长时间才能开始播放曲目。并且内存使用量进入 GB 范围(即整个音频文件被加载到内存中)!这对我的应用程序(或任何音频播放器应用程序)来说是不可接受的。
P.S。我查看了 AudioKit 源代码,但找不到替代的 AKAudioFile 初始值设定项、AKAudioPlayer 中的设置或另一个音频 file/player class 可以满足我的要求。
我是不是漏掉了一些显而易见的东西?我是 AudioKit 的新手。我假设这是最流行的 "high-level" MacOS 音频框架 playback/synthesis。我无法想象它的开发人员会错过这么基本的东西?还是我的期望完全被误导了?
这是我的播放器代码的本质:
do {
let akFile = try AKAudioFile(forReading: track.file)
akPlayer = try AKAudioPlayer(file: akFile)
AudioKit.output = akPlayer
AudioKit.start()
akPlayer.start()
} catch {
print("Problem")
}
我建议尝试开发分支上出现的新 AKPlayer 内容。 AKAudioPlayer 的日子屈指可数了。您可以向 AKPlayer 发送一个常规的 AVAudioFile,这应该可以解决您的问题。
问题是 AKAudioPlayer(不是 AKAudioFile)只播放来自 Ram 的音频。正如 Aure 所说,要做的就是使用 AKPlayer。这目前仅在开发分支中,但默认情况下将从磁盘流式传输。
Audiokit 使用 AVAudioPlayerNode 可以直接从磁盘或缓冲区播放文件。您可以使用自己的 class 扩展 Audiokit。在这个例子中,我想用无缝循环播放磁盘中的文件。
import Foundation
import AudioKit
open class Xplayer: AKNode {
var url : URL? = nil
let playerNode = AVAudioPlayerNode()
private var mixer = AVAudioMixerNode()
var inFile : AKAudioFile
var isLooping : Bool = true
public init(audioFile: AKAudioFile)
{
self.inFile = audioFile
AudioKit.engine.attach(playerNode)
AudioKit.engine.attach(mixer)
AudioKit.engine.connect(playerNode, to: mixer)
super.init(avAudioNode: mixer, attach: false)
}
func Prepare()
{
let frames = inFile.length
var offsetFrame: Int64 = 0
self.isLooping = true
let sampleRate = playerNode.outputFormat(forBus: 0).sampleRate
var segmentTime : AVAudioFramePosition = 0
var segmentCompletion : AVAudioNodeCompletionHandler!
segmentCompletion = {
if (self.isLooping == true) { // Need to set false before stopping sound else delays start
segmentTime += frames - offsetFrame
self.playerNode.scheduleFile(self.inFile, at: AVAudioTime(sampleTime: segmentTime, atRate: sampleRate), completionHandler: segmentCompletion)
offsetFrame = 0
}
}
offsetFrame = 0
let frameCount = frames - offsetFrame
playerNode.scheduleSegment(inFile,
startingFrame: AVAudioFramePosition(offsetFrame),
frameCount: AVAudioFrameCount(frameCount),
at: nil,
completionHandler: segmentCompletion)
}
func Play()
{
Prepare()
playerNode.play()
}
func Stop()
{
isLooping = false
playerNode.stop()
}
func Change_sound(audioFile: AKAudioFile)
{
Stop()
self.inFile = audioFile
Play()
}
}
我的应用程序是 macOS 的音频播放器,使用 AVAudioEngine 框架在 Swift 3 中编写。
现在,我正在尝试利用 AudioKit 框架而不是直接使用 AVAudioEngine,因为它似乎是一个经过良好测试和信任的框架(AudioKit 3.7.1(不是 4.x),因为我仍在编码 Swift 3)
在我当前的音频播放器实现中(没有 AudioKit),我一次读取一小块音频数据(5 到 15 秒之间),原因很明显 - 在播放或在曲目内搜索时立即开始播放,并使内存占用量保持在合理的范围内。而且,我一直在内存中保留一个额外的 "look ahead" 缓冲区,以避免播放时出现间隙。
因此,如果我改用 AudioKit,我希望它也能做同样的事情 - 理想情况下,我可以指定要使用的缓冲区大小,它会读取给定大小的音频数据块。但是,它似乎总是一次读取整个文件。对于需要响应并保持合理内存占用的音频播放器应用程序来说,这是不可行的。
假设我播放了一个 3 小时的有声读物 MP3...将整个文件读入内存需要 5 到 10 秒。所以用户必须等待很长时间才能开始播放曲目。并且内存使用量进入 GB 范围(即整个音频文件被加载到内存中)!这对我的应用程序(或任何音频播放器应用程序)来说是不可接受的。
P.S。我查看了 AudioKit 源代码,但找不到替代的 AKAudioFile 初始值设定项、AKAudioPlayer 中的设置或另一个音频 file/player class 可以满足我的要求。
我是不是漏掉了一些显而易见的东西?我是 AudioKit 的新手。我假设这是最流行的 "high-level" MacOS 音频框架 playback/synthesis。我无法想象它的开发人员会错过这么基本的东西?还是我的期望完全被误导了?
这是我的播放器代码的本质:
do {
let akFile = try AKAudioFile(forReading: track.file)
akPlayer = try AKAudioPlayer(file: akFile)
AudioKit.output = akPlayer
AudioKit.start()
akPlayer.start()
} catch {
print("Problem")
}
我建议尝试开发分支上出现的新 AKPlayer 内容。 AKAudioPlayer 的日子屈指可数了。您可以向 AKPlayer 发送一个常规的 AVAudioFile,这应该可以解决您的问题。
问题是 AKAudioPlayer(不是 AKAudioFile)只播放来自 Ram 的音频。正如 Aure 所说,要做的就是使用 AKPlayer。这目前仅在开发分支中,但默认情况下将从磁盘流式传输。
Audiokit 使用 AVAudioPlayerNode 可以直接从磁盘或缓冲区播放文件。您可以使用自己的 class 扩展 Audiokit。在这个例子中,我想用无缝循环播放磁盘中的文件。
import Foundation
import AudioKit
open class Xplayer: AKNode {
var url : URL? = nil
let playerNode = AVAudioPlayerNode()
private var mixer = AVAudioMixerNode()
var inFile : AKAudioFile
var isLooping : Bool = true
public init(audioFile: AKAudioFile)
{
self.inFile = audioFile
AudioKit.engine.attach(playerNode)
AudioKit.engine.attach(mixer)
AudioKit.engine.connect(playerNode, to: mixer)
super.init(avAudioNode: mixer, attach: false)
}
func Prepare()
{
let frames = inFile.length
var offsetFrame: Int64 = 0
self.isLooping = true
let sampleRate = playerNode.outputFormat(forBus: 0).sampleRate
var segmentTime : AVAudioFramePosition = 0
var segmentCompletion : AVAudioNodeCompletionHandler!
segmentCompletion = {
if (self.isLooping == true) { // Need to set false before stopping sound else delays start
segmentTime += frames - offsetFrame
self.playerNode.scheduleFile(self.inFile, at: AVAudioTime(sampleTime: segmentTime, atRate: sampleRate), completionHandler: segmentCompletion)
offsetFrame = 0
}
}
offsetFrame = 0
let frameCount = frames - offsetFrame
playerNode.scheduleSegment(inFile,
startingFrame: AVAudioFramePosition(offsetFrame),
frameCount: AVAudioFrameCount(frameCount),
at: nil,
completionHandler: segmentCompletion)
}
func Play()
{
Prepare()
playerNode.play()
}
func Stop()
{
isLooping = false
playerNode.stop()
}
func Change_sound(audioFile: AKAudioFile)
{
Stop()
self.inFile = audioFile
Play()
}
}