67804


お世話になっております．  
Swiftを使用してアプリを開いたら音が自動でなるコード実装したいのですが，以下の様に作ったところ音が再生されません．  
AVAudioPlayerの場合は再生が可能だったのでAudio Engineの使い方に問題があると思っております．  
コード自体は回ってしまいます．

お手数ですがよろしくお願いいたします．

[code]

    import UIKit
    import Accelerate
    import CoreAudioKit
    import AVFoundation
    
    class ViewController: UIViewController {
    
        var audioFile:AVAudioFile!
        var PCMBuffer:AVAudioPCMBuffer!
        var address:String?
        var buffer:[[Float]]! = Array<Array<Float>>()
        var samplingRate:Double?
        var nChannel:Int?
        var nframe:Int?
            
        let url = Bundle.main.bundleURL.appendingPathComponent("ファイル名.wav")
    
        //最初からあるメソッド
        override func viewDidLoad() {
            super.viewDidLoad()
            loadAudioData()
            // bluetooth接続用
            try! AVAudioSession.sharedInstance()
                .setCategory(.playAndRecord,
                             mode: .voiceChat,
                             options: .allowBluetoothA2DP)
        }
    
        
        func loadAudioData(){
                //オーディオファイルを読み込み、データをaudioFileに格納
                let player = AVAudioPlayerNode()
                let engine = AVAudioEngine()
                self.audioFile = try! AVAudioFile(forReading: url)
                self.samplingRate = self.audioFile.fileFormat.sampleRate
                self.nChannel = Int(self.audioFile.fileFormat.channelCount)
                self.nframe = Int(self.audioFile.length)
                self.PCMBuffer = AVAudioPCMBuffer(pcmFormat: self.audioFile.processingFormat, frameCapacity: AVAudioFrameCount(self.nframe!))
                try! self.audioFile.read(into: self.PCMBuffer)
                
                engine.attach(player)
                engine.connect(player, to: engine.mainMixerNode, format: self.PCMBuffer.format)
            
                do {
                  // エンジンの開始
                  try engine.start()
                  // プレイヤーの再生
                  player.play()
                } catch let error {
                  print(error)
                }
                
        }
    
        
    }
    
[/code]


CC BY-SA 4.0
2020-06-19T01:52:35.617
67798
2020-06-19T04:40:27.757
17131
question
swift
Audio Engineを使用した音源の自動再生について


大きく2つの問題点があります。

  1. `AVAudioEngine`がローカル変数になっている

  2. `AVAudioPlayerNode`に対して、せっかく作成した`AVAudioPCMBuffer`を再生するよう設定していない

`AVAudioEngine`のインスタンスは、`AVAudioEngine`の動作中(再生中)はずっとどこかに強参照で保持されていないといけません。`ViewController`クラスのインスタンスプロパティにしておくのが適切でしょう。

(一方、`audioFile`から`nframe`までのインスタンスプロパティは、なぜインスタンスプロパティなのか理解できませんでした。以下のコード例では、それらのインスタンスプロパティは削除して、ローカル変数にしています。何か別の処理で使用するために必要なら適宜書き換えて下さい。ついでに言うと、Implicitly
Unwrapped Optionalと通常Optionalの使い分けの基準も不明です…。)

[code]

        let engine = AVAudioEngine() //<-1.
        
        func loadAudioData() {
            //オーディオファイルを読み込み、データをaudioFileに格納
            let player = AVAudioPlayerNode()
            do {
                let audioFile = try AVAudioFile(forReading: url)
                let nframe = audioFile.length
                guard let pcmBuffer = AVAudioPCMBuffer(pcmFormat: audioFile.processingFormat, frameCapacity: AVAudioFrameCount(nframe)) else {
                    print("Failed creating AVAudioPCMBuffer")
                    return
                }
                try audioFile.read(into: pcmBuffer)
                
                engine.attach(player)
                engine.connect(player, to: engine.mainMixerNode, format: pcmBuffer.format)
                
                player.scheduleBuffer(pcmBuffer, completionHandler: nil) //<-2.
            } catch {
                print(error)
                return
            }
            
            do {
                // エンジンの開始
                try engine.start()
                // プレイヤーの再生
                player.play()
            } catch let error {
                print(error)
            }
        }
    
[/code]

(強制アンラップや強制tryを使用していた部分も書き換えました。「自分には理解できない挙動をする(可能性がある)」と言う場合に、それらを使用するべきではありません。)

再生するのに不要なコードは削除してあります。また、`scheduleBuffer`ではなく、`scheduleFile`を使えばもう少し短くなりますが、`AVAudioPCMBuffer`を使う意図がよくわからないので、そこはそのままにしてあります。

`//<-1.`と`
//<-2.`で示した修正以外は今回の事象に関して本質的なものではありませんが、出来る限り「予想外の事態が発生した場合に得られる情報を黙って捨てない」ようなコーディングを心がけられた方が良いかと思います。


CC BY-SA 4.0
2020-06-19T04:40:27.757
67804
2020-06-19T04:40:27.757
13972
67798
answer