AVAudioConverter портит данные

Я пытаюсь преобразовать AVAudioPCMBufferот Float32 44,1 кГц до Int16 8 кГц. я использую AVAudioConverter. Но после конвертации я получаю поврежденные данные. Когда я читаю данные с микрофона каждые 100 мс, я получаю битый каждый 800-й образец (первый образец в считанных данных). Разбитый образец выглядит следующим образом:битый образец

Это всего лишь один сэмпл из 800, но каждые 100 мс он звучит как действительно раздражающий щелчок. Вот фрагмент моего кода:

...
    let outputFormat = AVAudioFormat(commonFormat: .pcmFormatInt16,
                                     sampleRate: 8000,
                                     channels: 1,
                                     interleaved: false)!
    let input = self.engine.inputNode
    let bus = 0
    let inputFormat = input.outputFormat(forBus: bus)
        
    let bufferSize = inputFormat.sampleRate * 0.1 // Read every 100ms
        
    input.installTap(onBus: bus, bufferSize: UInt32(bufferSize), format: inputFormat) { (buffer, time) -> Void in
                
        let convertedBuffer = self.convertBuffer(buffer: buffer, from: inputFormat, to: outputFormat)
        if self.isRecording {
            self.inFile?.seekToEndOfFile()
            let data = Data(buffer: UnsafeBufferPointer(start: convertedBuffer.int16ChannelData![0], count: Int(convertedBuffer.frameLength)))
            self.inFile?.write(data)
        }
...

func convertBuffer(buffer: AVAudioPCMBuffer,
                   from inputFormat: AVAudioFormat,
                   to outputFormat: AVAudioFormat) -> AVAudioPCMBuffer {
        
    let converter = AVAudioConverter(from: inputFormat, to: outputFormat)!
        
    let inputCallback: AVAudioConverterInputBlock = { inNumPackets, outStatus in
        outStatus.pointee = .haveData
        return buffer
    }
        
    let convertedBuffer = AVAudioPCMBuffer(
        pcmFormat: outputFormat,
        frameCapacity: AVAudioFrameCount(outputFormat.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate))!
        
    var error: NSError?
    let status = converter.convert(to: convertedBuffer, error: &error, withInputFrom: inputCallback)
    assert(status != .error)
        
    return convertedBuffer
}

Когда я пишу буфер без какого-либо преобразования, я получаю чистый звук без искажений. Если я буду читать данные каждые 200 мс, каждая 1600-я выборка будет повреждена. Таким образом, поврежден только первый образец из каждого полученного мной буфера.

Я действительно не знаю, что не так с моим кодом и почему он так работает. Есть ли ошибка?

PS Меня не очень волнует преобразование, все, что мне нужно, это получить необработанные аудиоданные 16 бит PCM 8 кГц с микрофона. Если кто-нибудь знает, как это сделать по-другому, я очень признателен за вашу помощь.

1 ответ

Решение

Аудиоконвертеры имеют внутреннее состояние. Создание одного преобразователя вместо одного при каждом вызове convertBuffer должен исправить проблему.

Другие вопросы по тегам