JUCEで作るUnity Native Audio Plugin

# JUCEって何？

JUCE (Jules' Utility Class Extensions)は、C++言語によるマルチメディア系アプリケーションの開発を支援するフレームワークです。クロスプラットフォーム設計のライブラリと、付属されているプロジェクトジェネレータ『Projucer』から各種IDE(VisualStudio, Xcode, Makefile)向けにプロジェクトファイルを出力することで、ワンソースからWindows, macOS, Linux, iOS, Android で動作するアプリケーションを作成することができます。
[公式サイト](https://juce.com/)

JUCEの最大の特徴として、オーディオプラグインを開発するためのテンプレートが充実していることが挙げられます。VST/AudioUnit/AAX/RTASプラグインといった、DTMユーザーにはお馴染みのプラグインフォーマットを開発するのに長けており、日本国内外で多くの採用事例があります。
JUCEについてより詳しく知りたい場合は、こちらの記事[JUCE ハンズオン 〜JUCEをはじめよう〜](https://qiita.com/COx2/items/12a48c4a30c49732dcc5)や、[JUCE Advent Calendar 2017](https://qiita.com/advent-calendar/2017/juce)をご覧いただければと思います。

# JUCE 5.4.0からUnity Native Audio Pluginが正式サポート

これまではVST/AudioUnit/AAXといったDAW向けのオーディオプラグインのビルドがサポートされていましたが、5.4.0からはUnityゲームエンジンのNative Audio Pluginも仲間に加わりました。
これにより、VSTとして開発していたDSPのコードを、そのままUnity上で実行することができるようになります。

参考: https://juce.com/discover/stories/unity-native-plug-in-support

# Unity Native Audio Pluginとは
UnityのAudio Mixerコンポーネントにインサートすることができるプラグイン形式のDSPです。

参考： https://docs.unity3d.com/Manual/AudioMixerNativeAudioPlugin.html

# 新規プロジェクトを作成する
それでは、サイン波を生成するオーディオプラグイン『HelloSinewave』を作成してみましょう。
プロジェクト作成ウィザードから`Audio Plugi-In`を選択します。
![unity0.PNG](https://qiita-image-store.s3.amazonaws.com/0/93566/f3257359-c8c4-a070-fe03-6c4df708c5a2.png)

### プロジェクト設定で[Plugin Formats]内の`Unity`にチェックを入れる

![unity1.PNG](https://qiita-image-store.s3.amazonaws.com/0/93566/b78a8934-82ca-e0dd-bc8a-3e649d6b8104.png)

#### プロジェクトをIDEで開く

プロジェクト一覧にUnity用のプロジェクトが追加されていることが分かります。
![unity2.PNG](https://qiita-image-store.s3.amazonaws.com/0/93566/c21101ae-8c79-a36b-a0b1-a4fdd03af125.png)

#### HelloSinewaveのコーディング

`PluginProcessor.h`を開き、メンバ変数を追加します。

```
class HelloSinewaveAudioProcessor  : public AudioProcessor
{
~~~省略~~~

private:
    AudioParameterFloat* angleDelta;    // プラグインのパラメータ
    float angle = 0;                    // サイン波の位相

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HelloSinewaveAudioProcessor)
};
```

`PluginProcessor.cpp`を開き、パラメータのインスタンス生成・登録と、サイン波をレンダリングする処理を実装します。

```
HelloSinewaveAudioProcessor::HelloSinewaveAudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
     : AudioProcessor (BusesProperties()
                     #if ! JucePlugin_IsMidiEffect
                      #if ! JucePlugin_IsSynth
                       .withInput  ("Input",  AudioChannelSet::stereo(), true)
                      #endif
                       .withOutput ("Output", AudioChannelSet::stereo(), true)
                     #endif
                       )
#endif
{
    // パラメータのインスタンス生成とパラメータの登録
    angleDelta = new AudioParameterFloat("ANGLE_DELTA", "Angle Delta", 0.0f, 1.0f, 0.1f);
    addParameter(angleDelta);
}

void HelloSinewaveAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
{
    ScopedNoDenormals noDenormals;
    auto totalNumInputChannels  = getTotalNumInputChannels();
    auto totalNumOutputChannels = getTotalNumOutputChannels();

    for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
        buffer.clear (i, 0, buffer.getNumSamples());

    // サイン波をレンダリングする処理
    for (int sampleIndex = 0; sampleIndex < buffer.getNumSamples(); sampleIndex++)
    {
        angle += angleDelta->get();
        
        for (int channel = 0; channel < totalNumInputChannels; ++channel)
        {
            auto* channelData = buffer.getWritePointer(channel);
            channelData[sampleIndex] = std::sinf(angle) * 0.3f;
        }
    }
}
```

### ビルドを実行
ビルドが完了すると、ファイル名に`audioplugin_`の接頭辞が追加された動的ライブラリが生成されます。
![unity3.PNG](https://qiita-image-store.s3.amazonaws.com/0/93566/5cc7bf7d-8871-2bf1-0303-097948f53b41.png)


# Unityで実行する

### Unityでプロジェクトを作成する
Unityを開き、Native Audio Pluginの実行に必要な作業を行います。

+ AudioSourceコンポーネントをシーンに追加する
+ AudioMixerをアセットに追加する
+ AudioMixerをAudioSourceコンポーネントの`Output`にセットする
+ audioplugin_HelloSinewaveをアセットに追加する

![Unity4-1.PNG](https://qiita-image-store.s3.amazonaws.com/0/93566/d2d0d76b-ce5e-3c8c-8555-0bc6677f2848.png)

### AudioMixerにプラグインを追加する
AudioMixerファイルを選択したら、インスペクターから[Add Effect]をクリックして、リストに表示された`audioplugin_HelloSinewave`をクリックします。
![unity5.PNG](https://qiita-image-store.s3.amazonaws.com/0/93566/9c7486de-1179-46e4-4511-98e86a117ba3.png)

### シーンを再生する
シーンを再生すると、`audioplugin_HelloSinewave`によってミキサーのトラックにサイン波が流れます。
インスペクターの[Edit in Playmode]をクリックすると、シーン再生時にパラメータをインスペクターから操作することができます。
[Angle Delta] パラメータを操作すると、サイン波のピッチ（周波数）が上下することが確認できます。
![Unity6.PNG](https://qiita-image-store.s3.amazonaws.com/0/93566/7ca07096-394d-afdb-c805-c38af1d3085b.png)


### プラグインのパラメータをC#スクリプトから操作できるようにする
インスペクターに表示されたパラメータ名を右クリックすると、コンテキストメニューに`Expose xxx`という項目が表示されます。
この項目を有効にしたパラメータはC#スクリプトからアクセスすることができるようになります。
スクリプト用に抽出されたパラメーターは、SetFloat 関数を使って設定することができます。
![Unity7.PNG](https://qiita-image-store.s3.amazonaws.com/0/93566/fd7c064f-5e6d-1926-9008-f1c40c1dbe47.png)

参考: [オーディオミキサーパラメーターの抽出 (Exposed Parameters)](https://unity3d.com/jp/learn/tutorials/topics/audio/exposed-audiomixer-parameters)


### 注意点

Unity Native Audio PluginではMIDI入出力を扱うことができません。
そのため、MIDIデータをトリガーとして処理を実行するようなインストゥルメント系などを移植する場合は、別途トリガー系のパラメータを用意しておくなどの実装が必要になるでしょう。