UnityでAudioLiveCoding

上の動画を見て「すげえ!音ってこんな簡単に生成できんの!」
と興味を持ったのでちょっとやってみようと思った。
しかし探してもライブコーディングできそうな既存の環境がなさげ。
以前にUnityで波形を生成するという記事を見たことがあったので、
Unity使ってライブコーディングするおもちゃを作ってみました。

livecoding-audio

Unity Web Player | livecoding-audio

イカ実装についてです

ランタイム上でコードを実行する

UnityにはLivityというエンジン上でコード編集ができ、
即反映できるアセットがあるらしい。

Unity でライブコーディングを実現するアセットLivity

けどどうせならランタイム上で動かしたい。それにタカイし・・
なのでこのアセットを使うのは今回は見送りに。

僕は普段C#でコーディングしてるので、C#でコード実行できないかなーと調べてみたら

プログラミング/C#/C#で書かれたスクリプトを実行する

CSharpCodeProvider を用いてコードのコンパイルが行えるらしい。
おまけにexeも吐けるとか。今回の目的ではないけども便利そう。

しかし、残念なことに

Unity Script Reference – Mono Compatibility

上記のページで実行可能環境見てみると
compatiblility

.NET 2.0環境でしか動作しない模様・・
WEBを切り捨てるならいいと思いますが、
どうせならWEB上で気軽にできたらいいなーと思ったので
これを用いての実装もやめました。

あとはJavaScriptでの実装ですが、
JavaScriptにはevalがあったような・・ためしに書いてみたら

var code = "Debug.Log( 'Hello Sayaka-chan!' );";
eval( code );

hello

つかえた。

Unityのあらゆるコードがかけてしまうので
セキュリティー的にはあやしい気がしますが見なかったことにします。
(ほんとはちゃんと構文解析して自前でやったほうがいいのかな?)
ということで今回はJavaScriptのevalを使って実装してみます。

C#とJavaScriptの連携

JavaScriptを使うといいつつもやっぱ使い慣れてるC#で実装は行いたいので
コード実行部分はJavaScript、他はC#で実装したいところ。
そうなるとJavaScriptとC#の連携を行う必要がありますが、結構楽でした。

[Unity] JavaScriptとC#間のアクセス

  • 呼び出される側のスクリプトをAssets/Plugins以下に置く
  • 呼び出す側、呼び出される側のスクリプトを任意のGameObjectに追加
  • GetComponentでスクリプトを取得し、操作する

Assets/Plugins以下に置かなくてはならないのが管理の都合上めんどくさいですね。
呼び出し自体は特に不自由なくできるみたいです。
関数やpublicなメンバへのアクセスもできました。

波形を作って鳴らす

肝心のどうやって音を鳴らすのかですが、
MonoBehaviour.OnAudioFilterRead(float[], int) を用います

Unity Script Reference

本来は出力されている音にリアルタイムにエフェクトをかけるためのものらしいですが、
なにも出力されていない状態でもこの関数経由で音を生成することができます。

■[Unity][Unity3d]音データをジェネレートする(頑張ればファミコンのピコピコ音も作れるよ)

先ほどの動画のような記述をすることを目標に、実装してみます。
以下、関連部分の抜粋です。


public float mTime = 0.0f;
public float mFrequency = 261.62f;
public float mSampling = 48000.0f;

void OnAudioFilterRead( float[] data, int channels )
{
  for( int i = 0; i < data.Length; i += channels )
  {
    float t = (mTime+i) / mSampling;
    float w = Mathf.PI * 2.0f * mFrequency;
    data[i] = Mathf.Sin( w * t ) * 0.5f;
    for( int k = 1; k < channels; k++ )
    {
      data[i+k] = data[i];
    }
  }
  mTime += data.Length;
}

OnAudioFilterReadが呼ばれるたびにバッファにデータを詰め込んでいきます。
複数チャンネルある場合は同じ音をコピーしておきます。
あとはデータをつめた分時間を進めておしまい。
これで正弦波がつくれました。アラ簡単

上記のスクリプトをカメラなどAudioListenerを持っているGameObjectに追加すると音がでます。

今まで音作りとは無縁だったので自分で音がだせるとわりとうれしいですね。

この波形計算の部分を外部に出して編集可能にしてみます。

ちょっと長くなったので続きはまた別の記事で!


コメントを残す

メールアドレスが公開されることはありません。