More Related Content Similar to 【Unite Tokyo 2018】Audio機能の基礎と実装テクニック (17) More from UnityTechnologiesJapan002 (20) 【Unite Tokyo 2018】Audio機能の基礎と実装テクニック2. 一條貴彰
代表作:Steam / N3DS 「Back in 1995」
Unite 2016「個人ゲーム開発における『収益化』の現状と未来」
通称、狂気講演
趣味: 洋楽80’s Popsのレアレコード収集 / DJ
刀剣おじさん、ユーリおじさん
ゲーム作家 / 株式会社ヘッドハイ 代表取締役
@takaaki_ichijo
23. Audio Clip プラットフォーム共通の設定
• Force To Mono
• 強制モノラル
• ステレオ素材→モノラル化
で容量半分
• Load In BackGround
• 非同期読み込みする。メインスレッドを止めない。
• ファイルサイズが大きい場合、再生が遅れることがある
• AudioClip.loadStateから「Loading, Loaded, Failed」のステートが取れる
24. Audio Clipのプラットフォーム個別の設定
• Load Type
• ゲーム実行時にサウンドデータをどのように読み込むかの設定
• Preload Audio Data
• シーン読み込み時にメモリに読み込むかどうか
• Compression FormatとQuality
• 圧縮設定
• Sampling Rate Setting
• 音素材のサンプリングレート周波数設定
25. Audio Clip: Compression Format
• Vorbis(Ogg)
• 現状はだいたいこれを選択
• Qualityで圧縮率を指定できる
• 数値が小さいと音質は劣化する
• ADPCM
• 低圧縮率(1/3.5固定)、低音質だけど再生負荷が軽い
• 銃撃音とか足音とか、ザラッとしても違和感のない音に有効
• PCM
• 無圧縮
• デコード処理がないので、本当に負荷がヤバい時に使う
他にもプラットフォーム固有のフォーマットがあり、使うと軽くなる場合がある
26. Audio Clip: Sampling Rate Setting
音のアナログ信号をデジタルに変換するときの1秒当たりのサンプル数。
「44.1kHz (44,100Hz)」は、1秒に44,100回アナログ信号を計測したということ
27. Audio Clip: Sampling Rate Setting
• Preserve Sample Rate: 変えない
• Optimize Sample Rate: 自動的に最適サンプリングレートに変更
• Override Sample Rate: サンプリングレートを指定値に変更
• 小さくするとデータ量は減るものの音質が悪くなる(モワッとした感じ)
• サンプリングレートの設定傾向
• 44,100Hz: CD音質。曲やカットシーンボイスとか
• 22,050Hz: 効果音、環境音など重要でない音
• 11,025Hz: 雑にしても気にならない効果音向け
28. Audio Clip: LoadType “Decompress On Load”
• 圧縮データを読み込み時にメモリで展開
• 多くのメモリが消費されるが、再生レスポンスが早く負荷が軽い
• メモリをメチャクチャ使うので、だいたいの場合は適さない
• これ使うより圧縮設定をADPCMにしたほうがいい
(何でこれデフォルトなの…)
デコード
CPU
29. Audio Clip: LoadType “Compressed In Memory”
• 圧縮データをそのままメモリに読み込み、再生時に展開
• 読み込み時のメモリ消費は少ない
• 再生時に展開するので、CPU負荷が発生する(特にVorbis圧縮の場合)
• CPU負荷はProfilerのAudio項目にある「DSP CPU」で確認できる
• ほとんどの音はこの設定でいい
デコード
CPU
30. Audio Clip: LoadType “Steaming”
• 圧縮データをメモリに置かず、再生時に遂次ストレージから読み
• Vorbis圧縮の場合リアルタイムデコードをしているので負荷と再生遅延がある
• ストレージに常にアクセスが走る
• CPU負荷は ProfilerのAudio項目内「Streaming CPU」から見れる
• ボイスやBGMなど、比較的長く、再生遅延が気にならない音向け
リアルタイム
デコード CPU
31. Preload Audio Data
オン: シーンの読み込み時にAudioClipをメモリに読み込む
LoadType: Streamingのときは無効になる
オフ: 最初のAudioSource.Play()が呼ばれたタイミングでAudioClipをメモリに読み込む
→ストレージからの読み出し・デコード処理で再生が遅れる
または、AudioSource.LoadAudioData() で任意のタイミングで読む
AudioSource.UnloadAudioData() で破棄する
32. Audio Clipのロード関連は3種類
•Load In Back Ground
→非同期読みするかどうかの選択
•Load Type
→メモリ上にどう読み込むのかの選択
•Decompress On Load
•Compressed In Memory
•Streaming
•Preload Audio Data
→どのタイミングでメモリに読み込むかの選択
33. Audio Clipのパラメーター設定を自動化
Asset Post Processorを使う
public void OnPostprocessAudio(AudioClip AudioClip)
{
AudioImporter audioImporter = assetImporter as AudioImporter;
string path = audioImporter.assetPath;
// MenuSeフォルダの中身は全部モノラル化//
audioImporter.forceToMono = path.Contains(“MenuSe”);
//BGMフォルダの中身は全部バックグラウンド読み込み//
audioImporter.loadInBackground = path.Contains(“BGM”);
}
※プラットフォームごとの設定はAudioImporterSampleSettingsクラス経由で設定
36. Audio Sourceインスペクター
• Play On Awake
• ゲームオブジェクトが有効になった瞬間に再生
(なんでデフォルトオンなの)
• Loop
• ループ再生する
• Priority
• 再生優先度
• Unity上で同時に再生できる音数は限られている
• 0~255の数値で指定
• 絶対に再生されてほしい音には小さい数字
37. Audio Sourceインスペクター 2
• Volume
• 音量設定
• 0~1の数値で指定
• Spatial Blend(スぺィシャルブレンド)
• スペース、つまり空間による影響量
• 3D空間内で音が鳴ったときの、位置関係か
ら音の聞こえ方をどれぐらい変化させるか
• パフォーマンスの影響なし
46. Audio Manager (Project Settings) その1
• System Sample Rate
• 出力時のサンプリングレート
• 「0」の場合、プラットフォームごとのデフォルト設定になる
• PCやハイエンド機は48,000Hz、iOS/Android は 24,000Hz。
47. Audio Manager (Project Settings) その2
• DSP Buffer Size
• 再生レイテンシーに関係する設定
• Default: デフォルト
• Best Latency: パフォーマンスの低下と引き換えにレイテンシを抑える
• Good Latency: バランス
• Best Performance: レイテンシの増加と引き換えにパフォーマンスをよくする
48. Audio Manager (Project Settings) その3
• Max Virtual Voices
• Unity内部で管理可能なサウンド再生リクエストの数
• Max Real Voices
• 実際に同時再生が可能な数
• ハードウェアによっては固定されている
• Audio Sourceで設定したプライオリティは、この範囲内で管理される
53. 前準備: AudioSourceに拡張メソッド追加
public static bool Play(this AudioSource audioSource, AudioClip audioClip = null, float volume = 1f)
{
if (audioClip == null || volume <= 0f) return false;
audioSource.clip = audioClip;
audioSource.volume = volume;
audioSource.Play();
return true;
}
audioSource.Play(audioClip, 0.5f); って書ける、楽
1行でAudio Clip渡しとnullチェックとボリューム設定と再生開始をやる関数を作る
54. コルーチンを使ったフェードインの実装例
public static IEnumerator PlayWithFadeIn(this AudioSource audioSource, AudioClip audioClip,
float fadeTime = 0.1f)
{
audioSource.Play(audioClip, 0f);
//目標ボリュームに到達するまで毎フレームボリュームを上げる//
while (audioSource.volume < 1f)
{
float tempVolume = audioSource.volume + (Time.deltaTime / fadeTime );
//目標ボリュームより計算結果が大きいか判定(急に1を超えた大ボリュームにならないようにする)//
audioSource.volume = tempVolume > 1f ? 1f : tempVolume;
yield return null;
}
}
ボリューム0で再生開始して、毎フレーム徐々にボリュームアップする
フェードアウトはこの逆で、毎フレームボリュームを下げる
60. クロスフェードの実装の例
private List<AudioSource> audioSourceBGMList = new List<AudioSource>();
~~中略~~
public static void PlayWithFade(AudioClip audioClip, float fadeTime = 0.1f)
{
//空いてるAudioSourceを探す//
AudioSource audioSourceEmpty = audioSourceBGMList.FirstOrDefault(asb => asb.isPlaying == false);
//現在再生中のBGMがあればフェードアウト処理//
AudioSource audioSourcePlaying = audioSourceBGMList.FirstOrDefault(asb => asb.isPlaying == true);
if (audioSourcePlaying != null)
{
StartCoroutine(audioSourcePlaying.StopWithFadeOut(fadeTime)); //フェードアウト//
}
StartCoroutine(audioSourceEmpty.PlayWithFadeIn(audioClip, fadeTime)); //フェードイン//
}
71. スクリプトからボリュームを設定・取得
public float GetBgmVolumeByLinear()
{
float decibel;
audioMixer.GetFloat("BGMVolume", out decibel);
return Mathf.Pow(10f, decibel / 20f);
}
public void SetBgmVolumeByLiner(float volume)
{
float decibel = 20.0f * Mathf.Log10(volume);
if (float.IsNegativeInfinity(decibel))
{
decibel = -96f;
}
audioMixer.SetFloat("BGMVolume", decibel);
}
※Audio Mixerはボリュームの単位が
デシベルである点に注意。
84. 再生コールバックのコルーチン実装
public static IEnumerator PlayWithCompCallback(this AudioSource audioSource,
AudioClip audioClip, float volume = 1f, UnityAction compCallback = null)
{
audioSource.Play(audioClip, volume);
float timer = 0f;
while (timer < audioClip.length)
{
timer += Time.deltaTime;
yield return null;
}
compCallback.?Invoke();
}
85. さては非同期だなオメー 版
public static async Task PlayWithCompCallback(this AudioSource audioSource,
AudioClip audioClip, float volume = 1f)
{
audioSource.Play(audioClip, volume);
int audioClipLengthMs = (int)TimeSpan.FromSeconds(audioClip.length).TotalMilliseconds;
await Task.Delay(audioClipLengthMs);
}
Task.Delay()を使った再生完了コールバックもできなくはない、しかしポーズできない