こちら

CEDEC 2016
ワークショップ
VOCALOID SDK for Unity で
自由に歌わせられるアプリをつくってみよう
【補助資料】
©2016 VOCALOID Group, Yamaha Corporation
サンプルプロジェクト
•  仕様
– スペースキーの押下で,
開始 & unity-chan! がジャンプ
– 開始とともにボールが落下し,
unity-chan! はボールをヘディングする
– ヘディング位置が低すぎると失敗とし,
5連続失敗で,待機状態に戻る
– 時間経過とともにゲームの速度が上がる
* 本プロジェクトは「unity-chan! OFFICIAL WEBSITE」で配布されている
「SDユニティちゃん 3Dモデルデータ」をベースにしています
©2016 VOCALOID Group, Yamaha Corporation
2
サンプルプロジェクト
•  改造目標
– unity-chan! がボールをヘディングする
度に ドレミファソラシド の高さで歌う
– ヘディングの位置が低すぎると音を外す
– 歌詞を変更することができる
* 本プロジェクトは「unity-chan! OFFICIAL WEBSITE」で配布されている
「SDユニティちゃん 3Dモデルデータ」をベースにしています
©2016 VOCALOID Group, Yamaha Corporation
3
VOCALOID プラグインの基本的な使い方
• 
• 
YVF クラス (static) が API を包含
プラットフォームごとの namespace 下に,それぞれ YVF クラスがある
#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;"
using System.Collections;"
"
public class Example : MonoBehaviour {"
"
void Start () {"
// API はすべて static にアクセス."
YVF.YVFStartup("personal", Application.streamingAssetsPath + "/VOCALOID/DB_ini");"
} "
}"
* 簡素化のため,スライド上のサンプルコードはサンプルプロジェクトでの書き方と一致しない場合があります
©2016 VOCALOID Group, Yamaha Corporation
4
VOCALOID プラグインの基本的な使い方
• 
多くの API は,戻り値としてメソッドの実行結果を表す enum を返す
–  YVFResult (情報取得系以外のほぼすべての API の戻り値)
–  YVFFindResult (情報取得系 API の戻り値)
•  YVFFind~()
•  YVFNext~()
YVF.YVFResult result = YVF.YVFStartup("personal", path);"
"
// 結果に応じて必要な処理をする if (result == YVF.YVFResult.Success) {"
print("正常終了");"
"
} else if (result == YVF.YVFResult.InvalidString) {"
print("入力文字列が不正");"
// TODO"
}
©2016 VOCALOID Group, Yamaha Corporation
5
VOCALOID プラグインのライフサイクル
AppStartup
YVFStartup()
Playback合成
Real+me合成
YVFShutdown()
AppShutdown
©2016 VOCALOID Group, Yamaha Corporation
6
VOCALOID プラグインの起動,合成モード設定
// VOCALOID エンジンの起動"
public void Startup() {"
if (!initialized) {"
"
// Workshop..."
YVF.YVFResult result = YVF.YVFStartup("personal", "
Application.streamingAssetsPath + "/VOCALOID/DB_ini");"
print(result);"
if (result != YVF.YVFResult.Success) {"
return;"
}"
// ...Workshop"
"
initialized = true;"
"
// Realtime 合成モードに設定する (バッファサイズ: 512 Samples)"
// Workshop..."
YVF.YVFRealtimeSetStaticSetting(YVF.YVFRealtimeMode.Mode512);"
// ...Workshop"
"
VAudio.Create();"
}
}"
Scripts/VocAudioManager.cs
©2016 VOCALOID Group, Yamaha Corporation
7
VOCALOID プラグインの終了
// VOCALOID エンジンの停止"
public void Shutdown() {"
if (initialized) {"
VAudio.Delete();"
"
// Workshop..."
YVF.YVFShutdown();"
// ...Workshop"
"
}"
initialized = false;"
}
• 
Scripts/VocAudioManager.cs
アプリケーション終了前に,必ず VOCALOID プラグインの終了処理を行ってください
©2016 VOCALOID Group, Yamaha Corporation
8
Realtime 合成
流れ
1.  リアルタイム合成処理の開始 (イベントの待ち受け開始)
2.  歌詞設定 (事前に設定した歌詞でループする)
3.  イベントの追加
4.  イベントの確定
5.  Unity のオーディオ出力データに歌声合成データを設定,出音
6.  リアルタイム合成処理の終了
イベント
ノートオン/オフや表情パラメータ設定の変更などの情報
©2016 VOCALOID Group, Yamaha Corporation
9
Realtime 合成
Unityアプリケーション上位層
VOCALOIDプラグイン
inac+ve
オーディオ出力データ
VOCALOID
エンジン
歌声ライブラリ
©2016 VOCALOID Group, Yamaha Corporation
10
Realtime 合成
-リアルタイム合成処理の開始-
Unityアプリケーション上位層
オーディオ出力データ
VOCALOIDプラグイン
ac+ve
[リアルタイム合成処理の開始]
VOCALOID
エンジン
歌声ライブラリ
©2016 VOCALOID Group, Yamaha Corporation
11
Realtime 合成
-歌詞設定-
Unityアプリケーション上位層
オーディオ出力データ
[歌詞の設定]
VOCALOIDプラグイン
ac+ve
VOCALOID
エンジン
よろしくね
歌声ライブラリ
©2016 VOCALOID Group, Yamaha Corporation
12
Realtime 合成
-イベントの追加,確定-
Unityアプリケーション上位層
VOCALOIDプラグイン
ac+ve
オーディオ出力データ
[イベントの追加,確定]
e.g.ノートオン
VOCALOID
エンジン
よろしくね
歌声ライブラリ
©2016 VOCALOID Group, Yamaha Corporation
13
Realtime 合成
-歌声合成データの取得-
Unityアプリケーション上位層
オーディオ出力データ
歌声合成データ short[]
よー
[歌声合成データの取得]
VOCALOIDプラグイン
ac+ve
VOCALOID
エンジン
よろしくね
歌声ライブラリ
©2016 VOCALOID Group, Yamaha Corporation
14
Realtime 合成
-歌声合成データの設定,出音-
Unityアプリケーション上位層
VOCALOIDプラグイン
ac+ve
オーディオ出力データ
VOCALOID
エンジン
よろしくね
Unityのオーディオ出力用データに
歌声合成データを設定,出音
歌声ライブラリ
©2016 VOCALOID Group, Yamaha Corporation
15
Realtime 合成
-リアルタイム合成処理の終了-
Unityアプリケーション上位層
オーディオ出力データ
VOCALOIDプラグイン
inac+ve
[リアルタイム合成処理の終了]
VOCALOID
エンジン
歌声ライブラリ
©2016 VOCALOID Group, Yamaha Corporation
16
Realtime 合成
OnAudioFilterRead を利用した実装
•  OnAudioFilterRead
–  短いインターバルで呼ばれる,オーディオフィルタリングを行うメソッド
–  優れたレイテンシ
• 
オーディオフィルタリングを実行するのではなく,直接歌声合成データを
書き込む
©2016 VOCALOID Group, Yamaha Corporation
17
Realtime 合成
-リアルタイム合成処理の開始・終了-
public void Create() {"
// リアルタイム合成処理の起動 (イベント待ち受けの開始)"
// Workshop..."
YVF.YVFResult result = YVF.YVFRealtimeStart();"
if (result != YVF.YVFResult.Success) {"
return;"
}"
// ...Workshop"
"
renderData = new short[AudioSettings.GetConfiguration().dspBufferSize * 2];"
"
// OnAudioFilterRead() で値を設定できるように AudioClip を生成,AudioSource を Play"
AudioClip clip = AudioClip.Create("VOCALOID", YVF.YVFSamplingRate, 1, YVF.YVFSamplingRate, true);"
AudioSource source = gameObject.GetComponent<AudioSource>();"
source.loop = true;"
source.clip = clip;"
source.Play();"
}
"
public void Delete() {"
// リアルタイム合成処理の終了 (イベント待ち受けの停止)"
YVF.YVFRealtimeStop();"
}"
©2016 VOCALOID Group, Yamaha Corporation
Scripts/VocAudio.cs
18
Realtime 合成
-歌詞設定-
// 歌詞の設定"
public void SetLyrics(string lyrics) {"
"
// Workshop..."
"
YVF.YVFRealtimeSetLyrics(lyrics, YVF.YVFLang.Japanese);"
"
// ...Workshop"
"
}"
Scripts/VocAudio.cs
©2016 VOCALOID Group, Yamaha Corporation
19
Realtime 合成
-歌詞設定-
Unityアプリケーション上位層
オーディオ出力データ
[歌詞の設定]
VOCALOIDプラグイン
ac+ve
VOCALOID
エンジン
よろしくね
歌声ライブラリ
今ココ
©2016 VOCALOID Group, Yamaha Corporation
20
Realtime 合成
-イベントの追加,確定-
// ノートオン (発音開始) イベントを VOCALOID エンジンに通知する"
private void NoteOn(int noteNumber) {"
if (YVF.YVFRealtimeGetSynthState() == YVF.YVFRealtimeSynthState.Running) {"
// 現在発音しているノートのノートオフ (発音停止),新しいノートオン (発音開始)を追加して確定 (Commit)"
"
// Workshop..."
"
YVF.YVFRealtimeAddNoteOff();"
YVF.YVFRealtimeAddNoteOn(noteNumber);"
YVF.YVFRealtimeCommitMidi();"
"
// ...Workshop"
"
}"
if (runningCoroutine != null) {"
StopCoroutine(runningCoroutine);"
}"
runningCoroutine = StartCoroutine(dynamicsCoroutine());"
}
Scripts/BallController.cs
©2016 VOCALOID Group, Yamaha Corporation
21
Realtime 合成
-イベントの追加,確定-
Unityアプリケーション上位層
VOCALOIDプラグイン
ac+ve
オーディオ出力データ
[イベントの追加,確定]
e.g.ノートオン
VOCALOID
エンジン
よろしくね
歌声ライブラリ
今ココ
©2016 VOCALOID Group, Yamaha Corporation
22
Realtime 合成
-歌声合成データの取得,設定,出音-
void OnAudioFilterRead(float[] data, int channels) {"
if (YVF.YVFRealtimeGetSynthState() != YVF.YVFRealtimeSynthState.Running) {"
return;"
} "
// 合成済み歌声合成データサイズの取得"
int numBufferdSamples = (int)YVF.YVFRealtimeGetAudioNumData();"
if (numBufferdSamples <= 0) {"
return;"
}"
"
"
// 合成済み歌声合成データを short[] renderData に書き込む"
// Workshop..."
"
YVF.YVFRealtimePopAudio(renderData, numBufferdSamples);"
// ...Workshop"
"
// 歌声合成データをAudioClipに書き込む"
for (int i = 0; i < numBufferdSamples; ++i) {"
float value = renderData[i] / 32768.0f;
// uint16_t (-32768 ~ 32767) → float (-1.0 ~ 1.0)"
int index = i * channels;"
for (int j = index; j < index + channels; ++j) {"
data[j] = value;"
}"
}"
}
Scripts/VocAudio.cs
©2016 VOCALOID Group, Yamaha Corporation
23
Realtime 合成
-歌声合成データの取得-
Unityアプリケーション上位層
オーディオ出力データ
歌声合成データ short[]
よー
[歌声合成データの取得]
VOCALOIDプラグイン
ac+ve
VOCALOID
エンジン
よろしくね
歌声ライブラリ
今ココ から 次ページ→
©2016 VOCALOID Group, Yamaha Corporation
24
Realtime 合成
-歌声合成データの設定,出音-
Unityアプリケーション上位層
VOCALOIDプラグイン
ac+ve
オーディオ出力データ
VOCALOID
エンジン
よろしくね
Unityのオーディオ出力用データに
歌声合成データを設定,出音
歌声ライブラリ
→前ページ ココ まで
©2016 VOCALOID Group, Yamaha Corporation
25
ヘディングの位置が低すぎると音を外す
void OnTriggerEnter(Collider collision) {"
if (collision.tag == "UnityChanHead") {"
// ボールが上向きの速度をもっている場合には衝突判定を無視する"
if (GetComponent<Rigidbody>().velocity.y > 0) {"
return;"
}"
"
// ドレミファソラシド の高さで順番に歌う"
int noteNumber = middleC + majorScale[noteIndex++];"
if (noteIndex >= majorScale.Length) {"
noteIndex = 0;"
}
// 続く..
Scripts/BallController.cs
©2016 VOCALOID Group, Yamaha Corporation
26
ヘディングの位置が低すぎると音を外す
// ..続き OnTriggerEnter
"
// ヘディングしたときのボールの高さが一定値以上のときに成功とする"
if (transform.position.y > threshold) {"
mistaken = 0;"
bound();"
} else {"
++mistaken;"
"
// 失敗したら音を外す"
// Workshop..."
"
int rnd = Random.Range(1, 4);"
rnd = (Random.Range(0, 2) == 0) ? rnd : -rnd; "
noteNumber += rnd;"
"
// ...Workshop"
"
// 続く..
Scripts/BallController.cs
©2016 VOCALOID Group, Yamaha Corporation
27
ヘディングの位置が低すぎると音を外す
"
// ..続き OnTriggerEnter
"
if (mistaken <= excuse) {"
bound();"
} else {"
// 失敗が連続した場合は,ボールにx軸方向の力をかけ床に落とし終了とする"
GetComponent<Rigidbody>().AddForce(5, 0, 0, ForceMode.VelocityChange);"
}"
}"
NoteOn(noteNumber);
} else if (collision.tag == "Field") {"
// 床に落ちたら終了"
NoteOff();"
VDirector.Deactivate();"
}"
}
Scripts/BallController.cs
©2016 VOCALOID Group, Yamaha Corporation
28
©2016 VOCALOID Group, Yamaha Corporation