1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【OSC】【Unity】OSCCore を用いた OSC 通信実装 2

Last updated at Posted at 2025-11-25

はじめに

本記事では、Unityで OSCCore を用いた、OSC通信を実装します。

前回の記事とは異なり、OSCCoreのWrapperクラスを独自実装します。
ここでは、int型を使用したシンプルな例を記載しています。

OSCCoreの追加方法や、Sceneのオブジェクト構成などは前回の記事を参考にしてください。

対象読者

  • UnityアプリでOSC通信を実装したい方

環境

  • MacBookPro M3
  • Unity 2022.3.62f1

1. OSCSender クラス実装 (Client側)

処理の流れ

OSCメッセージを送信する流れは以下の通りです:

  1. OscClientを初期化 → 送信先のIPアドレスとポート番号を設定
  2. Sendメソッドを呼び出す → データ型に応じたSendメソッドで送信

実装

OSCSender.cs
using UnityEngine;
using OscCore;
using UnityEngine.UI;

namespace CustomSample
{
    public class OSCSender : MonoBehaviour
    {
        [Header("OSC Settings")]
        
        [Tooltip("The IP address to send to")]
        [SerializeField]
        string _ipAddress = "127.0.0.1";
        
        [SerializeField]
        string _addressInt = "/sample/int";

        [Tooltip("The port number to send to")]
        [SerializeField]
        int _portNumber = 9000;

        // OSCメッセージを送信するクライアント
        OscClient _client;

        [Header("UI")]
        [SerializeField] Button _sendButton;

        void Start()
        {
            Initialize();

            // ボタンが押されたら、int型の値10を送信
            _sendButton.onClick.AddListener(() => {
                _client?.Send(_addressInt, 10);
            });
        }

        void OnDestroy()
        {
            _client = null;
        }

        void Initialize()
        {
            _client = null;
            // 新しいクライアントを作成
            _client = new OscClient(_ipAddress, _portNumber);
        }
    }
}

コードの詳細解説

OscClientの初期化

_client = new OscClient(_ipAddress, _portNumber);

ポイント:

  • OscClientはOSCメッセージを送信するためのクライアント
  • 送信先のIPアドレス(_ipAddress)とポート番号(_portNumber)を指定
  • 今回は、127.0.0.1はローカルホスト(自分のPC)を指すIPアドレスを指定

Sendメソッド

_client?.Send(_addressInt, 10);

ポイント:

  • Send(address, value) - OSCアドレスと値を指定して送信
  • この例では、"/sample/int"というアドレスに、int型の値10を送信
その他の送信例

Sendメソッドはオーバーロード(同名で引数が異なるメソッド)として実装されており、様々な型のデータを送信できます。

// int型
_client.Send("/address", 10);

// float型
_client.Send("/address", 3.14f);

// string型
_client.Send("/address", "Hello");

// Vector2型
_client.Send("/address", new Vector2(1.0f, 2.0f));

// Vector3型
_client.Send("/address", new Vector3(1.0f, 2.0f, 3.0f));

// bool型
_client.Send("/address", true);

// その他: double, long, Color32, byte[], char なども送信可能

2. OSC Receiver クラス実装(Server側)

処理の流れ

OSCメッセージを受信して、受信に応じた処理を実行する流れは以下の通りです:

  1. OSCメッセージ受信 (バックグラウンドスレッド) → ReadIntで値を読み取り
  2. メインスレッドで処理ProcessIntOnMainThreadでEventを発火
  3. Unityで利用 → 他のコンポーネントがOnIntReceivedイベントを受け取る

実装

OSCReceiver.cs
using System;
using UnityEngine;
using OscCore;

namespace CustomSample
{
    public class OSCReceiver : MonoBehaviour
    {
        [Header("OSC Settings")]
        [Tooltip("The address to listen for incoming messages on")]
        [SerializeField]
        string _address = "/sample/int";
        
        [Tooltip("The local port to listen for incoming messages on")]
        [SerializeField]
        int _portNumber = 9000;
        
        OscServer _server;
        
        // 外部のスクリプトから購読できるイベント
        public event Action<int> OnIntReceived;
        
        // バックグラウンドスレッドで読み取った値を一時保存
        int _receivedInt;

        void Start()
        {
            Initialize();
        }

        void Update()
        {
            // メインスレッドで実行待ちの処理を実行
            _server?.Update();
        }

        void OnDestroy()
        {
            // ポートを解放
            _server?.Dispose();
        }

        void Initialize()
        {
            try
            {
                // 既存のサーバーがあれば削除
                OscServer.Remove(_portNumber);
                
                // 新しいサーバーを作成
                // _server = new OscServer(_portNumber); ← 非推奨
                _server = OscServer.GetOrCreate(_portNumber);
                
                
                // メッセージ受信時の処理を登録
                _server.TryAddMethodPair(_address, ReadInt, ProcessIntOnMainThread);
            }
            catch (System.Exception e)
            {
                Debug.LogError($"Failed to initialize OSC server on port {_portNumber}: {e.Message}");
            }
        }

        // バックグラウンドスレッドで値を読み取る
        void ReadInt(OscMessageValues values)
        {
            _receivedInt = values.ReadIntElement(0);
            Debug.Log($"[Background Thread] Read int: {_receivedInt}");
        }
        
        // メインスレッドで値を処理してEventを発火
        void ProcessIntOnMainThread()
        {
            Debug.Log($"[Main Thread] Processing int: {_receivedInt}");
            OnIntReceived?.Invoke(_receivedInt);
        }
    }
}

コードの詳細解説

OscServerの初期化

_server = OscServer.GetOrCreate(_portNumber);

ポイント:

  • OscServerはOSCメッセージを受信するためのサーバー
  • 受信するポート番号(_portNumber)のみを指定(IPアドレスは指定しない)
  • サーバーは指定したポートで待ち受け、どのIPアドレスからのメッセージも受信可能

インスタンス生成方法:

  • new OscServer(_portNumber) は非推奨
  • OscServer.GetOrCreate(_portNumber) を推奨

GetOrCreateメソッドの使用を推奨する理由

  • 同じポートに対して既にサーバーが存在する場合は、それを再利用
  • 存在しない場合は新規作成し、内部のOscServer.PortToServerに自動登録
  • ポートの重複使用によるエラーを防止
  • OscServer.Remove()などの管理機能が正しく動作

new OscServer(_portNumber) によるポート重複エラー例

// ❌ これはエラーになります
void Start() {
    Initialize();
    Initialize(); // ←2回目の初期化でエラー
}

Removeによる管理機能が動作しない。そのため、Failed to initialize OSC server on port 9000: Address already in useのエラーとなってしまう。

TryAddMethodPair

_server.TryAddMethodPair(_address, ReadInt, ProcessIntOnMainThread);

ポイント:

  • 第一引数: 監視するOSCアドレスを指定
  • 第二引数: バックグラウンドで実行する処理
  • 第三引数: メインスレッドで実行する処理

OSCメッセージはバックグラウンドスレッドで受信されます。しかし、UnityのAPI(GameObject操作、UI更新、Event発火など)はメインスレッドでしか実行できないので、TryAddMethodPairを使用します。

TryAddMethodを使用した場合のエラー例

// ❌ これはエラーになります
_server.TryAddMethod(_address, (values) => {
    int value = values.ReadIntElement(0);
    // バックグラウンドスレッドからEvent発火するとエラーになる!
    OnIntReceived?.Invoke(value); 
});

値の読み取り

void ReadInt(OscMessageValues values)
{
    // 受信したメッセージから、0番目の要素をint型で取得
    _receivedInt = values.ReadIntElement(0);
    Debug.Log($"[Background Thread] Read int: {_receivedInt}");
}

ポイント:

  • ReadIntElement(0) - メッセージの1番目の値をint型で取得
  • フィールド変数_receivedIntに保存することで、メインスレッドに値を渡す
  • この時点ではまだUnityのAPIは使用してはならない

メインスレッドでの処理

void ProcessIntOnMainThread()
{
    Debug.Log($"[Main Thread] Processing int: {_receivedInt}");
    // Eventを発火して、他のスクリプトに通知
    OnIntReceived?.Invoke(_receivedInt);
}

ポイント:

  • メインスレッドで実行されるため、UnityのAPIが使用可能
  • OnIntReceived?.Invoke() でイベントを発火し、購読している他のスクリプトに値を通知

Update() でサーバーを更新

void Update()
{
    _server?.Update();
}

ポイント:

  • サーバーは、メインスレッドキューに溜まったコールバックを処理するために、Update()メソッドを呼び出す必要がある

The server must have its Update() method ticked to handle main thread queued callbacks.

Updateを忘れると、メインスレッドで実行したい処理ProcessIntOnMainThreadが実行されません。

ポートの解放

void OnDestroy()
{
    _server?.Dispose();
}

ポイント:

  • OnDestroy で OscServer を忘れずに破棄して、ポートを解放する
  • ポート番号やAddressを更新したタイミングなど、適切なタイミングで破棄する

適切に破棄しない場合、既に指定した番号のポートを使用してしまっているErrorになる可能性があります。OscServer・OscClient 共に適切なタイミング破棄することを忘れずに行いましょう。また、OscServer.Removeメソッドなどもうまく活用してみてください。

3. TextDisplayer クラス実装

OSCReceiverのイベントを購読する側を実装します。

実装

TextDisplayer.cs
using UnityEngine;
using UnityEngine.UI;

namespace CustomSample
{
    public class TextDisplayer : MonoBehaviour
    {
        [SerializeField] Text _displayText;
        [SerializeField] OSCReceiver _oscReceiver;

        void Start()
        {
            // OSCReceiverのイベントを購読
            _oscReceiver.OnIntReceived += Display;
        }

        void OnDestroy()
        {
            // イベントの購読を解除
            _oscReceiver.OnIntReceived -= Display;
        }

        // イベント発火時に呼ばれるメソッド
        public void Display(int message)
        {
            Debug.Log($"Displaying message: {message}");
            _displayText.text = message.ToString();
        }
    }
}

OSCReceiverから渡された値をmessageとして受け取り、ToString()でint型を文字列に変換したものを、Textに表示する機能を実装しました。

4. 動作確認

正しく実装できていれば、以下の流れで動作します:

  1. OSCSenderのボタンをクリック → int型の値10を送信
  2. OSCReceiverが受信OnIntReceivedイベント発火
  3. TextDisplayerが反応Displayメソッドが呼ばれる
  4. UIに表示 → Textに "10" が表示される

スクリーンショット 2025-11-18 14.59.52.png

OscCore MonitorWindow

また、Window > OscCore > Monitorを選択すると、MonitorWindow を表示できます。
こちらで、メッセージ受信時の以下の情報を確認できます:

  • 使用中のポート番号
  • 受信したOSCメッセージのアドレス
  • 受信した型と値

まとめ

本記事では、OSCCoreのOscClientとOscServerを利用した、Wrapperクラスを実装する方法を紹介しました。

今回はint型を使用したシンプルな例でしたが、OscClientのSendメソッドは様々な型に対応しています。プロジェクトの要件に応じて適切な型を選択してください。

エラーの原因となるポイントなどもまとめたので、通信が上手くいかない場合の参考になればと思います。

ぜひこの実装を活かして、より面白いOSC連携アプリケーションを開発してみてください!
楽しい開発をはじめましょう!

参考文献

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?