Звуковые глюки при воспроизведении буфера через AVAudioPlayerNode в iOS (Swift) *, работающие в симуляторе, но не на устройстве

При использовании AVAudioPlayerNode для планирования короткого буфера для немедленного воспроизведения на сенсорном событии ("Touch Up Inside"), я заметил слышимые глюки / артефакты при воспроизведении во время тестирования. В симуляторе iOS звук совсем не глючит, однако при воспроизведении приложения на реальном устройстве iOS слышны искажения при воспроизведении. Звуковое искажение происходит случайным образом (сработавший звук иногда будет звучать великолепно, в то время как в других случаях он звучит искаженно)

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

Я сократил код до глобальных для ясности и простоты. Любая помощь или понимание будет принята с благодарностью. Это моя первая попытка разработки приложения для iOS и мой первый вопрос, размещенный на Stack Overflow.

let filePath = NSBundle.mainBundle().pathForResource("BD_withSilence", ofType: "caf")!
let fileURL: NSURL = NSURL(fileURLWithPath: filePath)!
var error: NSError?
let file = AVAudioFile(forReading: fileURL, error: &error)

let fileFormat = file.processingFormat
let frameCount = UInt32(file.length)
let buffer = AVAudioPCMBuffer(PCMFormat: fileFormat, frameCapacity: frameCount)

let audioEngine = AVAudioEngine()
let playerNode = AVAudioPlayerNode()

func startEngine() {

    var error: NSError?
    file.readIntoBuffer(buffer, error: &error)
    audioEngine.attachNode(playerNode)
    audioEngine.connect(playerNode, to: audioEngine.mainMixerNode, format: buffer.format)
    audioEngine.prepare()

    func start() {
        var error: NSError?
        audioEngine.startAndReturnError(&error)
    }

    start()

}

startEngine()

let frameCapacity = AVAudioFramePosition(buffer.frameCapacity)
let frameLength = buffer.frameLength
let sampleRate: Double = 44100.0

func play() {

    func scheduleBuffer() {
    playerNode.scheduleBuffer(buffer, atTime: nil, options: AVAudioPlayerNodeBufferOptions.Interrupts, completionHandler: nil)
    playerNode.prepareWithFrameCount(frameLength)
    }

    if playerNode.playing == false {
        scheduleBuffer()
        let time = AVAudioTime(sampleTime: frameCapacity, atRate: sampleRate)
        playerNode.playAtTime(time)
    }
    else {
        scheduleBuffer()
    }
}

// triggered by a "Touch Up Inside" event on a UIButton in my ViewController

@IBAction func triggerPlay(sender: AnyObject) {
   play()
}

Обновить:

Хорошо, я думаю, что я определил источник искажения: громкость узла (ов) слишком велика на выходе и вызывает обрезание. Добавив эти две строки в мою функцию startEngine, искажение больше не происходило:

playerNode.volume = 0.8
audioEngine.mainMixerNode.volume = 0.8

Тем не менее, я до сих пор не знаю, почему мне нужно уменьшить выходной сигнал - сам мой аудиофайл не обрезается. Я предполагаю, что это может быть результатом того, как реализован AVAudioPlayerNodeBufferOptions.Interrupts. Когда буфер прерывает другой буфер, может ли быть увеличение выходного объема в результате прерывания, вызывая ограничение вывода? Я все еще ищу твердое понимание относительно того, почему это происходит.. Если кто-то желает / может дать какие-либо разъяснения по этому поводу, это было бы здорово!

0 ответов

Не уверен, что это проблема, с которой вы столкнулись в 2015 году, это может быть та же проблема, что и @suthar в 2018 году.

У меня возникла очень похожая проблема, и это было связано с тем, что sampleRate на устройстве отличается от симулятора. На macOS это 44100, а на iOS-устройствах (поздних моделях) это 48000.

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

Я использовал формат mainMixer при подключении моего playerNode, а также при создании моего pcmBuffer. Не обращайтесь к 48000 или 44100 где-либо в коде.

    audioEngine.attach( playerNode)
    audioEngine.connect( playerNode, to:mixerNode, format:mixerNode.outputFormat(forBus:0))

    let pcmBuffer = AVAudioPCMBuffer( pcmFormat:SynthEngine.shared.audioEngine.mainMixerNode.outputFormat( forBus:0),
                                      frameCapacity:AVAudioFrameCount(bufferSize))
Другие вопросы по тегам