しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

AVAudioEngineで複数音源を合成して再生

AVAudioEngineを使って複数のmp3音源を同時再生する実装を試してみました。

プロジェクトを作ったら、再生したい音をプロジェクトに追加します。
今回はドとミの音を追加しました。

f:id:llcc:20180521135924p:plain

まずは単一の音源を再生します。
再生はAVAudioPlayerNodeを使って行います。

import UIKit
import AVFoundation

class ViewController: UIViewController {
    let engine = AVAudioEngine()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let player = AVAudioPlayerNode()
        if let path = Bundle.main.path(forResource: "do", ofType: "mp3") {
            let url = URL(fileURLWithPath: path)
            
            if let file = try? AVAudioFile(forReading: url) {
                engine.attach(player)
                engine.connect(player, to: engine.mainMixerNode, format: file.processingFormat)
                player.scheduleFile(file, at: nil, completionHandler: nil)
                try? engine.start()
                player.play()
            }
        }
    }
}

次に複数の音源を再生します。
AVAudioPlayerNodeを複数生成する事で実装しました。

import UIKit
import AVFoundation

class ViewController: UIViewController {
    let engine = AVAudioEngine()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let player1 = AVAudioPlayerNode()
        let player2 = AVAudioPlayerNode()
        if let path1 = Bundle.main.path(forResource: "do", ofType: "mp3"), let path2 = Bundle.main.path(forResource: "mi", ofType: "mp3") {
            let url1 = URL(fileURLWithPath: path1)
            let url2 = URL(fileURLWithPath: path2)
            
            if let file1 = try? AVAudioFile(forReading: url1), let file2 = try? AVAudioFile(forReading: url2) {
                engine.attach(player1)
                engine.attach(player2)
                engine.connect(player1, to: engine.mainMixerNode, format: file1.processingFormat)
                engine.connect(player2, to: engine.mainMixerNode, format: file2.processingFormat)
                player1.scheduleFile(file1, at: nil, completionHandler: nil)
                player2.scheduleFile(file2, at: nil, completionHandler: nil)
                try? engine.start()
                player1.play()
                player2.play()
            }
        }
    }
}