【cluster】25秒を超える音源を再生するクラフトアイテムの仕組み
cluster のワールドクラフトで、25秒を超える音源を再生するクラフトアイテムを作れないか試行錯誤してみました。
実際に動かしているワールド
今回紹介する仕組みで作ったクラフトアイテムは、以下のワールドに設置しています。
クラフトアイテムの制限をどうやって超えるか
短い効果音を鳴らすアイテムであれば難しくないのですが、一曲を最後まで再生して、そのままループさせようとすると、面倒なことがたくさんありました。
クラフトアイテムには、収録できる音声の長さや数、アイテムの容量、スクリプトの大きさなど、いくつもの制限があります。ひとつのアイテムに入れられる音声は、最大でも5秒のクリップが5個までなので、合計25秒です。
それより長い音源は、短いクリップに分割して、さらに複数のアイテムへ分けて持たせる必要があります。すると今度は、それらをなるべくずれないように順番に鳴らす仕組みが必要になります。アイテムを増やせばワールドクラフトの容量を圧迫しますし、アップロードの順序も計画的に行う必要があります。
ひとつひとつは地味な作業ですが、曲が長くなるほど管理するものが増えて、手作業で間違えずに作るのがだんだん難しくなります。
この記事ではまず、いま考えているクラフトアイテムの仕組みと、作るために必要になった作業をまとめてみます。
考え方:制御アイテムと再生Podの役割分担
この記事の方法では、曲全体を管理する「制御アイテム」と、音声の各区間を受け持つ複数の区間音源で構成します。以後、後者は再生Podと呼ぶことにします。例えば75秒の曲であれば、こんな感じの役割分担にします。
制御アイテム
├─ 再生Pod 1:曲の前半を担当
├─ 再生Pod 2:曲の中盤を担当
└─ 再生Pod 3:曲の後半を担当ユーザー自身がワールドに置くのは、基本的に制御アイテムひとつだけです。制御アイテムが、必要なPodを自動的に用意して再生を始めます。停止、先頭からの再再生、曲末のループも制御アイテムが管理します。
内部では複数のアイテムが動きますが、使うときは「一曲を鳴らすひとつのアイテム」として扱えるようにする想定です。
最初の準備:音源を再生可能な形式に整える
最初に調べるのは、音源の形式、長さ、チャンネル数、サンプルレートなどです。それをクラフトアイテムで扱える状態へ変換します。
音量も確認します。ピークが大きすぎる音源は調整が必要ですが、飛び出した部分だけを乱暴に削ると、元の音が変わってしまいます。そこで必要な場合だけ、曲全体へ同じ割合の調整をかけ、バランスをなるべく崩さないようにします。
音を切る位置も、単に「約5秒ごと」で済ませるわけにはいきません。小数の秒数だけで扱うと、丸め誤差で少しずつ位置がずれることがあります。実際の音声サンプル数を基準にし、上限ぎりぎりにならないよう安全幅も持たせます。
単にファイルを一定時間ごとに分割すればよい、というわけではありません。
計画:クリップと再生Podの対応を管理する
変換した音源は短いクリップに分け、いくつかずつ再生Podへ割り当てます。曲が長くなれば、クリップもPodも増えます。
分割すると、以下の情報を曲全体で矛盾しないように管理する必要があります。
このクリップは曲の何ミリ秒目から始まるのか
どのPodが担当するのか
そのPodは全体の何番目なのか
曲全体は何秒で、ループの間に何秒休むのか
各Podが同じ曲に属しているか
番号や開始位置がひとつずれただけでも、音が抜けたり、別の区間が重なったりします。手作業で作る場合は、表と設定ファイルを見比べながら、同じ値を何度も転記することになります。このあたりは、曲が長くなるほどかなり面倒です。
制御:再生時刻をPod間で共有する
再生Podは、それぞれ独立したクラフトアイテムです。
単純に考えると、前のPodが再生を終えたときに、次のPodへ開始の合図を送ればよさそうです。ただし、この方法では通信や処理のわずかな遅れが次のPodへ引き継がれます。区間が増え、ループを重ねるほど、予定時刻から少しずつずれていく可能性があります。
そこで、Pod同士で順番に合図を回すのではなく、すべてのPodに同じ再生開始時刻を知らせる方法にしています。各Podは「曲の開始から何ミリ秒後に自分の区間を再生するか」を持っていて、現在時刻と照らし合わせて再生します。
ループするときも、直前のループが実際に終わった時刻へ足し算はしません。最初の基準時刻と曲の長さから、その回の予定時刻をあらためて求めます。ひとつの境界で出た短い遅れを、次の区間や次のループまで引きずりにくくするためです。
容量節約:必要な再生Podだけを逐次生成する
長い曲ほどPodが増えます。しかし、すべてのPodを最初から最後までワールドに置いておくと、今度はワールドクラフトの容量を簡単に圧迫してしまいます。
曲を長く再生できても、そのためにワールドのほかの展示や仕掛けを置けなくなってしまうのは困りますね。
そこで、必要な区間のPodだけをオンデマンドで生成・破棄する方法を採用します。
再生中の区間と、その次に出番が来る区間を先回りして用意しておきます。役目を終えたPodは音を止めて破棄し、消えたことを確認してから、さらに次のPodを生成します。曲の先頭へループするときも、制御アイテムが同じ流れを管理します。
いま再生するPodを生成
↓
次のPodを先回りして準備
↓
担当区間を再生
↓
役目を終えたPodを停止・破棄
↓
消えたことを確認して、その次のPodを生成注意が必要なのは、破棄を指示したPodがすぐに消えるとは限らないことです。古いPodが実際に消えたことを確認せずに生成を続けると、容量を減らすための仕組みなのに、逆にPodが重複してしまう可能性があります。
この入れ替えによって、曲全体では多くのPodを使う場合でも、実行中に存在するPodを必要な範囲に絞れます。長尺音源を扱いながら、ワールドの容量をほかの表現にも残すための工夫です。
Podの生成には時間がかかることがあります。遅すぎれば次の区間に間に合いません。そのため、いつ作り始めるか、準備が済んだか、予定時刻に参加できるかまで、再生コントロールの一部として扱っています。
実験:クリップの境界を実機で検証する
全Podが同じ予定表を見ていても、音声を鳴らす命令を音源のサンプル単位の正確さで予約できるわけではありません。スクリプトの更新間隔や様々な要素が、実際の聞こえ方に関係します。
そのため、クリップの境界には短い無音や重なりが出ることがあります。
では、次のクリップを少し早く鳴らせばよいのかというと、そう単純でもありません。すでに音が重なっている境界をさらに早めれば、二重音やクリックが目立つ可能性があります。持続音、ドラムのように立ち上がりの鋭い音、歌声や会話でも結果は変わります。
そこで、調査用に周波数を設定した試験音源を作り、実際にワールドで鳴らしてOBSで録音し、どこに無音や重なりが発生するかを調べました。その結果を産駒に、隣り合う区間を少し重ね、クロスフェードで滑らかにつなげる方法などを実験しています。
波形上の数字も大事ですが、最終的には実際に聞いてどう感じるかも確認する必要があります。数値が小さくても耳につく境界はありますし、多少の重なりがあったほうが自然に聞こえる素材もあります。
なお、現時点でサンプル単位の完全なギャップレス再生を保証できるものではありません。このあたりは引き続き検証中です。
アップロード:再生Pod→制御アイテムの順番
制御アイテムは、各再生Podを呼び出すための確定済みIDを必要とします。しかし、そのIDは再生Podのアップロードが完了するまで分かりません。つまり、制御アイテムだけを先に完成させることはできません。
順番はこうなります。
音源を解析・変換する
↓
再生Podを構築・検証する
↓
再生PodをアップロードしてIDを集める
↓
全IDを組み込んだ制御アイテムを構築・検証する
↓
制御アイテムをアップロードするPodが増えれば、アップロードと完了確認、IDの記録も増えます。途中で通信が切れたときは、「送れていない」のか、「送信は終わったが結果確認に失敗した」のかも見分けなければなりません。すでに成功したPodを無駄に作り直さず、途中から再開するための記録も必要です。
手作業なら、IDをひとつずつ控え、間違えずに制御アイテムへ書き戻し、どこまで成功したかを管理することになります。ここも、曲が長くなるほど面倒になるところです。
回復制御:異常時には再生を止めてやりなおす
正常なときに音が鳴るだけではなく、何かがおかしいときにどうするかも考えておく必要があります。
必要なPodが足りなければ、再生を始めない
同じ担当のPodが重複していれば、そのまま進めない
別の曲や古い再生指示を混ぜない
Pod同士の時計が大きくずれていないか確かめる
再生中にPodが消えたら、残った区間だけを鳴らし続けない
作り直す前に、古いPodが消えたことを確認する
正しく破棄できないときは、二重再生を避けて無理に増やさない
たとえば途中のPodがなくなったとき、残りだけで再生を続ければ、曲の一部が周期的に抜けます。自動復旧しようとして古いPodと新しいPodを重ねれば、今度は二重に鳴るかもしれません。
そのため、異常を検出した場合はいったん再生を止め、安全に作り直せる状態を確認してから再開するようにします。実際にワールドへ置いて使うことを考えると、こういう処理も必要になります。
まとめ:クラフトアイテムが完成するまで
ここまでの流れを並べると、次のようになります。
音源を用意する
↓
形式・長さ・音量を調べる
↓
再生規格へ変換する
↓
クリップへ分け、Podへ割り当てる
↓
曲全体の再生予定表を作る
↓
各Pod用クラフトアイテムを構築・検証する
↓
Podを順番にアップロードする
↓
確定したIDから制御アイテムを作る
↓
制御アイテムをアップロードする
↓
実機で生成・入れ替え・同期・ループ・停止を確かめる元になるのはひとつの音楽ファイルですが、完成までには音声処理、分割計画、容量管理、同期、クラフトアイテム生成、アップロード、異常時の制御、実機での確認が必要になります。
今後:長尺音源をもっと簡単に扱えるように
実際に試してみると、長尺音源を cluster で鳴らすこと自体よりも、そのための細かな準備を毎回間違えずに繰り返すことのほうが大変でした。
音声の上限を調べ、細かく分割し、Pod番号と開始時刻を揃え、アップロード済みIDを管理する。仕組みを一度理解しても、別の曲を作るたびに同じ作業が待っています。
音源と再生方法を決めたら、あとはワールドへ設置できるクラフトアイテムができあがる、というところまで簡単にできないか、道具を作ったり、いろいろと作戦を考えたりしているところです。
まだ試している途中ですが、うまくいけば、cluster のワールドクラフトで音楽を使うハードルも少し下げられるんじゃないかと思っています。
※ 本記事には、現在も検討・検証中の仕組みが含まれます。cluster の仕様変更や実機試験の結果により、構成や対応範囲が変わる場合があります。また、音の境界について、サンプル単位の完全なギャップレス動作を保証するものではありません。
