-50 ошибка при преобразовании буфера PCM с AVAudioConverter - PullRequest
1 голос
/ 18 февраля 2020

Я пытаюсь преобразовать AVAudioPCMBuffer с частотой дискретизации 44100 в единицу с частотой дискретизации 48000, но я всегда получаю исключение (ошибка -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)")
}

Есть идеи?

1 Ответ

1 голос
/ 19 февраля 2020

Инженер Apple ответил на это на своих форумах разработчиков. Я пропустил, что convert(to:from:) вариант AVAudioConverter не может преобразовать частоту дискретизации, поэтому вы должны использовать 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
}
...