Hello, afroWorld

afroscriptのafroblog

AV Foundation × Core MotionでiPhoneを“楽器”にしよう

f:id:afroscript:20190626203345j:plain

どーも。Swift初心者なのにSwift愛好会の運営をしているafroscriptです。

Swift愛好会 vol.41 @リブセンスで談義してきたので、その資料とコードをアップしておきます。

僕の拙いコードが役に立つとは到底思えませんが、もし試してみたい人が入ればご参考に。

love-swift.connpass.com

ちょっとだけDemo動画(撮ってくれてた)

資料はこちら

コードはこちら

//
//  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()
            }
            
        }
        
    }


}

参考資料