Mac OS Xのsayコマンドを使った簡易英語リスニング練習法

自分はいつまでたってもリスニングが苦手です。
特に数字の場合「fourty seven thousand six handred eighty nine」と発音されても
「47689」という数字がすぐには頭に思い浮かびません。

そこでMac OS Xのターミナルから使えるsayコマンドを使って数字の練習を出来るようにしました。

このようなスクリプトを組むと、1秒置きにランダムな数字(0〜32767)をMacが発音してくれます。

Practice for number in English

スピードやスピーカー(say -vで選べます)を調節することで色々な練習法が出来そうです。

BigDataダッシュボード勉強会

SIOSテクノロジーさんとTreasure Dataさん主催で、
ビッグデータをいかに可視化するか」をテーマにした勉強会が開催されたので行ってきました。

以下気になった点をメモとして残しておきます。 間違って解釈している箇所がありましたらご指摘下さい。

Treasure Dataと連携するダッシュボードツール

  • Treasure DataとMetric Insightsを組み合わせたダッシュボードの事例
  • Treasure DataさんはBIツールとしてExcelを使えるよう開発中とのこと
  • Q&A
    • 「Treasure Dataを導入している企業で最も良く組み合わせて使われるBIツールはあるか?」
    • 「最も使われている、というものはない。企業によって組み合わせて使われているBIツールは様々。インタラクティブな操作性ではTableauの右に出るものはないと感じているし、普及面の観点からだとExcelがやはり一番使われているBIツール。」

f:id:furuyamayuuki:20130822184735j:plain

f:id:furuyamayuuki:20130822185247j:plain

スモールデータ回帰分析ダッシュボード "adelie"

  • adelie
    • (重)回帰分析による多変量間の相関関係の計算を行い、可視化するツール
    • 分析するコンサルタントと現場の隔たりが大きい現状を踏まえて、現場の人間が分析できるようにと考えられ作られた
  • インラインで解析するが、気にいったモデル(メトリクス)があったら分析モデルとして保存して以後参照できる
  • 技術的な面
    • Python
      • numpy/scipy
    • Nginx
    • uWSGI
    • Pyramid
    • c3.js
      • D3.jsをラップした独自ライブラリ。対話的なチャートの制御・情報の取得が可能

f:id:furuyamayuuki:20130822191001j:plain

f:id:furuyamayuuki:20130822191040j:plain

Tableau Software

  • Tableau Desktopのデモ
    • 数百万件のデータをインポートしても、とてもスムーズに操作できていた
    • 操作方法を理解したら何でもできちゃいそうな印象
    • OpenGL使って描画しているため、データセットが大きくても描画はめちゃくちゃ速い

f:id:furuyamayuuki:20130822195505j:plain

OSSを活用したダッシュボードの紹介

  • Treasure Dataに蓄積しているデータを時間軸でグラフ表示するためのアプリケーションをrailsで開発
    • githubに公開しているという話だったけどURLがわからない...
  • Treasure Dataには、定期的に集計して結果をプッシュしてくれる機能があるらしく、TDのクレデンシャル情報をアプリ側で管理しなくて済んでいる
    • この定期的に集計してプッシュしてくれる機能はBigQueryにも欲しい・・・
  • GrowthForecastKibanaを使用してダッシュボード的なものを作る話もあったり

f:id:furuyamayuuki:20130822200454j:plain

Happy Hacking KeyboardをBluetooth化する(無改造版)

前回Happy Hacking Keyboard(HHKB)のコントローラから自作してBluetoothキーボードに改造しました。
今回はHHKBには一切手を入れずに、HHKBをBluetooth化してみたいと思います。

f:id:furuyamayuuki:20130817185550j:plain

※当方電子工作は初心者なため、以下の内容の正しさは保証出来ません。
また、改造に伴う機器の故障等も自己責任でお願いします。

必要なもの

ArduinoをUSBキーボードのホストにする

Bluetooth化の大まかな流れとしては、HHKBのUSBケーブルをArduinoに接続し、HHKBから送られてくる信号をArduinoBluetoothに変換してPCに送ります。 Arduinoが一旦PC代わりとなり、本来ならPCが受け取る信号をArduinoを通して送るイメージです。 USBデバイスを操作する側をホストと呼びますが、つまりArduinoがUSBキーボードのホストになればいいわけです。

ArduinoのUSBホスト化はUSBホストシールドとそれに対応したライブラリ USB Host Shield 2.0を使います。 このライブラリにはUSBのHIDデバイスに対応したクラスが用意されており(hidboot.(cpp|h))、その中のKeyboardReportParserクラスをサブクラス化して使います。

HHKB側からUSB経由でHIDレポートが送られてくるとKeyboardReportParser::Parseメソッドが呼び出されます。そのParseメソッドをオーバーライドすれば、送られてきたHIDレポートを自由に扱えます。 今回はそのHIDレポートをBluetoothモジュールに素通りさせればokです。
HIDレポートについては前回のものを参考にしてくだい。

class HIDKeyboardParser : public KeyboardReportParser
{
    virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
};

void HIDKeyboardParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
    // bufにはHHKBから送られてきたHIDレポートが入っているので、
    // そのレポートをそのままBluetoothモジュールに対してシリアルで送信
    sendKeyCodesBySerial(buf[0], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
}

void sendKeyCodesBySerial(uint8_t modifiers,
                          uint8_t keycode0,
                          uint8_t keycode1,
                          uint8_t keycode2,
                          uint8_t keycode3,
                          uint8_t keycode4,
                          uint8_t keycode5)
{
    Serial.write(0xFD); // Raw Report Mode
    Serial.write(0x09); // Length
    Serial.write(0x01); // Descriptor 0x01=Keyboard

    /* send key codes(8 bytes all) */
    Serial.write(modifiers); // modifier keys
    Serial.write(0x00, 1);   // reserved
    Serial.write(keycode0);  // keycode0
    Serial.write(keycode1);  // keycode1
    Serial.write(keycode2);  // keycode2
    Serial.write(keycode3);  // keycode3
    Serial.write(keycode4);  // keycode4
    Serial.write(keycode5);  // keycode5
    delay(5);
}

全体のスケッチはaddsict/USBKeyboard2BTにあります。 このスケッチをArduinoに転送し、ArduinoBluetoothモジュールをシリアルで接続するだけでBluetooth化の完了です。

f:id:furuyamayuuki:20130817185745j:plain

これでHHKBに限らずUSBキーボード(HID)ならどんなものでも一瞬でBluetoothキーボードにすることが出来ます。 あとはPICやAVRマイコンなどを使用して小型化すれば実用的になりそうです。

*1:秋月で売っているRN-42-EKも同じRN-42が載っているので代わりに使えるかもしれません。HIDプロファイルも設定により切り替えれるみたいですので。

Happy Hacking KeyboardをBluetooth化する

PFUHappy Hacking Keyboard Professional2(HHKB)を購入しました。
今までキーボードはMacbookのもので十分だと感じてましたが、一度触ってみるとキーボードにこだわる人の気持ちがわかる、とても素晴らしいキーボードです。
今回はせっかくならば無線化したいということでBluetooth化してみました。

※当方電子工作は初心者なため、以下の内容の正しさは全く保証出来ません。
また、改造に伴う機器の故障等も自己責任でお願いします。

使用するソフトウェアは全てGitHub上 https://github.com/addsict/YetAnotherHHKBController にあります。

必要なもの

ArduinoでHHKBのコントローラを作成する

HHKBのキータッチを自由にハンドリングするためにはキーボードのコントローラを自前で用意する必要があります。
マイコンの知識は余りないので、今回は手軽にプロトタイピングができるArduinoを使用することにしました。

キーボードのコントローラは、

  1. キーが物理的に押されているかどうかをチェックし
  2. 押されていればその信号をキーボードの接続先デバイス(パソコンなど)に送る

という役割を持ちます。
キーボードというと、キーが押されたら電気信号が流れ、それによってコントローラが動くイベント駆動的なものだと直感的には思いますが、実際はとても短い間隔(HHKBの場合15ms)で全てのキーを1つ1つ押されているかチェックする、ポーリング処理を行なっています。

コントローラの処理を擬似コードで書くとこのようになります。

while(1) {
    for (全てのキー) {
        check_key_pressed();
        if (押されていたら) {
            send_key_code_to_computer();
        }
    }
}

全てのキーをチェックするにはその分だけマイコンのGPIOピンの数が必要ですが、実際は「キーの数 >> マイコンのGPIOピンの数」なので、キーはマトリックス状(行×列)に配置しマルチプレクサを介してキーを選択します。
例えば64個のキー(行8 × 列8)がある場合、行と列を2進数で表せば合計6本のGPIOがあれば十分です。

while(1) {
    start = timer_start();

    for (行から1つ選択) {
        for (列から1つ選択) {
            check_key_pressed();
            if (押されていたら) {
                send_key_code_to_computer();
            }
        }
    }

    while(timer_end() - start <= 15);
}

15ms毎にキーのスキャンを行うタイマーコードも含めました。 完全なコードはこちらにあります。
コントローラ周りに関しては、自作キーボードの作り方を説明しているShiggy Enterprisesというサイトが参考になりました。

BluetoothとHIDキーボード

Bluetoothは使用したいサービスによって様々なプロファイルを使い分けますが、
Bluetoothキーボードでよく使われるプロファイルはHID(Human Interface Device Profile)とSPP(Serial Port Profile)のどちらかです。 HIDはホストマシンにあらかじめドライバなどを入れておく必要がないので、改造するにあたってはHIDプロファイルが手っ取り早そうです。

HIDキーボードではキーボードのキーの状態を、HIDレポートと呼ばれる8バイトのパケットでホストマシンに伝えます。 HIDレポートの構成は以下のようになっています。

|       0        |       1        |     2 ~ 7     |
|----------------|----------------|---------------|
| modifier keys  | reseverd(0x00) | keycode 1 ~ 6 |
|----------------|----------------|---------------|
  • 0バイト目: modifier keys
    • 修飾キー(ShiftやControlキーなどのこと)を1ビットずつ論理和(OR)を取ったものを入れます
  • 1バイト目: reserved
    • 常に0x00が入ります
  • 2 ~ 7バイト目: keycode1 ~ 6
    • 実際に押されているキー(修飾キーを除く)を入れます

たとえば「左Shift(0xE1) + 左Command(0xE3) + a(0x04) + b(0x05)」が押されている場合、

0x0A #0xE1を0x01, 0xE3を0x03にし論理和を取った値
0x00
0x04
0x05
0x00
0x00
0x00
0x00

をホストマシンに送ります。

USBキーボードの同時押しは最大6キーまでとなっているのが多いですが、それはこのHIDレポートの構造から来ているのでした。
HIDレポートでは単純に現在押されているキーを送ればよく、「どのキーが新規に押された」「押されていたこのキーが離された」などのキーの状態を把握する必要がないので、 コントローラ側の実装はシンプルになります。これらのキーの状態の管理はキーのバウンシングも含めてホストマシン側でやってくれます。 HIDキーボードで使うキーコードの仕様は http://www.usb.org/developers/devclass_docs/Hut1_11.pdf (P.53〜)を参照してください。

今回使用したBluetoothモジュール、RN-42HIDはArduinoとUART(シリアル)で通信が出来るようになっています。
Arduino側はHIDレポートを組み立て、それをシリアル通信でRN-42HIDに送信するだけで、Bluetoothのパケットのペイロードに入れて送ってくれます。 コントローラはBluetoothのことを一切気にする必要がなくシリアルで送りたい信号を送ればいいので、実際の通信路がUSBケーブルであろうとBluetoothであろうと透過的に扱うことが出来るので便利です。

回路を製作しHHKBと接続する

電気回路・電気工作については全くの初心者なので余り深くは触れません。詳しくは写真から判断して下さい。

f:id:furuyamayuuki:20130727161232j:plain

f:id:furuyamayuuki:20130727161412j:plain

気を付けなければいけない点としては、

  1. HHKBのVccは5V、RN-42HIDのVccは3.3Vなので5V, 3.3Vの両方が必要
  2. 電池1本1.5Vなので2本直列に繋げても3Vにしかならない。昇圧回路AS1322Aで5Vにする
  3. 5Vにした入力電圧は三端子レギュレータで3.3Vに落としRN-42HIDのVccとする
  4. RN-42HIDのUARTは3.3Vの電圧なので、ArduinoのTXからRN-42HIDのRXに入力される信号を3.3Vに降圧させる

UARTを3.3Vに降圧するために、5.1kΩと10kΩの抵抗で分圧回路を作りRXの入力電圧にしています。
コントローラとHHKBとの接続に関してはtmkさんのInternal of HHKB proを非常に参考にさせて頂きました。

ホストマシンに接続する

回路を組み立てたら電源スイッチをONにしホストマシンとペアリングを行います。 ペアリング後以下のように接続されていればBluetooth化完了です。

f:id:furuyamayuuki:20130727163327p:plain

HHKBは見た目もそうですが中身も非常にコンパクトになっていて、電池や回路を中に組み込むのに苦労しました。

f:id:furuyamayuuki:20130727160759j:plain

*1:秋月で売っているRN-42-EKも同じRN-42が載っているので代わりに使えるかもしれません。HIDプロファイルも設定により切り替えれるみたいですので。

require.jsとdata-main属性

require.jsを使っていて少しハマったのでメモ書き。

requre()関数をトップレベルのHTML(moduleを宣言していないHTML)に使用する場合、 data-main属性でconfigファイルを読み込もうとすると失敗します。

このような場合です。

<script src="require.js" data-main="require-config.js"></script>
<script>
require([
    'jquery',
], function ($) {
    console.log($);
});
</script>

// require-config.js
requirejs.config({
    paths: {
        jquery: 'jquery-1.8.2.min'
    },
});

これはrequire.jsファイルを読み込んだ後、data-main属性に指定されたファイルを読み込む前にrequire()関数が評価されてしまうためです。
configが読み込まれるまでrequire()関数は待ってくれるはずだと勝手に思い込んでいました。

回避策としては、ドキュメントにも書かれているようにrequire.jsを読み込む前にあらかじめconfigを設定しておけばokです。
事前に設定する場合は、requireという変数に設定項目をオブジェクトとして渡しておきます。

<script src="require-config.js"></script>
<script src="require.js"></script>
<script>
require([
    'jquery',
], function ($) {
    console.log($);
});
</script>

// require-config.js
var require = {
    paths: {
        jquery: 'jquery-1.8.2.min'
    },
};

Mac OS X wi-fi tips

Mac OSではネットワークの設定はLocationという単位で切り替えることができます。
terminalからは /usr/sbin/scselect コマンドで現在の設定を確認できます。

$ scselect

  xxxxxxxx-44F6-4EFE-BE5C-B5E0B91B7CDC (foo)
* xxxxxxxx-1D83-4E30-A533-77C2CE1E59EA (Automatic)
  xxxxxxxx-FAE4-4D87-9014-D1012E0807A5 (bar)

scselectコマンドの後にLocation名を書くとその設定に切り替わります。
自分は頻繁に切り替えるのでエイリアスを設定しておきました。

$ echo 'ailas foo-net="scselect foo"' >> ~/.bashrc

またwi-fiの調子が悪い時はAirMacのON-OFFを繰り返すとたまに改善することがあるので、
これもエイリアスに登録しておきます。
AirMacの操作は /usr/sbin/networksetup コマンドを使うと可能です。

$ echo 'alias wifi="networksetup -setairportpower en0"' >> ~/.bashrc
# en0はMacBookの場合です。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ wifi on  # AirMac起動
$ wifi off # AirMac停止

【iOS】バックグラウンドでBluetoothのコネクションを維持する

iOSデバイスでのBluetooth通信は基本アプリが画面内に表示されている'フォアグラウンド'の時のみ有効です。
今回はアプリがバックグラウンドに隠れた間でも、Bluetooth通信を可能にする裏技的な(?)tipsを紹介します。

バックグラウンドで実行可能な処理

まずiOSでバックグラウンド実行が可能なものを見てみましょう。
iOSでは、バックグラウンドで行える処理が以下のものに限られています。
Apple iOS App Programming Guide

  • 音楽の再生
  • 位置情報の取得
  • VoIP
  • Newsstandを使用するアプリ
  • 外部アクセサリから定期的に情報をアップデートするアプリ

このような、バックグラウンドでの動作が重要なサービスに限り許されています。

iOS Bluetoothフレームワークの種類

iOSが提供するBluetoothフレームワークには大きく分けて2種類あります。

名称 使用可能なデバイス バックグラウンド通信
Game Kit Bluetoothが使用可能なiPhone全て ×
Core Bluetooth iPhone4S以降

CoreBluetoothはBluetooth LE(Low Energy)に対応した外部機器との通信のみに使われます。
今回のターゲットはGame Kitフレームワークでのバックグラウンド通信です。

Bluetoothのコネクションを維持する方法

ではバックグラウンド通信を可能にするにはどうしたらいいのでしょうか。
実は、音楽をバックグラウンドで再生している間は、Bluetoothの通信が可能となっています。

以下、無音の音楽を永遠と再生し続けるサンプルコードです。

    // オーディオデータフォーマットを表す構造体を作成
    AudioStreamBasicDescription dummyASBD;
    dummyASBD.mSampleRate = 44100.0;
    dummyASBD.mFormatID = kAudioFormatLinearPCM;
    dummyASBD.mFormatFlags = kAudioFormatFlagsCanonical;
    dummyASBD.mBytesPerPacket = 4;
    dummyASBD.mFramesPerPacket = 1;
    dummyASBD.mBytesPerFrame = 4;
    dummyASBD.mChannelsPerFrame = 2;
    dummyASBD.mBitsPerChannel = 16;
    dummyASBD.mReserved = 0;
    
    OSStatus status;
    // AudioQueueの作成
    status = AudioQueueNewOutput(&dummyASBD,
                                 dummyAudioQueueCallBack,
                                 self,
                                 NULL,
                                 NULL,
                                 0,
                                 &dummyAudioQueue);
    if (status) {
        NSLog("error @AudioQueueNewOutput");
    }
    
    // 再生
    status = AudioQueueStart(dummyAudioQueue, NULL);
    if (status) {
        NSLog(@"error @AudioQueueStart");
    }

実際にバックグラウンドで試すときは、アプリのinfo.plistのバックグラウンドモードの項目にAudio Playが設定されていることを確かめてください。

<key>UIBackgroundModes</key> 
<array>
    <string>audio</string>
</array>

この状態であれば、GKSessionクラスのsendDataToAllPeers:withDataMode:error:メソッドや、receiveData:fromPeer:inSession:context:メソッドでデータの送受信が可能となっています。

最後に

もしかすると、音楽の再生以外にもバックグラウンド処理が許されているもの(例えばVoIPなど)でも同じことが可能かもしれません。
尚、この方法はAppleのガイドラインには書かれていないため、明らかに不推奨な方法だと思われます。 バックグラウンドで通信することに意義があるサービスのみに適応するよう心がけてください。