音通信ライブラリChirpを利用してTHETAを操る

## お知らせ

### 2020/12/22

現在、Asio Ltd.はSONOS社傘下に入り、Chirpライブラリは公開されておらず、アプリケーションも公開されておりません "が"（続きがあります）

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">We are excited to announce that Chirp has been acquired by <a href="https://twitter.com/Sonos?ref_src=twsrc%5Etfw">@Sonos</a>.<br><br>We’ve loved seeing developers apply our SDKs to such an imaginative range of applications. Our thanks to everyone who has supported us on our mission over the last 9 years 🙌<br><br>More info: <a href="https://t.co/U5GTeuaTzd">https://t.co/U5GTeuaTzd</a> <a href="https://t.co/XKYM9ooDFu">pic.twitter.com/XKYM9ooDFu</a></p>&mdash; Chirp (@chirp) <a href="https://twitter.com/chirp/status/1227915479920107520?ref_src=twsrc%5Etfw">February 13, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

本記事のTHETAプラグインソースコードと共に公開している[音楽ファイル（MP3やWAV）](https://github.com/theta-skunkworks/theta-plugin-chirp-remote/tree/master/audiofiles)を
スマートフォンや各種オーディオ機器等で再生することにより、
THETAプラグインストアに公開している[この記事のプラグイン](https://pluginstore.theta360.com/plugins/skunkworks.chirpremote/)を利用することができます。

### 2020/01/07
お待たせいたしました！ 
本記事で作成したプラグインが THETAプラグインストアに公開されました！
画像をクリックしていただくか、画像したのURLをクリックして頂くとストアへ行けます！

[![000_ストアトップ画像.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265455/9a886ce4-74d1-a21e-41d3-09698d8f8fda.png)
](https://pluginstore.theta360.com/plugins/skunkworks.chirpremote/)

https://pluginstore.theta360.com/plugins/skunkworks.chirpremote/

これで、開発者ではない方々もChirpの振る舞いを簡単にお試しいただけます！


## はじめに

リコーの @KA-2 です。

弊社では[RICOH THETA](https://theta360.com/ja/)という全周囲360度撮れるカメラを出しています。
<B>RICOH THETA V</B>や<b>RICOH THETA Z1</b>は、OSに<B>Android</B>を採用しています。Androidアプリを作る感覚でTHETAをカスタマイズすることもでき、そのカスタマイズ機能を「プラグイン」と呼んでいます（詳細は本記事の末尾を参照）。

今回は、音波でデータ通信するライブラリ「 <b>[Chirp](http://www.chirp.io)</b> 」をTHETA plug-inに取り込んで、THETAを操ってみました。
Chirpは、今年の夏にarduino（ESP32を利用した互換機を含む）に対応したので、電子工作界隈で話題になっているライブラリです。
Android用ライブラリもあったのでTHETA Plug-inでためしてみた次第です。
以下の動画で、動作させた様子をご覧下さい。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">音通信ライブラリ「Chirp」でTHETAをリモート操作。<br>音楽ファイル再生で操作したり、無料のChirp Messengerアプリで設定を確認しながらの操作も。<br>なんと、THETAは近超音波を聴けるだけでなく、鳴らせます！<br>Qiita記事はこちら↓<a href="https://t.co/MOAlGDMFxT">https://t.co/MOAlGDMFxT</a><a href="https://twitter.com/hashtag/thetaplugin?src=hash&amp;ref_src=twsrc%5Etfw">#thetaplugin</a> <a href="https://twitter.com/hashtag/chirp?src=hash&amp;ref_src=twsrc%5Etfw">#chirp</a> <a href="https://t.co/Ym6lkxrBuF">pic.twitter.com/Ym6lkxrBuF</a></p>&mdash; THETAプラグイン開発者コミュニティ (@thetaplugin) <a href="https://twitter.com/thetaplugin/status/1185027199990022144?ref_src=twsrc%5Etfw">October 18, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

どうです？
THETAは、コマンドを音で受信できるだけでなく、応答を音で返せるんです。
ピヨピヨとかわいい可聴音のやりとりは、某有名映画のロボットを彷彿させます。
そして、<b>THETAは、可聴音だけでなく「ほぼ超音波」（以降は「近超音波」と記載します）でのデータ送受信も行えます！</b>

[こちらの記事](https://qiita.com/kushimoto/items/e2ee2b1abd05dc50ffcf)で、THETAのスピーカーは、自然音を再生する場合、あまり大きな音が鳴らせないとお知らせしています。それでも(特別なことをしなくても)、近超音波だと3m程度の距離でもデータ通信できちゃいました。近超音波は一般的な騒音の影響を受けにくく、静かな場所では他人の迷惑にもならないので実用したい方も多いのでは？
<b>イベント会場など、Wi-FiやBluetoothの電波が使えない状況でもChirpならば使えます！</b>

また、音通信全般としては、一方的に指示を送るだけなら特別な機材やソフトが必要ありません。<b>音楽ファイルを再生できる機器でTHETAを操れてしまうんです！</b>。
今回の記事では、スマートフォンの音楽プレーヤーのみならず、ボイスレコーダーや電子工作向け機器などを使った実験もしています。（死蔵している超小型mp3プレーヤーがTHETA用リモコンとして復活するかも？）

以降で順番に詳しく解説していきますね。


## Chirpについて（概要） 

Chirpサイトの[トップページ](http://www.chirp.io)を参照すると、「<b>Chirpは音のQRコードのようなもの</b>」と表現しています。「１つの機器がデータを発して、複数の機器が同時に受け取れる」という点や、「文字列のみならず、バイナリーデータの送受信も行える」という点はとても似ています。
他には、<b>「ペアリング不要」「電波環境が悪いイベント会場などでも通信可能」「低コストなハードウェアでも対応できる」</b>といった特徴もあります。

### 特定の機器とだけ通信できる？

Chirpにはマルチチャンネルで混信を避ける仕掛けもあります。チャンネルが1つであっても、データ自体（ペイロード）を工夫すれば如何様にでもできます（工夫を成立させるためにペアリングのような手続きが必要にはなります）。

ただし、今回作成したプラグインについては、無料の範疇で送受信できるデータ量に制約があったので、これらの工夫はしていません。
（Chirpの通信可能距離は音量に比例します。通信距離を伸ばすために音量を大きくするにもマナー的限界もしくはハードウェアの限界があります。むやみやたらに届くものではありません。当面は、このプラグインを使う複数の人が近距離に居ることは稀とおもわれ、ほぼ問題ないでしょう。）

### 騒音があるとどうなるの？

「[Chirp Technology](https://chirp.io/technology/)」ページの「How it works」のブロックに図付きで詳しい解説があります。スマートフォンでは図が見れなかったので転載します。

![02_ChirpTechnology.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265455/3b4e960e-5750-e662-5a6e-9650fc85bdf1.png)

周波数を変えながら通信し、CRCコードやリードソロモン符号による誤り検出と訂正も行われています。ノイズ耐性が高そうです。

使用してみると、可聴音であっても、かなりノイズに強い音通信だと感じました。
近超音波は通信周波数帯が重なるノイズがあまりありません。

<font color="Silver">■ 余談 ■</font>
<font color="Silver">近超音波のChirp通信中にGR IIIのダストリムーバルを動かして苛めてみたけど、そんな程度はビクともしません。というよりも、スペクトルをみると、そもそもぶつかってないみたいでした。。。</font>
<font color="Silver">以下は、実験中の音をリニアPCM（96kHz/24bit）録音し、周波数スペクトル表示したものです。聴こえないけど録音してから"見る"ことはできますね。</font>

![GR3_ダストリムーバル中の通信.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265455/fb899b3c-fe5d-57e7-5138-6975e33899de.png)


### 通信速度とデータ量はどれくらい？

無料で利用可能な範疇の詳細については、次章「サンプルライブラリ(Chirp SDK)について」の「Chirpプロトコル（通信周波数）の種類と制限」にまとめた表をご参照ください。表を見ずに読み進めるために要約すると「無料の範疇ではちょっと通信速度が遅く、送受信できるデータ量も少ない」と感じるわけですが、あくまでそれは無料の範疇だからと思われます。

ChirpのR&D部門では、一般的なハードウェアに搭載した近超音波の実験用Chirpプロトコルにおいて、2000bpsの通信にも成功しているようです。すごい！

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Our R&amp;D team was able to successfully produce a data rate above 2kbps within the near ultrasonic band only, over the air, using consumer hardware. Research engineer, Haris, explains: <a href="https://t.co/vKlO00Utev">https://t.co/vKlO00Utev</a></p>&mdash; Chirp (@chirp) <a href="https://twitter.com/chirp/status/1171786720590909441?ref_src=twsrc%5Etfw">September 11, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


## サンプルライブラリ(Chirp SDK)について

### 無料の利用条件

[こちら](https://chirp.io/pricing/)に「Free」と「Enterprise」の違いが表にまとめられています。

- 個人と非営利団体は無料で使えます。
- 商用利用でも10000MAU（一ヶ月あたりのアクティブユーザー数が10000以下）であれば無料です。

サンプルライブラリのまま有料で使う方法は読み取れません。ですが、有料にするならば、個別に相談をしてカスタムプロトコルとするのほうが良いであろうことは、「通信速度とデータ量はどれくらい？」に記載した内容から察せると思います。

### ユーザー登録とビルド

<b>無料であっても、ユーザー登録をして資格情報を取得しないとライブラリを動作させることができません。</b>

登録は簡単です。Chirpサイトホーム画面の右上「DEVELOPERS」ボタンから[開発者サイト](https://developers.chirp.io/)に行き「SIGN UP」ボタンを押して、名前、メールアドレスを登録したあと、パスワードを設定するだけです。登録が済むと、詳細なドキュメントを参照できたり、Chirp SDKのダウンロード（mavenを使う場合でも）が行えるようになったりします。

そして、最も重要な、以下３種類の資格情報の文字列が取得できるようになります。

|キー文字列名称|説明|
|---|---|
|CHIRP_APP_KEY|ユーザー固有の文字列|
|CHIRP_APP_SECRET|ユーザー固有の文字列|
|CHIRP_APP_CONFIG|使用するChirpのプロトコル(周波数)を識別するため文字列<br>（ユーザー固有と思われます）|

この文字列を、使用するプラットフォーム（コンピューター言語）で指示されている箇所に記載して（ビルドが必要な場合はさらにビルドをして）ライブラリを利用します。

### 対応しているプラットフォーム（コンピューター言語）

開発者サイト[Documentationページ](https://developers.chirp.io/docs)の画面左側「GETTING STARTED」を参照してください。みればわかりますが、多くのプラットフォーム（コンピューター言語）に対応しています。

<b>Chirpを利用したTHETAプラグインを作成する場合、Android向けのライブラリを利用します。</b>[こちら](https://developers.chirp.io/docs/getting-started/android)のドキュメントを元にライブラリをリンクすることになります。
今回の記事では、<b>THETAプラグインでChirpを利用する際、サクっと作り始められる雛形プロジェクト一式</b>を提供していますので、一からご自身で環境構築したい場合やChirpライブラリの処理を詳しく知りたい場合に上記を参照すると良いでしょう。

余談ですが、2019/9/18にAndroid用SDKがアップデートされました。本プラグインは執筆時点で最新のバージョン3.10.0に対応しています。API名称の修正が行われたタイミングなので、このバージョンより前か後かは、ちょっと大切なことかもしれません。これより古いバージョンはもう使わないほうが良さそうです。

### Chirpプロトコル（通信周波数）の種類と制限

無料の範疇で利用可能なChirpプロトコルと制限を以下にまとめておきます。
（ひと目でわかるページが見当たらなかったので、まとめちゃいます。最新の情報は前述のユーザー登録後に参照できる、[資格情報を取得するページ](https://developers.chirp.io/applications)で一つずつご確認ください。）

※下表は、2019年10月初旬時点の情報です※

|<br>Chirpプロトコル名称<br>(Configuration名称)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|通信周波数帯と<br>チャンネル数<br>|1回の通信で<br>送受信可能な<br>データ量| 通信速度制限<br> |
|---|---|---|---|
|standard|1500Hz to 12975Hz<br> with a total of 1 channel(s).|32 bytes<br> in 4.52s|56.6 bps|
|16kHz|500Hz to 7800Hz<br> with a total of 1 channel(s).|90 bytes<br> in 8.16s|88.2 bps|
|16kHz-mono|2000Hz to 7865Hz<br> with a total of 1 channel(s).|32 bytes<br> in 4.48s|57.1 bps|
|ultrasonic|18200Hz to 19905Hz<br> with a total of 1 channel(s).|8 bytes<br> in 4.08s|15.7 bps|
|ultrasonic-<br>multichannel|17500Hz to 20090Hz<br> with a total of 8 channel(s).|7 bytes<br> in 3.24s|17.3 bps|

補足ですが、
「ultrasonic」と名称がついているものは、Chirpの詳細解説では「neer-ultrasonic」と表現しています。つまり、世の中に多く出回っているオーディオ機器で再生可能な周波数の上限 20kHz付近（→可聴音と定義されている上限付近→一般に超音波と定義されてい周波数に近い周波数）を利用している事を強調しています。超音波というと、メガヘルツオーダーの周波数を連想して高価なハードウェアが必要と思う方がいらっしゃるかもしれず、そんな誤解を避けるための呼び方のようです。
18kHzくらいより高い可聴音の周波数は、ほとんどの人が聴き取ることができません。「ほぼ超音波」「近超音波」という表現は上手ですね。


### スマートフォン用サンプルアプリ（サンプルライブラリ利用例）
Asio社は、サンプルライブラリの利用例をいろいろと公開しています。
その中でも、<b>[Google Play(Android)](https://play.google.com/store/apps/details?id=io.chirp.messenger) および [App Store(iOS)](https://apps.apple.com/app/chirp-messenger/id1438119896)に公開されているスマートフォンアプリ「Chirp Messenger」は、今回作成したプラグインへの命令送信とその応答受信に利用できます。</b>

ただし、ストアに置かれているアプリは「16kHz-mono」のプロトコル固定です。「ultrasonic」や「standard」で通信を行う「Chirp Messenger」がほしい方は、以下に公開されているソースコードを、各自がビルドする必要があります。

- [<b>Android用「Chirp Messenger」ソースコード</b>](https://github.com/chirp/chirp-android-examples#kotlin)
- [<b>iOS用「Chirp Messenger」ソースコード</b>](https://github.com/chirp/chirp-ios-examples/tree/master/Swift/Messenger)

※資格情報を仕込んでからビルドするのをわすれずに！
※Chirpプロトコル毎にキー文字列が異なるのも注意！

Android用は、THETAプラグイン開発環境と同じAndroid Studioでビルドできます。とくにハマることもなくあっさりビルドできましたので、Androidスマートフォンを利用する方は試してみることをおすすめします。近超音波は便利ですよー！


## 作成したTHETAプラグイン「Chirp Remote」の仕様

前述のようなサンプルライブラリの条件を踏まえ、今回作ったプラグインの特記事項を箇条書きにすると以下です。

- 対応するChirpプロトコルは「16kHz-mono」「ultrasonic」「standard」の3種類とする。
- 「Chirp Messenger」を有効活用したいため、通信内容は文字列とする。
- コマンド文字列は、どのChirpプロトコルでも共通とし、パラメータ込み最長8 Bytesに制限する。
- Chirpプロトコル(最長データ長)に合わせ応答内容を変える。
- 応答なしモードも設ける。<font color="Silver">（音楽ファイル再生で操作するケースでは応答不要。ユーザーが目的に応じてOn/Offできるよう配慮した。）</font>
- Chirpで応答を返す時だけ音量を最大にする。<font color="Silver">（シャッター音は指定音量を維持、消音に設定していてもChirp返信の音は鳴るよう実装。音量が小さいときに可聴音の通信失敗が増えたため対策した。可聴音を最大音量で鳴らしても迷惑にならないので許容する。）</font>
- 撮影指示を実行した場合は応答を返さない。<font color="Silver">（露光中はTHETAのカメラタスクがシステムボリュームをオフにするため。レリーズ音や光り物の消灯という反応で代替する。)</font>
- 動画の記録開始／停止には対応しない。<font color="Silver">（作成したプラグインがChirp受信のためにマイクのリソースを握っていると、THETAのカメラタスクが動画記録を行えないため。プラグインがリソースを離すと録画開始はできるものの、音通信トリガーで録画停止が行えない。対策検討が面倒なので割愛。）</font>
- THETA Z1, THETA V両対応プラグインとはするが、THETA Z1を優先した仕様とする。
- webUIはなしとする。

以降には、コマンド表、応答文字列、本体ボタン操作、表示(OLED or LED)、プラグイン終了時に保存する情報をまとめておきます。

### コマンド仕様

[GitHubの日本語README「List of commands」](https://github.com/theta-skunkworks/theta-plugin-chirp-remote/blob/master/README_jp.md#list-of-commands)を参照してください。

### 応答メッセージ仕様

[GitHubの日本語README「Response message specification」](https://github.com/theta-skunkworks/theta-plugin-chirp-remote/blob/master/README_jp.md#response-message-specification)を参照してください。

### ボタン操作仕様（機種共通 VはFnなしなだけ）

[GitHubの日本語README「Button operation」](https://github.com/theta-skunkworks/theta-plugin-chirp-remote/blob/master/README_jp.md#button-operation)を参照してください。

### 本体表示仕様(THETA Z1:OLED)

定常状態の表示は以下のとおり。

![03_OLED画面説明.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265455/7a4e8a8a-fbc4-7b78-a8a9-524b731c4dcb.jpeg)

Chirpコマンド受信と応答送信の表示ギミックは、個人的な遊び心でこんな感じにしてます。

![04_OLED画面_送受信.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265455/32e93c3c-1e4a-127a-75a1-4518ccc077a8.gif)


### 本体表示仕様(THETA V:LED)

![05_THETA_V_LED仕様.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265455/289a3ab7-d56f-334d-4195-dc4434e99afd.jpeg)

※LED3は、WLANモード切り替え操作後の約2sec間、切り替え結果が表示されます。
　(この表示をするため、APモード=青、CLモード=緑をChirpのために割り当てしていません)
※LED5はデバッグ用コマンドを打って動画モードにしたときに表示されます。


### プラグイン終了時に保存される情報

[GitHubの日本語README「Information to be saved when the plug-in ends」](https://github.com/theta-skunkworks/theta-plugin-chirp-remote/blob/master/README_jp.md#information-to-be-saved-when-the-plug-in-ends)を参照してください。

## ソースコード

今回作成したプラグインのファイル一式を[こちら](https://github.com/theta-skunkworks/theta-plugin-chirp-remote)においておきます。

この事例は 「THETAプラグインでChirp SDKを利用する事例」のみならず、以下の事例にもなっています。

- THETA Z1とTHETA Vの両対応プラグインですが、機種判別なしの共通処理でwebAPIを使っている。将来の機種追加やAPI変更耐性が高い。
- 過去記事「[THETA Z1のOLED描画ライブラリ的なもの](https://qiita.com/KA-2/items/b16fd6adc6db7db0fb8e)」を有効活用（継承して独自処理を追加する）。
- Chirpの通信部分を他の通信（シリアル、QRコード、etc）に置き換えても成立する。

こんなことも頭に置きながら、辞書的に活用して頂けると幸いです。
以降ではソースコード一式を読み解くためのガイド的な説明を記載します。
Chirpに関するところはちょっと詳しく説明しておきますのでご安心を。


### 全体の構成

[THETA Plug-in SDK](https://github.com/ricohapi/theta-plugin-sdk)のプロジェクト一式をベースに[Android用Chirp SDK](https://developers.chirp.io/docs/getting-started/android)を取り込んだ構成です。
機能ごとにファイルを分割してあるので、他のプラグインを作るときの流用もしやすくなっていると思います。

「theta-plugin-chirp-remote\app\src\main\java」配下のフォルダ構成は以下となっています。

```
theta-plugin-chirp-remote\app\src\main\java
├com
│└theta360\pluginapplication
│　├model		// THETA Plug-in SDKのままです。
│　├network	// 過去事例と同じようにHttpConnector.javaにメソッド追加したのみです。
│　├oled		// Oled.java(OLED描画ライブラリ的なもの)のみです。
│　└task		// HID Remoteベースに修正&追加したwebAPI実行用タスク12ファイルがあります。
└skunkworks
　└chirpremote	// MainActivity.javaを含む3ファイル（コマンド解析、表示の2ファイルを追加）があります。
```

- 過去事例 HttpConnector.javaの説明は[こちら](https://qiita.com/KA-2/items/763f818fffdfc1b79b9a#httpconnectorjava)
- OLED描画ライブラリ的なものの記事は[こちら]()
- HID Remoteの記事taskの説明は[こちら](https://qiita.com/KA-2/items/e847c780cc0fee187f89#%E5%90%84%E7%A8%AE%E3%82%A2%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E5%AE%9F%E8%A1%8C%E9%83%A8)

### Chirpの資格情報設定箇所

資格情報については「ユーザー登録とビルド」にて説明済みです。
今回作成したTHETAプラグインでは、プラグインを起動したまま、操作によってChirpプロトコルを切り替えられるようになっている点がサンプルプログラムと異なります。
これを実現するために「CHIRP_APP_CONFIG」キー情報は、3種類の周波数それぞれについて取得し、MainActivity.javaの以下に示す箇所に記載してください。

```java:MainActivity.java
    private static final String CHIRP_APP_KEY = "Please set the credential you have acquired.";
    private static final String CHIRP_APP_SECRET = "Please set the credential you have acquired.";
    //16kHz-mono
    private static final String CHIRP_APP_CONFIG_16K_MONO = "Please set the CHIRP_APP_CONFIG key for the '16kHz-mono' protocol.";
    //ultrasonic
    private static final String CHIRP_APP_CONFIG_US = "Please set the CHIRP_APP_CONFIG key for the 'ultrasonic' protocol.";
    //standard
    private static final String CHIRP_APP_CONFIG_STD = "Please set the CHIRP_APP_CONFIG key for the 'standard' protocol.";
```

### Chirp周り
前述の通り、<b>今回公開したソースコード一式では、Chirpの環境構築が済んでいます。</b>もし、ご自身でChirpの環境構築をしたい場合は[こちら](https://developers.chirp.io/docs/getting-started/android)を参照してください。基本はmavenで取り込むだけなので楽です。より詳細なChirpメソッドの説明は[こちら](https://docs.chirp.io/android/chirpsdk/io.chirp.chirpsdk/-chirp-s-d-k/index.html)にあります。

上記にはないTHETAプラグイン固有のポイントは以下です。

#### パーミッション設定を促すダイアログに関するコードは不要

THETAは「画面操作できない」という仕組みのため、マイクに関するパーミッションは

- <b>開発者はVysorのSettings->Appからパーミッションを与える。</b>
- プラグインストアからの利用者にはインストール時にパーミッションを与える。

というTHETAプラグイン固有作法になっています。（<b>マイクを使う開発者はデバッグのとき太字をお忘れなく！</b>）

したがって、Chirpのドキュメントにあるコードの中で[ダイアログを促すコード](https://developers.chirp.io/docs/getting-started/android#runtime-permissions)は全部削除して問題ありません。

たとえば ChirpのドキュメントにあるonResume()の

```java:ChirpWebPageSample.java
  if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.RECORD_AUDIO}, RESULT_REQUEST_RECORD_AUDIO);
  }
```

や、以下メソッドがまるごと不要です。

```java:ChirpWebPageSample.java
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
 ～省略～
}
```

#### onStateChanged(),onSystemVolumeChanged()は使わないけど残した

今回作成したプラグインでは、onStateChanged(),onSystemVolumeChanged()のメソッドを使用していません。しかし、THETAプラグインでChirp SDKを使う雛形という立場から、雛形コードを残してあります。

#### THETAプラグインでマイクを使う作法を入れる

[こちらの記事](https://qiita.com/kushimoto/items/e2ee2b1abd05dc50ffcf#1-%E3%83%A2%E3%83%8E%E3%83%A9%E3%83%AB%E3%81%A7%E9%8C%B2%E9%9F%B3%E3%81%99%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B)で解説済みです。以下の部分をChirpライブラリまわりの処理を呼ぶ前に行ってください。

```java:MainActivity.java
    @Override
    protected void onResume() {
        super.onResume();

        // マイクを使うプラグインにおけるTHETA固有の設定。
        // これをしないとChirpライブラリに音を渡せない。
        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        audioManager.setParameters("RicUseBFormat=false");

        ～省略～
    }
```

#### プラグイン(アプリ)動作中の周波数切り替えを可能としたので、独自のChirpメソッドが増えてます。

引数に応じて、Chirpのコンフィグレーション（通信周波数）を設定する処理をメソッドにしてあります。

```java:MainActivity.java
    private void initalChirpSdk(int chirpConfig) {
        ～省略～
    }
```

#### 音量変更はChirp SDKメソッドで行う

今回作成したTHETAプラグインでは、THETA固有音はプラグイン起動前の状態を維持しますが、Chirp通信は"音"が必要なので、データ送信前に「送信用の音量」とし、データ通信後に元に戻すという処理をしています。
その際、音量変更はChirp SDKのメソッドで行っています。Chirpライブラリ動作中にwebAPIのコマンドで音量変更が行えない（エラーになる）のでご注意ください。

```java:MainActivity.java
    private void sendString(String sendStr) {
        //入力チェック
        long maxSize = chirp.maxPayloadLength();
        byte[] payload = sendStr.getBytes();
        if (maxSize < payload.length) {
            Log.d(TAG, "Invalid Payload");
            return;
        }

        //音量を送信用に設定する
        chirp.setSystemVolume(displayInfo.replyVolume);
        //送信
        ChirpError error = chirp.send(payload);
        if (error.getCode() > 0) {
            Log.d(TAG, error.getMessage());
            //音量を戻す
            chirp.setSystemVolume(displayInfo.restoreVolume);
        }
    }
```

```java:MainActivity.java
        @Override
        public void onSent(byte[] data, int channel) {  //送信完了
            /**
             * onSent is called when a send event has completed.
             * The data argument contains the payload that was sent.
             */
            String sentString = "null";
            if (data != null) {
                sentString =  new String(data);
            }
            Log.d(TAG, "ConnectCallback: onSent: " + sentString + " on channel: " + channel);

            //音量を戻す
            chirp.setSystemVolume(displayInfo.restoreVolume);

            displayInfo.messageCnt=0;
            displayInfo.messageType = DisplayInfo.DIALOG_MSG_NORM;
            displayInfo.messageStr = "";

            displayInfo.setLedChirpSending(false);
        }
```

余談ですが、今回については、送信用音量を最大固定としていますが、「THETA固有音とは独立した任意の音量」に変更しやすいコードが書いてあります。

### MainActivity.javaのChirp以外のポイント

#### WLANモードのチェック方法あります

<2022/10/26追記>
>RICOH THETA X では、（追記時点 FW 1.30.0までは確実）
>- _networkTypeの応答でOFFが取得できません。OFF前のAP/CLの状態がとれます。
>- _networkTypeSupportに対応していません。
>以降の処理は、RICOH THETA V/Z1 までで有効な手段となります。


「プラグインが起動したときのWLANモード(AP/CL/OFF)を識別したい」という場合があります。その時は[webAPI getOptionの「_networkTypeSupport」](https://github.com/ricohapi/theta-api-specs/blob/main/theta-web-api-v2.1/options/_network_type.md)で取得することができます。ドキュメントはWi-Fi経由での呼び出し前提であるため、'OFF'という応答について記載がないのですが、プラグインからだと'OFF'という応答が得られるのがポイントです。

今回は、

- taskフォルダ配下にCheckWlanModeTask.javaというタスクを用意
- MainActivity.javaのonResume()でタスクを呼び出す

```java:MainActivity.java
        //WLANモード(OFF/AP/CL)を取得
        new CheckWlanModeTask(mCheckWlanModeTaskCallback).execute();
```

という実装にしてあります。ご参考まで。

#### プラグイン起動のMode長押し後、不要なonKeyUpを誤認識する問題の対策を改善

[「音声認識モジュールと連携する記事」](https://qiita.com/KA-2/items/940469de8db26d4e8997#%E6%9C%AC%E4%BD%93%E3%83%9C%E3%82%BF%E3%83%B3%E6%93%8D%E4%BD%9C%E9%83%A8%E5%88%86)にて、

>プラグイン起動するためにModeボタン長押しがされると、プラグインが起動したあとに指を離すこととなり、そのイベントがプラグインにまで届いてしまいます。
>このonKeyUpを「firstModeButtonUp」の変数によってスルーするようにしている

と解説していた件、「最初のModeボタンonKeyUpを無視する」というコードだったので不完全でした。。。
今回は<b>「ModeボタンonKeyDownと対になるonKeyUpではない時、無視する」</b>と改善していますので、コードを参照してみてください。
（失礼いたしておりました。。。）

#### SharedPreferencesで前回動作時の情報を引き継ぐ

Androidアプリを作成している方々には当たり前だったのですが、それを知らず、たびたび説明に登場している「[HID Remoteの記事](https://qiita.com/KA-2/items/e847c780cc0fee187f89)」では、ゴリゴリと自分で書いていました（汗
今回からSharedPreferencesを使うよう改善しています。

```java:MainActivity.java
    //==============================================================
    // 設定保存・復帰
    //==============================================================
    private static final String SAVE_KEY_CHIRP_CONFIG  = "chirpConfig";
    private static final String SAVE_KEY_CHIRP_REPLY = "chirpReply";
    private static final String SAVE_KEY_TIME_SHIFT = "timeShift";
    SharedPreferences sharedPreferences;

    void restorePluginInfo() {
        sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());

        displayInfo.chirpConfig = sharedPreferences.getInt(SAVE_KEY_CHIRP_CONFIG, DisplayInfo.CHIRP_CONFIG_16KHZ_MONO);
        displayInfo.chirpReply = sharedPreferences.getBoolean(SAVE_KEY_CHIRP_REPLY,true);
        displayInfo.timeShift = sharedPreferences.getBoolean(SAVE_KEY_TIME_SHIFT,false);
    }

    void savePluginInfo() {
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putInt(SAVE_KEY_CHIRP_CONFIG, displayInfo.chirpConfig);
        editor.putBoolean(SAVE_KEY_CHIRP_REPLY, displayInfo.chirpReply);
        editor.putBoolean(SAVE_KEY_TIME_SHIFT, displayInfo.timeShift);
        editor.commit();
    }
```

これを必要な箇所で呼び出すだけ。楽になりました。


### 表示部(Z1向け)

「本体表示仕様(THETA Z1:OLED)」にまとめた振る舞いは、「theta-plugin-chirp-remote\app\src\main\java\skunkworks\chirpremote」フォルダにある「DisplayInfo.java」にクラスとしてまとめています。

このクラスは、[「OLED描画ライブラリのようなもの」の記事](https://qiita.com/KA-2/items/b16fd6adc6db7db0fb8e#%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89)で作成したクラスを継承しています。
上記記事では1ファイルでサンプルコードを提供したかったので無茶をしていましたが、今回はMainActivity.javaがスッキリしました。

### 表示部(V向け)

THETA VのLED制御だけ処理を切り離すほどコード量がなかったので、Z1向けOLED用のクラス「DisplayInfo.java」にメソッドをまとめてしまいました。

MainActivity.java LED変更のトリガーとなる箇所から、以下メソッドを呼び出すことで「本体表示仕様(THETA V:LED)」にまとめた振る舞いをするようにしています。

```java:DisplayInfo.java
    void setLedChirpReceiving(boolean ledOn) {
    void setLedChirpSending(boolean ledOn) {
    void setLedChirpConfigAndTsStat() {
```

### コマンド解釈部

「コマンド仕様」にまとめた独自コマンドを解釈する処理を、「theta-plugin-chirp-remote\app\src\main\java\skunkworks\chirpremote」配下にある「Command.java」に、クラスとしてまとめてあります。

コマンド解釈をしたあとは、各タスクに処理をディスパッチします。
独自コマンド固有の固定値もここに集まっています。

他の通信（シリアル通信、QRコード、etc）でTHETAをリモート操作する場合、同じコマンド体系を使うならばこのクラスのメソッドを呼べばよいだけになりますし、独自体系のコマンドとする場合（バイナリにするなど）にはこのクラスを書き換えればOKです。

### コマンド実行部（各種タスク群）

「theta-plugin-chirp-remote\app\src\main\java\com\theta360\pluginapplication\task」配下に、webAPIを実行する以下のファイルがあります。

|No<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|ファイル名<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|説明<br>&nbsp;|
|---|---|---|
|1|ChangeApertureTask.java|絞り値を変更します|
|2|ChangeCaptureModeTask.java|静止画/動画切り替えをします|
|3|ChangeEvTask.java|露出補正値を変更します|
|4|ChangeExposureDelayTask.java|タイマー値を変更します|
|5|ChangeExpProgTask.java|露出プログラムを変更します|
|6|ChangeIsoTask.java|ISO感度を変更します|
|7|ChangeShutterSpeedTask.java|シャッター速度を変更します|
|8|ChangeVolumeTask.java|THETA固有音の音量を変更します|
|9|ChangeWbTask.java|ホワイトバランスを変更します|
|10|CheckWlanModeTask.java|WLANモードを取得します（説明済）|
|11|GetCameraStatusTask.java|カメラの状態を周期チェックするためのタスクです|
|12|ShutterButtonTask.java|本体のシャッターボタンと同じ振る舞いに加え、タイムシフト撮影の開始／停止も行えます|

基本は、[HID Remoteのtaskにあるコード](https://github.com/theta-skunkworks/theta-plugin-usb-hid-sample/tree/master/app/src/main/java/com/theta360/pluginapplication/task)をベースとして以下変更を加えています。

- 「発話=音楽ファイル再生なし」とした。
- タスク間インターフェース修正（Customer利用）してタスク間で共通の結果設定処理（コールバック的処理）を仕込めるようにした。
- THETAの機種依存や条件依存をしないよう作り変えている。具体的には「Support値」を利用している。例えば<b>シャッター速度は機種によって範囲が異なったり露出プログラムによって範囲が変わりますが、設定する都度Support値をチェックすることですべて共通処理になります。</b>
- これまでに不足していた撮影パラメータ設定処理をおおむね網羅した。（静止画のAUTOモードで実行できる特殊撮影は除く）

「Chirpライブラリ動作中に、webAPIからの音量変更はできないけれどTHETAの音量変更タスクを残す」など、<b>後から使える小道具</b>として配慮しました。
THETAプラグインを作成する方々に有効活用してもらえると嬉しいです。


## オーディオファイルについて

### 配布ファイルについて
GitHubに公開したファイル一式の中に「[audiofiles](https://github.com/theta-skunkworks/theta-plugin-chirp-remote/tree/master/audiofiles)」というフォルダがあります。
その配下に、mp3ファイルとwavファイル、それぞれ3種類のChirpプロトコルについて、再生するだけでTHETAが操れる音楽ファイルを置いておきました。

![06_オーディオファイル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265455/2fa17665-a1b8-ad97-f90c-35a92d0ba31b.png)


すべてのコマンドを網羅していますが、パラメータとの組み合わせは省略している場合があります。シャッター速度、ISO感度、ホワイトバランスの色温度などは、結構な幅を細かい分解能でパラメータ選択できますのでご容赦を…。必要に応じて、以降の手順で作成してください。

### 作り方（Pythonコマンドラインツール）
[こちら](https://developers.chirp.io/docs/tutorials/command-line)の手順にしたがって環境構築から行ってください。概ね以下の手順です。

1. Pythonをインストール（これはPythonのサイトを調べてください）
2. Pythonのパッケージ管理ツールpipで chirpsdkをインストール
3. Pythonホームディレクトリに「.chirprc」というテキストファイルを作り、Chirp資格情報を記載する。
4. [おまけ] Windows環境の場合、コマンドにパスを通しておく。

[4. Windows環境の補足]

- コマンドの実体となるPythonスクリプトは、「C:\Users\（ユーザー名）\AppData\Local\Programs\Python\Python37-32\Lib\site-packages\bin」あたりにあります。
- </br>コマンドの実体になるPythonスクリプトに拡張子がついていないので「.py」という拡張子をつけるとよいです。


これができたあとは、「Generate a .wav file containing a Chirp payload」にしたがってwavファイルを生成するだけです。めちゃくちゃ簡単です。多量に作る場合はバッチファイルのようなもので生成すればよいです。

しかし、、、
windows環境では、Pythonコマンドラインツールのセットアップで数点ハマるかもしれない事があるので、以下に記しておきます。

#### Windows環境におけるPytonホームディレクトリ「~/」はどこ？
Chirp資格情報を記載するファイル「.chirprc」をPythonのホームディレクトリ「~/」に作れとあるわけですが。。。「Windows版Pythonにおけるホームディレクトリがどこかワカラン」でしばし放心状態になりました。

調べた結果、「私の場合」としかかけませんが（汗

>C:\Users\（ユーザー名）\

でした。
よーし！これでコマンドラインChirpつかえるぞー！とおもいきや、次のトラップが待っています。

#### Windows環境における「.chirprc」のファイル名トラップ
「.chirprc」というテキストファイルに書くだけ。簡単簡単。。。
とおもいきや、Windowsは、ファイル名の先頭が「.」で拡張子がないファイルを作らせてくれず、しばし失神しました（汗

調べた結果、ファイル名を入力するときに<b>「.chirprc.」と、お尻にピリオドをつけてリターンキーを打つ</b>という技があることを知りました。
いやぁ。。。知りませんでしたこんな技。お恥ずかしい。。。


### 配布ファイルについているタグ情報について

今回配布する音楽ファイルには、wav、mp3共に、

- アーティスト名 ＝ Chirp Remote
- アルバム名 ＝ プロトコル名称（16kHz-mono/ultrasonic/standard）
- 曲名 = 送信しているコマンド文字列

が設定してあります。

Chirpコマンドラインツールが出力されるwavファイルには上記タグは付与されていないので、「[SuperTagEditor改 Plugin Version (Nightmare)](https://hp.vector.co.jp/authors/VA012911/STEP/step.html)」を使って付与しました。

wavファイルのタグが読めるソフトは少ないかもしれませんが、音解析の定番フリーソフト「[audacity](https://www.audacityteam.org/)」では読めました。こうしておくと、他の音楽ファイルフォーマットへの一括変換のときに便利です。
mp3ファイルにタグをつけておく効能は「オーディオファイル再生で使う」の章を参照するとわかります。

### 配布ファイルのビットレートについて

Chirpコマンドラインツールが出力するwavファイルは、

- <b> モノラル, 16bit, 44100Hzサンプル</b>

です。
リサンプルしないと読めない機器もあるかもしれません。稀にステレオにすると読める機器もありました。このあたりは再生機器にあわせて試行錯誤してください。
wavファイルフォーマットについては[こちら](https://www.youfit.co.jp/archives/1418)などが参考になります。


上記wavファイルから生成したmp3ファイルのビットレートは以下としてあります。

- <b>「16kHz-mono」「standard」用が 48kbps</b>
- <b>「ultrasonic」が 192kbps</b>

古いmp3プレーヤーでは配布しているファイルが認識できないケースもあります。
ultrasonicはmp3変換によって微妙に（コマンドとして影響がない程度に）波形が乱れており、ちょっとノイズのような音が聞こえます（再生機器の能力によってノイズの出方も変わります）。綺麗に近超音波を再生したい場合はwavファイルを使うほうがよいでしょう。
また、ultrasonicのwavをmp3に変換するときは、ビットレートを80kbps以上にしないとサンプル数が足りず波形が潰れるのでご注意ください。


## 使い方

### Chirp Messengerで使う

詳細な応答文字列をみたいならば「16kHz-mono」「standard」がよいです。
Chirp音を鳴らしたくない場合は「ultrasonic」がよいです。

どのChirpプロトコルを使用していても操作はすべて同じで簡単です。<b>「コマンド仕様」の文字列を打つと「応答メッセージ仕様」の応答が帰ってきます。</b>
このプラグインをTHETA Z1で使う場合、OLEDに十分な情報を出しているので、「Chirp応答なし」で使うのも良いと思います。

![ChirpMessenger基本操作.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265455/e2ebd9c3-d82f-a9bb-5f89-03aec22eddf9.gif)


### オーディオファイル再生で使う

<b>THETA側と周波数があった音楽ファイルを再生すればTHETAが反応します。超簡単。</b>

この使い方では、「Chirp応答なし」にする方が大半と思います。
音楽ファイルが正しく再生できているか不安になる場合は、事前に「Chirp Messenger」に受信させて確認をすると良いです。

自分に必要な音楽ファイルだけチョイスすれば自分だけの操作メニューができあがりますし、かなり便利なのかも！プレイリストをTHETAに聞かせてシーンに応じた初期設定にするなんて使い方もできますね。

<b>簡単ゆえにバリエーションが無限大。</b>いくつかの事例をベースに快適に使うポイントを説明します。

#### スマートフォン

１コマンドづつ操作する場合のコツは<b>「1曲再生したら止まる」プレイヤー</b>を使うことです。手動操作でイチイチ止めないと次々にコマンドが送られる状態はしんどいです。
（1ファイルづつ「フォルダを分ける」とか「アルバム名を分ける」という手もありますけれど…）

Androidスマートフォンの場合「[GoneMAD Music Player](https://play.google.com/store/apps/details?id=gonemad.gmmp)」という有料プレーヤー（14日間無料）で、その振る舞いにできました。他にもあったら紹介してください。

![使い方_再生1音楽プレーヤー.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265455/7bce72b3-ae31-190e-a114-91304af3bf30.gif)

iOSの場合は、プレイリストを作成してチェックを外すとその振る舞いにできるようです。私はiPhoneをつかっていないので、どなたか試して頂けると助かります。

#### ボイスレコーダー

<b>ボイスレコーダー（ICレコーダー）は、大抵の場合、音楽ファイルも再生でき「1曲再生したら止まる」ができます。</b>アルバム名、曲名表示ができるとChirpプロトコルを選択してコマンド一覧からコマンドを選ぶという操作感になります。<b>まるで、最初からTHETAリモコンだったような振る舞いに（笑）。</b>

![使い方_再生2_ボイレコ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265455/cb60bdd0-7733-32fb-4aff-0c6f779f9683.gif)

（これを狙って、アルバム名や曲名のタグをいれていたのです）

#### 格安プレーヤー＆イヤホン

<b>イヤホンジャック出力のみのmp3プレイヤーと100円ショップのイヤホンなんていう組み合わせでも、近超音波で音量最大にしておくと、おおむね60～70cmくらいまでデータ送信できます！</b> 自撮り棒につけたTHETAにレリーズをさせるだけなら、こういう手段もアリかもしれません。死蔵していたmp3プレーヤーが復活する方もいらしゃるかもしれませんね。お安いほどに「1曲再生したら止まる」ができなかったり曲名表示ができない点は注意です。

![使い方_再生3_格安MP3とイヤホン.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265455/7ec6ae5f-a3f3-64a7-fc1a-5cfc759b0665.gif)

※上記は、実売1500円程度の[こちらのプレイヤー](https://www.green-house.co.jp/products/gh-kanadt8/)に100円ショップのイヤホンを繋いで、THETAに撮影指示をしています。「1曲再生したら止まる」ができない点がしんどいです。

#### 数百円クラスのプレーヤーは要注意

試してみたのは[コレ](https://www.amazon.co.jp/gp/product/B07DJ8H92K/ref=ppx_yo_dt_b_asin_title_o06_s00?ie=UTF8&psc=1)です。なんと、購入時点で119円。

![100円プレーヤー.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265455/c6810dd2-68c8-c47d-b751-e98ef975af3a.gif)

中身は、メニュー画面から判断するに、基本[こちら](https://rocketnews24.com/2018/10/29/1132172/)と同じハードウェアやファームウェアだと思われます。（[画面なしのコレ](https://rezv.net/gadget/34288/)も同じでしょうね…）
いかにも怪しい……とはいえ、<b>本体スピーカーが付いている</b>ことに惹かれ人柱してみました。

- 本体スピーカーだけでなく<b>実績のあるイヤホンや外部スピーカーでもChirp通信はNG</b>（音楽なら本体スピーカーですらそれっぽく鳴るのに…惜しいなぁ）
- 可聴音は人間の耳で聴き比べても微妙に違う音が鳴っているのがわかる（汗
- ちなみに、イコラーザー機能はNOR（ノーマル）です。他はエフェクトがキツイ。

<b>この振る舞いは、DACの過程でどこかの周波数をカットオフしているんじゃないでしょうか！？</b>
（イコラーザー機能がNOR（ノーマル）でも、なにか波形を弄っている仕様では。。。）

小さいのに本体スピーカー内蔵は魅力です。なんとwavファイルも再生しちゃったのに。惜しい、惜しいよコレ。。。
というわけで、<b>ここまで怪しいものに手を出す時はご注意ください！基本ダメモトです（笑）</b>


## 番外編

### M5Stackから近超音波mp3を鳴らす

Chirp ESP32用ライブラリは現時点 16kHz-monoのプロトコルにしか対応していません。しかしです。ESP32を利用したHWの中でもM5Stackはスピーカーがついていてmp3を鳴らす手段があります。
というわけで、[こちらの記事](https://qiita.com/ktansai/items/f0096495e2ca7fa38eb7)を参考にして鳴らしてみた結果が以下です。
（記事中ではアニメGIFで音がありません。音つき動画は後日Twitterで公開するかもしれません。未定です。）

![M5Stack_Ultra.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265455/7b18f459-f431-91a6-78f8-a03b2ce1df74.gif)

THETA、純正Chirpアプリ、どちらでもコマンドを認識できたものの・・・

<b>M5Stackでは "人間に聴こえまくる音" でしか再生できない！</b>

M5Stackは、"自然音を鳴らすと爆音固定になる"ことで有名でしたが、この近超音波ファイルを鳴らした場合には爆音にならないだけでも凄いことなのかもしれません。
つまり、[こちらの記事](http://blog-yama.a-quest.com/?eid=970193)を参考に、可変抵抗をつけて音量を絞ればよいのかも！？


### M5StickVから近超音波wavを鳴らす

[M5StickV](https://www.switch-science.com/catalog/5700/)は、wavファイル再生に対応しており、サンプリング周波数などが同じだったので「ミクミンさん作成 Brownie の起動音を今回作成したwavファイルに差し替える」という簡単動作確認をしてみました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">M5StickV の物体認識アプリ brownie ですが、<br>アプリは <a href="https://t.co/ABpArRG4SV">https://t.co/ABpArRG4SV</a> にあります。<br>簡単ですが日本語の説明も書きました(microSDカードの相性の話も書きました) <a href="https://t.co/inM7yA1pLL">https://t.co/inM7yA1pLL</a></p>&mdash; ミクミンP/Kazuhiro Sasao (@ksasao) <a href="https://twitter.com/ksasao/status/1155127815051726849?ref_src=twsrc%5Etfw">July 27, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

やったことは、microSDカードに鳴らしたいwavファイルを置き、boot.pyの「wavファイル名」と「音量の数値」を書き換えただけです。
[こちらの記事](https://qiita.com/manontroppo1974/items/43105469a8d560bfead8
)も参考になるかもしれません。

<b>結果</b>

- 16kHz-monoの音は簡単に鳴って、Chirpアプリ、THETA共に認識できました。
- ultrasonicの音は・・・Chirpアプリ、THETA共に反応なし。一体どーなって？<br>※音量は5くらいから最大の100まで色々振ってみましたが同じです。

なにしろ超音波ゆえ体で感じられない。。。
そこで「[Ultra Sound Detector](https://play.google.com/store/apps/details?id=com.microcadsystems.serge.ultrasounddetector&hl=ja)」というアプリで、17kHz～20kHz近辺の音圧時間変化を確認しました。
その結果が以下。

![M5StickV実験.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265455/d9c4d96e-a443-4100-598e-5e28ddf12355.gif)

<b>おぉっ！？該当周波数帯になにかが出てはいるぞっ！</b>

しかし、受信失敗のケースでも「受信中」にはなったりする純正Chirpアプリですら反応なし。
たぶん、このあたりの周波数に対応していないスピーカーなのかもしれません。
（あとで部品しらべてみよう。。。いや、教えて頂けたらありがたいです！）

### スマートスピーカーとChirp通信で連携する

すみません、試してはいないのですが・・・

スマートスピーカーで所望のアルバムの所望の曲を再生するのって簡単なのですよ。
スマートスピーカーで超音波の音楽ファイルを再生させてTHETAを操るという簡単連携ができちゃうわけです。

THETA側はというと、Wi-FiやらBluetoothやらは未使用でして、今回作成したプラグインに撮った画像をどこかへアップロードさせるような機能追加をするなどの余白があります。
精度良い自然言語理解をする仕掛けをTHETAに内包させるより、手っ取り早く「言葉でTHETAに多様な仕事をさせる」という実験をすることができそうです。


### 3Dモデリングのために複数台THETAの同期撮影をする

実は私、何年か前（もちろんTHETAにPlug-inなんて仕組みが導入されてない頃）、「Wi-Fiを使って5台のTHETAを（できるかぎり）同時撮影をする」なんてことを試したことがあります。
それぞれのTHETAとペアリング済みのESP8266モジュールから、電気信号トリガーで一斉にtakePictureコマンドを送出させるなんてことをした訳ですが。。。
結構タイミングが揃わないものなのです（動くさまは壮観でしたけれどｗ）

今回のプラグインを使うとどーなるのか、ちょっと試してみました。

![番外編_5台同期撮影.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265455/d092a0bf-2aa6-0718-618f-161c21989449.gif)

何回やってもこんな感じ。いくらかズレはありますが、過去より安定しています！
なんといっても、難しい仕掛けが不要というのが良いです。


## まとめ

Chirp SDKとTHETA Plug-inの組み合わせで、新たにTHETAを無線で操る術が手に入りました。Chirp SDKは、無料で利用できる範疇でもこんなに使えるツールなわけですが、もっと可能性を感じます。

今回はリモートコントロールにChirp SDKを利用しましたが、もうちょっと送れるデータ量が増えると、「THETAからいずれかのサイトにアップロードした映像のURLを、その場で複数の人へ同時に通知する」というような使い方も良いと思っています。（無料では、近超音波で送受信できるデータ量が少ないのが歯がゆいですね。。。）

あと、裏技的に、近超音波は、可聴音（音楽や効果音）と重ねて送信することも可能です。重ねる可聴音しだいではUI・UX的にもっと面白いことができそうです。
今回のコードを参考にいろいろとトライして頂けると幸いです。

と、いうわけで、今回作成したプラグインですが、現在SKUNK WORKSとしてストア公開している[HID Remote](https://pluginstore.theta360.com/plugins/skunkworks.hid/)に続きー

<b>SKUNK WORKSストア公開プラグイン　第3弾「Chirp Remote」</b>

~~の手続きをしてみようと思います。
とはいえ、いろいろ難関がありそうなので時間がかかるかもしれません。~~
（2020/01/07 追記：[ストア公開しました！](https://pluginstore.theta360.com/plugins/skunkworks.chirpremote/) 開発者ではない方々もお試しいただけます！）


<b>ん！？"第3弾"？</b>
----

と思ったソコのアナタ。すごいTHETAプラグイン通ですね。
Qiita記事化もしているSKUNK WORKSストア公開プラグインはまだ１つだけでした。実は、こっそり

<b>SKUNK WORKSストア公開プラグイン　第2弾 [「Plug-in Launcher for Z1」](https://pluginstore.theta360.com/plugins/skunkworks.launcher/)</b>

なるものをストア公開しました！

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">パートナーから新しいプラグインが公開になりました！THETA Z1でより簡単にプラグインを選択できるようになります。<br><br>何を隠そう、開発元SKUNK WORKSはこちらのコミュニティメンバーが開発したプラグインだったりします。<a href="https://twitter.com/hashtag/thetaplugin?src=hash&amp;ref_src=twsrc%5Etfw">#thetaplugin</a><a href="https://t.co/ijFBmKphJF">https://t.co/ijFBmKphJF</a></p>&mdash; THETAプラグイン開発者コミュニティ (@thetaplugin) <a href="https://twitter.com/thetaplugin/status/1184740720378204160?ref_src=twsrc%5Etfw">October 17, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

これ[【THETA Z1 OLED描画ライブラリ的なものつくりました】](https://qiita.com/KA-2/items/b16fd6adc6db7db0fb8e)の副産物なのです。THETA Z1にインストールしてあるプラグインを一覧から選択してどれでも起動できちゃいます。（プラグインは2GBまでわりと沢山インストールできるものの、ボタン操作だけで"直ぐに"起動できるのはZ1の場合3個まで(Vは1個)」という制限があります。不便だったので作ってしまいました。）
こちらもよろしくお願いいたします。


## RICOH THETAプラグインパートナープログラムについて

THETAプラグインをご存じない方は[こちら](https://github.com/ricohapi/theta-api-specs/blob/main/core/products/theta-plugin.md)をご覧ください。
パートナープログラムへの登録方法は[こちら](https://qiita.com/mShiiina/items/55d98f366e650ca42251)にもまとめてあります。
興味を持たれた方は[Twitter](https://twitter.com/thetaplugin)のフォローと[THETAプラグイン開発コミュニティ(Slack)](https://join.slack.com/t/thetadeveloper/shared_invite/enQtNzcxODI2MTk2ODg0LWY5YmU2ZTIxNGYwNzlmNWZjMWMyMWFlMzY3ZmQ3NGU3ZjZiZjI0Njk4MGIxMDU5NDJiMzQ4Y2FkNDEzYmFlNGU)への参加もよろしくおねがいします｡