3

当使用 AVAudioPlayerNode 安排一个短缓冲区以在触摸事件(“Touch Up Inside”)上立即播放时,我注意到在测试时播放时会出现可听见的故障/伪影。iOS 模拟器中的音频完全没有故障,但是当我在实际的 iOS 设备上运行该应用程序时,播放时会出现声音失真。声音失真随机发生(触发的声音有时听起来很棒,而其他时候听起来失真)

我尝试过使用不同的音频文件、文件格式,并使用 prepareWithFrameCount 方法准备播放缓冲区,但不幸的是结果总是一样的,我想知道可能出了什么问题。

为了清晰和简单起见,我将代码简化为全局变量。任何帮助或见解将不胜感激。这是我第一次尝试开发 iOS 应用程序,也是我在 Stack Overflow 上发布的第一个问题。

let filePath = NSBundle.mainBundle().pathForResource("BD_withSilence", ofType: "caf")!
let fileURL: NSURL = NSURL(fileURLWithPath: filePath)!
var error: NSError?
let file = AVAudioFile(forReading: fileURL, error: &error)

let fileFormat = file.processingFormat
let frameCount = UInt32(file.length)
let buffer = AVAudioPCMBuffer(PCMFormat: fileFormat, frameCapacity: frameCount)

let audioEngine = AVAudioEngine()
let playerNode = AVAudioPlayerNode()

func startEngine() {

    var error: NSError?
    file.readIntoBuffer(buffer, error: &error)
    audioEngine.attachNode(playerNode)
    audioEngine.connect(playerNode, to: audioEngine.mainMixerNode, format: buffer.format)
    audioEngine.prepare()

    func start() {
        var error: NSError?
        audioEngine.startAndReturnError(&error)
    }

    start()

}

startEngine()

let frameCapacity = AVAudioFramePosition(buffer.frameCapacity)
let frameLength = buffer.frameLength
let sampleRate: Double = 44100.0

func play() {

    func scheduleBuffer() {
    playerNode.scheduleBuffer(buffer, atTime: nil, options: AVAudioPlayerNodeBufferOptions.Interrupts, completionHandler: nil)
    playerNode.prepareWithFrameCount(frameLength)
    }

    if playerNode.playing == false {
        scheduleBuffer()
        let time = AVAudioTime(sampleTime: frameCapacity, atRate: sampleRate)
        playerNode.playAtTime(time)
    }
    else {
        scheduleBuffer()
    }
}

// triggered by a "Touch Up Inside" event on a UIButton in my ViewController

@IBAction func triggerPlay(sender: AnyObject) {
   play()
}

更新:

好的,我想我已经确定了失真的来源:节点的音量在输出时太大并导致削波。通过在我的 startEngine 函数中添加这两行,失真不再发生:

playerNode.volume = 0.8
audioEngine.mainMixerNode.volume = 0.8

但是,我仍然不知道为什么我需要降低输出 - 我的音频文件本身没有剪辑。我猜这可能是 AVAudioPlayerNodeBufferOptions.Interrupts 实现方式的结果。当一个缓冲区中断另一个缓冲区时,是否会因中断而导致输出音量增加,从而导致输出削波?我仍在寻找关于为什么会发生这种情况的可靠理解。如果有人愿意/能够对此提供任何澄清,那就太好了!

4

1 回答 1

0

不确定这是否是您在 2015 年遇到的问题,可能与 @suthar 在 2018 年遇到的问题相同。

我遇到了一个非常相似的问题,这是由于设备上的 sampleRate 与模拟器不同。在 macOS 上为 44100,在 iOS 设备(最新型号)上为 48000。

因此,当您在 48000 设备上用 44100 个样本填充缓冲区时,您将获得 3900 个静音样本。播放时听起来不像是静音,听起来像是一个小故障。

在连接我的 playerNode 以及创建我的 pcmBuffer 时,我使用了 mainMixer 格式。不要在代码中的任何地方引用 48000 或 44100。

    audioEngine.attach( playerNode)
    audioEngine.connect( playerNode, to:mixerNode, format:mixerNode.outputFormat(forBus:0))

    let pcmBuffer = AVAudioPCMBuffer( pcmFormat:SynthEngine.shared.audioEngine.mainMixerNode.outputFormat( forBus:0),
                                      frameCapacity:AVAudioFrameCount(bufferSize))
于 2019-02-17T07:17:49.137 回答