らくとあいすの備忘録

twitter : lactoice251

2022年の活動振り返り

こんにちは、らくとあいすです。いつもは技術記事ばかりでこういった振り返りはしていないのですが、今年はかなりめまぐるしく過ぎていってしまった感じがあったので振り返りつつ思い出してみようという感じで書き始めました。VRChatでライブをしたり、色々作ったりしている人の1例として記録に残す意味もあるかもしれません。

Typeman制作参加

今年、個人的に一番大きな出来事を挙げるのであれば、伊東ケイスケ監督作品『Typeman』への制作参加が挙げられると思います。

www.youtube.com

本作品は、VRChatを介して演者とその場で関わりあいながら物語を体験する、インタラクティブVRアニメーション、またはVR演劇です。VRサウンドエンジニアというクレジットで載せてもらっていますが、作曲の森下唯さん、レコーディング&ミキシングエンジニアの蓮尾美沙希さん (WOWOW) と共に、Typemanの音回りの制作を行っていました。もう少し具体的には、Unity上で森下さんの曲や、蓮尾さんが作成した効果音や環境音を実際に利用する部分での調整やシステム回りを担当しました。例えば、"キー"へのインタラクション、楽器的演出のためのシステム・一部アニメーション、立体音響の調整、環境音のシステム等々です。

参加の経緯としては、VR蕎麦屋タナベさんの紹介で、伊東監督にAmebient を体験頂いて、それをきっかけにお話を頂き参加することになりました。ありがたい縁でした!とはいえ、こういった大型の作品制作、まして映画祭への作品出展などはまったくの未知の領域だったので、お話をもらった段階では別の方を紹介する方が良いのではないか...と考えていたのですが。Canon for cubes など他の作品もいくつか見て頂いて、それでもということでしたので思い切って頑張ってみようということに決めました。

いざ始まってみると、制作は基本ずっと楽しく進みました。一番楽しかったのは、WOWOWのスタジオで伊東監督、森下さん、蓮尾さんはじめ制作陣が集まって音回りの作業を一気に進めた日です。(その場に一緒に居るのですが) VRChat内で話しつつ、音量感や立体音響、残響感、曲の展開のペースなど色々と調整をし、時にはスタジオで再ミックスをして頂いたり、時には伊東監督の新しいアイデアをその場で実装したり、朝から晩までてんやわんやでした。色んな人のスキルとアイデアが一つになっていく経験はとても良いものでした。

結果として、Typemanは、ヴェネチア国際映画祭へのノミネートとPremio bisato d'oro 2022(プレミオ・ビサト・ ドーロ/金鰻賞)での最優秀短編賞の受賞、多くの国際映画祭へのノミネートなどたくさんの良い評価を頂くことになりました。素晴らしい作品に関わらせて頂いて光栄でした! prtimes.jp

Beyond the Frame Festival

Typemanに関連してトークイベントに出演させて頂きました。

We met in virtual reality

Typemanとは直接関係ないのですが、映画祭繋がり。"We met in virtual reality"というJoe Hunting監督のVRChatドキュメンタリー映画に一部ピアノ演奏で出演しました。 海外コミュニティの話がメインではありますが、VRChatあるあるなどもたくさん詰まった、面白く、心温まるドキュメンタリーです。Typemanと同じく、ヴェネチア国際映画祭で上演されるなどこちらも各地の映画祭での上演が続いています。なんとU-Nextでも日本語字幕版が見られるようになりました!

EMN Records

アムニェカさん の作った、バーチャルで音楽活動する人たちの助け合い・情報交換サークルEMN Recordsに参加しました! 私の関わった今年の主な活動は、Vオリジャズコンピのアルバム制作参加と、ジャズ理論輪講の開催です。

Vオリジャズコンピ

Vオリジャズコンピとは、VTuberさんのオリジナル楽曲 (Vオリ) をジャズアレンジして、VTuberやバーチャルで活動する人を中心にしたバンドでインストカバーしたアルバムです。

www.youtube.com

私は、次の4曲にピアノで参加しています。

  • Loro/「靴と鍵と私」
  • イトイ/「Phantom sense」
  • 月宮ヤギリ/「燈色」
  • 星こにあ/「WORLD PAINTER

アルバム制作にしっかり関わるのもほぼはじめてだったので、色々と手探りでしたが、各原曲もアレンジもとても良いものだったので大変ながらも楽しく参加させてもらいました! 特に、イトイさんの「Phantom sense」は、複雑な変拍子曲でしかもピアノソロ原曲ということもあって、かなりじっくり時間をかけて取り組むことになりましたが、原曲とはまた一味違った良い作品になったと思います。ぜひぜひ、聴いてみてくださいね!

open.spotify.com

ジャズ理論輪講

ジャズ理論輪講会は、Mark Levine著の"Jazz Theory"というジャズ理論の教科書をじっくり一緒に読んでいくような会です。 もともと本は買っていたのですが、たまに参照する程度でじっくり読み通すことが出来ておらず...

という感じで呟いたところ、のむさん・アムニェカさんがすぐに賛同してくれて、EMN Recordsの企画としてやってみるという話になりました。 この輪講会は現在第21回まで8名の参加者で毎週月曜日に開催しています。内容としては、各週担当者が担当範囲を読み込んで説明・自主研究の発表などを行って、そのあとその内容についてみんなで質疑・議論するというような形です。また、不定期で輪講後に、その週の内容を触れたり触れなかったりするセッションをやったりもしています。一人で読んでいるだけでは、なかなか気づきづらい部分や、ハーモニーに対する各々の認識・聴こえ方の違い、異なるバックグラウンドの知識の交流など、毎週たくさんの刺激をもらえる回でとても楽しく続けられています。年明けからは、最後の第三部がはじまるので引き続き楽しみです!

ワールド制作

今年は、個人のワールド制作としてはあまり多くのことが出来ずに少し心残りでした。来年は、すこしこっちに重心を戻したい感じもありますね。 今年唯一制作を進めていたのが、suzukiさんの制作・公開されているワールド・システム Graphiliaを改変した、”Sound Graphilia”の制作です。元々、GraphiliaはノードベースでShaderを書く仕組みをVRChat上に構築したもので、私はこれを拡張してノードベースで音を作れる試みをしていました。今年中にPublishしたかったのですが...!来年のはやいうちには、と言う感じです。

VRプラットフォーム上でのライブ

2022年は本当に本当にたくさんのライブをした年でした。振り返ってみると、合計49ライブ...。 誘いにのって頂いた、誘ってくれたミュージシャンの方々本当にありがとうございました!

VR楽器ライブ

2021/12/28 VRミュージックフェス Vol.1  

ギリギリ2021年ですが、せっかくなので。おきゅたんbotさんの主催されているくらげビートと、音楽プロデューサー保本真吾さんプロジェクト「ジョイミューラジオ!」のコラボ企画である、「VRミュージックフェス」にVR楽器演奏で出演しました。

パフォーマンスとしては、これまでに作ったPlay with cubesと、Canon for cubes、さらにAmebientの音色 を組み合わせて、そこに観客に追従するような新しい演出を加えたものを、手元のコントローラー群で操作出来るようにしたものでした。見て頂いた方がわかりやすいと思うのでアーカイブでぜひ!

youtu.be

おきゅたんbotさんは、2018年にはじめてVRライブをした時から配信等で常に関わってくれていて、その縁もあって今回のライブにお声がけ頂きました。いつもVR楽器演奏という、なかなか伝えるのが難しいコンテンツをYouTubeでわかりやすいように伝えて頂いて大変感謝しています!

youtu.be

9/25 仮想水槽4

仮想水槽は、yukihataさんが主催されている、DJやマシンライブ、楽器演奏など多種多様なパフォーマンスと、VJの組み合わせが特徴的な音楽イベントです。

今回は、Live Codingを中心としたパフォーマンスということでお声がけ頂いていましたが、せっかくなので (そして仮想水槽の懐の広さを信じて) SonicPi Live CodingとVR楽器とピアノ演奏の組み合わせでのライブを試みました。

youtu.be

リアル側の演奏を映像に乗せた同期信号と共に送って、VR楽器の演奏周期と同期させるというアイデアキヌさんと議論していて、その実装を試みてみた回でもありました。実際には動画配信された時点での音と映像のズレなどはどうしようもなく、完全な同期はなかなか困難であるという状況ではありましたが、面白くなりそうな一端は届けられたのではないかなと思っています。また、今回kaiwareさんにVJを担当して頂いています。こんなに入り組んだ状況の中、かつ直前まで構成が確定しないような状況の中、完璧に対応して映像を合わせて頂いて本当に感謝しています...!

VR楽器自体は、 2021/12/28 VRミュージックフェス Vol.1の時に構築したものに、お客さん同士を繋いで和音を構成する線のような楽器と、そのコントローラーを加えたものを使いました。

ピアノ、Live Coding演奏ライブ (OpenMICを除く)

VRライブに考えるにあたって、実際に身をもってVRで演奏ライブをやりきってみるのが良いかなーと思っていたのもあり、今年は、ピアノでの演奏ライブを増やしてみようと思っていました。それから、SLTなどでの出演を増やしていたのですが、そこから雪だるま式にライブが増えていって大変なことになりました!ここは本当に数が多かったので一言、二言ずつにします!本当はそれぞれ話したいようなこともたくさんあるのですが...

1/22 君のピアノは。2022 at SLT

2020年に第一回の行われたピアノオンリーのライブイベントの第二回に参加しました。 ソロピアノをしっかりと弾くライブイベントはなかなかなく大変さはあるのですが、出演者ごとに違うピアノの音色を楽しめる貴重なイベントでした! また、このイベントで弾いた"Maria Cervantes"をきっかけに、4/3、9/4のEl Solに繋がっていきます...!

2/14 Jazz Live at SLT

ボーカルのあずさん、ベースののむさん、ドラムのYukihataさんとのジャズライブです。 ボーカルフロントのバンドは今まであまりやったことが無かったので、色々と手探りでしたがあずさんの力強い声に引っ張られて良いライブになりました。 そしてあずさんのバンドでは、2022年沢山ライブをすることにすることになります、たくさん誘って頂いてありがとうございました! youtu.be

2/19 Sonic Pi Live Coding at GHOSTCLUB

GHOST CLUBでSonic PiでのLive Codingを久々に行いました。VJには三日坊主さんが入ってくれて、意外とはじめての組み合わせでした。 GHOST CLUBは結構せめた音楽を演奏しても、集中して聴いたり踊ったりしてくれる環境があって本当にありがたいですね。

2/25 Solo Piano at Club Sara's buddy

VRChatのトラブルによって4/15に延期となったPiano Therapyの代わりに、急遽ソロピアノを演奏することになりました。

2/27 VR dvp 2nd session at 玉響

トラックメイカーさんがDJ的に音楽を流し、そこに即興で演奏を合わせていくという面白いスタイルのイベントでした。 私は、メリッサさんのオリジナル曲に合わせてピアノを弾いてきました。次の展開を考えながら、ギリギリ音を合わせていく感じのスリリングさが楽しかったです!

3/5 JAZZ IN VRC Part4 (ゲスト キヌさん) at SLT

2021年にサックス・リーダーの初吹音さきさん、ドラムのYukihataさんとのベースレストリオとして結成されたジャズバンドの四回目のライブでした。今回は、ゲストにキヌさんを加えて、ジャズ×ポエトリーリーディングという面白い編成に。一見突飛なようですが、良いコラボレーションになった思っています!特にGHOST ver 匣はぜひぜひ聴いてみてください。 youtu.be

3/13 VRC×REALITY合同セッション in cluster

REALITYを中心に活動されているバーチャルSAX吹きのまよさんと、初吹音さきが共同主催で開催した、セッションイベントです。VRChat、REALITYを中心に活動するミュージシャンがClusterに集まってセッションするというプラットフォーム横断的なイベントで、普段お会いしない方の演奏を聴いたりセッションしたり出来る良い機会でした!

3/14 第5回 題名のないVRC音楽会

ジェミーさん、紫陽なつさんが主催されている、VRChat上での音楽会に、ボーカルさんのあずさんと、ベースのぴゅら子さんと共に参加してきました。ドラムレスの編成でのバラード曲などは大変難しかったですが、お互いの音を感じることと、自分のタイム (≒主張) をしっかりキープしていくことを共存させるような、セッションの醍醐味を存分に楽しめるライブでした。

3/20 Sonic Pi Live Coding at Algorave 10th Birthday Party, Twitch

Algorave 10周年イベントとして開催されたAlgorave 10th Birthday Partyに、SonicPi Live Cordingと楽器演奏の組み合わせで参加してきました。 一人10分ずつ世界中のLive Corderで24時間を繋ぐというすごいイベントでした! youtu.be

4/3 EL Sol at AWAKE

1/22に「君のピアノは」でのソロピアノでのラテン曲を聴いたtktkさんと意気投合し、2/8にSLTでデュオ演奏していたところ、EL SOL主催のcremaさん に声をかけて頂くという縁が繋がって実現したライブです。EL SOLでは、tktkさんに加えて、フルートのLazさん、ベースののむさん、ドラムのからし明太子さん、パーカッションのMaruさんを加えたラテンバンド、"LA SIESTA DE VIRTUAL"として出演しました。(主に私のせいで) なかなか難しい選曲も多く、かなり多くの合わせ練習を必要としましたが、その分とても充実したものになりました! youtu.be

4/6 azWiz at PaleBlueDotClub (EchoArena試合観戦&JazzLive)

メンバー不定のあずさんのバンドazWizとして、EchoArena JAPAN Creators (EAJC) 主催のイベント、EchoArena試合観戦&JazzLiveに出演しました。 Echo VRというのは、ディスクをお互いのコートに投げ入れることを目的とするVRゲームで、EAJCはそのプレイヤーが集まってEcho VRについての情報を発信している団体です。 本イベントはその一環として、EchoArenaの試合観戦とJazz Liveを同一のVRChatワールドで行うという面白い試みでした!

4/15 Piano Therapy Op.2 at MusicStellarLake

2/25にトラブルで延期になってしまった本イベントですが、ようやく4月に開催されました! このイベントは、AudioLinkを介して反応するパーティクル演出とピアノ演奏を組み合わせて楽しむことを目的にしたもので、MusicStellarLakeの美しいワールドの中で行われます。 なので、普段よりすこししっとりと、自分でもパーティクルの光を楽しみながら即興演奏してきました!

5/6 Lactoice & tktk duo session at GHOSTCLUB (GHOSTWEEK)

ある日Amebientにtktkさんと居たところ、たまたま居合わせたGHOSTCLUB主催の0b4k3さんと話が進んで、二人でGHOSTCLUBのイベントに出演することになりました。GHOSTCLUBの中庭の中心でライブをさせてもらえるということで、中庭のしっとりとして穏やかな感じから、GHOSTCLUBの奥の激しい感じまでを表現するようなライブ構成にしてみました。また、ライブの最後には今年アレンジさせて頂いた"ow (piano arr: lactoice)" (後述) にtktkさんを加えて演奏させて頂きました! youtu.be

5/22 azWiz at Club Sara's Buddy

azWizとして出演する今年二回目のClub Sara's Buddyでした。高層ビルのきらびやかな雰囲気の中、しっとりとしたジャズをドラムレスで演奏してきました。 youtu.be

6/19 ALLVERSE JAZZ BAND at メタソニ2, AnimeConNL

loyさん 主催の大型イベントALLVERSE WEEKENDSの中のイベントとして、メタソニ2、AnimeConNLに、ALLVERSE JAZZ BANDとして出演してきました。 ALLVERSE JAZZ BANDは、ギターのアムニェカさん、サックスの初吹音さきさん、ベースののむさんとのカルテットで、それぞれのオリジナル曲を1曲ずつ演奏するというライブでした。

8/14 Tide Tyde at RIPPLE

Tide Tydeは、完全フリーのセッションとDJ、マシンライブ、Shader Live Coding、VJを組み合わせた、Yukihataさん主催の実験的なイベントです。Yukihataさん、isagenさんの二人からはじまったフリーセッションが、段々と広がりこのライブに繋がりました。ここまでフリーなセッションというのは、VRChatの中でも外でもやったことがなく、試行錯誤の連続でしたが、全員の意図が噛み合ったり、逆に予想外の方向に飛んでいったりする感覚が楽しくすっかりハマってしまいました。

8/25 azWiz at PaleBlueDotClub, VRChat (オカムラ杯inVket)

azWizとして2回目のEchoArena JAPAN Creators (EAJC) 主催のイベント出演でした。 今回は、Vketとの連動企画ということで、EAJCのkumaさん 制作の前回よりも一層パワーアップした専用会場でのライブでした。

8/26 VR即興音楽ツアー at STYLY

VR即興音楽ツアーは、リアルメタバースプラットフォーム STYLYにアップロードされた、いくつかのシーンを巡りながら、各シーンに合わせてピアノで即興演奏をするというイベントでした。三日坊主さんに誘って頂いて出演することになったのですが、VRChatのワールドとはまた一味違った雰囲気のシーンが多く、新鮮な気持ちで楽しんで演奏出来ました。また、三日坊主さんが次にどのシーンを出すか、という読み合いも面白かったです。

8/28 azWiz at Club Sara's Buddy

azWizとして出演する今年3回目のClub Sara's Buddyでした。今回は前回のバンドに加えて、ドラムのinuさんが加わりました。決してうるさくならず、すっと雰囲気をまとめてくれるドラミングによって一層演奏しやすくなりました。 youtu.be

9/4 El Sol2 @ La Isla del Sol

4/3に開催されたラテンライブEL Solの第2回!今回は出演できなかったパーカッションのMaruさんに代わって、パーカッション・ビブラフォンみちのくさんが参加してくれました。さらにギターでアムニェカさんも加わってくれて、かなり大所帯のバンドとなりました。今回会場制作も自分達で行っていて、tktkさんがメイン部分、cremaさんがボードのデザイン、私が一部システムとカメラワークという形でした。前回に引き続き大ボリュームでしたが、とても充実感がありました! youtu.be

9/17 JAZZ IN VRC at M4L1C3 Resonate

JAZZ IN VRCの特別編のようなかたちで、音楽ライブを行っている海外コミュニティのResonance VR主催のイベントM4L1C3 Resonateに出演してきました。会場で聴こえる言葉はほとんど英語で、なかなかコミュニケーションも難しい状況ではあったのですが、演奏がはじまると絵文字や拍手で楽しんでいる様子を皆さん伝えてくれていました。

11/26 azWiz at BarContrast

この日はなんとazWizで二つもライブがありましたが、その一つ目がBarContrastでのライブでした。いつもは、あずさんの選曲でライブすることの多いazWizですが、今回はラテン系統でやってみたい曲を挙げてみたところ、全曲ラテン系のかなりアツいセットリストになりました。歌モノのラテンはずっとやってみたかったので、演奏出来て嬉しかったです!

11/26 azWiz at Roots

同日のBar Contrastのライブの後、そのままRootsでのライブとなりました。こちらはかなり大型のイベントで、同一の会場で2パラレルでライブが行われているという面白い開催形態でした! 改めて、VRChat内でライブをする人が増えているんだなあと実感しますね。セットリストはBar Contrastのものとほとんど同一ですが、さらに何曲か追加して体力を使い果たす感じのセットリストでした笑

12/10 Sheenaさんバンド クリスマスライブ at BarContrast

ボーカルのSheenaさん、ドラムのStomさん、サックスの初吹音さきさん、ベースののむさんとのバンドでした。クリスマス曲を中心に、ジャズ曲を織り交ぜながらのライブでした。いよいよ12月に入って、VRChat上であってもクリスマスライブが増えてきたりするのはなんだか面白いですね。

12/13 azWiz at Okamura Night Circus in 1952 (EchoVRオカムラエレコム杯 in Vket)

azWizとして3回目のEchoArena JAPAN Creators (EAJC) 主催のイベント出演でした。たくさん呼んで頂いてありがたい限りですね! 今回も、kumaさん制作の特別会場で、創業当時のOkamuraの工場の中にライブ会場が出現しました!また、今回のライブでは(overさん)https://twitter.com/over_keys含め鍵盤が二人居る編成で結構難しいかなと思っていたのですが、overさんの音の入れ方が絶妙で非常に厚みのある良いサウンドになりました。

12/18 Jazz Quintet at Jazz&Bar:OcLa, Cluster

3/13のVRC×REALITY合同セッションを主催されていた、サックスのまよさんリーダーのJazz QuintetでCluster上でのライブを行いました。いわゆる"スタンダード本"に載っているようなセッション定番曲ではなく、知る人ぞ知る感じのジャズ曲を中心にしたライブで、曲をしっかり頭に入れるところからなかなか大変でしたが、その分新鮮な気分でプレイ出来たように思います。 youtu.be

12/18 azWiz at Club Sara's Buddy

なんとazWizとして出演する今年4回目のClub Sara's Buddyでした。今回は、初共演のトランペットのmonetteさんが加わってくれていました。VRChatのバンドでトランペットの方と一緒に演奏するのははじめてでしたが、一層Club Sara's Buddyの雰囲気に合うようなリッチなサウンドが引き出されていて演奏していてもとても楽しかったです。 youtu.be

Open mic形式のライブ

上記のライブ以外には、SLTや玉響といったOpen mic形式の会場で突発的なライブも行っていました。これについては、共演させて頂いた方と、演奏日を並べて書かせて頂きます。 このOpen micでの共演から、上で書いたような大きめのライブに繋がったり、あらたな人とのつながりが出来たりしたことも多かったので、こういった場所の存在にはとても感謝しています!

  • 1/8 シェルさん at SLT
  • 1/15 さきさん、yukihataさん at SLT
  • 1/29 Lazさん at SLT
  • 2/8 tktkさん at SLT
  • 2/5 あずさん、のむさん、yukihataさん at SLT
  • 2/26 ぴぼさん at SLT
  • 3/12 あずさん、のむさん at SLT
  • 3/26 のむさん、さきさん at SLT
  • 4/9 シェルさん at SLT
  • 6/11 Lazさん、tktkさん at SLT
  • 7/2 ソロピアノ at SLT
  • 7/24 しーなさん、のむさん、STomさん at 玉響
  • 8/13 のむさん at 玉響
  • 8/27 さきさん、zakkさん、コジローさん、めんたいさん (V Messengers) at SLT
  • 9/10 さきさん at SLT
  • 9/17 ソロピアノ at SLT
  • 10/8 シェルさん at SLT
  • 10/22 アムニェカさん at SLT
  • 11/5 tktkさん、みちのくさん at SLT
  • 11/27 ソロピアノ at SLT
  • 12/17 まよさん、さきさん、めんたいさん at SLT

その他の活動

ow (piano arr: lactoice)

0b4k3さんの楽曲"ow"の、CUE [Archive]のためのアレンジ"ow (2022 edit)"をさらにピアノアレンジした"ow (piano arr: lactoice)"を、カセットテープ媒体に収録して頂きました。これは、元々仮想水槽2で"ow"をピアノアレンジしたところからスタートしていて、今回カセット化するにあたって、2022editだけではまだテープの時間に余りがあるということでお声がけ頂いた形です。この収録は、グランドピアノを借りて生ピアノの音色に拘って行いました。こちらも是非聴いてみてくださいね。

0b4k3.bandcamp.com

ゼロから始めるVRCピアノ生活 (ゼロピアノ)

第二回の講師として呼んで頂き、ダイアトニックコードや、2-5-1といったジャズの基本的な理論の解説と、そのピアノでの弾き方について話してきました! 第五回までの講義が終わって、1月には参加者の発表会があるみたいで楽しみです!

技術記事「VRの世界に音を存在させる」

VRChatワールド探索部 Advent Calendar 2022の記事として、VRの世界に音を存在させるという技術記事を執筆させてもらいました。結構マニアックな記事かなとも思っていたのですが、意外にも反応が大きく嬉しく思っています。未読の方はぜひぜひ。

日産アリアとめぐる環境ツアー BGM提供

以前作曲したStair54を日産アリアとめぐる環境ツアーのBGMとして利用頂きました。

youtu.be

AI ProgrammerとSonicPi

最近話題の生成系AIの一つ、AI ProgrammerでSonic Piのコードを生成させる試みで遊びました。

おわりに

こうして振り返ってみると、本当に本当に多くの人と関わらせて頂いた一年だったと思います。 関わって頂いた方、色々とお話を振ってくれた方、本当にありがとうございました!来年以降もよろしくお願いします。 来年はワールド制作にも、もう少し軸を戻していければと思っています。 それでは良いお年を!

VRの世界に音を存在させる

こんにちは。らくとあいすです。 VRChatワールド探索部 Advent Calendar 2022 12日目の記事です。

本記事では、VRChatをはじめとするVRの世界において、「音をそこに存在させる」ための技術と、そのVRChatでの利用方法を紹介します。想定する読者としては、

  • VRChatで音のあるワールドを作ってみたい人
  • VRChatのワールド探索や音楽ライブを音の視点からもっと楽しみたい人
  • 立体音響についてごく基礎的な事項を知りたい人

などになると思います。ただし私は、立体音響やゲームサウンドの専門家ではないため、いちVRChatのワールド制作者として、種々の文献等を頼りに記事を執筆しております。誤った情報がないように努めておりますが、学術的な信頼性を期待出来る水準の記事ではない点ご留意いただければと思います。

1. はじめに

現実の私たちの生活空間にはたくさんの音があります。音は、物体の振動や空気の流れによって空気が揺らされることによって発生します。揺らされた空気は波として伝播し、部屋の床や壁などの物体に反射し、共鳴し、一部は吸収されます。それらが、最終的には耳介によって耳の中に集められ、鼓膜を揺らすことで人間に認知されます。従って、音はその発生源の性質はもとより、音の発生源から鼓膜に到るまでの環境や、自身の耳の形状といった多くの情報を含んだ形で、私たちに届けられることになります。例えば、トンネルに入った時の足音の変化で、私たちは目をつぶっていてもその環境の変化をうかがい知ることが出来ます。

一方で、イヤホン、またはヘッドホンといった耳に直接取り付けるデバイスを用いた場合は、そうした現実空間の影響をほとんど受けない形で音を聴くことになります。予めデジタルデータとして記録した音の粗密を、スピーカーの振動として現実空間に再現し、スピーカーと鼓膜の間のごく短い経路を通って我々に届けられます。スピーカーやその筐体の特性を受けるため、デジタルデータそのものの形の波面が耳に届くわけではありませんが、少なくとも良く調整された一定以上の品質のヘッドホン・イヤホンでは高い再現度で音を再生出来ます。

VRChatをはじめとしたVRの世界では、ほとんどの場合イヤホンやヘッドホンから再生された音を聴くことになります。当然、VRの世界の環境の影響を、直接的に音が受けることはありません。左右2チャンネルのステレオ音源が用意されたのであれば、再生装置はそれを律儀に再生するのみで、頭をふっても、トンネルに入っても勝手に音が変わることはありません。

従って、作られたVRの世界の中で、あたかもその世界で発された音が存在しているように感じさせるためには、その状況で我々が聴く音を計算によって再現する必要があります。これは、非常にシンプルな状況であればあまり難しいことではありません。例えば、反射も吸収もない無響室のような部屋の中 (自由空間) で、ある一点から発される音 (点音源) は、距離の二乗に比例して減衰します。しかし、現実的な状況を考えると、ある地点で観測する音には、わずかに遅れて到達する無数の反射音が重ね合わされるほか、頭部での遮蔽や耳介での反射の影響を受けて変化します。音源も点音源ではなく、一般には大きさをもっています。これらの条件を近似無しに計算して聴こえる音を計算することは現実的には不可能であるので、実際には様々な近似のもとでの計算を行うことになります。

本記事では、実際にVRの世界におけるいくつかの状況を想定しながら、各状況において適切な音提示の手法について紹介します。

2. 空間に存在するように音を鳴らす手法

2.1 オブジェクトベースの立体音響

VR空間で特定のオブジェクト (例えばハンドベル) から音が鳴るような状況を考えます。この時期待される挙動は、

  • オブジェクトの見えている方向から音が聴こえてほしい
  • 音の聴こえ方は、頭の回転に追従して変わってほしい
  • 近づいていけば、今度は耳元の近くで鳴っているように聴こえてほしい

といったようなものだと思います。この挙動を再現するためにはまず、人は何故左右や上下、距離感を感じ取れるのかということを考える必要があります。

音源の水平回転方向 (方位角) の認知においては直感的にも明らかなように、左右の耳に届く音の大きさの差 (Inter level difference; ILD) が影響を及ぼします。これは、右から来る音は右耳で大きく聴こえるという、ごく単純な話です。しかし、低い音、すなわち波長の長い音については回折によって頭部を回りこんで反対側の耳に届く割合が大きいため、ILDが方向知覚にあまり役に立たなくなります。そこで活用されるもう一つの情報が、左右の耳に届く音の時間差 (Inter time difference; ITD) です。我々の耳は1ms以下の非常に小さな音の時間差を聴きとることが出来るため、左右の耳に音が届く僅かな時間差の情報を音の方向を捉えるのに活用出来ます。ここで、110Hzのサイン波について、左耳より右耳の音を10dB小さくしてILDを再現したものと、それに対してさらに右耳の音を2ms遅らせてITDを再現したものを聴いていただきます。ITDの付与により、より明確に音源方向が感じ取れることが分かると思います。

  • ILDの再現のみ

  • ILD + ITDの再現

音源の垂直回転方向 (仰角) の認知については、一般に方位角と比べて弁別が難しい。これは、我々が左右二つしか耳を持っていないために、垂直方向の音源の移動に対してはILDやITDが顕著な特徴として表れないためです。それでも、我々の頭は上下方向に対称な形をしていないため、上から来る音と下から来る音では、耳に入るまでの反射や吸収のパターンがわずかに変化します。この変化は、特定の周波数の音の吸収 (ノッチ) に現れることが知られており、スペクトル的手がかり (Spectral cue; SC) と呼ばれています*1。なお、このSCは音の前後判定にも寄与しています。音源との距離の認知については一般的にあまり容易ではありません。ただし、こちらも左右の耳に届く音の角度差によって変化するスペクトラルキューや、ILD、ITDとの関連があることが報告されています*2。また、実環境においては、遠くの音ほど部屋の反響の影響を受けて音像がぼやけるといったことも距離を認知する手がかりとなります。

VRChatでは珍しくないが、耳が4つ付いている場合は、上下方向のITDが利用出来るため、仰角知覚の精度が向上するかもしれない。写真提供:えなじーさん、モデル:翠蓮

VR空間において、音の方向や距離感を再現するためには、人間が利用している音の手掛かり (ILD、ITD、スペクトラルキュー) を、頭部トラッキングに基づいて算出される頭の角度、音源との距離等に応じて変化させれば良いと考えられる*3。そのために、現在最も良く用いられる方法が、実際に人間の耳内にマイクを装着して測定した、頭部インパルス応答 (Head-Related Impulse Response; HRIR)を利用するものです。

インパルス応答についてや、その測定方法はより詳しい文献を紹介するにとどめさせて頂きますが*4、HRIRは簡単に言えば無響室内に居る人の近くでごく短い音 (パルス音) を鳴らした時に耳内に到達する音波を測定したものです (ただし、実際の測定には短い音ではなく、Swept-sineやM系列等を用いる)。誤解を恐れずに言えば、あらゆる音は無限に短いパルス音を強さを変えながら連続的に足し合わせたようなものであり、耳に届く音はそれぞれのパルス音に対するHRIRを足し合わせたものと言えます。このような演算を、畳み込み (Convolution) と言います。

VR空間内においてある距離・角度に音源が現れた際には、事前にその距離・角度に最も近い場所で収録されたHRIRを選び出し、それを音源に畳み込むことによってその位置から到来した音の聴こえを再現出来るというわけです。とはいえ、この方法にもまだ課題はあり、例えばVR空間上で音源が発生する位置は (少なくともfloat精度程度には) 連続であり、その細かさで現実空間のHRIRを測定することは不可能です。これには、インパルス応答の補完などの手法の利用が研究されています。またHRIRは、耳や頭の形状に影響を受けるため、他人の頭部によって収録されたHRIRを用いた場合に期待する定位感が得られない場合があることが知られています。この影響の軽減のため、多くの場合複数人のHRIRを平均した応答が立体音響の生成に用いられています (おそらくVRC_SpatialAudioSourceもこの方式) *5。また、近年では耳の画像等の情報を利用して、個人に最適なHRIRを選び出す方式も登場しています*6

最後にVRChatにおいて、このHRIRに基づく立体音響を利用する方法についても触れます。これは、シーン上に配置したAudioSourceにVRC_SpatialAudioSourceコンポーネントを取り付けるだけで実現されます。ただし、以下のいくつかの設定を確認する必要があります:

  • VRC_SpatialAudioSourceコンポーネント内、Enable Spatializationにチェックを入れる
  • AudioSourceのプロパティでSpatial Blendを3Dにする

ちなみに、Enable Spatializationにチェックを入れない状態でAudioSourceのプロパティ上でSpatial Blendを3Dとした場合HRIRの畳み込みは行われず、ILDのみを用いて音の方向が提示されます。これらの比較については、過去の記事で実験結果を共有しているため必要に応じて参照して頂ければと思います。実在感のあるオブジェクトベース立体音響を目指す場合、ほとんどの場合はEnable Spatializationにチェックを入れるべきですが、次のようなケースではチェックを外す選択肢もあるかもしれません:

  • VRChat上での配信ライブ
    • TopazChatやTwitchを経由してVRChat上に音を配信する形式のライブにおいて、配信の音を最も変化なく伝える方法は、AudioSourceのSpatialBlendを2Dとしてステレオ再生することです。しかし、これでは観客の頭の運動等に音がまったく連動しないため、臨場感が削がれるかもしれません。一方で、AudioSourceのSpatialBlendを3DとしてEnable Spatializationを有効にした設定を用いた場合、「配信の音がスピーカーの方向から鳴っていてそれを実際に耳で聴いたときの音」に近いものが聴こえることになるため、配信の音そのものとは若干音が変わってしまいます。それは正しい音の変化とも言えますが、そのような変化を嫌い・かつ頭の運動に伴う音像の変化が欲しい場合については、AudioSourceのSpatialBlendを3Dにして、かつEnable Spatializationを非有効にする手もあるかもしれません。ここは演者と主催者のポリシーによるところであると思います。(切り替えUIが標準的に設けられるようになると良いかもしれない。)
  • 非常に大量の音源がある、かつ低演算量を目指す場合
    • 演算量については、検証出来ていないためたしかな事は言えませんが、HRIRの信号への畳み込みに一定のCPUリソースを食われることはたしかです。音源が大量に存在する場合、負荷はその分増大するため、低演算量を要求されるプロジェクトの場合、Enable Spatializationを非有効とすることは一つの選択肢になりうるかもしれません。(もちろん、実際のプロファイルに基づいて行われることが望ましい。)

VRC_SpatialAudioSourceの音響特性の調査。(上図) VRC_SpatialAudioSourceを用いない3DAudioSourceを頭の周囲で移動させた時の、左耳での周波数応答。(下図) VRC_SpatialAudioSourceを用いた場合での同様の測定。3DAudioSourceでは単に再生音量が変わるだけなのに対して、VRC_SpatialAudioを用いることで、周波数応答に方向に特有のノッチやピーク (SC) が出現することがわかる。(詳細は過去の記事を参照)

2.2 残響について

2.1節では、音の伝搬における頭部や耳の影響を取り込むことで、方向や距離を感じ取ることの出来る音を作り出す手法について述べました。ただし、ここでは部屋の壁や天井といった、体以外の物体による音の伝播への影響が考慮されておらず、ほとんどの場合でHRIRは無響室において収録されたものが用いられています。

部屋の影響を取り入れるためのもっとも直接的な方法は、音源から耳に届くまでのあらゆる音の反射経路を取り出し、それらの経路において耳に届くまでの時間と減衰・吸収を求めることです。これは、部屋形状がごくシンプルな場合にはある程度現実的な計算量で計算可能であり、例えば「鏡像法」というアルゴリズムが良く知られています。鏡像法や、Unity上での鏡像法のシミュレーションについては、よしたかさんによるこちらの講演資料に詳しいです*7

ただし、鏡像法等の方法によって、逐次に音源から人までの反射経路と遅延を計算することは非常にコストが高く、部屋形状が複雑であったり音源が複数個となった場合はさらに困難です*8。そこで多くの場合は (頭部の場合と同様) 室内の物体の音への影響をインパルス応答として測定 (または生成)し、このインパルス応答を音源に畳み込むことによって、残響 (リバーブ) を表現します。このような方式のリバーブをコンボリュージョン・リバーブと呼びます。

VRChat(Unity) において利用出来るリバーブもコンボリュージョン・リバーブです。これは、AudioSourceにAudioReverbFilterを取り付けるか、Audio Listenerを取り付けたMain CameraにAudioReverbFilterを取り付けることで適用可能です。前者は、取り付けたAudioSourceのみへのリバーブ、後者は聴こえる全ての音へのリバーブとなります。

ちなみに、VRChatにおいてPost processing stack (PPS) とMainCameraに取り付けるリバーブを併用する場合、VRC Scene DescriptorのReference Cameraとして設定したPost-process layerを設定したCameraに、AudioReverbFilterを追加してしまうと、この効果が反映されないという問題がある。この場合は、「Main Camera」という名前のCameraを一つ用意してこちらに、AudioListenerとAudioReverbFilterを取り付け、Reference Cameraとして設定するPPS付きのCameraにはAudioListenerやAudioReverbFilterを取り付けないようにする必要がある。

UnityのAudioReverbFilterでは、プロパティからコンボリュージョン・リバーブの設定を変更出来ます。これは、部屋の形状や壁面の反射率に合わせてリバーブをコントロールするために用いることが出来ます。プロパティの詳細は公式ドキュメントに記載されている通りですが、ここでもそれぞれの設定項目について簡単にまとめておきます。

  • Reverb Preset: プリセットとしていくつかの環境を想定したリバーブのバラメータが用意されています。"User"を選択した場合は、下記パラメータを用いて自分でリバーブの調整を行うことが可能となります。
  • Dry Level: 元信号 (リバーブを適用しない信号) のレベルです。
  • Room: リバーブを適用した信号のレベルです。
    • ところで、ドキュメントには"Room effect level at low frequencies"と記載されているが、一方でRoom LFにも"Room effect low-frequency level"と記載されています。こちらは、"at low frequencies"ではなく全体のレベルなのではないかと思っているのですが、実際のところは不明です。
  • Room HF (LF): リバーブを適用した信号のレベルの高音 (低音) 域成分のレベルです。
  • HF (LF) Reference: 高音域 (低音域) として設定する周波数の範囲を決めます。
  • Decay Time: 低音域での残響減衰時間です (何Hzを基準にしているかは不明。おそらく一般的には500Hzなど?)
  • Decay HFRatio: 低音域にたいする高音域の残響減衰時間の比です
    • 一般に現実空間であれば、高音域の方が物質に吸収されやすいため、残響成分では低音域が大きくなりやすい。 したがって、Decay HFRatioを1.0以上の値にするのは、物理的には考えづらい状況です。(そのような効果を狙うのであれば1.0を超えても良いと思います。)
  • Reflections Level: 初期反射のレベル
  • Reflections Delay: 初期反射の遅延時間
  • Reverb Level: 後部残響のレベル
  • Reverb Delay: 後部残響の遅延時間
    • 反射音として到来する音のうちはじめ (の方) にやってくる音を初期反射、後の方にやってくる音を後部残響といいます
    • 初期反射の遅延時間が大きい (= 直接音が到来してから反射音が到来するまでの時間が長い) ということは、音源との距離に対して部屋のサイズが大きいことを意味します

2.3 シーンベースの立体音響

ある程度遠方に、非常に多くの音源があるような場合を考えます。例えば、森の中で木々の葉がこすれたり、街中で無数の人が話したり歩いたり、雨が降っていたりといった状況が当てはまります。この状況は、2.1のオブジェクトベースの立体音響において非常に多数の音源が存在するケースとも言えるが、雨粒一つ一つの音に対してHRIRの畳み込み演算を行い立体音響を生成することは現実的ではありません。

このようなケースで現状 (VRChatワールドとして) 最も良く用いられている手段は、おそらく(Spatial blendを2Dとして、Enable Spatializationを非有効にしたAudioSourceを用いて) ステレオ音源を2D音源として再生する方式だと思います。この方法では、当然頭部の回転やプレイヤーの移動によって音が変化することはありませんが、雨音のように方向感のあまりない音に対しては多くの場合十分と言えます。ただし、建物の中から雨の降る屋外に移動したり、森を抜けて草原に出たりといったように、環境音がプレイヤーの動きによって動的に変化することが期待される状況は十分にあり得ます。このようなケースには、2DのAudioSourceの音量や、Low Pass Filter (LPF) 等の設定をプレイヤー位置に応じて変化させることで、ある程度対応可能です。2D AudioSourceの制御による環境音の遷移については過去の記事にも書いているため興味があれば参照して頂ければと思います。

より臨場感ある環境音の表現を得るために立体音響を導入するための手法としては、アンビソニックスの利用が挙げられます。アンビソニックスの詳細についてはより詳しい文献*9 を紹介するにとどめますが、ごく簡略化して言えば (同一球面上に配置された) 多数のマイクロフォンを利用して、観測地点からみた全天球上の音場を記録するフォーマットです。もう少し言えば全天球上の音場を、球面調和関数の各成分に展開して記録するものです。アンビソニックスの現在最も普及している形式は、一次アンビソニックス (First Order Ambisonics; FOA) と呼ばれるものです。これは、球面調和関数展開の1次までの項を利用するもので、無指向W (0次) と、X, Y, Z (1次) の4つのチャンネルから構成されます。アンビソニックス形式で記録された全天球の音場は、後から回転して再生することが可能です。アンビソニックスを利用すれば、VR空間においてプレイヤーの頭部回転に対して音場を逆方向に回転させることで、頭部の動きに追従した立体的な環境音を再生することが可能となります。ただし、アンビソニックスはあくまでも全天球上の音場を記録しているに過ぎないため、プレイヤーの並進運動に対応することは出来ません。従って、6DoFのVRコンテンツに用いる場合においては、プレイヤーのごく近くで鳴っているような音にはあまり適さない点に注意が必要です。

VRChatでのアンビソニックス形式の音の再生方法については、こちらの動画 が詳しいですが、簡単に日本語で手順を書いておきます:

  1. アンビソニックス形式の音源を用意する
  2. Unityのプロジェクトにimport
  3. Edit>Project settings>Audio>Ambisonic Decoder Plugin>Oculus Spatializerを選択します
  4. アンビソニックス音源のimport settingsでAmbisonicsにチェック、Load TypeをStreamingに変更しからApplyします
  5. シーンにAudio Sourceを設置し、Spatial blendを2D、VRC_SpatialAudioSourceのEnable Spatializationを非有効にします
  6. 上記AudioSourceのAudioClipとしてアンビソニックス音源を設定します
  7. アンビソニックス音源の正面方向を向けたい方向に、AudioSourceのZ軸を向けます

以上でアンビソニックス形式の音の再生が可能となり、実際にVRChatワールド内において頭を動かすことで音が変化することが確認出来ます。

3. さいごに

本記事では、主にVRChatで音のあるワールドを作る人に向けて、立体音響にまつわる基礎的な事項を紹介しました。非常に奥の深い分野で、書ききれていないところ、知識の至らないところ多々あったかとは思いますが、より詳細な文献に至る前段階として、少しでも理解の助けになれば幸いです。また、ワールドを探索する人にとっても、この記事がワールドを音の観点からより楽しめるようなきっかけとなれば幸いです。

*1:K. Iida+, "Median plane localization using a parametric model of the head-related transfer function based on spectral cues", Applied Acoustics vol. 68, 2007, URL: http://www.iida-lab.it-chiba.ac.jp/literature/research.papers/14.median.plane.localization.using~.aa-2007.pdf

*2:金 海永 他 (2000)、拡張輻輳角モデルを用いた音像距離定位の制御 日本バーチャルリアリティ学会論文誌 vol.5 No.3、URL: https://www.jstage.jst.go.jp/article/tvrsj/5/3/5_KJ00007553639/_pdf/-char/ja

*3:谷幸雄 (2017)、頭部伝達関数による音像定位 日本音響学会誌73巻3号 小特集—頭部伝達関数とその応用—、URL: https://www.jstage.jst.go.jp/article/jasj/73/3/73_173/_pdf

*4:河原英紀 (2020)、インパルス応答の基本概念 日本音響学会誌 76 巻 3 号、URL: https://www.jstage.jst.go.jp/article/jasj/76/3/76_148/_pdf

*5:平均HRIRを用いた場合、当然そのデータの平均から外れた頭部・耳の形状の場合は立体音響の質が下がってしまう。おそらく、ほとんどの日本人にとってVRChat上での音は十分な立体音響として聴こえていないのではないかと思う。実際私も、VRChat上で上下や前後の判定を行うことは結構難しいと感じた。

*6:SONY 360 Reality Audio: https://www.sony.jp/headphone/special/360_Reality_Audio/

*7:吉高 弘俊、VR音響のための鏡像法による距離減衰の再現、URL: https://learning.unity3d.jp/2121/

*8:とはいえ、近年は計算機パワーの増大に伴って動的に変化するようなリバーブについても導入がはじまっているらしい

*9:西村竜一 (2014)、特集記事「アンビソニックス」 映像情報メディア学会誌 Vol. 68 No. 8、 URL: https://www.jstage.jst.go.jp/article/itej/68/8/68_616/_pdf

SonicPiをMIDIコントローラで制御する話

こんにちは。

久し振りにSonicPiでライブをしたのですが、今回はMIDIコントローラを初導入しました。

SonicPiでのMIDIコンからの入力の受け方について少しまとめておきたいと思います。 本記事は、程度SonicPiに慣れ親しんでいる方を想定しています。

環境

  • SonicPi for Win x64 v3.3.1
  • DJ TechTools MIDI FIGHTER TWISTER
    • 16個のロータリーエンコーダのついたMIDIバイス。ノブを押し込むことでもMIDI信号を送信出来る。

SonicPiでのMIDIの受け方

Sonic Piでは接続されているMIDIバイスからの入力を、Time Stateと呼ばれる共有メモリに保持しています。

ここは、良くわかってないで書きますが、(SonicPiのTutorialによれば) Time Stateはグローバル変数と似ているがスレッドセーフであるとのことです。 例えば、複数スレッド (ループ) 間で共通の値 (例えばBPM) にアクセスしたいとき、グローバル変数ではそれがあるスレッドで書き換えられると他のスレッドに影響を及ぼしますが、Time Stateの変更はスレッド間で独立に行われるため、determinism guaranteesであるということみたいです。

Time Stateは、シンボル (コロン+文字列) または文字列によって名前付けられる。MIDI入力は次のような文字列でTime Stateに格納されます:

"/midi:[MIDIデバイス名]:[MIDIチャネル]/[MIDIイベント]"

MIDIバイスの名称は、環境設定>入出力>MIDIポートから確認出来ます*1。 格納されたMIDI Time Stateは、get または syncによって取得することが出来ます:

note, velocity = get (or sync) "/midi:[MIDIデバイス名]:[MIDIチャネル]/[MIDIイベント]"

getによる取得は、MIDI Time Stateにその時保持されている値を取り出すもので、syncによる取得はMIDI Time Stateが新しい入力によって更新されたときにその値を取得するものです。 また、MIDI Time Stateの名前はアスタリスク ( * ) によるワイルドカードを用いて指定することが出来ます。 これは例えば、MIDIイベントとMIDIチャネルを "*"に置き換えることによってあるMIDIバイスから入力される信号を全て受け取るといったように利用することが出来ます。

受け取ったMIDI入力を使用出来る形にする

基本方針は次の通りです:

Note On/Off

Note On/Offは今回スイッチ/トグル的な情報の取得 (例えば全ミュートや、乱数の更新) と、手でSFXを鳴らすために使いました。 下記のコードのように、Note On/Offでそれぞれスレッドを用意してそれぞれはON/OFFの入力をsyncで待ちます。そして、やってきたMIDI信号のNoteに応じて処理の振り分けを行います。n==1の場合の処理は、ON/OFFで連動していてONが押されてからOFFまでの間mute=trueとする処理。また、n==11の時はONが押されたら即座にサンプルを再生します。

live_loop:midion do
  use_real_time
  n,v = sync "/midi:midi_fighter_twister_2:1/note_on"
  if n==1
    mute = true
  end
[中略]
  if n==11
    sample fx2s,rand_i(fx2N)
  end
end

live_loop:midioff do
  use_real_time
  n,v = sync "/midi:midi_fighter_twister_2:1/note_off"
  if n==1
    mute = false
  end
end

Control Change

Control changeは、連続的な値の変化 (サンプルを鳴らす頻度、乱雑さ、リバーブの深さ、LPFなど) のために使いました。 ただし、SonicPiでは一度鳴った後の音に対して音を連続的に変化させることが出来ないことには注意が必要で、あくまでも各音を鳴らす時の設定を変化させるというところにとどまります。 Control changeも、MIDI ON/OFFと同じように受け取れますが、複数のノブを同時に回して同一チャネルにCC信号を送ったときMIDI ON/OFFと同じような書き方だと片方が取れなくなるのではないかと思うので [未検証]、今回は各16個のノブを回したときに別のチャネルにControl change信号が送られるようにし、それぞれを独立に受信します。 ただし、この場合に下記のようにsyncを使ってしまうと、ch1のControl change信号が来ないとそれ以降の信号が受け取れないようになってしまう。

live_loop:midicc do
  use_real_time
  _,v1 = sync "/midi:midi_fighter_twister_2:1/control_change"
  _,v2 = sync "/midi:midi_fighter_twister_2:2/control_change"
  _,v3 = sync "/midi:midi_fighter_twister_2:3/control_change"
end

そこで今回はやや無駄があるようにも思われるがgetによって信号を受信することにしました。ただし、getの場合は受信を待ってはくれないので別途sleepが必要となる:

live_loop:midicc do
  use_real_time
  _,v1 = get "/midi:midi_fighter_twister_2:1/control_change"
  _,v2 = get "/midi:midi_fighter_twister_2:2/control_change"
  [中略]
 if v1 != nil
    rbd = v1/127.0
  end  
  if v2 != nil
    rhh = v2/127.0
  end
  [中略]
  sleep 0.3
end

受け取ったMIDI入力を元にリズムや音を作る

今回はリズムの生成アルゴリズムの変数とエフェクトのパラメータの部分に主にMIDI信号を利用した。 明確な機能というよりは、お気持ち的に割り当てている変数が多いですが...下記が実際に行った機能割り当てです。

f:id:Raku_Phys:20211128174420p:plain
MIDIコンへの機能割り当て

ざっくりと各項目について書いていきます。

Control changeのパラメータ

各サンプルの頻度

今回のリズム生成の基本的な方針は、6つのサンプルグループと2つのシンセのいずれかを時間単位あたりひとつだけ鳴らすというもので、この8つのグループから各拍にどれを選択するかという頻度を8つのノブでコントロールします。例えば、1,2番目のノブだけを振り切るとバスドラとハイハットだけが鳴るといったような感じです。

1ループの音数

時間単位あたりひとつだけ音を鳴らすという方針の上では、各拍の音は独立、つまりループという概念は生まれませんが音楽的まとまりの導入(とエフェクトの負荷軽減)のため、いくつかの拍を1まとまりとして「1ループ」という概念を導入しています。ここでは、1ループに含まれる音の数を変更します。

ループのまとまり感

前項のようにループを導入してもそのままでは、各音は完全に独立です。 今回は音楽的なまとまりをかなりヒューリスティックに導入していて、この「まとまり感」変数をあげていくと、ループ先頭でバスドラが鳴りやすく、ループ中間でハットが鳴りやすくなり、逆にそれ以外の拍では鳴りづらくなっていきます。ループの音数が4のときは普通の四つ打ちに近づいていく感じですね。ループの音数を5や7にして変拍子を作り出すことも出来ます。

音程の広がり

今回音程のある楽器として、ベース、単音のシンセ、コードの三つが導入されていますがこれらのうちシンセとコードについて、ある割合でオクターブジャンプするようになっています。その割合をここでコントロールします。

サンプルの種類幅

各リズムサンプルグループ (バスドラ、ハイハット、クラップ、タム、パーカッション、グリッチ系) は、それぞれ複数のサンプルを持っています。この中からどの程度のバリエーションを取り出すかという部分がこの変数です。サンプルの順番として、おとなしめのものが前半に、激しめのものが後半にくるようにしておきます。

HPF/LPF cutoff

サンプルに対するHigh pass, Low pass filterのカットオフです。 ここで、他のエフェクトはループ単位でかけていますが、このエフェクトだけは各拍毎に更新しています。

バーブMIX

バーブのdry/wet割合です。今回はもともと深めのリバーブをかけておいて、dry/wetのmixだけでリバーブをコントロールすることにしています。

PAN

グローバルなPAN振りです。もともと各サンプルはある程度の乱数幅を持ってそれぞれPANが振られていますが、このノブを回すとその乱数幅が収束していって、振り切った時にはL/Rに偏るようになっています。

Note On/Offのパラメータ

MUTE

全ミュートです。ただし、SonicPiは既に鳴らした音をミュート出来ないので、実際には次の拍以降に鳴るはずの音を鳴らさないということをしています。このスイッチは押している間ずっとミュートで、NoteOffを受信したときにミュートを解除するという動作にしています。

ループ内seed固定

1ループごとに固定のseedを設定しなおすかどうかのスイッチです。1ループごとにset_random_seed [seed値]でseedを設定しなおすと、各ループではまったく同じ音が繰り返されることになります。これによって、例えば、1ループの音数が16の時は1小節のリズムパターンのように振舞います。逆にseedを設定しないときは、ループ間ではまったく別の音が鳴ることになります。

seed変更

これは、前項のループ内seed固定が有効な時に効果があります。ループ内seed固定をしているそのseedをこのボタンを押すたびに変更します。これによって、ループパターンを変更して好みのものを「ガチャ」出来るようになります。

Bass ON

これは主にエンコーダが足りないためにBassだけ独立させているだけですが、Bassはバスドラと連動させた動きが多いので、鳴らし方・頻度はバスドラの頻度パラメータに紐づけて、鳴らすかどうかをこのスイッチで決めています。

エフェクトON/OFF

今回は、bitcrusherと、ixi_technoの二つのエフェクトを用意しています。エフェクトのパラメータをいじるのではなく、単にON/OFFをするスイッチです。

SFX

その他のNote ON/OFFと違って楽器的な振舞いをします。ボタンを押したタイミングで、性質の違う3つのSFXグループからランダムなサンプルを選んでそれぞれ再生されます。

時間単位

最小時間単位の長さを変更します。例えば、最小時間単位が1のときに比べて1/4の時は4倍のテンポになるといった感じです。

まとめ

Sonic PiをMIDIコンで制御するために、MIDI入力を受け取る方法とそれを使った実際の制御方法例を示しました。 別の使い方としては、シンセサイザーのように各シンセのパラメータを変更したりするようにも使っている人が多いようですね *2。 最後に、参考までに全体コードを載せておきます。コメントも何もないのでかなり見づらいかもしれませんが... 改変等はご自由にどうぞ!

use_bpm 138

load_synthdefs "C:/Synth/my-synth"
set_volume! 5
bds = "C:/SPS/gc1127/bd/"
bdN = 2
hhs = "C:/SPS/gc1127/hh/"
hhN = 2
claps = "C:/SPS/gc1127/clap/"
clapN = 3
toms = "C:/SPS/gc1127/tom/"
tomN = 6
percs = "C:/SPS/gc1127/perc/"
percN = 54
glitchs = "C:/SPS/gc1127/glitch/"
glitchN = 30
fx1s = "C:/SPS/gc1127/fx1/"
fx1N = 3
fx2s = "C:/SPS/gc1127/fx2/"
fx2N = 3
revs = "C:/SPS/gc1127/rev/"
revN = 4
Ns = [3,4,5,6,7,11,16]
Ms = [0.25,0.5,3.0/4.0,1.0]
key = -4
bsl = [:C3,:C3,:C2,:C2,:C2,:C2,:C2,:C2,:C2,:C1,:C1,:C1,:C1,:Db1,:Db2,:G1,:G2,:Db3].ring
synl = [:C2,:C3,:C3,:F3,:G3,:Bb3,:C4,:Db4,:Eb4,:F4,:G4,:Bb4,:C5].ring
cdl = [:C4,:C4,:Eb4,:F4,:C5]

mute = false
fixseed = false
withbs = false
seed = 0
rbd = 0
rhh = 0
rclap = 0
rtom = 0
rperc = 0
rglitch = 0
rsyn = 0
rcd = 0
octr = 0.0
width = 0.6
gpan = 0.0
acc = 0
var = 0.0
rev = 0.0
hpfco = 0.0
lpfco = 0.0
N = 4
M = 1
ixi = 0
bit = 0

set_mixer_control! hpf:0,hpf_slide:0.5
set_mixer_control! lpf:127,lpf_slide:0


live_loop:metro do
  sleep 4
end

live_loop:loop1,sync: :metro do
  F = 4.0 - var*4.0
  fbd = 1.0
  fhh = 1.0
  it = 0
  if fixseed
    use_random_seed seed
  end
  with_fx :reverb,room:rev,mix:0.2+rev*0.8 do
    with_fx :ixi_techno,res:0.9,mix:ixi do
      with_fx :bitcrusher,bits:5,mix:bit do
        N.times do
          with_fx :rhpf,cutoff:hpfco,res:0.9 do
            with_fx :rlpf,cutoff:lpfco,res:0.9 do
              if not mute
                oct = 12*(5.0*octr*rand-1.0).to_i
                frbd = rbd
                frhh = rhh
                if it==0
                  frbd = rbd*(1.0 + 50.0*acc)
                else
                  frbd = rbd/(1.0 + acc*20.0)
                end
                if it==(N/2.0).to_i
                  frhh = rhh*(1.0 + 50.0*acc)
                else
                  frhh = rhh/(1.0 + acc*20.0)
                end

                rsum = frbd+frhh+rclap+rtom+rperc+rglitch+rsyn+rcd
                if rand<rsum
                  r = rsum*rand
                  if r<frbd
                    sample bds,(bdN*rand**F).to_i,amp:0.75,pan:gpan
                    with_synth:sine do
                      play 30,amp:0.75,pan:gpan
                    end
                    if withbs
                      with_synth :tb303 do
                        play bsl.choose+0+key,amp:0.4,release:0.3+0.1*rand,cutoff:60+70*rand if rand<0.8*(1.0 - acc)
                      end
                    end
                  elsif r<frbd+frhh
                    sample hhs,(hhN*rand**F).to_i,amp:0.75,pan:(gpan + 0.2 + (rand**0.5 - 0.2)*width).clamp(1)
                  elsif r<frbd+frhh+rclap
                    sample claps,(clapN*rand**F).to_i,amp:0.75,pan:(gpan + -0.2 + (0.2 - rand**0.5)*width).clamp(1),rate:1.0 + 2.0*(rand-0.5)*var*var
                  elsif r<frbd+frhh+rclap+rtom
                    sample toms,(tomN*rand**F).to_i,amp:0.9+0.2*rand,pan:(gpan + -0.4 + (0.4 - rand**0.5)*width).clamp(1)
                  elsif r<frbd+frhh+rclap+rtom+rperc
                    sample percs,(percN*rand**F).to_i,amp:0.3+0.8*rand*rand,pan:(gpan + width*(rand**0.5-0.5)*2.0).clamp(1),rate:1.0 + 3.0*(rand-0.5)*var*var
                  elsif r<frbd+frhh+rclap+rtom+rperc+rglitch
                    sample glitchs,(glitchN*rand).to_i,amp:0.3+0.8*rand*rand,pan:(gpan + width*(rand**0.5-0.5)*1.5).clamp(1),rate:1.0 + 4.0*(rand-0.5)*var*var
                  elsif r<frbd+frhh+rclap+rtom+rperc+rglitch+rsyn
                    with_synth :myssaw do
                      play synl.choose+0+key+oct,release:0.3+0.13*rand,amp:0.15+0.3*rand
                    end
                  elsif r<frbd+frhh+rclap+rtom+rperc+rglitch+rsyn+rcd
                    with_synth :dtri do
                      play chord(cdl.choose+key+oct,'m7'),release:0.2,amp:1.5
                    end
                  end
                end
                if withbs
                  with_synth :tb303 do
                    play bsl.choose+0+key,amp:0.3+rand*0.22,release:0.18+0.1*rand,cutoff:40+70*rand if rand<acc*rbd
                  end
                end
                with_synth :myssaw do
                  play synl.choose+0+key+oct,release:0.2+0.04*rand,amp:0.15+0.15*rand if rand<rsyn
                end

              end
              it += 1
              sleep 0.25/M
            end
          end
        end
      end
    end
  end
end

live_loop:midion do
  use_real_time
  n,v = sync "/midi:midi_fighter_twister_2:1/note_on"
  if n==1
    mute = true
  end
  if n==2
    fixseed = !fixseed
  end
  if n==3
    seed = seed + 7
  end
  if n==4
    withbs = !withbs
  end
  if n==5
    bit = 1.0 - bit
  end
  if n==6
    ixi = 1.0 - ixi
  end
  if n==9
    sample revs,rand_i(revN),amp:1.5
  end
  if n==10
    sample fx1s,rand_i(fx1N)
  end
  if n==11
    sample fx2s,rand_i(fx2N)
  end

  if n>=13
    M = Ms[n-13]
  end
end

live_loop:midioff do
  use_real_time
  n,v = sync "/midi:midi_fighter_twister_2:1/note_off"
  if n==1
    mute = false
  end
end

live_loop:getmidicc do
  use_real_time
  _,v1 = get "/midi:midi_fighter_twister_2:1/control_change"
  _,v2 = get "/midi:midi_fighter_twister_2:2/control_change"
  _,v3 = get "/midi:midi_fighter_twister_2:3/control_change"
  _,v4 = get "/midi:midi_fighter_twister_2:4/control_change"
  _,v5 = get "/midi:midi_fighter_twister_2:5/control_change"
  _,v6 = get "/midi:midi_fighter_twister_2:6/control_change"
  _,v7 = get "/midi:midi_fighter_twister_2:7/control_change"
  _,v8 = get "/midi:midi_fighter_twister_2:8/control_change"
  _,v9 = get "/midi:midi_fighter_twister_2:9/control_change"
  _,v10 = get "/midi:midi_fighter_twister_2:10/control_change"
  _,v11 = get "/midi:midi_fighter_twister_2:11/control_change"
  _,v12 = get "/midi:midi_fighter_twister_2:12/control_change"
  _,v13 = get "/midi:midi_fighter_twister_2:13/control_change"
  _,v14 = get "/midi:midi_fighter_twister_2:14/control_change"
  _,v15 = get "/midi:midi_fighter_twister_2:15/control_change"
  _,v16 = get "/midi:midi_fighter_twister_2:16/control_change"
  if v1 != nil
    rbd = v1/127.0
  end

  if v2 != nil
    rhh = v2/127.0
  end

  if v3 != nil
    rclap = v3/127.0
  end

  if v4 != nil
    rtom = v4/127.0
  end

  if v5 != nil
    rperc = v5/127.0
  end

  if v6 != nil
    rglitch = v6/127.0
  end

  if v7 != nil
    rsyn = v7/127.0
  end

  if v8 != nil
    rcd = v8/127.0
  end

  if v9 != nil
    N = Ns[(7.0*(v9-1.0)/127).to_i]
  end

  if v10 != nil
    acc = v10/127.0
  end

  if v11 != nil
    octr = v11/127.0
  end

  if v12 != nil
    var = v12/127.0
  end  

  if v13 != nil
    hpfco = v13
  end

  if v14 != nil
    rev = v14/127.0
  end

  if v15 != nil
    gpan = 2.0 * (v15/127.0 - 0.5)
  end

  if v16 != nil
    lpfco = v16
  end
  sleep 0.3
end

*1:MIDIバイスを入力した順番によって、名称の末尾の数字が変更されうるので注意が必要です。

*2:Nikoさんとか寝る前さんとか

VRC_SpatialAudioSourceの音響特性

またまた、VRC_SpatialAudioSourceの話。 毎回もう使わないって言ってる気がするけど、代替を考えるためには良く知る必要がある...。 今回は、そもそもVRC_SpatialAudioSourceってどのぐらいちゃんと「Spatialization」してるんだろうかという話。 ドキュメントには逆二乗減衰しか書いてないので本当にわからない。

角度に対する応答の検証

Head-related transfer function (HRTF) の畳み込みなどのちゃんとしたSpatializationの効果が入っているとすると、前後左右上下で周波数特性に差が出るはず。さらに左寄りまたは右寄りの位置の音源に対しては、波が左右の耳に到達するまでの時間差から左右位相差が現れるはず。これらを確かめるため、VRChatで記録したデータからVRC_SpatialAudioSource有/無の場合を比較する。

実験は前後左右上下の6つのAudioSourceから、ホワイトノイズを発することによって行う。体の向きによってAudioSourceと受聴点の関係が変わらないように、常にプレイヤーの頭に全てのAudioSourceが追従するようにU#Scriptで制御した。また、Spatializationが非有効かつSpread=0のとき、左90度の音源に対して右側での音量は0となるが、比較の分かりやすさのため、Spread=70まで上げて、音源と反対側のチャネルにおいて、Spatializationが有効の時と同程度のゲインが得られるようにした。

周波数特性

まずは周波数特性から。図は左チャネルについて2D-Audioに対する各周波数帯域でのゲイン比を示す。 Spatializationが非有効の場合、レベル差は現れるものの周波数特性は全く変化しない。一方、Spatializationが有効の場合、1000Hzより上の帯域で音源方向によって異なる周波数特性が見られる。特に、4000Hzから10000Hz付近に見られる大きなノッチが特徴的だがこれはスペクトラルキューと呼ばれるもので、人はこの高域に表れるノッチやピークの変化から音源の方向を捉えていることが知られている。

f:id:Raku_Phys:20210710202925p:plain
ホワイトノイズに対する周波数応答。(上) Spatialization非有効。(下) Spatialization有効。

位相差

次に、左右の耳の位相差を調べる。図は右チャネルの位相から左チャネルの位相を引いた位相差の時間平均を示している。これを見ると、Spatializationが非有効の場合は左右の耳の間でまったく位相差がない一方で、Spatializationが有効の場合位相差が現れているのがわかる。ここでは、位相差の物理的妥当性までは検討しないが、少なくともLeft/Rightで位相が逆転していることはもっともらしい。こうした、低域における左右耳の位相差も、人が音源方向を認知する上で重要であることが知られている。

f:id:Raku_Phys:20210710205100p:plain
左右チャネルの位相差。(上) Spatialization非有効。(下) Spatialization有効。なお、高域の位相差は空間エイリアシングの影響で、意味を持たないため1000Hzまでを示している。

距離に対する応答の検証

距離による周波数特性の変化を調べる。実験は、プレイヤーの正面方向、0.1, 0.5, 1.0, 3.0, 10.0, 30.0mの6地点に配置したAudioSourceから発したホワイトノイズを記録することによって行う。

周波数特性

図は、音源距離を変化させたときの、周波数応答を示している。ごく近接では高域のノッチが浅くなりフラットな周波数分布となっているのに対して、離れた距離では高域に深いノッチが現れることがわかる。逆に3m以降ではほとんど周波数特性は変化していない。これは頭部の大きさに対して十分離れているためと考えられる。

f:id:Raku_Phys:20210710214427p:plain
音源距離を変化させたときの、ホワイトノイズに対する周波数応答。

まとめと感想

今回は、そもそもVRC_SpatialAudioSourceってどのぐらいちゃんと「Spatialization」してるんだろうか、ということでVRC_SpatialAudioSourceの角度と距離に関する応答を調べた。 あまり信用していなかったが、やってみるとそれなりにちゃんとHRTFをシミュレートしているらしいことがわかった。 これでなんでドキュメントに逆二乗則ですとしか書いてないのか理解できない。

全然ダメだったら代替を考えるかと思ったが、こうデータを見ると使わないのは勿体ないと思わざるを得ないので悩ましい...。特に位相差を手で入れるのはかなり困難...。 あと、今回色々と音を比較していて思ったのは、もしSpatializationを有効にするのであればそれを前提として音作りをする必要がありそうということ。 イヤホンで聴いて音を作ると、つい耳に馴染むように外から聴こえてきたような音を作ってしまいがちだが、それをしてしまうと二重で頭部の影響を受けたようなものになってしまって音がぼやけてしまうかもしれない。音を作る時は、Spatializer的なプラグインを入れながら最終的な聴こえを確認しつつ進めるのが良さそうだと思う。

VRC_SpatialAudioSourceのクリックノイズ問題

今回もVRChatでの立体音響等について.次のツイートのように,VRC_SpatialAudioSourceの"Spatialization"を有効にしたときにだけ音の鳴り始めでプツっとなる問題を検証.

結論

親オブジェクトRigidbodyコンポーネントが付いている時に、その子オブジェクトとして配置されたVRC_SpatialAudioSource付きのAudioSourceUdon経由で鳴らすと、音の鳴り始めにクリックノイズがのる。

検証

Time.deltaTimeで時間を測って、AudioSourceを1秒毎に鳴らすU#ScriptでAudioSourceを鳴らす。 片方 (左側) は直置きのAudioSource、もう片方 (右側) は親オブジェクトにIs Kinematicのrigid bodyを付けた。 結果は動画のように、rigid bodyを付けた方だけ2回に1回程度の頻度でクリックノイズが乗った。

using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;

public class Test_spatialaudio : UdonSharpBehaviour
{
    public AudioClip clip;
    public AudioSource source;
    private float t;
    private void Update()
    {
        if (t > 1.0f)
        {
            source.PlayOneShot(clip);
            t = 0.0f;
        }
        t += Time.deltaTime;
    }
}

解決策

AudioSourceの親オブジェクトにRigidbodyを付けるのは、Pickupオブジェクトから音を鳴らすなど、音をあるオブジェクトの動きに追従させたい時。 なので、追従を親子関係ではなく、Script経由で行えば、親オブジェクトにRigidbodyを置くことを回避し、クリックノイズを避けることが出来る。

さいごに

VRC_SpatialAudioSource、ひとまず目に見えた問題は回避されましたが他にもどこに地雷が潜んでいるのかわからないのでちょっともう触りたくないですね...。

一応検証に使ったワールドを置いておきます。

https://vrchat.com/home/launch?worldId=wrld_095d2450-a9b3-482e-ac7a-8552a1e804e3&instanceId=77423~private(usr_08f6abeb-183b-463e-b355-53978f61b24d)~canRequestInvite~region(us)~nonce(e81eb2a7-2ab0-474b-8e19-def0946c6fc2)

雑記20210617

あれだけハードルを下げておいて1か月以上空くという本末転倒感ですが...Audio Source回りで謎の挙動があったのでまとめておきます.

やりたいこと

2Dと3DのAudioを連続的に切り替える. 使い所は色々あって,例えば音の発生源の近くでは音の定位感が強いけど,離れれば反射でほぼ等方的に聴こえるとか.後は単純に演出として,「何か」が環境に拡散した感じを出したいとか.

問題点

Unity の 3D Audio Source にはSpatial Blendのプロパティがあって 2D/3D のスライダーになってます.Unity上ではただこのスライダーをC#等々で目的に応じて動かしてあげれば素直に動いてくれました.

しかし,Unity上で素直に動いているこれをVRChatに持っていくと妙な挙動になりました.

  • 距離減衰は2Dになると消えてどこまでも聴こえるようになる
  • 3Dによる効果はそのまま残る.モノラルでかつ定位感のある音が聴こえる.

どうやらVRChat上に運んだ時に何か変な処理が入るようです.

原因

VRChat上に運んでおかしくなるということは,VRC Spatial Audio Sourceに関連する事項である感じがします. 上の問題が起きたとき,VRChat Spatial Audio Sourceコンポーネントはつけていませんでした. それで,VRC Spatial Audio Sourceには,「Enable Spatialization」というチェックボックスがあります.

これは,名前の通りSpatialization (3D効果) を有効にするかどうかです.これがチェックボックスなので2Dから3Dに連続変化させるような場合にVRC Spatial Audio Sourceは付けたらダメなのではと思っていたのですが,これが結果的には誤りでした.

解決

2Dと3DのAudioを連続に切り替えたいときは,

  1. VRC Spatial Audio Sourceを付ける
  2. VRC Spatial Audio SourceのプロパティでEnable SpatializationをDisableにする
  3. Audio SourceのプロパティでSpatial Blend を動かす

これで動作しました.Enable SpatializationをDisableしても3Dにすると,Unity Audio Source標準の3D Audioにはなるようで...(なんだそれ). こうしないと,上手く切り替わってくれませんでした.

さいごに

2Dと3DのAudioを連続に切り替えるお話でした.使う人いるのかな...いないかもしれない.... もし使う場合は,検証漏れとか全然ありそうなので上手くいったりいかなかったりしたら教えてください.

それではまた,何か書くことが出来たら書きます.

雑記20210512

この雑記は、少し試してみたいことが出来たときに、それを手短にまとめて置いていこうと思っているものです。 最近時間が分断気味な状態がしばらく続いているので、ちょくちょくと手を動かす理由付けとしてはじめてみました。 身の回り (極めて局所的) で良く書かれている「日記」に触発された部分は多分にあると思いますが、題材としてその日あったことを取り上げるつもりでは今のところありません。目下は、この雑記を書こうと思った発端の一つでもある、Unity/VRChatの3D Audioについてちまちまと調べものをしたり、検証したりして書いていきたいと思っています。 ある程度継続して続いて、それなりにまとまったらタイトルのついた記事になるかもしれませんが。今のところは未定です。三日坊主で終わる可能性もなきにしもあらずなので。

Unity/VRChatの3D Audioわからんの話

雑記のハードルを下げるためにも、今日はわからんという話だけを書こうと思います。 3年ほどではありますが...しばしばUnity/VRChatで3D Audioを触ってきましたが、よくわからんな?と思いながら都度調整してきた部分が色々とあります。 特に、VRC_SpatialAudioSource は、毎度雰囲気で使っているところがあります。 (あるいは使ってません...。)

ドキュメントを見るぐらいのことはしているんですが、あんまり詳しいことは書いていないようです。 Spatializationに関連する事項として書かれているのは逆二乗減衰ぐらいのようですが、まさか音量を調整する処理しか入ってないということはないでしょう。 実際、音量が距離で変わるだけであれば、自分の前方の音源と後方の音源は区別が出来ないはずですが、VRChat上でVRC_SpatialAudioSourceを付けた音源はその区別があると信じています (そう感じてはいるんですが、厳密に波形を比較したりはしていないの意味)。人間が、前方の音と後方の音を区別出来るのは、耳や頭の形が前後対称でないからです。このような人間の頭部構造に由来する音の伝達の違いは頭部伝達関数 Head-Related Transfer Function (HRTF) によって表現されますが、VRC_SpatialAudioSourceが前後を区別出来るものであるとするならば、そういった効果が (どんな程度であれ) ある程度含まれていることになります。また、現実をシミュレートしているのだとすると、空気を通過することで高音の方が素早く減衰する効果を反映するために多少ローパスフィルタがかかっているかもしれません。

VRC_SpatialAudioSource以前に使われていた、ONSPAudioSourceについては、公式で説明があるように、上記のようなSpatializationの効果は十分に実装されているようです (VRChat内でどの程度動いていたのかはわかりませんが...)。VRC_SpatialAudioSourceもこれを引き継いでいるものと思っているのですが、明確な記述は見つけられていません (もし知っている人がこれを見ていたら、良かったら教えて下さい)。仮に完全にONSPだと同じだとして、実際VRChatでどう動作しているのかは、いくらか検証しておきたいところです。

今のところ思いついている確認したい項目は次のようなものです:

  • HRTFの効果は入っている? (前後の区別は、思い込みではなく本当についているか?)
  • 距離減衰についてどんな効果が含まれているか。
  • VRC_SpatialAudioSourceをつけなかった場合は何が変わるか。
  • Unity上での再生とVRChat上での再生は違うように感じる (VRC_SpatialAudioSourceはUnity上で動いていない?)。何が違うのかは確認しておきたい。
  • VRC_SpatialAudioSourceを付けた場合に、Unityの標準のAudioのパラメータの影響のかかり方はどのように変化するか (あるいはしないか)。

今後の雑記ではこのあたりを、少しずつ調べられたらと思っています。 場合によっては実験をするという方向ではなく、ソースを探して読むという方向になるかもしれませんが。