Unity with VOCALOIDを触ってみる

※この記事は「[Altplus Advent Calendar 2016](http://qiita.com/advent-calendar/2016/altplus)」の22日目の記事です。

こんにちは。

こういう記事を書くのはとても久しぶりになります。
どうせやるならと思いまして、昨年から気になっていた[Unity with VOCALOID](http://business.vocaloid.com/unitysdk/)を触ってみます。

そもそもUnity with VOCALOIDっていったい何？という話ですが、
**「VOCALOIDを用いてUnityで音声の合成ができる」**という、とても夢が広がる技術だそうで、発表があってからずっと気になってはいたものの、感覚的にはイマイチ盛り上がってないのかなーと感じています。（どうでしょう？）

でも、動的に歌声を生成することが出来るなんてすごいじゃないですか。もうちょっと盛り上がっても良いと思うんですよね。
ということで紹介してみます。

それでは早速やっていきたいと思いますが、
といっても、正直順を追って説明できるレベルのものではなかったので、[ヤマハ公式サイト](http://business.vocaloid.com/unitysdk/download/)に置いてある、「サンプルプロジェクト3種類同梱パック」の「CreateSequence demo」を元に改変して今回のネタとしました。
とりあえず軽くポイントとなる箇所だけ説明します。

エンジンの起動とモードの設定
---
まずはエンジンを起動します。staticなYVFクラスを取り回す感じです。プラットフォーム毎にnamespaceが違うので、クラスのインポートの部分がこんな感じに。。。

```
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
using Yamaha.VOCALOID.Windows;
#elif UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
using Yamaha.VOCALOID.OSX;
#elif UNITY_IOS
using Yamaha.VOCALOID.iOS;
#endif
using UnityEngine;

public class Hoge : MonoBehaviour {
    void Start () {
        YVF.YVFStartup("personal", Application.streamingAssetsPath + "/VOCALOID/DB_ini");
    }    
}
```

起動後、モードの設定をします。
大きく分けて
・Playback合成モード
・Realtime合成モード
の2つのモードがあるようです。

ざっくり言うと、Playbackの方が、事前に用意したデータで発声、Realtimeの方が、その瞬間に合成して発声するものの様です。
Playback合成モードは最初に出来た曲があって、それをいじったりするという時に使う。（VSQXファイルを再生できる模様）
Realtime合成モードは、たとえばボタンを押すなどした時にリアルタイムで音声を発声させたい時に使う。という感じでしょうか？

```
// PlayBack合成モードの場合。引数はエンジンのインスタンス数で、並列で歌声合成処理を実行する必要がない場合は1を設定する。
YVF.YVFResult result = YVF.YVFSetStaticSetting(engineCount);
```

```
// Realtime合成モードの場合。512はバッファサイズ。
YVF.YVFResult result = YVF.YVFRealtimeSetStaticSetting(YVF.YVFRealtimeMode.Mode512);
```

今回改変したサンプルはシーケンスを作って再生するというものなので、PlayBackモードになっています。

ノートの編集
---

実はこの間に色々あるのですが、ごめんなさい。省略します。
今回肝となる、ノートの編集部分です。ノートを編集し、シーケンスを作成→再生する。という流れになります。
ノートに音階や長さ、発生する単語などを設定します。

```
// ノートの編集.
List<VocaloidNote> melody = new List<VocaloidNote>();
VocaloidNote nt = new VocaloidNote();

string jsonData = "{\"noteArray\" : [{\"noteLength\" : 240,\"noteNumber\" : 76,\"lyricStr\" : \"じ\"},";
jsonData += "{\"noteLength\" : 240,\"noteNumber\" : 76,\"lyricStr\" : \"ん\"},";
jsonData += "{\"noteLength\" : 240,\"noteNumber\" : 76,\"lyricStr\" : \"ぐ\"},";
jsonData += "{\"noteLength\" : 240,\"noteNumber\" : 76,\"lyricStr\" : \"る\"},";
jsonData += "{\"noteLength\" : 720,\"noteNumber\" : 76,\"lyricStr\" : \"べ\"},";
jsonData += "{\"noteLength\" : 240,\"noteNumber\" : 76,\"lyricStr\" : \"る\"},";
jsonData += "{\"noteLength\" : 240,\"noteNumber\" : 76,\"lyricStr\" : \"じ\"},";
jsonData += "{\"noteLength\" : 240,\"noteNumber\" : 76,\"lyricStr\" : \"ん\"},";
jsonData += "{\"noteLength\" : 240,\"noteNumber\" : 76,\"lyricStr\" : \"ぐ\"},";
jsonData += "{\"noteLength\" : 240,\"noteNumber\" : 76,\"lyricStr\" : \"る\"},";
jsonData += "{\"noteLength\" : 720,\"noteNumber\" : 76,\"lyricStr\" : \"べ\"},";
jsonData += "{\"noteLength\" : 240,\"noteNumber\" : 76,\"lyricStr\" : \"る\"},";
jsonData += "{\"noteLength\" : 480,\"noteNumber\" : 76,\"lyricStr\" : \"す\"},";
jsonData += "{\"noteLength\" : 480,\"noteNumber\" : 79,\"lyricStr\" : \"ず\"},";
jsonData += "{\"noteLength\" : 720,\"noteNumber\" : 72,\"lyricStr\" : \"が\"},";
jsonData += "{\"noteLength\" : 240,\"noteNumber\" : 74,\"lyricStr\" : \"な\"},";
jsonData += "{\"noteLength\" : 720,\"noteNumber\" : 76,\"lyricStr\" : \"る\"}";
jsonData += "]}";

NoteArrayModel noteArrayData = JsonUtility.FromJson<NoteArrayModel>(jsonData);

int StartTime = preTick;
for ( int i = 0; i < noteArrayData.noteArray.Count; i++ ) {
	nt.ClearNote();
	nt.Note.noteTime = StartTime;
	nt.Note.noteLength = noteArrayData.noteArray[i].noteLength;
	nt.Note.noteNumber = noteArrayData.noteArray[i].noteNumber;
	nt.Note.lyricStr = noteArrayData.noteArray[i].lyricStr;
	StartTime += nt.Note.noteLength;
	melody.Add( new VocaloidNote(nt) );
}
```

今回、最低限で音階と長さと言葉のみ設定しています。ノートの登録は楽してjsonにしちゃいました。
こういうとき、unityの[JsonUtility](https://docs.unity3d.com/ja/current/ScriptReference/JsonUtility.html)は便利ですね。
NoteArrayModelというモデルクラスを作って、jsonデータをデシリアライズして、ぐるぐる回してます。
リファレンスにC4=72とありましたので、音階はそれに合わせて設定しました。
ド=72
レ=74
ミ=76
ファ=77
ソ=78
ラ=80
シ=81
ド=82
こんな感じかと思います。

歌声合成の実行
---

最終的に歌声を合成して実行します。
ソースコードについては説明できるだけの知見を得ることが出来なかったので割愛します。
[サンプルソースコードやセミナーの資料](http://business.vocaloid.com/unitysdk/download/)にかなり詳しく書いてありますので、そちらを参照しましょう。

できたもの
---
[windows版実行ファイル](https://bitbucket.org/norihiro_narayama/adventcalendar2016/downloads/JingleBells.exe_win.zip)
[Mac版実行ファイル](https://bitbucket.org/norihiro_narayama/adventcalendar2016/downloads/JingleBells_mac.zip)
[リポジトリはこちら](https://bitbucket.org/norihiro_narayama/adventcalendar2016/src/e05ac693690bf6e2fe43942e9368ecb7046a74f3?at=master)
*Unityのバージョンは5.5です
*VOCALOID SDKのバージョンは1.3.0.0です
*動作には別途VOCALOID SDKをダウンロードし、インポートしてください。
http://business.vocaloid.com/unitysdk/download/

所感
---
サンプルの改変とはいえ、結構簡単に音声合成が出来るのは魅力です。
今回触りませんでしたが、音色などもかなり細く設定できるようになっています。
[ゆっくりしていってね！でおなじみのSoftTalk](https://www35.atwiki.jp/softalk/pages/15.html)の上位版みたいなものはサクッと作れそうな感じでした。

そして、以下感じた問題点です。
・なにをやっているのかを読み解くコストが結構高い
・モバイルでのパフォーマンスが少し心配
・現状、利用できる音声ライブラリがユニティちゃんのみ
これらが解消されていくと、より広がっていける。かもしれないですね。


以上です。ではまたどこかで。