web-dev-qa-db-ja.com

AVAudioEngineによるリアルタイムオーディオ

Hej。 Swiftの新しいAVAudioEngineでリアルタイムオーディオアプリケーションを実装したい。新しいフレームワークを誰かが経験しましたか?リアルタイムアプリケーションはどのように機能しますか?

私の最初のアイデアは、(処理された)入力データをAVAudioPCMBufferオブジェクトに格納し、次にAVAudioPlayerNodeで再生できるようにすることでした。

import AVFoundation

class AudioIO {
    var audioEngine: AVAudioEngine
    var audioInputNode : AVAudioInputNode
    var audioPlayerNode: AVAudioPlayerNode
    var audioMixerNode: AVAudioMixerNode
    var audioBuffer: AVAudioPCMBuffer

    init(){
        audioEngine = AVAudioEngine()
        audioPlayerNode = AVAudioPlayerNode()
        audioMixerNode = audioEngine.mainMixerNode

        let frameLength = UInt32(256)
        audioBuffer = AVAudioPCMBuffer(PCMFormat: audioPlayerNode.outputFormatForBus(0), frameCapacity: frameLength)
        audioBuffer.frameLength = frameLength

        audioInputNode = audioEngine.inputNode

        audioInputNode.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)
            {
                // doing my real time stuff
                self.audioBuffer.floatChannelData.memory[i] = floats[i];
            }
            })

        // setup audio engine
        audioEngine.attachNode(audioPlayerNode)
        audioEngine.connect(audioPlayerNode, to: audioMixerNode, format: audioPlayerNode.outputFormatForBus(0))
        audioEngine.startAndReturnError(nil)

        // play player and buffer
        audioPlayerNode.play()
        audioPlayerNode.scheduleBuffer(audioBuffer, atTime: nil, options: .Loops, completionHandler: nil)
    }
}

しかし、これはリアルタイムとはかけ離れており、あまり効率的ではありません。アイデアや経験はありますか?そして、それは問題ではありません。Objective-CまたはSwiftを好むなら、私はすべてのメモ、コメント、コメント、解決策などに感謝します。

16
Michael Dorner

Objective-CとSwiftの両方でAVAudioEngineを実験しています。私のエンジンのObjective-Cバージョンでは、すべてのオーディオ処理は純粋にCで行われます(AVAudioPCMBufferを通じて利用可能な生のCサンプルポインターをキャッシュし、Cコードのみでデータを操作することにより)。そのパフォーマンスは印象的です。好奇心から、このエンジンをSwiftに移植しました。オーディオファイルをリニアに再生する、またはFM合成を介してトーンを生成するなどのタスクでは、パフォーマンスは非常に良好ですが、配列が関与するとすぐに(たとえば、オーディオのセクションが非線形に再生および操作されるグラニュラーシンセシス) )、パフォーマンスに大きな影響があります。最適化を最適化しても、CPU使用率はObjective-C/Cバージョンよりも30〜40%高くなります。私はSwiftを初めて使用するので、おそらく他の最適化については無知ですが、私が知る限り、C/C++は依然としてリアルタイムオーディオに最適です。また、The Amazing Audio Engineもご覧ください。これと、古いC APIを直接使用することを検討しています。

ライブオーディオを処理する必要がある場合は、AVAudioEngineが適切でない場合があります。この質問に対する私の回答を参照してください: installTapOnBus:bufferSize:format:block :)を1秒あたり20回呼び出します

10
Jason McClinsey

私はこれがあなたが望むことをすると思います: https://github.com/arielelkin/SwiftyAudio

歪みをコメントアウトすると、クリーンなループになります。

5
zzzel

AppleはSwiftのリアルタイムコーディングに関して公式の立場をとっています。 2017年のCore AudioのWWDCセッション で、Appleエンジニアは、Swiftまたは実際のObjective Cメソッドのいずれも使用しないと述べました-timeオーディオコールバックコンテキスト(暗黙的にCのみ、またはおそらくC++とASMを使用することを意味します)。

これは、SwiftおよびObjective Cメソッドを使用すると、制限のないレイテンシのない内部メモリ管理操作が含まれる可能性があるためです。

これは、AVAudioEngineコントローラークラスにObjective Cを使用するのが適切なスキームである可能性があるが、tapOnBusブロック内の(Objective Cの)Cサブセットのみを意味します。

4
hotpaw2

Apple at WWDC2017 in What's New in Core Audio Video によると、エンジニアはSwiftリアルタイムのコンテキストから「安全ではない」。

ここで、エンジンのレンダリングはリアルタイムのコンテキストから行われるため、オフラインでのObjective-Cのレンダリングや、デモで見たSwiftメタ)を使用できなくなります。

そして、Objective-CまたはSwiftリアルタイムコンテキストからのランタイムを使用するのは安全ではないためです。そのため、代わりに、エンジン自体が、検索とキャッシュが可能なレンダーブロックを提供し、後でこのレンダーブロックを使用して、リアルタイムコンテキストからエンジンをレンダリングします。次のことは、実行することです。入力ノードをセットアップして、入力データをエンジンに提供できるようにします。ここでは、提供する入力の形式を指定します。これは出力とは異なる形式にすることができます。また、エンジンは、入力データが必要になるたびに呼び出し、このブロックが呼び出されると、エンジンは実際に必要な入力フレームの数を通知します。

2
Lloyd Rochester