2020年12月05日

IQ1は論文を読み上げてほしい

期待されてもなぁ...

一応研究者としてお金をもらっているので論文を書くものの、IQ1の人間が自分の書いた論文の校正などできるわけもなく、文の上を滑っていく視界を前に「疲れてるなあ」などとつぶやく。
誤字脱字くらいチェックしたい。
だが、もう眼精疲労もたまっている。
ああ、誰か読んでくれないものか...
特に可愛い声だとありがたいんだけどなぁ...VOICEROIDとかCeVIOとか...

なんてことが(一応)あったので、PDFの読み上げについて調べた。
英語の論文?Grammarlyでも利用してドウゾ。
ヘタに読み上げで確かめるより速いし確実。
(あと可愛い声の英文対応がない。是非作ってくださいお願いします何でもはしませんが即買わせていただきますから。
あとソフト名挙げてる辺りからお察しかと思うがWindows前提の話なのであしからず。

PDF読み上げならViewerが対応してないか?


調べると案外PDFの読み上げの状況は良くなかったりする。
VOICEROIDの方は全然外部のAPIとか考えていないが、CeVIOの方はSAPI5とかに対応していて、なんと今はナレーター(スクリーンリーダー)の読み上げも対応している。
頑張ってるなあ。
しかし、例えばADOBE READERなんかは初期から入っている音声合成は対応するものの、他はほぼ不可能。
読み始めの位置も調整できなさそうで勝手の悪さに頭を抱えた。コレハナイ。
Windows組込みの音声イマイチ可愛くない...

棒読みちゃん


棒読みちゃんというアプリケーションがある。
いろんなソフトの仲介役もこなす(SAPI以外にも追加でVOICEROIDを呼び出せるプラグインがある)なかなかすごいやつだ。
で、これにクリップボード監視というのがあるのだが、これを使えば読ませられないことはない。
まあ、コピー元に改行が入ってたりするとそこで途切れたり(多くのPDF Viewerで「見かけの行が変わると改行を入れる」ので頻発、とはいえこの挙動自体は妥当だと思う)、そもそも作業中だとコピーなんて頻出する操作だからそのたびに変なの読み始めたりするけど...
作業してたらこれらに我慢できなくなったのでパスで。

最近はブラウザもイケるよね


PDF Viewerといえば最近はブラウザ組込みで見られることが増えている(pdf.jsすごいなあ)。
ChromeもFirefoxもEdge(今はほぼChromeだがそうなる前から)もだ。
で、見てみたところEdgeには組込みで読み上げ機能がある!
しかもネット経由で滑らかに読んでくれる機能まである。おおすごい、確かに抑揚あって滑らか。
でも可愛くないな(我が儘)。
(無理矢理設定したらEdge上の読み上げをCeVIOにさせることができたが、どこ読み上げてるか見えないとかいろいろ不都合があるのであんまりよくなさそう。あと改行...やり方は「組込みのエンジンをSAPI5に無理矢理対応させる」の逆をした)

ちなみに、ブラウザ上の表示でなぜかFirefoxだけ「見た目の改行を無視する」ようになっているようで、最初は「Firefox+棒読みちゃんのクリップボード監視」でいいかと考えていた。
作業をなぞったらあっという間に不満爆発して諦めたのだが。

Web Speech APIとアドオン


ところで現在のブラウザだとWeb Speech APIというのがあり、こいつがなかなか侮れない。
Windows上での読み上げはどうやらSAPI5に対応するらしい。
というわけで、アドオンを作った。
https://github.com/chiguri/speechmaker_firefox
cloneしてFirefoxにmanifest.jsonをデバッグモードで読ませれば動く。
オプションで読ませるボイスを選択したあと、テキストを選んで右クリックでSpeech Synthesisで読み上げが始まる。
もちろんPDFを開いているタブでも動く。
speechmaker.png
↑実行例(PDF開いてる)。
ついでに棒読みちゃんのWebSocketプラグインに投げるオプションもつけたので棒読みちゃんも使える→VOICEROIDにも読んでもらえる。
(ある程度長い文章はWebSocketかプラグインの制約かで失敗するのだが)
や↑ったぜ。
え、アドオンの公開?気が向いたから一応申請はしたけど説明足りないと止められたからしばらくないよ。めんどいし。

終わりに


眼精疲労が出ているときは読み上げに集中できないため、読み上げてもらっても目が滑る代わりに声が右から左に通過するだけだった、というのがオチである。可愛い声のおかげでぐっすり眠れるが
所詮IQ1の浅知恵であった。
CeVIO AIだともっと滑らかに読み上げてもらえるんだろうか...楽しみだ

明日は...なんにもない日のようだ。良い日曜日を。
posted by chiguri at 00:00| Comment(0) | ネタ

2020年06月23日

LLVM frontend tutorial Kaleidoscopeのビルドを始めるまでにした苦労

見に来ている人がLLVMとは...なんて話題には多分興味無いと思うので飛ばすとして、かなり頑張っているプロジェクトであるLLVMにはチュートリアルが複数ある。
今回その中のフロントエンド用のチュートリアル Kaleidoscopeを研究室の輪講としてやることになった。
なおAgdaの本をやっていたのはもう終わった。早かった。

LLVMのチュートリアルのページを見るとOCaml版とC++版がある。
しかしLLVMのリポジトリを見たら分かるとおり、OCaml版は本当に長く放置されていて、APIは古すぎてちゃんと新しいのを探さないといけないし、camlp4だし、ところどころ引っかかるみたいだし、そもそもObjective Camlだし...(頑張った方もいらしたようだ)
一方C++は2018年に何かで使ったらしく、修正が入っている。これはありがたい。

ソースコードは全て公開されているので、輪講としては若干気になるものの、絶対に環境に依存するから、事前に動かせるのがありがたい。
と思ったけどそれでも苦労するんだなぁ...

ビルドで困った人の助けになればと書いておく。

Ubuntu編


こちらは二転三転するのだが、結論を言うとリンカーにオプションを渡さないといけない。

aptでLLVMを入れてソースコードを持ってくると簡単にコンパイルできる。さすがUbuntu。優秀。
さくっとMakefile書いて、テスト用に(というにはおこがましいが)チュートリアルに書かれている例題を持ってきて、実行。そしてコケる。

Symbols not found - [ printd ]

そりゃないよ〜

Chapter 4から、JITを使ってシンボル解決をして外部関数を呼び出すということをするのだが、よくある数学関数(sinやcos)は普通に呼べるのに、処理系のソースコード内で定義している関数(putchardとかprintdとかいう名前)が呼べない。
チュートリアルでは何事もなかったように呼べている。いやいや呼べないんだけど。シンボル見つからないって文句言われるんだけど。

最初の解決策


どうやら共有ライブラリの関数は呼べているようなので、呼びたい関数を共有ライブラリ(.so)にして実行時にロードしてもらえばどうか、と試したところうまくいった。
うまくいったけど実行が面倒なんですがこれ...(実行時にいちいち LD_LIBRARY_PATH=. ./toy みたいに書いている)

別の解決策


JITのバグを疑っていて考えなかったけれど、そもそもこの関数シンボルテーブルにあるの?と思い立ってobjdumpで見てみる。
...前にオプションで二つのシンボルテーブルがあることを知った。

  • -tで見られるシンボルテーブル。聞き覚え有り。

  • -Tで見られる動的シンボルテーブル。聞き覚え無し。


人に聞いたらELF(linuxでよく使うバイナリフォーマット)にはあるらしい。動的シンボルテーブルの内容は動的リンク時などに使うテーブルなのだとか。
で、どうやらLLVMのJITがこっちを見ているようだ。printdやらputchardはシンボルテーブルにはあったけど動的シンボルテーブルにはなかった。なるほど動的リンクとJITだから確かに結びつく。
どうせリンカーに何かオプションがあるに違いないと思って調べたところ、--export-dynamicというフラグを見つけたので、clang++越しに渡すことにした。
clang++ -Xlinker --export-dynamic -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core mcjit native` -O3 -o toy

みたいにコンパイルする。
最終的にこれで無事動いた。

Mac編


端的に言うとllvm-configが出す情報がなんか不完全らしく、--libsの先をallにしたら足りた。あとリンカーのバージョンを下げるオプション-mlinker-version=450もつけたら動いた。

これ学生が見つけた話だからここに詳細を書いても仕方ない気がする。
こっちのビルド時のコマンドはこんな感じ。
clang++ -mlinker-version=450 -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs all` -O3 -o toy

Ubuntuの時に使ったオプションは多分使えない。
あとlibsの指定でallを書くのはUbuntuでも有効。記述量減るので使った。頑張れclang。

なんとか無事輪講を開始できそうである。
posted by chiguri at 16:24| Comment(324) | 講義

2020年04月27日

Agdaのデータ型宣言により定義される要素の型

研究室の輪講がらみだが、Agdaのデータ型宣言とコンストラクタの暗黙的パラメータについてごちゃごちゃになったのでここにメモ。

以下のようなデータ型宣言があったとする。

data T {a : A} (b : B) : X -> Set where
C1 : {c1 : C1} (d1 : D1) : T b x1
C2 : {c2 : C2} (d2 : D2) : T b x2

x1(またはx2)はaやbやc1やd1(c2やd2)からXの項が作られているものとする。

このとき、生成される要素は以下の3つである。

T : {a : A} -> (b : B) -> X -> Set
C1 : {a : A} -> {b : B} -> {c1 : C1} -> (d1 : D1) -> T {a} b x1
C1 : {a : A} -> {b : B} -> {c2 : C2} -> (d2 : D2) -> T {a} b x2


簡単に説明。

  • Tは比較的そのまま。あえて言えばコロンが矢印になっているくらい。

  • C1とC2は引数に「Tのパラメータだったもの」が先頭の暗黙的パラメータとしてくっついている。ただしコロンより後ろに書かれていたXはない。


つまるところ、影響があるのはTの宣言でコロンの前に書かれたaやbである。

  • Tにとっては、コロンの前後にかかわらず「この型が取るパラメータ」であるため、基本的に宣言そのままの引数になる。

  • Tのコロンの前にあるパラメータaとbはこの型宣言全体で可視なパラメータである。各コンストラクタはaやbを使える。一方残りの型Xのパラメータについては(今回は無名であるのもあるがそうでなくても)型宣言全体では見えず、あくまでSetまで書かれた範囲でしか見えない。


このようにaやbは可視範囲が広いので、コンストラクタが独立して存在するにあたり相当する値をどこかから拝借しなければならない。結果としてaやbは暗黙的パラメータとして追加される。
もちろんよほどのことがない限りこのパラメータを明示的に渡すことはない(必要とされる型から自動で推論される)が、c1やc2を渡そうとする際に若干ややこしいことになるので注意。({c1 = ...}のような書き方をすると問題を回避しやすい)

なお、このパラメータは便利なのだが、コンストラクタ記述時に制約がつく。
定義時、全てのコンストラクタの型はTに(aや)bを適用した型で終わることが要求される。今回の例で言えば、必ず結果が T {a} b ... の形の型でなければならない。一方、型Xのパラメータについてはそのような制限はなく、コンストラクタ毎に異なってよい(x1とx2は異なってよい)。
あと、この制約は「結果の部分」にのみかかり、コンストラクタのパラメータにTが出現しても(aや)bを使う必要性は無い。

_≡_ の定義が複雑な考えと思うかもしれないが落ち着いて読めば読める。
xが型パラメータにあるのはコンストラクタで第一引数が固定されても特に影響ないため。
第二引数が第一引数と同じという制約はあくまでコンストラクタで行う。
posted by chiguri at 20:22| Comment(0) | Agda

2019年11月08日

IQ1 Advent Calendar 2019 七日目 -680時

IQ1 Advent Calendar 2019、七日目の記事です。
今(書いてる時間)は2019年12月7日 -680時です。
12月7日じゃない?IQ1なのでよくわかりません。

おしまい。

posted by chiguri at 16:01| Comment(0) | 雑多

2017年07月06日

AWStatsのインターフェースをいじろう(というのはお薦めできない)

結果として面倒だったので、「表示を変えた箇所を調べておけばバージョン変わってもなんとかなるかな?」くらいに考えている人は参考にならないとだけ言っておく。

AWStatsはログ解析ツールとしては結構有名どころらしく、普通にパッケージ管理ソフトで入るため、単に使いたいと言う場合にはあまり苦労することもなく導入できる。
また、使い方も調べればそれなりにでてくるため、さほど問題は起こらない。(少なくともここに来るような人にはすぐ見つけられるはず)
しかし、インターフェースは微妙なところもあり、変更したいと思ったりもする。

もっとも、やってみた感想は「やめた方がいい」なのだけど。

変更内容は、一年前の情報も同時に表示すること。
自分の所属が大学であるため、webサーバーの負荷などは大体月と曜日に依存している。
そのため、何か変化や異常があると、昨年と比較できれば割と簡単に見えるのである。
しかし、AWStatsのインターフェースはなぜかその年の情報しか出さないので、比較が難しい。
(また、その年しか出さないので、1-3月あたりでは表示される情報がなさすぎて使いづらい)

じゃあ並べるようにすればいいんじゃないかといじり始めたが、どうにもこうにも・・・
起こった問題(怒った問題)を挙げていこうと思う。

1)月ごとの情報を表示する箇所は割と簡単に見つけられて、HTMLMainMonthlyという関数になっている。
この中に前の年のデータを表示するルーチンを無理矢理書き込めばいいはずなのだが、全く部品化されていないので、今見ている年の処理をコピペするしかない。やれやれ。

2)よく見るとところどころにコメントアウトされたあからさまに不要とおぼしきコードが見える。バージョン管理してるだろうが。消せ。

3)無理矢理表示を追加してるうちに、月ごとの関数から移って日ごとの情報を表示する関数が目に入るが、インデントが少し壊れてる。直せ。(もっとも、自分が見たバージョンは現在のバージョンよりさらにひどかったので、少しずつ直しているのだろうか。全部直せよとは思うが。)

4)表示させるように変更したので、一年分の情報は読んでいるが全てのログを見ているわけではないということにすぐ気づく。サーバーによってはログがすごい量なのだから当たり前ではあるが、どこで読んでるのか分かりづらい。表示に使っているデータの変更箇所を追うと、どうやら3330行くらいからのRead_History_With_TmpUpdateという関数で読んでるらしい。呼び出し箇所を見ると月ごとに読むようにしている。ただし、選択した月とそれ以外で月以外にもう一つ引数が異なっている。意味はさっぱりわからず。中を見れば分かるかと関数の範囲を見ると3800行ある。読めるかこんなもの。

5)とりあえず選択していない月と同じように読ませればなんとかなるかとやってみたところ、前の年の表示に成功。一安心かと思ったら明らかに「時間毎の通信量」が増加している。何が起こってるのかと調べると昨年の同月分を単純に足している様子(1年後を表示させて気づいた)。変数から当たりを付けてRead_History云々を見ると「選択した月の情報なら計算対象にして、他の月だったら無視する」という状態になっている。月だけ??年のチェックは???

6)努力の甲斐あって表示に成功。ただ日本語表示になっているのにところどころ「日 月」の順になっていてもやもやする。かと思ったら一箇所だけ「〜年〜月〜」(日付はあるが「日」がない)になっていたりする。さらに気持ち悪い。何かと思って表示部を見たら順番がハードコーディングされている。一箇所だけ別ファイルからフォーマットを読んで出力している(ただし微妙に不足している)。だからその中途半端なのをやめろというのに。というか多言語対応やってるんならハードコーディングするなよ。

とまあこんな感じである。
全部手で直したので、当然のことながらバージョンアップしたらおじゃん。
全体的に思うのは、
1)全体のメンテナンスに気を遣っているか若干怪しい。
2)細かい引数指定があるのに、普通に出てくるはずの組み合わせを想定していない。
3)大域変数だらけで関数毎に想定している状態がさっぱりわからない。
4)関数がでかすぎる。
全体のテスト以外してないよねこれ、という感じである。
posted by chiguri at 01:30| Comment(0) | 雑多