2014/12/20(土)Web Speech API と Twitter n-gram を利用した英語発音矯正ゲーム

4月からは自分が研究室で唯一の日本人になってしまうので、英語の発音のトレーニングをひたすら楽しく積めるWebアプリケーションを研究の合間に作っていました。

「えいごのはつおんとれーにんぐ」 https://pron.chobitool.com/

開発は6日間ぐらいで、そのうち素材集めに3日ほど費やしました。

Web Speech API に音声認識と音声合成のインターフェースがあるので、これらをフル活用しました。出題される問題は Twitter n-gram の高頻度の表現から抽出しています。

いい練習になるので、マイクとChromeがあればどうぞ。

オペレーターズサイドという音声認識ゲームに触発されて「なんだとはなんだゲーム」も作りました。

学生寄宿舎の壁が薄すぎて小さい声でしか練習できないのが辛いところです。

2014/09/20(土)KindleGenで縦書き

以下のCSSを用いてKindleGenでmobiファイルを生成したら縦書きになりました。ハマった点は、HTML5のノリでCSSの「type="text/css"」を省略するとCSSがまったく適用されなくなる点。別のリーディングシステム(Readiumなど)では正常に縦書きで表示されるため、問題の特定に2時間以上かかりました。

自作ライブラリである程度のCSSを自動生成している関係でp要素のCSSは上書きしている形になっています。

@charset "UTF-8";

body
{
    -webkit-writing-mode: vertical-rl;
    -epub-writing-mode:   vertical-rl;
    writing-mode:         vertical-rl;

    -webkit-text-orientation: vertical-right;
    -epub-text-orientation:   vertical-right;
    text-orientation:         vertical-right;

    line-height: 1.8;
    letter-spacing: 0.1em;

    -webkit-word-break: break-all;
    -epub-word-break: break-all;
    word-break: break-all;

    -webkit-line-break: strict;
    -epub-line-break: strict;
    line-break: strict;
}

.tcy
{
    letter-spacing: 0;

    -webkit-text-combine: horizontal;
    -epub-text-combine: horizontal;
    text-combine: horizontal;

    -webkit-text-combine-horizontal: all;
    text-combine-horizontal: all;
}

p
{
    margin: 0;
    padding: 0;
    text-indent: 1em;
}

.dialog
{
    text-indent: 0em;
}

h2
{
    margin-left: 3em;
    margin-right: 2em;
    text-indent: 3em;
    font-size: large;
    font-weight: normal;
}

p
{
    margin: 0;
    padding: 0;
    text-indent: 1em;
}

.dialog
{
    text-indent: 0.5em;
}

Kindle PWでの表示 Nexus7での表示 iPhone5Sでの表示

スクリーンショットはKindle Paperwhite 2013、Nexus7 2013、iPhone5Sの順番ですが、見事に表示がバラバラ。最後の「!」2つはU+203Cの感嘆符です。Kindleでは普通の「!」を縦中横させるほうがいい感じですな。

Kindle PWとNexus7ならある程度は表示を揃えられそうなので、この2つを優先しますかね。

2014/05/01(木)1文字フォントの作り方(無料)

💩 (うんこ)を表示できるフォント(うんこフォント)を作ったので作り方を軽くまとめておきます。

用意するハードウェア

  • スキャナー(デジタルでフォントを描く場合はなくてもOK)

最初に用意するソフトウェア

  • Gimp
  • Inkscape

フォント(SVGファイル)作成手順↓

  1. 紙に文字を書く
  2. スキャナーで読み込む(300dpiぐらい)
  3. Gimpで2値化(白と黒に分けること)
  4. 気に入らないところがあればGimpで編集
  5. bmpファイルで保存
  6. Inkscapeを起動
  7. 「ファイル」→「ドキュメントの設定」→「カスタムサイズ」で正方形にする(1000px x 1000pxぐらい)
  8. bmpファイルをドラッグ・アンド・ドロップしてInkscapeで読み込み(埋め込み)
  9. 「パス」→「ビットマップをトレース」→「OK」ボタンを押す
  10. 「テキスト」→「SVG フォントエディタ」→「新規」ボタンを押す
  11. 「フォント 1」をクリックして「ファミリ名」を適当なフォント名(うんこフォントなら「Unko」とか)にする
  12. 「グリフ」タブをクリック→「グリフを追加」ボタンを押す
  13. 「グリフ 1」の「マッチング文字列」に作りたいフォントの文字を入力
  14. 「選択オブジェクトから曲線を取得」ボタンを押す
  15. 「プレビューテキスト」に作りたいフォントの文字を入力して描いたフォントが反映されているか確認
  16. 「ファイル」→「名前を付けて保存」でファイルの種類はInkscape SVGのままで保存

Inkscapeの操作は自作フォントの作り方|windowsで無料で作成!How to make Font in Inkscape.It's completely free.が詳しいです。

SVGファイルから eot, ttf, woff ファイル作成手順(難易度高め)

  1. Linuxで「sudo apt-get install npm」する(パッケージ管理システムによって少し変わる)
  2. さらに「npm install -g svg2ttf」する
  3. 「svg2ttf from.svg to.ttf」でttfファイルを作成(もちろん適切なファイル名で)
  4. WOFFコンバータでttfファイルからwoffファイルとeotファイルを作成!(終了)

紙にかいた文字は↓ですが、線はもっと太くしたほうがいいです。 うんこ

↑のように線が細いと、小さく表示したときに文字が見えなくなるのでGimpでかなり太くしないといけなくなります。 unko

ファイルサイズは woff, eot, ttf で2,000から3,000 バイトぐらいになりました。

2014/03/08(土)PerlでServer-Sent Events

サーバからPUSHされたイベントを受け取るやつ。(http://www.w3.org/TR/eventsource/

Server-sent Event

最初リアルタイムで反映されなくて試行錯誤していたのですが、nginxの設定を変えたらリアルタイムで反映されるようになりました。(http://stackoverflow.com/questions/13672743/eventsource-server-sent-events-through-nginx

コードは下の通りで「plackup」とかで立ち上げられます。

#!/usr/bin/env perl

use strict;
use warnings;
use AnyEvent;
use Time::Piece;
use HTTP::ServerEvent;

my $AFTER    = 1;
my $INTERVAL = 1;
my $DURATION = 60 * 30; # 秒

my $html = do { local $/; <DATA> };

my $app = sub {
    my $env = shift;

    if ($env->{PATH_INFO} ne '/sse/events')
    {
        return [ 200, ['Content-Type', 'text/html'], [$html] ];
    }

    if ( ! $env->{"psgi.streaming"} )
    {
        my $err= "Server does not support streaming responses";
        return [ 500, ['Content-Type', 'text/plain'], [$err] ];
    }

    return sub {
        my $responder = shift;
        my $writer    = $responder->([ 200, [ 'Content-Type' => 'text/event-stream; charset=UTF-8' ] ]);

        my $cnt = 0;

        my $t; $t = AnyEvent->timer(
            after    => $AFTER,
            interval => $INTERVAL,
            cb       => sub {
                my $now = localtime->strftime('%Y-%m-%d %H:%M:%S');

                my $event = HTTP::ServerEvent->as_string(
                    id   => ++$cnt,
                    data => $now,
                );

                $writer->write($event);

                undef $t if $cnt > $DURATION;
            }
        );
    };
};

__DATA__
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Server-Sent Events</title>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
</head>

<body>
  <h1>Server-Sent Events</h1>
  <div id="msg"></div>
  <script>
    var eventSource = new EventSource('/sse/events');
    var msg = $("#msg");

    eventSource.onmessage = function(e)
    {
        console.log("message");
        console.log(e.data);

        msg.prepend("<p>" + e.data + "</p>");
    };

    eventSource.onopen = function(e)
    {
        console.log("open");
    };

    eventSource.onerror = function(e)
    {
        console.log("error");
    };
  </script>
</body>

2014/02/08(土)WebページへのDirectional Formatting Charactersの埋め込み

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>てすと</title>
</head>
<body>
<p>‮あいうえお</p>
</body>

で、ブラウザ上でも「おえういあ」になったので、Webアプリとかでは「Directional Formatting Characters」の入力を削除しておくべきっすね。(アラビア語やヘブライ語かけないと困るような場合は例外として)

実際はp要素のところはこう書いています。

<p>(U+202Eの文字を符号化したもの)あいうえお</p>