Archive for the ‘My software’ Category

煮ても焼いても食えない楽天モバイルとそのルータRakuten WiFi Pocket(以下RWP)だったが、その後もひそかにいじっていた。その結果、「Linux遊び」ができることは分かったが、それで何かおもしろい・役に立つことに使えるかというと、やっぱり使えないことが分かったw

とりあえず、どうすれば遊べるかを書く。

PCからRWPに繋いでLinuxを使う。

まだ出たばかりで、気付いている方は少ないかも知れないが、RWPにはtelnetで接続できる。ZTEのLTEルータ・モデムで検索すると、特別な手順が必要だったり標準でないポート番号に繋ぐように書いてあるが、RWPでは変えられていないので※、「普通に」繋がる。

※中を見ると、ポート番号を変えるつもりのようだが、バグか何かで変わっていないようだ。間違えてポート番号を指定せずにやったら繋がったので、拍子抜けしたw

なお、外(WAN)からtelnetできると大変危険だが、試したら繋がらないようなので、最低限のパケットフィルタは設定されているようだ。

RWPの管理者のアカウントでログインすると、以下のように普通にLinuxが使える。

$ telnet 192.168.0.1 
Trying 192.168.0.1...
Connected to 192.168.0.1.
Escape character is '^]'.

login: XXXXX
Password:

BusyBox v1.21.0-uc0 (2020-12-04 22:11:15 CST) built-in shell (ash)
Enter 'help' for a list of built-in commands.

~ # uname -a
Linux DEMO 3.4.110 #2 Fri Dec 4 22:06:09 CST 2020 armv7l GNU/Linux

~ # cat /proc/cpuinfo
Processor : ARMv7 Processor rev 4 (v7l)
BogoMIPS : 620.54
Features : swp half fastmult edsp tls 
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part : 0xd03
CPU revision : 4

Hardware : ZX297520V3
Revision : 0000
Serial : 0000000000000000

~ # df
Filesystem 1K-blocks Used Available Use% Mounted on
ubi0:rootfs 60912 16276 44636 27% /
mdev 27472 0 27472 0% /dev
tmpfs 27472 0 27472 0% /dev/shm
ubi1_0 3080 76 3004 2% /securefs
ubi0:rootfs 60912 16276 44636 27% /mnt/tmp

ノード名が"DEMO"だったりリビジョンもシリアルも0だったりして、なかなか香ばしいw 表示が正しいとすれば、カーネルを構築したのが12/4なので、まさに「作って出し」って感じか・・・

その割にはちゃんとIPv6が使えるので、なかなかカオスな感じではある。元(ZTEの物?)ができているだけのことなのか。

なお、ファーム更新でtelnetが止められて遊べなくなると困るので、自動更新を停めた。

micro SDを介してPCとファイルの受け渡し

RWPの「中身」をじっくり見るために、micro SD(以下SD)にバックアップすることができる(SDのマウントポイントは"/etc_rw/config/mmc2")。また、それをPCから取得することもできる。管理画面でSDを"HTTP Share"にすればSDの内容が見られるので、それをダウンロードすればいい。

Rakuten WiFi Pocketのmicro SDにブラウザでアクセスする。

バックアップするにはtarコマンドが便利だが、標準では使えないので、下記のようにフルのbusyboxを入れればOKだ。

標準で使えるddでもいいが、ファイルシステムがUBIFSで手軽に開けないので、僕はtarを使った。

上のような手順で、RWPでsshdなどが動いていなくてもPCとファイルがやり取りできる。

あと、curlは使えるようなので、PCにサーバがあるかクラウド経由ならやり取りできる。

フルのbusyboxでコマンドを増やす。

そのままだとbusyboxの機能(コマンド)が少なくて不便なうえに余り遊べないが、ARMv7l用のフル版をダウンロードして入れれば動く(もちろん、全部のコマンドが使えるかは不明)。RWPに入っているのと同じバージョンのもの(1.21.1)がちゃんと動いた。最新の1.31を試したらtarで落ちてしまったが、別の問題(ルートファイルシステムがフルになると落ちる感じ)だったのかも知れない。

Rakuten WiFi Pocketで(フルの)busyboxを動かす。

SSHサーバ(dropbear)は試していないが、きっと動くのではないか。

設定・状態関連

RWPの中にはいくつか設定ファイルがあり、大抵テキストなので普通に読める。また、運用中の設定や状態は/bin/nvというコマンドで取得・変更・一覧できる。以下に例を示す。

nv get rssi #  RSSIの表示
nv show # 一覧表示

参考までに、rssi以外で良く使いそうな値を以下に示す(ほとんどiV501と同じである)。

  • signalbar: 電波強度(バーの数)
  • network_type: WANのタイプ(LTEなど)
  • network_provider: キャリア名
  • mcc, mnc: 接続先のMCCとMNC
  • network_num_oper: 接続先キャリアの番号?
  • cell_id: 繋がっているセルのID?
  • sta_count: Wi-Fiの子機の数
  • monthly_tx_bytes, monthly_rx_bytes: 月の送受信データ量
  • battery_charging: バッテリが充電中か
  • battery_pers: バッテリの残量(%でなく0-4)

テキストファイル以外にsqliteのDBもあり、接続先関係の設定や接続先を固定するように見える設定があるが、どのように使われている・使うのか分からない。

接続先の固定(できず)

設定ファイルの一部を変更してauに繋がらないようにできないか試したが、できなかった。具体的には、楽天とau(KDDI)のPLMNの設定らしき部分があったので、auの値をダミーにして再起動したが、効かなかった。バグ(書いてある値の10の位と1の位がコメントと逆だった・・・)でその設定は無効なのか、設定方法が違うのかは分からない。

また、管理画面のネットワーク設定で接続先をマニュアル設定にすればLTEの接続先を選択できるのだが※、Rakuten(44011)にしても、電波状態によって勝手にKDDI(44053)に変わってしまった。

Rakuten WiFi PocketのLTEの接続先を楽天モバイルにしても・・・

※この設定を変更するには、一旦WAN(LTE)を切断する必要がある。

ちなみに、上記nvコマンドで取れる動作状態ではmcc, mnc, network_num_oper, cell_idなどが現在のLTEの接続先を調べるのに有用そうだ。

IPアドレスの変更

RWPのIPアドレスは192.168.0.1に固定されていて不便だと思って居たが、実は変更できる。上と同様に、一旦WAN(LTE)を切断すれば変更できるようになる。なお、WAN(LTE)を切断している状態で起動するとtelnetで接続できないので、接続後にLTEを切ること。

Rakuten WiFi PocketのIPアドレスを変更できた。※

※キャプチャではDHCPサーバの設定が元のままなので注意。

 

結局のところ・・・

まあ、1円で確かに「Linuxが動く小さい物」は手に入ったが、以前諦めたWi-Fi内蔵SDカード(PQI Air Card II)と同様、I/Oがない(外部のセンサや動くものなどに繋げられない)ので、僕には全くおもしろく使えない。温度計や照度センサやGPSや接点出力が入っていればいろいろ使えそうだが もちろんなく、せいぜい、電池の温度(本体が熱くなければ、周囲の温度に比例した温度になる)を取ったりセルの番号で大まかな位置を取る程度か。

これのCPUがものすごく高速だったら、何か(少し前だったら、仮想通貨のマイニング?)計算させるとかできるが、全くそんなこたぁないw ちなみに、BogoMipsはCore i7-2600 (3.4GHz)の1/10くらいだ。

ただ、USBはあるので、そこにカメラや温度計などを繋いで使えればいいが、果たしてどうだろうか(Androidスマフォと同様に繋がるのかも知れないし、ホストに繋げる専用ポートなのかも知れない)。面倒なので試していない。

もしUSBストレージやPTPが認識できれば、デジカメの画像をRWPのSDに一時保存するようにするのは容易そうだ。が、「やればできる」程度で実用性があるかどうか・・・ せめてauに繋がらないようにできれば、画像をクラウドにアップロードするようにできるだろうが、auに繋がるのではすぐに通信データ量オーバーになって不便だ。

あとは、本体に付いている小さい画面とボタンで文字などを表示・入力できるようにしたり、ゲームを動かすこともできるかも知れないが、僕は興味ないのでやらない(やってどこかに「Rakuten WiFi Pocketでテトリスを動かしてみた」とか投稿すると受けるとは思うがw)。

でも、そのうち何か思い付くかも知れない。とは言え、本当にやりたいことがあるならRaspberry Piでも買ったほうがずっと早いwww

 

最後に一応書きますが、以上のようなことは全く奨励しません。下手したら動かなくなります。「こういうこともできるかも知れないなぁ」という、初夢や幻想だと思って下さい。

 

PS. 今遊んでいる・試行錯誤されている方から、「お前、余計なこと書くなよ(塞がれるだろうが)!!」とか言って怒られるだろうか?

  •  1
  •  2

時間にものを言わせw、しつこく、煮ても焼いても食えない楽天モバイルをなんとか料理しようとした。結果を先に書くと、さまざまな制限付きで「まあ使える」ようにはなったが、やっぱりイマイチであった。

そもそも一番の問題は、勝手に容量上限付きのパートナー回線(au)に切り替わってしまうため、実質的にはデータ量無制限でないことだ。それで、どうにかして、モバイルルータ(Rakuten WiFi Pocket, 以下RWP)の現在の接続先(楽天かauか)を調べられないか、そして、可能なら、接続先(またはバンド)を楽天(Band 3)だけに制限できないかと思って試行錯誤した。

すると、接続先(またはバンド)の制限はできなかったものの、現在の接続先は、管理画面(web)で簡単に分かることが分かった。なんとも灯台下暗しだった(これ、楽天のFAQにも書いてないので、彼らも知らないのかも知れない)。以下に示す(英語モードで使っていたので英語で書いたが、日本語モードでの表現は適宜推測して欲しい)。

Network Settings → APNのタブにMCCとMNCが出る。 (下図の赤枠)

MCC= 440, MNC=11なら楽天モバイル, MNC=53ならau

Rakuten WiFi Pocketの接続先(楽天/au)を調べる。 (表示は楽天の場合)

そして、管理画面のソースを調べて、iVideoのiV501用に作ったスクリプトを少し手直してRWPでも使えるようにして、MCCとMMCが取得できた。変数名はmccとmncである。以下に実行例を示す。

./iv501-vars.sh mcc mnc
mcc="440";mnc="11"

なお、RWPの変数の取得は以下のようなコマンドでできる("rssi"(電波強度)は取得する変数名)。

wget -q -O - --header \
'Referer: http://192.168.0.1/index.html' \
"http://192.168.0.1/reqproc/proc_get?isTest=false&cmd=rssi"

更に管理画面のソースを見たら、RWPのいくつかのコマンドの実行方法も分かり、RWPの再起動も出来るようになった。以下に、wgetを使った実行例を示す(事前にブラウザなどで管理画面にログインしておく必要がある)。

wget -q -O - --header \
'Referer: http://192.168.0.1/index.html' \
--post-data='isTest=false&goformId=REBOOT_DEVICE' \
http://192.168.0.1/reqproc/proc_post

なお、RWPの変数名やコマンドは、管理画面のソース(特にservice.js)を見れば結構分かる。そういう素直な作りにしてくれていたのはありがたいw これがUSやEUや日本だと、難読化されてしまってやる気が失せるが、CNの「別にいいじゃん」精神には好感が持てる。

ここまで出来れば、RWPの接続先(またはバンド)を固定できなくても※、定期的に接続先を監視して、auだったら再起動すればいい(実際には、再度auに繋がるかも知れないし、NWが切れてしまって不便なので、良くはなくて「まあ使える」や「いいかも」程度)。

※調べると、これの元になったようなZTEのLTEルータではSET_NETWORK_BAND_LOCKコマンドでできるようなのだが(→ 参照)、RWPではできないようだ。実は少し違うコマンドでできるのかも知れないが、管理画面にないので、コマンドなどを調べられなかった。

それで、「こいつ 動くか!?」と思い、(上記のiv501-vars.shで)接続先と電波強度を監視しつつ、設置場所を変えつつ速度を測定して位置を調整した。すると、(iVideoの時と同様、)とても狭い範囲(上下左右前後: 約10-20cm, 水平方向の回転角: 20°くらい(ちなみに、この角度はiVideo(SBM)とは違う))で、(最初に比べれば)悪くない速度が出ることが分かった。例えば、ダウンロードが30-40Mbps, アップロードが2-3Mbpsである。

ただ、その狭い範囲を外れると速度は落ち、下手すればauに繋がってしまうこともあるので(今日試した限りでは、位置を変えなければauにはならなかったが、前を鳥が横切ったりしたらどうなるか・・・)、ルータをガッチリ固定する必要があり、全くモバイルではない。それに、そもそも、(特にアップロードが)遅い!!!

遅いのは、電波強度が-110dBm前後と弱いせいだと思う。-105dBm前後の場所は少し速かった。全く低レベルだ。

それで更に微調整して最適な位置を探していたら、ある時からぱったりと上下ともに3Mbpsしか出なくなってしまった。もしやと思って調べたら、また速度制限である。どうも、一日10GB使うと、その日いっぱいは3Mbpsに制限されるようで、調べたら確かにそのくらい使っていた。

再び溜息・・・

まあ、モバイルとしては一日10GBは小さくないし、3Mbpsも激遅ではないし、その日限りで解除されるのも悪くないけど、上のルータが固定必須という件も合わせて、余りにも不便だ。これでは全然光の代わりにはならないし、外に持ち出してスマフォで使うのにも気後れする。

 

というところで、また何か思い付くかも知れないけど、楽天モバイルは(光に比べて)制限が多いので、それが緩和されない限り僕には使えない。

 

でもまあ、いろいろ分かっておもしろかったので、良しとする^^

 

PS. 従来は新年の挨拶などを書いていましたが、なぜかどうも今年は全くそういう気分でないので、全部すっ飛ばして通常運行してますw たぶん、全部こいつが悪いんですwww

  •  1
  •  2

以前ちょっと書いたように、Androidスマフォでの自動処理などに便利に使っていたAutomagicが終了になってしまったので、他の同等なアプリに移るか使わないで済むようにしようとしていた。具体的には、それまで使っていた2つの処理: スマフォ内の画像のPCへの自動転送とWriteNoteの代わりのメモ作成・送信が対象だった。

調べてみると、有名なTaskerは余りにも操作性が悪いとのことだったし(あと、デモ版がない)、ちょっと試したAutomateは まあ悪くなかったが、またいつか使えなくなる可能性があるのは嫌だし、電池を食う可能性があったので、そういうアプリを使わないで済む方法を考えた。

WriteNoteの代わりについては、以前も書いたように、比較的容易にBNoteという自分用サービスができた。自分のサーバでノートを記録するサーバプロセスを動かしておき、スマフォのブラウザで書き込むものである。

残ったのはスマフォ内の新規画像(動画、音声も可能)のPCへの自動転送だが、これがなかなか難しかった。技術的には全然高度ではないが、Automagicなどのようなアプリなしでスマフォを外から状態取得・制御することは不可能なので、そこを「なんとか」するのが難しかった。具体的には、スマフォ内に新規画像が出来たことはスマフォしか知っていないが、AutomagicなどがないためPCに通知することができないのだ。

それでも、いろいろ考え、試行錯誤やAndroidの動作を確認して、以下のような処理にした。スマフォ側アプリは使わないので、全部Linux PCからの処理だが、念のため、処理の主体として"[PC]"と書いた。

  1. [PC] スマフォがLANに接続され、sshが通じるまで待つ。(= スマフォが室内に入ったか、スリープが解除されるまで待つ。)
  2. [PC] スマフォ内の新規画像の有無を調べる。
  3. [PC] 新規画像があれば取り込む。
  4. [PC] 少し(今は3分)待つ。
  5. [PC] スマフォがLANに接続されていてsshが通じていたら、2へ。
  6. [PC] スマフォにsshが通じなくなったら、1へ。

最初に書いたように、元々Automagicのプログラムからの通知を契機に画像をPCから取得するプログラム(システム)があったのだが、それを上のような処理もできるように変更(機能追加)した。従来のはサーバーモード、今回のはpull(またはポーリング)モードと呼んで居る。今回は、上の処理の3以外の部分を作った(正確には、共通部分=3は同じものを使いたかった)。

なお、「スマフォ側アプリは使わない」と書いたものの、実際にはsshサーバアプリ(SimpleSSHD)を使っている。これにより、PCからスマフォに接続してコマンド(多くのLinuxコマンドが使える)を実行したり、スマフォのストレージにアクセスしたりする。sshサーバ(sshd)はとても汎用的なので、Automagicのようにディスコンになって困ることはまずない。ある製品がディスコンになっても、互換の別のものに置き換えることが容易なためだ。

スマフォ内に新規画像が出来たことをスマフォから通知できないので、PCから定期的に調べる(ポーリング)ことにした。この方法はほとんどいつも無駄にファイルを検索するので好きでないが、仕方ない。頻繁にストレージにアクセスすることで電池消費率が増えなければ良しとしたが、今のところ問題なさそうだ。Androidの仕様なのか、スリープ状態の時は処理が遅くなる(例: 新規画像の検索(の開始)に1分以上掛かることがある)ので、GUIでないプログラムも省電力化されているようだ。

それから、外から帰って来た時などに、スマフォへの接続がなかなかできない問題があった。いろいろ調べたら、スマフォがルータに接続していないためで、当たり前のことだった。Androidはあまり頻繁にWi-Fiをチェックしないようだ。帰宅して画面を点灯しないでいると数十分は繋がらないので、15-30分間隔だろうか(それで、以前は即座に繋げるようなフローをAutomagicで作ったのだが、電池を食うので止めた)。

もう一つの問題は、やはり省電力化に関係すると思われるが、sshで繋がっても、コマンドによって処理が遅いものがあることだ(速いコマンド・場合があることが謎である)。具体的にはrsync(新規画像の取得に使う)が遅くなることが多かった。また、find(新規画像の検索に使う)も遅くなることがある。正確には、どちらも実行が遅いのでなく、起動するのが遅いようだ。rsyncは数分間掛かることがあり、普通の設定だとタイムアウトしてしまう。かといって、タイムアウトを10分などにするのも今ひとつだ。

それで、試しに、sshfsでスマフォのストレージをPCにマウントして画像取得してみたら、マウントされるのが遅いことがあるものの、その後は高速に処理できたので、画像取得はsshfs+rsync(スマフォのストレージをローカルととして扱う)で行うことにした。

ただ、そんなことは(今まで使っていて、今回も使っている)画像取得プログラムは想定していないので、いろいろな対処(「調整」)をした。それらを場当たり的でなく、なるべく汎用的にするのが大変だったが、「まあまあ」だ。

その他に、スマフォの処理状況をPCは分からないので、書き込み中の中途半端な画像を取り込んでしまうのを防ぐことにした。これも どう実装するか悩んだ。結局、ファイルの更新時刻が新し過ぎるものは取り込まないようにした。※ 具体的には、ファイルの更新時刻が現在時刻より1分以内のものは次回(約3分後)に取り込むようにした。

※他の方法として、画像ファイルなどの中身(が正しいか)をチェックすることも可能だが、既存のプログラム(例: ffmpeg, ImageMagickのidentify)で最後の数バイトが欠けても分かるものはなさそうだったので、止めた。

ただ、3分待たずに画像を取り込みたいこともあるかも知れないので、以前同様に手動取り込みもできるようにした。スマフォ側からは、ブラウザでPC側のサーバに(従来と類似の手順で)アクセスする(通知を送る)ことでできるようにした。PC側からは、上の2と3の処理を(周期的なタイミングでなく、)僕のしたいときにするような処理にしている(従来と同じ処理)。

細かい工夫として、スマフォのIPアドレスはルータの設定や交換などで変わる可能性があるが、そのたびにPCの画像取得の設定を変えなくても済むように、スマフォをMACアドレスで管理し、通信する時にarpコマンドでIPアドレスを調べるようにしている。なお、スマフォやPCが起動直後などでarpテーブルに登録されていない場合は、broadcast pingなどで調べるようにした。

 

作って(正確には既存プログラムの改良)出来て、それなりにちゃんと動き出した。手前味噌だが、スマフォで写真を撮影したり画面キャプチャして少しすれば(忘れて居たりするw)勝手にPCに来て、digiKamで"New"のタグが付けられていて一目で分かるので、かなり便利だ。

 

という訳で、めでたく(というか、多くの場合と違って何も問題はなかったので、めでたくはないのだが)Automagicを使わなくすることができた。

 

(バックグラウンドで動く、純然たるサーバプログラムなので全く画像がない。出すとしたら、(ハッカー映画みたいな)ターミナルにデバッグ文字列が流れる動画?w)

  •  0
  •  0

先日買ったLogitecのHDDケース(ビデオ用)が僕のPCや別の外付けHDD(バックアップ用)と相性が悪いようで、USB3では まともに繋げられないことが分かった。もちろん、そもそも、ビデオは観ないので気にする必要はなく、そのまま「そういうものだ」と目をつぶって忘却の彼方に放り出せばいいのだが、それはできない相談だw 随分試行錯誤して、原因に関係ありそうなことが分かって対処ができ、今は無事USB3で繋がるようになった。

環境

  • マザーボード: ASUS P8H67-V
    • USB3のコントローラ: ASMedia ASM1042
  • HDDケース
    • Logitec LGB-EKU3 (= LHR-EKWU3BK)
    • センチュリー 裸族のインテリジェントビル5Bay CRIB535EU3
  • OS: Linux Mint 20 Xfce

現象

  • LogitecのHDDケースに入れたHDDとセンチュリーのケースに入れたHDDをASMediaのUSB3ポートに繋いで同時に電源を入れると、片方(ほとんどはLogitec)が認識されないことが多い。
    • 認識されない場合、Logitecの電源はoff(ランプが消灯)になる。
    • 片方ずつ電源を入れた場合はほとんど問題ない。
      • ただし、センチュリーのケースはタイミングによっては起動しないことがある(offにした直後にonすると、まず駄目)。
      • Logitecもたまに駄目なことがある。
  • 認識されなかった場合、lsusbコマンドでも表示されない。
  • 認識されなかった場合でも、問題のドライブのUSBコネクタを抜き挿しすれば直る。

原因に関係ありそうなこと

  • ドライブを接続した場合、システムのログ(syslog)には、USBのconfig error(詳細は不明)が出ることが多い。
  • センチュリーのケースは一旦High Speedで認識され、すぐに切断されてSuper Speedになることが多い。
    • ただし、上の2つの現象が起こっても正常に認識されることもある。
  • 以下は推測
    • センチュリーのケースの電源が経年劣化で弱くなっていて、電源投入直後の動作が不安定。
      • 仕様上は電源の容量は足りている(HDDの起動時の消費電流を概算で確認した)。
    • Logitecのケースの自動電源オフ機能がせっかち過ぎて、アイドル(USBプロトコル的に非接続)状態だとすぐにoffになってしまう。
      • この状態になると、PCに繋がっていないのと同じなので、電源off/onや抜き挿しする以外は何もできない。
    • ASM1042が古く、USB3対応が怪しい。
    • 同様に、マザーボードも古く、BIOSのUSB3対応が怪しい。
    • 同様に、LinuxのASM1042ドライバが怪しい。

関係なかったこと・試さなかったこと

  • UAS(USB Attached SCSI)が問題になるという情報があったが、どうもASM1042(またはLinuxのドライバ)は対応していないようで(ログに非対応というメッセージ("usb 4-2: USB controller 0000:05:00.0 does not support streams, which are required by the UAS driver.")が出る)、UASを有効にしても無効にしても、現象には関係なかった。また、速度も変わらなかった。
    • ただ、非対応と出るので、念のために無効にしている。
    • 古い情報(2014)だが、LinuxではASM1042のUASはうまく動かないために、無効にするパッチが出ていたようだ。それが今はどうなっているかは不明(無効にはなっておらず、致命的な問題もないが、うまくも動かない)。
  • ドライブやケースが冷えていることは関係なかった(寒い朝に起動しても問題は起こらなかった)。逆に熱いほうが関係しているのだろうか? あるいは、純粋にタイミング的な問題で、温度には無関係なのかも知れない。
    • 今日の昼の比較的暖かい時に試したら問題なかったので、温度は関係なさそうだ。 (12/15 16:50)
  • BIOSのUSB関係の設定はいくら変えても関係なかった。
    • 意味が分からないものがほとんどで、マニュアルにも書いてないものがあり、手探りで試した。
  • 以下は試さず。
    • BIOSのファームウェアは最新なので、更新しようがなかった。
    • ASM1042のファームウェアは公式に配布されていないので、更新しようがなかった。
    • どちらかのドライブをUSB3のハブを介して接続すれば、あるいは、別のUSB3インタフェースボードを使えば直りそうな気がしたが、どちらも手持ちはないからお金が掛かるし、わざわざ古いPCに追加するのは馬鹿らしいので止めた。
    • センチュリーのケースの電源を交換したかったが、やっぱり手持ちはないので、壊れてからにすることにした。
    • 書いたあとで気になったが、どちらかあるいは両方のケーブルが悪いということはあるだろうか? まずないとは思うが、そういうオチもあるから怖い。

対処

  • 問題のドライブ(のUSBコネクタ)をソフト的に抜き挿ししてみたら、うまい具合に両方のHDDが認識されたので、処理を自動化するプログラムを作った(次項を参照)。
    • 検索したら いくつかの方法が見付かったが、USBコントローラを無効にしてから有効にするのが効果があった。 (→ 参照)
      • 具体的には、LinuxのUSBコントローラのunbindとbindという制御ファイルにコントローラのデバイスID(Linuxのデバイス関係にはいろいろな名前があるので、正しい呼び方は分からない)を書き込む。
        • 例(super userで実行):
          • dev_id="0000:05:00.0" (/sys/bus/pci/drivers/xhci_hcdの下にIDの名前のディレクトリがあるので、対象のものを探す)
          • 無効化: echo $dev_id > /sys/bus/pci/drivers/xhci_hcd/disable
          • 有効化: echo $dev_id > /sys/bus/pci/drivers/xhci_hcd/enable
      • この方法だと、そのコントローラに繋がっているすべてのデバイスが切り離されてしまうので、多くのデバイスを使っている場合は余り便利でない。(別のコントローラに繋がっているデバイスは全く問題ない)
    • 念のため、抜く前に、認識されてマウントされているディスクをumountすることにした。

ソフト

  • 問題発生の検出と対処を自動化するスクリプト(chk-usb3-mf.sh)を作った。
  • chk-usb3-mf.shは以下の処理を行う。 (概要)
    1. システムのログ(/var/log/syslog)にメッセージが記録されるたびにチェックし、問題に関係のあるイベント(下記)を抽出して、それぞれに対応する処理を行う。
      • USB config error (例: "usb usb4-port1: config error"): 処理に必要ではなく、参考のために抽出している。
      • Super Speedデバイスの認識 (例: "usb 4-1: new SuperSpeed Gen 1 USB device number 4 using xhci_hcd"): それほど重要ではなく、参考のために抽出している。
      • High Speedデバイスの認識 (例: "usb 3-1: new high-speed USB device number 2 using xhci_hcd"): 処理に必要ではなく、参考のために抽出している。
      • SCSIデバイスの接続 (例: "sd 6:0:0:0: Attached scsi generic sg3 type 0")
        • なぜか、ディスクIDの先頭は"sd"の場合と"scsi"の場合があった。
      • ディスクのマウント (例: "Mounted /dev/sdd1 at /media/XXXX/VOLUME on behalf of uid YYYY"): 上のattachと比べてマウントには時間が掛かるので、今は参考程度にしか使っていない。
      • 周期タイマー(ログのイベントではない): タイムアウト処理のため、一定時間(2秒)ごとに起動する。
    2. SCSIデバイスが接続されたら、ディスク数を+1する。
    3. ディスク数が想定値(2)になったらOK(= 問題は起こらなかった)なので、タイマを停めて内部状態をリセットする。
    4. そうでない場合はタイマを起動する。
    5. タイマがタイムアウトした(前回のSuper Speedデバイスの認識から規定時間(6秒)以内にディスク数が想定値(2)にならなかった)場合、問題が発生したので、USBの再スキャン(USBコントローラの無効・有効化)処理を行う。
      1. 再スキャンを行うかのダイアログを出す。
      2. 回答が「行う」の場合は、以下を実行する。
        1. Super userの権限が必要なので、以下の処理をpkexecを使って行う。
        2. 認識されたディスクがマウントされていたらumountする。
          • タイミングによっては、問題を検出したときはドライブを認識だけしていて、この処理の直前にマウントされる場合があるので、ドライブのデバイス名が分かる場合は、エラーになってもいいのでumountするようにした。
        3. そのディスクのUSBコントローラ(= ASM1042)を無効にする。
        4. 少し(1秒)待つ。
        5. 無効にしたUSBコントローラを有効にする。
        6. 少し(1秒)待つ。: 不要と思われるが、念のために入れた。
      3. 内部状態をリセットする。

結果

  • 成功: おそらく10回以上試したが、問題の発生を確実に検出できてダイアログを表示し、そこで指定することでUSBデバイスの再スキャンを行って両方のドライブを認識できるようになった。

その他

  • 電源投入直後に比べ、コントローラの無効・有効後のドライブの認識はすごく速い。これが何か関係あるのかも知れない。
    • 単に、HDDなので電源on後に回転数が上がるのを待つ時間があるだけなのか?
  • ASM1042のSuper SpeedとHigh Speedは、仮想的に別のポートとして扱われている(LinuxではデバイスIDが異なる)。
  • 一度、ファイルマネージャ(Thunar)の動作がおかしくなった。Thunarのボリューム管理と本プログラムのumount処理が競合したと思われる。
  • 想定した数のドライブが接続されていることを前提にしているので、本当にドライブが少ない場合でも問題が起こったと認識してダイアログが出るのが今ひとつ。
    • ドライブが認識されていない状態ではドライブが繋がっているかどうかは分からないので、ドライブ数を自動で判別するのは難しい。
  • イベントのチェックや再スキャン処理の実行はもっとスマートな方法(udevを使う?)があると思うが、udevはなかなか手ごわいので、今回は見送った。
  • 本当はダイアログを出さずに自動的に再スキャンしたいが、無限に再スキャンし続けることがありそうなので、今は止めている。

 

これでめでたくLogitecのHDDケースもUSB3で繋げられるようになった。USB3になった効果としては、転送速度が約2倍(80MB/s前後)になった。とはいえ、何度も書いているように、このHDDを使うことはほとんどないので、あくまでも自己満足の世界であるw

ただ、USBポートのソフト的な抜き挿しは以前からやりたかった(何度も失敗していた)ので、用途は限定的ながらもその方法が分かったのは、収穫だ。

 

そして、(前に書いたが、)Logitecのケースについては、この処理に加えて、定期的にアクセスすることで自動電源オフ機能を実質無効化できたのと電源・アクセスランプを前面に付けたので、ようやくまったく普通に使えるようになった。いやぁ、全く面倒な奴だ・・・w

 

PS. デバッグや動作確認で何度もoff/onすると、いつかセンチュリーの電源が壊れそうで ひやひやしていたが、今はまだ大丈夫そうだ。でも、古いもの(2011年に購入)なので いつかは壊れる気がする。

  •  0
  •  0

先日ようやくEvernoteからの脱却が片付いて、これで ちょっとのんびりできそうだとPCをいじっていたら、ふと、観もしないビデオが山ほど入ったHDDを整理したくなった。

詳しく書くと、僕のPCにはSSD(システムディスク)の他にHDDが2個あり、ビデオはビデオ用HDDと、(それだけでは足りず、)もう一個(ドキュメントや音楽用)に入っている。その後者に入っているビデオをどうにかしてビデオ用HDDに移し、ビデオ用HDDをPCから外して保管し、PCのHDDをドキュメント・音楽用だけにして簡素化したくなった。そうすれば、使いもしないHDDをいつも動かしておくことがなくなって気分が良くなり、将来小さいPCケースにすることもできそうだからだ。

なお、外したHDDをずっと動かさないでおくと、メカが劣化して いざ使う時に動かなくなりそうなので、HDDアダプタに入れてバックアップHDDと同じ電源系統にして、バックアップする時に電源が入るようにして、定期的に動かすことで劣化を防ぐことを考えた。

とは言え、そもそも今まで溜まったビデオを観たことなんてほとんどないので、そういう維持措置、それどころかデータ自体が不要な気もしたが、まあ、無碍に捨ててしまうのもなんなのでw、今は残すことにした。

ビデオの容量の大半は地デジなどのTV番組(当時はちゃんとN○Kと契約していたw)を録画したファイル(MPEG2-TS、以下TS)で、1本10GB以上にもなることがある(今となっては「馬鹿かな?」と思うし、当時も確かに大きいとは思って居たものの、HDDも大きいからそれほど大きな疑問はなかった)。

TSを圧縮する方法を調べたら、MPEG4(以下MP4)にするといいようだった。ffmpegというプログラムで試してみたら、容量が1/10くらいになった(例: 約30分の番組で、TSが3.3GBだったのが、MP4にしたら330MBになった)ので、「これはいい!」と、「ちょっとやってみる」ことにした。そして、いつものように想定外の問題が多発して苦労した・・・w

それにしても、もう圧縮方式の細かいことは分からなくなってしまったが、TSはなんであんなに巨大(圧縮が効いてない)なのだろうか? 駄目な子だったのか、MP4はその後の進歩の成果なのか。これだったら、一般人がTSで保存する意味はほとんどないではないか。

記憶と記録から思い出すと、以下のような想定外の問題に苦しんだ・・・

  • ffmpegのクソ仕様
    • ffmpegは標準入力(stdin)からキーを読み込むらしく、一括変換スクリプトが誤動作して(ffmpegにファイル名を読み込まれてしまい、最初のファイル1個しか変換できなかった)訳が分からず、しばらく悩んだ。普通はstdinがターミナルか判定するものだが、なぜかしていないようだ。
      • でも、今となっては(以下に延々と書く問題に比べたら)こんなのは可愛い方だったw
    • あと、警告だかを黄色い文字で出されて(ターミナルの背景が明るいので)、全然読めなくて困った。
  • 一部のファイルで音ズレ (謎) ← 二か国語とステレオ放送の切り替えが悪かったようだ。
    • TVのタイマー録画は番組開始の少し前から録画が始まるが、前の番組と本編の音声モード(二か国語/ステレオ)が異なると(例: 本編の前がニュース)、MP4に変換した時に本編が音ズレする(約0.8秒、音が遅れる)問題が起こった。
      • TSを再生する時は問題なかったのが不思議だが、実は他にもいろいろ問題はあって、どうやら まともに再生できるものは少なかった。
      • Windowsでは、日本製の日本のTVにきっちり対応しているソフトを使って居たので大丈夫だったが、Linuxではまともに再生していなかったので気づかなかった。
      • → いろいろ調べ、試行錯誤して、ffmpegのjoinというフィルタで二か国語の主と副音声をMP4のステレオの左右に振り分けてみたら(後述)、なぜか音ズレがしなくなった。
        • ↑ 主/副と左/右の対応を無意識に決めてしまったが、大丈夫かと今になって心配になった。でもまあ、左右はいつでも交換できるから、いいやw
  • 「ガラパゴスMPEG2-TS」の問題
    • デジタルTVを録画した場合、1ファイル中に複数の「プログラム」というものが入っており、中にはワンセグらしきものもある。どういう訳か、そのワンセグが再生されたり変換時に抽出されることがある(その場合、ぼやけた天気予報のようなものになることが多い。: これを見た時、放送の予定が変わってちゃんと録画されていなかったのかと、今更ながら思ってw、ファイルを削除した。でも、あとで本当のことが分かってバックアップから戻した)。正常な場合も多いので、不思議だ。
    • 上記の二か国語とステレオ放送の問題もある。
    • 更に、アナログと違って「二か国語かつステレオ」の番組もあって、一応両方残したいが、どうやったら全部をMP4に入れられるのか分からず、途方に暮れた。。。
      • → 上の音ズレに似たような処理で、ffmpegの-mapというオプションで二か国語の主と副音声をMP4の2組のステレオ音声にして対応した(合計4チャネル)。主と副は再生時にプレーヤーで選択できる。
  • MP4は万能でない。
    • 小さいビデオ(MPEG2など)を圧縮すると、画質の劣化がひどい。
      • → 一括変換時はファイル形式(suffix)でTSだけを抽出し、更に、ファイルサイズが小さい場合も変換しないようにした。
  • Linuxには何でも再生できる動画プレーヤーがない。
    • (ガラパゴス)TS, BD, DVD, MPEG2などのフォーマット全部をまともに再生できるプレーヤーはない。
      • いろいろ試した結果、対応フォーマットの幅広さに関してはffplayが一番マシで、次はCelluloidかvlcと思う。
      • ただ、ffplayは余りにも簡素で使い勝手が悪いので、再生用のスクリプトを作った。
        • DVD(IFOやVOBを指定)や、音声(MP2)が別になったMPEG2(M2V)を音声を合わせて再生できるようにしたり、動画のサイズ(画素数)に従って、適当なサイズで表示するなどの機能を付けた。
        • が、作りながら、そもそも観ないのに そんなものを作る必要はあるのかと疑問に思ったw ただ、たまに確認する時(があるとして)などに何も考えずに観られたほうがいいのは確かなので、意味はある。
      • → その後、ffplayで再生するのは、他のプレーヤーでは特殊な場合に対応できないTSだけにして、あとはvlc(DVD)とCelluloid(MP4, BD, MPG, 他)を内部的に切り替えて使うように改良した。適材適所である。
        • なお、vlcはDVDのメニューが動くので使った。
  • HDDケース(Logitec LGB-EKU3(= LHR-EKWU3BK))の問題
    • 自動で電源offになるのが早過ぎて、USB3のポートにバックアップ用HDDと一緒に繋ぐと認識されないことが多い。USB3だと単独でも駄目なことがある。
      • バックアップ用HDDの起動が遅く、それまでにHDDケースがアクセスされないと電源が切れてしまうようだ。
      • PCが古く、当時出たてのUSB3 IFとの相性が悪いのかも知れない。
      • → 仕方ないので、HDDケースはUSB 2に繋ぐことにした(そういうことなら、もっと安いUSB2対応のケースにすれば良かった・・・)。まあ、ビデオなら問題はない(そもそも観ないしw)。
    • 使っていて気付いたこと。
      • このケースは5分間(短い!!)アクセスしないとスタンバイになり、次にアクセスする時は結構時間が掛かり(数秒間だろうが、10秒以上に感じる)、その間は関係するアプリがハングしたようになってイライラするので、ディスクがマウントされている時は定期的(4または5分ごと)にアクセスするようにして、スタンバイさせないようにした。今、効果を確認中である。 (12/12 12:20)
      • 電源・アクセスランプが後ろ側(ケーブルを繋ぐ側)にあって(コストダウンのためだと思う)、正面から見えなくて不便だ。今は後ろ側を前に向けているがかっこ悪い。あとで改造して、ランプを正面に移したい。 (12/12 12:23) → 前面にランプを追加した。 (12/13 7:03記)
      • 「アルミ製ケースで放熱性がいい」とうたっているが、疑わしい。密閉して通風せず、HDDとケースが密着しておらず(上部で接してはいるが、充分とは思えない)、ケースも放熱しやすい形状ではないので、熱はこもると思う。実際、HDDの温度は通常より高目になった(10℃近く高くなった)。熱くはないが、熱を持つタイプを長時間使うと良くなさそうだ。 (12/13 5:30)
    • 結局、このケースはなんかイマイチだ・・・ 一応使えるけど。
  • Linuxのデバイス名が変わる問題
    • 大昔と違い、ディスクのデバイス名が起動時の状況で変わるため、外付けHDDを繋いだまま起動すると、それが/dev/sda(通常はシステムドライブの名前)になってしまい、状態監視ソフトMuninのHDD関連の表示がおかしくなる。。。
      • udevの設定で回避できそうだが、とりあえずは、起動時には外付けHDDはoffにすることにした。
      • デバイス名が変わってもちゃんと起動するだけマシだが・・・
        • 良く考えると、デバイス名が変わっても大きな問題なく動くのがなかなかすごいと思う。
        • 更に考えると、「だったら、デバイス名なんて意味ないから止めろよボケ!」って言いたいが、僕には作れないので言えない。
      • → その後、MuninのHDD関連のプラグイン: hddtemp_smartctlとsmartの設定で、ディスクのデバイス名でなくディスクID(/dev/disk/by-id/*)でアクセス・表示するようにして、デバイス名が変わっても値が変わらないようにした(ディスクIDはなかなか長いが仕方ない)。他にもデバイス名を使うプラグインはあるが、方法が分かったので良しとする。 (12/12 12:12)
        • → その後、hddtemp_smartctlで仮想的な(公称の?)デバイス名を使う方法が分かり、従来どおりの表示(例: "/dev/sda")にできた。また、特定のドライブのタイプを指定する方法も分かった(これにより、デフォルトでは対応していない外付けドライブの温度も表示できるようになる)。概略を以下に書く。 (12/12 23:48)
          • /etc/munin/plugin-conf.d/munin-nodeのhddtemp_smartctlセクションに以下を設定する。
          • 仮想的なデバイス名の指定: env.dev_仮想デバイス名 実際のデバイス名("/dev/"は省く)
            • 例: env.dev_sda disk/by-id/ata-ADATA_SX900_.....
          • 特定のドライブのタイプの指定: env.type_デバイス名 ドライブのタイプ
            • 例: env.type_sdc sat
      • → その後、BIOSのSATA設定でシステムドライブなどのPlug and playをoffにしたら、外付けHDDを繋いだまま起動しても内蔵ディスクのデバイス名が変わらなくなったようだ。Plug and playが有効なドライブはUSB接続と同等に扱われるのか。 (12/14 7:03)
  • 動画管理ソフト tinyMediaManagerの最新版(V4)が有料(サブスクリプション)になってしまった。しかも、安くない。
    • 今の版(V3)に不満があることもあって代替を探したが、なかなかいいものないので、「自作するかなあ」と思い掛けたが、そもそもほとんど使わないので、今使っている古い版で充分だと気付いた。

他にもあったかも知れないが、思い出せない。

そんなこんなで、ようやく落ち着いた。PCが古いため、約150本(最初は最低限だけ圧縮しようと思って居たが、段々、あれもこれもと増えた)のビデオの圧縮に数日間掛かったが、その甲斐あって、合計約3TBが約2TBに減り、目論見どおりビデオ用HDDをPCの外に取り出せて、PCのベイはまさにスカスカだ^^ 変換したビデオを削除すれば、ドキュメント・音楽用HDDの空きが500GBくらい増えて1.2TBくらいになる。こっちもスカスカだ。これなら、ちょっと怖いけど、将来は大き目のSSD一個にできるかも知れない。

 

なお、TSの圧縮(MP4への変換)は以下のようなコマンドで行った(それぞれ見様見真似・試行錯誤で決めたので、これで本当に正しいかは不明)。

通常の場合:

ffmpeg -i (ファイル名).ts -c:v libx264 -crf 29 -preset veryfast (ファイル名).mp4

説明: -crfは品質を、-presetは変換速度を指定するようで、検索したり少し試して、上のようにした。crfが29だと圧縮後のサイズが1/10くらいになった。

音ズレへの対応:

fm_cda_L_pno=(左チャネルに対応するTSのプログラム番号(例: 1024))
fm_cda_R_pno=(右チャネルに対応するSのプログラム番号(例: 1025))
ffmpeg -i (ファイル名).ts -c:v libx264 -crf 29
-preset veryfast -filter_complex
"[0:$fm_cda_L_pno][0:$fm_cda_R_pno]join=inputs=2:
channel_layout=stereo[a]" -map 0:0 -map "[a]" (ファイル名).mp4

説明:TSの中にいくつかあるプログラムなるもののうち、日本語と英語と思われるものの音声をMP4の左と右に割り当てている。本来は、放送のモードがステレオに変わったらステレオになるべきだと思うが、録画に使ったソフトかffmpegの仕様なのか、ずっと二か国語モードのままなので、このようにした。

なお、検索して参照したページにもう一つの方法として書かれていた、amendというフィルタだと、左右が混ざってしまって良くなかった。 (良く分からないで使っているせいだとは思う)

ただ、本来は、音声モードが変わる時になぜか起こる音ズレを解消したかったのに、単に音のチャネル割り当てで直ったのが謎だ。

ステレオの二か国語への対応:

ffmpeg -i (ファイル名).ts -c:v libx264 -crf 29 -preset veryfast
-map 0:0 -map 0:1 -map 0:2 (ファイル名).mp4

説明: デジタルTVの二か国語放送は主・副音声ともにステレオなので、それぞれの音をMP4に入れた。主音声は最初の2チャネルペア(-map 0:1)、副音声はそのあとの2チャネルペア(-map 0:2)になっており、プレーヤーでは、例えば、vlcでは"Audio track"で切り替えることができる。

 

それから、確認のためにMP4に変換後のビデオをちょっとずつ観ていたのだが、いろいろな感想があった。

  • 昔の洋楽のPVの番組は、ほとんど音(演奏)でしか知らないアーティスト(例: ボストン、プリテンダーズ、ブームタウン・ラッツ)が動く姿が観られて、なかなか興味深かった。あと、たまに、口パクでなく本当に演奏しているものもあって、貴重だった。
    • まあ、今ならYouTubeでいくらでも観られて、そでも観ないのだから、やっぱり僕には必要ではないのだろうが、ちょっと観るのはおもしろい。
    • でも、年代にもよって、60年代は「いかにも」で ほとんどつまらなかった。ビートルズは異質だったのか、特別僕の好みだったようだ。そして、60-80年代ではやっぱり80年代が良かった。
    • 更に余談だが、さっきPVを観たプリテンダーズのボーカルの女の人は「姉貴」って感じで頼れそうな気がする。でも、下手に甘えると「ウルセー」とか言われれそうだが、実際にはそうでもなさそうなのがいい。と妄想しているw
      • あと、プリテンダーズはギターが二人ともテレキャスだったのがポイント高い(たまたまその曲だけかも知れないが)。高校の頃はシンプルな外観が大好きだった。今は、音から言うとレスポールかねえ。
  • YMOは好きだけど、各メンバー(坂本も細野も高橋も)は全員好きじゃない。(今となっては)全員暗くて意識高そうで、更に気持ち悪い。
  • 当時(十年くらい前)好きで録り溜めた日本の女優・歌手などの番組は、全部捨てたいw
  • 当時でもベテランの領域になっていたアイドル系女性歌手を、とてもクリアなPCのディスプレイでアップで観てしまうと、「うむ・・・」という気分になった。
  • 当時書いたかも知れないが、2011年2月の「題名のない音楽会」でマーティー・フリードマンがエレクトリックギターでソロを演奏した、ラフマニノフのピアノ協奏曲 第2番(抜粋?)がなかなか良かった。乗りはいいし、音もいいし(意外にもギターの音は浮いておらず、ピアノに通じる響きすらあった)、カデンツァがうまい具合にギターソロに対応していた。
    • もう少し細部が丁寧なら、完璧になったと思う。あと、カデンツァのアドリブはもう少し自由さやゆらぎが少ない方が良かった気がする(一言で書くと、「少しやり過ぎ感があったかも」)。それがロックギターで、それは好きだけど、曲はロックではないので。: この味付けは なかなか難しいと思う。
    • そして、「やっぱりピアノには負けるよなー」と思ったw
    • この番組はYouTubeにないようなので、意外に結構貴重なのかも知れない。
    • 余談だが、彼の演奏を探したら「天城越え他」(2011)があり、僕も石川のそこら辺の歌は好き(かっこいいと思う)だし、ギターがなかなか気持ちいいので、意外に趣味が近いところがあるのかも知れない。でも、あの髪の毛は邪魔そうだw
  • ほんの一瞬を観ただけでつまらないと感じる作品は多い。松田優作は好きだけど、時代劇などはつまらない。
  • 生のキャンディーズ(初期)は歌が下手だった・・・ 小泉も。
  • 大昔にLDやVHSからPCに取り込んだビデオと同じ作品でHD版などでもあるものがあり、それらを比べるととんでもなく画質が違うので驚く。昔はあんなに小さくてボケボケの映像でも、「LDは綺麗だ」とか言って観ていたものだ・・・ (ボケや画質の悪さは、PCに取り込んだ当時に知識が足りなくて、設定が今一つだったせいもある。VHSの3倍モード的な感じで、ボケ以外にギザギザになっている。)
  •  1
  •  0

Evernoteからの脱却の一環として先日作った、WriteNoteの代わりのメモアプリ・システム BNoteを改良、というか何度も作り直して居た。いろいろ試したものの、結局、25年くらい前を彷彿させる※素っ気ないwebとなった。

※でも、marqueeやアニメGIFは使ってないので許されそうだw

僕にとって一番重要なのは、主に外出先で手軽に「サッと」ノート(タイムスタンプ付きメモ)を書くことができる、しかも、入力欄が大きくて見やすい・書きやすいということで、それらは充分に満たしているし、自分だけで使うものなので、やり過ぎるのは疲れるうえに馬鹿らしいから、とりあえずは良しとした。

以下にその変遷を書く。

  1. Automagic版
    • Automagicに問題はなかったが、この夏に終了になってしまったため、なるべく移行した方がいいと考えた。
    • また、入力欄が小さい(ほとんど調整できない)のがちょっと気に入らなかった。
  2. Automate版: 初期の機能確認まで
    • Automagicの代替アプリのひとつ、Automateを試してみた。
    • 機能的には使えそうなことは分かった(入力欄はAutomagicより良かった)が、有料だし面倒(グラフィカルなプログラミングはスマフォでしかできないので、結構疲れるし、何をするにもやり方が違う)なので止めた。
    • 入れたら電池消費が増えた(本当かは不明)気がしたのも、止めた理由の一つ。
  3. Web版 (作らなかったかも: 記憶が曖昧)
    • 試しに作って動いたが、ちゃんと使うには認証が必要なので、WordPress版に移行した。
  4. WordPress版
    • WordPress(以下WP)の非公開の投稿(ログインしないと表示できない)に無理やり(<pre>の中に入れた)HTMLとプログラム(PHP)を書いて、ノートが書けるようにした。
    • WPで認証できるメリットがあったため、やってみた。
  5. Web版 (WPで認証)
    • さすがに(中身が)綺麗でなかったので、単独のwebページにした。ただ、認証は必要なので、(無理やり)WPの認証を使った。
      • どういう仕組みかは分からないが、wp-load.phpを取り込むと、ログインしているかの確認ができる。
  6. Web版 (Joplinに保存): 中止
    • サーバにJoplinアプリ(コマンドライン版)をインストールすれば、自動でJoplinに取り込めて便利だと考えたが、以下の理由で中止した。
      • サーバにJoplinのストレージのNextcloud(以下NC)のアカウント情報を保存するのは良くない。
      • Joplinアプリのキャッシュ(Joplinのノート全部が入る)は暗号化されないが、それではNCのストレージを暗号化している意味がなくなる。
  7. Web版 (NC管理下に保存)
    • ノートのファイルをNCの管理下に保存し、NCでデスクトップPCに同期できるようにした。
    • NCの仕様により、ノートは平文で保存している。
      • BNoteのノートは量が少ないので、許容することにした。
  8. NCのFormsアプリ改造版: 断念
    • ファイルはNCに保存するのに認証がWPなのは変なので、NCの認証が効くNCのアプリを利用しようとしたが、断念した。
    • Formsアプリ(アンケートなどに使うアプリ)が結果が見やすいので試してみた。
      • Formsの入力ページを外のページのIFRAMEに入れて位置情報を追加しようとした。
        • しかし、どうしてもFormsの入力フィールドに位置情報を設定(自動記入)できなかった(設定してもサーバに届かない)ので、諦めた。
  9. NCの外部サイト版: 断念
    • NCから外部サイトを開ける機能にBNoteのweb版を指定して、NCの認証を利用しようとしたが、手軽に使える認証情報はなかった。
      • その情報(例: 外のNCのページのrequesttoken)とNCのDB内に保存された値を比較すれば、認証しているか確認できそうだと考えたが、DB内には見つからなかった。
    • NCのOAuth2機能が使えそうだったが、それほど手軽ではなかったので断念した。
  10. WP版 (Basic認証+α) ← 今ここ
    • 既にある手軽な認証機能を使うのを諦め、(昔ながらに)自分で認証することにした。
    • HTTPSなら、Basic認証は(カッコ悪いけど)それほど脆弱でないので、そうした。
    • また、愉快犯によるブルートフォース攻撃を避けるため、URLのパスを"bnote"のような分かりやすいものでなく暗号みたいな文字列にして、ログインを試すこと自体を難しくした。
      • 仮にログインできても、ノートが書けるだけで読めないので、(DoS攻撃は別として)致命的な問題は起こらなそう。
      • とは言え、変な引数やバッファオーバーフローなど、考慮していない脆弱性があるかも知れないので慎重を期した。

以下に、作った(出来た)ものについて書く。

BNoteの機能

  • スマフォで(PCでも)短いノート(タイムスタンプ付メモ)が書ける。
    • ブラウザで動くのでアプリのインストールは不要。
      • ただし、スマフォの場合、Operaでは位置が取れず、Firefoxはなぜかハングして表示できないので、事実上はChrome系しか使えない。
  • 各ノートには時刻と位置(取得可能な場合)が追加される。
    • 各ノート間は空行で区切られる。
    • その日の最初のノートの前には日付も入る。
  • 一日分のノートは1個のファイル(ファイル名に日付が入る)にまとめられる。
    • ユーザ(一人しか居ないが)・年ごとに別のディレクトリになる。
  • ノートのファイルはサーバに作成され、自動でデスクトップPCに同期される。
  • ノートを新規作成・更新したらメールで通知が来る。(Joplinへの転記忘れを防ぐため)

 

実装メモ

  • 認証: Basic認証
    • 上記のとおり、HTTPSならそれほど脆弱でないと考えた。
  • ノートの入力: HTML(FORM, textarea)
    • ノートをJavaScriptで送るためPOSTは面倒だったので、GETを使っている(URLのクエリー文字列にノートを含めている)。それぞれのノートは短いので、GETでも大きな問題はなさそうだと考えた。
  • 位置の取得: JavaScript
    • 送信ボタンを押した時に位置を取得し、ノートと一緒にサーバに送る。
    • 位置取得条件は「何でも可」(高精度でなくても可、無限に過去のものも可)にして、電池消費を増やさないようにしている。また、「あればいい」スタンスなので、取得タイムアウトを0.5秒と短めにした。
  • ノートへの時刻・位置情報の自動付加: PHP
    • ノートの送信時刻を各ノートの前に付け、位置(送られて来たら)を後ろに追加して、ファイルに記録する。
    • 時刻は、クライアント(ブラウザ)から送られて来たらそれを使い、なければサーバでの受信時刻を使う。
  • ノートの保存先: 通常のファイル (NCで同期)
    • NC(暗号化ストレージ)以外で作成・更新したファイルの取り込みを容易にするため、「外部ストレージ」の機能を使った。
  • ノートの同期: Nextcloudアプリ
    • 今までは別のファイルをrcloneで同期していたが、こちらのほうがリアルタイム性があって便利なので、全部を切り替えた。
  • 新規作成・更新ノートの通知: crontab+find
    • 定期的に検索している。
      • 最後に最新だったファイル名を保存しておき、それより新しいものを調べている。

問題点・TODO

  • サーバが停まっていたり、通信出来ない場合はノートが書けない。
    • そういう時は、エディタやJoplinを使うとか、手で紙に書けばいいか。。。
      • 通信できる場合は、元祖のWriteNoteを使ってもいい。
    • ブラウザのローカルストレージを使う手もありそうだが、なかなか面倒そうだし、やり過ぎだろう。
  • 複数のセッションで同時に書き込むと、きっと良くないことが起こる。
    • 対応するとすれば、書き込む時に排他制御するのだろうが、一人で同時に別の端末から書き込むことは物理的にできないので、対処しなくても大きな問題ではない。
  • 位置の取得条件などを変えられると便利かも。
    • そういう設定を付けても、いじることはまずなさそう・・・

その他

  • FirefoxのAndroid版は、上記のようにハングしたり位置が取れないだけでなく、viewportの動作がChromeやOperaと違っていた(textareaの幅がものすごく広くなった)ので、以前もそうだったが、相変わらず使えないと思った。
  • Operaで位置が取れないのは、navigator.geolocation.getCurrentPosition()のオプションの高精度("enableHighAccuracy")を有効にしていないからかも知れない。(未確認: これを指定すると電池を食いそうなので、余りしたくない)
  • 今はノートの記入にはChromeを使っていて、電池消費が気になるが、使いながら確認したい。
  • JavaScriptを使うと、(セキュリティ上の条件はあるが)iframeの親(外)や子(中)にアクセスできることが分かり、なかなか強力だと感心した。

 

PS. Evernoteからの脱却はほとんど終わったようなものだ。近頃はEvernoteでノートを書くどころか、全然アクセスしていない。あとは残りのノートをJoplinに移行する「だけ」だからロボットにでも頼めばいいが、適当なものがないのでw、やる気が出た時にやろうと思っている。ノートの数が多いので、重要なものだけは目で確認し、残りは一括処理しようと思っていて、その準備は大体できている。あとは一括処理するスクリプトを書く「だけ」だ。これもロボットに頼みたい(爆)

なお、Joplinは最高とは言えないが、少なくともEvernoteの10倍は いい。自分でいろいろ いじれるのもいい。ただ、Androidアプリはもう少し頑張って欲しい(大きいノートではビューア以外に使うのはキツい)。今はデスクトップ版に注力している感じなので、今後に期待したい。

PS2. その後、Hacker newsを見ていたら、僕と同じようにタイムスタンプ付きメモをしたい人(→ 元のスレッド: jlduggerという人のコメント)が居ることを知り、そのためのツール(jrnl)があることを知った。ノートの記録(表示)のされ方がBNoteそっくりなのに驚いた。 (11/26 14:16)

  •  0
  •  1

数日前には「やらない」と書いたのだが、やっぱり、できそうなことはやってみたいので、WriteNoteの代わりを作ってみた。

最初は、書いた内容をオープンなフォーマットのファイル(例: プレーンテキスト)に保存できるチャットとかメモアプリがあればいいと思ったが、そういう都合のいいものはなかった。チャットだと受け側のログをコピー・ペーストすればいいが、書き始める時に相手(= 受け専用の自分)を指定するのが面倒だし、間違って他の人を指定する可能性もあるので止めた。メモアプリは内部データの場所が分からないのと、わざわざ「エクスポート」しなければ外部フォーマットのファイルには書き出せないものばかりだった。

それで、Automagicで作った。処理は簡単で、以下のようなものだ。

  1. [僕] アイコンをタップして起動する。
  2. [僕] ノートのテキストを入力する
    • "CANCEL"を押すと書き込まれない。
  3. (GPSで)現在の位置を取得する。
    • 新しく位置を取得するのに時間が掛かるので、通常はそれ以前に得られた位置を使うようにした。
    • ただ、移動中など、特別に正確な位置を取得したい場合に備えて、位置の取得を待てるようにもした。
  4. 入力されたテキストに現在時刻(※)を前置し、位置を追加して、毎日分のファイルに追記する。

※書いていて誤りを見つけた。前置するのは時刻だけでいいのに、日付も入れている。まあ、その方がJoplinに転記する時に日の間違いが起こりにくいからいいか。あとは、その日の一番最初に日付を書くのも良さそうだ。 → そうした。

更に、PC側は既存の自作の画像自動取り込みプログラムでノート取り込めるようにした。そうすれば、外から帰宅したら、撮影した画像(あれば)と一緒に自動で取り込まれる。まだやっていないが、取り込んだノートの有無や更新を調べて通知すれば、Joplinに取り込み忘れることもない。

この方式の欠点は、ノートを書くたびにクラウドサーバに送られる訳ではない(帰宅してPCに転送するまでスマフォの中にある)ので、何かのトラブル(スマフォの故障・紛失、プログラムの誤動作※)でノートが消える心配があることだ。その代わり、ずっと通信できなくても問題ないので一長一短だろう。

※誤動作に関しては、追記する前にノートのバックアップを作るようにした。

あと、テキストの入力欄が小さくてちょっと不便かも知れないが、使って試してみたい。

(11/12 16:16) その後、ノートをDropboxに送信するようにして、ローカルだけでなくクラウドへの保存も可能にした。まあ、単なる興味からで、オーバースペックであるw

それから、Automagicの入力欄をカスタマイズできないか調べていたら、この夏にAutomagicが提供終了してしまったことを知った。便利に使っていたのに残念だが、仕方ないので代わりを探すことにした。すると、早くもAutomateというのが良さそうな感じだ。外観や機能がAutomagicより整理されているのがいい。もう一個、Taskerというのがあるが、多くの人が使いにくいと言っているので余り使いたくない。

ただ、今度はなるべくこういうツールを使わず実現できる方法を探したい。PCではいろいろ作り込むとしても、スマフォ側はなるべく標準機能だけで実現したい。今回のノート記録は(散々探してなかったので)難しそうだが、もう一つの用途の、画像のPCへの自動転送では、Automagicは基本的にはPCに転送できる(Wi-Fiで通信可能な)ことを通知しているだけなので、できそうな気がする。

 

(23:50 わずかに加筆・修正)

  •  0
  •  1

大大大(数十回繰り返し)大っ嫌いになったのでwww、ThunderbirdからEvolutionに乗り換えようとして、ほぼ完全に(正確には7/8くらいw)できた。この前試した時、カレンダーにいくつか気に入らない点があったのでメールだけ使って実感したのだが、「当たり前の感覚」で使える点でEvolutionのカレンダーの方がずっと筋が良さそうなことに気付いた。※ だから、多少の欠点はなんとかしたいと思った。

※例えば、Evolutionは基本的にプラグイン(またはアドオン)はない(あることはあるが、両手で数えられるくらいしかなく、ないに等しいうえに、ほとんど使ってない)けど、Thunderbirdと違い、それで大きな不満も問題もない。つまり、基本がしっかりしている、「分かってる」のだ。

Evolutionで一番気に入らないというか不便なのは、メールモードでウインドウの右端に縦に出せるTo Do Bar(ThunderbirdのTodayペインを意識していると思われる)が残念にも

  • 現在時刻でスクロールしない。
  • 時刻が小さくて読めない。
    • こちらは、おそらく、前回のようにGTK3のCSS(gtk.css)で変えられると思う。

ために、「今」はリスト中のどこかや今後の予定が分からないことなのだが、それは今までのように、(Evolutionの下にThunderbirdを出し、)Evolutionの脇にThunderbirdのTodayペインを表示することでしのごうと思う。

それ以外の下記の問題は、使い方や我慢でカバーできる。

  • デフォルトの通知はダイアログだけで、音を出さない。出したい時は、予定を作るたびに音のファイルを指定する必要がある。
    • → 基本的に、音はうるさいから要らないと思って居た(だったら、この文句は何だったんだ・・・w)。あと、机上にスマフォがあるので、画面を見ていない時でもそのバイブの音で分かる(可能性が高い)。
  • 色遣いがイマイチな場合・箇所がある。
    • → 一番(かつ、おそらく唯一)イマイチなのはカレンダーのTasksだが、カレンダーの色を薄くしたら、まあまあになった。
      • 色の濃度を交互に変えるのを止めるとか濃度の変化を少なくできればいいのだが、残念ながらできないようだ。
      • これもGTK3のCSS(gtk.css)で変えられればいいが、プログラムで固定かも知れない。

なお、検索したらたまたま出たEvolution関係の掲示板をいくつか見てみたが、(欧米らしくなく?)なかなか頑固でフレンドリーでもオープンマインドでもない(ぶっきらぼう? ホリ○モン的??w)方が多い感じで(GNOMEってそういう文化なのだろうか? いや、UNIX・Linux系は大抵そういう気がする)、要望を出してもサラっと(あるいは、鼻で笑われて)却下されている感じなので、期待できない。それよりは自分で何とかした方が良さそうだ。

それから、次の問題は再発しなくなった。おそらく、Evolutionの前に試したRainlender2がおかしくしていたのだろう。全くひどいソフトだ。

  • 予定の編集後のサーバへの保存に失敗することがある。繰り返すものが駄目な感じ。

そして、Thunderbirdから完全に脱却するために、Todayペイン相当を自作したくなった。やり方は分かった(下に概要を書く)ので作るだけなのだが、やっぱりそれなりに手間が掛かるので、ちょっと保留している(サボり先輩ーーーw)。

Todayペイン代替プログラムの基本機能・動作

  • 直近の予定を一覧表示する。
    • 予定のデータは、Evolutionのキャッシュ(sqlite3)から読める。また、evolution-data-server(EDS)からDbusで取ることもできそうだし、SyncEvolutionというソフトを使えばサーバからも取れる。
      • キャッシュが一番手軽そうだが、問題も起こりやすい。
      • なぜか、キャッシュ中のカラムsummaryなどの日本語の濁点がない(例: 「資源み」)のだが、バグなのだろうか? だとしたら器用だw
        • でも、本物(カラムECacheObj, VEVENT)は正しいので問題ない。
  • 現在時刻に合わせてスクロールする。
  • 予定が追加・更新されたら、それを反映する。
  • 下にTODO一覧も表示したい。
  • 予定やTODOの項目にマウスオーバーすると内容を表示し、ダブルクリックするとその編集画面を出したい。 (後者はすごく難しい)

 

Thunderbird(Mozilla)もEvolutionも独りよがりなのは変わらないのだが、Mozillaは頼んでも居ないことをして(しかも頻繁に!)ユーザーを困らせる点が一番クソ(f*cking)だ。ある時点で気に入って(というか、他になかったから)使っていても、突然大きく(不便に、でも、もともと使いにくいところはそのまま・・・)変えてしまって、ドヤ顔で「今度の最高でしょ? これからももっと良くするよ」って言うような感じだ。まるで劣化版林檎だ。

「そんなんだったら何もしなくていいよ!」と思うが、それ(何もしない)がEvolutionなのだ。いいのか悪いのか・・・。 (まあ、クソじゃないだけいいと思う。)

そんな訳で、同様のことをしているブラウザFirefoxも捨てたい気分なのだが、なかなか代わりが難しい・・・ ChromeかOperaかなぁ。

つくづくMozillaは馬鹿だと思う今日この頃。このままなら長くないね。

 

参考: 森高千里 「これっきりバイバイ」 (1989)

 

PS. こ、これは・・・ 好きだけど、一体どうして??

そして、こっちも強烈だwww

  •  0
  •  1

全く異なる2つのソフト(Tcl/Tk, digiKam7)に関する話だが、どちらも小さいこと(でも、すごく苦労したものもある)なので一つの稿に書く。いずれも、本来はそれぞれのソフトのフォーラムなどに書くべきだが、フォーラムがなかったり(digiKamにはバグ報告の手段はあるが、KDEのBTSなので なんか気軽に書けない雰囲気だった)、ソフトが余りにも古くて(Tcl/Tk)、フォーラムがあるか調べるのも無駄そうだし(→ 現代的なフォーラムはなかった。大昔の「ニュース」(アーカイブ?)だけだった)、連絡しても修正されそうもない気がするので、とりあえずここに書くことにした。

こうして書けば、少なくとも日本(語)の人には検索されるだろうし、今は海外でもキーワードが翻訳されて検索にヒットするようなので、全くの無駄ではないと思う(そもそも、本文に英語のキーワードも書いてあるから、やる気のある人は そこだけ見ればパッと分かりそうだw)。それから、題やカテゴリではLinuxとしているが、実際にはどちらも他のOSでも動く。が、Linux以外で問題が起こるかは不明だ。

(10/4 15:53 その後もう一個対処したので、3として追記する。)

 

1. Tk(wish)のtextウィジェットの高さがおかしくなる。

問題の詳細

一つのtextウィジェット(ワードラップ)にサイズの異なる(タグで指定する)数種類の文字列を入れて表示すると、Tkの認識する高さ(表示行数)と実際が食い違って、高さが低く表示され、文字列の終わりの方が表示されない場合がある。一行が長くて自動改行(wrap)される場合に起こりやすいが、一つのtextウィジェット中に複数のサイズの文字列が存在することが大きいようだ。

以下のような3つの部分からなる内容(各部分を指示しやすくするために、それぞれの頭に番号を付けた)のtextウィジェットを約250pxの幅、ワードラップで表示すると、最後の3の部分(アルバム名)が途中(ラップで改行する手前)で切れる

  1. 北ウイング - 30th anniversary mix
  2. 中森明菜
  3. ベスト・コレクション 〜ラブ・ソングス&ポップ・ソングス〜 (2012)

表示例(左側がおかしい)

原因(推定)

一つのtextウィジェット内で複数のフォントサイズを使い、ワードラップをさせている場合に、Tk内部の表示行数(displaylines)の計算・処理がおかしくなるようだ。

上の例の場合、textウィジェットのdisplaylinesは6(この値は表示されている行数の5より多いので、ある程度はサイズの違う文字列への対応がされているが、完全でないように思える)だが、それを高さ(configure -height)に設定すると不足する(この場合は7でないと完全には表示されない)。

対処

textウィジェットのフォントサイズの異なる部分ごとに高さ(displaylines)を求め、それらの合計を高さに設定する。

上の例では、1(曲名)、2(アーティスト名)、3(アルバム名)の各部分で高さ(部分の先頭から最後の文字までの表示行数: 例: .textWidget count -displaylines 1.0 end)を求めたら、それらの合計は7行(上: 3, 1, 3)となり、正しい高さで表示された。ただ、2の部分は改行を除外しないと1行高くなってしまうので、謎はある。

また、正しい高さで表示されれいる場合でも、全体の高さ(表示行数)を求めると6行のままなので、Tk内部の行数の処理がおかしいようだ。

なお、表示が完全か(目視以外で調べる)は、textウィジェットの外側(親)の高さ(なぜか正しい)とtextウィジェットの高さ(どちらもpx単位)の比較と、textウィジェットのyviewの内容から判定している。

この時、textウィジェットのsyncコマンドでは表示(内部的な処理?)が完全に終わらないようで、取得できる値がおかしいことがあるので、Tcl(Tkでない)のupdateコマンドを実行する必要がある(最初はこれが分からずに苦労した)。

上の例では、textウィジェットはgridウィジェットで配置しているので、外側(親)の高さはgridのtextウィジェットを配置している行(row)のbboxから求められる。また、textウィジェットの高さはyviewから求められる。また、yviewが空だったり、yviewの最初と2番目の要素が0, 1.0でない場合(例: 0.0, 0.8)には表示が完全でない(欠けている)。ただ、2番目の要素(最後に表示されている文字列の割合)はいつも1.0になる訳ではなく、1.0に近い値(例: 0.98)でも「完全」とみなす(許容する)必要がある(あるいは、最下部に広目の空白が入ること許容することで1.0(全く欠けがない)を守れるが、見た目が良くない)。

結果

以下のように、Minispの表示が正常になった。30曲くらい再生して表示を確認しているが、今のところ問題が起こっていない。備考に書いた高さの調整処理も行われていない(最初に設定した高さのままで完全に表示されている)。

備考

簡単に書いたが、何が原因で表示がおかしくなるのか分からず、調査にも対処にもとても苦労し、時間が掛かった。

なお、上記のようにまだ謎があるため、textウィジェットの高さの計算がうまく行かなかった場合に備えて、表示(高さ)を調整する処理も実装した(実はこれを先に作った)。基本的は処理としては、textウィジェットが完全に表示されているかを調べ(上記の方法)、そうでなかったら、完全になるまで1行ずつ高さ(行数)を増やすものである。また、高さが高過ぎた場合には減らす必要があるので、その処理も実装したが、今は使っていない。

この問題は、PCのOSをLinux Mint 20に更新した時に自作のSpotifyのミニプレーヤー(Minisp)で再発した問題である。以前は原因が分かっていなかったので、対処が不充分・不的確だった。

 

2. digiKam7でGoogle mapsの地図が表示されない。

問題の詳細

位置情報のある画像の地図をGoogle mapsで表示しようとすると、地図ペインが空白のまま。また、小さいおかしなウインドウが出て消えない。

なお、地図がMarble Virtual Globeの場合は問題ない。

原因(推定)

digiKam7がルート証明書(libnssckbi.so)がロードできない。digiKam7の想定するディレクトリ構造と実際の位置が異なるためのようだ。

Ubuntu 20系の場合、libnssckbi.soは/usr/lib/x86_64-linux-gnu/nssにあるが、digiKam7は/usr/lib/x86_64-linux-gnuを想定しているようだ。

digiKam7のログに以下のように出るので分かる。

[12345:23456:1234/23456.34567:ERROR:nss_util.cc(748)] After loading Root Certs, loaded==false: libnssckbi.so: cannot open shared object file: No such file or directory
[12345:23456:1234/23456.34567:ERROR:cert_verify_proc_nss.cc(969)] CERT_PKIXVerifyCert for maps.google.com failed err=-8179

対処

ライブラリのパスにlibnssckbi.soのあるディレクトリ(Ubuntu 20系でx86の場合、/usr/lib/x86_64-linux-gnu/nss)を、以下のいずれかで追加する。

  • digiKam7を起動するシェルなどの環境変数LD_LIBRARY_PATHに追加する。
    • 例: export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/nss:$LD_LIBRARY_PATH
  • AppImage中の起動スクリプトAppRun内のLD_LIBRARY_PATHに追加する。
    • 例: export LD_LIBRARY_PATH=$DIR/usr/lib/:/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/nss:$LD_LIBRARY_PATH

念のため、上では/usr/lib/x86_64-linux-gnuも追加した。

AppRunを見るには、AppImageのファイルに--appimage-mountオプションを指定して起動する。 → マウントポイント(/tmp/.mount_digika*)直下にAppImageがある。

修正したAppRunでdigiKamを起動する方法は各自で考えること(一番簡単なのは、AppImageを展開して修正することである)。

なお、消えない小さいウインドウは、地図表示がエラーの時に出るようなので、一旦、地図を表示しないようにしてdigiKam7を再起動すれば出なくなるし、地図が正常に出ていれば出ない。

結果

digiKam7の地図のペインにGoogle mapsの地図が表示されるようになった。

備考

digiKam5の時も同様な問題があり、その時はGoogle mapsのAPIキーが期限切れで出なくなっていたので、今回もそれかと思ったが違っていた。digiKam7は今年の7月に出て、落ち着いてから移行しようと思って居て、もういいかと思ったのだが、まだ早過ぎたようだ。

こういう問題が起こるのは、digiKam7がOSのパッケージでなく、AppImageという(良く分からないけど、)手抜き的なパッケージで配布されているからだ。もちろん、数多くのディストリビューションごとにパッケージなんて作ってられないのは分かるが、始末が良くない話だ。実際、digiKamはAppImageのために日本語入力できないという問題もある(これも、以前自力で解決した)。

その後、PS2の問題(マウスカーソルがおかしい)を調べているうちに、どうもdigiKam 7はまだ駄目な気がして来た。digiKam 7にして良くなったことは特にない(むしろ、悪いことが多い)ので、digiKam 6に戻した。もう少ししたら試してみたい。 (10/2 13:31)

 

3. Spotifyの音量がなぜか下がることがある。

問題の詳細

Xfce4のパネルやJACKを再起動すると、Spotifyの音量が下がる(大体7dB以上下がるので、半分以下になる)。

原因(推定)

パネルのPulseAudioプラグイン(実体はlibpulseaudio-plugin.so)が再起動する時に悪さをするようだ。それを無効にしたら、パネルやJACKを再起動してもSpotifyの音量が下がらなくなったので。

ただ、なぜJACKを再起動するとPulseAudioプラグインが再起動するのかは不明(正確には、この時はPulseAudioプラグインが再起動したかは確認しなかったので、別の経路なのかも知れない)。

対処

PulseAudioプラグインを使うのを止め、同等の機能のアプリ(pavucontrol)を使うことにした。僕はJACKを使っているからPulseAudioの調整はほとんどしないので、アプリで充分だ。

結果

パネルやJACK(、もちろんpavucontrolも)を再起動してもSpotifyの音量が下がらなくなった。

備考

どうも、Mint 20のXfce4にはいろいろバグが多い感じだ。digiKamの外に こっちも早まった感じ・・・

余計かつまともに動かないものは入れておきたくないので、PulseAudioプラグインなど(下記)を削除(アンインストール)した(PulseAudioプラグイン以外は動くが余計)。

xfce4-pulseaudio-plugin xfce4-xapp-status-plugin xfce4-eyes-plugin xfce4-verve-plugin

(10/4 15:53 追記)

 

PS. 書いたあとで気付いたが、BTSとかTkとか、偶然だけど音楽の意味もあって なかなかおもしろいw

PS2. digiKam7にはもう一つ気に入らないことがある。マウスをサムネイルに載せた時のカーソルが酷いのだ。6では普通だったのに、「1980年代ですか?」って感じだ。いつも思うが、KDEの(アプリ以外も)センス(デザイン以外も)は全然好みでない。でも、他にいいアプリがないから使っている。

ちなみに、このカーソルのファイルがどこにあるのか分からず、なかなか直せない。 (10/2 4:58)

気に入らないdigiKam7のマウスカーソル

(10/2 11:19) いろいろ調べたり試したりしてみたのだが、直接的には、digiKam7が使うQt5のアイコン(Qt::PointingHandCursor: 指で指す形状)が見つからないようで、その代替としてX11のcursorフォントの文字hand1(0x3a)が使われているようだ(だから、80年代は当たっていたw)。

どうも、digiKam7のAppImageとOS(Linux Mint 20)の折り合い・相性が悪い感じだ。ただ、digiKam6では同じ環境で問題なくそのカーソル(実は、このカーソルもそんなにいいとは思わないが)が出るので、(本文に書いた)Google mapが出ない問題と同様にdigiKam7側に何か問題があるように思う。それが何かはまだ分からない。

いずれにしても、ちょっと早まってしまったようだ。。。

  •  0
  •  0

iPhoneで定期撮影できるカメラアプリは、どういう訳か無料ではなかなかいいものがない。あっても大抵はタイムラプス動画用で、それ以外はかなり古いものが多い。標準カメラアプリのタイムラプスなんて謎仕様もいいところで、定期撮影には全く使えない。

また、iOSにはAndroidのAutomagicのようなまともなオートメーションアプリがない。いくつかのオートメーションアプリを検討したが、今はないか今一つだった。

  • Workflowは良さそうだったが、Appleに吸収されてiOS 13の「ショートカット」アプリ(以下、ショートカット: それにしても混乱させるひどい名前だ・・・: 英語版では"Shortcuts"(アプリ名)と"a shortcut"(ショートカット)と、どうにか区別できていたのだろう)になってしまったようだ。
  • 有名なIFTTTは、僕が詳しくないせいか、作れる処理が余りにも単純で(条件 → 処理(1個)の実行だけ?? しかも、処理はネットサービスだけ??)、この作業には使えなさそうだった。

それで、iOS 13に更新してショートカットを使うことにした。が、ショートカットの出来のひどさ(今気付いたが、これは元のWorkflowに由来していそうだ。他に、iOSの不自由さにもよるのだろう)に苦労し、イライラした。

やりたいのは、以下の処理である。

  1. バックグラウンドで動き
  2. 一定時間(例: 30分)ごとに撮影し、
  3. 画像をPCに転送する。

ショートカットとそのオートメーションでは、上のどれも容易にはできなかった。

まず、ショートカットやオートメーションはバックグラウンドで動かない。詳しくは試していないが、それらの画面が表示されていないと実行が停まってしまうようだった。更に、画面をロックしたら、オートメーションが自動実行する時にコード入力画面になってしまう。

→ そのため、画面を自動ロックしないように設定し、ショートカットの画面を隠さないように注意して使うことにした。画面を自動ロックしないということは、アイドル状態でも画面が暗くならないから焼き付きが心配なので、画面の輝度を最低(0)にするようにした。まあ、こんなに使いにくいiPhoneなんて滅多に使わないから、焼き付いたっていいけど、気分が悪いので一応配慮する。

その後、画面は液晶なので、いくらバックライトを暗くしても焼き付くかどうかには関係ないと思われるので、画面の輝度を最低にするのは余り意味がなさそうなことが分かった。まあ、バックライトの寿命を伸ばすとか寝ている時の眩しさを減らす意味はありそうだ。 (7/25 4:38)

次に、一定時間ごとに処理を実行できない。あるのは、指定時刻に起動するトリガ(1個しか指定できない)だけで、しかも、それは自動的には実行できない(指定した時刻には、起動するための通知・確認が出る)という素晴らしさ。。。(→ 参照) 「オートメーション」の機能にも関わらず、自動で起動しないって「アホですか?」と言いたい(海外の掲示板でも嘆かれていた)。

→ そのため、スクリプティングの繰り返し機能を使って、撮影間隔の時間分(30分)待つようにした。なお、撮影・処理や転送に意外に時間が掛かるようで、毎回30分待つと撮影時刻が段々遅れるので、1回の処理時間(約25秒)分短く待つようにした。

本来は、処理開始時刻を保存し、処理が終わってから少し(例: 10秒)待ち、その時の時刻から経過時間を計算するのを繰り返して確実に30分待つべきで、そうしたかったが、ループから脱出する方法がないなど、余りにも使いくく・分かりにくくてくじけ、安直な方法にした。そのため、今度は早目に撮影されることも起こるようになった。。。

→ やっぱり、決め打ちの待ちをすることや撮影時刻がずれるのは気に入らないので、上記の処理をどうにか実装した(下のショートカット「1日分の撮影」中の[撮影間隔(30分)を空ける]の部分)。 (ループから脱出の代替手段の参考)

→ 更に調べた結果、今までは定数しか指定できないと思って居た待ち時間に、変数を指定する方法が分かり※、上記のループは不要になった。これができたおかげで撮影間隔の精度がかなり上がった。

※待ち時間の数値を長押しするとオプションが出る(繰り返しの回数も同様; 参照)。分かりにくいことこの上ない。数字すら直接入れられず、▲▼のボタンでしか値が変えられないフィールドに変数が指定できると思えたり、そこを長押しするとオプションが出るなんてことを思い付く人は、まさに超能力者だ。普通はオプションは「歯車」じゃないかなあ、あるいは、その部品の地の部分を長押しでもいいけど、フィールド長押しは掟破りだ・・・

また、制限は多いものの、確認なしでオートメーションを実行できる方法(裏ワザ?)を見付けた。それは、「おやすみモード」をトリガにするもので、一日1-2回なら、固定時刻に自動的に起動できる。例えば、トリガをおやすみモードがonになった時にすれば、毎日1回、おやすみモードの開始時刻に自動実行できる。

まあ、普通に使う方だと、昼夜関係ない時におやすみモードになるのは困るだろうから、余り汎用性はなさそうだ。

最初はそうしていた(1日分の撮影をおやすみモードで毎日開始するようにした)。が、良く考えると不便(一旦停めたら、起動時刻を調整しないと翌日まで開始しない)で馬鹿らしいので、1年分の撮影をするショートカット(1日分の撮影を約365回繰り返す)を作って、それを手で起動するようにした。スクリプティングでは無限に繰り返すことができないので、とりあえず1年にしたが、さすがに1年間も停めずに撮影することはないので、これで充分だ。

ショートカットやオートメーションがバックグラウンドで動かないのや、多くのオートメーションが自動で起動しないのも、Appleがセキュリティにうるさいからだと思う。元々Workflowは社外のアプリだったので できなかったのだろうし、Appleに吸収されてショートカットになっても、まだそういう改良はしていない(する予定もない??)のだろう。ガチガチで不便この上ない。

画像を(自分の)PCに転送するのは、いろいろ頑張ればできそうだが、ここまでで呆れ果てたので、安直にDropboxに送るようにした。その機能はあったので助かった。

最初は画像をメールで送ろうとしたのだが、なぜか、画像が添付されずに空のメールしか送れなかったので、Dropboxにした。結果的に、メールより手軽でいい。

他の問題は、カメラで撮影する時にシャッター音が出てうるさいことがある。

→ 撮影に無音カメラアプリを使えばいいのかも知れないが、できるか不明だったので※、とりあえずテープでスピーカーを塞いだ(イヤフォンジャックにプラグを挿しても効かないようだ)。ただ、まだ音は聞こえて、時々ちょっと驚いたり、盗撮されているような気分になるw

※別のカメラアプリは ショートカットからは起動しかできず、撮影できないので使えなかった。まったく不便だ・・・ あと、iPhoneのスピーカーは下と上(耳に当てる部分)にあるということを知って、愕然とした。美しさ()を自慢するiPhoneが そんなんでいいのかよぉ。そういう訳で、シャッター音を小さくするには両方を塞ぐ必要があるそうだ。 (7/25 12:43)

 

結局、以下のような処理(ショートカットのプログラム)を作った。

1日分の撮影

  1. [1日分の繰り返し] 以下を48回(24時間/30分= 48回)繰り返す。
    1. 現在の時刻を変数t0に格納する。
    2. 画面の輝度を最低(0)にする。: 手で明るくした場合に備えて。
    3. 背面カメラで撮影する。
    4. 撮影した画像のサイズを小さく(幅: 750画素)する。
    5. それを左に90°(-90°)回転させる。: iPhoneを横に倒しているため(回転方向は左か右かあやふや)。
    6. それをライブラリに保存する。
    7. 最新の画像をDropboxに送る。: 本来は上で保存した画像を指定すべきだが、この処理が外部のショートカットのため、方法が今一つ分からなかった。
    8. [撮影間隔(30分)を空ける]
      1. 現在の時刻を変数t1に格納する。
      2. t1とt0の差(秒)を求め、変数dtに格納する。
      3. (1800-dt)秒待つ。

1か月分の撮影: 余り意味はないが、処理単位を明確にするために作った。

  1. 以下を31回繰り返す。
    1. ショートカット「1日分の撮影」を実行する。

1年分の撮影: これをホーム画面に置き、手軽に定期撮影を開始できるようにする。

  1. 少し(例: 5秒)待つ。: 画面のタッチによる本体の揺れが収まるのを待つため。
  2. 以下を12回繰り返す。
    1. ショートカット「1か月分の撮影」を実行する。

この方式にはいい点が少しだけあって、撮影した画像をDropboxに送るようにしたので、PCを停めていても画像は転送し続けられ、それらはブラウザで見られ、PCがそれらの画像で溢れないことだ。もちろん全部、iOSでなくDropboxのおかげだwww

なお、画像サイズを小さくしているため(1枚100KBくらい)、Dropboxの無料アカウントでもほとんど無限に保存できそうだ。もし不足したら、PCに送って削除すればいい。

 

PS. 撮影には関係ないが、iPhone 6sは なぜかセルフパワーハブからは充電できず(Nexus 4や臭いはセンサはできる)、一晩動いた末に電池が空になり掛けた。仕方ないので、専用のACアダプタを追加した。全く面倒なことが多くて、本当に大っ嫌いだ

 

(7/25 12:57までに さまざまな加筆・修正)

  •  1
  •  0

前回、「(センサの値を)自動測定したくなった」と書いたが、半分くらいできるようになった。とりあえず、定期的にスマフォ(Nexus 4)で においセンサ(JSM-131SC)の画面を自動撮影し、その画像をPCに転送するようにした。通常は1時間に1-2回の測定なので、一日分でも画像は24-48枚にしかならず、自分で画面を読んで、手で測定値をスプレッドシートに入力するのでも苦にならない。

スマフォからセンサを常に同じ画角で撮影できるようにするため、それらを載せるスタンド(段ボール製)と自動撮影・画像転送プログラム(Automagic利用)を作った。

試行錯誤はしたが、丁度良さそうな箱があったので、それをベースにすることにした。ただ、スマフォのカメラは隅にあるため、普通にセンサの正面に載せたのでは画面が撮影できず、横にずらさないといけないのが落とし穴だった。使った箱が細かったので、スマフォを横置きにしてちゃんと写るようにすると、スマフォの重心が箱の外になって落ちてしまう。それで、最初は、スマフォをセンサに対して斜めに置いた画面は傾くが実用にはなるからいいと思ったが、やっぱり気に入らなかった。

次に、センサも斜めに置いてスマフォとセンサが平行になるようにしてみた。それなりに画面はちゃんとするが、斜めだと位置決めが難しく、完全には調整できず、やっぱり満足できなかった。

こういう本末転倒エキセントリックなこと、家電なら昔のS社、車だとH社がよくやって自爆するのかな?w 僕は好きだけどね。

結局、両方とも(普通に)箱に対して直角に置くことにし、そのためにスマフォが落ちないように横に台を追加して、ようやく満足できる画像が撮影できるようになった。ちょっとした欠点は、段ボールが結構弱く、何度もスマフォを抜き差しすると、微妙に撮影角度が変わってしまうことだが、まあ、それほど大きな問題ではない。それから、見栄えが悪いが、いつものことだw

定期撮影するプログラムは、もちろんそういうアプリは いくつかあったのだが、機能や使い勝手が今一つだったり制限があって不便だったので、Automagic(Android用グラフィカル言語)で即席に作った。指定の間隔でカメラで撮影して、90°回転して保存するという、猫でも作れそうなwとても簡単なものだ。

PCへの画像の自動転送は、以前作ってAQUOSで使っているもの(これもAutomagicで作った)がほとんどそのまま使えた。ただ、撮影したら(何分も待たずに)すぐに転送したかったので、指定のディレクトリにファイルが増えたら(= センサを撮影したら)転送するように、開始条件を追加した。

今はACアダプタで電源を供給しているので、どちらのプログラムも特に省電力の考慮は不要なので、作るのは楽だった(とはいえ、調整には結構手間が掛かった)。

自画自賛だけど、使ってみるとなかなか便利だ。何も考えなくても勝手に撮影されるので、写す手間がないし、うっかりしたり寝ている間のデータが抜けなくていい。欲を言えば、今は手で記録している、測定時の室温、湿度、外気温や天候なども同時に記録(撮影)したいが、まあ、すべての要望は満たせない(それに、今は、それらの情報は臭いには関係ないことが分かった)。あと、これだと、読む位置を決め打ち(固定)にすればOCRで測定値の抽出もできそうだが、まあ、測定が目的でないので多分しないだろう。

あと、このセットを自分に対して斜めに置いておけば、臭いなどが気になった時に測定値が(スマフォに隠れずに)見られるのもいい。

それから、作る前は気付かなかったのだが、これだとセンサとスマフォの距離が近いために画面が大きく写るので、サムネイルでも測定値が読めるから、スプレッドシートへの転記が楽でいい。あと、同じく距離が近いから画像の画素数を減らせるので、ファイルサイズが小さくて済む(1280x960画素、約500KB: 以前は約2500x3300画素で2MB前後になっていた)のもいい。

 

なお、臭いに関しては別途書きたいが、エアコンダクトを開けると駄目なようなので閉じ、換気扇を常に回して換気扇からの逆流を防ぐことを考えた。それで今は机の脇の本棚で定点観測している。ただ、エアコンに溜まった臭いを防ぐのが難しい(臭いを出さないようにすると、寒くなる)・・・

 

PS. 定期撮影機能は鳩の監視にも使えるかも知れない。鳩は短時間しか居ないから撮影間隔を短くするので、画像データが大きくなりそうだが、撮影期間を朝だけとかに限定すれば大丈夫か。まあ、鳩の場合は動体検知して動画を撮影した方が良さそうだ(できるか不明だし、既存のアプリがあればそっちが良さそうだ)。それでも、いわゆるタイムラプス動画はできるし、いろいろ使えそうな気がして来た。いずれにしても、設置・調整が一番面倒だ。 (6/21 8:00)

 

(6/22 16:36 Automagicで定期撮影するプログラムの画像を追加)

  •  0
  •  0

まだ「概ね」で いろいろ問題はあるけど、以下のように、僕が欲しかった機能はすべて実現した。

  • 指定した期間内または前回のバックアップ後に更新されたノートを指定ディレクトリにバックアップ(ダウンロードと保存)する。
  • ノートの本体(テキスト)だけでなく、添付された画像など(リソース)もバックアップする。
    • 純正Evernoteアプリの全ノートのエクスポートと違い、ノートごとに分けてバックアップする。また、本体と各リソースも別のファイルにしている。(その方が扱いやすいと考えたため。)
  • ノートの最新版がバックアップ済みの場合は、ダウンロードしない。
  • バックアップしたノートは、webブラウザでプレビュー可能。
    • トップページにはノート一覧(ノートのタイトル、更新日時、ノートブック、GUID)が表示され、タイトルをクリックするとプレビューされる。プレビューは、Web版Evernoteにまあまあ近づけた(というか、見栄えはまったく凝ってない(テキトーにやったらそれなりに見えた)。: 例に挙げたノートも目をひかないw)。

(5/23 20:19) その後、プレビュープログラムを改良し、トップページは「(バックアップした)Evernoteのブラウザ」のようになって来た。以下のような機能を追加したほか、見栄えを少し良くした。やっぱり、PHPだと開発効率が10倍はいい感じだし、やる気も出るw

    • フィルタリング機能: 更新年月、作成年月、バックアップ年月、ノートブック名で表示するノートを絞り込める。また、左の各フィールドに対して正規表現でフィルタリングできる。
    • ソート機能: タイトル、更新日時、作成日時、バックアップ日時、ノートブック名でソートできる。ソートの昇順・降順は、フィールド名を押すことで反転する。ソートに使っているフィールドは太字になり、ソート順は▲(昇順)/▼(降順)で示される。
    • 編集補助機能: トップページまたはプレビューページのノート名横の"Edit"を押すと、web版Evernoteでノートの編集ができる。 (あとから思い付いて追加したので、キャプチャ画像にはない。)

改良したトップページ (ノートブック名でフィルタリングした状態)

これくらいできると、僕には、ノートを探すことなどに関してはweb版Evernoteより使いやすい。Web版Evernoteはマウスの加減で画面がちょろちょろ動くのが鬱陶しいし、ノートが多いと下の方がなかなか出て来なくて(しかも、下を出すと上を出すのが遅い・・・)不便なのだ。技術的には高度だろうけど、本当に使いやすいのかと思う。

構想や調査・準備(・他のこと)に時間が掛かったが、ここまでの実装は5日くらいでできた(または、5日も掛かった)。気付くと寝食が犠牲になっていて、なかなかハードだったw

問題や不満な点や残件はいろいろある。

  • 多くのノートをバックアップしようとすると、Evernote APIのrate limit(レート制限: APIを使い過ぎるとエラーになってしまう)に掛かって、しばらく(例: 30分-1時間)使えなくなる。一旦制限に掛かると、制限期間が終わってもすぐに駄目になることが多く、かなり間隔を空ける必要がありそう。(← プログラムのバグのため、無限にダウンロードしていたせいだった。) → 僕の全ノートのバックアップは時間的に困難かも知れない。 → (5/22 16:02) 調整やデバッグをしたら調子が良くなって、1年分を1時間くらい(レート制限解除の待ち時間を含む。正味の時間はもっと短い)でダウンロードできるようになった。 → (5/22 19:14) 無事、全ノート(2011年から今年まで)がバックアップできた。なお、(多過ぎて)過不足や内容の確認はできない模様w (バックアップのサイズ: 562MB, ノート数: 725)
    • あるアプリを初めて使う場合は、使い始めてから24時間は無制限("Initial Sync Boost")なのだが、当然ながら開発中に終わってしまった。。。
    • 開発用認証キーを取得すると、それで「最初の24時間」が使えて良さそうだが、今は配布が停止中。
      • 開発用キーとAPIのキーは別なので、後者を取得すればいいようだが、ちょっと躊躇している。
    • 他のサービスのように、APIの推奨実行間隔や制限に掛かる条件を明記してくれたり、APIの戻り値にレート制限に掛かりそうな情報(例: 「あとどのくらいで制限になる」)を出してくれるとありがたいのだが、そうではないようだ。その点ではSpotifyはまともだ。
  • そもそも、Evernote APIは無駄に凝っている。複数プログラミング言語対応などを目指したのか、Thriftとかいうのを使っているが、複雑で面倒でどうしようもない。センスが悪い。最高でなくていいので、もっと「普通」の、楽なやり方にすればいいのに。この点でもSpotifyは随分良かった。
  • Evernote APIでは、ノートのリソース(画像など)だけの追加や置き換えができず、そうしたい時には、ノート全体(すべてのリソースを含む)を再びアップロードし直すことになるようで、スマフォでは大きいノートの編集が重くなるのも分かる気がした。通信データ量も増えてしまうから、とてもイマイチな仕様だ。 (5/25 16:40)
  • バックアップ期間の日時指定がUTCなので、今一つ不便。(単に変換をサボっているだけ)
  • 元のプログラム(clinote)の内部構造が大変イマイチで、すごく保守性が悪い。
    • 同じ名前や似た名前のファイルが違うディレクトリに何個もあって、今自分がどれを見ているのか分からなくなる。
    • 関数名や型の名前も同様に同名や似たような名前のものが多く、それらの間で頻繁に行き来するので、何がどこにあるのか把握できない。その割には、かなり細かいこともやっていて、本人が間違えないのが不思議。逆に、大雑把なところも多く、バランスが悪い気がする。
    • 作者は僕とは違う感性のようだ。GMBもちょっと似た雰囲気だった。USの人とは違う気がするので、どちらもヨーロッパの人?
    • することは大体分かったので、いつかはPHPで0から書き直したい! (いつになることやら・・・)
  • GO言語もイマイチ。
    • やっぱり、コンパイラ・静的な言語は不便だ。
      • 例えば、変数が静的なので、配列への要素の追加・削除が普通にできない。昔のCでの苦労を思い出す・・・ そういう処理をしようとして、「あ・・・」と気が重くなって、手抜きをする。
      • 変数の型にも厳格で、実体が同じだってエラーにするからいちいち面倒だ。
    • 変態的かつ不便なだけで、全然メリットが感じられない。
      • ;だの{}だの()を省けるようにしたって、そういうのは本質じゃないから全然良くない。逆に、様式が多いのは戸惑いを生じるから面倒だ。
      • 日時のフォーマットの指定方法なんて、アフォとしか思えない。これがGoogleの乗り?
      • あと、今時ポインタなんて要らないんだよ、クソジジイ!!!
        • ↑ 変数は「参照している間はなくならない」そうで、Cでのスタックとヒープの違いがないとのこと。だから、関数内のローカル変数のアドレスを呼び側に渡しても何も問題ないそうで、すごく気持ち悪い。その点でも、やっぱりポインタやアドレスをなくせば良かったのにと思う。 (5/25 16:40)
      • 重複した機能のライブラリがあって(例: osとioutilのファイルアクセス)、新しい言語なのに既にごちゃついている感じ。
    • この点でも、いつかはPHPで書き直したい!
  • まだリストア(アップロード)機能を作っていないので、本当にリストアできるかが不明(プレビューできているので、おそらく大丈夫とは思うが・・・)。最悪でも、本文とリソースはバックアップできているから何とかなるはず。
    • → (5/25 16:40) とりあえずできた。バックアッププログラムを作る時には気付かなかったのだが、ノートをアップロードする時にはリソースのタイプ(MIME)やハッシュ値(MD5)や、画像の場合にはサイズ(幅・高さ)も要るので、面倒だったがGoのライブラリで認識・生成した。
    • 今回も、Goの変態さに気付いてしまった(上に書いた)。

次に、細かい機能や実装などについてのメモを以下に書く。

  • コマンドライン版のEvernoteクライアントclinoteを改造した本体と、それを呼ぶシェルスクリプト(en_backup.sh)、バックアップしたノートのプレビューを行うCGIプログラム(enb_viewer.php)で構成した。
  • clinoteの改造概要
    • ノート一覧をCSV形式で出せるようにした。CSV形式の他に、元々の形式で出る余計な区切り(線)を出さないようにすることができるようにした。
      • 元々の表示は昔のDOSやPC98のプログラムみたいで、使い勝手も趣味もとても悪い。
    • ノート本体だけでなくリソースもダウンロード・保存できるようにした。保存時にノートを変更せずに、Evernoteからダウンロードしたままの形式(ENML形式)で保存することもできるようにした。
    • ノート情報(タイトル、更新日時、作成日時、ノートブック、GUID)を情報ファイルに記録するようにした。
      • バックアップ時に、これに記録された更新日時とEvernoteから取得した更新日時を比較して、再度のダウンロードや上書きをしないようにしている。
      • プレビュー時も、この情報を使ってタイトルなどを表示している。
    • リソースのファイル名はリソースのハッシュ値(Evernoteが計算してノート本体から参照される値)にしたので、変更が簡単に検出できる(はず)。
      • (5/22 13:25) その後、ノート内の各リソースが更新されたかを調べると、リソース(例: 画像)数の多いノートでAPIの実行数が増えてレート制限が起こりやすくなることが分かった。Evernoteはデータ転送量よりAPIの実行の方が重い(コストが高い)と考えているようだ。それも分かるが、何となく釈然としなかった(僕は転送量を減らそうとして失敗した)。 → 結局、ノートが更新されていたら、各リソースの更新はチェックせず、ノートと一緒に全部ダウンロードするようにした。
        • APIの実行数を最小にするという点では、ノート本体の更新チェックもせず、とにかく全部ダウンロードするのがいいが、さすがにかなり遅くなるので止めた。
    • ノート(本体、リソース、ノート情報ファイル)はノート本体のGUIDの名前を持つディレクトリに保存するようにした。
    • APIレート制限の状態を簡単に知ることができるように、同期状態(GetSyncState)を表示するサブコマンド(sync-state)を追加した。
      • clinoteは、レート制限エラーが起こっても他と同様のエラーにするだけで、制限が解除されるまで待つべき時間(rateLimitDuration)が分からない。
      • 一方、レート制限エラーはさまざまなところ(API呼び出し)で起こり得るので、そのすべてに表示処理を追加することは容易でない。GOの機能でできるのかも知れないが、慣れていないのとプログラムが複雑で、僕には無理だった。
      • そのため、追加したsync-stateサブコマンドではレート制限エラーでの待つべき時間をエラーメッセージに表示するようにした。そして、プログラム実行時にレート制限エラーが起こったあとでsync-stateを実行すれば、そこでもレート制限エラーが起こるはずなので、そのエラーメッセージからレート制限が解除されるまでに待つべき時間を抽出できるようにした。
    • バックアップしたノートのリストア用に、clinoteでノートを新規作成するサブコマンド(note new)にノートのアップロードを行うオプションを追加した。 (5/25 16:40)
      • そのオプションに、アップロードするノートとリソースファイルの格納されたディレクトリを指定する。
      • リソースのアップロード時に、タイプ(MIME)やハッシュ値(MD5)や、画像の場合にはサイズ(幅・高さ)が要るので、リソースファイルから生成するようにした。
      • ノートのタイトルを指定しない場合には、ノートのディレクトリに(バックアップ時に作成された)ノート情報ファイルがあれば、そこに記録されたタイトルが使用される。
      • ただし、既存のノート(同名で存在する可能性がある)と容易に区別できるように、指定しない限り、アップロード専用のノートブックに入れ、タイトルにアップロードしたという識別記号を前置するようにした。
  • バックアップ実行用スクリプト(en_backup.sh)の概要
    • バックアップ対象期間、保存ディレクトリ、APIレート制限時の自動リトライなどが指定可能
      • うまい方法がなかったので、レート制限エラーかどうかとレート制限が解除されるまでの時間は、前述のようにログ(clinoteの出力)から抽出している。
    • 最後にバックアップした日時をファイルに保存しておき、次回以降にバックアップ対象期間を指定しない場合には、前回以降に更新されたノートをバックアップすることが可能。 → crontabに書いておいて、定期的に自動バックアップすることも簡単にできる。
    • バックアップ期間の指定は検索条件(例: "updated:20200501T000000Z -updated:20200520T000000Z")としてclinoteに渡し、Evernote APIで行っている。
  • Webプレビュープログラム(enb_viewer.php)の概要
    • バックアップしたノートをHTMLに変換して表示する。
      • 変換といっても、リソース(画像など)が表示できるようにタグを置換している程度。以下に主な規則を書く。
        • プレビューページの先頭に<!DOCTYPE html><html>を入れる。
        • ENML → HTML簡易変換 (PHPの正規表現(PREG))
          • <!DOCTYPE(\s)en-note\s[^>]+> → 削除
          • <(/)?en-note> → 削除
          • <en-media\s+'<img '
          • hash="([^"]+)"'src="'.$img_dir.'$1"' (注: $img_dirはノートのディレクトリ)
        • Evernote内リンクの変換
          • "https://www.evernote.com/shard/([^/]+/){3}([^/^\?]+)(\?[^"]+)?" + → (そのノートのGUID($2)ををプレビュープログラムに指定して表示させる)
          • evernote:///view/[^/]+/[^/]+/([^/]+)(/[^"]+)? → (そのノートのGUID($1)をプレビュープログラムに指定して表示させる): これはNixnote2独自のものかも知れない。
        • プレビューページの最後に</html>を入れる。
    • まだCSSなどは使用していないので(多分、今後もやらない)、とりあえず見える程度のもの。

最後にその他の情報などを書く。

  • Web版Evernoteでノートを変更してから数分(2-3分)経たないと、APIにその更新が反映されない。
    • ノートをバックアップする時、編集中のものをバックアップするのを防ぐため、更新後少し経ったものを対象にしようと思って居たので、この仕様は偶然にも都合がいい。
  • これを作っていて、今までに試したEverenote互換アプリで、最初の同期が終わらず、全然使い始められないないものがあった理由が分かった。ノートが多過ぎて、最初の同期中にレート制限が掛かり、待ちと制限の繰り返しになっていたのではないか。
    • それならそのように表示すればいいと思うが、なぜかそういうアプリは少ない。出てもすぐに消えてしまったり、意味不明なエラーを出して、今どうなっているのかが分からないものが多い。
  • 想像だが、NixNote2は余計なことをし過ぎていて(どういう訳か、Evernoteの普通のやり方から外れて独自のことをしている感じ。Evernoteのクライアントなのに・・・)、ノートが編集できなくなったり、同期が失敗したり、スマフォで開く時にノートが重くなったり、フォーマットが乱れたり(純正アプリと違うことが多い)するのではないかと思う。 ← 今読み返すと、全く使い物にならない。
  • バックアップしたノートのサイズを比べてみたら、僕のが約560MBに対して、純正アプリのは約900MB(ただし、昔のもの)と約2倍だった※。一方、NixNote2のは約3.2GBと馬鹿のように大きい。その点でも糞アプリだったようだ。 (5/23 6:32)
    • ※僕のは保存するデータが何か欠けているのかも知れない。あるいは、画像などを文字にエンコードせずにそのまま保存しているから小さいのかも知れない。

 

余談

バックアップしたノートのビューアをPHPで作ったら、もう、水を得た魚のようにスラっと気持ち良く作れて、サクッと動いた。いくらでも機能を追加できる気分になれるのは、すごくいいことだ。どっかのモグラや蛇や真珠もどき(駱駝・玉ねぎ)とは全然違うw もちろん、赤い宝石なんてお呼びでないwww (5/22 19:28, 22:14)

 

(5/23 5:48, 6:32 加筆; 8:37 最初の文章が消えていたので復元した。若干加筆。; 5/23 20:19, 21:00 Webプレビュープログラムの機能追加を追記; 5/25 16:40 アップロードを作った件と、Evernote APIとGoのおかしさを追記)

  •  0
  •  1

(身から出た錆?に追われて疲れた話: 僕しか使っていないソフトの話で普遍性がないが、なるべく一般的に書く。)

数日前、PCを再起動した後に、Linux用音楽プレーヤーgmusicbrowser(GMB, 「僕版」)の再生履歴を自作の音楽再生履歴・感想記録システムMlhiのwebで見たら、アルバム画像がおかしいのに気付いた。別のアルバムの画像が表示されていた。実はこれは今年の3月頃にも起こっていて、GMBの曲の番号(ID)が詰められた(昔のBASICのリナンバーみたいなもの)ため、MlhiのDBに登録されたIDとずれて、別の曲のアルバム画像がGMBから取得・表示されることが分かったので、その時はIDを詰める処理をスキップするようにして解決したと思っていた。

僕としては、ユニーク(重複しない)かつ不変であるべきIDを詰める(変える)なんて意図が理解できない※。詰める理由はライブラリ内の曲が削除されたからだと想像しているのだが、IDは整数で、今は少なくとも32ビット(64ビットだって行けるだろう)だから、少なくとも2000万、あるいは4000万曲には割り当てられるから、使い放題だ。だから、曲を削除してもIDを詰める必要は全くない。にも関わらず、なぜそんな危険で無駄なことをするのだろうか。まあ、作者の思想とか気の迷いなのだろう。

※こういうのが、いわゆる「想定外」問題だ。「普通はないよね」って思うことは、実はいくらでもあるのだ。普通なんて幻想だ。そして、全部「想定外」と言えば何でも許される訳ではなく、どこまで想定したかがポイントだ。偉い人たちは、そこが分かってない(、というかうまく逃げているのだろう)。

それから、そういう事態になってもなるべく破綻しないように作るのも、設計・開発者のセンスとか能力だ。

それに、曲の削除にしたって、個人で何千万曲も入れる訳じゃないから多少無効な曲があったって、(今もそうしているように)フラグだけ設定してエントリは削除せず、残しておいてもいい(それが気になるなら、DBの構造をちゃんとすべきなのだ)。

これに似た問題として、マイナンバーの番号不足を想像する。(以前書いたが、)僕の計算では遅かれ早かれ足りなくなると思うのだが、いつかリナンバーするのか、あるいは、また作り直すのか。

のだが、やっぱり再発した。こういう根深い問題は大抵再発して、なかなか直らないと相場が決まっているので、「やっぱり」と思うとともに結構がっかりした。

IDを詰めないようにしたつもりなのに、なぜかまだ詰めるようだ。もちろん、作者は行方不明で聞くことはできず、直してももらえないので、自分で解決するしかない。そして、3月に(いや、それ以前から)思ったが、GMBは超大嫌いなPerlで書かれているうえに、内部構造が妙に凝っていて理解不能なので、根本的に直すことができない。

仕方ないので、MlhiがGMBの曲を指定するのにGMBのIDでなく、別の新しいIDを使うことにした。結構大改造なので、なるべく避けたかった。まあ、そもそも、GMBのIDの仕様を確認もせずに勝手に(ユニークかつ)不変と思い込んで使った僕が悪いので、全く身から出た錆ではあるが、なかなか大変だった。

大改造だけど、なるべく変更を少なくしたかった。そこで、MlhiのDBの構造は変えず、GMBのIDを入れていたプレーヤー固有のトラックIDを格納するフィールド(カラム)に格納する内容を変えることにした。GMBのIDの代わりに、曲の音響的な特徴から生成したID(今までもMlhiのトラックID(メインのキー・ID)として使っていたもので、AcoustIDのfpcalcコマンドで計算している)を格納するようにした。GMBのIDと新しいIDはプリフィクスで識別できるようにして、同じフィールドに混在可能にした。なお、この新しいIDは、当然ながらGMBのDBにも登録し(フィールドを追加した)、GMBのIDがいくら変わっても(その新しいIDで)同じ曲が検索できるようにした。

GMBに曲の固有ID(utid)を追加した("Track ID"の列)。まだ再生していない曲("Today's girl")では空だが、再生すると自動で設定される(「ザ・ベスト」)。"ID"は従来のGMBのID(固有でない)。

また、そのようなDBの中身の変更をバッチ処理(SQL)で行うのは失敗のリスクがあったので※、使いながら自動的に変更するようにした。つまり、GMBでの曲の再生時(Mlhiへの履歴の登録時)に、既存の曲のプレーヤー固有のトラックIDのフィールドに昔のID(GMBのID)が入っていたら、新しいID(曲の特徴から生成したID)に入れ替えるのである。

※実際、MlhiのDBは確認のためにしかツールで開いていなかったのに、いつの間にかDBのエントリが一個空になっていた・・・ 間違って何か押したか、修正中に(あるいはもっと前に?)バグが出たのかは不明だ。 ← バックアップを調べたら、変更版を試している時に誤動作して消えたようだ。

なお、曲の特徴からIDを生成するのは、今まではMlhiに履歴を登録するプログラム(登録プログラム)で行っていたが、そのIDをGMBにも格納するようになったので、GMBで生成して登録プログラムに渡すようにした。

余談だが、PerlからID生成プログラムを実行する時、曲のファイル名に日本語が入っていると文字化けして、どうしても直らなかった。ごく当たり前のことすら普通にできないのでブチ切れそうになったが、仕方ないので、Base64でエンコードしてプログラムに渡すようにした。

もう、とにかくPerlなんて1文字だって見たくない!! 何もかもオカシくぐちゃぐちゃで※、見るだけでイライラが溜まる。Perlだったら断然Pythonの方がいい(でも、僕にはPHPが一番だ)w 良くあんなものでまともなプログラムが書けるものだ。そこには感心する。

※"my"や"our"なんてセンスが悪いし、関数(サブルーチン)の引数は(,)で囲い区切ってってもそうでなくてもいいなんて見難いし、$とか@とか%とか()とか[]とか{}とか=~とか\とか、とにかく記号が多過ぎて(しかも、それらの複合もある)、「いい加減にしろ!」だ。

GMBの場合の処理の流れの概要は、以下のようになる(Spotifyでは曲の固有IDがISRCになっている以外は概ね同様)。

曲の再生開始

GMB

  1. 開始から指定時間(例: 3秒)後に、以下を実行する(すぐにスキップした場合は登録しないようにしたかったため)。
  2. その曲に固有ID(utid)が設定されていなければ、音響的特徴から生成して、GMBの曲DBのutidフィールドに格納する。+
  3. Mlhiに再生開始を通知する(utidを指定)。

Mlhi(履歴登録プログラム)

  1. 指定された曲が以前再生したことのあるか(指定されたutidがトラックIDのエントリがDBに格納されているか)調べ、なければ(初めて再生する曲)そのエントリを作成する。その時、GMBから曲の情報(例: タイトル、アーティスト、アルバム)を取得する(utidで曲を指定する)。
  2. 以前再生したことのある曲の場合、DB内のプレーヤー固有のトラックIDがutidでなかったら、指定されたutidに置換する。+
  3. 再生開始日時をDBに記録する。また、再生回数を+1する。

曲の再生終了

GMB

  • Mlhiに再生終了を通知(utidを指定)する。併せて完奏率も送る。

Mlhi(履歴登録プログラム)

  • 再生終了日時と完奏率をDBに記録(追加)する。完奏率は、それまでの完奏率と合わせる処理をする(履歴表示時に平均の完奏率を求めるため)。

曲の再生履歴の表示

Mlhi(web)

  1. DBから再生履歴を抽出し、GMBの曲の場合には、アルバム画像のファイル名や曲の長さなど(履歴には関係なく自明なため)DBには格納していないが、履歴表示にはあった方がいい追加情報をGMBから取得する(utidで曲を指定する)。
  2. その他の情報(例: コメント、評価)をDBから抽出し、履歴と共に成形して表示する(→ )。

※今回追加した処理は項目の最後に"+"を付けて示した。

 

変更を少なくしようとはしたけれど(実際、処理の流れの本筋は何も変わっていない)、やっぱり結構多くなり、昔作ったのですっかり忘れていたこともあって大変で、4日くらい掛かった(ている)。その間は、例によって、気付くと一日が終わっていたり、食事中にもバグが見付かったりして、全く気が休まらなかった。更に、昔の誤り(しかも、関係ないところにも!)も結構あって、「どんなものでもテキトーに作ってはいかん」と思い知らされた。。。

とは言え、何でもきっちり作っていたら、終わらずに使えなくなってしまう(機会を逃す)ので、そこの見極めが難しい。そこら辺もセンスや能力なのだろう。

そして、動作確認して基本的にはOK(何度も戻って修正した)だったのだが、そもそもの、GMBのIDのリナンバーが起こらず、本当に効果があるのかが確かめられない。曲を削除しても強制終了しても、なぜか起こらない。どうにも挙動不審なプログラムで、そういうのを使い続けるのもどうかとは思うのだが、他にいいものがないので仕方ない(いつかは自分で作り直したいが、無理だろうな)。

問題の現象が再現しないのでは仕方ないので、定期的にGMBのIDのリナンバーが起こったかどうかを検出するように定期実行機能(crontab)に設定しておいて、起こったら改めてアルバム画像を確かめることにした。

 

なお、僕しか使っていないものなので、他の方では直ったどうかも判然としないからキャプチャを載せても意味がないが、以下のように直った(単なる自己満足で載せるw)。

問題修正後のMlhiの再生履歴のアルバム画像

図中の"FCM5:"で始まるのが、曲の特徴から生成したIDである(それをGMBの新しいIDにも使っているので、"GMB:FCM5:-"と略記している)。また、"AIM5:"はアルバムのIDである。

 

PS. 当然ではあるが、曲の特徴から生成するIDは、同じ曲(ファイル)ならいつ何回生成しても同じ値になり(昔生成した値と今回生成した値が同じだった)、まだ重複していないので、ちょっと感心した。

PS2. 誰も気にしてないはと思うが、僕が好きなのは80年代のコイズミまたはkyon2であって、現代のダサい小泉さんではない。この投稿は妙なタイミングになったが、そこのところははっきりさせたいw (5/11 19:28)

 

(5/11 9:10 画像を追加、わずかに加筆・変更; 18:52 処理の流れの概要を追加、その他に加筆)

  •  1
  •  0

[English follows]

先日、「[Linux] マウスホイールの加速ができた! (PoC)」で触れたプログラムの公開の要望を頂き、検討したところ、不足な点や問題はあるものの、いろいろやって遅くなるよりは、とりあえず使って試して頂くほうがいいと考えたので、今私が使っている版をV0.1として公開します。

より多くの方にお試し・使用して頂ければと思い、日英両方で記載します。日本語版を先に("[English follows]"や"[Ja]"の後や"/"の前に)書き、英語版は"[English]"や"[En]"や"/"の後に書きます。

(2020/4/16 8:16) NixNote2などでの動作の改善や、Cコンパイラがない・コンパイルしたくない場合などにxdotoolを使う機能などを追加した、V0.2を公開しました。

[English]

A few days ago, I have been asked to publish my own program "acc-wheel" which accelerates Linux/X11's mouse wheel (it has been introduced in my past article "[Linux] Succeeded in accelerating mouse wheel! (PoC)" (written in Japanese)). Although it is not complete (has some problems and limitations), it is better to publish now and made it evaluated and used than continue working on and being "too late". So, I would like to publish current version of the software as "V0.1".

Because I would like the software to be evaluated or used globally, this article is written in both Japanese and English. Japanese descriptions are first (after "[English follows]" or "[Ja]", or before "/"), and then English ones (after "[English]", "[En]", or "/").

(2020/4/16 8:16) Released V0.2, which improves behavior on some apps. (eg. NixNote2), can use xdotool for envs. without C compiler, or for who don't want to compile, and other improvements.

1. ソフトウェアの説明 / Software description

1.1 概要 / Abstruct

[English follows]

acc-wheelは、X Window System (X11)の動作しているデスクトップLinuxでWindowsやmwillacOSのようなマウスホイールの加速を実現します。これは単にホイールの回転量を常に数倍にする(例: ×2)のではなく、ホイールを回転させる速度に応じて回転量を増やす「真の加速」なので、通常の使用時(= ホイールをゆっくり回す場合)に不都合は起こりません。

また、ドライバなどの特別なプログラムでなく通常のプログラムなので、起動するだけで手軽に使えます。

ただし、実行するユーザーがマウスのイベントデバイスを読み出せるように、あらかじめユーザー情報を設定する必要があります。また、V0.1では、マウスイベントを発生させるためのプログラムのコンパイルが必要です。

[English]

acc-wheel implements mouse wheel acceleration as in Windows or macOS on desktop Linux systems running  X Window System (X11). This is not simply multiplying wheel rotation with fixed number (ie. ×2), but a "true acceleration", which increases the amount of rotation according to the speed of rotating speed of the wheel. So, inconvenience never happens in ordinary usage (ie. when rotating the wheel slowly).

In addition, because this is an ordinary program (not special one like device driver), you can use it very handy - just start it.

Notes: Before using, you have to make your user account to be able to read mouse's event device. And, V0.1 requires compilation of an accompanied C program which generates mouse events.

1.2 動作 / Opeation

[English follows]

acc-wheelの処理概要は以下のとおりです。

  1. マウスのイベントデバイス(例: "/dev/input/by-id/usb-Microsoft_Comfort_Mouse_6000-event-mouse")からイベントを読み出す。
  2. ホイールイベントだった場合、イベントの発生速度(= ホイールの回転速度)を求める。
  3. 速度が高速だった場合、追加のホイールイベントを発生させる(→ ホイールの「加速」になる)。
    • 追加のイベントの量(= 加速の度合い)は以下の3つのモードで選択可能。
      • S (ステップ)モード: イベントの発生速度がとても速い場合、より多くの追加イベントを発生させる。 (デフォルト)
      • L (比例加速)モード: イベントの発生速度に比例した追加イベントを発生させる。
      • LS (遅目の比例加速)モード: Lモードと同様だが、少な目の追加イベントを発生させる。
  4. 1に戻る。

[English]

Overview of acc-wheel's process is as follows:

  1. Read events from mouse's event device (eg. "/dev/input/by-id/usb-Microsoft_Comfort_Mouse_6000-event-mouse").
  2. If the events are from wheel, calculate event generation speed(= wheel rotation speed).
  3. If the speed is fast, generate additional wheel events (→ become "acceleration" of wheel rotation).
    • Amount of added wheel events (= amount of acceleration) can be chosen in the following three modes:
      • S (Step) mode: If the speed is very fast, generate more events.
      • L (Linear) mode: Generate events proportionally to the speed.
      • LS (Slow linear) mode: Like L mode, but generate less events.
  4. Go to 1.

1.3 環境 / Environment

1.3.1 対応・要求環境 / Supported/required environment

  • X11の動作しているLinuxデスクトップ / Desktop Linux running X11.
  • マウスがイベントデバイスになっていること("/dev/input/by-id/usb-マウス名-event-mouse"がある)。 / The mouse is an event device (ie. Mouse's event device exists as "/dev/input/by-id/usb-Mouse-name-event-mouse".)
  • 実行するユーザーがマウスのイベントデバイスを読み出せること。 / The user has a read permission to the mouse event device.

1.3.2 必要なソフトウェア / Required software

  • PHP言語 / PHP language processor
    • 例: Ubuntu系の場合、php-7.3, php7.3-cliパッケージ / Eg.: php-7.3 and php7.3-cli packages for Ubuntu
  • X11の開発パッケージ / X11 dev. package
    • 例: Ubuntu系の場合、libx11-dev / Eg.: libx11-dev for Ubuntu
    • 使用X11ライブラリ / X11 libraries used: libX11, libXtst, libXext
  • [V0.2: なくても可 / V0.2: Not mandatory] Cプログラム(gen-mouse-ev.c)のコンパイルのため、gccまたは他のCコンパイラ。 / gcc or other C compilers (to compile accompanied C program: gen-mouse-ev.c).
  • [V0.2 のみ / V0.2 only] xdotoolコマンド (マウスイベントを発生させるためにgen-mouse-ev.cの代わりに使う場合) / xdotool command (when using it to generate mouse events instead of gen-mouse-ev.c)
    • 例: Ubuntu系の場合、xdotoolパッケージ / Eg.: xdotool package for Ubuntu

1.3.3 開発・確認環境 / Developed and tested env.

Linux Mint 18.3 Xfce

1.3.4 ユーザーによる動作確認済み環境 / Reported working envs. by users

2. デモ動画 / Demo movie

Linux Mint XfceにてFirefoxブラウザでホイールを回転させた比較 / Comparison of rotating the wheel on a Firefox browser running on Linux Mint Xfce.

通常の場合(acc-wheelを起動させず)にホイールを速く回転させた場合 / Rotating the wheel fast in ordinary situation (without running acc-wheel).

 

acc-wheelをSモードで動かし、ホイールを遅く回転させた場合 / Running acc-wheel in S mode, rotating the wheel slowly.

 

acc-wheelをSモードで動かし、ホイールを速く回転させた場合 / Running acc-wheel in S mode, rotating the wheel fast.

 

acc-wheelをSモードで動かし、ホイールをとても速く回転させた場合 / Running acc-wheel in S mode, rotating the wheel very fast.

 

3. ダウンロード / Download

acc-wheel-0.2.1.tar (md5sum: 77aac373e8799d9b9374b4fac035f4d8)

(Old version: acc-wheel-0.1.tar (md5sum: ab8f590f11146b484741a1646bc4c2d8))

Releases also available on GitLab.

4. インストール手順 / Installation

[English follows]

4.1 標準的な手順 (特にUbuntu系の場合)

  1. 実行するユーザーがマウスのイベントデバイスを読めるようにする。 (例: ユーザーIDをマウスイベントデバイスのグループ(例: input)に追加する。)
    1. マウスイベントデバイスのパーミッションを確認する
      • 例: ls -lL /dev/input/by-id/usb-Microsoft_Comfort_Mouse_6000-event-mouse
      • crw-rw---- 1 root input 13, 68 4月 8 08:08 /dev/input/by-id/usb-Microsoft_Comfort_Mouse_6000-event-mouse
    2. デバイスがグループ(例: input)での読み出し可の場合、ユーザーID(例: user)をそのグループに追加する。
      • 例: sudo usermod -G input user
    3. Linux・デスクトップにログインし直す。
  2. acc-wheelの作業用のディレクトリを作るか既存のものに移動する。
    • : cd ~/work
  3. ダウンロード・展開する。 → ディレクトリ "acc-wheel"ができる。
    • :
      • [V0.1] wget -O - https://piulento.net/bsw/acc-wheel/acc-wheel-0.1.tar | tar xf -
      • [V0.2] wget -O - https://piulento.net/bsw/acc-wheel/acc-wheel-0.2.tar | tar xf -
  4. [V0.2では省略可] acc-wheelにchdirし、gen-mouse-ev.cをコンパイルする。 → マウスイベントを生成するプログラムgen-mouse-evができる。
    • : cd acc-wheel && gcc -o gen-mouse-ev gen-mouse-ev.c -lX11 -lXtst -lXext
  5. [V0.2のみ] マウスイベントを発生させるのにxdotoolを使う場合、xdotoolをインストールする。
    • 例: sudo apt-get install xdotool

[English]

4.1 Standard steps (ie. on Ubuntu systems)

  1. Enable your read access to your mouse event device (eg. add your user ID to mouse event device's group (eg. input)).
    1. Check mouse event device's permission.
      • Eg.: ls -lL /dev/input/by-id/usb-Microsoft_Comfort_Mouse_6000-event-mouse
      • crw-rw---- 1 root input 13, 68 4月 8 08:08 /dev/input/by-id/usb-Microsoft_Comfort_Mouse_6000-event-mouse
    2. If the device can be read by group (eg. input), add your id (eg. user) to the group.
      • Eg.: sudo usermod -G input user
    3. Re-login to the Linux/desktop.
  2. Make or choose a work dir. for acc-wheel and chdir to it.
    • Eg.: cd ~/work
  3. Download the archive and extract. → Dir. "acc-wheel" will be made.
    • Eg.:
      • [V0.1] wget -O - https://piulento.net/bsw/acc-wheel/acc-wheel-0.1.tar | tar xf -
      • [V0.2] wget -O - https://piulento.net/bsw/acc-wheel/acc-wheel-0.2.tar | tar xf -
  4. [V0.2: Not mandatory] Chdir to acc-wheel and compile gen-mouse-ev.c. → Program to generate mouse event "gen-mouse-ev" will be made.
    • Eg.: cd acc-wheel && gcc -o gen-mouse-ev gen-mouse-ev.c -lX11 -lXtst -lXext
  5. [V0.2 only] Install xdotool when using it to generate mouse events instead of gen-mouse-ev.
    • Eg.: sudo apt-get install xdotool

4.2 参考: ユーザーから頂いた情報 / Supp.: Information from users

4.2.1 Fedora31 Gnome3でのインストール / Installation on Fedora31 Gnome3 (2020/4/14: 匿名 / anonymous)

  • 以下のパッケージを追加でインストールする。 / Install additional packages as the following steps:
    • sudo dnf install libXtst-devel
    • sudo dnf install php-cli
    • sudo dnf install php-process
  • マウスのナチュラルスクロールの設定はoffにする必要あり。 / Mouse's "natural scrolling" has to be disabled.

5. 使用手順 / Usage

  1. acc-wheel.phpを起動する。 / Run acc-wheel.php.
    • 書式 / Synopsis: php acc-wheel.php [-m S|L|LS] [-d[v]] [-v|-q] [-xdt] [-h] [mouse-event-dev-name] (-xdt, -h: V0.2のみ / V0.2 only)

      • -m: 加速モード / Wheel acceleration mode
        • S: ステップ加速モード (デフォルト) / Step acceleration mode (default)
          • [Ja] ホイールの回転速度がとても速い場合、より多く加速する。
          • [En] If the wheel speed is very fast, acceleration becomes large.
        • L: 比例加速モード / Linear acceleration mode
          • [Ja] ホイールの回転速度に比例した追加イベントを発生させる。
          • [En] Accelerate proportionally to the wheel speed.
        • LS: 遅目の比例加速モード / Slower linear acceleration mode
          • [Ja] Lモードと同様だが、少な目の追加イベントを発生させる。
          • [En] Like L mode, but smaller acceleration.
      • -d, -dv: デバッグモード / Debug mode (-dv: より多くの情報を出力する / more verbose)
      • -v: 冗長モード (デフォルト) / Verbose mode (default)
      • -q: 非冗長モード / Quiet mode
      • [V0.2] -xdt: マウスイベントの発生させるのにgen-mouse-evでなくxdotoolを使う。 / Use xdotool instead of gen-mouse-ev to generate mouse events.
      • [V0.2] -h: 使用法を表示する。 / Show usage.
      • mouse-event-dev-name:
        • [Ja] マウスイベントデバイスのパス (例: /dev/input/by-id/usb-Microsoft_Comfort_Mouse_6000-event-mouse)
          • 指定しない場合、自動でマウスを検索し、最初のものが使用される。
        • [En] Path of mouse event device (Eg.: /dev/input/by-id/usb-Microsoft_Comfort_Mouse_6000-event-mouse)
          • If not specified, system's mice are searched automatically and the first one will be used.
    • 実行例 / Example: php acc-wheel.php < /dev/null>& /dev/null &
  2. マウスホイールを速く回転させると、ウインドウのスクロールが加速されます! / Scroll mouse wheel faster, and the window's scrolling speed will be accelerated!

参考: マウスイベント生成プログラム: gen-mouse-evの使い方 / Supp.: Usage of mouse event generation program: gen-mouse-ev

  • 書式 / Synopsis: gen-mouse-ev [mouse-button-syms...]
    • mouse-button-syms: 生成するマウスボタン記号(番号) / Mouse button symbols (numbers) to generate.
      • 1, 2, 3, ...: ボタン番号 / Button number
        • 4: ホイール上向き / Wheel up, 5: ホイール下向き / Wheel down
      • Sn: n (ms)スリープする / Sleep n (ms).
      • C: XSyncを実行する / Perform XSync.
      • 指定しない場合、マウスボタン記号を標準入力から取得する。 / If not specified, mouse button syms. are obtained from stdin.
        • ボタン記号と改行(\n)を入力して行く。 / Specify one button sym. per line. Each line ends with newline(\n).
        • 空行の場合はXSyncを実行する / When empty line entered, XSync is performed.
  • 実行例 / Example
    • ./gen-mouse-ev 4 C S200 4 :  ホイール上, XSync, スリープ200ms, ホイール上 / Wheel up, XSync, Sleep 200ms, Wheel up
    • echo -e "4\nC\nS200\n4" | ./gen-mouse-ev : 上と同じ(標準入力から読む) / Same as above (button syms. are read from stdin).

6. 調整 / Tweaks

  • 加速特性の調整 / Adjusting acceleration mode/rate.
    • acc-wheel.phpの-mオプションでモードを変える。 / Specify acc. mode with -m option of acc-wheel.php.
      • acc-wheel.phpの変数$wheel_acc_configsに各モードの加速パラメタが定義されている。 / Params. of each mode are defined in $wheel_acc_configs in acc-wheel.php.
  • ブラウザの「スムーススクロール」はoffにしたほうがいい。 / It 's better to disable browser's "smooth scroll".
  • うまく動かない場合、マウスのイベントデバイス(/dev/input/by-id/usb-マウス名-event-mouse)のモードを確認すること。 / If acc-wheel doesn't work, check the permission of mouse event device (/dev/input/by-id/usb-mouse-name-event-mouse).

7. 制限事項・既知の問題 / Limitations and known problems

  • 対応するマウスは1個だけ。 / Only one mouse is supported.
  • 加速されたホイールイベントが少し遅れて出ることがあり、思わぬ結果になることがある。 / Sometimes, generation of accelerated wheel events are delayed and unexpected behavior may occur.
  • アプリケーションによっては(例: NixNote2)、今ひとつ正常に動作しない。 / Some applications (eg. NixNote2) doesn't handle accelerated wheel events well. → V0.2で改善した。 / Improved on V0.2.
    • [Ja] [NixNote2, digiKam6] ホイールを速く回した時のスクロール量がおかしい(スクロールしない、変なところにジャンプする、もたつく)。
    • [En] [NixNote2, digiKam6] When wheel speed is very fast, scrolling amount is not right (eg. doesn't scroll, jump to unexpected loc., or scroll amount is very small).
  • [V0.2] [xdotoolを使用する場合: -xdt] 追加ホイールイベントを発生させるたびにxdotoolを起動するので効率が悪い(例: 負荷が少し重くなる)。 / [When using xdotool: -xdt] Because xdotool is invoked every time when generating additional wheel events, the process is not so efficient (eg. CPU load will be a little bit heavy).
    • xdotoolに標準入力からコマンドを指定しても動作しないため。 / Because xdotool does not seems to execute commands read from stdin.

8. TODOs

  • 不具合修正 / Fix problems.
  • 加速パラメタの調整を容易にする。 / Make adjustment of acc. param. easy.
  • その他のさまざまな改良。。。 / And other various improvements...
  • インストーラーやMakefileを作る。 / Make an installer (and Makefile).
  • ☑ GitHubやGitLabなどで公開する。 / Publish on GitHub or GitLab. → 試しにGitLabで公開した。 / Experimentally published on GitLab.

9. ライセンス / License

[English follows]

このソフトウェアはMITライセンスで公開します。正式なドキュメントができるまでは、この投稿も本ソフトウェアの一部とします。

[English]

This software is published under the MIT license. Until formal documents are available, this article should be treated as part of the software.

ライセンス文書 / License text

Copyright 2018-2020 Butty PiuLento

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

10. サポート / Support

[English follows]

ご感想やインストールや使用上の問題などは、この投稿にコメントして下さい。可能な範囲で対応します。

[English]

Any comments would be appreciated, and if you have any trouble in installing and using acc-wheel, please comment to this post. I will support as possible.

11. 謝辞 / Acknowledgement

[English follows]

gen-mouse-ev.cで実行している、XTestでマウスホイールイベントを発生させるアイデアはBharathi Subramanianの"X11 Fake Mouse Events Generation using XTest Extension" (2010)より得ました。

[English]

Idea of issuing mouse wheel events using XTest (performed in gen-mouse-ev.c) was obtained from Bharathi Subramanian's "X11 Fake Mouse Events Generation using XTest Extension" (2010).

 

Mod. history (English only)

2020/4/14 9:40: 11. 謝辞 / Acknowledgement: Corrected "gen-mouse-ev.c" was old name ("send-mouse-ev.c").

2020/4/14 10:03: 1.3.4 ユーザーによる動作確認済み環境 / Reported working envs. by users, 4.2 参考: ユーザーから頂いた情報 / Supp.: Information from users: Added info. of Fedora31 Gnome3 from anonymous user.

2020/4/14 12:13: 5. 使用手順 / Usage: Added gen-mouse-ev's usage as supp.

2020/4/14 17:25: Experimentally published on GitLab.

2020/4/15 13:55: 1.3.2 必要なソフトウェア / Required software: Added php7.3-cli.

2020/4/15 14:21: 3. ダウンロード / Download: Added releases on GitLab.

2020/4/15 20:47: 制限事項・既知の問題 / Limitations and known problems: Added digiKam6 to incompat. apps. Fixed NixNote2's name.

2020/4/16 8:16: Released V0.2 and added the info. Deleted "V0.1" from the title.

2020/4/19 16:29: 3. ダウンロード / Download: Updated to V0.2.1

  •  0
  •  3

(今日も小ネタを)

なぜか ちゃんとしたスクリプトを作る気が起こらず、いつもコマンドの履歴やEvernoteのメモからコピペする処理がある。カップ麺などで3分間待つ時のタイマーだ。

もちろん、スマフォの時計アプリでできるのだが、使うとなぜか電池使用率が増えるので、使わないようにしている。ただ、それが原因かどうかは未確定だ。

あと、Linuxデスクトップにも適当なアプリがありそうだが、ちょっと探していいのがなかったので、面倒だから作った。

以下である(3分間の場合)。メッセージの英語はテキトーなので、イマイチかも。あと、処理もテキトーです。ノークレーム・ノーリターンでお願いしますw

tend=`expr 3 \* 60`; t0=`date +%s`; while true; do date; t=`date +%s`; dt=`expr $t - $t0`; rest=`expr $tend - $dt`; echo "Elapsed $dt sec (rest=$rest sec)."; if [ $dt -ge $tend ]; then zenity --info --text='REACHED TIME!!!'; break; fi; sleep 10; done

以下のように、経過時間を10秒ごとに表示し、時間が来るとダイアログ(zenityを利用)で通知が出る。

2020年 3月 7日 土曜日 11:26:06 JST
Elapsed 0 sec (rest=300 sec).

待つ時間を変えるには、冒頭の変数tend(秒単位の待ち時間)を適宜調整すればいい。

なぜ ちゃんとしたスクリプトを作らないかというと、スクリプトにするといろいろ機能を追加したくなって(例: 待ち時間をGUIで設定、時間が来たら音を出す)、それが面倒だからだと思う。あと、これを使う時はお腹が空いているので、スクリプトなんて作る暇はなく(「えーと、あれどこだ」的に探す)、食べたら満足して忘れてしまうこともありそうだw

 

PS. 今、レトルトカレーを温めるのにこれを探したので、ついでに投稿したw (インスタント食品が好きそうだけど、実は料理が得意そうな)サボり先輩に捧ぐ(爆)

  •  0
  •  0

ここ数日、「例のトリッキーなやつ」(先日の投稿の、Spotifyアプリのログから音量正規化のための値(RG値)を抽出して正規化する方法)が諦めきれず、悪戦苦闘していた。何度も諦めたのだが、そのたびにアイデアが出て来てしまって再挑戦する羽目になり、今日は随分いい感じになったのたが、やっぱり駄目だった。

記念(または証拠)に、最良の状態での動作光景を載せる。画面左上はRG値取得用Spotifyアプリ、右上はミュート(上側)・ゲイン調整+リミッター(下側)用アンプ、左下はミニプレーヤー、中央から右下は再生用Spotifyアプリである。曲間でのアンプの設定の変化や、プレーヤーの切り替わり(アプリ下部の緑の帯)に着目されたい(もちろん、手で操作している訳ではないし、マウスなどを自動操作するツールを使っている訳でもない)。

Spotifyアプリから音量正規化のための値を抽出して音量正規化している画面

動作の流れは以下である。

  1. Spotifyアプリ(音量正規化: off)が再生を開始する(またはトラックが変わる)のを待つ。
  2. アンプでSpotifyアプリの出力をミュートする。
  3. プレーヤーをRG値取得用Spotifyアプリ(音量正規化: on)に切り替える。
  4. その曲のRG値が取得できるまで(再生して)待つ。
  5. アンプにRG値を元に計算したゲイン(増幅量)を設定する。
  6. プレーヤーを再生用Spotifyアプリに切り替える。
  7. 曲の先頭に戻る。
  8. アンプのミュートを解除する。
  9. 再生を開始する。

基本動作はできた※のだが、試しに少し(15分くらい)動かしていたら、RG値取得用アプリとSpotifyサーバの通信ができなくなってRG値が取れなくなってしまった。再生用アプリの動作は問題ないので、短時間(RG値取得用アプリに切り替わっている時間は約2秒)で切り替えるとうまく動かなくなってしまうのかも知れない。まあ、再生し始めたと思ったらすぐに切り替えるなんておかしな使い方を想定していないのはもっともだから、仕方ない。

※本方式での音量正規化処理自体は、全く問題なかった。性能(音量の揃い具合)はSpotifyアプリよりも良かった(とはいえ、大差ではない)。また、前回(「と思いきや」のあと)失敗した、プレビュー版のRG値とは異なる場合が多かったので、そちらには得体の知れない値が入っているようだ。

あと、不思議なことに、投稿用に動画を撮り直そうとして再度動かしてみたら、プレーヤー切り替えのタイミングがずれて※、曲間で余計な音(RG値取得中または曲の先頭に戻る前の音)が出るようになってしまった(上の動画はボツのテイクを投稿用に少し編集している。でも、ちゃんと動いていたのは確かで、夢や幻や捏造ではないw)。だから、SpotifyのアプリもWeb APIも、こういうタイムクリティカルな用途には無理があるようだ。

※アプリの切り替え時間(= RG値の取得・処理時間= 曲間)は最初は4秒くらいだったのだが、それでは遅過ぎるので(結構苦労して)高速化・最適化したら不安定になったようだ。元の遅い版ならもう少し安定なのだろうが、それでは気分が悪いw それどころか、最初は1秒以内にしたいくらいだった。

そもそも、(前回も書いたが、)これをやりたかった理由の一つはダイナミックレンジをなるべく減らしたくないことだが、再度計算してみたら、Spotifyの音量正規化のQuietモード(基準音量: -23LUFS)を使っても2ビットも落ちないことが分かった※ので、ポップ音楽でそこまでこだわる意味は全くないから無理する必要はない。

※先日の試算では、音量を-23LUFSにするのに23dB下げると考えたが、それは誤りで、SpotifyがRG値の計算に用いているReplayGainの基準音量は-14LUFSなので、(-14-(-23)=)9dB下げる程度であり、それは(9/6=)約1.5ビット相当である。

あと、RG値取得用アプリが駄目になる問題は、例えば、通信できなくなったらしばらく(数分?)待ってアプリを再起動すれば回復できるだろうが、たとえ自動的にするとしても、再起動されるまでは聴けなくなって気分が良くないし、音量正規化のon/off切り替え時にアプリを再起動したくないからこの方法にしようとしたのに、(再生用ではないけど)やっぱり再起動が要るのでは馬鹿らしい。それに、上に書いたように、タイミングが変動して安定して動かないのでは、とても実用にはならない。

そんな訳で、結果的には無駄なことをして疲れたが、いろいろ(細かい)発見があっておもしろかったせいか、余りがっかりはしていない。むしろ、事前の予想どおり駄目だったものの、基本的には目論見どおりに動作して満足したし、方が付いてせいせいしたw

 

最後に、開発中に分かったことなどを少し書く。

  • Spotifyアプリを外部から制御するにはWeb APIとDbusの2種類でできるが、プレーヤーを切り替えて使う場合はWeb APIだけを使った方がいい。Dbusで操作すると、どのプレーヤーが対象か分からなくなったり、意図したプレーヤーが操作されなかったり、プレーヤーの切り替えがうまくいかない場合がある。
    • Web APIはかなり遅い(数百ms/回)のでDbus(数十ms/回)で高速化したかったのだが、残念ながら駄目だった。
  • SpotifyのWeb APIを短時間に頻繁に使うとサーバがエラーを返すようだ(本文に書いたエラーもこれと同様)。HTTP 500なのでアクセス制限(rate limit)ではないようだが・・・
  • 更に、頻繁に使わなくても謎の動作をする場合がある。Dbusを使わなくてもおかしくなることがあるようだ。
  • 曲の開始直後に先頭にシークすると前の曲にジャンプしてしまうようで、少し待たないといけないようだ。
  • Linuxのサウンド系には謎の損失(音量低下)があるようで、どこかで4dBくらい音量が下がる。PulseAudio(実際にはALSA)からJACKに入るところか、JACKからサウンドカード(実際にはALSA)に出るところかと想像している。
    • ポップ音楽用の音量正規化の場合、目標の音量をReplayGainと同じ-14LUFSにしたので、理論上はアンプのゲインをRG値そのものにすれば良いはずなのだが、この損失を戻すためのゲイン(4.5dB)を加算した。
    • なお、クラシック音楽用ではその損失を加味して、4dB下げるだけで目標の音量(-23LUFS)になった。
  • (書いても誰も分からない気がするが、)本方式の制御プログラムでは、2つのイベント入力(SpotifyアプリのログとDbusのイベント)を混ぜて受信することで、両方ともタイムアウトなしの受信にすることができ、イベントに対するレスポンス時間の短縮と負荷の軽減ができた。でも、本文に書いたように、高速化したら逆効果だったようだw

 

PS. それにしても、昨日(12/29)までは年末という気がしなかったのだが、今日(12/30)になったら急に「今年ももう終わりか」モードになって、妙に慌ただしい気分になってしまった。そして、「年末なのにプログラミングなんてしている場合かっ?」て気もしたが、特に他にすることもないので問題ないw

  •  0
  •  0

Spotifyの音量正規化の改良では散々試行錯誤したが、ようやく自分が納得できるかたちで実現できた。もちろん、結果(性能)も全く問題なかった。音量(Integrated loudness)の値は全く問題なかったし、随分聴いてみたが、(自作とは全然違って、)我慢できないほどうるさい曲(演奏)※も小さ過ぎるものもなく、随分手を焼いていた曲もあっさり大丈夫だった。これなら気楽に聴いていられそうで、ようやく目的が達成できた感じだ。

※正確には、「うるさい」と感じる演奏はある。が、その音量値は全く異常でなかった。ということは、音作り(周波数分布や音質の悪さ? いわゆる「海苔波形」?)によるのか、僕との相性が悪い(音の好みや聴覚のラウドネス特性とのズレ?)のだと思う。実際、不思議なことに、アンプの音量を小さくしていても、いつもうるさく感じる演奏はやっぱりうるさく感じる。つまり、「うるさい」は音量が大きいだけではないということだ。まあ、語義からしても当たり前か。

以下に試行錯誤の経過や内容を書く。

前回の投稿ではSpotifyの音量正規化のNormalとQuietを手で切り替えて使うと書いた。そして、前回も書いたが、音量を揃える(増やす)ために増幅してもそれほど音質が劣化しないことが分かったので、その方法を詳しく検討した。基本的には、単に(ソフトの)アンプで増幅すればいいのだが、使う要素(アンプの種類)や増幅する量を最適にしようとしたのだ。

まず、以下を試した。増幅量は+11dB(-23LUFSを-12LUFSにしようとした)にした。

  • JACKのjack_mixerのボリューム:音は悪くない感じがした。 → その後、長時間聴いたら耳閉感が起こった。
  • PulseAudioのボリューム (Spotifyのsink-input):音が悪い感じがした。わずかに耳閉感が出た。

PulseAudioでの増幅で音質劣化がありそうだったので、何種類かの増幅量で歪率を測定したが、オーバーフロー(0dBを超える)しなければ(+15dBくらいまで)は問題なさそうだった。それで、実際の曲で試したら、ポップ音楽でも意外にダイナミックレンジが広いようで、+9dBでも簡単にオーバーフローした。

それで、リミッターでオーバーフローしないようにすることにした。PulseAudioで増幅してオーバーフローすると、その時点で歪んでしまうので、あとにリミッターを入れても無意味なので、JACKのアンプ+リミッターの構成にすることにした。リミッターにもいくつかの種類があり、以下でオーバーフローさせて試したが、いいものは少なく、結局、Fast Lookahead limiterを使うことにした。これには入力にゲインがあって、それがアンプの役割をするので丁度良かった。

  • Fast Lookahead limiter: 一番いい感じ。過大入力でも、自然な音で0dBを超えないように制限される。
  • Wave Shaper (Sine-Based): 過大入力(例: +17dB)で音が変わる(歪む)。
  • Simple Limiter (Peak Env. Track.): 過大入力(例: +17dB)で「ワウワウ」になる。
  • Calf Sound GearのCalf Stereo Tools: 最初は良かったが、長く聴いたら耳閉感が起こった。
    • 後述のNon Mixerにした時に、バイパス機能とSoftClip(リミッター)があるので試した。

それから、Spotifyの音だけを増幅したいので、SpotifyのJACKへの出力を独立にし、更に、ポップ音楽用とクラシック音楽用で増幅をon/offする必要がある。

その前に、いつも評価用に使っている曲をSpotifyの正規化(Quiet)+増幅(+9dB)で試したところ、殆どのポップ音楽は問題なかったが、"Speak to me"は駄目で、Normalと同様な不自然さがあった。原因を調べたら、前回の投稿の付録に詳しく書いたが、オーバーフローがリミッターでカットされる時間が長いためだと分かった。それで、増幅量を+6dBに減らし、リミッターの回復時間を長く(2秒)にすることで不自然さを緩和した。回復時間を"Speak to me"の鼓動の周期より長くすれば、ずっと音量が下がったままになるので、不自然さが緩和されるのだろう。完璧ではないが、"Speak to me"のような曲は例外的だから許容できると考えた。ただ、他の曲が不自然になるかも知れないので、その時に調整したい(今のところは問題ない)。

結局、以下の3つのモードを作ることにした。

ポップ向けでの増幅量について: 通常のReplayGainで正規化する(あるいは、0dBまで目一杯出す)他のプレーヤー(具体的にはgmusicbrowser, GMB)と音量を揃えるにはなるべく上げる方がいいが、前述したオーバーフローによる劣化も嫌なので、試行錯誤(勘?w)で決めた。+7dBだと、SpotifyのQuietモードでの基準音量 -23LUFSを-16LUFSまで上げることが期待できる(当初は+10dBして-13LUFSくらいにしたかったが、やり過ぎのようだ)。

3つのモードはミニプレーヤーのボタン(右端の"Sp", "S", "-")で切り替える。音量正規化の有無はSpotifyを再起動すればいいが(とはいえ、重いから避けたかったが、それ以外に方法がないので仕方ない)、JACKのアンプで外部から制御できるものがなかった(後述するように、実はそうではないが、当時はそう思っていた)ので、増幅の有無の切り替えが困難だった。それで、接続(配線)を変えることにした。簡単に書くと、以下のように切り替える。

  • 増幅あり: Spotify → アンプ → ミキサー → 補正用イコライザ → 出力
  • 増幅なし: Spotify → ミキサー → 補正用イコライザ → 出力

なお、なるべくSpotifyを再起動しないで済むように、右クリックで音量正規化モードの切り替えを逆順にできるようにしたのだが、順番を覚えていないためにやっぱり再起動になる羽目になるので、マウスオーバーでガイドを出すようにした。

なお、プログラム(xdotool)でリミッター(アンプも兼ねる)のEnableボタン(中央付近)を押すことでも、増幅の有無の切り替えが可能なので試してみたのだが、勝手にマウスが動くと(その後自動で元に戻しても)結構ストレスに感じるし、その時の操作状態によっては誤動作・操作することもあるので止めた。

その後、モード切替のたびに接続(配線)を変えるのは全然スマートでないし、遅いし、JACKサーバへの負荷が重そう(頻繁に繰り返すとおかしくなりそうな気がした)なので、避けられないか考えた。それで、以下の2種類を順に試した。

  1. OSC(Open Sound Control)という仕組みで外部プログラムから制御可能な、Non Mixer(エフェクタも入れられるミキサー)を使い、リミッターの増幅量を変える。
    • Non Mixerはエフェクタのon/off(Bypass)を外部プログラムから制御できないので、増幅なしの場合にはリミッターの増幅量を0dBにすることで、offの状態にした。
    • この方法には実用上は何も問題がなく、充分良かったのだが、微妙に気に入らないために別の方法を探して、次の項のjack-rackになった。例えば、以下が気に入らなかった。まあ、車で言えばトヨタのように、「ソリが合わない」ってやつだろうかw まあ、jack-rackが駄目なら戻ればいい。
      • 外部からBypassが制御できない。ゲインでもできるけど、何か直接的でない。
      • 大げさ: ウインドウが無駄に大きいけど小さくできない(確か、一番幅を狭くした状態がこれ)。
      • 名前が悪い(結構真面目に良くない)。「おフランス」なのだろうか?
  2. MIDIでjack-rack(エフェクタを入れるソフト)を外部プログラムから制御し、リミッターのon/offを切り替える。
    • 試行錯誤の結果(以前試した記録が役に立った)、MIDIを使う方法が分かり、どうにかjack-rackも制御できるようになったので、リミッターのon/offが外部から制御できるようになった(のEnableボタンを押すのと同じ効果)。
      • ただし、ちょっとしたバグがあり、jack-rackの起動後にMIDI設定のダイアログが出てしまうが、仕方ない(これを自動で閉じるようにしたら動作がおかしくなってしまったので、手で閉じることにしている)。
      • ↑面倒だし目障りなので、xdotoolで"OK"ボタンを押すようにして自動で閉じるようにした。ただ、ウインドウサイズが変わると予期せぬ事態が起こりそうだ。 (18:19)

MIDIについての特記事項を以下に列挙する。

  • JACKサーバ: MIDIドライバ(midi-driver)に"seq"を指定する。
    • 上記設定をすればa2j_control(a2jmidid)は不要と思われる。
  • MIDIの配線: 当然ながら、JACKで、外(ALSA?)からのMIDI情報の出口(僕の環境では"Midi-Through:midi/playback_1")と制御対象の要素(jack-rack)を接続しておく(図左側の赤線)。
  • MIDI制御情報の送信: sendmidiコマンドを利用した。他にもあるが、僕には一番使いやすかった。
    • 実行例: sendmidi dev "Midi Through Port-0" ch 1 cc 0 0: (僕の環境・設定において)jack-rackの"Enable"をoffにする。
      • 注: 上記MIDIデバイス名はJACKでのもの(一つ上の項に書いた)とは異なる(ALSAのもの?)。sendmidi listコマンドで名前を確認すること。
  • jack-rackの設定: 制御したい要素(例: ボタン)上で右クリックすると設定ダイアログが出るので、そこにチャネル番号(sendmidiのchに指定する番号)とコントローラー番号(sendmidiのccに指定する番号。正式な名称は不明)を設定する。
    • この方法がなかなか分からなくて諦めていたのだが、jack-rackのgithubのページでようやく分かった。
    • Enableについては、設定値に127以上を指定しないとEnable状態にならない(Disable状態にする時は0でいい)ので、0と256を指定することにした。
    • あとで使うかも知れないので、Input gainとWet/dryも設定できるようにした。
  • どうしてか、(音と違って)JACKでの正式なMIDIのポート名は"system:midi_playback_1"のような分かりにくいものになり、起動のたびに番号が変わる感じで(要確認: 思い違いかも知れない ← クライアント(jack-rack)側の名前の番号は、起動順序で変わるのかも知れない)、自動で配線を保存・復元する機能がうまく動かなかった。それで、現在使っているMIDIの線は1本と少ないので、自動保存・復元の対象にせずにJACKの起動スクリプトで個別に配線することにした。
    • JACKの設定などで直るのかも知れない。
    • ↑JACKの設定ではなく自動で割り振られるようなので、JACKサーバ起動時にMIDIポート名の変換テーブルを作り、接続の自動保存時に、そのテーブルを元に、クライアントの起動順序で変わらないポート名(alias)に変換して保存するようにした(変換後の名前でも接続できるので、復元は問題ない)。 (12/23 22:42)
  • MIDIではデバイスの設定状態を取得することができない(標準的な方法がない)ので、アンプの状態は常に「上書き」する(現在の状態と比較するようなことは行わない)ことにし、設定後に状態をファイルに保存しておき、ミニプレーヤー(minisp)の起動時に保存された状態を再設定することにした。
    •  (ソフトの)MIDIは高速だしデータ量も少ないから、これで大きな問題はなさそうだ(世の中の電子楽器は基本はそうなのだろう)。
    • また、再生停止中にJACKサーバが再起動することもあるので、再生開始時にそれを検出したら(サーバの起動後に起動時刻をファイルに記録しておく)保存された状態を再設定することにした。上で「問題ない」と書きつつも、毎回無意味に設定するのは気分が悪いので、ここでは無駄な設定を省くようにしたw

それから、Spotifyの音量正規化(改良版)の性能を自作の方式と比較した結果を書く。双方で共通する38曲(演奏)について比較した。

判定条件

  • 音量の許容範囲: 基準(中心)から±2LUFS以内 (幅: 4 LUFS)
    • 音量(Integrated loudness)が上記許容範囲内なら問題なし(○)とする。
    • 問題なしの外側2 LUFSを可(△)とし、可の外側を不可(×)とする。
    • 下記の「偏差」は、音量が許容範囲の外側(○以外)に出た量である。

Spotify (Quietモード)+増幅 (ポップ音楽用: "Sp")

  • 設定
    • 基準音量: -16 LUFS
    • 音量の許容範囲: -18 .. -14 LUFS
  • 結果
    • 範囲内(○): 35曲 (92%)
    • 可(△): 3曲 (7.9%)
    • 不可(×): 0曲 (0%)
    • 合計: 38曲
  • 統計量
    • 音量の平均: -15.8 LUFS
    • 音量の標準偏差: 1.39
    • 偏差の平均: 0.1 LUFS
    • 偏差の標準偏差: 0.39

自作の方式 (ポップ音楽用: "Pk")

  • 設定
    • 基準音量: -20 LUFS
    • 音量の許容範囲: -22 .. -18 LUFS
  • 結果
    • 範囲内(○): 25曲 (61%)
    • 可(△): 9曲 (22%)
    • 不可(×): 7曲 (17%)
    • 合計: 41曲
  • 統計量
    • 音量の平均: -19.5 LUFS
    • 音量の標準偏差: 2.80
    • 偏差の平均: 0.74 LUFS
    • 偏差の標準偏差: 1.54

はっきり言って完敗である。Spotifyには不可(×)の曲がまったくなかったのには感心する。しかも、範囲内(○)に収まっている率が1.5倍と高く、音量のばらつき(音量の標準偏差)は半分以下、偏差の平均は1/7以下である。(数値的には)充分に音量が揃っていると言える。

ただ、負け惜しみではあるが、Spotifyは必要なデータを使って「普通に音量正規化(ReplayGain)をしている」のだから、良くて当たり前だとは思う。が、自作で情報(RG値)が不足した状態でいくら頑張っても勝ち目はないし、意味がないことは確かだ。

最後に、今回分かったことなどを列挙する。

  • クラシック音楽は予想以上にダイナミックレンジが広い。例: チェロの演奏(「無伴奏チェロ」 "Suite No. 5 in C Minor BWV 1011: V. Gavottes I & II")でもピークが平均値+約18dBまである。
  • 思い込みかも知れないが、日本のポップ音楽は比較的音量が揃っている。正規化後の音量が申し合わせたかのように基準値付近だった。国民性?
  • どうしてか、Calf Studio Gear(JACK Audioのエフェクタのスイート)はやっぱり駄目だった。リミッターですら耳閉感が起こる。根本的に作りが悪いのだろうか? でも、誰も文句を言っていないようだから、僕との相性なのか・・・
  • 少しだけでもMIDIの使い方が分かったのは収穫だ。演奏はしないが、JACKの要素の制御に使えるのが便利だ。
  • 同様に、今回は使わないことになったが、OSCも制御に便利そうだ。ただ、手間を掛けてそういう新しいのを作らずに、Dbusを使えば良かったのにとも思う・・・

これにて音量正規化問題は一旦終了!

一段落して、心置きなく気楽に音楽が聴ける。

 

と思いきや、、、毎度のことながら、そうは問屋が卸さなかったwww

昨夜、複雑なために一旦諦めたトリッキーなSpotifyの音量正規化用の値(以下、RG値)取得の方法を、なるべく簡単に実現するにはどうしたらいいかなどと考えながらSpotifyのログを眺めていたら、思わぬ展開になった。すごく簡単に取れるかも知れないことが分かったのだ。

RG値はSpotifyアプリのログに出ることは分かっていたが、音量正規化をonにしないと出ないし、その仕様がいつなくなるかも知れないのだが、SpotifyのWeb APIのGet a Trackなどで取れるプレビュー(試聴)用のMP3ファイルに入っていたのだ。全くコロンブスの卵というか、灯台下暗しだ。

その前に、RG値も入っていると思われる、ヘッダ部("head file")取得用URLがログから分かり、その中身はBase64エンコードされたOggだったので、「もしや!?」と思ったのだが、曲のデータ同様中身が暗号化されていてお手上げだった。

ただ、プレビュー用のファイルを普通にsoxiやexiftoolやプレーヤーで情報を表示してもなぜかRG値(例: REPLAYGAIN_TRACK_GAIN)が出ないので諦め掛けたのだが、ffprobeでは"Side data"として出た。だから、通常のMP3での格納方法ではないのかも知れない。あるいは、僕がMP3に詳しくないだけか?

↑調べたら、MP3のRG値は「LAMEタグ」というものに入るようだ(MP3の標準タグ(ID3v2?)に入らないのかは分からない)。eyeD3というコマンドに--lametagというオプションを指定すると見られる(そうしないと見られない!)。あ、lameはフリーのMP3エンコーダだから、LAMEタグという名前からして、それが独自に付けているようだ。ということは、入ってないものも、将来なくなる可能性もありそうだ。MP3は随分使われているのに、RG値すら標準で入れられないのだとしたら、なかなか面妖だなあ。。。 (18:51)

それで、その値が正しいかを確認するため、数曲で全体(全曲)とプレビュー版のRG値(track gain)を比べた。なお、全体のRG値はSpotifyアプリのログから抽出した。

  • 夏の扉
    • 全体: -8.71 dB
    • プレビュー版: -9.30 dB
    • 差: -0.59 dB
  • どうにもとまらない
    • 全体: -8.64 dB
    • プレビュー版: -9.10 dB
    • 差: -0.46dB
  • Speak to me
    • 全体: +13.49 dB
    • プレビュー版: +14.10 dB
    • 差: +0.61dB
  • Born to be wild
    • 全体:-3.64 dB
    • プレビュー版: -3.40 dB
    • 差: +0.24 dB

一見、全体とプレビュー版で随分値が違っていたのでがっかりし掛けたが、差を求めたら1dB未満(0.5dB前後?)なので、使えるかも知れないと考えた。

最初はRG値の差は圧縮率の違い(全体: 160kbps, プレビュー: 96kbps)によるものだと思ったが、その後、プレビュー版は先頭の30秒だけで、RG値もその部分のものであるために異なっているのではないかという懸念が生じた。それで、先頭の音量は小さく、後半に大きくなる曲("Stairway to heaven")で確認したら、プレビュー版のRG値も全体ものらしいことが分かった。: プレビュー版のRG値は全体の値とほぼ同じで、更に、手持ちのもの(マスタリングが異なるかも知れない)の先頭を切り出してRG値を求めたら、(先頭は音量が小さいため、)プレビュー版や全体より随分大きな値になった。以下にそれらの値を示す。

  • Spotify
    • 全体: -5.26 dB
    • プレビュー版: -5.0 dB
  • 手持ちの曲の先頭(30秒)の切り出し: +5.2dB (GMBで求めた)

実際、手持ちの演奏のラウドネス(Integrated loudnessをebur128コマンドで求めた)は13.3LUFS違っていた。

  • 全体: -11.1 LUFS
  • 曲の先頭(30秒): -24.4 LUFS

念のため波形を比較すると、確かに先頭と全体の平均音量は10dBくらい違っていそうだから、きっと大丈夫だ。

"Stairway to heaven"の振幅: 上: 全体, 下: 先頭30秒 (縦軸はdB)

実際、Spotifyの立場で考えると、プレビューを提供するためだけに全部の曲のRG値を計算し直すのは馬鹿らしいし、プレビュー版の再生時に正規化するとしたら(実際にはしないと思う)、全体のRG値でする方が本来の雰囲気に近く、「試聴」の意図に合うから、全体のRG値を入れている(実際には全体の値を捨てずに残しているだけ?)のは腑に落ちる。想像だが、この値はレーベルから提供された試聴用ファイルに入っているものなのではないだろうか? (音源提供者向けの案内を調べれば分かるかも知れない)

プレビュー版内のRG値を使う場合には、以下のような手順で「普通の」(自分の好きな基準音量に合わせられ、Spotifyアプリのリミッターを回避する)音量正規化ができそうだ。

  1. Spotifyアプリが再生開始するのを待つ。
  2. API: Get a Trackを使い、プレビュー版を取得する。
    • Get a trackのpreview_url要素より。
  3. プレビュー版のファイル(MP3)からtrack gainを抽出する。
    • ffprobeを使う (exiftoolやsoxiでは出ない)
  4. 音量正規化処理を行う。
    • 抽出したtrack gainに従って、音量補正値をアンプに設定する。
      • 基本的にはtrack gain(dB)そのものをを設定すればいいが、オーバーフローを回避するために、適切にオフセットする(下げる)必要がある。

あとは作るだけ。だが、ちょっと疲れた。それに、寒いしお腹空いたしw

 

と書いたところで、思わぬ落とし穴に気付いた。: すべての曲に、あるいは、今後もずっと、プレビュー版にRG値が入っているか疑問だ。入ってない曲があったり、いつかなくなる可能性がありそうだ。上に書いたように、この値は使われることがないだろうし、意図的に捨てていないからあるだけで、Spotifyのサービスの仕様ではないからだ。

そうなっても、(今までのように、)いくらでも回避策は考え付くだろうが、結局、堂々巡りになりそうな感じだ。それだったら、(音質などが完璧ではないものの、)気楽に聴ける今の状態で満足するのが一番得策な気はするが・・・ うーむ。 まあ、興味本位で「お遊び」でやるなら ありかな(いや、全部遊びだがw)。

↑イマココ

(12/25 12:41) 「プレビュー版のRG値で正規化」をちょっと試してみた。結論は、やっぱり駄目だった。以下に理由を書く。

  • 予想どおり、RG値が入ってない曲がある。確率は5%程度ではあるが、少なくない。
  • 更に、RG値がおかしい曲もあった。こちらは10%程度と多い。
    • 数曲について、Spotifyアプリのログに出る全体(正式版)のRG値とプレビュー版のRG値を比較したところ、正規化後の音量が駄目だったものは大きく異なっていた。
    • 逆に、プレビュー版のRG値で正規化でも問題ない場合は近かった。
    • 当然ながら、全体のRG値で正規化した音量を計算したら基準範囲内だったので、問題なさそうだった。

どちらも致命的だ。評価用プレイリスト(ポップ・クラシック合計約90曲)で試したところ、ポップ音楽はまあまあだったが、クラシック音楽は惨憺たる結果だった。うまく行くものもあるから、その曲のプレビューのRG値が良くないのだが、どうしてそうなのかは分からない。プレビュー部分だけのRG値が入っているとか、元の版が違う(プレビュー用は初期のマスタリングなど?)とか、テキトーに計算したとかだろうか。いくら原因が分かっても、プレビュー自体すらなくてもいいような状態でSpotifyは全く保証していないので、対処してもらえる訳がない。

プレビューですらこんなことでは、以前書いた、ログからRG値を抽出する「トリッキーな方法」なんて余計駄目だろう。

いずれにしても、結果としてはイマイチだった。これがうまく行ったらすごくいいと思うが、やっぱり問屋が卸してくれなかった・・・ まあ、作るのはそれほど大変でなく、いつものようにおもしろかったからいいや。

そういう訳で、今は元の状態に戻して、「気楽に聴ける」状態になった(この音量正規化が破綻しないのには本当に感心するw)。これを試した一番の理由の、正規化をon/offする時のSpotifyの再起動を回避する件については、別の方法を考えたい。

一応、設定画面を開かずに、外部から音量正規化をon/offする方法はないかSpotifyに聞いたが、「ない」とのことだった。まあ、それは仕方ない。きっと、かなりニッチな要望なのだろう・・・ (12/25 15:38)

(とりあえずは、)本当に一件落着■

 

(題の漢字は、各自自由にご想像下さいw)

  •  0
  •  0

どっかの国の政府とか軍隊みたいに、勝算がないのに精神論(利権も?)で金・労力を投入して無理な行軍を延々と続けて、最後に、さまざまな言い訳をしながら形式上は「成功」などと発表してドヤ顔して(それどころか、首謀者が逃亡・知らん顔して、)煙に巻くのは愚の骨頂だ。駄目なものはなるべく早く気付いて切る(少なくとも、再検討や方向転換する)のが重要だ。

試行錯誤しているSpotifyの音量正規化処理の改良だが、ポップ音楽モードがそこそこ うまく行って、クラシック音楽モードも調整して目処が立ったものの、今朝寝ながら思い付いた(気付いた)。Spotifyアプリの(標準の)音量正規化機能がどのくらいのものなのか、それと今回の自作の方式にどのくらいの差があるのか確認しようと。特に、曲の特徴量のデータが誤っているのではないかというくらい大音量になるいくつかの曲(例: "Take My Breath Away", "Catacombae")は、Spotifyアプリの音量正規化ではどうなるのか興味があった。

やってみたら、多くの収穫があった。

  • Spotifyアプリの音量正規化の性能はいい。自作の方式よりずっと音量が揃う。ポップ音楽での音量幅(ラウドネスの不揃い度)は、自作の方式では、(試した数曲の音量の範囲が広かったとはいえ、)おかしい音量になる曲を除いても、目分量でSpotifyの2倍(LUFS値の幅)くらいだった。おかしい音量になる曲を含めれば数倍になる。
  • Spotifyアプリの音量正規化のうち、Quietモードでは、Normalモードと違い、すごく静かな曲(例: "Speak to me")を不自然にしてしまうコンプレッサー(のような処理)が働かないようだった。
  • Spotifyアプリの音量正規化用の値は、ログやコンソール出力から取得できる。ただし、音量正規化をonにしていないと出ない。

Spotifyアプリの結果を聴いたら悔しいくらいだった(上記の困った曲が何の問題もない音量で出ていた)。悔しいけれど、結局、自作の方式でいくら頑張っても苦労ばかりで余りメリットはなさそうだ(そもそも、目的はそこにない)。それよりは、Spotifyアプリの音量正規化をうまく使えばいい。

一番手軽なのは、音量正規化をする場合は常にQuietモードを使うことだ。これなら、ポップ音楽でもクラシック音楽でも切り替え不要で、静かな曲でも音が不自然になることはなさそうだ。ただ、目標音量が-23LUFS程度と小さいので、もったいない気がする。特に、ポップ音楽では、もっと音量を上げてSN比を向上させたりダイナミックレンジを減らさないようにできる(だからNormalモードを使いたいのだが、例のコンプレッサーが邪魔だ・・・)。が、そもそも、音量正規化して聴くというのは、BGMのように気軽に聴いている時であり、その時にSNだのダイナミックレンジだのと言っても無意味だ。逆に、真剣に聴く時には音量正規化を使わないから、これで問題ないとも言える。

少し前に試行錯誤中に知ったのだが、Spotifyアプリの音量正規化はトラックモードとアルバムモードを自動で切り替える(アルバム再生時は後者になる)とのことなので、自作しようと思った切っ掛けの一つの、アルバムモードがないことも解決できた(この機能は後から追加されたのか、最初からあったが公表されていなかったのか)。そういう点でも、特にモバイルなどで切り替えずに使いたいなら、Quietモードにしておけば不便はない(まあ、モバイルでは周囲が騒がしいので、すごく静かな曲が不自然でも問題なさそうだから、Normalでもいいとも言える)。

ただ、Quietモードのもう一つの問題は、音量が小さいので他のプレーヤー(僕の場合は、gmusicplayer, GMB)と合わないことだ。これは結構厄介だ。Spotify(音量正規化)からGMBに切り替えた途端に大音量(約+11dB, 3.5倍)になるので、常に注意が要るし(大抵忘れて驚くw)、アンプの音量調整が煩雑だ。アンプの音量を変える代わりに他のプレーヤーの音量を下げる手もあるが、やっぱり「もったいない」から避けたい。逆に、Spotifyアプリの音量を後で大きくして合わせる手もあるが、一旦小さくしているのを増幅すると音質が劣化するから嫌だ。

書いた後で気付いたが、小さくしたのを増幅すると音質が劣化するというのは本当だろうか? (アナログでなく)ディジタルなので、増幅でオーバーフローしない限り、小さくした時より劣化することはない気がして来た。あとで検討したい。 ← データフォーマットにも関係ありそうだ。 → 検討結果を付録に記載した。 (12/19)

調べると、-23LUFSというのはEUの放送の基準レベル、あるいは、クラシック音楽向けだそうで(USや日本の放送は-24LUFS)、それに合わせるのは悪くないとは思うものの、自分の閉じた環境なのに一律に低く合わせるのはやっぱりおかしい気がする(実際、SpotifyやYouTubeの基準は-14, -13LUFSと、-23LUFSよりかなり大きい)。

以下に、候補とそれぞれの欠点をまとめる。

  • 自作の音量正規化
    • 音量を揃える能力がSpotifyより低い。
    • 全然揃わない曲がある。
    • 原因: Spotifyから音量正規化のための値(ReplayGain)が取れないので、音響的特徴量から推測しているため。
  • Spotifyの音量正規化: Quietモードのみ
    • ポップ音楽でダイナミックレンジがもったいない。
    • 音量が小さいので、音質が劣化する?
    • 他のプレーヤーと音量が揃わないので不便。 → 増幅すると音質が劣化する(要確認 → 検討結果を付録に記載した。 (12/19))。
    • 原因: Quietモードは音量が小さいため。
  • Spotifyの音量正規化: Normal, Quietモードを切り替える。
    • Normalで不自然になる曲(静かなもの)がある。
    • 原因: Spotifyアプリの処理(コンプレッサー?)が入ることがあるため。

上述のとおり、自作の音量正規化が駄目なのはSpotifyからReplayGainが取れないためなのだが、どうにかして取る方法はないかと試行錯誤していたら、思わぬことで取れた! 既に書いては居るが、アプリのログやコンソール出力に表示されるのだ。以下に"Speak to me"での例を示す。太字がトラックのReplayGainである。

02:05:55.089 I [libvorbis_ogg_decompressor.cpp:401] track gain: (13.25Db), track peak: (0.409425dB), album gain: (-5.09dB), album peak: (1.02865dB), normalization: trackgain

ちなみに、それらはGMBでの同じ曲(同じマスターと思われる)でのReplayGainの値と概ね合っていた。

なお、peakの単位が"dB"と書いてあるが、誤りであろう(正しくは単位なし)。同じく"Db"もtypoだろう。ここら辺は そうなる状況が分かる。つい指が動いたとか、余計にコピペしたとか。「(見ると気になるけど、)デバッグ用だからまあいいか」、みたいなw

それで、自作の音量正規化にSpotifyのReplayGain(以下、"RG")値を使う(苦肉の)策を考えた。理論的には、RG値取得用と再生用の2つのSpotifyアプリを使えばできそうだ。以下に手順概要を示す。

  1. 再生用Spotifyアプリを音量正規化offにする。
  2. RG値取得用Spotifyアプリをログまたはコンソール出力ありで起動する。
  3. RG取得用Spotifyアプリの音量正規化をon(NormalまたはQuiet)、音量=0(-∞ dB)にする。
  4. RG取得用Spotifyアプリで再生開始する。
  5. ログまたはコンソール出力からRG値を取る。(すぐに出るはず)
  6. RG取得用Spotifyアプリを一時停止する。
  7. 得られたRG値で再生用Spotifyアプリの音量を調整する。(現在の自作と同じ方法)
  8. Spotify APIを使い、有効なプレーヤ(デバイス)を再生用Spotifyアプリに切り替える。
  9. 再生用Spotifyアプリで最初から再生開始する。

ちょっと手で試して、やればできそうな気はしたが、(すっかり忘れて居た)昔のGoogle play musicの時(→ )と同様に、余りにもトリッキーで嫌になるくらいだ。また、アプリが2個なのでメモリも2倍食いそうなのも嫌だ。そもそも、ログにRG値が表示されるのは仕様でもなんでもないので、出なくなったら元の木阿弥だ。。。

だから、やっぱり筋が悪い。

そして、作るのは面倒だw

それで、とりあえずは、Spotifyの音量正規化機能を使うことにし、ポップ音楽とクラシック音楽でNormal(ポップ)とQuiet(クラシック)を切り替えて使ってみて、Normalでどのくらい不自然な曲があるかで判断することにした。Normalで駄目な曲は(DBに記録しておいて)自動でQuietに切り替える手が考えられるし、多かったらQuietだけ使うとか、上のトリッキーな手を使うことも考えられる。

それにしても、「とりあえず」のNormalとQuietを手で切り替えて使うにも自作ミニプレーヤー(minisp)に多少の変更が要るので、「ちょっと疲れたから、まあ明日にするか・・・」と一休みしているw ← イマココ

相変わらず寄り道が多く、先は長いw

 

(12/19 16:40) 付録: (デジタルで)増幅すると音質が劣化についての検討

結論は、「理論的には劣化しないが、現実には劣化する」である。以下に理由を書く。

まず、本文に書いた状況での音質劣化は、音量を下げた時点で生ずるものが主である。音量を下げることによってデータの有効ビット数が減るため、振幅分解能が減る(例: ものすごく小さい音が消える)ためだ。音を格納するデータフォーマットが浮動小数点型であれば、おそらく分解能が減ることはないが、整数型の場合には減る。その程度は以下のように試算できる。

音量を-23dB下げた場合、1ビットは約6dBなので、23/6= 約3.8ビット減る。

これによるダイナミックレンジの減少量は、データフォーマットを16ビットとすれば、3.8*6= 22.8dBである(音量を下げた分(23dB)そのもの)。

(2020/1/2 12:28記) 注: その後、Spotifyが音量正規化値の計算に使っているReplayGainの基準音量は-14LUFS相当であることが分かった。そのため、実際に下がる音量は9dB程度で、減るビット数は1.5ビット程度と少なく、特にポップ音楽では、音質の劣化もダイナミックレンジの減少もほとんど問題にならない。

実害について考えれば、対象はポップ音楽であり、そのダイナミックレンジを高々18dB(約3ビット分)程度と推測すれば、音量を下げた残りのビット数は16-3.8= 12.2ビットで、音源の3ビットより充分大きいので、記録された振幅がよほど小さくない限り、問題ないと考えられる。

次に、増幅の影響を考える。増幅は乗算なので全く音質が劣化する要素はないが、現実には、処理系や出力のデータフォーマットは整数型で取り得る範囲が有限なため、大きく増幅すると上限を超えて(オーバーフローして)音質が劣化する。つまり、波形の超過分がカットされるので、音が変質する(例: 歪む)。

この検討中に気付いたのだが、私が"Speak to me"で感じた不自然な感じは、オーバーフローによるものだった。具体的には、音量正規化時に過大に増幅するとオーバーフローが生じ、その超過分をカットすると生じる(これはリミッターの動作であり、本文中の「コンプレッサー」は実際にはリミッターであった)。

不自然さが起こる原因を詳しく推測すると、この曲は低音(鼓動)が強いため、それがオーバーフローしてカットされるのだろう。カットされるのが単発的(不定期)や短時間(瞬間的)に起こるのなら気づきにくいからまだいいのだが、この曲の場合は、定期的に起こる鼓動で、テンポが遅いために比較的長時間音が大きい状態なので、カットされる期間が長く、その間の他の音の聞こえ方が変わって不自然になるのだろう。

この現象はSpotifyアプリの音量正規化だけでなく、私の環境でも起こったので気付いた。具体的には、次のような処理をした時に、Spotifyアプリの音量正規化(Normal)と同様の不自然さが生じた。

Spotifyアプリの音量正規化(Quiet) → アンプ(増幅率: 6-9dB程度) → リミッター

また、Spotifyアプリの音量正規化(Quiet)だけでは不自然さは生じなかったので、問題はリミッターに起因する可能性が高い。

なお、「リミッターが原因だったら使わなければいい」ということはない。リミッターがなくても、超過分はどこかで(例: DACで出力する時)カットされ、それはリミッターよりもひどい音質劣化を生じる可能性が高い。

(12/19 22:23) 補足: 上でデータフォーマットを16ビットと想定したのは、Spotifyアプリの出力がそう("s16le")だからで、通常のOSのサウンドシステムはもっとビット数の多いフォーマットをサポートする。例えば、私の使っているJACK Audioは32ビット浮動小数点である。だから、音質の観点ではSpotifyに音量正規化をさせるのは得策でない。上述の、音量を下げることによるダイナミックレンジの低下などが起こる。が、もし仮にJACKの中やその手前のPulseAudioで行うなら、劣化する可能性はほとんどない。

その後の増幅はJACKで行っているので、通常の増幅率ではオーバーフローしないから、音質劣化も発生しないはずだ。しかし、元々のデータが最大値に近いほうに詰められているためにオーバーフローするし、そうでなくてもDAC(サウンドカード)に出す時にオーバーフローする。それを防ぐには、リミッターを入れるか、音量を下げて(= 適当な値で除算して)全体的なレベルを小さくして(= 小さい方にずらす)DACに出すことが考えられる。

結局、後者はSpotifyの音量正規化(Quietモード)の小さい音のまま出力することと同等である。もちろんそれでも良かったのだが、他のプレーヤーと音量を合わせたいから増幅しようとした。

 

PS. SpotifyアプリからのRG値取得には、音楽圧縮フォーマット展開用ライブラリ(vorbisを使っているようだ)をすげ替えればできるかと思ったのだが、自前で作っているかスタティックリンクしているらしく、外部のものは使っていなかった。考えが甘かったが、まあ、そうれはそうだろう・・・ あとは、逆コンパイルしてバイナリエディットとかいう手もあるかも知れないが、「うーん」だ。それに、プログラムの改ざん検証をしているかも知れないから、できないかも知れない。

なんてことを考え出すから、寄り道が増える訳で・・・

  •  0
  •  0

使っているうちに不満(例: うるさい曲がある)が出て来たために、Spotifyの自作ミニプレーヤー(minisp)の音量正規化処理で、音量の補正量をやはり自作再生履歴DB(Mlhi)に記録しおいてそれがあれば使えるようにしようと思ったのだが、そもそも、元々の方式がいい加減では補正ばかりになって良くないことに気付いた。それで、まずは音量正規化処理を改良することになり、今は、その改良した方式の評価のために、Spotifyで再生している曲の音量を自動で測定する機能を作っている※。音量はできるだけ聴感に近い方がいいので、ラウドネス(Integrated loudness: "I", 参考)にした。随分目的から離れてしまった気がするが、きっと気のせいだろうw 自分でやり出したこととはいえ、なかなか面倒だが、いろいろな物を組み合わせて機能を実現するのはおもしろい。

※なぜ自動化しようと思ったのかというと、ラウドネスメーターはあらかじめ曲の先頭で計測開始しておかなければ、正確なIntegrated loudnessの値が出ないので、だらだらと評価がてら聴いていて「大き/小さ過ぎるかな?」(調整がおかしい?)と思ってからでは遅く、再計測しなくてはならないからである。再計測にしたって、曲全体を再度聴くのは苦痛なので、先頭だけなど一部になって、正確でなくなってしまう。曲間で自動リセットしてくれるような測定アプリがあればいいが、そういうものはなかった。また、GUIに表示された測定値を見て手で記録するのは面倒だし間違い易いから、自動でファイルに記録できれば好都合だ。

更に、複数の補正条件・設定の比較についても、それぞれの条件で評価用のプレイリストを再生しておけば(僕が聴いて居なくても、スピーカーで音を出さなくても)通して測定できるので、(この機能が完成した暁には)容易になるはずだ。

更に、普通に再生しながら、補正条件とその結果の音量を測定してDBに記録しておき、次回はそれに基づいて最適な音量に調整するってことも可能な気がしていて楽しい。

更に、今思い付いたが、AIみたいな機能で、長時間いろいろな曲を自動再生して勝手に学習させて、設定を自動調整するなんてのもいかにもおもしろそうだが、先は長いし、そもそもSpotifyを聴くだけなのにそこまでする必要があるのかと・・・w

こうやって風呂敷夢を広げるから、大変になるのだ。

詳しくは別に書くつもりだが、音量正規化の基本的な処理は、従来と同じようにSpotify APIで取得できる曲(トラック)の特徴量(loudnessとenergy)を組み合わせて、曲の本来の音量を推測(復元)し、それを元に正規化している。今回は、その推測の方法を改良しようとしている。今までは思い付きで対数あるいは指数関数を使っていたが、今は下のグラフのような、energyによって特性(係数)が変化する式を試している。グラフはいかにももっともらしくて うまく行きそうに思えるが、そんなことはないw それに、これは何かの理論に基づいている訳ではなく、やっぱり思い付きや試行錯誤からの経験によるものである。試すとまあまあうまく行く(しないよりはずっといい)のだが、やっぱり限界はあるし、値に問題はなくても聴覚に合わないことがある(合わないものが充分に少なくなったら、補正量をDBに入れようと思っている。が、いつになることやら・・・)。

あと、以前のように、公開DBに音量正規化用の値(再生ゲイン)などがないか探したたら、2つ見付かった。一つは前回も見付かったDynamic range databaseで、もう一個はAcousticBrainzだ。前者は、前回は(記憶している限りでは)APIがないのとレパートリーが狭そうなので止めた。後者は、言い方は悪いが「玉石混交」(「ゴ○屋敷」などもっとひどい言い方はあるが、それは言い過ぎだろう)で、全く手軽に使えないので却下した。確かにデータは多いのだが、全然整理されておらず、ただ数字があるだけで、同じIDなのにそれぞれ随分違っていてどれが正しいのか分からず、禄に検索もできなかったら、どうやって使うのかと思う。

作業の途中で分かったことも多かった。SpotifyのAPIから得られるloudnessは多くの場合はIntegrated loudnessまたはReplayGainと同様(同等)のものなのだろうが、そうでないことも多い。中で変・特殊な処理(音量(loudness)が小さいけどenrgyが大きい曲では更にloudnessを小さくしているフシがある)をしている可能性と、データが誤っている場合もありそうだ。そもそもSpotifyアプリで使っている再生ゲインを出してくれれば、こんな苦労をしなくて済むのだが(アプリの一時ファイルを見たりしたが、それらしい値は見つからなかった)・・・

そもそも、Spotifyアプリの音量正規化処理が「普通」だったら、こんな苦労は全くしなくていい(実際、したい訳じゃなくて、ただ音楽を聴きたいw)のだが、前回書いたように、やっぱり謎の処理をしていることが分かった(何人かの方が書かれていた: )。どうやら、アプリにコンプレッサーとかリミッターのような処理が入っていて、特にすごく音量が小さい曲(僕が気付いた曲: Pink Floyd: "The dark side of the moon"の"Speak to me")でおかしくなるようだ。再生ゲインの値がおかしい可能性はあるにしても、せめてその余計な機能がなければまだ良かったのに、どうもお節介な感じだ・・・

ラウドネスの測定プログラムは、GUIのものならいくつかあるのだが、測定・記録を自動化するのは困難なので、スクリプト(jack_captureで音を録り、ffmpegのebur128フィルタでラウドネスを計算する)を作ってミニプレーヤーに組み込んだ。基本的には、ただ再生しているだけでデータが貯まるから楽ちんなのだが、例によっていろいろ凝るから本末転倒になって、処理が複雑になればバグは増えるからデバッグが大変で、また勝手に疲れている。 ← イマココ

 

PS. 以前、「Spotifyには満足している」と書いたが、誤りではない。が、それはあくまでも曲目と音質についてであって、機能は別であるw

PS2. これを書いていて、技術バカにありがちな、「フラット(あるいはリニア)信仰(あるいは症候群、至上主義)」という言葉を思い付いた。やっぱり、こだわり過ぎは駄目なんだろうと思う。が、気軽に聴いている時に、曲のたびに「うるさい!!」とか「小さい・・・」とイライラしてボリュームを調整するのは嫌だってのは大いにある。

PS3. Evernoteやスマフォ・PCのおかげで紙やペンとは無縁の日々なのだが、さすがにグラフの形を考えるのはEvernoteでは無理で(タブレットなら手描きできそうだが、それも煩雑な気がする)、紙が必要だった。が、すぐに使えたのは小さい電話用のメモ帳しかなかったw

(12/14 13:11 少し修正)

  •  0
  •  0

先日買ったUSBオーディオインタフェース Focusrite Scarlett Solo (以下Scarlett)のファームウェアは、制御アプリ(Focusrite Control、以下FC)で自動確認・ダウンロードしている訳ではなく、ユーザが適宜webサイトを見て更新に気付いたら、自分でFCをダウンロード・インストールする必要があり、それを実行すれば通知が出ることが分かった。また、更新されたファームウェアはFCのインストール時に展開されることも分かった。

自分でwebサイトを見て更新をチェックするのは面倒だし(絶対に忘れる)、僕は基本的にWindowsを使っていないから、FCを動かすこと自体が面倒だ。とはいえ、ファームウェアはそれほど頻繁に変わらないだろうし、問題に気付いた時にチェックする程度で充分だろう。そもそも、僕はScarlettをたまにしか使わないw それでもおもしろそうだったので、自動で更新チェックとダウンロードができるようにしてみた。

もちろんFocusriteのサイトにAPIがある訳でもないので、いつもながらの古色蒼然としたスクレーピングなどを駆使して更新をチェックすることにした。以下に手順を示す(いつもと同様、こういうニッチなことに需要があるとは思えないので、概要とか概念(、そしてLinuxがいかに便利かw)の紹介に留めた)。

  1. Focusriteのダウンロードページ(製品ごとにURLが違うので、指定しやすい)をダウンロードする。
    • Scarlett Solo(3G)の例: https://customer.focusrite.com/support/downloads?brand=Focusrite&product_by_type=1365&download_type=software
  2. ダウンロードしたページ(HTML)を解析してFCのバージョンを調べる。
    • FCバージョンの記載例: <h3>Focusrite Control Windows - 3.4.0</h3> : 太字がFCのバージョン
  3. あらかじめ保存しておいた現在のFCバージョンと異なっていたら、あるいは、現在のFCバージョンが保存されていなかったら、FCをダウンロードする。ダウンロードURLは上記ページ中にある。
    • FCのダウンロードURLの記載例: href="/sites/customer/files/downloads/Focusrite%20Control-3.4.0.exe"
  4. ダウンロードしたFCを展開し、中のデバイス記述ファイル(XML)を取得する。
    • FCのインストーラーは(今のところ、)Inno Setupというプログラムで作られているので、Linuxでは(実際にインストールしなくても、)innoextractというプログラムで中身を展開できる。
    • デバイス記述ファイル名の例: app/Server/Resources/Devices/Scarlett Solo (3rd Gen).xml
  5. デバイス記述ファイルを解析して、ファームウェア(以下、FW)のバージョンを調べる。
    • FWバージョンの記載例: <segment name="App_Upgrade" nickname="App" version="1552" file="SctG3_Solo.bin" encrypted="true"> : 太字がFWのバージョン
  6. あらかじめ保存しておいた現在のFWバージョンと異なっていたら、あるいは、現在のFWバージョンが保存されていなかったら、FWが更新されていると通知する。
  7. FCとFWのバージョンが変わっていたら、どこかに保存する。

ページのURL、スクレーピング、HTMLの解析、インストーラーの展開、ファイル名の決め打ち、XMLの解析など、多くの点でひ弱(Focusrite側の変更に弱い)ではあるが、他に方法がないので仕方ない。まあ、変更が頻繁でない限りは便利だろう。今は動作確認中だが、問題なかったら、4日に1回程度チェックするようにcrontabに設定しようと思っている。

なお、もしFWが更新されていた場合には、(試行錯誤の挙句ノートPCにインストールした)本物のWindowsにFCをインストールし、それにScarlettを接続してFWを更新しようと思っている。

  •  0
  •  0