くろっくのおぼえがき。

個人開発関係の話を書きます。

Unityで世界初のバーチャルモノサシストになる

f:id:clock_v:20201224104333p:plain

はじめに

こんにちは。くろっく(@clock_v)です。
先日Twitterの方で色々と情報を出しました、"MONOSIMULATOR"(通称:バーチャルモノサシ)に関して、開発時のこと、裏話などいろいろと書いておきます。
よく考えたらアプリの操作説明さえもどこにも載せてないのでちゃんと書かなきゃね(多分別記事にするけど・・・)。
ということで以下本題です。

※今回の記事ではソースコードの一部のみ、或いはそれらを少し改変したものを載せました。というのも一部変数に人の名前が入っていたりして、全文をそのまま掲載するのはあまり気が進まないためです。各機能に必要な部分だけ掲載しています。

モノサシストってなんだよ

一般人からするとモノサシストってなんだよっていう疑問が最初に来ますよね。こういう人たちです。


ちなみに2つ目の動画には私も出ています(小声)

こんな風に、定規(主にステンレス製)の台からはみ出した長さを変えながら弾いて音階を表現するのが定規演奏、そして定規演奏のパフォーマーのことをモノサシストと呼ぶわけです。

これスマホで出来たら面白くね?という話が一時期盛り上がりまして、おれおさん(@mono_oreo)メロスさん(@merosu_215)の協力により今回の開発に至りました。さらにはVtuber桃空しいなさん(@v_momosorasiina)に実際に使っていただいたりしてます。こちらでもプロトタイプ公開中です。

公開当時のTwitterでのお知らせがこちらです。スレッドも続いていますので良かったら覗いてください。

2020/12/25追記
各サイトにデモ動画をアップロードしました!
YouTube
https://www.youtube.com/watch?v=dA2EdaNoI4Q
ニコニコ動画
【定規】世界初のバーチャルモノサシストになってみた【作って演奏してみた】【くろっく】 - ニコニコ動画


開発前日譚

ちょうど夏休みの頭にUnityの教科書(いわゆる猫本)を2日で速習し、何か作りたいなあと思っていました。
実はバーチャルモノサシは数年前、先述の話が盛り上がったときに作ろうとして挫折した経験があり、そのほったらかしにしてたファイルを偶然見つけてしまったのです。
当時はちょっとC#の基本文法が読める程度の知識しかなく、プログラミングの腕はカスだったのでよく調べもせずに投げ出していました。

そもそも定規みたいに音程変更なんてできるわけないやろ・・・ゲームエンジンやぞ・・・と思いつつUnityの音周りを漁った結果、
pitchパラメータ
なんですかこれ。
いやどう見てもpitchって書いてあるじゃん。
これは作るしかねえな!!!!!!!!!!!!

開発開始

やったこと、実装した機能としてはこんな感じ。

  • 定規を作る
  • タップした時に音が鳴る
  • 定規を移動できる
  • タップ判定を定規に追尾させる
  • 定規の位置が音程に反映される
  • 2点タップ(定規を移動させる手と弾く手を区別して認識)
  • 音色を複数扱う
  • そのほか

定規を作る

そもそも定規無いじゃん!!!!!!!!!!ということで作ります。
私含め多くの場合、モノサシストは演奏台としてガラス製の鍋敷きを敷いています。ちなみに大体この定規と鍋敷きです。

初期投資1000円かからずに始められるんですよ。
こんなお手軽な趣味他にありませんよね?(巧妙なステマ)

というわけで両方blenderでつくりました。
制作した定規と鍋敷きのモデル
モデルと実物の比較
上がモデル、下が実物になります。
結構再現度はこだわりました。満足の出来です。
実際にはこの後これにMaterialで金属光沢を付けていきます。
これで必要なモデルはそろったので、コードを書き始めることにします。

タップしたときに音が鳴る

定規演奏の基本ですね。定規を弾いたら音が鳴る。
手順としては、

  1. タップを検出
  2. AudioSource.Play()の呼び出し
  3. AudioListenerで取得

の3ステップになります。プ〇アクティブみたいですね。
ではタップの検出から。スマホなどは画面が小さく、定規も必然的に面積が小さくなってしまう・・・そう思いUIのPanelを画面半分に配置しそれを利用してタップ判定をすることにしました。EventTriggerコンポーネントをPointerDownで使ってみたところだいぶいい感じに判定してくれてよかったです。
Panelを設置
ここから音を鳴らしていくわけですがUnityって便利ですね。.wavファイルを適用して.Play()するだけで音が鳴りました。やったー。
あとはAudioListenerを鍋敷きの縁、定規の真下の部分に置いてこの部分は完成です。

    public void soundPlay()
    {
        Debug.Log(mySlider.value);
        monoSound.Play();
    }

定規を移動できる

これについては一番簡単なやり方を取りました。UIのSliderの値を定規の座標(transform.position)に連動させるだけ。Slider自体がちょっと動かしにくかったのでつまみ部分の大きさをちょっと細長くしました。
Sliderを設置

    public Slider mySlider;
    float pos, initialPos;

    Vector3 myPos;

    // Start is called before the first frame update
    void Start()
    {
        myPos = this.transform.position;
        initialPos = this.transform.position.z;
    }


    // Update is called once per frame
    void Update()
    {
        pos = initialPos + mySlider.value;
        myPos.z = pos;
        this.transform.position = myPos;
    }

タップ判定を定規に追尾させる

これはどういうことかというと、演奏動画でもわかるように実際の定規演奏では定規の"先端部分"を弾くため、半面パネルどこでもOK!というのでは定規演奏感がちょっと薄れてしまうんですよね。というわけでモードを分けてどちらも選べるようにしてみた次第です。

方法としては定規の先端部分に透明にしたCubeを配置し、それに対して上のPanelのようにタップ判定を与える、という形です。これもEventTriggerで実現できました。便利。

で、そのCubeの移動についてなんですが、これはLocalPositionで常に定規に対して一定の位置にするような設定を使うことで実現できます。前に書いたtransform.positionっていうのは空間内での座標になるんですが、こっちは定規を原点として空間を考えたときの座標みたいな感じですね。

これでやってみたところ、無事追尾とタップ判定が実現できました。
Cubeを設置

定規の位置が音程に反映される

はじめに、で触れたpitchくん、ようやく登場です。優秀なUnityくんはpitchの値をいじれば読み込んだ.wavファイルをbpmを変えて流してくれます。つまり基本になる音を決めて、そのpitchの値(=再生速度)を上手く操作すればいい感じに音が変わってくれるわけです。

じゃあどうやってそのpitchの変え方を上手く定義するか。録音して分析するのがよさそうですね。
自分でも少しやってみましたが、近似できそうな雰囲気はありました。ただ今録音環境がなくなってしまったんですよね・・・

そんなわけで知り合いモノサシストの中でも音程が正確で録音音声もきれいな2人、おれおさん(@mono_oreo)メロスさん(@merosu_215)に連絡。「1cm,2cm,...,10cmまで1cm刻みで音録音してその.wavファイルください!」とお願いしたところOKを頂きました。本当にありがとうございました...!!!

頼む、こっちでもいい感じに近似できてくれ・・・と祈りながら周波数分析をかけます。
Excelをポチポチしながらグラフを描いてみたところ・・・

グラフ1
グラフ2

なんですかこの奇麗さは??????

あんまり奇麗にならなかったらどうしようとか思ってた自分の不安を返してほしいくらい奇麗な並びしてます。一発で決定係数0.9993って何だよ。たけーよ。無駄に洗練された無駄に正確な無駄のない無駄な動きみたいになってます。

超奇麗に並んでくれたのでここではとりあえず片方だけ、Excelくんが教えてくれた数式をTap.csのUpdate()内でピッチの値に適用し、ここの作業は終了です。

    void Start()
    {
        monoSound = soundPlayer.GetComponent<AudioSource>();
        cor = (float)(coeff * Mathf.Pow(5, ord)) - 1.0f; // 補正項
    }

    // Update is called once per frame
    void Update()
    {
        monoSound.pitch = (float)(coeff * Mathf.Pow(mySlider.value, ord)) - cor;
    }

ちなみに上での補正項というのは、どうしても生じるfloat範囲での累乗計算のずれを軽減するものです。xのa乗の形ゆえに変化が急になる部分ではこのずれが地味に操作感に影響するので・・・

 一応音が変になってないかテストしないと・・・と思い実行。結果は・・・

 

 

 

 

全 く 違 和 感 が あ り ま せ ん 。 最 高 。

 

 

 

Update()はフレームごとに中の動作を実行してくれるので、再生中に定規が動いても音程が変わってくれます。

ここまででほぼ定規になりました(?)。

2点タップ

ここは先人の知恵です。
qiita.com

音色を複数扱う

上でも述べたように2人分の音源を頂いたので、両方実装したいなということで。
勿論音程変更の近似式もそれぞれで設定します。

タップしたら音が鳴る、のところでAudioSourceっていうのがありましたが、アレに読み込ませるファイルをスクリプトとUIで指定するだけでした。ここはそんなに大きな問題ではなかったですね。
ToggleのON/OFFで音が変わるように分岐させてここは終了です。

    void Update()
    {
        if (!soundToggle.isOn)
        {
            monoSound.clip = soundA;
            // 音程変更、補正項などの処理
        }
        else
        {
            monoSound.clip = soundB;
            // 音程変更、補正項などの処理
        }
    }

 

そのほか

そのほかにやったことはこんな感じです。

  • スライダーの位置を変更できるToggleの設置
  • 画面サイズが変わったときの対応
  • タップしたときにエフェクトが出る

だいたいこの辺を実装してほぼ今公開してる状態になりました。

最後に残った問題

上で見てきた通りこれタップ操作前提なんですよ。
つまるところ、スマホアプリにしたかったんですよね。
でも実は配布ってお金かかるんですよ。
某有名な林檎さんでは年1万ちょいとか。きついなあ・・・
泥もラグが激しいから演奏向きじゃないし・・・

 

...........せや!!!

 

というわけでWebアプリとしてUnityroomに公開することとしました。
unityroom.com
MonoSimu!prototype | フリーゲーム投稿サイト unityroom

iPadなどでのアクセスがやりやすいと思います。
よかったら遊んでね。
(UnityのSwitch Platformめちゃくちゃ便利だった・・・)
感想などを #バーチャルモノサシ でツイートしてくれると嬉しいです。
 

今後について

まだまだ実装したい機能もあるので当然ながら開発は続けていきます。
あと実はAndroidなら配布できなくもない状況ではあるんですよね。そのうち配布するかもしれません。

最初の方のツイートにもある通り実はVtuberさんにも使っていただけるみたいでして・・・

開発者より上手です。
みんなもしいなちゃんを推そうな。

そんなわけでざっくりと、こんな感じで制作してたよーっていうのを書いてみました。
記事書くのも初めてなので分かりにくい部分はあるかもしれませんが大目に見てください。
また何か作ったりしたら記事書くかも。でわでわ。

初参加LT会で登壇者になってバーチャルモノサシを語った話。

この記事は2020年12月13日に開催された#stdout2020という学生限定のLT会の参加レポです。
イベントの詳細は以下をご覧ください。
f:id:clock_v:20201217193142p:plain
joken-nuce.connpass.com

はじめに

こんにちは。くろっく(@clock_v)です。
先日開催された学生限定LT会#stdout2020に登壇者として参加し、バーチャルモノサシについて語らせていただきました。
自分はガチの初LT会(観覧ですら参加したことがない)だったのでめちゃくちゃ緊張しました。
というか初回から登壇しようとするなアホが。
当日のアーカイブYouTubeに残っていますのでよかったらご覧ください。自分は1:07:30前後から喋ってます。

なんで登壇したの

今年の10月にサポーターズ様主催のオータムハッカソンなるものに参加したのですが、そこで今回の主催者さんのひとりであるカズ之助さん(@Tech_Kazu)と偶然ご一緒しました。そこでTwitterをフォローしておいたところ、こんなツイートが・・・


思えばこれをリツイートしたのがすべての元凶でした。
当初は人数があまり集まっていなかったようで、LT会に少し憧れのあった私は「この規模感なら乗り込めるやろ!www」と思い軽率に参加を決めました。まさかの登壇者で。
いや~LT会って参加者全員何か喋るもんだと想像してたんですよね。だから何かしなきゃなって。アホ。
そして開催数日前に来た連絡のメールを確認したところ、

登 壇 者 1 8 名

はい。

話題の決定と資料作成

自分はそもそも制作物がバーチャルモノサシしかないので話題は自動的に決定。ここから資料作成が始まりました。
最大の課題は「モノサシスト」というニッチもニッチな界隈をどうやって紹介するか。
ここがうまくいくかがバーチャルモノサシをプレゼンするうえで最重要項目でした。
出オチでもいいからインパクトが欲しい、そう考えた結果が・・・

タイトル詐欺でした。

「身近なものをバーチャル化して遊ぶ話(仮)」として始め、定規演奏の映像をぶっこんでいい感じにそっちの話に持っていこう。そんなこんなでできた資料がこちらです。
drive.google.com
協力してくださった方々から名前や動画をきちんとお借りできたのがよかったなあと思います。
桃空しいなさん(@v_momosorasiina)のデモ動画はだいぶ印象を残せたみたいです。
本当にありがたかった・・・。




当日

あまりの緊張にPC前とトイレの間を往復しまくってました。あと実は発表時間を把握したのが当日朝とかだった(5分だと思ってたら10分だった)ので時間調整に震えていました。
他の方々は研究の紹介などガチなやつが多く、非常に面白かったです。
自分はだいぶニッチな無駄開発の話を持ってきてしまったので、「あれ雰囲気間違えたか!?!?!?」と少しだけ焦っていたりしました。
モノサシの受けやいかに。

意外とみなさんご存知!!!!!びっくり!!!!!
正直めちゃくちゃ浮きそうだなあと想定してたので、興味を持っていただけて本当に嬉しかったです。

こだわりポイントにも反応いただけて涙が出そうでした。
そんなこんなで無事自分のターンを終え、皆さんの熱弁を聞きながら第1部の残り、そして第2部を終えました。
ベラルーシ・・・行きたいなあ・・・。

闇の懇親会

学生の集まりの醍醐味。やっぱり同じ界隈の人とお話しするのは楽しいですね。
ちなみに僕はちょくちょくガチプロのお話を聴くbotになっていたりしました。
っょっょえんじにあこわい。
部屋が4つほど準備されていて、好きに動いて喋る、という形式でした。
割と自由にお話しできた感じはありましたね。一部の部屋がめっちゃ肥大化したりしてて笑いました。
一部屋4~5人以下のときが特に話しやすかった印象。
面白い方が多く、今後も交流の機会があったら嬉しいなあ、などと。
来年あたり自分も酒カス側で楽しみたいですね。

さいごに

今回のLTを企画運営してくださったカズ之助さんマヤミトさんありがとうございました!
後先考えない参加でしたが雰囲気も和やかで、「ああ、あのとき課題投げ捨ててよかったなあ」と思えるくらい楽しかったです!
#stdout、ものづくり初心者がアウトプットをするための神環境かもしれません。
学生が運営してるのもあって、精神的なハードルは非常に低い感じがしました。

次回も(あれば)参加したいなあ。#stdout2021、待ってます・・・!(進捗を生まねば・・・)



それでは本当に最後に。


定規は楽器です、これだけでも覚えて帰ってください。

はじめまして。

はじめまして。くろっく(@clock_v)と申します。

大学生になったので、きちんと制作に本腰を入れたいなと思いその記録及び覚え書きとしてブログを開設しました。
基本的に内容は開発録とかになるかな、と思います。
そのうちポートフォリオサイトも作りたいな。折角フロントエンドのお勉強やったし。
開発や創作などのお知らせを流すためのTwitterアカウントも別に開設してます。よかったらこちらもフォローしてください。こっちのほうが静かなのでおすすめです。
twitter.com


正直開発記録なんてTwitterでいいじゃん、と思っていたのですが、140字ごとでは込み入ったお話はできませんし、どんどん情報も流れてしまうのでこの形を取ることにしました。決して僕がツイ廃で情報流しても日常ツイートで埋もれるからではありません。

そんなわけでよろしくお願いします。