Audio Linkコントローラー(簡易)
AudioLinkとは
そもそもAudioLinkとはなんぞや?という話ですが、音に合わせて自動でいろいろ動かせる!という仕組みです。
例えばこんなことができます!
・ワールド内の音楽に反応してオブジェクトが出たり消えたりする
・サブ音声の音楽に反応してライトの光が点滅する
などです!
これはあくまでも例ですが、出たり消えたり、光ったりという他にも形が変わる、色が変わるといったこともできそうです!
導入方法や使い方に関しては公式よりガイドが公開されています。
この記事に書いてある通りに実行すればとりあえず動かせます。
サンプルも豊富なのでいろいろ遊べます。Boothなどにもすでに自作のAudioLink対応シェーダーを公開してる方もいます。
コントローラーを作ろう
ひととおり遊んでみた方はわかるかもしれませんが、出力する音によって反応が良かったり悪かったりしませんか?
そういう場合はUnityの設定を変更してアップロードすれば反応のしやすさなどを変更できます。

しかし、設定を変更するたびに毎回アップロードするのは不便ですね!
そこで公式ガイドでは「パラーメータ変更用スクリプト」というのも同時に公開しています。
これだと、アップロードしなくてもワールド内で設定変更が可能です。
が、この方法だと決められた数値にしか変更できません。
それならば、ワールド内で好きなように数値を変更できるコントローラーがあれば便利なのでは!?というわけでコントローラーを作りましょう!
ちなみに、AudioLinkコントローラーはパッケージにも同梱されていますが他のプラットフォーム用なのでclusterでは動きません。

シーン内に出せますが機能しません
コントローラーの特徴
スイッチを押すと数値入力画面が出てきます。
数値を入力すると設定が変更されます。
スイッチの色やデザインは自由に変更可能です。
記事内のコードをコピーするだけなのでスクリプトがわからなくても作れます。

注意事項
スクリプトはAIによって生成しています。
筆者はスクリプトについてはさっぱりわかりません💦
なので、内容についての解説はできません💦
ご意見、ご質問も受けられません💦
エラー修復のコードが含まれているようです👍
コントローラーの構造
コントローラーの構造はおおまかにこのようになっています。
スイッチに数値が入力されると、AudioLink本体とHolderに数値が出力されます。
AudioLinkでは設定が変更され、音への反応が変わります。
Holderは数値を一時保存しておくところです。ここに入った数値はテキストとして目に見える数字が表示されます。

Unityでの全体図はこのようになります。
Gainなどのワールド内の表示をしてますが無くてもわかる人はつけなくてもOKです。

(AudioLinkはコントローラーに組み込まない)
作成例では7項目の設定ですが、ワールドの設計によっては必要な項目だけでもOKです。

AudioLink本体の設定
AudioLink本体はコントローラーとは別の階層でもOKです。
AudioLink本体に「Scriptable Item」を追加します。
以下のスクリプトをコピペします。
///<reference types="@clustervr/cluster-script-types"/>
/* ─────────────────────────────────────────────
AudioLinkHub.js 2025-06 改訂
・受信メッセージ "SetAudioLinkParams"(args は連想オブジェクト)
・該当する setter だけ呼び出し → 最後に applySettings()
・タイポ修正済み(Threshold1/2/3)
───────────────────────────────────────────── */
const DEBUG = false;
const al = $.audioLink();
if (!al) {
$.log("AudioLinkHub: AudioLink コンポーネントが見つかりません");
}
/* 受信設定
{ player:true, item:true } =
他アイテム・他プレイヤーからの送信を両方受け取る */
$.onReceive((messageType, args, sender) => {
if (messageType !== "SetAudioLinkParams") return;
if (!al) return;
if (DEBUG) $.log("AudioLinkHub: args=" + JSON.stringify(args));
if (args.gain != null) al.setGain(args.gain);
if (args.bass != null) al.setBass(args.bass);
if (args.treble != null) al.setTreble(args.treble);
if (args.x0 != null) al.setCrossover0(args.x0);
if (args.x1 != null) al.setCrossover1(args.x1);
if (args.x2 != null) al.setCrossover2(args.x2);
if (args.x3 != null) al.setCrossover3(args.x3);
if (args.threshold0 != null) al.setThreshold0(args.threshold0);
if (args.threshold1 != null) al.setThreshold1(args.threshold1); // ← 修正
if (args.threshold2 != null) al.setThreshold2(args.threshold2); // ← 修正
if (args.threshold3 != null) al.setThreshold3(args.threshold3); // ← 修正
if (args.fadeLength != null) al.setFadeLength(args.fadeLength);
if (args.fadeExpFalloff != null) al.setFadeExpFalloff(args.fadeExpFalloff);
if (args.autogainDerate != null) {
al.setEnableAutogain(true);
al.setAutogainDerate(args.autogainDerate);
}
al.applySettings();
}, { player: true, item: true });スイッチの構造
スイッチの構造は基本的にこのようになります。
▽項目名(GainやBassなどのパラーメーター名)
ValueHolder(数値を保管するところ。)
▽Canvas
Text(数値を表示するところ)
Input(スイッチ本体。コライダー必要。)
項目名は設定するパラーメーター名です。その中のValue HolderやInputにも他の項目と混同しないように名前をつけるとわかりやすいです。
なお、KeyやIDは書いてある通り入力しないとギミックが動きません。
Gain
全体的な反応のしやすさのパラメーターです。
調整範囲は0.0~2.0、初期値は1.0です。

GainValueHolder
空のゲームオブジェクトを作成します。
「Scriptable Item」を追加します。
以下のコードをコピペします。
///<reference types="@clustervr/cluster-script-types"/>
const MIN = 0.0;
const MAX = 2.0;
let value = 1.0;
function save(v) {
value = +(Math.min(MAX, Math.max(MIN, v)).toFixed(2));
$.setStateCompat("this", "gain", value);
}
$.onStart(() => save(value));
$.onReceive((msg, arg) => {
if (msg === "SetValue") {
const v = parseFloat(arg);
if (!isNaN(v)) save(v);
else $.send("DisplayError", "無効な数値(例: 1.5)");
} else if (msg === "Reset") {
save(1.0);
}
});Canvas(Text)
Textを作成するとCanvasができるのでそのまま使います。作成方法はこちら。
Textに「Set Text Gimmick」を追加します。
以下のように設定します。


GainInput
CubeやQuadなどの見た目とコライダーがあるオブジェクトを作成します。
「Scriptable Item」を追加します。
以下のコードをコピペします。
///<reference types="@clustervr/cluster-script-types"/>
let holder = null;
let audioLinkHub = null;
let lastFetchAttempt = 0;
const FETCH_INTERVAL = 10000;
const MAX_ATTEMPTS = 3;
function fetchHandles() {
const now = Date.now();
if (now - lastFetchAttempt < 1000) return;
lastFetchAttempt = now;
if (!holder || !holder.exists()) holder = $.worldItemReference("Gainholder");
if (!audioLinkHub || !audioLinkHub.exists()) audioLinkHub = $.worldItemReference("audioLink");
}
$.onStart(() => {
fetchHandles();
$.setInterval(() => {
if (!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) fetchHandles();
}, FETCH_INTERVAL);
});
$.onInteract(player => {
if (!holder || !audioLinkHub) fetchHandles();
player.requestTextInput("gainInput", "Gainを入力(0.0〜2.0)");
});
$.onTextInput((text, meta) => {
if (meta !== "gainInput") return;
const v = parseFloat(text);
if (isNaN(v)) {
$.send("DisplayError", "無効な数値(例: 1.5)");
return;
}
let attempts = 0;
while ((!holder || !holder.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (holder && holder.exists()) {
holder.send("SetValue", v.toString());
} else {
$.send("DisplayError", "エラー: Gain設定失敗。ワールドを再読み込み");
}
attempts = 0;
while ((!audioLinkHub || !audioLinkHub.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (audioLinkHub && audioLinkHub.exists()) {
audioLinkHub.send("SetAudioLinkParams", { gain: v });
} else {
$.send("DisplayError", "エラー: AudioLink設定失敗。ワールドを再読み込み");
}
});「World Item Reference List」を追加します。
以下のように設定します。

Bass
低音の反応のしやすさです。
調整範囲は0.0~2.0、初期値は1.0です。
これ以降は基本的にGainと同じなので、変更箇所だけを記載します。

BassValueHolder
///<reference types="@clustervr/cluster-script-types"/>
const MIN = 0.0;
const MAX = 2.0;
let value = 1.0;
function save(v) {
value = +(Math.min(MAX, Math.max(MIN, v)).toFixed(2));
$.setStateCompat("this", "bass", value);
}
$.onStart(() => save(value));
$.onReceive((msg, arg) => {
if (msg === "SetValue") {
const v = parseFloat(arg);
if (!isNaN(v)) save(v);
else $.send("DisplayError", "無効な数値(例: 1.5)");
} else if (msg === "Reset") {
save(1.0);
}
});Canvas(Text)

BassInput
///<reference types="@clustervr/cluster-script-types"/>
let holder = null;
let audioLinkHub = null;
let lastFetchAttempt = 0;
const FETCH_INTERVAL = 10000;
const MAX_ATTEMPTS = 3;
function fetchHandles() {
const now = Date.now();
if (now - lastFetchAttempt < 1000) return;
lastFetchAttempt = now;
if (!holder || !holder.exists()) holder = $.worldItemReference("Bassholder");
if (!audioLinkHub || !audioLinkHub.exists()) audioLinkHub = $.worldItemReference("audioLink");
}
$.onStart(() => {
fetchHandles();
$.setInterval(() => {
if (!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) fetchHandles();
}, FETCH_INTERVAL);
});
$.onInteract(player => {
if (!holder || !audioLinkHub) fetchHandles();
player.requestTextInput("bassInput", "Bassを入力(0.0〜2.0)");
});
$.onTextInput((text, meta) => {
if (meta !== "bassInput") return;
const v = parseFloat(text);
if (isNaN(v)) {
$.send("DisplayError", "無効な数値(例: 1.5)");
return;
}
let attempts = 0;
while ((!holder || !holder.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (holder && holder.exists()) {
holder.send("SetValue", v.toString());
} else {
$.send("DisplayError", "エラー: Bass設定失敗。ワールドを再読み込み");
}
attempts = 0;
while ((!audioLinkHub || !audioLinkHub.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (audioLinkHub && audioLinkHub.exists()) {
audioLinkHub.send("SetAudioLinkParams", { bass: v });
} else {
$.send("DisplayError", "エラー: AudioLink設定失敗。ワールドを再読み込み");
}
});
Treble
高音の反応のしやすさです。
調整範囲は0.0~2.0、初期値は1.0です。

TrebleValueHolder
///<reference types="@clustervr/cluster-script-types"/>
const MIN = 0.0;
const MAX = 2.0;
let value = 1.0;
function save(v) {
value = +(Math.min(MAX, Math.max(MIN, v)).toFixed(2));
$.setStateCompat("this", "treble", value);
}
$.onStart(() => save(value));
$.onReceive((msg, arg) => {
if (msg === "SetValue") {
const v = parseFloat(arg);
if (!isNaN(v)) save(v);
else $.send("DisplayError", "無効な数値(例: 1.5)");
} else if (msg === "Reset") {
save(1.0);
}
});Canvas(Text)

TrebleInput
///<reference types="@clustervr/cluster-script-types"/>
let holder = null;
let audioLinkHub = null;
let lastFetchAttempt = 0;
const FETCH_INTERVAL = 10000;
const MAX_ATTEMPTS = 3;
function fetchHandles() {
const now = Date.now();
if (now - lastFetchAttempt < 1000) return;
lastFetchAttempt = now;
if (!holder || !holder.exists()) holder = $.worldItemReference("Trebholder");
if (!audioLinkHub || !audioLinkHub.exists()) audioLinkHub = $.worldItemReference("audioLink");
}
$.onStart(() => {
fetchHandles();
$.setInterval(() => {
if (!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) fetchHandles();
}, FETCH_INTERVAL);
});
$.onInteract(player => {
if (!holder || !audioLinkHub) fetchHandles();
player.requestTextInput("trebleInput", "Trebleを入力(0.0〜2.0)");
});
$.onTextInput((text, meta) => {
if (meta !== "trebleInput") return;
const v = parseFloat(text);
if (isNaN(v)) {
$.send("DisplayError", "無効な数値(例: 1.5)");
return;
}
let attempts = 0;
while ((!holder || !holder.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (holder && holder.exists()) {
holder.send("SetValue", v.toString());
} else {
$.send("DisplayError", "エラー: Treble設定失敗。ワールドを再読み込み");
}
attempts = 0;
while ((!audioLinkHub || !audioLinkHub.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (audioLinkHub && audioLinkHub.exists()) {
audioLinkHub.send("SetAudioLinkParams", { treble: v });
} else {
$.send("DisplayError", "エラー: AudioLink設定失敗。ワールドを再読み込み");
}
});
Low
ここからの4項目はしきい値(Threshold)です。しきい値とは「この数値以上になったら反応する」という値です。
Lowは低音域のしきい値です。
パタメーター名はThreshold0です。
調整範囲は0.00~1.00、初期値は0.45です。小数点以下が1桁増えます。

T0ValueHolder
///<reference types="@clustervr/cluster-script-types"/>
const MIN = 0.0;
const MAX = 1.0;
let value = 0.45;
function save(v) {
value = +(Math.min(MAX, Math.max(MIN, v)).toFixed(2));
$.setStateCompat("this", "threshold0", value);
}
$.onStart(() => save(value));
$.onReceive((msg, arg) => {
if (msg === "SetValue") {
const v = parseFloat(arg);
if (!isNaN(v)) save(v);
else $.send("DisplayError", "無効な数値(例: 0.5)");
} else if (msg === "Reset") {
save(0.45);
}
});Canvas(Text)

T0Input
///<reference types="@clustervr/cluster-script-types"/>
let holder = null;
let audioLinkHub = null;
let lastFetchAttempt = 0;
const FETCH_INTERVAL = 10000;
const MAX_ATTEMPTS = 3;
function fetchHandles() {
const now = Date.now();
if (now - lastFetchAttempt < 1000) return;
lastFetchAttempt = now;
if (!holder || !holder.exists()) holder = $.worldItemReference("T0holder");
if (!audioLinkHub || !audioLinkHub.exists()) audioLinkHub = $.worldItemReference("audioLink");
}
$.onStart(() => {
fetchHandles();
$.setInterval(() => {
if (!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) fetchHandles();
}, FETCH_INTERVAL);
});
$.onInteract(player => {
if (!holder || !audioLinkHub) fetchHandles();
player.requestTextInput("threshold0Input", "Threshold0を入力(0.0〜1.0)");
});
$.onTextInput((text, meta) => {
if (meta !== "threshold0Input") return;
const v = parseFloat(text);
if (isNaN(v)) {
$.send("DisplayError", "無効な数値(例: 0.5)");
return;
}
let attempts = 0;
while ((!holder || !holder.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (holder && holder.exists()) {
holder.send("SetValue", v.toString());
} else {
$.send("DisplayError", "エラー: Threshold0設定失敗。ワールドを再読み込み");
}
attempts = 0;
while ((!audioLinkHub || !audioLinkHub.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (audioLinkHub && audioLinkHub.exists()) {
audioLinkHub.send("SetAudioLinkParams", { threshold0: v });
} else {
$.send("DisplayError", "エラー: AudioLink設定失敗。ワールドを再読み込み");
}
});
Low Mid
中低音域のしきい値です。
パタメーター名はThreshold1です。
調整範囲は0.00~1.00、初期値は0.45です。

T1ValueHolder
///<reference types="@clustervr/cluster-script-types"/>
const MIN = 0.0;
const MAX = 1.0;
let value = 0.45;
function save(v) {
value = +(Math.min(MAX, Math.max(MIN, v)).toFixed(2));
$.setStateCompat("this", "threshold1", value);
}
$.onStart(() => save(value));
$.onReceive((msg, arg) => {
if (msg === "SetValue") {
const v = parseFloat(arg);
if (!isNaN(v)) save(v);
else $.send("DisplayError", "無効な数値(例: 0.5)");
} else if (msg === "Reset") {
save(0.45);
}
});Canvas(Text)

T1Input
///<reference types="@clustervr/cluster-script-types"/>
let holder = null;
let audioLinkHub = null;
let lastFetchAttempt = 0;
const FETCH_INTERVAL = 10000;
const MAX_ATTEMPTS = 3;
function fetchHandles() {
const now = Date.now();
if (now - lastFetchAttempt < 1000) return;
lastFetchAttempt = now;
if (!holder || !holder.exists()) holder = $.worldItemReference("T1holder");
if (!audioLinkHub || !audioLinkHub.exists()) audioLinkHub = $.worldItemReference("audioLink");
}
$.onStart(() => {
fetchHandles();
$.setInterval(() => {
if (!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) fetchHandles();
}, FETCH_INTERVAL);
});
$.onInteract(player => {
if (!holder || !audioLinkHub) fetchHandles();
player.requestTextInput("threshold1Input", "Threshold1を入力(0.0〜1.0)");
});
$.onTextInput((text, meta) => {
if (meta !== "threshold1Input") return;
const v = parseFloat(text);
if (isNaN(v)) {
$.send("DisplayError", "無効な数値(例: 0.5)");
return;
}
let attempts = 0;
while ((!holder || !holder.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (holder && holder.exists()) {
holder.send("SetValue", v.toString());
} else {
$.send("DisplayError", "エラー: Threshold1設定失敗。ワールドを再読み込み");
}
attempts = 0;
while ((!audioLinkHub || !audioLinkHub.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (audioLinkHub && audioLinkHub.exists()) {
audioLinkHub.send("SetAudioLinkParams", { threshold1: v });
} else {
$.send("DisplayError", "エラー: AudioLink設定失敗。ワールドを再読み込み");
}
});
High Mid
中高音域のしきい値です。
パタメーター名はThreshold2です。
調整範囲は0.00~1.00、初期値は0.45です。

T2ValueHolder
///<reference types="@clustervr/cluster-script-types"/>
const MIN = 0.0;
const MAX = 1.0;
let value = 0.45;
function save(v) {
value = +(Math.min(MAX, Math.max(MIN, v)).toFixed(2));
$.setStateCompat("this", "threshold2", value);
}
$.onStart(() => save(value));
$.onReceive((msg, arg) => {
if (msg === "SetValue") {
const v = parseFloat(arg);
if (!isNaN(v)) save(v);
else $.send("DisplayError", "無効な数値(例: 0.5)");
} else if (msg === "Reset") {
save(0.45);
}
});Canvas(Text)

T2Input
///<reference types="@clustervr/cluster-script-types"/>
let holder = null;
let audioLinkHub = null;
let lastFetchAttempt = 0;
const FETCH_INTERVAL = 10000;
const MAX_ATTEMPTS = 3;
function fetchHandles() {
const now = Date.now();
if (now - lastFetchAttempt < 1000) return;
lastFetchAttempt = now;
if (!holder || !holder.exists()) holder = $.worldItemReference("T2holder");
if (!audioLinkHub || !audioLinkHub.exists()) audioLinkHub = $.worldItemReference("audioLink");
}
$.onStart(() => {
fetchHandles();
$.setInterval(() => {
if (!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) fetchHandles();
}, FETCH_INTERVAL);
});
$.onInteract(player => {
if (!holder || !audioLinkHub) fetchHandles();
player.requestTextInput("threshold2Input", "Threshold2を入力(0.0〜1.0)");
});
$.onTextInput((text, meta) => {
if (meta !== "threshold2Input") return;
const v = parseFloat(text);
if (isNaN(v)) {
$.send("DisplayError", "無効な数値(例: 0.5)");
return;
}
let attempts = 0;
while ((!holder || !holder.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (holder && holder.exists()) {
holder.send("SetValue", v.toString());
} else {
$.send("DisplayError", "エラー: Threshold2設定失敗。ワールドを再読み込み");
}
attempts = 0;
while ((!audioLinkHub || !audioLinkHub.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (audioLinkHub && audioLinkHub.exists()) {
audioLinkHub.send("SetAudioLinkParams", { threshold2: v });
} else {
$.send("DisplayError", "エラー: AudioLink設定失敗。ワールドを再読み込み");
}
});
High
高音域のしきい値です。
パタメーター名はThreshold3です。
調整範囲は0.00~1.00、初期値は0.45です。

T3ValueHolder
///<reference types="@clustervr/cluster-script-types"/>
const MIN = 0.0;
const MAX = 1.0;
let value = 0.45;
function save(v) {
value = +(Math.min(MAX, Math.max(MIN, v)).toFixed(2));
$.setStateCompat("this", "threshold3", value);
}
$.onStart(() => save(value));
$.onReceive((msg, arg) => {
if (msg === "SetValue") {
const v = parseFloat(arg);
if (!isNaN(v)) save(v);
else $.send("DisplayError", "無効な数値(例: 0.5)");
} else if (msg === "Reset") {
save(0.45);
}
});Canvas(Text)

T3Input
///<reference types="@clustervr/cluster-script-types"/>
let holder = null;
let audioLinkHub = null;
let lastFetchAttempt = 0;
const FETCH_INTERVAL = 10000;
const MAX_ATTEMPTS = 3;
function fetchHandles() {
const now = Date.now();
if (now - lastFetchAttempt < 1000) return;
lastFetchAttempt = now;
if (!holder || !holder.exists()) holder = $.worldItemReference("T3holder");
if (!audioLinkHub || !audioLinkHub.exists()) audioLinkHub = $.worldItemReference("audioLink");
}
$.onStart(() => {
fetchHandles();
$.setInterval(() => {
if (!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) fetchHandles();
}, FETCH_INTERVAL);
});
$.onInteract(player => {
if (!holder || !audioLinkHub) fetchHandles();
player.requestTextInput("threshold3Input", "Threshold3を入力(0.0〜1.0)");
});
$.onTextInput((text, meta) => {
if (meta !== "threshold3Input") return;
const v = parseFloat(text);
if (isNaN(v)) {
$.send("DisplayError", "無効な数値(例: 0.5)");
return;
}
let attempts = 0;
while ((!holder || !holder.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (holder && holder.exists()) {
holder.send("SetValue", v.toString());
} else {
$.send("DisplayError", "エラー: Threshold3設定失敗。ワールドを再読み込み");
}
attempts = 0;
while ((!audioLinkHub || !audioLinkHub.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (audioLinkHub && audioLinkHub.exists()) {
audioLinkHub.send("SetAudioLinkParams", { threshold3: v });
} else {
$.send("DisplayError", "エラー: AudioLink設定失敗。ワールドを再読み込み");
}
});
さらに機能追加
ここまで作ったものでも十分機能はしますが、もうひとつ機能を追加してもいいでしょう。それはResetです!押すと最初の値にする、というものです。
作り方はInputボタンをコピーして、スクリプトを書き換えるだけです。
Gain(規定値1.0)
///<reference types="@clustervr/cluster-script-types"/>
const RESET_VALUE = 1.0;
const FETCH_INTERVAL = 10000;
const MAX_ATTEMPTS = 3;
let holder = null;
let audioLinkHub = null;
let lastFetchAttempt = 0;
function fetchHandles() {
const now = Date.now();
if (now - lastFetchAttempt < 1000) return;
lastFetchAttempt = now;
if (!holder || !holder.exists()) holder = $.worldItemReference("Gainholder");
if (!audioLinkHub || !audioLinkHub.exists()) audioLinkHub = $.worldItemReference("audioLink");
}
$.onStart(() => {
fetchHandles();
$.setInterval(() => {
if (!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) fetchHandles();
}, FETCH_INTERVAL);
});
$.onInteract(() => {
let attempts = 0;
while ((!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (holder && holder.exists()) {
holder.send("Reset", null);
} else {
$.send("DisplayError", "エラー: リセット失敗。ワールドを再読み込み");
}
if (audioLinkHub && audioLinkHub.exists()) {
audioLinkHub.send("SetAudioLinkParams", { gain: RESET_VALUE });
} else {
$.send("DisplayError", "エラー: AudioLinkリセット失敗。ワールドを再読み込み");
}
});Bass(規定値1.0)
///<reference types="@clustervr/cluster-script-types"/>
const RESET_VALUE = 1.0;
const FETCH_INTERVAL = 10000;
const MAX_ATTEMPTS = 3;
let holder = null;
let audioLinkHub = null;
let lastFetchAttempt = 0;
function fetchHandles() {
const now = Date.now();
if (now - lastFetchAttempt < 1000) return;
lastFetchAttempt = now;
if (!holder || !holder.exists()) holder = $.worldItemReference("Bassholder");
if (!audioLinkHub || !audioLinkHub.exists()) audioLinkHub = $.worldItemReference("audioLink");
}
$.onStart(() => {
fetchHandles();
$.setInterval(() => {
if (!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) fetchHandles();
}, FETCH_INTERVAL);
});
$.onInteract(() => {
let attempts = 0;
while ((!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (holder && holder.exists()) {
holder.send("Reset", null);
} else {
$.send("DisplayError", "エラー: リセット失敗。ワールドを再読み込み");
}
if (audioLinkHub && audioLinkHub.exists()) {
audioLinkHub.send("SetAudioLinkParams", { bass: RESET_VALUE });
} else {
$.send("DisplayError", "エラー: AudioLinkリセット失敗。ワールドを再読み込み");
}
});Treble(規定値1.0)
///<reference types="@clustervr/cluster-script-types"/>
const RESET_VALUE = 1.0;
const FETCH_INTERVAL = 10000;
const MAX_ATTEMPTS = 3;
let holder = null;
let audioLinkHub = null;
let lastFetchAttempt = 0;
function fetchHandles() {
const now = Date.now();
if (now - lastFetchAttempt < 1000) return;
lastFetchAttempt = now;
if (!holder || !holder.exists()) holder = $.worldItemReference("Trebholder");
if (!audioLinkHub || !audioLinkHub.exists()) audioLinkHub = $.worldItemReference("audioLink");
}
$.onStart(() => {
fetchHandles();
$.setInterval(() => {
if (!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) fetchHandles();
}, FETCH_INTERVAL);
});
$.onInteract(() => {
let attempts = 0;
while ((!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (holder && holder.exists()) {
holder.send("Reset", null);
} else {
$.send("DisplayError", "エラー: リセット失敗。ワールドを再読み込み");
}
if (audioLinkHub && audioLinkHub.exists()) {
audioLinkHub.send("SetAudioLinkParams", { treble: RESET_VALUE });
} else {
$.send("DisplayError", "エラー: AudioLinkリセット失敗。ワールドを再読み込み");
}
});Low(規定値0.45)
///<reference types="@clustervr/cluster-script-types"/>
const RESET_VALUE = 0.45;
const FETCH_INTERVAL = 10000;
const MAX_ATTEMPTS = 3;
let holder = null;
let audioLinkHub = null;
let lastFetchAttempt = 0;
function fetchHandles() {
const now = Date.now();
if (now - lastFetchAttempt < 1000) return;
lastFetchAttempt = now;
if (!holder || !holder.exists()) holder = $.worldItemReference("T0holder");
if (!audioLinkHub || !audioLinkHub.exists()) audioLinkHub = $.worldItemReference("audioLink");
}
$.onStart(() => {
fetchHandles();
$.setInterval(() => {
if (!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) fetchHandles();
}, FETCH_INTERVAL);
});
$.onInteract(() => {
let attempts = 0;
while ((!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (holder && holder.exists()) {
holder.send("Reset", null);
} else {
$.send("DisplayError", "エラー: リセット失敗。ワールドを再読み込み");
}
if (audioLinkHub && audioLinkHub.exists()) {
audioLinkHub.send("SetAudioLinkParams", { threshold0: RESET_VALUE });
} else {
$.send("DisplayError", "エラー: AudioLinkリセット失敗。ワールドを再読み込み");
}
});Low Mid(規定値0.45)
///<reference types="@clustervr/cluster-script-types"/>
const RESET_VALUE = 0.45;
const FETCH_INTERVAL = 10000;
const MAX_ATTEMPTS = 3;
let holder = null;
let audioLinkHub = null;
let lastFetchAttempt = 0;
function fetchHandles() {
const now = Date.now();
if (now - lastFetchAttempt < 1000) return;
lastFetchAttempt = now;
if (!holder || !holder.exists()) holder = $.worldItemReference("T1holder");
if (!audioLinkHub || !audioLinkHub.exists()) audioLinkHub = $.worldItemReference("audioLink");
}
$.onStart(() => {
fetchHandles();
$.setInterval(() => {
if (!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) fetchHandles();
}, FETCH_INTERVAL);
});
$.onInteract(() => {
let attempts = 0;
while ((!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (holder && holder.exists()) {
holder.send("Reset", null);
} else {
$.send("DisplayError", "エラー: リセット失敗。ワールドを再読み込み");
}
if (audioLinkHub && audioLinkHub.exists()) {
audioLinkHub.send("SetAudioLinkParams", { threshold1: RESET_VALUE });
} else {
$.send("DisplayError", "エラー: AudioLinkリセット失敗。ワールドを再読み込み");
}
});High Mid(規定値0.45)
///<reference types="@clustervr/cluster-script-types"/>
const RESET_VALUE = 0.45;
const FETCH_INTERVAL = 10000;
const MAX_ATTEMPTS = 3;
let holder = null;
let audioLinkHub = null;
let lastFetchAttempt = 0;
function fetchHandles() {
const now = Date.now();
if (now - lastFetchAttempt < 1000) return;
lastFetchAttempt = now;
if (!holder || !holder.exists()) holder = $.worldItemReference("T2holder");
if (!audioLinkHub || !audioLinkHub.exists()) audioLinkHub = $.worldItemReference("audioLink");
}
$.onStart(() => {
fetchHandles();
$.setInterval(() => {
if (!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) fetchHandles();
}, FETCH_INTERVAL);
});
$.onInteract(() => {
let attempts = 0;
while ((!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (holder && holder.exists()) {
holder.send("Reset", null);
} else {
$.send("DisplayError", "エラー: リセット失敗。ワールドを再読み込み");
}
if (audioLinkHub && audioLinkHub.exists()) {
audioLinkHub.send("SetAudioLinkParams", { threshold2: RESET_VALUE });
} else {
$.send("DisplayError", "エラー: AudioLinkリセット失敗。ワールドを再読み込み");
}
});High(規定値0.45)
///<reference types="@clustervr/cluster-script-types"/>
const RESET_VALUE = 0.45;
const FETCH_INTERVAL = 10000;
const MAX_ATTEMPTS = 3;
let holder = null;
let audioLinkHub = null;
let lastFetchAttempt = 0;
function fetchHandles() {
const now = Date.now();
if (now - lastFetchAttempt < 1000) return;
lastFetchAttempt = now;
if (!holder || !holder.exists()) holder = $.worldItemReference("T3holder");
if (!audioLinkHub || !audioLinkHub.exists()) audioLinkHub = $.worldItemReference("audioLink");
}
$.onStart(() => {
fetchHandles();
$.setInterval(() => {
if (!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) fetchHandles();
}, FETCH_INTERVAL);
});
$.onInteract(() => {
let attempts = 0;
while ((!holder || !holder.exists() || !audioLinkHub || !audioLinkHub.exists()) && attempts < MAX_ATTEMPTS) {
fetchHandles();
attempts++;
}
if (holder && holder.exists()) {
holder.send("Reset", null);
} else {
$.send("DisplayError", "エラー: リセット失敗。ワールドを再読み込み");
}
if (audioLinkHub && audioLinkHub.exists()) {
audioLinkHub.send("SetAudioLinkParams", { threshold3: RESET_VALUE });
} else {
$.send("DisplayError", "エラー: AudioLinkリセット失敗。ワールドを再読み込み");
}
});AudioLinkコントローラーがあるとワールドを更新しなくても、音を出しながらその場で調整できちゃいます!
コントローラーの形や色も好きなように作りましょう!
ばっちりな調整でAudioLinkを楽しみましょう!
ちなみに技術や知識次第ではもっといいコントローラーが作れると思います!作ったら筆者にもこっそり教えてください(笑)
<<前の記事
アバターだけが映るミラー
