iOS で SceneKit を試す(Swift 3) その81 - シーンに音楽や効果音をつける。
正直なところ、Core Audio など iOS 標準機能が使用できるので、 SceneKit のオーディオ再生機能を使用する必要はないけどご紹介。
SceneKit でのオーディオ再生の特徴としては、VR や HoloLens と同様に 3D 空間の位置に対して音源を再生(ミキシング)させることができる。
SceneKit では音を鳴らす方法は2つ。
- ノードの addAudioPlayer に SCNAudioSource (AVAudioNode) を設定した SCNAudioPlayer で再生する
- SCNAction の playAudio で SCNAudioSource を指定して再生する
使用するクラス
- SCNAudioSource
- SCNAudioPlayer
SCNAudioSource
プロパティ名 | デフォルト値 | 説明 |
---|---|---|
init?(named: String) | なし | オーディオファイル名の指定 |
init?(fileNamed: String) | なし | main bundle からのオーディオファイル名の指定 |
init?(url: URL) | なし | URL からのオーディオファイル名の指定 |
isPositional | true | オーディオの音量やリバーブなど距離によって自動的に変化させる。false にすると場所に関係なく一定で再生される |
load() | なし | 事前読み込み用メソッド。shouldStream プロパティの値が true の場合は無効 |
volume | 1.0 | 音量を設定する |
rate | 1.0 | 再生スピード。値を大きくすると再生速度が速くなる |
reverbBlend | 0.0 | リバーブ (お風呂場のような音響効果)を付加する |
loops | false | 繰り返し再生するか否か。デフォルトは false で1回のみの再生 |
shouldStream | false | true の場合はソースファイルから直接読み込み、オーディオバッファデータにロードを行わない。 |
SCNAudioPlayer
プロパティ名 | 説明 |
---|---|
init(source: SCNAudioSource) | SCNAudioSource を設定し初期化する |
init(avAudioNode: AVAudioNode) | AVAudioNode を設定し初期化する |
audioSource | SCNAudioSource を設定する |
audioNode | AVAudioNode を設定する |
willStartPlayback | SCNAudioPlayer 再生前に呼ばれる。ループの場合は最初に戻った際毎回呼ばれるので注意 |
didFinishPlayback | 再生が止まった時呼ばれる |
コードを書いてみる
いつも通り、Xcode の Game テンプレートで SceneKit 選択して、GameViewController.swift を開き、viewDidLoad() の下のところに以下のコードを書く。
あと、適当なオーディオファイルをプロジェクトに追加して、ファイル名を変更すること。
m4a ファイルなどインポート時にターゲットのチェックが外れるものがある。ターゲットが外れていると設定していてもファイルが見つからず音が鳴らないため注意。
let audioNode = SCNNode() audioNode.name = "audioNode" audioNode.position = SCNVector3(0,0,0) scene.rootNode.addChildNode(audioNode) let audioSouce = SCNAudioSource(named: "audio.wav") audioSouce?.loops = true let audioPlayer = SCNAudioPlayer(source: audioSouce!) audioNode.addAudioPlayer(audioPlayer) audioPlayer.willStartPlayback = { print("willStartPlayback") } audioPlayer.didFinishPlayback = { print("didFinishPlayback") }
画面タップで音を止める
いつも通り、func handleTap(_ gestureRecognize: UIGestureRecognizer) の中身を変える。
func handleTap(_ gestureRecognize: UIGestureRecognizer) { let scnView = self.view as! SCNView let audio = scnView.scene?.rootNode.childNode(withName: "audioNode", recursively: true)! audio?.removeAllAudioPlayers() }
シーンから名前をつけた audioNode のノードを探し出し、全ての SCNAudioPlayer を消す。
今回、設定していないが SCNAudioPlayer は複数設定でき、個別で SCNAudioPlayer を消すことができる。
SCNAction で設定する
使用するのは playAudio。
waitForCompletion が true の場合は再生持続時間が SCNAction の長さになる。
false の場合は再生後すぐ完了され、他のアクションがあれば再生中でも移行される。
let audioSouce = SCNAudioSource(named: "a.wav") node.runAction(SCNAction.playAudio(audioSouce!, waitForCompletion: true))
Action なので、他の Action との併用、
順番に行う sequence や全て同時に実行する group が使用できる。
今回はここまで。