ブラウザの Web Bluetooth API を使って toio で使える効果音のいくつかをセットで鳴らす（環境は p5.js Web Editor を利用）

## はじめに
ブラウザの Web Bluetooth API と toio を組み合わせたお試しについての記事です。

toio の通信仕様は公開されていて、それに従った BLE での処理を行うと、toio を様々なプログラミング言語で制御することができます。

今回は、ブラウザ上で実行する JavaScript の処理で、以下の toio のサウンド機能を扱います（その際に、ブラウザの API である「[Web Bluetooth API](https://developer.mozilla.org/ja/docs/Web/API/Web_Bluetooth_API)」を使っています）。

●サウンド | toio™コア キューブ 技術仕様 ＞ 「効果音の再生」
　https://toio.github.io/toio-spec/docs/ble_sound/#%E5%8A%B9%E6%9E%9C%E9%9F%B3%E3%81%AE%E5%86%8D%E7%94%9F

そしてサウンド機能の中でも、公式が用意している効果音のいくつかを利用する、ということを試してみます。

### 今回の内容を試した時の様子
実装内容の話に入る前に、先に今回の内容を試した時の様子（以下の動画）を紹介します。

<iframe width="560" height="315" src="https://www.youtube.com/embed/NwkidFlz7mI?si=VYe30wXdCP02lLIT" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

上記の動画の見た目からは分からないですが、今回の実装では「画面をクリックすると音が鳴る」という処理の流れにしています。また、音を鳴らす部分は「ある 4つの効果音を順番に鳴らす」という内容にしています。

上記の動画では、その効果音を鳴らす処理を 2回実行してみています。

## 今回の実装
それでは、今回実装した内容の話に入っていきます。

まずは、プログラム全体を示します。
※ 開発・実行に [p5.js Web Editor](https://editor.p5js.org/) を用いており、その環境内の sketch.js のみ書きかえて使っています（HTML や CSS はそのまま）。

```javascript:sketch.js
const TOIO_SERVICE_UUID = "10b20100-5b3b-4571-9508-cf3efcd7bbae";
const TOIO_SOUND_CHARACTERISTIC_UUID = "10b20104-5b3b-4571-9508-cf3efcd7bbae";

const sleep = (msec) => new Promise((resolve) => setTimeout(resolve, msec));

let characteristic;
let isConnected = false;

async function playSimpleSound() {
  try {
    if (!isConnected) {
      const device = await navigator.bluetooth.requestDevice({
        filters: [{ services: [TOIO_SERVICE_UUID] }],
        optionalServices: [TOIO_SOUND_CHARACTERISTIC_UUID],
      });
      const server = await device.gatt.connect();
      service = await server.getPrimaryService(TOIO_SERVICE_UUID);
      isConnected = true;
      console.log("接続しました");
      characteristic = await service.getCharacteristic(
        TOIO_SOUND_CHARACTERISTIC_UUID
      );
    } else {
      console.log("音を鳴らす処理");
      await sleep(200);
      await characteristic.writeValueWithResponse(
        new Uint8Array([0x02, 0x04, 0xff])
      );
      await sleep(800);
      await characteristic.writeValueWithResponse(
        new Uint8Array([0x02, 7, 0xff])
      );
      await sleep(800);
      await characteristic.writeValueWithResponse(
        new Uint8Array([0x02, 9, 0xff])
      );
      await sleep(800);
      await characteristic.writeValueWithResponse(
        new Uint8Array([0x02, 10, 0xff])
      );
      console.log("効果音を鳴らしました");
    }
  } catch (error) {
    console.error(`Error: ${error}`);
  }
}

function setup() {
  createCanvas(400, 400);
  background(220);
}

function mouseClicked() {
  playSimpleSound();
}
```

### 実装内容の補足： 大まかな部分
上記で実装している内容は、おおまかには以下のとおりです。

- 画面をクリックすると playSimpleSound() を実行する
   - playSimpleSound() の処理は以下のとおり
      - toio との接続が行われていなかったら、toio との接続を行う： `if (!isConnected) {}` の中の処理
      - 既に toio と接続されていたら効果音を鳴らす： `console.log("音を鳴らす処理")` 〜 `console.log("効果音を鳴らしました")` までの処理

また、複数の効果音を鳴らしている処理の中で待ちの処理を入れるため、冒頭に書いている以下の処理を用いています。

```javascript
const sleep = (msec) => new Promise((resolve) => setTimeout(resolve, msec));
```

なお、冒頭に書いている 2つの UUID は、toio の仕様のページに記載があるものを用いています。

### 実装内容の補足： 効果音を鳴らす処理
効果音を鳴らす処理は、[writeValueWithResponse()](https://developer.mozilla.org/ja/docs/Web/API/BluetoothRemoteGATTCharacteristic/writeValueWithResponse) を使っている部分です。

その中で、Uint8Array() で toio に送るデータを作っています。

#### Uint8Array() の括弧の中の内容
Uint8Array() の括弧の中の内容は、以下となっています。

- [0x02, 0x04, 0xff]
- [0x02, 7, 0xff]
- [0x02, 9, 0xff]
- [0x02, 10, 0xff]

ここで指定している数値などの意味は、toio公式の仕様で書かれている以下の内容に従ったものです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/93e1bd5c-1253-892d-3de4-60fa8f9255ad.png)

効果音の ID は、以下の公式に書かれているものから選んでいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/2c18cdda-8825-6eba-bd87-d2f58d670f4f.png)

（効果音の ID の部分は、`0x04` と書いたり `7（、9、10）` と書いたりしてみていますが、両方の書き方をそれぞれ試してみただけで、特にそれらを混在させていることに意味はありません）

このような実装で、動画で示した内容を実現することができました。


## 【追記】　モーター制御の話
今回の記事の流れを踏襲した形で、時間指定付きモーター制御を扱う話も記事に書きました。

●ブラウザの Web Bluetooth API を使って toio の時間指定付きモーター制御を扱う（環境は p5.js Web Editor を利用） - Qiita
　https://qiita.com/youtoy/items/9067dff49c0ce09ac084