Экспортировать аудиофайл после добавления эффекта

У меня есть аудиофайл, который я хочу обработать с использованием некоторых эффектов (например, эффект тангажа), а затем записать окончательный результат в файл.

Прежде чем обрабатывать файл и сохранять его на диск, я позволяю пользователю играть с эффектом тангажа и слушать изменения в реальном времени.

вот как я делаю вещи в реальном времени:

    let audioSession = AVAudioSession.sharedInstance()
    audioSession.setCategory(AVAudioSessionCategoryPlayback, error: nil)
    audioSession.setActive(true, error: nil)

    audioEngine = AVAudioEngine()
    audioFile = AVAudioFile(forReading: audioUrl!, error: nil)

    audioPlayerNode = AVAudioPlayerNode()
    audioEngine.attachNode(audioPlayerNode)

    changePitchEffect = AVAudioUnitTimePitch()
    changePitchEffect.pitch = 1.0 // default
    audioEngine.attachNode(changePitchEffect)

    audioEngine.connect(audioPlayerNode, to: changePitchEffect, format: nil)
    audioEngine.connect(changePitchEffect, to: audioEngine.outputNode, format: nil)

    let frameCapacity = UInt32(audioFile.length)
    let buffer = AVAudioPCMBuffer(PCMFormat: audioFile.processingFormat, frameCapacity: frameCapacity)
    if audioFile.readIntoBuffer(buffer, error: nil) {

        audioEngine.startAndReturnError(nil)

        audioPlayerNode.scheduleBuffer(buffer, atTime: nil, options: .Loops, completionHandler: nil)

        audioPlayerNode.play() // start playing in a loop
    }

затем используя UISlider, я позволяю пользователю изменять значение высоты тона во время прослушивания звука в цикле.

Итак, когда пользователь заканчивает игру с шагом и нажимает следующую кнопку, мне нужно сохранить аудиофайл с выбранным значением основного тона.

Мой вопрос: как мне создать новый аудиофайл с эффектом тангажа?

Я не хочу записывать, пока пользователь слушает звук и играет с эффектом тангажа, я хочу только экспортировать конечный результат (без воспроизведения файла, конечно)

Ответ 1

Так как использование AVAudioSession не является явным требованием в заголовке вопроса, есть два возможных ответа:

Проиграйте через node (с AVAudioSession)

Установите кран на node. См. Справочник по основам AV Foundation.

audioPlayerNode.installTapOnBus(0, bufferSize:frameLength, format: audioInputNode.outputFormatForBus(0), block: {(buffer, time) in
    let channels = UnsafeArray(start: buffer.floatChannelData, length: Int(buffer.format.channelCount))
    let floats = UnsafeArray(start: channels[0], length: Int(buffer.frameLength))

    for var i = 0; i < Int(self.audioBuffer.frameLength); i+=Int(self.audioMixerNode.outputFormatForBus(0).channelCount)
    {
        // process
    }
})

Механизм переключения AVAudioSession требует воспроизведения. Подробнее о записи во время воспроизведения ответа с помощью @matt.


Использовать AudioUnit (без AVAudioSession)

Инициализируйте AudioSession с помощью AudioSessionInitialize, чтобы воспроизвести и записать, настроить поток чтения и записи и передать AURenderCallbackStruct, указывая на ваш код обработки данных. Это, однако, не позволяет вам извлечь выгоду из AVAudioUnitTimePitch. Вы можете узнать больше об этом решении в Как сделать запись в реальном времени с обработкой эффекта в iOS.