我正在编写一个我应该播放部分音频文件的应用程序。每个音频文件包含单独轨道的音频数据。 这些部分是包含开始时间和结束时间的部分,我尝试按照我选择的顺序播放这些部分。
例如,假设我有4个部分:
A - B - C - D
我激活B和D,我想玩,B,然后D,然后B再次,然后D,等等。
顺利跳跃"在回放中我认为淡入/淡出开始/结束部分缓冲区非常重要。
所以,我有一个基本的AVAudioEngine
设置,AVAudioPlayerNode
和一个调音台。
对于每个音频部分,我缓存一些信息:
AVAudioFramePosition
的元组和中段的AVAudioFrameCount
元组现在,当我安排一个部分进行游戏时,我会说AVAudioPlayerNode
:
scheduleBuffer(_:completionHandler:)
无选项)scheduleSegment(_:startingFrame:frameCount:at:completionHandler:)
)scheduleBuffer(_:completionHandler:)
无选项)所有在"时间" nil
。
这里的问题是我可以听到声音部分界限处的声音和蹩脚的声音,我无法看到我做错的地方。 我的第一个想法是我手动淡化(基本上将样本值乘以体积因子),但不这样做的结果相同。 我以为我没有及时安排,但事先安排部分,例如A - B - C预先有相同的结果。 然后,我尝试了不同的帧位置计算,音频格式设置,结果相同。
所以我在这里没有想法,也许我没有正确的计划机制。
任何人都可以确认我可以在AVAudioPlayerNode
中混合调度缓冲区和段吗?或者我应该只安排缓冲区或段?
我可以确认只安排分段工作,播放完全没问题。
关于如何缓存音频部分信息的一些背景信息..
在下面的代码中,从file
,AVAudioFile
和URL
begin
值加载到磁盘上的end
类型为TimeInterval
,并代表我的音频部分的开头/结尾。
let format = file.processingFormat
let startBufferFrameCount: AVAudioFrameCount = 4096
let endBufferFrameCount: AVAudioFrameCount = 4096
let audioSectionStartFrame = framePosition(at: begin, format: format)
let audioSectionEndFrame = framePosition(at: end, format: format)
let segmentStartFrame = audioSectionStartFrame + AVAudioFramePosition(startBufferFrameCount)
let segmentEndFrame = audioSectionEndFrame - AVAudioFramePosition(endBufferFrameCount)
startBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: startBufferFrameCount)
endBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: endBufferFrameCount)
file.framePosition = audioSectionStartFrame
try file.read(into: startBuffer)
file.framePosition = segmentEndFrame
try file.read(into: endBuffer)
middleSegment = (segmentStartFrame, AVAudioFrameCount(segmentEndFrame - segmentStartFrame))
frameCount = AVAudioFrameCount(audioSectionEndFrame - audioSectionStartFrame)
此外,framePosition(at:format:)
将TimeInterval
值乘以传入的AVAudioFormat
的采样率。
我为每个音频部分缓存此信息,但无论是否提前安排,我都会听到部分边界的点击。 我还尝试在调度时不要混用缓冲区和段,但我没有改变任何东西,所以我开始认为我做错了帧计算。