【Unity】OscCoreの使い方

UnityのOSCライブラリであるOscCoreの使い方について調べました。
[stella3d/OscCore: A performance\-oriented OSC library for Unity](https://github.com/stella3d/OscCore)

OscCoreは他のOSCライブラリと比較して、メモリアロケーションを少なくしてガーベッジコレクションを減らすことでパフォーマンスの向上を図ることを目的として作られたそうです。

本記事の内容はUnityバージョン2021.2.9f1、エディタ上でのみ検証しています。

## インストール

GitHubリポジトリの[Releases](https://github.com/stella3d/OscCore/releases)ページからunitypackageをダウンロードしてインポートします。

## 使い方

### OSCの受信

#### コンポーネントを用いたOSCの受信

`OscReceiver`コンポーネントを`Input`コンポーネントを使ってOSCの受信によりメソッドを実行します。
`OscReceiver`コンポーネントを`Add Component > OSC > OSC Receiver`から、`Input`コンポーネントを`Add Component > OSC > Input`から追加します。`OscReceiver`コンポーネントと同じオブジェクトか子孫オブジェクトに`Input`コンポーネントを追加すると、自動でその`OscReceiver`コンポーネントに紐づけられます。`Input`コンポーネントは次のようにデータ型ごとに存在するので、受信するデータに合わせて選択します。
![OscReceiver_s.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/7f0a0a84-99da-4834-cc76-f5e065f84937.png)

#### スクリプトを用いたOSCの受信

スクリプトからOSCを受信する場合には、`OscServer`を使用します。`OscServer`は`OscReceiver`コンポーネントから取得するか、`OscServer.GetOrCreate`で取得します。`OscServer#TryAddMethod`でOSCアドレスに対してメソッドをバインドします。

```c#:OscCoreReceiveScriptSample01.cs
using UnityEngine;
using OscCore;

public class OscCoreReceiveScriptSample01 : MonoBehaviour
{
    [SerializeField] int port = 8000;
    const string OscAddress = "/OscCore/sample";
    OscServer server;

    void OnEnable()
    {
        if (server == null)
        {
            server = OscServer.GetOrCreate(port);
        }
        server.TryAddMethod(OscAddress, ReadValues);
    }

    void OnDisable()
    {
        server.RemoveMethod(OscAddress, ReadValues);
    }

    void ReadValues(OscMessageValues values)
    {
        Debug.Log($"OscCore received: {values.ReadStringElement(0)} {values.ReadFloatElement(1)} {values.ReadIntElement(2)}");
    }
}
```

:::note warn
私が試したところ、受信データにstringが含まれていると取得したデータが正しく解釈されませんでした。
:::

`OscServer#TryAddMethod`でバインドされたメソッドはメインスレッド外で実行されます。そのため、メソッド内ではUnity APIをほとんど使用することができません。`OscServer#TryAddMethodPair`を使用するとメインスレッドで実行されるメソッドも追加できるので、そこでUnity APIを使用します。

```c#:OscCoreReceiveScriptSample02.cs
using UnityEngine;
using OscCore;

public class OscCoreReceiveScriptSample02 : MonoBehaviour
{
    const string OscAddress = "/OscCore/sample";
    [SerializeField] int port = 8000;
    OscServer server;
    string receivedString;
    float receivedFloat;
    int receivedInt;

    void OnEnable()
    {
        if (server == null)
        {
            server = OscServer.GetOrCreate(port);
        }
        server.TryAddMethodPair(OscAddress, ReadValues, ProcessValues);
    }

    void OnDisable()
    {
        server.RemoveMethod(OscAddress, ReadValues);
    }

    void ReadValues(OscMessageValues values)
    {
        receivedString = values.ReadStringElement(0);
        receivedFloat = values.ReadFloatElement(1);
        receivedInt = values.ReadIntElement(2);
    }

    void ProcessValues()
    {
        Debug.Log($"OscCore received: {receivedString} {receivedFloat} {receivedInt}");
    }
}
```

:::note warn
ただし、私が試したところProcessValuesが実行されませんでした。
:::

#### モニタリング

`Menu > WIndow > OscCore > Monitor`から`OscCore.MonitorWindow`ウィンドウを表示します。`OscCore.MonitorWindow`ウィンドウで受信したOSCを確認できます。

### OSCの送信

#### コンポーネントを用いたOSCの送信

`OscSender`コンポーネントと`PropertyOutput`コンポーネントを使って指定したオブジェクトのプロパティをOSCで送信します。
`Add Component > OSC > OSC Sender`から`OscSender`コンポーネントを、`Add Component > OSC > Property Output`から`ProperyOutput`コンポーネントを追加します。`OscSender`コンポーネントと同じオブジェクトか子孫オブジェクトに`PropertyOutput`コンポーネントを追加すると、自動でその`OscSender`コンポーネントに紐づけられます。
![PropertyOutput_s.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/a64154d7-eecb-7b75-3248-3e70fa005313.png)

:::note warn
私が試したところ、PropertyOutput#Updateの最初にあるガード節に引っ掛かり、OSCの送信が行えませんでした
:::

#### スクリプトを用いたOSCの送信

スクリプトからOSCの送信を行う場合には、`OscClient`を使用します。
`OscClient#Send`でOSCアドレスとデータを指定して送信します。`OscClient#Send`はデータ型ごとにオーバーロードメソッドが存在しています。

```c#:OscCoreSendScriptSample.cs
using UnityEngine;
using OscCore;

public class OscCoreSendScriptSample : MonoBehaviour
{
    [SerializeField] string ipAddress = "127.0.0.1";
    [SerializeField] int port = 8080;
    OscClient client;

    void Start()
    {
        client = new OscClient(ipAddress, port);
    }

    void Update()
    {
        client.Send("/OscCore/string", "hoge");
        client.Send("/OscCore/float", 123.456f);
        client.Send("/OscCore/integer", 100);
    }
}
```

## まとめ

UnityのOSCライブラリであるOscCoreについて解説しました。
ところどころ挙動が怪しくて、実際に使っていくには厳しいかなぁという印象を受けました。