C4でパリピな感じのiPhoneアプリを作ろう

# はじめに
## ご挨拶
こんちは！
iPhoneアプリのプログラミングやってます、いのっちです！
日々プログラミングで生活を楽しくすることだけを考えています。
そして今日もまた楽しいアプリを作ろうと思います。

## 概要
今日は[C4](http://www.c4ios.com/)という、swiftでクリエイティブコーディングできるフレームワークを使ってアプリを作っていきたいと思います。

## 作るもの
### そもそもパリピな感じなアプリとは
定義を決めましょう。僕はパリピなアプリを、

- カラフル
- 騒がしい

という2点で定義しました。ここに関しては異論は認めません。
では早速作っていきましょう。

# 環境構築
まずは環境を作りましょう。

XcodeにC4を追加します。
XcodeはmacのApp Storeで無料でダウンロードできます。
Xcodeのダウンロードに関する説明はここでは割愛させていただきます。

## C4のダウンロード
[こちら](http://www.c4ios.com/install/)からC4をインストールしましょう

![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/b720aea5-2e0e-4e31-c11b-41c67d7177f7.png)

ダウンロードの方法はいくつかあるようですが、一番難易度の低い**ジャッキーチェーン**のやり方をオススメします。
なぜC4のダウンロードでこの難易度の表現をしたのかは全くもってわかりません。
C4のインストーラがダウンロードできたら **.pkg** を展開して案内に従ってインストールします。

## C4の新規プロジェクトを作成
インストールが正常に完了したらXcodeを開きましょう。
新規プロジェクトを作成すると、こうなっているはずです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/1fe9b2db-0e44-90ee-2add-d9e9d019fd4c.png)
今回は **C4 Single View Application** を選びます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/6ce2860f-593c-2946-4a11-d7105bb928d4.png)

プロジェクト名は好きにつけてほしいんですが、"C4"というプロジェクト名はやめてください。本物のC4と名前が衝突します。
僕は"PartyC4"という名前にしました。

## 開発環境構築
さて、早速コードを書きたいんですが、いくつか問題があります。

- C4はswift4に対応していない
- Main.storyboard使わないから消したい

この2点を解決したいと思います。
### ビルドするswiftのバージョンを変更する
C4という名前のわりにswift4に対応していないのは残念です。
プロジェクトの **Build Setting** の **Swift Language Version** からswiftのバーションを変更します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/5186bd4c-576e-8686-78bf-9e0122a4069b.png)
ありました。この **Swift 4.0** を **Swift 3.2** に変更しましょう。

### Main.storyboardを消す
クリエイティブコーディングするのにMain.storyboardは不要です。
実行したいファイルを切り替えるのが大変になるだけなので、今回はMain.storyboardを消します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/5685778d-c09b-98e3-8f02-c5b503413ac9.png)

Main.storyboardをDeleteします。**Move to Trash** して完全に葬ってくださいね。

ただ消しただけだと、実行した時にプロジェクトはMain.storyboardを探して動くのがデフォルトの設定なので、この設定を変える必要があります。

またプロジェクトの設定にいきます。
**General** の **Deployment Info** の **Main Interface** を消して空欄にしましょう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/5af5dd80-289f-95df-00c1-1f91a6df41bf.png)

そして **AppDelegate.swift** を編集します。

```swift:AppDelegate.swift
// 前略
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        /* ここから追記 */
        // MARK : 最初に表示するVCを定義
        let initialViewController = WorkSpace()
        
        self.window = UIWindow(frame: UIScreen.main.bounds)
        self.window?.rootViewController = initialViewController
        self.window?.makeKeyAndVisible()
        /* ここまで追記 */
        
        return true
    }
// 後略
```
これで完了です。
**initialViewController** に実行したいクラスを入れて実行します。

たとえば、**MyCanvusController** クラスにコードを書いて実行したいときは、**initialViewController** に入れるクラスを **WorkSpace**から **MyCanvusController** に書き換えてあげます。簡単ですね。

なぜ上記のコードで**WorkSpace()**と書いたのかというと、C4のプロジェクトを作るとこの**WorkSpace**というクラスで**CanvusController**が勝手に作られるからです。

ここで試しに実行(Run)してみましょう。
白い画面が表示されたら成功です！

# コーディング
やっとコードが書けます。幸せです。
これから書くコードは僕が作りたかったパリピアプリのために必要なコードを、細分化して紹介しています。
C4の他のコードを学びたいからは[C4のリファレンス](http://www.c4ios.com/tags/)を置いておくので、必要でしたら参照してください。

## 円を表示しよう
### ひとまず円を表示しよう
新しいファイル、クラスを作りましょう。
**New File** から **iOS -> Source -> Swift File** を選択します。
この先で作るファイルも全てこの選択をします。
ファイル名は **CircleCanvusController.swift** としました。

さて、このファイルに円を表示するコードを書いていきます。

```swift:CircleCanvusController.swift
class CircleCanvusController: CanvasController {
    
    // 表示する円
    var circle: Circle!
    
    // 実行して最初に呼ばれるメソッド
    override func setup() {

        // 円の中心と半径を指定する
        circle = Circle(center: canvas.center, radius: 100)

        // canvasに追加する
        canvas.add(circle)
    }
}
```

そして **AppDelegate.swift** の **initialViewController** に入れるクラスを **WorkSpace**から **CircleCanvusController** に書き換えて、実行してみましょう。

<img width="375" alt="IMG_1994.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/123416/d0fde140-2813-e803-a25d-4c3b436fd9ce.png">

こうなれば成功です！ おめでとうございます。
でも少し味気ないですねこの円。装飾しましょう。

### 円を装飾しよう
背景を黒くして、円の色を変更しましょう。
さきほどのファイルに書き足していきます。

```swift:CircleCanvusController.swift
    // 実行して最初に呼ばれるメソッド
    override func setup() {

        // canvasの背景色を黒に変更(RGBA)
        canvas.backgroundColor = Color(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0)
        
        // 円の中心と半径を指定する
        circle = Circle(center: canvas.center, radius: 100)

        // 円の色を変更(HSBA)
        circle.fillColor = Color(hue: 0.33, saturation: 1.0, brightness: 1.0, alpha: 0.7)

        // 円の枠線を消す(枠線の太さを0にする)
        circle.lineWidth = 0.0

        // canvasに追加する
        canvas.add(circle)
    }
```

実行してみましょう！

<img width="375" alt="IMG_1995.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/123416/308b1e72-de85-02ba-075f-2c9a3df6db1d.png">

こうなれば成功です！
だんだんパリピっぽくなって、、きていません？

## 写真を表示しよう
### ひとまず写真を表示しよう
楽しげな写真を探しましょう。
僕はこちらを採用しました。
![party.jpg](https://qiita-image-store.s3.amazonaws.com/0/123416/102f8529-27a9-6a53-3717-ef1fbea4f385.jpeg)

僕はこの写真を **party.jpg** と命名してプロジェクトに追加しています。

新しく写真を表示するためのファイル、クラスを作成します。
ファイル名は **ImageCanvusController.swift**、クラス名は **ImageCanvusController**としてこのクラスにコードを書いていきます。

```swift:ImageCanvusController.swift
class ImageCanvusController: CanvasController {
    
    // 実行して最初に呼ばれるメソッド
    override func setup() {

        // 画像を表示
        let partyImage = Image("party.jpg")!

        // 写真のheightを画面の高さにする
        partyImage.height = canvas.height

        // 写真の中央位置を画面の中央にする
        partyImage.center = canvas.center

        // canvasに写真を追加
        canvas.add(partyImage)
    }
}
```

書けたら実行してみましょう。
AppDelegateの書き換えも忘れずにやりましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/123416/475d031a-1b29-8b97-4f98-158707ebf6e4.png)

最近このエラーよく出ます。
原因は2つ考えられます。

- 写真の名前とコードで指定している名前が違う
- 写真のTarget Membershipのチェックが外れている

前者はよく確認してくだいさい。後者はこう直します。

![party_jpg_と_「C4でパリピな感じのiPhoneアプリを作ろう」を編集_-_Qiita_と_ImageCanvasController_swift.png](https://qiita-image-store.s3.amazonaws.com/0/123416/e2041a8d-042c-8942-5d59-6dc92526d0d9.png)

ここにチェックを入れて再度Runしてみてください。

<img width="375" alt="IMG_1996.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/123416/d202ff66-98a9-76f9-6fb8-0aa5f0432023.png">

出ました！
でもちょっと主張が激しいですね。調整してあげましょう。

### 写真を加工しよう
さきほどのクラスに追記します。

```swift:ImageCanvusController.swift
    // 実行して最初に呼ばれるメソッド
    override func setup() {
        
        // canvasの背景色を黒に変更(RGBA)
        canvas.backgroundColor = Color(red: 0, green: 0, blue: 0, alpha: 1)
        
        // 画像を表示
        let partyImage = Image("party.jpg")!
        
        // 写真のheightを画面の高さにする
        partyImage.height = canvas.height
        
        // 写真の中央位置を画面の中央にする
        partyImage.center = canvas.center
        
        // 写真の透明度をあげる
        partyImage.opacity = 0.7
        
        // canvasに写真を追加
        canvas.add(partyImage)
    }
```

実行してみましょう
写真がさっきより黒っぽくなっていれば成功です！

## オーディオを再生しよう
さて、賑やか要素として音を追加します。

### ひとまずオーディオを再生しよう
新しくオーディオを再生するファイル、クラスを**AudioCanvasController**という名前で作成します。
オーディオは好きな楽曲をプロジェクトにインポートしてください。
僕は最近エド・シーランが好きなので、**Galway Girl.mp3** をインポートしました。

コードを書きます。

```swift:AudioCanvasController.swift
class AudioCanvasController: CanvasController {
    
    // 再生するオーディオを指定
    let audioPlayer = AudioPlayer("Galway Girl.mp3")!
    
    // 実行して最初に呼ばれるメソッド
    override func setup() {
        
        // オーディオの再生オプションの設定
        audioPlayer.loops = true
        
        // 再生
        audioPlayer.play()
        
    }
}
```

実行してみましょう。流れましたでしょうか！

### オーディオの波形からレベルを取得しよう
曲の抑揚を数値で取得したいと思います。先程のファイルに追記します。

```swift:AudioCanvasController.swift
class AudioCanvasController: CanvasController {
    
    // 再生するオーディオを指定
    let audioPlayer = AudioPlayer("Galway Girl.mp3")!
    
    // 実行して最初に呼ばれるメソッド
    override func setup() {
        
        // オーディオの再生オプションの設定
        audioPlayer.loops = true
        
        // レベルを取得する許可
        audioPlayer.meteringEnabled = true
        
        // 再生
        audioPlayer.play()
        
        // 更新頻度の定義
        let timer = Timer(interval: 1.0 / 30.0) {
            self.update()
        }
        timer.start()
    }
    
    func update() {
        audioPlayer.updateMeters()
        
        // 左と右のオーディオレベルを取得
        let powerAverageLeft = pow(10, 0.05 * audioPlayer.averagePower(0))
        let powerAverageRight = pow(10, 0.05 * audioPlayer.averagePower(1))
        
        // 平均値
        let average = (powerAverageLeft + powerAverageRight) / 2
        
        // コンソールに出力
        print(average)
    }
}
```

これでコンソールに楽曲の音源のレベルが出力されるようになりました。

## いままでのコードをまとめよう
さて、これまでやってきたことを全てまとめます。

新しく **TotalCanvasController** というファイル、クラスを作成します。

書きます。

```swift:TotalCanvasController.swift
class TotalCanvusController: CanvasController {

    // 表示する円
    var circle: Circle!
    
    // 再生するオーディオを指定
    let audioPlayer = AudioPlayer("Galway Girl.mp3")!
    
    // 円の背景色のHSBのHueの値
    var circleColorHue = 0.0
    
    // 実行して最初に呼ばれるメソッド
    override func setup() {
        // canvasの背景色を黒に変更(RGBA)
        canvas.backgroundColor = Color(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0)
        
        // 画像を表示
        let partyImage = Image("party.jpg")!
        
        // 写真のheightを画面の高さにする
        partyImage.height = canvas.height
        
        // 写真の中央位置を画面の中央にする
        partyImage.center = canvas.center
        
        // 写真の透明度をあげる
        partyImage.opacity = 0.7
        
        // canvasに写真を追加
        canvas.add(partyImage)
        
        // 円の中心と半径を指定する
        circle = Circle(center: canvas.center, radius: 100)
        
        // 円の色を変更(HSBA)
        circle.fillColor = Color(hue: circleColorHue, saturation: 1.0, brightness: 1.0, alpha: 0.7)
        
        // 円の枠線を消す(枠線の太さを0にする)
        circle.lineWidth = 0.0
        
        // canvasに追加する
        canvas.add(circle)
        
        // オーディオの再生オプションの設定
        audioPlayer.loops = true
        
        // レベルを取得する許可
        audioPlayer.meteringEnabled = true
        
        // 再生
        audioPlayer.play()
        
        // 更新頻度の定義
        let timer = Timer(interval: 1.0 / 30.0) {
            self.update()
        }
        timer.start()
    }
    
    func update() {
        
        // 円の背景色のHSBのHueの値を更新
        circleColorHue += 0.01
        if circleColorHue > 1.0 {
            circleColorHue = 0.0
        }
        circle.fillColor = Color(hue: circleColorHue, saturation: 1.0, brightness: 1.0, alpha: 1.0)
        
        ShapeLayer.disableActions = true
        audioPlayer.updateMeters()
        
        // 左と右のオーディオレベルを取得
        let powerAverageLeft = pow(10, 0.05 * audioPlayer.averagePower(0))
        let powerAverageRight = pow(10, 0.05 * audioPlayer.averagePower(1))
        
        // 表示する円の半径 = (その平均値) * (画面の幅 / 2)
        let radius = (powerAverageLeft + powerAverageRight) / 2 * canvas.frame.width * 1/2
        
        // サイズを変更
        circle.frame.size = Size(radius, radius)
        
        // 中央位置を設定
        circle.center = canvas.center
        ShapeLayer.disableActions = false
    }
}
```

実行します。完成です！
アプリは音と一緒に動くため、完成アプリのキャプチャは載せないでおきます。

# 〆
今回はC4というフレームワークを使って、アプリを作ってみました。
普段書いているswiftとは少しコードの書き方が違うが故、よりswiftを客観的にみることができた気がします。
ここから学ぶことは普段と少し違うことをやってみると普段のことをより知ることができるかもってことなのかもしれません。
いい収穫を得ました。

今回作ったアプリは解説が多い分シンプルになってしまいましたが、計算式をいじったりするだけでもっとアクティブになります。他にもマイクで外部の音声の波形から円のサイズを変化させたりする試作品も作ったりしたんですが、記事のボリューム的に別の記事で紹介させていただけたらと思います。

ここまで読んでくださってありがとうございます。
フィードバックいただけたらもっと嬉しい次第です。よろしくお願いします。どろん。