ブラウザ上の p5.js のプログラムで OSC を使う（サーバー・クライアントは osc-js で実装）

以下の記事の続きです。

●ブラウザで OSC を扱う初めの一歩（osc.js、osc-js、p5.js用ライブラリを見てみたりなど）【2021年9月】 - Qiita
　https://qiita.com/youtoy/items/efe9b07be57454dec5d5

上記の記事の中で記載していた「[osc-js](https://www.npmjs.com/package/osc-js)」を使い、Node.js でサーバーを用意しつつ、ブラウザ上で動くクライアントも実装してみます（osc-js を使いつつ、p5.js と併用する形）。

## OSC のサーバー（WebSocket を利用するもの）を Node.js ＋ osc-js で準備
前の記事にも書いたように、ブラウザで扱う場合は WebSocket を使う形になるため、仲介役になるサーバーが必要です。

それについて、[osc-js の Wiki の「Node.js Server」の項目](https://github.com/adzialocha/osc-js/wiki/Node.js-Server)を見つつ、準備していきます。

Node.js の npm コマンドで、osc-js を準備します。
今回、グローバルインストールではなくローカルインストールで進めます。

```bash
$ npm install osc-js
```

上記でインストール後に、こちらを使ったサンプルプログラムを準備します。
公式の内容をほぼそのまま使う形で用意します（ファイル名は「app.js」にしました）。

```javascript:app.js
const OSC = require('osc-js')

const plugin = new OSC.WebsocketServerPlugin({ port: 9912 })
const osc = new OSC({ plugin: plugin })

osc.on('/test', message => {
  console.log(message.args)
})

osc.on('open', () => {
  console.log("open");
  setInterval(() => {
     osc.send(new OSC.Message('/response', Math.random()))
  }, 1000)
})

osc.open()
```

そして、コマンドで上記の app.js を実行して、サーバーを立ち上げます。

## ブラウザで動く OSC のクライアントを osc-js で準備
サーバーの準備ができたところで、それに接続するクライアントを準備します。

プログラムは、オンラインの開発・実行環境である [p5.js Web Editor](https://editor.p5js.org/) を使ってみようと思います。

### ライブラリの読み込み
p5.js Web Editor のサンプルプログラムでは osc-js を利用できないので、ライブラリの読み込みをするようにします。

index.html で、以下のページに掲載された CDN上のライブラリの URL を読み込みます。
　●osc-js CDN by jsDelivr - A CDN for npm and GitHub
　　https://www.jsdelivr.com/package/npm/osc-js

具体的には `https://cdn.jsdelivr.net/npm/osc-js@2.1.2/lib/osc.min.js` です。

### サーバーにメッセージを送るプログラムを軽く動かしてみる
以下の公式の Wiki の内容を見つつ、まずはサーバーに接続する部分を最小限で作ってみます。
　●Websocket Client Plugin · adzialocha/osc-js Wiki
　　https://github.com/adzialocha/osc-js/wiki/Websocket-Client-Plugin

上記のサンプルそのままだと、接続先が「ws://localhost:8080」になり、ポート「9912」で待ち受けているサーバーにつながらないので、この部分はポート指定を行うようにします。
また、Webページ上のボタンをクリックして動作させる前提の部分も、p5.js用の処理に置きかえます。

具体的には、以下のようなソースコードになりました。

```javascript:sketch.js
let osc;

function setup() {
  createCanvas(400, 400);

  osc = new OSC();
  osc.open({ port: 9912 });
}

function draw() {
  background(220);
}

function keyPressed() {
  if(key === 's') {
    const message = new OSC.Message("/test", Math.random());
    osc.send(message);
    
    console.log("send message")
  }
} 
```

これで、3回くらいメッセージ送信を行ってみると、クライアント・サーバー側のそれぞれのメッセージ出力が以下のようになりました。

【クライアント側の出力（メッセージ送信側）】
![送信側.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/1f21ff77-e4d8-e236-436b-0eb8f568ab29.jpeg)

【サーバー側の出力（メッセージ受信側）】
![受信側.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/b9b12e7e-468b-1c11-b1b6-a5d72ced4b59.jpeg)

### クライアント側でサーバーからのメッセージを受けとってみる
今回動かしているサーバー側のサンプルは、`setInterval()`　で定期的なメッセージ送信をしています。
それをクライアント側（ブラウザで動いているプログラム）で受信して出力できるよう、プログラムを書きかえてみます。

差分は数行ほどになりますが、書きかえ後のプログラム全体は以下のとおりです。

```javascript
let osc;

function setup() {
  createCanvas(400, 400);

  osc = new OSC();
  osc.open({ port: 9912 });

  osc.on("/response", (message) => {
    console.log(message.args);
  });
}

function draw() {
  background(220);
}

function keyPressed() {
  if (key === "s") {
    const message = new OSC.Message("/test", Math.random());
    osc.send(message);

    console.log("send message");
  }
}
```

これで、ブラウザ側のコンソール出力を見てみると、一定時間ごとに数値が出力がされて以下のようになりました。
![サーバー側から送信されたメッセージを受けとる.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/49486b0c-c69e-b7a6-222c-9dbc834077f0.jpeg)

正常に動作していそうです。

## おわりに
今回、p5.js で OSC を扱うために osc-js というライブラリを用いた実装を行いました。

サーバー側もクライアント側（ブラウザ側）も osc-js を用いたプログラムを動かし、双方向のメッセージのやりとりができたことを確認できました。

今後は、別のデバイス・アプリ・プログラムとの間の OSC を用いた通信を試せればと思います。

## 追記
UDP を使った OSC通信についても試して記事にしました。

●ZIG SIM と Node.js のプログラム（osc.js を利用）との間で UDP による OSC通信を軽く試す（OSC Data Monitor の話も） - Qiita
　https://qiita.com/youtoy/items/fddc750759f4ecef7ca7

上記について、当初は osc.js　ではなく今回使った osc-js を使おうとしました。
でも、UDP を用いた通信がうまくいかず、自分の実装・使い方がまずいだけかもしれないですが osc.js　を使ってみることにしました。