IoTでマトリョミン(楽器)を作ってみた(2/2)AR.jsでマトリョーシカ編


## はじめに

音楽まったくやってない人って楽器ひくことにちょっとしたあこがれないですか？
私はそんな一人です、楽器ひいてみたい。
ということで、かくかくしかじかあってマトリョミン作ることにしました。[前回](https://qiita.com/suo-takefumi/items/1c39e8434b68358c4339)は、音を奏でるテルミン(風)までを作りました。今回は、見た目をマトリョーシカにしていきます。

## 完成デモ

できたマトリョミン(風)はこちら。ARで見た目をマトリョーシカにしていて、奏でる音階に合わせてマトリョーシカの表情が変わります。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">テルミンを内蔵するマトリョーシカ、その名もマトリョミン。マトリョミン風の楽器をIoTで作ってみる。<br>ステップ(7) ARで見た目をマトリョーシカにするの完成<br>よし！マトリョミン風の楽器できた！<a href="https://twitter.com/hashtag/Matryomin?src=hash&amp;ref_src=twsrc%5Etfw">#Matryomin</a> <a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://twitter.com/hashtag/AFrame?src=hash&amp;ref_src=twsrc%5Etfw">#AFrame</a> <a href="https://twitter.com/hashtag/ARjs?src=hash&amp;ref_src=twsrc%5Etfw">#ARjs</a> <a href="https://twitter.com/hashtag/obniz?src=hash&amp;ref_src=twsrc%5Etfw">#obniz</a> <a href="https://t.co/QPn6TUzLzU">pic.twitter.com/QPn6TUzLzU</a></p>&mdash; suo-takefumi (@zsipparu) <a href="https://twitter.com/zsipparu/status/1340555905201410050?ref_src=twsrc%5Etfw">December 20, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 距離センサーとスピーカーで音を奏でて、かつARと連携する仕組みを作る

[前回](https://qiita.com/suo-takefumi/items/1c39e8434b68358c4339)は、距離センサーとスピーカーで奏でる音を制御しましたが、今回はさらにARとも連携させます。ARは、A-FrameとAR.jsを使いました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/18b92fb3-5d5c-b553-b467-0f61471ba5ad.png)

前回LEGOで組み立てたテルミン(風)に、LEGO互換パーツ化したARマーカーを付けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/f68fe516-7ea6-9aa3-13ee-32e4dde9c415.png)

※LEGO互換ARマーカーの作り方はこちらで紹介しています
　→[レジンでLEGO互換パーツを自作したい！その(１)](https://note.com/agw/n/na2e8383ca5c4)

## 制御スクリプトはこちら

[前回](https://qiita.com/suo-takefumi/items/1c39e8434b68358c4339)にちょっと追加で制御スクリプトが作れると思っていたのですが、甘かった。obniz x A-Frame x AR.js 連携の情報が見つからなくて結局自作しました(ちょっと苦戦しました)。

```html
<!doctype HTML>
<html>
<script src="https://unpkg.com/obniz@3.10.1/obniz.js"></script>
<script src="js/aframe.min.js"></script>
<script src="js/aframe-ar.js"></script>
<body style="margin: 0px; overflow: hidden;">
<script>
let obnizConnectFlg = 0;
let hcsr04;
let speaker;
let glNo = 0;
let updateFlg=0;
const SCALELENGTH = 15;
const STARTCOUNT  = 5;
const CYCLEVAL  = 500;

const scaleArr = new Array();
const dispArr  = new Array();
scaleArr.push(0);   dispArr.push("無(近)");
scaleArr.push(262); dispArr.push("ド");
scaleArr.push(294); dispArr.push("レ");
scaleArr.push(330); dispArr.push("ミ");
scaleArr.push(349); dispArr.push("ファ");
scaleArr.push(392); dispArr.push("ソ");
scaleArr.push(440); dispArr.push("ラ");
scaleArr.push(494); dispArr.push("シ");
scaleArr.push(523); dispArr.push("ド(高)");
scaleArr.push(0);   dispArr.push("無(遠)");

const OBNIZ_ID = 'xxxx-xxxx'; // お持ちのObniz ID を設定

const obniz = new Obniz(OBNIZ_ID);
obniz.onconnect = async function() {
    hcsr04  = obniz.wired("HC-SR04", {gnd:0, echo:1, trigger:2, vcc:3});
    speaker = obniz.wired("Speaker",{"signal":10, "gnd":11});
    obnizConnectFlg = 1;
}

AFRAME.registerComponent('canvas-texture', {
	init: function()
	{
		this.canvas = document.querySelector("#myCanvas");
		this.canvas.width  = 595;
		this.canvas.height = 842;
		this.context = this.canvas.getContext('2d');
		this.x = 200;
		this.y = 100;
		this.dx = 5;
		this.dy = 3;
		this.image = ["00.png","01.png","02.png","03.png","04.png","05.png","06.png","07.png","08.png","09.png"];
		this.imgSrc = "";
        this.dtsum = 0;
        this.distance = 0;
        this.updateFlg = 0;
    },
	update: function(){

		let material = this.el.getObject3D("mesh").material;
        const chara = new Image();
        console.log("glNo = " + glNo + ", this.image[ glNo ] = " + this.image[ glNo ]);
		chara.src = "images/" + this.image[ glNo ];
		chara.onload = () => {
			this.context.drawImage(chara, 0, 0);
			if (!material.map)
				return;
			else
				material.map.needsUpdate = true; 
		};
    },
	tick: function(t, dt)
	{
		this.dtsum += dt;
		if( this.dtsum >= CYCLEVAL ){
            this.dtsum = 0;
            if(obnizConnectFlg == 1){
                this.obniz();
            }
		}        
    },
    obniz: function(){
        hcsr04.measure(function(distance){
            console.log("distance = " + distance);
            updateFlg = 1;
            const tmpNo = Math.floor( distance / SCALELENGTH ) - STARTCOUNT;

            if(tmpNo < 0){
                glNo = 0;
            }else if(tmpNo >= 9){
                glNo = 9;
            }else if( !isNaN(tmpNo) ){
                glNo = tmpNo;
            }else{
                glNo = 9;
            }
            speaker.play( scaleArr[ glNo ] );
            updateFlg = 1;
        });
        if( updateFlg == 1){
            updateFlg = 0;
            this.update();
        }
    }
});
</script>

<a-scene embedded vr-mode-ui="enabled: false;" arjs="debugUIEnabled: false;">
    <a-assets>
        <canvas id="myCanvas"></canvas>
    </a-assets>
    <a-marker type="pattern" url="data/hiro.patt">
        <a-plane
                width="2" height="2.82"
                position="0 0 0"
                rotation="-90 0 0"
                material="src: #myCanvas; transparent: true; opacity: 0.95;"
                canvas-texture
        ></a-plane>

    </a-marker>
    <a-entity camera></a-entity>
</a-scene>
</body>
</html>
```

## イラストの準備

描いたマトリョーシカのイラストは全10種類。
9種類はこちら

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">テルミンを内蔵するマトリョーシカ、その名もマトリョミン。マトリョミン風の楽器をIoTで作ってみる。<br>ステップ(6) マトリョーシカのイラスト完成<a href="https://twitter.com/hashtag/Matryomin?src=hash&amp;ref_src=twsrc%5Etfw">#Matryomin</a> <a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://t.co/uRynpctFMp">pic.twitter.com/uRynpctFMp</a></p>&mdash; suo-takefumi (@zsipparu) <a href="https://twitter.com/zsipparu/status/1340545094592565249?ref_src=twsrc%5Etfw">December 20, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

10枚目がこれ。距離が近すぎたらこのイラストが表示されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/14623f72-248b-0013-e0be-3f83a04b8408.png" width="220" />


## さいごに

アドベントカレンダーに参加したくて、マトリョミン(風)の楽器を作りました。obnizとA-Frame,AR.jsの連携が思ったより難しかったですが、無事つくれてよかった。