【问题标题】:Write array of floats to a wav audio file in swift将浮点数组快速写入 wav 音频文件
【发布时间】:2017-06-29 22:58:14
【问题描述】:

我现在有这个流程:我用 AudioEngine 录制音频,将其发送到音频处理库并取回音频缓冲区,然后我有强烈的意愿将其写入 wav 文件,但我完全不知道如何迅速做到这一点。

我已经从另一个 stackoverflow 答案中尝试了这个 sn-p,但它写入了一个空且损坏的文件。(load a pcm into a AVAudioPCMBuffer

//get data from library

var len : CLong = 0
let res: UnsafePointer<Double> = getData(CLong(), &len )
let bufferPointer: UnsafeBufferPointer = UnsafeBufferPointer(start: res, count: len)

//tranform it to Data

let arrayDouble = Array(bufferPointer)
let arrayFloats = arrayDouble.map{Float($0)}
let data = try Data(buffer: bufferPointer)

//attempt to write in file
    do {
        let format = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 16000, channels: 2, interleaved: false)

        var buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(data.count))
        buffer.floatChannelData!.pointee.withMemoryRebound(to: UInt8.self, capacity: data.count) {
            let stream = OutputStream(toBuffer: $0, capacity: data.count)
            stream.open()
            _ = data.withUnsafeBytes {
                stream.write($0, maxLength: data.count)
            }
            stream.close()
        }
        //settings are from AudioEngine.inputNode!.inputFormat(forBus: 0).settings

        var audioFile = try AVAudioFile(forWriting: url, settings: settings)
        try audioFile.write(from: buffer)

    } catch let error as NSError {
        print("ERROR HERE", error.localizedDescription)
    }

所以,我想我对 floatChannelData 的这种转换是错误的,或者一切都错了。任何可以阅读它的建议或指针都会很棒!

【问题讨论】:

    标签: ios swift audio core-audio audiotoolbox


    【解决方案1】:

    在一位出色的同事的帮助下,我们设法让它发挥作用。显然,填充后的 AudioPCMBuffer 也需要通知它的新大小。 我也使用了完全错误的格式。

    代码如下:

    let SAMPLE_RATE =  Float64(16000.0)
    
    let outputFormatSettings = [
        AVFormatIDKey:kAudioFormatLinearPCM,
        AVLinearPCMBitDepthKey:32,
        AVLinearPCMIsFloatKey: true,
        //  AVLinearPCMIsBigEndianKey: false,
        AVSampleRateKey: SAMPLE_RATE,
        AVNumberOfChannelsKey: 1
        ] as [String : Any]
    
    let audioFile = try? AVAudioFile(forWriting: url, settings: outputFormatSettings, commonFormat: AVAudioCommonFormat.pcmFormatFloat32, interleaved: true)
    
    let bufferFormat = AVAudioFormat(settings: outputFormatSettings)
    
    let outputBuffer = AVAudioPCMBuffer(pcmFormat: bufferFormat, frameCapacity: AVAudioFrameCount(buff.count))
    
    // i had my samples in doubles, so convert then write
    
    for i in 0..<buff.count {
        outputBuffer.floatChannelData!.pointee[i] = Float( buff[i] )
    }
    outputBuffer.frameLength = AVAudioFrameCount( buff.count )
    
    do{
        try audioFile?.write(from: outputBuffer)
    
    } catch let error as NSError {
        print("error:", error.localizedDescription)
    }
    

    【讨论】:

    • 嗨 zo_chu 我想知道在录制时是否已完成转换为 wav 文件...目前我可以录制为 m4a 格式,然后在我停止后,录音机会将文件转换为 wav 格式。我正在寻找直接以 wav 格式录制谢谢
    • @ChinchanZu 嗨,我直接写成 wav,它就像一个魅力。示例中的 URL 指向一个 wav 文件。
    • @zo_chu 请告诉我您的代码中的 buff 数组是什么?
    • @MaheshDangar 在我的代码爱好者中是我正在使用的库给我的 Doubles 数组。
    • @zo_chu 非常感谢您的回复,请问您使用的是哪个库?
    【解决方案2】:

    Swift 5 更新

    这是在swift 5中将浮点数组写入wav音频文件的更新。该函数可以用作以下saveWav([channel1, channel2])

    func saveWav(_ buf: [[Float]]) {
        if let format = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 2, interleaved: false) {
            let pcmBuf = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(buf[0].count))
            memcpy(pcmBuf?.floatChannelData?[0], buf[0], 4 * buf[0].count)
            memcpy(pcmBuf?.floatChannelData?[1], buf[1], 4 * buf[1].count)
            pcmBuf?.frameLength = UInt32(buf[0].count)
    
            let fileManager = FileManager.default
            do {
                let documentDirectory = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false)
                try FileManager.default.createDirectory(atPath: documentDirectory.path, withIntermediateDirectories: true, attributes: nil)
                let fileURL = documentDirectory.appendingPathComponent("out.wav")
                print(fileURL.path)
                let audioFile = try AVAudioFile(forWriting: fileURL, settings: format.settings)
                try audioFile.write(from: pcmBuf!)
            } catch {
                print(error)
            }
        }
    }
    

    为确保上述函数正常工作,请使用以下函数将音频文件转换为浮点数组,并使用saveWav将其保存回音频文件

    do {
        guard let url = Bundle.main.url(forResource: "audio_example", withExtension: "wav") else { return }
        let file = try AVAudioFile(forReading: url)
        if let format = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: file.fileFormat.sampleRate, channels: file.fileFormat.channelCount, interleaved: false), let buf = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(file.length)) {
    
            try file.read(into: buf)
            guard let floatChannelData = buf.floatChannelData else { return }
            let frameLength = Int(buf.frameLength)
            // we convert audio using audio pcm buffer to arrays of floats with two channels
            let channel1 = Array(UnsafeBufferPointer(start:floatChannelData[0], count:frameLength))
            let channel2 = Array(UnsafeBufferPointer(start:floatChannelData[1], count:frameLength))
            // we save the audio back using saveWave function
            saveWav([channel1,channel2])
        }
    } catch {
        print("Audio Error: \(error)")
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-22
      • 1970-01-01
      • 2016-02-22
      • 2014-03-20
      • 1970-01-01
      • 2011-09-08
      • 1970-01-01
      • 2023-03-21
      相关资源
      最近更新 更多