脳汁portal

アメリカ在住(だった)新米エンジニアがその日学んだIT知識を書き綴るブログ

ラズベリーパイの音声をDAC(pcm5102a)でI2S出力する

普段音声出力はRaspberryPi3のオーディオジャック(アナログ出力)から行っていますが、DACを介すことでI2S出力(デジタル出力)に変更する方法です
f:id:portaltan:20171122154620j:plain

I2S

I2Cじゃありません. Inter IC SoundでI2Sです
4本(または3本)の信号線でステレオ音声をシリアル伝送する規格

名前 rasPiのpin No. 説明
BCK(BCLK) 12 ・bit clock
・serial clock(SCLK)とも呼ばれる
LRCK(LRCLK) 35 ・Left Right Clock
・ステレオにおいて、LチャネルとRチャネルを区別するための信号
DATA 40 ・PCM Data
・serial data
・デジタル化された音声データのビット列
MCK - ・Master Clock
・ラズパイのGPIOからは出力されていない
・ICによっては上記3信号と同期するように自動で調整してくれるものもあり、その場合は不要
  (今回使うPCM5102AもBCKから生成してくれるので不要)
・System Clock(SYSCLK)とも呼ばれる

Inter-IC Sound - Wikipedia

DAC

Degital Analog Converter
ラズパイからI2Sで出力したデジタル信号をスピーカーやヘッドフォンで使えるアナログ信号に変換するもの
今回はPCM5102AというDACチップを利用します
デジタル-アナログ変換回路 - Wikipedia

使ったもの

世の中には既に全て実装済みのDACボードがありますが、今回はチップを買って全てブレッドボード上に1から組み上げます

item 買ったところ 個数
IC&変換基板 http://akizukidenshi.com/catalog/g/gK-11836/ 1
ブレッドボード http://akizukidenshi.com/catalog/g/gP-00315/ 1
ブレッドボード用電源モジュール https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-4RAW 1
抵抗(47Ω) http://akizukidenshi.com/catalog/g/gR-25470/ 3
抵抗(470Ω) http://akizukidenshi.com/catalog/g/gR-25471/ 2
コンデンサ(2.2nF) http://akizukidenshi.com/catalog/g/gP-07686/ 2
コンデンサ(0.1μF) http://akizukidenshi.com/catalog/g/gP-10147/ 4
コンデンサ(2.2μF) http://akizukidenshi.com/catalog/g/gP-08152/ 2
コンデンサ(10μF) http://akizukidenshi.com/catalog/g/gP-04621/ 4

回路図

公式ページのデータシートに回路図例があるので、その通りに組み込みます
http://www.tij.co.jp/jp/lit/ds/symlink/pcm5102a.pdf
f:id:portaltan:20171122161633p:plain
注意する点としては

  • GNDに落とすところはグランドバウンス対策で47Ω抵抗をはさんでいる
  • SCK(MCK)は今回ラズパイからとれないので、GNDに落とすことでpcm5102AがBCKから生成してくれる
  • ブレッドボード電源モジュールは3.3Vで使用
  • 上記のデータシートの回路図はなぜかICチップ逆になっているので注意

f:id:portaltan:20171122162404p:plain

ケーブル接続

次にラズパイと上記DACセットを接続する
I2Sは普通に調べても表記されていないことが多く、以下のサイトがわかりやすいです
https://bluefish.orz.hm/sdoc/raspi_i2sout.html

ソフトウェア側設定

ハードのほうの組み込みが完了したら、次はラズベリーパイ側の設定を行っていきます
pcm5102Aのドライバはデフォルトでラズベリーパイにインストールされている(/boot/overlays/以下で確認できるか)ので、利用するための記述のみ行います
ドライバのマッピング

sudo vi /boot/config
### 以下の1行を末尾に追加
dtoverlay=hifiberry-dac

ドライバのロード
起動時にドライバをロードするように設定する

sudo vi /etc/modules
### 以下の1行を末尾に追加
snd_soc_hifiberry_dac

上記の設定が済んだら一度再起動する

確認
以下のようにドライバ変更が反映されていたらOK

$ lsmod | grep dac
    snd_soc_hifiberry_dac     2511  0
    snd_soc_core          125885  3 snd_soc_bcm2835_i2s,snd_soc_hifiberry_dac,snd_soc_pcm5102a
    snd_pcm                75698  4 snd_bcm2835,snd_soc_core,snd_soc_hifiberry_dac,snd_pcm_dmaengine

$ aplay -l
    **** List of PLAYBACK Hardware Devices ****
    card 0: sndrpihifiberry [snd_rpi_hifiberry_dac], device 0: HifiBerry DAC HiFi pcm5102a-hifi-0 []
      Subdevices: 1/1
      Subdevice #0: subdevice #0
    card 1: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA]
        .
        .
    card 1: ALSA [bcm2835 ALSA], device 1: bcm2835 ALSA [bcm2835 IEC958/HDMI]
        .
        .

DACがcard0のdevice0に割り当てられていることが確認できる

音声出力確認

wavファイルで確認
注意点として、この構成ではモノラルの音源は再生できず、再生しようとすると以下のようなエラーになってしまう

$ aplay -D hw:0,0 /usr/share/sounds/alsa/Noise.wav
    Playing WAVE '/usr/share/sounds/alsa/Noise.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Mono
    aplay: set_params:1239: Channels count non available

なので適当にフリーの音源サイトからwavファイルをダウンロードしてきてそれを再生する

$ aplay -D hw:0,0 /home/pi/fanfare.wav
    Playing WAVE '/home/pi/fanfare.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo

mp3で確認
mp3で確認する場合はmpg321等を利用する

$ mpg321 #{mp3file}

環境によってはエラーが出るが、sudoで実行するとうまくいくことがある

以上で完了。想像以上にてこずった。

ケーブルを整理してラズパイから給電に変更したもの

f:id:portaltan:20171229165755j:plain

openssl.cnfは編集せずにオレオレ証明書をSAN対応させてchrome58へinstallする

前回自己証明書の作成方法を書いたんですが、IEとかはその証明書を使えば警告なしでアクセスできるようになるんですがChromeの場合は以下のような警告が出てしまいます
f:id:portaltan:20171016173917p:plain

これはChromeが今年の春らへんにリリースしたv58から証明書の中の項目のCN(Common Name)の利用を非推奨化し、SAN(Subject Alternative Name)の方を利用しなさいという仕様になったためです

手順の途中でFQDNを入力するところがあったと思いますが、通常ではここで入力した値はCNという項目の値になります
しかしChromeではCNではなくSANの方へ入力したいので少し追加で操作が必要です

調べているとopenssl.cnfを編集する方法がよく出てきますが、サイトによって編集箇所や記述も違い、かつ編集量も多いので、色々調べていった結果以下のようにSANの情報だけ別ファイルにエクステンションとして切り出し、そのファイルをオプションで読み込ませてやることでopenssl.cnfは編集せずSAN対応版の証明書を作成することができました

# 秘密鍵とCSRは普通に作成(以前作成したものでよい)

## extension fileの作成
$ echo subjectAltName=DNS:${FQDN} > san.ext
 
# 自己証明書の作成
$ openssl x509 -days 3650 -req -signkey ${name}.key < ${name}.csr > ${name}.crt -extfile san.ext
  • ${FQDN}にはCNに入力していたFQDN(fizzbaz.foobar.comみたいな)を入力
  • ${name}は作成した秘密鍵CSR等の名前をそれぞれいれる

本当にSAN情報が付加されているかは以下のコマンドで確認できます

$ openssl x509 -text -noout -in ${name}.crt
Certificate:
     .
     .
    Signature Algorithm: sha256WithRSAEncryption
     .
     .
      X509v3 extensions:
         X509v3 Subject Alternative Name:
             DNS:fizzbaz.foobar.com
     .
     .

自己証明書の作成方法

自己証明書(オレオレ証明書)の作成方法
基本的には
1. 秘密鍵の作成
2. 秘密鍵を使って証明書署名要求の作成
3. 秘密鍵と証明書署名要求を使って証明書の作成
という流れになる

1. 秘密鍵の作成

$ openssl genrsa -aes128 2048 > test.key
  • genrsa: RSA鍵の作成(generate rsa)
  • aes128:
    • 秘密鍵の暗号化(128bitごとにブロックを分けてそれぞれ暗号化する)
    • これいれるとパスワードの入力を求められるので忘れないようにする
    • desは古い方式らしい
  • 2048: 秘密鍵のbit長の指定(この場合は2048bit)
  • key:
    • 公開鍵の拡張子はエンコード方式(.pem, .der)で書く方法と、種類(.key, .csr, .crt)で書く方法がある
    • 好みで決めていいが今回は後者で説明する
  • (pem/der):
    • エンコード方式を示す
    • opensslの場合特に指定しないでデフォルトの場合pem方式で、テキスト化されている
    • 他にはDER方式とかあり、こちらはバイナリ化されている

2. 証明書署名要求(CSR: Certificate Signing Request)の作成

$ openssl req -new -key test.key -out test.csr
	Enter pass phrase for test.pem: # 秘密鍵作成時に入力したパスワード入力
	.
	.
	.
	-----
	Country Name (2 letter code) [AU]:JP # 国名
	State or Province Name (full name) [Some-State]:Tokyo #都道府県名
	Locality Name (eg, city) []:Setagaya # 市区町村名
	Organization Name (eg, company) [Internet Widgits Pty Ltd]:HogeHoge, Inc. # 会社・団体名
	Organizational Unit Name (eg, section) []:Development Section1 # 部署名
	Common Name (e.g. server FQDN or YOUR name) []:foobar.nouziru.com # FQDN
	Email Address []: nouziru@mail.com # メールアドレス

	Please enter the following 'extra' attributes
	to be sent with your certificate request
	A challenge password []: # 入力不要
	An optional company name []: # 入力不要
確認
$ openssl req -text -noout -in test.csr
	Certificate Request:
    	Data:
       		Version: 0 (0x0)
       		Subject: C=JP, ST=Tokyo, L=Setagaya, O=HogeHoge, Inc., OU=Development Section1, CN=foobar.nouziru.com/emailAddress=nouziru@mail.com
        	Subject Public Key Info:
        	.
        	.
        	.

3. 自己証明書(CRT)の作成

$ openssl x509 -days 3650 -req -signkey test.key < test.csr > test.crt
	Signature ok
	subject=/C=JP/ST=Tokyo/L=Setagaya/O=HogeHoge, Inc./OU=Development Section1/CN=foobar.nouziru.ddns.net/emailAddress=nouziru@mail.com
	Getting Private key
確認
$ openssl x509 -text -noout -in test.crt

以上で自己証明書の作成は完了

$ ls -l
total 44
-rw-r--r-- 1 nouziru nouziru 1359 Oct 12 13:11 test.crt
-rw-r--r-- 1 nouziru nouziru 1082 Oct 12 12:58 test.csr
-rw-r--r-- 1 nouziru nouziru 1766 Oct 12 12:56 test.key

csrファイルは特に必要ないので削除してもかまわない

その他

derファイルへの変換
$ openssl x509 -in test.crt -outform DER -out test.der
SAN情報を付加する場合(Chrome58対策)

crtを作るときに以下のようにextファイルを作成してdomain情報をのせる

## create extension file
$ echo subjectAltName=DNS:${YOUR DOMAIN} > v3.ext
 
# generate crt
$ openssl x509 -days 3650 -req -signkey ${name}.key < ${name}.csr > ${name}.crt -extfile v3.ext

ThetaS vs. Gear360(2017)

比較機種

ThetaS(RICHO)

theta360.com
f:id:portaltan:20170620164043p:plain

スペック比較

ThetaS Gear360
静止画解像度(最大) 5376×2688 5472 x 2736
静止画撮影モード
  • オート撮影
  • シャッター優先
  • ISO優先
  • マニュアル撮影
  • オート撮影
オート撮影補助機能
  • ノイズ低減モード
  • DR補正
特になし
ISO感度 ISO100~1600
  • 100, 125, 160, 200, 250, 320, 400, 500, 640, 800, 1250, 1600の中から選択
ISO400~1600(?)
  • ISOの感度限界として400, 800, 1600を指定できる
  • 任意の値に設定することは出来ない模様
シャッタースピード 1/6400~60秒 設定不可
F値(絞り) F2.0(固定) F2.2(固定)
露出補正 -2.0~+2.0EV (1/3EVステップ) -3.0~+3.0EV (1/10EVステップ)
ホワイトバランス
  • オート
  • 屋外、日陰、曇天、白熱灯1、白熱灯2、昼光色蛍光灯、昼白色蛍光灯、白色蛍光灯、電球色、蛍光灯
  • マニュアル指定はなし
  • オート
  • 屋外、曇天、白熱灯、蛍光灯
  • マニュアル指定はなし
マルチブラケット
  • 13パターンまで設定可能
  • マニュアルで設定
なし
セルフタイマー 2秒, 5秒, 10秒 2秒, 5秒, 10秒
インターバル撮影 8秒~60分内で指定可能 なし
HDR合成 4枚で合成
  • 風景HDR合成
  • 3枚撮影で合成
静止画出力形式 equirectangular dual-fisheye
動画解像度(最大) 1920×1080 4096×2048
動画フレームレート 30fps 24fps
動画記録時間(最大) 25分 130分
モリー 8GB(内蔵) 256GB(別売りmicroSD)
ペアリング可能端末
動画出力形式 dual-fisheye dual-fisheye

スマホアプリ

ThetaS

RICOH THETA S

RICOH THETA S

  • Ricoh Co., Ltd.
  • 写真/ビデオ
  • 無料
play.google.com

静止画・動画編集アプリ

ThetaS

theta360.com

Gear360

Galaxy Gear 360 | Galaxy Mobile Japan 公式サイト

  • アプリの項目を見ても説明書に載ってるURLにアクセスしてもサイト内検索しても見つからなくて、探すのにかなり手こずった・・・

比較してみた

  • スティッチ精度
    • 両方スティッチの精度は高い
    • ただしGear360の場合はレンズの境目が少しぼやける
    • また、Gear360では二つのレンズ間で色味が異なる
  • HDR機能
    • ThetaSの方が優秀だった(室内撮影)
    • Gear360は風景HDRと指定があるので、外でとるとまた違う結果になるかもしれない
  • 撮影
    • 設定項目などでThetaSの圧勝
  • スマホアプリ
    • Gear360はGalaxy端末からじゃないとフルに機能を使えないのが辛い
  • 画質
    • Gear360は若干画像にノイズがのる
  • 動画
    • Gear360は動画の途中でレンズの境目に被写体(動体検知している?)が入ると、その被写体を優先的に貼りあわせようとするので他がゆがむ
      • これは好みだが無くてもいい気がする
      • ThetaSはスティッチ範囲は固定のよう
    • 動画はやはり2k(ThetaS)と4k(Gear360)では比べ物にならないほど差が出る
      • 2kはブラウザベースでも結構厳しい
  • VR
    • Gear360はGalaxy端末を利用した場合はすぐにGearVRから確認できるので楽

まとめ

  • 静止画をとるならThetaS
  • 動画をとるならGear360

とはいえGear360(2017)は出たばっかりで、ThetaSは発売してから結構時間がたって色々FBももらって洗練されていっているのは当然なので、今後のFW updateに期待したい

ReactVR 環境設定

react VR

facebook.github.io

Preparation
### download node.js
$ curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
$ sudo apt-get install -y nodejs

### download react vr
$ npm install -g react-vr-cli
  /usr/bin/react-vr -> /usr/lib/node_modules/react-vr-cli/index.js
  /usr/lib
  mqw react-vr-cli@0.3.1
    mqw chalk@1.1.3
      tqq ansi-styles@2.2.1
      tqq escape-string-regexp@1.0.5
      tqw has-ansi@2.0.0
      x mqq ansi-regex@2.1.1
      tqq strip-ansi@3.0.1
      mqq supports-color@2.0.0

### make initial project
$ cd WelcomeToVR
$ npm start

ここまできたらhttp://localhost:8081/vr/にアクセスするとこんな感じの画面が見れます
f:id:portaltan:20170615110341p:plain

WebVRのフレームワークで実写系360度コンテンツを表示する方法(Aframe / google vrview / react vr)

Aframe

aframe.io

how to use
<script src="https://aframe.io/releases/0.5.0/aframe.min.js"></script>
<a-scene>
  <a-sky src="path/to/img"></a-sky>
</a-scene>
オプション

初期表示の位置変更

<a-sky src="path/to/img" rotation="0 180 0"></a-sky>

google vrview

360° Media  |  Google VR  |  Google Developers

preparation
$ git clone https://github.com/googlevr/vrview.git
how to use
<script src="vrview/build/vrview.min.js"></script>
<div id="vrview"></div>
<script>
    var vrView;
    window.addEventListener('load', onVrViewLoad)
    function onVrViewLoad(){
        vrView = new VRView.Player('#vrview', {
            image: 'path/to/img',
            width: '100%',
            height: '100%',
        });
    }
</script>
オプション

f:id:portaltan:20170615103446p:plain

画像を重ねる方法(positionとかtopとか)

html5で画像を重ねて表示する方法
毎回力技でやっているので備忘録として
使用するpropertyは主にpositionとz-indexと位置に関するtop/left/bottom/right

基点の指定(position)

  • relative, absolute, static, fixedをとる
  • 指定しない場合のデフォルトはstatic

static

  • positionのデフォルト値
  • topとかleft等の位置情報やz-indexを指定しても反映されない
<div>
  <img src="freedom.jpg" />
</div>

f:id:portaltan:20170530123620p:plain

明示的にstaticを指定して位置情報を与えても変わらない

<div style="position: static; top: 150px; left: 100px;">
  <img src="freedom.jpg" />
</div>

f:id:portaltan:20170530123628p:plain

absolute

  • 親ボックスの端を基準にして、指定距離だけ移動した位置に表示
    • 親ボックスとはpositionプロパティにstatic以外が指定されている要素のこと
    • 何も指定されない場合はwindowの端が基準になる
<div style="position: absolute; top: 150px; left: 100px;">
  <img src="freedom.jpg" />
</div>

次にpositionをabsoluteに変更するとtopとleftプロパティが反映され、上端から150px、左端から100pxずれた位置に画像が表示される
f:id:portaltan:20170530123731p:plain

ここでずれた位置に画像を一つ追加してみる

<div>
  <img src="kira.png" />
</div>

<div style="position: absolute; top: 150px; left: 100px;">
  <img src="freedom.jpg" />
</div>

見事新しい画像が先ほどずらした150pxの空間に配置されました
f:id:portaltan:20170530124410p:plain

relative

  • 本来そのコンテンツが表示される位置を基準に指定した値だけ移動して表示する
<div style="position: relative; top: 100px; left: 100px;">
  <img src="freedom.jpg" />
</div>

単純に1つの画像を表示するだけではabsoluteとほぼ同じ
f:id:portaltan:20170530123731p:plain

次にabsoluteとの時と同じくずらした位置に画像を追加します

<div>
  <img src="kira.png" />
</div>

<div style="position: relative; top: 150px; left: 100px;">
  <img src="freedom.jpg" />
</div>

f:id:portaltan:20170530124532p:plain
すると今度は少し下の位置に表示されてしまいました
これはabsoluteの場合は親ボックス(今回はwindowの端)から指定した分だけ移動した位置に表示されていたのが、relativeの場合は実際に表示されるはずだった位置から指定した分だけ移動しているためです
f:id:portaltan:20170530125118p:plain

fixed

  • windowの端から指定した距離だけ移動
  • そしてスクロールしても移動せずに固定(fix)される

位置の指定(top / bottom/ left / right)

  • topは上記で指定した基準からどの程度下にずらすかを示す
  • bottom, left, rightは同様に下、左、右からどの程度ずらすかを示す
<div style="position: absolute; top: 50px;">
  <img src="freedom.jpg" />
</div>

f:id:portaltan:20170530130335p:plain

<div style="position: absolute; bottom: 50px;">
  <img src="freedom.jpg" />
</div>

f:id:portaltan:20170530130425p:plain

  • topとbottom, leftとright両方を指定したい場合、それぞれtopとleftが優先される
<div style="position: absolute; top: 50px; bottom: 50px; left: 50px; right: 50px;">
  <img src="freedom.jpg" />
</div>

f:id:portaltan:20170530130537p:plain

画像の重ね方

やっと本題の画像の重ね方ですが、上のpositionの位置の指定を使えば簡単にできます
今回はフリーダムの画像の上にキラの写真を重ねます

absoluteの場合

<div>
  <img src="freedom.jpg" />
</div>

<div style="position: absolute; top: 100px; left: 100px;">
  <img src="kira.png" />
</div>

f:id:portaltan:20170530131143p:plain
親ボックスの左上を基点にして下に100px、右に100px移動したところにキラの顔が表示されました

relativeの場合

上記のpositionを単純にrelativeにすると以下のようになります
f:id:portaltan:20170530131558p:plain
これは上で説明したように基点が実際に表示される場所(フリーダムの画像の下)になるためです
このケースでもし画像を重ねあわせたい場合は位置を指定する際に逆にマイナスを指定することで重ねることができます
f:id:portaltan:20170530154251p:plain

更に画像を重ねる場合

同じようにpositionと位置を指定していけば何重にも画像を重ねることができます

<div>
  <img src="freedom.jpg" />
</div>

<div style="position: absolute; top: 100px; left: 100px;">
  <img src="kira.png" />
</div>

<div style="position: absolute; top: 150px; left: 150px;">
  <img src="kira2.jpg" />
</div>

f:id:portaltan:20170530132656p:plain
f:id:portaltan:20170530134553p:plain

重なりの順番(z-index)

今回は順番的に上から『キラ⇒キラ⇒キラの乗ってたやつ』となりましたが、この順番もz-indexで変更することができます

  • z-indexの値の大きい要素が上に表示されます
  • デフォルトは親要素と同じ値か0です
  • positionがstaticの場合は反映されない

なので以下のように記述すれば一番下のフリーダムが1番上に表示されて、他の2枚はその下に隠れます

<div style="position: absolute; z-index: 20;">
  <img src="freedom.jpg" />
</div>

<div style="position: absolute; top: 100px; left: 100px;">
  <img src="kira.png" />
</div>

<div style="position: absolute; top: 150px; left: 150px;">
  <img src="kira2.jpg" />
</div>

f:id:portaltan:20170530133735p:plain

absoluteとrelativeの違い(親要素の高さ)

relativeとabsoluteの違いとしてもう1つあげられるのが、親要素の高さの扱いです。

  • relativeの場合はそのまま残る
  • absoluteの場合はなくなる

両方staticの場合、親要素に色をつけて見やすくしてみると

<div style="background-color: blue;">
  <img src="freedom.jpg" />
</div>
<div style="background-color: red;">
  <img src="justice.jpg" />
</div>

f:id:portaltan:20170530155700p:plain

ここから上の要素をrelative、下をabsoluteにすると

<div style="position: relative; background-color: blue;">
  <img src="freedom.jpg" />
</div>
<div style="position: absolute; background-color: red;">
  <img src="justice.jpg" />
</div>

f:id:portaltan:20170530155821p:plain

逆にすると上の要素の高さがなくなり、下のrelativeの要素が基点とする位置がずれて両方の画像が重なってしまいます
わかりやすくabsoluteの方を上になるようにz-indexで調整しています

<div style="position: absolute; background-color: blue; z-index: 2;">
  <img src="freedom.jpg" />
</div>
<div style="position: relative; background-color: red;">
  <img src="justice.jpg" />
</div>

f:id:portaltan:20170530160219p:plain