本解説は、2023年12月(AudioLink Ver1.2.0)に書かれた解説になります。
最新版とは違う場合もありますので、適時に調べてみましょう!
初めに
この記事は AudioLink を使ったシェーダーの制作する時に使う関数を解説していきます。
導入方法などは解説しませんので、ご了承下さい。
また、もしも間違えている個所がありましたら、教えていただけたら幸いです。
AudioLinkで解析するAudioSourceについて
現在VRChat上の様々なワールドで使われているAudioLink。
(最新のバージョンでは通常のunityアプリでも動作するようになっているようです)
ワールドにAudioLinkを置いて、解析する AudioSource を入れれば動いてくれる簡単設計です。
その AudioSource の設定については、AudioLink.prefab に入っている[AudioLinkInput]が使用している設定を参考にするのが良いです。
- エフェクトの影響を受け無くする (Bypass *** のチェックボックスをONにする)
- Volume を0.01に(0にしてはいけない)
そしてVRChatのワールドとしてアップロードするために必要な VRC_SpatialAudioSource を追加して、Enable Spatialization のチェックを外して2D音源にし、NearとFarを調節して音の解析させたい範囲全体に響き渡るようにしましょう。
AudioLinkの設計上(Unityの仕様上)音の解析は、VRC_SpatialAudioSource で設定されている音源からの位置減衰を適応して、聞こえている音量にて解析をしています。なので、3D音響や減衰を強めにしていると音源の近くに居る人と遠くに居る人で解析の結果に違いが出てしまいます。ですが、 AudioSource の Volume 設定は解析に関係なかったりします。
これによって、実際には聞こえてないぐらい遠い場所からでも音の解析が出来る事になります。
AudioLinkは小さな音でも解析した音のデータに補正を掛かけています。しかし、大きい音の方がしっかりと解析できると思われます。
(補正計算: 1 / Volume を解析したデータに積算している)
例えば、少し離れた場所に野外フェス会場が見えていて、音がよく聞こえない状況であっても、フェス会場にあるAudioLinkに対応した照明はビカビカ光っているなどという事も可能です。
AudioLink Shader関数
VRChat Creator Companion よりAudioLinkをインストールする事でAudioLinkを利用する事が出来ます。
#include "Packages/com.llealloo.audiolink/Runtime/Shaders/AudioLink.cginc"
をShaderに追加する事によってAudioLinkの関数を使用する事が出来ます。
AudioLink
AudioLinkのテクスチャはこのような感じになってます。
画像引用元: AudioLink Doc
128 x 64サイズで、解析されたデータが順番に並んでいる形です。
AudioLinkの関数を使用するには、データ取得の関数にテクスチャのUV位置を指定する形となります。
AudioLinkData( ALPASS_AUDIOLINK + uint(0,x) ).r
例えばこのような形になり、この場合だと " AudioLinkData() "がピクセルの数値そのままを取得する関数になっており、
" ALPASS_AUDIOLINK "がテクスチャ上のUV位置が指定されていて、どの解析データを取るかの指定になってます。
その後の" + unit(0,x) "は、xには0~3の整数が入りBASSからTrebleまでの、どの音域のデータを取るかの指定です。
".r"については、赤(Red)の数値を取る形です。解析データによってはRGBAそれぞれに数値が入っています。
解析データの種類
AudioLinkが解析をするデータは多数あります。
// Map of where features in AudioLink are.
#define ALPASS_DFT uint2(0,4) //Size: 128, 2
#define ALPASS_WAVEFORM uint2(0,6) //Size: 128, 16
#define ALPASS_AUDIOLINK uint2(0,0) //Size: 128, 4
#define ALPASS_AUDIOBASS uint2(0,0) //Size: 128, 1
#define ALPASS_AUDIOLOWMIDS uint2(0,1) //Size: 128, 1
#define ALPASS_AUDIOHIGHMIDS uint2(0,2) //Size: 128, 1
#define ALPASS_AUDIOTREBLE uint2(0,3) //Size: 128, 1
#define ALPASS_AUDIOLINKHISTORY uint2(1,0) //Size: 127, 4
#define ALPASS_GENERALVU uint2(0,22) //Size: 12, 1
#define ALPASS_CCINTERNAL uint2(12,22) //Size: 12, 2
#define ALPASS_CCCOLORS uint2(25,22) //Size: 11, 1
#define ALPASS_CCSTRIP uint2(0,24) //Size: 128, 1
#define ALPASS_CCLIGHTS uint2(0,25) //Size: 128, 2
#define ALPASS_AUTOCORRELATOR uint2(0,27) //Size: 128, 1
#define ALPASS_GENERALVU_INSTANCE_TIME uint2(2,22)
#define ALPASS_GENERALVU_LOCAL_TIME uint2(3,22)
#define ALPASS_GENERALVU_NETWORK_TIME uint2(4,22)
#define ALPASS_GENERALVU_PLAYERINFO uint2(6,22)
// Added in version 2.5
#define ALPASS_FILTEREDAUDIOLINK uint2(0,28) //Size: 16, 4
// Added in version 2.6
#define ALPASS_CHRONOTENSITY uint2(16,28) //Size: 8, 4
#define ALPASS_THEME_COLOR0 uint2(0,23)
#define ALPASS_THEME_COLOR1 uint2(1,23)
#define ALPASS_THEME_COLOR2 uint2(2,23)
#define ALPASS_THEME_COLOR3 uint2(3,23)
#define ALPASS_FILTEREDVU uint2(24,28) //Size: 4, 4
#define ALPASS_FILTEREDVU_INTENSITY uint2(24,28) //Size: 4, 1
#define ALPASS_FILTEREDVU_MARKER uint2(24,29) //Size: 4, 1
// Added in version 0.3.0
#define ALPASS_GLOBAL_STRINGS uint2(40,28) //Size: 8, 4
#define ALPASS_GENERALVU_SOURCE_POS uint2(7,23)
// Added in version 1.0.0
#define ALPASS_MEDIASTATE uint(5,22)
一つ一つ解説していきましょう。
ALPASS_DFT
波形データを離散フーリエ変換したもの。128 x 2 ブロック使用。
A-1 (13.75Hz)を起点として、10オクターブ分の範囲を解析をしている。
1オクターブは24分割して解析しており、合計240ピクセルのデータになっている。
13.75Hzから約14kHzまで配置されており、低音域から高音域までサポートされています。
RGBAでの数値の違いは
- RED: 解析されたデータそのまま
- GRN: AudioLinkコントローラーの[Basic EQ]の設定が適応されたデータ
- BLU: ColorChordで使用する用の強めなフィルターをかけたデータ
- ALP: (予約)未使用
AudioLinkLerpMultiline( ALPASS_DFT + uint2( i.uv.x * AUDIOLINK_ETOTALBINS, 0 ) ).rrrr;
ALPASS_WAVEFORM
Waveformは 128 x 16 ブロックを使用し2048サンプルの波形データ(もしくは2046サンプル)
ちなみに、AudioLinkはこの波形データをシェーダーで受け取って、シェーダーであれやこれやして様々なデータに変換をしている(っぽい)。
中身は解析データままの-1~1の範囲を取る。
- RED: 24kHz audio, 振幅. 2046サンプル
- GRN: 48kHz audio, 振幅. 2048サンプル
- BLU: 12kHz audio, 振幅. 1023サンプル
- ALP: 24kHz audio の ステレオ差分データ. 2046サンプル
左チャンネルのデータは足して.r + .a
右チャンネルのデータは引く.r - .a
(ver2.5で追加)1
使用例 (24kHzのWaveFormデータを取得する場合)
AudioLinkLerpMultiline( ALPASS_WAVEFORM + uint2( i.uv.x * 2046, 0 ) ).r;
注釈
Udon#から4092のサンプリングデータをシェーダーで受け取って、そこからダウンサンプリングをしている。 GRNの48kHzのみ、加工無しで2048サンプリングデータを出している。、ALPASS_AUDIOLINK
AudioLinkは 1 x 4 ブロックのデータ。
Bass , low-Mid , high-Mid , Treble の音域別に解析データを取得する。
音域の幅やどのぐらいの音量でデータを取得するかは、AudioLinkのコンポーネントや、VRC内のAudioLinkコントローラーで設定をする。
- RED: 音の強さ・振動データ
- GRN / BLU: REDと同じデータ。今後のアップデートで解析の計算を変えたのを収納する可能性があります。
- ALP: (予約)未使用
使用例
AudioLinkData( ALPASS_AUDIOLINK + uint2( 0, i.uv.y * 4. ) ).rrrr;
ALPASS_AUDIOBASS
ALPASS_AUDIOLOWMIDS
ALPASS_AUDIOHIGHMIDS
ALPASS_AUDIOTREBLE
ALPASS_AUDIOLINKを使わないで、直接音域のテクスチャアドレスを指定する時に使用。
ALPASS_AUDIOLINKHISTORY
ALPASS_AUDIOLINKの時間でのデータ変移。127 x 4 ブロック。
テクスチャ上で右に行くほど古くなる。
使用例
AudioLinkLerp( ALPASS_AUDIOLINK + float2( i.uv.x * AUDIOLINK_WIDTH, i.uv.y * 4. ) ).rrrr;
(このデータ変移をスムーズに使いたい場合には、ALPASS_AUDIOLINKHISTORY を使用するのではなく ALPASS_AUDIOLINK を使用してください
ALPASS_GENERALVU
テクスチャの22~23行目に配置されているデータ群。
様々なデータ が格納されている。
VU
ALPASS_GENERALVUの[x:8~10][y:0]の部分には音の強度を示す VUデータ が格納されている
VUと言っているが計算式はRMSだと思われる。
取る数値は0~1になっている。
音の強度(RMS)
AudioLinkData( ALPASS_GENERALVU + uint2( 8, 0 ));
音のピークデータ
AudioLinkData( ALPASS_GENERALVU + uint2( 9, 0 ));
ピーク時間
AudioLinkData( ALPASS_GENERALVU + uint2( 10, 0 ));
それぞれ
RED: 左チャンネルの音の強度
GRN: 左チャンネルのピーク
BLU: 右チャンネルの音の強度
ALP: 右チャンネルのピーク
となっている。
基本はRedとBlueを使用するのが良いです。
注釈
GRNとALPにピーク音量が入っているのに、unit2(9,0)にもピーク音量があるじゃないかと思うかもしれませんが、 GRNとALPはAudioLink内で計算処理の方に使われています。ピーク時間も同様に計算処理に使用されています。ピークの更新は、1フレーム処理前の音から大きい音になった場合 と 更新後1秒経ったら必ず更新されます。
注釈2
RMS値とPeak値については下記のサイトを参照してください。Time
時間を観測する系のデータは、デコードが必要になっている。
ALPASS_GENERALVU_INSTANCE_TIME
ALPASS_GENERALVU_LOCAL_TIME
ALPASS_GENERALVU_NETWORK_TIME
それぞれ時間を取る事が出来ます。時間を取る関数は AudioLinkDecodeDataAsUInt
とAudioLinkDecodeDataAsSeconds
。
" INSTANCE_TIME "が、インスタンスが建ってからの時間(オーナーの退出等により同期がズレる事もあり、非推奨)。
" LOCAL_TIME "が、ローカルでの0時からの経過時間。
" NETWORK_TIME "が、サーバーに居る全員に同期される時間。アニメーションを同期させたい場合はこれを使用する事を推奨。
" INSTANCE_TIME "と" NETWORK_TIME "については1.5日時間で一巡する。
ALPASS_GENERALVU_UNIX_DAYS
ALPASS_GENERALVU_UNIX_SECONDS
UTCタイムゾーンでの日付や時間を取得できる。
ALPASS_GENERALVU_PLAYERINFO
VRChatでのプレイヤーデータが取れる。
RED:インスタンスでのプレイヤー人数
GRN:1ならインスタンスマスター
BLU:1ならインスタンスオーナー
ALF:未使用
Other
他にもあるので詳しくは 公式ドキュメント を参照してください
ALPASS_FILTEREDVU
VUにスムージングフィルターが掛かったデータ。フィルターの強さは4パターン。
xはフィルター強度の選択。x:0が一番強くフィルターが掛かっていて、x:4が一番弱い。
float4 vu = AudioLinkData(ALPASS_FILTEREDVU + uint2(i.uv.x*4, 0) );
RED : RMS Left
GLN : Peak Left
BLU : RMS Right
ALF : Peak Right
ALPASS_FILTEREDVU_INTENSITY
ALPASS_FILTEREDVU_MARKER
直接フィルタリングVUのデーターにアクセスする時に使用する。
INTENSITYが音の強度データ。
MARKERがピークのデータ。
REDかBLUEのデータを使用しておけば良いと思います。
FILTEREDVUの機能例については、Shaderフォルダーに入っている"FilteredVUDebug"を確認してみて下さい。
ALPASS_CCINTERNAL
内部カラーコードノートの表示(?)
今のところ変更される可能性がありますとの事。
ALPASS_CCCOLORS
ColorChordインデックスカラー。Unity上のAudioLinkで設定したテーマカラーの色を元に、時間経過で色が変化していく。また、音の強さで色も変化する。
UVをマッピングするのに適しています。
これらは本当に強度の異なる色なので、単に色として使用することができます。ColorChord から色をサンプリングする他の方法とは異なり、これらの色は時間が経過しても比較的安定しているので、ライトなどの世界の小道具の色付けに適しています。
AudioLinkコントローラーの下部に表示されている、"Theme Colors"で表示されている色を取得できます。
AudioLinkData( ALPASS_CCCOLORS + uint2( "colornumber: 0 ~ 3", 0 ) );
ALPASS_CCSTRIP
ColorChordの一本の直線的な帯で、直線的な円グラフのようなものと考えてください。ここの色を直接サーフェスに適用することができます。
AudioLinkLerp( ALPASS_CCSTRIP + float2( i.uv.x * AUDIOLINK_WIDTH, 0 ) ).rgba;
ALPASS_CCLIGHTS
2つの行があり、下の行は生のcolorchordライトの値を含んでいます。音に関連した色を必要とする個々のオブジェクトや照明が、バラバラに存在する場合に便利です。例:紙吹雪の破片、ランプ、スピーカー、ブロックなど。
2行目(0,1)は、ColorChordの内部状態を追跡するために使用されます。変更される可能性があります。使用しないでください。
float4 col = AudioLinkData( ALPASS_CCLIGHTS + uint2( uint( i.uv.x * 128) , 0 ) ).rgba;
ALPASS_AUTOCORRELATOR
この行の赤いチャンネルは、波形の偽自己相関を提供します。これはDFTから波形を再合成するものです。これは左右対称なので、右半分だけがオーディオリンクで表示されます。これを使用するには、左軸にミラーリングすることをお勧めします。この列の緑色のチャンネルは、無相関の自己相関を提供します。これは赤のチャンネルに似ていますが、始まりも終わりもありません。
return AudioLinkLerp( ALPASS_AUTOCORRELATOR + float2( ( abs( 1. - i.uv.x * 2. ) ) * AUDIOLINK_WIDTH, 0 ) ).rrrr;
ALPASS_FILTEREDAUDIOLINK
ALPASS_AUDIOLINKのデータと似ていますが、スムージングフィルターがかかっているので、非常に滑らかに動きます。
スムージングの強さは16段階に分かれています。
yで、ALPASS_AUDIOLINKと同様に4つの周波数別のデータを設定して
xで、スムージングの強さを設定します。x:0が一番スムージングが強く、x:15がスムージングが一番弱めです。
AudioLinkDataMultiline( ALPASS_FILTEREDAUDIOLINK + uint2(i.uv.x * 16, i.uv.y*4 ) ).rgba;
ALPASS_CHRONOTENSITY
4バンドのデータをもとに、数値が累積的に増減する区間です。これにより、時間の中でアニメーションがスムーズに動くようになる。
offset.x | Description |
---|---|
0 | 音の強さで動きが大きくなる。数値は後戻りしない。 |
1 | *1 |
2 | 音の強弱で、数値が上昇下降する(補正有り)。 |
3 | *1 |
4 | 音が弱いと定速上昇。強いと止まる。音が無いと動かない。 |
5 | *1 |
6 | フィルターなし、音の強さが0.05を上回ると上がっていく。 |
7 | フィルターなし、音の強さが0.05を下回ると上がっていく。 |
*1:すぐ上の処理と同じですが、ALPASS_AUDIOLINK の代わりに ALPASS_FILTERAUDIOLINK を使用してます。スムージングレベルはx:0を使用しており、かなり強いフィルターが掛かっています。
// [0 ~ 1]を繰り返す
float chrono = (AudioLinkDecodeDataAsUInt( ALPASS_CHRONOTENSITY + uint2( 1, _AudioLinkBand ) ) % 1000000) / 1000000.0;
// [0 ~ 1]を繰り返す。上記のより早く繰り返す。
float chrono = (AudioLinkDecodeDataAsUInt( ALPASS_CHRONOTENSITY + uint2( 1, _AudioLinkBand ) ) % 100000) / 100000.0;
// [0 ~ 6.28](つまり2π)を繰り返す
float chrono = (AudioLinkDecodeDataAsUInt( ALPASS_CHRONOTENSITY + uint2( 1, _AudioLinkBand ) ) % 628319) / 100000.0;
// [0 ~ 6.28](つまり2π)を繰り返す。上記と結果はほぼ同じだが計算は早い
float chrono = (AudioLinkDecodeDataAsUInt( ALPASS_CHRONOTENSITY + uint2( 1, _AudioLinkBand ) ) % 100000) / 100000.0 * 6.28;
解析には AudioLinkDecodeDataAsUInt を使用。これはRGBAの色情報を32ビット整数にエンコードします。
ALPASS_THEME_COLORx
AudioLinkでは、アバターに適用できる4つのテーマカラーを用意しています。デフォルトではColorChordの色が使用されますが、ワールドクリエイターはAudioLinkコントローラーを弄る事によって、マップのテーマカラーを選択し、動的に変更することができます。
ALPASS_MEDIASTATE
Udon経由で設定された、または接続されたオーディオソースから自動的にクエリされた、接続されたビデオプレーヤーの状態を提供します。
詳しくは公式ドキュメントを読んでください。
ALPASS_GLOBAL_STRINGS
文字列をShaderで書くやつ。
こちらも詳しくは、公式ドキュメントをお読みください。
その他の定義済値
// Some basic constants to use (Note, these should be compatible with
// future version of AudioLink, but may change.
#define AUDIOLINK_SAMPHIST 3069 // Internal use for algos, do not change.
#define AUDIOLINK_SAMPLEDATA24 2046
#define AUDIOLINK_EXPBINS 24
#define AUDIOLINK_EXPOCT 10
#define AUDIOLINK_ETOTALBINS (AUDIOLINK_EXPBINS * AUDIOLINK_EXPOCT)
#define AUDIOLINK_WIDTH 128
#define AUDIOLINK_SPS 48000 // Samples per second
#define AUDIOLINK_ROOTNOTE 0
#define AUDIOLINK_4BAND_FREQFLOOR 0.123
#define AUDIOLINK_4BAND_FREQCEILING 1
#define AUDIOLINK_BOTTOM_FREQUENCY 13.75
#define AUDIOLINK_BASE_AMPLITUDE 2.5
#define AUDIOLINK_DELAY_COEFFICIENT_MIN 0.3
#define AUDIOLINK_DELAY_COEFFICIENT_MAX 0.9
#define AUDIOLINK_DFT_Q 4.0
#define AUDIOLINK_TREBLE_CORRECTION 5.0
// ColorChord constants
#define COLORCHORD_EMAXBIN 192
#define COLORCHORD_IIR_DECAY_1 0.90
#define COLORCHORD_IIR_DECAY_2 0.85
#define COLORCHORD_CONSTANT_DECAY_1 0.01
#define COLORCHORD_CONSTANT_DECAY_2 0.0
#define COLORCHORD_NOTE_CLOSEST 3.0
#define COLORCHORD_NEW_NOTE_GAIN 8.0
#define COLORCHORD_MAX_NOTES 10
// Text constants
#define AUDIOLINK_STRING_MAX_CHARS 32
#define AUDIOLINK_STRING_LOCALPLAYER 0
#define AUDIOLINK_STRING_MASTER 1
#define AUDIOLINK_STRING_CUSTOM1 2
#define AUDIOLINK_STRING_CUSTOM2 3
これらを使用してシェーダーを制作する事で、もしも仕様変更があった場合でも問題無くシェーダーを使用できることでしょう。
データ取得関数
float4 AudioLinkData( int2 coord )
_AudioTextureにある1ピクセルからデータを取るための関数
float4 AudioLinkDataMultiline( int2 coord )
AudioLinkData()と同じだが、Waveformなど複数の行にまたがっているデータを取るときに使用する関数。
float4 AudioLinkLerp( float2 fcoord )
1ピクセルからだけでなく、隣近接ピクセルとの線形補間されたデータ値を取るための関数。
float4 AudioLinkLerpMultiline( float2 fcoord )
複数行のデータで線形補間されたデータ値を取るための関数。
AudioLink.cgin内で定義済み関数
glsl_mod( x, y )
GLSLのmodと同等の計算式。負数を与えられた時の計算結果がfmod()と違う。
float3 AudioLinkHSVtoRGB( float3 HSV )
HSVをRGBに変換。
float3 AudioLinkCCtoRGB( float bin, float intensity, int RootNote )
カラーコードの標準カラー生成機能関数(?)
bool AudioLinkIsAvailable()
_AudioTextureが利用できるかどうか?
float AudioLinkGetVersion()
AudioLinkのバージョンをfloatで取得。もしも"0"だったらAudioLinkは存在しない。
float AudioLinkRemap(float t, float a, float b, float u, float v)
Remaps value t from [a; b] to [u; v]
オマケ
UnityがPlayModeになった時に、Youtubeの動画を再生してくれるスクリプトが追加されてます
AudioLink/scriptsフォルダに、[ytdlpPlayer]というのがそのスクリプトです。
上記のような設定にする事で、Unity上でYoutubeを再生し好きな動画の音で解析を走らせることが出来ます。
ただのScriptなのでVRC上にアップロードされることは無いので、便利です。
この記事は以下のURLを元に制作をしました
-
現在はAVPROに存在するバグの為に、ステレオでの解析は出来ない様だ ↩