リモートに置いてある音楽ファイルをローカルPCのスピーカーで鳴らす

以前に「インターネットラジオを FM ラジオで聴く」というのを書きました。少し離れた場所にあるマシンにFMトランスミッターを付け、目の前のPCから操作する(そしてFMラジオで聴く)というものでした。

それから月日は流れ、ハードウェアを入れ換えたり、その際にOSもすっかりインストールし直したりしているうちに、そのリモートのマシンでの音声出力ができない状態になってしまいました。

そこで前回とは逆に「リモートに置いてある音楽ファイルをローカルPCのスピーカーで鳴らす」というのが、今回やりたいことです。目新しいことは何もなく、既に情報がどこかにあったので楽でした。自分のためのメモも兼ねてここに書いておきます。

先にまとめておくと、

  • リモート
    • 音楽ファイルが置いてある
    • Pulseaudio
    • MPD
  • ローカル
    • スピーカーが接続されている
    • Pulseaudio
    • gmpc

という構成になります。

Pulseaudio

ここではリモートもローカルも OS は Debian (これを書いている時点での安定版)です。

まず、ローカルで

sudo apt-get install pulseaudio
と pulseaudio をインストールし、

paplay local-sample.ogg

などとやってちゃんと動いていることを確認します。ところがここで音が出ませんでした。

sudo apt-get install pavucontrol

とやって pavucontrol で、「出力装置」を見ると、ポートが「HDMI」になっていました。ここの環境ではそこにスピーカーはなく、USBポートにサウンドアダプタを挿してその先にスピーカーがある状態です。「設定」で、GF108 High Difinition Audio Controller が HDMI になっているので、これを Off にすると、「出力装置」のポートが「スピーカー」または「デジタル出力(S/PDIF)」になって、音が出るようになりました。

リモートとローカルの Pulseaudio の設定

ローカルの /etc/pulse/default.pa で、

load-module module-native-protocol-tcp auth-ip-acl=192.168.1.0/24

リモートの /etc/pulse/client.conf で、

default-server = 192.168.1.xxx (スピーカーのあるPC)

とします。必要に応じてローカルのポート 4713 を開けます(今回のローカルPCはファイアーウォールを置いていないので特に設定の必要なし)。

テストとして、リモートで

paplay remote-sample.ogg

などとやるとローカルのスピーカーが鳴ります。

MPD

当初の目的は達成されましたが、このままでは不便なので、MPD を使うことにします。これは音楽再生やプレイリスト管理をリモートから行うためのものです。

リモート

まず

sudo apt-get install mpd

でインストールします。/etc/mpd.conf で、music_directory に音楽ファイルの置いてあるディレクトリを設定し、bind_to_address に接続を許すアドレス(今回は(LAN内の)どこからでも接続できるよう “any” としました)を設定します。

出力先の設定は

audio_output {
        type            "pulse"
        name            "My Pulse Output"
#       server          "remote_server"         # optional
#       sink            "remote_server_sink"    # optional
}

とします。ここで mpd を再起動します。

ローカル

ローカルPCには、gmpc をインストールして使います。これは高機能で、細かな設定やプレイリストの管理を行うことができます。ふだんは、再生/ポーズ/停止くらいの操作しか必要ではないので、シンプルな xfce4-mpc-plugin をパネルに置いてこれを使うことにします。

sudo apt-get install gmpc xfce4-mpc-plugin

どちらも、ホストとして MPD を動かしているリモートのマシンを指すように設定します。

MediaWiki のスパム対策

ほとんど放置気味の Wiki に、適当なアカウントが登録されては長文(ドイツ語)のページが作られる、というのがここ数日続いていました。見にくる人はほとんどいないし、その作られたページはさらにどこからもリンクされていないし、まったく誰にも何の得もない所業だと思うのですが、放っておくわけにもいかず、ちまちまと削除していました。

この Wiki は MediaWiki で運用しています。最近の MediaWiki には最初から ConfirmEdit という拡張機能が同梱されています。この機能の SimpleCaptcha というものを以前から有効化していました。これは、アカウント作成時や新規ページ作成時に、簡単な数式(足し算や引き算)の答を入力させるというものでした。にも関わらず変なアカウントやページを作られていたわけですから、スパムボット(いやまさか人力ではあるまい)はこれに対応したものだったようです。

数日続いたのでだんだん嫌になり、同じ ConfirmEdit の QuestyCaptcha を使うように、設定を変更しました。

LocalSettings.php の記述は

require_once( "$IP/extensions/ConfirmEdit/ConfirmEdit.php" );
require_once( "$IP/extensions/ConfirmEdit/QuestyCaptcha.php");
$wgCaptchaClass = 'QuestyCaptcha';
$wordarr = array (
        "日本語で質問に答えてください。質問1" => "答え1",
        "日本語で質問に答えてください。質問2" => "答え2",
        "日本語で質問に答えてください。質問3" => "答え3",
        "日本語で質問に答えてください。質問4" => "答え4",
        "日本語で質問に答えてください。質問5" => "答え5",
);
foreach ( $wordarr as $key => $value ) {
        $wgCaptchaQuestions[] = array( 'question' => $key, 'answer' => $value );
}

$wgCaptchaTriggers['edit']          = true; 
$wgCaptchaTriggers['create']        = true; 
$wgCaptchaTriggers['addurl']        = true; 
$wgCaptchaTriggers['createaccount'] = true;
$wgCaptchaTriggers['badlogin']      = true;

のようにします。質問はランダムに表示されます。質問と答を日本語とすることにより、日本語話者かどうかの判定も兼ねるようにしました。

しかしこの設定は、管理者の負担を善意のユーザーに転嫁するものでもあります。そのようなユーザーには CAPTCHA を求めないように、

$wgCaptchaWhitelistIP = array('192.168.0.0/24'); // 安全な接続元を IP アドレスで指定
$ceAllowConfirmedEmail = true; // メールアドレスを確認済みのユーザーは安全とみなす

も設定しておくことにします。

これでしばらく様子を見ることにします。

PDF の校正作業

出版前の本のレビューの依頼を受けるという機会に恵まれました。

著者からは PDF で原稿を受け取りました。作業の参考にしたのはテクニカルコミュニケーター協会が公開している「PDF 電子校正ガイドライン 第3版」 (PDF) です。端的に言うと、Adobe Acrobat Pro または Adobe Reader の「注釈」機能を使って、テキストの修正やコメントを付けていきます。

ところが、こちらの環境は Linux です。Linux には Adobe Acrobat Pro は存在しません。Adobe Reader も Mac/Win ではバージョンが XI (11) なのに、Linux 版は 9 のままであり、それ以降のバージョンは計画もない状況です。Linux 版の Adobe Reader 9 の注釈機能は、既に付けてある注釈を見ることはできても、あらたに注釈を付ける機能はなく、まったく話になりません。

Okular というソフトが注釈を扱えるようですが、その注釈は Okular でしか読めないらしいのです。なぜ Linux での環境がこれほど貧弱なことになってしまっているのか、愕然としました。

結局、このためだけに Windows XP を起動し、そこで Adobe Reader XI を使って作業したのでした。残念無念。

こうして作業して、注釈だけを別に保存します。はじめに受け取った原稿の PDF が 数十MB だったのに対して注釈はたったの 100KB ほどで、メールに添付してもたいしたことはありません。元の原稿は著者の手元には当然あるので、送る必要はありません。著者のほうでは送られてきた注釈ファイルを Acrobat 上で元の原稿に取り込んで確認できるというわけです。

受け取ったのは組版されて割付が終わっている段階です。著者校正の段階に相当し、それを第三者の目で内容的に誤りがないかを確認するということを求められているのかなと判断しました。プロの校正者ではないので、その人たちのようなチェックはできないはずなのですが、自分の性格からかつい細かな用字や読点に目がいってしまって、どっちつかずの「レビュー」になってしまいました。

そんなこんなが、いくらかでも役に立っていればうれしいのですが。

Mew のサマリに表示される本文の部分が変わった

Web のフォームによって送られる次のような書式のメールをしょっちゅう受け取ります。冒頭から

[氏名] ...
[よみかな] ...
[郵便番号] ...
[住所] ...
     ... 

のように、 [ ] ではじまる行があります(「氏名」や「住所」というのはあくまで例です)。

メールリーダーには Mew を使っているのですが、そのサマリ表示に上記の部分がばっさりカットされて、どうでもいいところからの本文の一部が現れるようになりました。

さて検索してみると、“[” ではじまる行を引用部分とみなし無視する、という変更が行われたようです。自分の手元でこのような変化がつい最近起こったのは Debian のパッケージの更新の時期によるものでしょう。

この部分(mew-scan.el の mew-regex-ignore-scan-body-list 定義部分)を元に戻しながら、~/.mew.el に setq

(setq mew-regex-ignore-scan-body-list
  '("^[ \t]*$"
    "^[ \t]*[-a-zA-Z0-9]+: "
;;    "^[ \t]*[[>:|#;/_}]" ;; https://github.com/kazu-yamamoto/Mew/commit/98d4fd7be3216792824e2c737006921b3b49b4b0 で加えられた変更
    "^[ \t]*[>:|#;/_}]" ;; を戻す。すなわち、"[" で始まる行を引用とはみなさない
    "^[ \t]*\\w+\\(['._-]+\\w+\\)*>"
    "^[ \t]*[[</(.-]+ *\\(snip\\|\\.\\.\\)"
    "^   "
    "^--"
    "^- --"
    "^=2D"
    "^.\\{1,100\\}\\(:\\|;\\|/\\)[ \t]*$"
    "^.\\{1,100\\}\\(wrote\\|writes?\\|said\\|says?\\)[^.!\n]?[ \t]*$"
    "^[ \t]*\\(On\\|At\\) .*[^.! \t\n][ \t]*$"
    "^[ \t]*In \\(message\\|article\\|mail\\|news\\|<\\|\"\\|\\[\\|(\\)"))

と書くことで、以前の状態にすることができました。

pandoc の使い方メモ — 相互参照について

やりたいことは「元の文章を markdown で複数のファイルに分割して書き、それをウェブで公開するために個々に HTML に変換したい。もう一方では印刷できるような一括した PDF を LaTeX 経由で作りたい。ついでに EPUB も作りたい」です。割とありがちなケースだと思うので、もっとすっきりした方法があるように思うのですが、うまく見つけられませんでした。

相互参照とは、HTML では id 属性と a タグで実現されるもの、LaTeX では \label{}\ref{} で表現されるものです。

索引は、LaTeX では後で処理するために \index{} で印を付けておくものです。HTML と EPUB では使いません。

例を挙げます。

a.md

はじめに {#hajimeni}
========

...

用意するもの
============

...

道具 {#dougu}
----

* 包丁
* まな板
* ...

これらは[「下ごしらえ」](b.html#shita)で使います。

* 大きな鍋\index{おおきななべ@大きな鍋}
* ...

これらは[「調理」](b.html#chouri)で使います。

材料 {#zairyo}
----

...

b.md

手順
====

下ごしらえ {#shita}
----------

ここで使う材料は[「材料」](a.html#zairyo)にまとめてあります。
...

調理 {#chouri}
----

...
大きな鍋\index{おおきななべ@大きな鍋}([「道具」](a.html#dougu)を参照のこと)を使います。
...

盛り付け {#moritsuke}
--------

おわりに
========

...


という文書が元になります。

HTML

a.md → a.html, b.md → b.html のように個々のページを独立して生成することにします。それを見越して、md ではリンクの書式のところにこれらのファイル名を入れておきます。

md を pandoc

pandoc -o a.html a.md
pandoc -o b.html b.md

と処理すると

a.html
<h1 id="hajimeni">はじめに</h1>
<p>...</p>
<h1 id="用意するもの">用意するもの</h1>
<p>...</p>
<h2 id="dougu">道具</h2>
<ul>
<li>包丁</li>
<li>まな板</li>
<li>...</li>
</ul>
<p>これらは<a href="b.html#shita">「下ごしらえ」</a>で使います。</p>
<ul>
<li>大きな鍋</li>
<li>...</li>
</ul>
<p>これらは<a href="b.html#chouri">「調理」</a>で使います。</p>
<h2 id="zairyo">材料</h2>
<p>...</p>
b.html
<h1 id="手順">手順</h1>
<h2 id="shita">下ごしらえ</h2>
<p>ここで使う材料は<a href="a.html#zairyo">「材料」</a>にまとめてあります。 ...</p>
<h2 id="chouri">調理</h2>
<p>... 大きな鍋(<a href="a.html#dougu">「道具」</a>を参照のこと)を使います。 ...</p>
<h2 id="moritsuke">盛り付け</h2>
<h1 id="おわりに">おわりに</h1>
<p>...</p>

ができます。LaTeX の索引のために挿入しておいた \index{} は無視されるので、特に気にすることはありません。

LaTeX 経由 PDF

ソースは複数ファイルに分割されていても最終的な成果物はひとつであってほしいため、main.tex を用意しておき、

main.tex
\documentclass[a5paper]{jarticle}
\usepackage[dvipdfmx]{hyperref}
\usepackage{makeidx}
\makeindex
\begin{document}
\tableofcontents
%
\input{a}
\input{b}
%
\printindex
\end{document}

これから dvi を作り、さらにそれから pdf を作ることにします(pandoc から PDF を出力させることもできるようですが、日本語のとおる環境を設定したり次に述べる処理を挟んだりするのがやりにくいので、こういうやり方にします)。

さて、ここで読み込まれる a.tex, b.tex を md から pandoc で生成するのですが、単純にやるだけでは、HTML 向けに書いていたリンクのところが

これらは\href{b.html\#shita}{「下ごしらえ」}で使います。

のようになってしまいます。これではよろしくないので、

sed 's/\(\[[^\]*\]\)[\(][^#]*\(#[^\)]*\)[\)]/\1(\2)/g' a.md \
| pandoc -t latex \
| sed 's/\(\\hyperref\[\([^\]*\)\]\)[\{][^\}]*[\}]/\1\{\\ref\{\2\}\}/g' \
> a.tex

のようにします。バックスラッシュと括弧だらけでわかりにくいですが、前段の sed

[「下ごしらえ」](b.html#shita)

[「下ごしらえ」](#shita)

のように、丸カッコ内のファイル名相当の部分を削除します。これで生成物の当該部分は

\hyperref[shita]{「下ごしらえ」}

となるので、後段の sed でこれを

\hyperref[shita]{\ref{shita}}

のように書き換えます。

これにより、生成物は

a.tex
\section{はじめに}\label{hajimeni}

\ldots{}

\section{用意するもの}\label{ux7528ux610fux3059ux308bux3082ux306e}

\ldots{}

\subsection{道具}\label{dougu}

\begin{itemize}
\itemsep1pt\parskip0pt\parsep0pt
\item
  包丁
\item
  まな板
\item
  \ldots{}
\end{itemize}

これらは\hyperref[shita]{\ref{shita}}で使います。

\begin{itemize}
\itemsep1pt\parskip0pt\parsep0pt
\item
  大きな鍋\index{おおきななべ@大きな鍋}
\item
  \ldots{}
\end{itemize}

これらは\hyperref[chouri]{\ref{chouri}}で使います。

\subsection{材料}\label{zairyo}

\ldots{}
b.tex
\section{手順}\label{ux624bux9806}

\subsection{下ごしらえ}\label{shita}

ここで使う材料は\hyperref[zairyo]{\ref{zairyo}}にまとめてあります。 \ldots{}

\subsection{調理}\label{chouri}

\ldots{}
大きな鍋\index{おおきななべ@大きな鍋}(\hyperref[dougu]{\ref{dougu}}を参照のこと)を使います。
\ldots{}

\subsection{盛り付け}\label{moritsuke}

\section{おわりに}\label{ux304aux308fux308aux306b}

\ldots{}

となります。

これで相互参照が正しくなった中間ソース a.tex, b.tex ができましたので、main.tex を

platex main
platex main
mendex main
platex main
dvipdfmx main

と処理して、最終的に main.pdf を得ることができます。

EPUB

pandoc は EPUB 形式を出力することもできます。

ソースは複数ファイルに分割されていても成果物はひとつにまとまっていたほうがいいので cat でつなぎます。また、HTML 向けに付けていたリンクの書き方を変更して(LaTeX の場合の前処理と同じです)、pandoc にかけます。

cat a.md b.md \
| sed 's/\(\[[^\]*\]\)[\(][^#]*\(#[^\)]*\)[\)]/\1(\2)/g' \
| pandoc --self-contained -o main.epub

これで最終成果物の main.epub ができます。LaTeX の索引のために挿入しておいた \index{} は無視されるので、特に気にすることはありません。

HTML や LaTeX、EPUB を出力する際には、もっと適切な pandoc のオプションを付けたり、テンプレートを用意したほうがいいのですが、ここでは相互参照に絞って説明するため、これらを割愛しました。

KVM に Kernel Samepage Merging (KSM)

いわゆる自宅サーバーの機器を更新し、これを機にソフトも KVM の上に載せてみることにしました。

用途と向きによって仮想サーバーを切り分けます。ホストも複数のゲストも、ぜんぶ Debian で同じバージョンです。ネットの検索によって得た知識でも何とかなります。

当初気づかずに、後から「こういうのがあるのか」と気づいたのが、KSM (Kernel Samepage Merging) でした(解説はたとえば Linux カーネル共有メモリーの徹底調査)。

KVM on Debian Squeeze – My Notes を参考に設定しました。

ホストとゲストの両方で /etc/rc.local を編集し、次を追加します。

echo 1 > /sys/kernel/mm/ksm/run
echo 300 > /sys/kernel/mm/ksm/sleep_millisecs

再起動後、/sys/kernel/mm/KSM/pages_sharing がゼロより大きな値になっていれば、有効になっています。

KSM は使わないほうがいい?

さて、はじめ気づかなかった KSM についての情報に行き当たったのは、とりあえずしばらく動かしていると、ゲストOSが徐々にメモリを食いつぶしていくという現象をどうにかしたいと思って調べてみたからです。 そこで上記のように KSM を有効にしてみたのですが、引き続き検索していると、「KVMで複数VMを起動してVM間の相互作用を減らしたいときに考えること 」という記事を見つけました。
  • メモリはオーバーコミットしない
    • メモリをオーバーコミットするとろくなことがありません。なので要るだけ積みあげます。安いし。
      • 特にゲストOSがlinuxの場合、メモリはあるだけ使おうとする。本来だとキャッシュとしての有効活用になるキャッシュを積極的に使う戦略が、メモリオーバーコミット環境下ではswapを多発させる原因になってしまう

うーむ。これが原因かもしれません。個々のゲストはさほど深刻な負荷があるわけではなし、一方が急に働くことになっても他方はそれほどでもないことがほとんどなので、個々のゲストのメモリ割り当てを、ほぼ実メモリと同じくらい、としていました。すなわち、ゲストに割り当てたメモリを合計すると実メモリの数倍になっていました。しかし、この記述によると

    • メモリは足りてるはずなのでKSMは停止する

確かに KSM はホストに負荷がかかるので、動かさずに済むならそのほうがいいかもしれません。

もうしばらく様子を見ながら(まだ理解できていないことも多いし)、考えたいと思います。

第何何曜日 再び

昨年末に「2013年に読まれた記事トップ10」を書く際にサイト統計を見たのですが、圏外すぐに「第何何曜日」がありました。古い記事ですが、それなりによく読まれています。

ところでいま調べなおしてみたら、PHP の strtotime() には便利な機能があるではありませんか。前の記事を書くときには見落としていたのか……。前の記事の脚注を見ると PHP 4 と書いているから、まだ使えなかったのかな。

というわけで、いま風に書き直してみます。

Y 年 m 月の第 i の w 曜日は、その月の d 日か

PHP ならこれはもう簡単で、そのまま書くだけです。

Y, m, i, w という記号では書きにくいので、具体的に「2013年12月の第3木曜日」を例にすると、

$d = date("d", strtotime("third Thursday of Dec 2013"));

です。「今月の第3木曜日」なら “third Thursday of this month” ですし、「次の第3木曜日」なら “third Thursday” だけです[1]。なんて簡単なんだ。

ここに日本語が使えると便利なのですが、さすがにそこまではできないようです。というのは、「おととい」を指定するのが、英語だと “day before yesterday” で、まどろっこしいからです。日本語だと今日の前後2日までは短い言葉があるのに[2]、英語だと前後1日までで、その先は持って回ったような言い方になってしまいます。話はやや違いますが、PostgreSQL の SQL でも “today”, “yesterday”, “tomorrow” のキーワードは使えるのですが(ほかの DB はどうなんでしょう?)、「おととい」をしょっちゅう入力したい私はしかたなく日付を使っていて、どうにかしたいなあと思っているのでした。

さて、前の記事の際の動機はゴミの収集日でした。「第 2, 4 月曜日」だとすると、次のゴミの日は

$gomi = date("Y-m-d", min( strtotime("second Monday"), strtotime("fourth Monday") ) );

で済みます。

ちょうど当該日にこれを実行すると、その日になります。しかしゴミの収集時刻 14:00 を過ぎていたら次の収集日を出力してほしいですね。

$base = ( date("G") <= 14 ) ? strtotime("today") : strtotime("tomorrow");
$gomi = date("Y-m-d", min( strtotime( "second Monday", $base ), strtotime( "fourth Monday", $base ) ) );
}

ちょっときれいじゃない気がするけど、こんなのでいいのかなあ。

  1. なお、この書式でも「第5週」の場合は注意が必要です。
  2. その先も「さきおととい」とか「しあさって」あたりまでは、たまに耳にします。