LoginSignup
23
19

More than 5 years have passed since last update.

[iOS]マイクアプリを作る

Last updated at Posted at 2018-12-23

Hello, World! あーみーです.

この記事はLife is Tech! Tokai Mentors Advent Calendar 2018 23日目の記事です.

忙しくてずっと下書きで眠っていたので,アドベントカレンダーの力を借りて記事を完成させました.

今回は僕が作ったアプリで恐縮ですが.このアプリの音声の入出力の部分を作ります.

はじめに

僕は合唱をやっていたので,音楽に関係するアプリを作りたいなと思い,iPhoneがマイクになるアプリを作ろうと思いました.

iPhoneでの音声入力は調べたら結構実装できる程度には記事が見つかるんですが,マイクを作りたいので,入力だけではいけません.その入力した音声を同時にスピーカーから出力しないとマイクとは言えませんから.

音声を入力と同時に出力する方法は調べてもなかなか記事が見つからなかったため,記事にしました.

環境

僕の今回のPC環境を以下に示します.

  • High Sierra 10.13
  • XCode 10.1
  • Swift 4
  • iPhoneX(実機でのテストのため)

マイク実装

#1. とりあえず部品を配置する

音声入力と音声出力に必要なUI部品は特に何もないですが,スピーカーに繋げて出力した時にハウリングしたり,音が大きいとビックリするので,それを制御するために以下の部品を配置します.

  • マイクON/OFF用UISwitch
  • マイクボリューム用UISlider

スクリーンショット 2018-12-22 17.02.52.png

#2. 音声入出力

音声の入出力自体はとても簡単でViewControllerを以下のようにするだけで,音は出るようになります.

import UIKit
import AVFoundation

class ViewController: UIViewController {

    private var engine = AVAudioEngine()

    override func viewDidLoad() {
        super.viewDidLoad()

        let input = engine.inputNode
        let output = engine.mainMixerNode
        let format = engine.inputNode.inputFormat(forBus: 0)

        engine.connect(input, to: output, format: format)

        try! engine.start()
    }
}

簡単ですね!

ただ,このままではマイクに無許可でアクセスしようとして起動と同時にアプリが落ちてしまうので,Info.plistに以下を追加します.

Key Value
Privacy - Microphone Usage Description [マイクを使用する理由]

また,#1の時に配置したUISwitchUISliderでマイクを制御するため,ViewControllerに以下も追記します.

    // マイクON/OFF用UISwitch
    @IBAction func changeMicState(sw: UISwitch){
        if sw.isOn {
            try! engine.start()
        }else{
            engine.stop()
        }
    }

    // マイクボリューム用UISlider
    @IBAction func micSlider(slider: UISlider){
        engine.inputNode.volume = slider.value
    }

どちらも値が変わった時に変更を加えたいので,Value Changedでアタッチします.

スクリーンショット 2018-12-22 17.32.45.png

#3. Bluetoothスピーカーから出力

マイクのように声を増幅させたいので,スピーカーから出力することが目的となります.
今でも,iPhoneのイヤホンジャックとスピーカーをミニプラグで繋げれば可能ですが,最近はイヤホンジャックが廃止されていますし,有線だと,スマートじゃありません.

なので,Bluetoothでスピーカーに接続していきます.viewDidLoad内に以下を追記すればBluetoothスピーカーにも対応できます.

    override func viewDidLoad() {
        super.viewDidLoad()

        // Bluetooth接続を許可
        try! AVAudioSession.sharedInstance()
            .setCategory(.playAndRecord,
                         mode: .voiceChat,
                         options: .allowBluetoothA2DP)
    }

ただ,Bluetoothでスピーカーに繋ぐと音声が入力されてから出力されるまでにタイムラグがあります.
自分の声が遅れて聞こえてくるので喋りづらいかもしれません.しょうがない気もしますが.

タイムラグをなくすことができるかどうかはわかりません.もし,方法知ってるよって方がいればコメント等お願いします.

これでマイクアプリは完成です!

エフェクト実装

せっかくのマイクアプリなので,多少のマイクパフォーマンスができるように変更していきます.
今回は以下の2つの機能をつけます.

  • リバーブ
  • ディレイ

#1. とりあえず部品を配置する

マイク用の部品に加えてリバーブ用,ディレイ用にもUISliderを追加します.

スクリーンショット 2018-12-22 19.42.39.png

画像の上から順に

  • マイクON/OFF用UISwitch
  • マイクボリューム用UISlider
  • リバーブレベル用UISlider
  • ディレイタイム用UISlider

となります,

#2. AVAudioEngineに繋げる

先程のViewControllerを以下のように変更します.

import UIKit
import AVFoundation

class ViewController: UIViewController {

    private var engine = AVAudioEngine()

    private var reverb = AVAudioUnitReverb()
    private var delay = AVAudioUnitDelay()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Bluetooth接続を許可
        try! AVAudioSession.sharedInstance()
            .setCategory(.playAndRecord,
                         mode: .voiceChat,
                         options: .allowBluetoothA2DP)

        let input = engine.inputNode
        let output = engine.mainMixerNode
        let format = engine.inputNode.inputFormat(forBus: 0)

        engine.attach(reverb)
        engine.attach(delay)

        reverb.wetDryMix = 0
        delay.delayTime = 0

        engine.connect(input, to: reverb, format: format)
        engine.connect(reverb, to: delay, format: format)
        engine.connect(delay, to: output, format: format)

        try! engine.start()

    }
}

音声にエフェクトをつけたい時は,ギターのエフェクターを繋げるみたいに,それぞれのエフェクトをinputからoutputまでの間に入れてあげればできます.

minimax (41).png

図だとこんな感じですね.

そして,エフェクターのつまみを回すように,エフェクトレベルを変更する関数を用意します.

    // リバーブレベル用UISlider
    @IBAction func reverbSlider(slider: UISlider){
        reverb.wetDryMix = slider.value
    }

    // ディレイタイム用UISlider
    @IBAction func delaySlider(slider: UISlider){
        delay.delayTime = TimeInterval(slider.value)
    }

どちらも値が変わった時に変更を加えたいので,Value Changedでアタッチします.

スクリーンショット 2018-12-22 19.53.14.png

リポジトリ

サンプルのプロジェクトがあるリポジトリはこちら

参考にしたサイト

さいごに

今回はiPhoneをマイクにするため,入力した音声をリアルタイムで出力するアプリを作成しました.また,マイクパフォーマンスができるようにエフェクトも追加しました.

忘年会,新年会の季節ですが,人数が多いと声が後ろまで届きませんよね.
是非,幹事の人は使ってみてはいかがでしょうか.

それでは,Happy Hacking! :smile:

23
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
19