AV Foundation × Core MotionでiPhoneを“楽器”にしよう
どーも。Swift初心者なのにSwift愛好会の運営をしているafroscriptです。
Swift愛好会 vol.41 @リブセンスで談義してきたので、その資料とコードをアップしておきます。
僕の拙いコードが役に立つとは到底思えませんが、もし試してみたい人が入ればご参考に。
ちょっとだけDemo動画(撮ってくれてた)
.@afroscript10 さんのデモ! #love_swift #love_kotlin pic.twitter.com/yyu0yFZGzw
— Hideyuki Nanashima (@jollyjoester) 2019年7月7日
資料はこちら
コードはこちら
// // ViewController.swift // instrumentTest // // Created by Kinoshita Yusaku on 2019/05/10. // Copyright © 2019 afroscript. All rights reserved. // import UIKit import AVFoundation import CoreMotion class ViewController: UIViewController { let motionManager = CMMotionManager() // 9 buttons var audioPlayerInstance2Bass : AVAudioPlayer! = nil var audioPlayerInstance2Cymbal : AVAudioPlayer! = nil var audioPlayerInstance2Hat : AVAudioPlayer! = nil var audioPlayerInstance2Snare : AVAudioPlayer! = nil var audioPlayerInstance2Tom1 : AVAudioPlayer! = nil var audioPlayerInstance2Tom2 : AVAudioPlayer! = nil var audioPlayerInstance2Tom3 : AVAudioPlayer! = nil var audioPlayerInstance1Cymbal : AVAudioPlayer! = nil var audioPlayerInstance1Snare : AVAudioPlayer! = nil var audioPlayerInstanceBuo : AVAudioPlayer! = nil var audioPlayerInstanceShakin2 : AVAudioPlayer! = nil var audioPlayerInstanceWadaiko : AVAudioPlayer! = nil var audioPlayerInstanceBoyon : AVAudioPlayer! = nil var audioPlayerInstanceScrach1 : AVAudioPlayer! = nil var audioPlayerInstanceScrach2 : AVAudioPlayer! = nil var audioPlayerInstanceAmaidesuwa : AVAudioPlayer! = nil var audioPlayerInstanceMadamada : AVAudioPlayer! = nil override func viewDidLoad() { super.viewDidLoad() /* モーションセンサー準備 */ // キューを実行する間隔(秒数) motionManager.deviceMotionUpdateInterval = 0.1 // キューで実行するクロージャ let handler:CMDeviceMotionHandler = {(motionData:CMDeviceMotion?, error:Error?) -> Void in self.motionAnimation(motionData, error: error as NSError?) } // 更新で実行するキューを登録してモーションセンサーをスタートする motionManager.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: handler) /* 音源再生準備 */ //drum2_bass let soundFilePath2Bass = Bundle.main.path(forResource: "drum2_bassdrum", ofType: "mp3")! let sound2Bass:URL = URL(fileURLWithPath: soundFilePath2Bass) do { audioPlayerInstance2Bass = try AVAudioPlayer(contentsOf: sound2Bass, fileTypeHint:nil) } catch { print("AVAudioPlayerインスタンス作成失敗") } audioPlayerInstance2Bass.prepareToPlay() //drum2_cymbal let soundFilePath2Cymbal = Bundle.main.path(forResource: "drum2_cymbal", ofType: "mp3")! let sound2Cymbal:URL = URL(fileURLWithPath: soundFilePath2Cymbal) do { audioPlayerInstance2Cymbal = try AVAudioPlayer(contentsOf: sound2Cymbal, fileTypeHint:nil) } catch { print("AVAudioPlayerインスタンス作成失敗") } audioPlayerInstance2Cymbal.prepareToPlay() //drum2_hat let soundFilePath2Hat = Bundle.main.path(forResource: "drum2_hat", ofType: "mp3")! let sound2Hat:URL = URL(fileURLWithPath: soundFilePath2Hat) do { audioPlayerInstance2Hat = try AVAudioPlayer(contentsOf: sound2Hat, fileTypeHint:nil) } catch { print("AVAudioPlayer1インスタンス作成失敗") } audioPlayerInstance2Hat.prepareToPlay() //drum2_snare let soundFilePath2Snare = Bundle.main.path(forResource: "drum2_snare", ofType: "mp3")! let sound2Snare:URL = URL(fileURLWithPath: soundFilePath2Snare) do { audioPlayerInstance2Snare = try AVAudioPlayer(contentsOf: sound2Snare, fileTypeHint:nil) } catch { print("AVAudioPlayer1インスタンス作成失敗") } audioPlayerInstance2Snare.prepareToPlay() //drum2_tom1 let soundFilePath2Tom1 = Bundle.main.path(forResource: "drum2_tom1", ofType: "mp3")! let sound2Tom1:URL = URL(fileURLWithPath: soundFilePath2Tom1) do { audioPlayerInstance2Tom1 = try AVAudioPlayer(contentsOf: sound2Tom1, fileTypeHint:nil) } catch { print("AVAudioPlayer1インスタンス作成失敗") } audioPlayerInstance2Tom1.prepareToPlay() //drum2_tom2 let soundFilePath2Tom2 = Bundle.main.path(forResource: "drum2_tom2", ofType: "mp3")! let sound2Tom2:URL = URL(fileURLWithPath: soundFilePath2Tom2) do { audioPlayerInstance2Tom2 = try AVAudioPlayer(contentsOf: sound2Tom2, fileTypeHint:nil) } catch { print("AVAudioPlayer1インスタンス作成失敗") } audioPlayerInstance2Tom2.prepareToPlay() //drum2_tom3 let soundFilePath2Tom3 = Bundle.main.path(forResource: "drum2_tom3", ofType: "mp3")! let sound2Tom3:URL = URL(fileURLWithPath: soundFilePath2Tom3) do { audioPlayerInstance2Tom3 = try AVAudioPlayer(contentsOf: sound2Tom3, fileTypeHint:nil) } catch { print("AVAudioPlayer1インスタンス作成失敗") } audioPlayerInstance2Tom3.prepareToPlay() //drum1_cymbal let soundFilePath1Cymbal = Bundle.main.path(forResource: "drum1_cymbal", ofType: "mp3")! let sound1Cymbal:URL = URL(fileURLWithPath: soundFilePath1Cymbal) do { audioPlayerInstance1Cymbal = try AVAudioPlayer(contentsOf: sound1Cymbal, fileTypeHint:nil) } catch { print("AVAudioPlayerインスタンス作成失敗") } audioPlayerInstance1Cymbal.prepareToPlay() //drum1_snare let soundFilePath1Snare = Bundle.main.path(forResource: "drum1_snare", ofType: "mp3")! let sound1Snare:URL = URL(fileURLWithPath: soundFilePath1Snare) do { audioPlayerInstance1Snare = try AVAudioPlayer(contentsOf: sound1Snare, fileTypeHint:nil) } catch { print("AVAudioPlayerインスタンス作成失敗") } audioPlayerInstance1Snare.prepareToPlay() //buo let soundFilePathBuo = Bundle.main.path(forResource: "buo", ofType: "mp3")! let soundBuo:URL = URL(fileURLWithPath: soundFilePathBuo) do { audioPlayerInstanceBuo = try AVAudioPlayer(contentsOf: soundBuo, fileTypeHint:nil) } catch { print("AVAudioPlayerインスタンス作成失敗") } audioPlayerInstanceBuo.prepareToPlay() //shakin2 let soundFilePathShakin2 = Bundle.main.path(forResource: "shakin2", ofType: "mp3")! let soundShakin2:URL = URL(fileURLWithPath: soundFilePathShakin2) do { audioPlayerInstanceShakin2 = try AVAudioPlayer(contentsOf: soundShakin2, fileTypeHint:nil) } catch { print("AVAudioPlayerインスタンス作成失敗") } audioPlayerInstanceShakin2.prepareToPlay() //wadaiko let soundFilePathWadaiko = Bundle.main.path(forResource: "wadaiko", ofType: "mp3")! let soundWadaiko:URL = URL(fileURLWithPath: soundFilePathWadaiko) do { audioPlayerInstanceWadaiko = try AVAudioPlayer(contentsOf: soundWadaiko, fileTypeHint:nil) } catch { print("AVAudioPlayerインスタンス作成失敗") } audioPlayerInstanceWadaiko.prepareToPlay() //boyon let soundFilePathBoyon = Bundle.main.path(forResource: "boyon", ofType: "mp3")! let soundBoyon:URL = URL(fileURLWithPath: soundFilePathBoyon) do { audioPlayerInstanceBoyon = try AVAudioPlayer(contentsOf: soundBoyon, fileTypeHint:nil) } catch { print("AVAudioPlayerインスタンス作成失敗") } audioPlayerInstanceBoyon.prepareToPlay() //scrach1 let soundFilePathScrach1 = Bundle.main.path(forResource: "scrach1", ofType: "mp3")! let soundScrach1:URL = URL(fileURLWithPath: soundFilePathScrach1) do { audioPlayerInstanceScrach1 = try AVAudioPlayer(contentsOf: soundScrach1, fileTypeHint:nil) } catch { print("AVAudioPlayerインスタンス作成失敗") } audioPlayerInstanceScrach1.prepareToPlay() //scrach2 let soundFilePathScrach2 = Bundle.main.path(forResource: "scrach2", ofType: "mp3")! let soundScrach2:URL = URL(fileURLWithPath: soundFilePathScrach2) do { audioPlayerInstanceScrach2 = try AVAudioPlayer(contentsOf: soundScrach2, fileTypeHint:nil) } catch { print("AVAudioPlayerインスタンス作成失敗") } audioPlayerInstanceScrach2.prepareToPlay() //amaidesuwa let soundFilePathAmaidesuwa = Bundle.main.path(forResource: "amaidesuwa", ofType: "mp3")! let soundAmaidesuwa:URL = URL(fileURLWithPath: soundFilePathAmaidesuwa) do { audioPlayerInstanceAmaidesuwa = try AVAudioPlayer(contentsOf: soundAmaidesuwa, fileTypeHint:nil) } catch { print("AVAudioPlayerインスタンス作成失敗") } audioPlayerInstanceAmaidesuwa.prepareToPlay() //madamada let soundFilePathMadamada = Bundle.main.path(forResource: "madamada", ofType: "mp3")! let soundMadamada:URL = URL(fileURLWithPath: soundFilePathMadamada) do { audioPlayerInstanceMadamada = try AVAudioPlayer(contentsOf: soundMadamada, fileTypeHint:nil) } catch { print("AVAudioPlayerインスタンス作成失敗") } audioPlayerInstanceMadamada.prepareToPlay() } /* 各音源再生の関数 */ func playSound2Bass() { audioPlayerInstance2Bass.currentTime = 0 audioPlayerInstance2Bass.play() } func playSound2Cymbal() { audioPlayerInstance2Cymbal.currentTime = 0 audioPlayerInstance2Cymbal.play() } func playSound2Hat() { audioPlayerInstance2Hat.currentTime = 0 audioPlayerInstance2Hat.play() } func playSound2Snare() { audioPlayerInstance2Snare.currentTime = 0 audioPlayerInstance2Snare.play() } func playSound2Tom1() { audioPlayerInstance2Tom1.currentTime = 0 audioPlayerInstance2Tom1.play() } func playSound2Tom2() { audioPlayerInstance2Tom2.currentTime = 0 audioPlayerInstance2Tom2.play() } func playSound2Tom3() { audioPlayerInstance2Tom3.currentTime = 0 audioPlayerInstance2Tom3.play() } func playSound1Cymbal() { audioPlayerInstance1Cymbal.currentTime = 0 audioPlayerInstance1Cymbal.play() } func playSound1Snare() { audioPlayerInstance1Snare.currentTime = 0 audioPlayerInstance1Snare.play() } func playSoundBuo() { audioPlayerInstanceBuo.currentTime = 0 audioPlayerInstanceBuo.play() } func playSoundShakin2() { audioPlayerInstanceShakin2.currentTime = 0 audioPlayerInstanceShakin2.play() } func playSoundWadaiko() { audioPlayerInstanceWadaiko.currentTime = 0 audioPlayerInstanceWadaiko.play() } func playSoundBoyon() { audioPlayerInstanceBoyon.currentTime = 0 audioPlayerInstanceBoyon.play() } func playSoundScrach1() { audioPlayerInstanceScrach1.currentTime = 0 audioPlayerInstanceScrach1.play() } func playSoundScrach2() { audioPlayerInstanceScrach2.currentTime = 0 audioPlayerInstanceScrach2.play() } func playSoundAmaidesuwa() { audioPlayerInstanceAmaidesuwa.currentTime = 0 audioPlayerInstanceAmaidesuwa.play() } func playSoundMadamada() { audioPlayerInstanceMadamada.currentTime = 0 audioPlayerInstanceMadamada.play() } /* ボタンアクション */ @IBAction func tapBtn1() { playSound2Hat() } @IBAction func tabBtn2() { playSound2Cymbal() } @IBAction func tabPtn3() { playSound1Cymbal() } @IBAction func tapBtn4() { playSound2Tom1() } @IBAction func tapBtn5() { playSound2Tom2() } @IBAction func tapBtn6() { playSound2Tom3() } @IBAction func tapBtn7() { playSound2Bass() } @IBAction func tapBtn8() { playSound2Snare() } @IBAction func tapBtn9() { playSound1Snare() } @IBAction func tapBtnButtom() { playSoundWadaiko() } @IBAction func tapBtnTop() { playSoundBoyon() } // モーションセンサーによる音源再生 func motionAnimation(_ motionData:CMDeviceMotion?, error:NSError?) { if let motion = motionData { // ジャイロスコープ(回転角速度:z軸) var gyroZ = motion.rotationRate.z gyroZ = round(gyroZ*100)/100 if gyroZ >= 5 { playSoundBuo() } if gyroZ <= -5 { playSoundShakin2() } // 加速度センサー (Z軸) var accelZ = motion.userAcceleration.z accelZ = round(accelZ * 1000) / 1000 if accelZ >= 1.8 { playSoundAmaidesuwa() } // 加速度センサー (Y軸) var accelY = motion.userAcceleration.y accelY = round(accelY * 1000) / 1000 if accelY >= 1.5 { playSoundScrach1() } } } }
参考資料
- 音鳴らす部分の参考記事
- ボタン素材とかどうすんねん → これ便利だった
- 楽器音は? → ここからお借りしました
- 効果音は? → ここからお借りしました