CRI ADXで音源の再生時間、再生終了時間を取得する
ADXは音声の再生中にミリ秒単位の再生時刻を取得できます。
再生時刻の取得についてはGetTimeメソッドとGetTimeSyncedWithAudioメソッドがあり、再生終了時刻はCriAtomEx.CueInfoのlengthプロパティで取得できます。
とりあえず以下のクラスを作って、適当なGameObjectにアタッチしてください。
キューシートは「TimeTest」という名前で追加済みであるものとします。
using CriWare;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class TimeTestClass : MonoBehaviour
{
private CriAtomExPlayer _player;
private CriAtomExPlayback _playback;
private CriAtomExAcb _exAcb;
private string _cueSheetName = "TimeTest";
void Start()
{
StartCoroutine(CreatePlayer());
}
public IEnumerator CreatePlayer()
{
_player = new CriAtomExPlayer(true);
_playback = player.Prepare();
_exAcb = CriAtom.GetCueSheet(_cueSheetName).acb;
// CRI Assets/CRI Addressablesを使っている場合は上記の行をコメントアウトして、
// 以下をコメントを外して使う。【Addressablesのパス】は事前に登録しておいたものにすること
//var handle = Addressables.LoadAssetAsync<CriAtomAcbAsset>("【Addressablesのパス】");
//var acbAsset = handle.WaitForCompletion();
//_exAcb = acbAsset.Handle;
// 再生準備完了待ち
while (_playback.GetStatus() != CriAtomExPlayback.Status.Playing)
{
yield return null;
}
}
}
このクラスに色々なメソッドを付けてみて確認します。
再生時間の取得
TimeTestClassに以下のメソッドを追加してください。
void Update()
{
Debug.Log("GetTime:" + GetTime());
Debug.Log("GetTimeSyncedWithAudio:" + GetTimeSyncedWithAudio());
}
public long GetTime()
{
return _criAtomExPlayback.GetTime();
}
public long GetTimeSyncedWithAudio()
{
return _criAtomExPlayback.GetTimeSyncedWithAudio();
}
これで音源の再生時間がデバッグログに毎フレーム出力されます。
基本的にはGetTimeを使用しますが、GetTimeSyncedWithAudioは処理速度を犠牲に正確な時間を取得できるので、リズムゲーム等、楽曲とゲーム内時間を同期する必要があるゲームでは後者を使用します。
用途次第で使う方を決めてください。
ちなみにGetTimeSyncedWithAudioを使わない場合は、new CriAtomExPlayer();で引数にtrueを指定せずにCriAtomExPlayerのインスタンスを作った方が処理負荷を抑えられます
CriAtomExPlayer.GetTimeとCriAtomExPlayback.GetTimeの違い
GetTimeSyncedWithAudioはCriAtomExPlaybackにしかないのですが、GetTimeはCriAtomExPlayer版とCriAtomExPlayback版があります。
結論から言うと、CriAtomExPlayback版を使いましょう。つまり上記のコードでOKです。
CriAtomExPlayerのドキュメントにはこう記されています。
同一プレーヤで複数の音声を再生し、本関数を実行した場合、本関数は "最後に"再生した音声の時刻を返します。
CRIWARE Unity Plugin Manual: CriAtomExPlayer クラス
複数の音声に対して再生時刻をチェックする必要がある場合には、 再生する音声の数分だけプレーヤを作成するか、または CriWare.CriAtomExPlayback::GetTime 関数をご利用ください。
対して、CriAtomExPlaybackのドキュメントはこちら。
CriWare.CriAtomExPlayer::GetTime 関数と異なり、本関数は再生中の音声ごとに時刻を 取得可能ですが、再生終了時刻を取ることができません。
CRIWARE Unity Plugin Manual: CriAtomExPlayback 構造体
基本的にはCriAtomExPlayback版でOKです。
「再生終了時刻を取ることができません」というのは、再生終了後に再生時間が-1になってしまうことを指しています。
再生終了時刻は後述の方法で別途取得できます。
CriAtomExPlaybackを使えないシチュエーションでのみ、CriAtomExPlayer版を使うといいでしょう。
再生終了時間の取得
TimeTestClassに以下のメソッドを追加してください。
※Updateメソッドは上書きしてください
void Update()
{
Debug.Log("GetAudioSourceLength:" + GetAudioSourceLength());
Debug.Log("GetTime:" + GetTime());
Debug.Log("GetTimeSyncedWithAudio:" + GetTimeSyncedWithAudio());
}
public long GetAudioSourceLength()
{
CriAtomEx.CueInfo cueInfo;
// CueInfoが読み込めなかった場合は暫定で-1を返す
if (!_exAcb.GetCueInfo(_cueSheetName, out cueInfo))
return -1;
return cueInfo.length;
}
単位はGetTimeやGetTimeSyncedWithAudioと同じミリ秒です。
1秒ちょうどのSEなら1000、2分ちょうどの楽曲なら60秒*2*1000=120000が返ってきます。
実はこれがこの記事を書こうと思ったきっかけで、ドキュメントを色々読んで実装にこぎつけました。
コードに起こしちゃえば簡単なんですけどね。
再生終了時間を知りたいことって結構あると思うんですが、意外と使わないんでしょうか……?
戻り値の型について
ADXから取得できる再生時刻・再生終了時刻は、戻り値の型がlongになっています。
しかし実際のところはint(32bit)の精度しかありません。
戻り値の型は long ですが、現状、32bit以上の精度はありません。
CRIWARE Unity Plugin Manual: CriAtomExPlayback 構造体
再生時刻を元に制御を行う場合、約24日で再生時刻が異常になる点に注意が必要です。
( 2147483647 ミリ秒を超えた時点で、再生時刻がオーバーフローし、負値になります。)
つまり、int型にキャストしても情報の欠損がないということです。
long型よりもint型の方が扱いやすいでしょうし、キャストして使ってしまいましょう。
いずれは64bit精度に対応するのかもしれませんが、24日以上の再生を行う用途って限られますよね。
24時間稼働しているオンラインゲームとかだと問題になることがあるのかな?
ADX自体はゲーム以外にも使えますし、24時間投影の街頭ビジョンとか?