使用 AVAudioConverter 转换 PCM 缓冲区时出现 -50 错误

-50 error when converting PCM buffer with AVAudioConverter

我正在尝试将采样率为 44100 的 AVAudioPCMBuffer 转换为采样率为 48000 的 AVAudioPCMBuffer,但在转换时我总是遇到异常(-50 错误)。这是代码:

guard let deviceFormat = AVAudioFormat(standardFormatWithSampleRate: 48000.0, channels: 1) else {
    preconditionFailure()
}

// This file is saved as mono 44100
guard let lowToneURL = Bundle.main.url(forResource: "Tone220", withExtension: "wav") else {
    preconditionFailure()
}
guard let audioFile = try? AVAudioFile(forReading: lowToneURL) else {
    preconditionFailure()
}

let tempBuffer = AVAudioPCMBuffer(pcmFormat: audioFile.processingFormat,
                                       frameCapacity: AVAudioFrameCount(audioFile.length))!
tempBuffer.frameLength = tempBuffer.frameCapacity
    do { try audioFile.read(into: tempBuffer) } catch {
        assertionFailure("*** Caught: \(error)")
    }

guard let converter = AVAudioConverter(from: audioFile.processingFormat, to: deviceFormat) else {
    preconditionFailure()
}
guard let convertedBuffer = AVAudioPCMBuffer(pcmFormat: deviceFormat,
                                                     frameCapacity: AVAudioFrameCount(audioFile.length)) else {
    preconditionFailure()
}
convertedBuffer.frameLength = tempBuffer.frameCapacity
do { try converter.convert(to: convertedBuffer, from: tempBuffer) } catch {
     assertionFailure("*** Caught: \(error)")
}

有什么想法吗?

一位 Apple 工程师在他们的开发论坛上回答了这个问题。我错过了 AVAudioConverterconvert(to:from:) 变体无法转换采样率,因此您必须使用 withInputFrom 变体。关于那方面的文档不太清楚,但我想出了:

private func pcmBufferForFile(filename: String, sampleRate: Float) -> AVAudioPCMBuffer {

    guard let newFormat = AVAudioFormat(standardFormatWithSampleRate: Double(sampleRate), channels: 1) else {
        preconditionFailure()
    }
    guard let url = Bundle.main.url(forResource: filename, withExtension: "wav") else {
        preconditionFailure()
    }
    guard let audioFile = try? AVAudioFile(forReading: url) else {
        preconditionFailure()
    }
    guard let tempBuffer = AVAudioPCMBuffer(pcmFormat: audioFile.processingFormat,
                                            frameCapacity: AVAudioFrameCount(audioFile.length)) else {
        preconditionFailure()
    }

    let conversionRatio = sampleRate / Float(tempBuffer.format.sampleRate)
    let newLength = Float(audioFile.length) * conversionRatio
    guard let newBuffer = AVAudioPCMBuffer(pcmFormat: newFormat,
                                           frameCapacity: AVAudioFrameCount(newLength)) else {
        preconditionFailure()
    }

    do { try audioFile.read(into: tempBuffer) } catch {
        preconditionFailure()
    }
    guard let converter = AVAudioConverter(from: audioFile.processingFormat, to: newFormat) else {
        preconditionFailure()
    }
    var error: NSError?
    converter.convert(to: newBuffer, error: &error, withInputFrom: { (packetCount, statusPtr) -> AVAudioBuffer? in
        statusPtr.pointee = .haveData
        return tempBuffer
    })
    if error != nil {
        print("*** Conversion error: \(error!)")
    }
    return newBuffer
}