Преобразование AVAudioPCMBuffer в NSData и обратно

Как преобразовать AVAudioPCMBuffer в NSData? Если это должно быть сделано как

let data = NSData(bytes: buffer.floatChannelData, length: bufferLength)

тогда как рассчитать bufferLength?

И как преобразовать NSData в AVAudioPCMBuffer?


person Shmidt    schedule 20.01.2015    source источник


Ответы (2)


Длина буфера равна frameCapacity * bytesPerFrame. Вот функции, которые могут выполнять преобразование между NSData и AVAudioPCMBuffer.

func toNSData(PCMBuffer: AVAudioPCMBuffer) -> NSData {
    let channelCount = 1  // given PCMBuffer channel count is 1
    var channels = UnsafeBufferPointer(start: PCMBuffer.floatChannelData, count: channelCount)
    var ch0Data = NSData(bytes: channels[0], length:Int(PCMBuffer.frameCapacity * PCMBuffer.format.streamDescription.memory.mBytesPerFrame))
    return ch0Data
}       

func toPCMBuffer(data: NSData) -> AVAudioPCMBuffer {
    let audioFormat = AVAudioFormat(commonFormat: AVAudioCommonFormat.PCMFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false)  // given NSData audio format
    var PCMBuffer = AVAudioPCMBuffer(PCMFormat: audioFormat, frameCapacity: UInt32(data.length) / audioFormat.streamDescription.memory.mBytesPerFrame)
    PCMBuffer.frameLength = PCMBuffer.frameCapacity
    let channels = UnsafeBufferPointer(start: PCMBuffer.floatChannelData, count: Int(PCMBuffer.format.channelCount))
    data.getBytes(UnsafeMutablePointer<Void>(channels[0]) , length: data.length)
    return PCMBuffer
}
person Rod Chen    schedule 24.05.2015
comment
Я тоже @Massimo. - person Brennan; 10.03.2017
comment
Мне удалось преобразовать NSData в AVAudioPCMBuffer (мне не нужно обратное, поэтому у меня нет этого кода): pastebin. com/raw/m5c74FPA - person Massimo; 13.03.2017
comment
@Massimo, как это изменить, означает AVAudioPCMBuffer на 16-битный NSData? - person Dipen Chudasama; 30.08.2017
comment
объективный ответ? - person Billy Caruso; 16.03.2019
comment
Для Swift 4 замените streamDescription.memory на streamDescription.pointee. - person Avi; 06.08.2019
comment
Привет, можно ли использовать .floatChannelData, когда данные на самом деле int16? - person ch271828n; 17.09.2020

Копировать буферы намного проще, если вы копируете через audioBufferList API. Это также работает независимо от формата фактического буфера.

extension Data {
    init(buffer: AVAudioPCMBuffer, time: AVAudioTime) {
        let audioBuffer = buffer.audioBufferList.pointee.mBuffers
        self.init(bytes: audioBuffer.mData!, count: Int(audioBuffer.mDataByteSize))
    }

    func makePCMBuffer(format: AVAudioFormat) -> AVAudioPCMBuffer? {
        let streamDesc = format.streamDescription.pointee
        let frameCapacity = UInt32(count) / streamDesc.mBytesPerFrame
        guard let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: frameCapacity) else { return nil }

        buffer.frameLength = buffer.frameCapacity
        let audioBuffer = buffer.audioBufferList.pointee.mBuffers

        withUnsafeBytes { (bufferPointer) in
            guard let addr = bufferPointer.baseAddress else { return }
            audioBuffer.mData?.copyMemory(from: addr, byteCount: Int(audioBuffer.mDataByteSize))
        }

        return buffer
    }
}
person Brian King    schedule 10.10.2018
comment
Чтобы избежать предупреждения 'withUnsafeBytes' is deprecated: use 'withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R' с Swift 5, вы можете передать функцию addr.baseAddress в copyMemory вместо addr. - person aleksmutlu; 07.11.2019