Archive for the ‘gmusicbrowser’ Category

面倒なのでずっと放置していたのだが、以前から気になっていたgmusicbrowserの(GMB)問題を一個修正した。きっかけは、今朝か昨夜だったか、シャフル再生中に、ある曲を聴きたくなったのだが、その問題のために躊躇したことだ。

その問題というのは、アルバムなり全曲のシャフルなりのプレイリストを再生中に一時的に別の曲を再生する(「キュー」機能)と、それが終わった後に本来の次の曲に戻らず、一時的に再生した曲がプレイリスト中にあればその次に飛び、なければプレイリストの先頭に戻ってしまうというものだ。

調べたら、元々そういう機能が作りこまれていないようなので(作者の精魂が尽きた?)、機能を追加した。相変わらずPerl言語はチンプンカンプンだし(Perlを作った人は、頭が腐っているか狂っている。どっちにしても、かなりおかしい。どうしてあそこまで分かりにくくしたのか、是非聞いてみたい)、GMBの造りも完全には理解できていないので苦労したが、何とかできた。なかなか疲れたし、昼食もとれなかった。「どうなってんだろう」と、軽い気持ちでエディタを開いたのが運の尽きだったw

それはともかく、終わってから、こういうのはデロリアン(タイムマシン)を改良しながら飛び続けたり、アイスティーに入れる氷を作るために巨大な装置を作ったドクに似ているかもなあと、ちょっと思った。

ちなみに、早速、聴きたかった「俺ら東京さ行ぐだ」を聴いて満足した。一体、どうしてそこまで好きなのか?w

 

PS. 今、「ついでにあの問題も・・・」と思い付いてしまった。午後も駄目っぽいなw

結局手を付けてしまって、案の定、手こずったが、ようやく何とかなった。またGMBの迷路のような造りが少し分かった。が、すぐに忘れそうだw (23:43)

ちなみに、その問題は、アルバムアーティストが設定されていないアルバムのジャケット画像がおかしくなる(別の同名のアルバムのものが表示される)というものだった。なぜか、GPMの曲を再生する時だけ起こるのだが、例えば、"Live in Japan"や"Greatest hits"という名前のアルバムで驚かされた。GMBのバグ以外に、ジャケット画像情報の格納の仕方が結構残念なことに気付いたのだが、さすがに抜本的な改良は難しい。 (5/6 0:12)

PS2. プログラミング言語の選択には、その人の個性とか趣味が現れるようで、職場の僕の居るチームでは、見事に各自が別々の言語を使っている。僕はPHP(awkやsedも)、隣の人はPerlといった具合だ(Cは、全員、必要な時に使う)。それで特に問題が起こらず、うまく行っているのも、おもしろいw おそらく、偉い人が、無理に「統一して効率を上げよう」と思うほど馬鹿でないのが効いているのだろうw (5/6 0:35)

  •   0
  •   0

この連休にはオーディオ(スピーカー・部屋)の音響特性の測定と調整をしようと思っていた。が、今日は下の家族が居るようで、子どもが走り回ったりして雑音が出るので延期した。それで、ちょっと前に思い付いた機能を作ってみた。

僕は、gmusicbrowser(GMB)の出力は標準のPulseAudioでなくJACKに出すようにしている。それに深い意味や大きなメリットがある訳ではないのだが、イコライザや出力はJACKなので、PulseAudioを介さずに直接JACKに入れることで、わずかに音の劣化が減ることを期待しているのだ。

が、それにはちょっとした問題がある。GMBのJACK出力は、曲を再生中以外ではなくなってしまうので、そのままでは再生するたびに接続しなければならず、全く実用的でない。それで、jack-plumbingという自動接続プログラムで接続するようにした。

それで問題なく使えていたのだが、先日、一つだけ問題が見つかった。音源がモノラル(正確にはチャネル数が1)の場合、左のスピーカーからしか音が出ないのだ(JACKでなく、PulseAudioの時は出ていた)。

どういうことかというと、GMBやJACKにはモノラルをステレオに変換(正確には、単一チャネルの音を両チャネルに出す)する機能がないため、モノラルの場合にはGMBからは最初の出力ポート(左チャネル)しか生成されず、jack-plumbingにもチャネル数が1の時は重複接続するような機能はないため、結局、左チャネルの入力ポートにしか接続されないので、左からしか音が出ないのだ。

モノラル(1チャネル)の音源なんてほとんどないから、我慢・無視すればいいだけなのだが、好奇心とか興味でなんとかしたくなった。それで、それにはGMBの改造が要るので、どうせやるなら、ついでにJACKへの自動接続機能も付けて、jack-plumbingを廃止したくなった。やり方は大体分かっていたので、今日は実装と修正をした。

それから、別件だが、少し前に、特定のアプリの音を特定の出力(例: ヘッドフォン)だけに出したくなって、それも実現していた。

以下に、それぞれの実現方法や実装の概要やちょっと苦労した点を書く。

(4/29 13:25追記) さっき、昨日思い付いたこと(下記の「Gstreamerの機能でも接続できるのかも知れない。」)を試したら、意外に苦労はしたものの、概ねうまく行った。おかげで、処理を大幅に簡素化できた。Gstreamerには分からないことが多過ぎて、まだ気に入らないこと(モノラルの処理)があるのだが、とりあえずは良しとする。以下に、その内容を"[4/29]"として追記する。

(4/30 9:42追記) 昨夜(4/29)、上に書いた「気に入らないこと(モノラルの処理)」もできた。Gstreamerの動作が調べたことと違うので、やっぱり苦労した。他に、特定アプリの音に関する接続漏れが見つかったので、修正した。以下に、それらの内容を"[4/30]"として追記する。

GMBからJACKへの自動接続機能

  • GMBで再生時、Gstreamer(再生用ライブラリ)の再生準備をした後(playbinというものの初期化後)、指定したJACKの接続先(入力ポート)に接続する。
    • JACKへの接続にはjack_connectコマンドを使った。もしかしたら、Gstreamerの機能でも接続できるのかも知れない。
    • [4/29] GstreamerのJACKモジュール、jackaudiosinkの自動接続機能でJACKに接続できるようになった。今までできなかったのは、仕様(使い方)を理解していなかったのと、JACKサーバに知らない機能があったためだった。
      • jackaudiosinkのプロパティconnectを"auto"にし、port-patternに接続先を設定(正規表現。例: "jack_mixer:In .+")すれば自動的に接続される。
      • JACKサーバのバージョンによっては、self connect(アプリが自分で接続する機能)が無効化されているために接続できない場合がある。その場合は、jack_controlコマンドでself connectモードを" "(self connect有効)に設定し、サーバを再起動する。
        • 例:  jack_control eps self-connect-mode " "
      • self connectを有効にした時、PulseAudioサーバのバージョンによっては、pacmdでmodule-jack-sinkをロードした時に、自動的にデフォルト出力に接続される場合がある。その場合は、ロード時に自動接続を無効化すればいい。
        • 例: pacmd load-module module-jack-sink connect=false
      • ただし、私はJACKサーバをjackdbusで起動しており、その場合にはmodule-jack-sinkが自動でロードされるようで、上記の指定は無効なので、JACKサーバの起動後に自分で切断している。設定ファイルに書けばいいのだろうが、JACKの開始スクリプトに書いた方が確実と考えた。
  • 曲をスキップさせたり再生ゲインのモードを変更した時などにはplaybinが初期化されるので、再度接続する。
    • [4/29] jackaudiosinkの機能で接続する場合には不要になった。
  • 理由は分からないのだが、playbinの初期化直後は接続に失敗するので、その場合は一定時間後にリトライするようにした。
    • たまたま、GMBには500msの周期処理(UpdateTime)があることに気付いたので、その中にリトライを追加した。
    • [4/29] jackaudiosinkの機能で接続する場合には、自分で接続しないので失敗することもなく、リトライは不要になった。
  • 接続済みの場合に再度接続しようとすると、無駄な処理の繰り返しになって負荷が増えるので、接続しようとする前に接続済みかどうかを調べるようにした。
    • JACKの接続確認にはjack_lspコマンドを使う自作のコマンドを使った。
    • [4/29] jackaudiosinkの機能で接続する場合には、自分で接続しないので不要になった。
  • 接続先ポートはGUIで設定できるようにすべきだが、頻繁に変える訳ではないので、今はプログラムの中に記述している。

GMBでのモノ→ステレオ変換

  • 上記のJACKへの自動接続時に、再生しようとしている曲がモノラル(チャネル数=1)だった場合、最初のチャネル(左)をJACKの右チャネル入力にも重複接続する。
  • [4/29] Gstreamerの信号処理機能を使えば、1チャネルを2チャネルにすることも可能そうだが、方法が分からなかったので、ミキサーにモノラル入力を追加し、モノラルの場合には、出力先をそこにすることにした。
    • 試しにモノラル入力に音を入れてみたら左右両方に出力されることが分かったので、こうした。
  • [4/30] Gstreamerの信号処理機能を使い、1チャネルを2チャネルにするようにした。
    • GMBのイコライザの処理を参考にして、Gstreamerの「パイプライン」というものを追加した。
    • 調べたところでは、"audioconvert ! audio/x-raw,channels=2"(チャネルを2つに増やす)というパイプラインでできるはずなのだが、どうしてもエラーになってしまう。また、"audioconvert mix-matrix='<<(float)1.0, (float)0.0>, <(float)1.0, (float)0.0>>'"(左チャネルの音を右チャネルにも出す)も駄目だった。試行錯誤の結果、"audiochannelmix left-to-right=1 right-to-right=0  ! audioconvert"(左チャネルの音を右チャネルにも出す)は成功したので、これを使うことにした。
  • 曲がステレオ(チャネル数>1)に戻った場合は、右チャネルへの重複接続※を切断し、通常の接続を行う。
    • JACK接続の切断にはjack_disconnectコマンドを使った。
    • [4/29] ※「右チャネルへの重複接続」は「モノラル入力への接続」と読み替える。
    • [4/29] jackaudiosinkの機能で接続する場合には明示的な切断手順がないため、一旦、playbinの状態を初期化してから設定すことにし直した。以下に手順を示す。
      1. playbinをset_state("null")で初期状態にする。
      2. 同様に、Ready状態にする。
      3. 出力先を変更する(port-patternを設定)。
      4. 1と同様に、Paused状態、Playing状態にする。→ 再生が再開する。
    • [4/30] GMBからは常に2チャネルが出力されるようになったので、重複接続やモノラル入力への接続切り替えは不要になった。
  • この時、通常の接続を接続する前に重複接続を切断すると、一瞬音が切れるように聞こえるので、通常の、右から右への接続を行ってから、重複接続(左から右)を切断するようにした。
    • こうすると、一瞬音が混じるはずだが、音が切れるよりはマシなので、こうした。実際には混じって聞こえる感じはしないので、一種の錯覚なのだろう。
    • [4/29] jackaudiosinkの機能で接続する場合には音が途切れないので、不要になった。

特定のアプリの音を特定の出力だけに出す。

  • PulseAudioに、新しい出力先を作る。
    • 新しい出力先を作るには、pacmdコマンドでmodule-jack-sinkをロードした(pactlでもできるはず)。
    • 例: pacmd load-module module-jack-sink channels=2 client_name=PA_alt_jack_sink  sink_name=PA_alt_jack_sink
  • 対象のアプリの音をその新しい出力に出すようにする。
    • アプリの音の出力先は、音量調節アプリ(pavucontrol)で設定すれば、それが記憶されて、以降は自動で出力されるようになるが、プログラムで明示的に接続した方が、後日、設定したことを忘れて困ることがないと思うので、次のようにした。
      • pactl subscribeコマンドでPulseAudioのイベントを監視し、対象のクライアントが接続されたら、pactl move-sink-inputコマンドで、対象のクライアントの出力を新しい出力に接続する。
      • subscribeではクライアントIDしか出力されないので、pactl list sink-inputsコマンドでクライアント名を取得して対象のクライアントかどうかを判定し、同時に得られるクライアントの出力(sink-input)IDをmove-sink-inputに指定する。
    • なお、pactlコマンドもクライアントとして認識されるので、上記処理でpactlを実行するたびに新規クライアントのイベントが生成されて無限ループになってしまうので、pactlコマンドの実行後は新規クライアントのイベントを1個読み捨てるようにした。そのため、タイミングによっては本当の新規クライアントイベントが破棄される可能性があるが、起こる確率が低いので、対処はしていない。

以下にJACKの接続例とミキサーの図を示す。

左図で、左中央の"gmusicbrowser"がGMBの出力で、上記の自動接続機能によって中央のミキサーの入力(jack_mixerのIN L,R)に自動接続される。モノラル時には、上記の変換機能によって、中央図のように、GMBの1つの出力が重複してL,Rチャネルに自動接続されて、両方のスピーカーから音が出るようになる。

[4/29] 改良後のJACKの接続例とミキサーの図を示す。

[4/29] モノラル時には、上段右図のように、GMBの出力がミキサーのモノラル入力(jack_mixerのMono_In)に入り、ミキサーによってL,Rチャネルに出力されるので、両方のスピーカーから音が出るようになる。

[4/30] モノラル時も左右チャネルから音が出るようになったので、ミキサーのモノラル入力への接続は行わなくなった。そのため、モノラル時の接続状態は上の「通常(ステレオ)再生時」と同じである。

特定アプリの音は、PulseAudioから左下のPA_alt_jack_sinkに出力され、ミキサーの入力(jack_mixerのAlt_In L,R)に接続されている(この接続は勝手に切れないので、静的な設定にしている)。ミキサーでは、この音(の中央列: Alt_In)をミュートしている(図のMボタンがミュート)ので、通常の出力(MAIN L,R)からは出ないのでスピーカーからは出ず、特定の出力(Realtek_aout)だけに出力される。ミュートを解除すれば、通常の出力にも流れて、イコライザ(jack_rack)を経由してJACKの標準の出力(system)に出て、スピーカーからも出すこともできる。

[4/30] 特定アプリ以外の音(通常の音)をヘッドフォンに出すことを忘れていたので、接続を追加した(jack_mixer: In Out L/R → Realtek_aout: playback_1/2)。

まあ、オーディオシステムは、あくまでも音楽を聴くのが目的であって、こういう作業はまったく本質ではない、自己満足とか慰みの領域ではあるのだが、自分で構築したシステム(暇さえあれば、自分のアイデアで改良できる)で音楽を聴けるのは、なかなか楽しい。そして、こんなことはWindowsやMacではまず無理(可能ではあるだろうが、手軽にはできない)だろうから、Linux+JACKにして良かったと思う。とはいえ、実は、こここに書いたことだけなら、WindowsやMacではやる必要のない作業なのかも知れないw

が、それにしても、こういう作業をすると、今まで知らなかった・やったことのないことを見つけたり気付いたりすることがあって、技術者としてはおもしろいし、いつか仕事でも使えるかも知れないから、一石三鳥だw まじめな話、Windowsだと、基本機能になければ(その基本機能もコロコロ変わる)、他人が作ったアプリを探して使うしかない(ものすごく時間を掛けて、自分で作れば別)から、おもしろくないしつぶしが効かない。あ、Mac?、あんなものは林檎社がUNIXを腐らせしまっているので、全く論外ですw

 

PS. 今の録音エンジニアなどの方には当たり前なのだろうが、今回のように、「接続を忘れてたから追加する」とかいうのがマウス1個wでできるのは、JACKの大きなメリットのように思う。昔(僕が中高大の頃)は、本物のケーブルで接続しなければならなかったから、端子やケーブルや機器が足りなければ接続できなかったし、端子の形状が違っても駄目だったし、信号レベルやインピーダンスも考慮すべきだったし、並列・直列接続し過ぎると音質が劣化するし、ミキサーを介さずに複数の出力を同じ入力に繋げるのは電気・音質的に良くないことだった。

今はそんなことを全く意識する必要がなく、自由に接続できるので、すごく便利だ。機器にしたって、「ミキサー(あるいはミキサーのチャネル)がない・足りないからから増やそう」と思っても、お金を工面して買いに行くw必要などなく、即座に無料で増やせる。もちろん、PulseAudioやALSAでもそういう変更は可能だが、GUIではできず、設定ファイルを書き換える必要があるから、「ちょっとやってみよう」という気にはならない。

そういうことがあるから、いろいろな手間や欠点があったにも関わらず、JACKに乗り換えようと思ったのかも知れない。 (4/29 10:34)

 

(4/29 5:02 加筆・修正; 13:58 改良した内容を追記; 4/30 10:16 4/29夜の改良・修正点を追記、その他、若干修正; 4/30 10:37 題を変更; 4/30 17:59 若干修正)

  •   0
  •   0

プログラムの「詰め」というのは、とにかく手間と時間が掛かる。大体、中心となる部分を作るのの10倍以上の時間が掛かるのではないだろうか。プログラムを使い物にするにはどうしても必要な作業のだが、退屈だし疲れるので、余り好きではない。それでも、なかなかうまく行かなかったことを打開するような、ちょっとしたアイデアがひらめくことがあって、それが本当にうまく行った時は楽しい。だから、いじりだすとなかなか止められない。仕事と違って、納期も予算もないのが困るw

一方、世の中には、すごいアイデアを思い付いたら、素早く目を引くデモ的な物(ポップ音楽だったら、サビとかデモ版)を作って、有名になったりお金をせしめたりしたら手放して(どこかに売って)、トンズラする(あるいは、別の物を作り出す)、スマートな人が結構居るようだが、無責任で嫌いだ。確かに、いいアイデアを出せるのはすごいと思うが、「最初にちょろっと書くのは誰だって楽しいんだよ!」とか「もう少し面倒見ろよ」と言いたくなる。

という訳で、日々続けているGPMDP (Google Play Music Desktop Player)の改良(もはや改造と言った方がいいだろう)は大分いい感じになってきた。まだ詰め切れていない点や不具合や抜本的な改良案もあるのだが、おおよそ7.5割くらいの出来になって、普通に(これには「変わったことはしてはいけない」という意味もあるw)音楽を聴けるレベルになった。具体的には、GMBだけで聴いている時と使い勝手での違和感がほとんどなくなった。例えば、GMBのリモコンで操作できるので本当に便利だ。実際に、昨夜からは、(実装・修正するだけじゃなくて)GPMの曲を聴くのに使っている。

問題だったユースケース(GPMDPをどういうふうにGMBと統合・機能分担して使うか)も、作業しているうちに大分詰められた。基本的には、GPMDPは曲の検索に使い、GPMDPの再生ボタンを押したら、実際の再生や再生の操作はGMBで行おうと思っている。まだ完全にシームレスになったとは言えないが、なかなかうまく統合できたと思う。

今週はさまざまな改良や修正をしたのだが、主にGPMDPとGMB (gmusicbrowser)との連携動作(例: 曲の追加や変更の同期)に関するものなので、見た目では、先週と比べて目立った違いは余りない。大きな違いは、(実際に曲を再生している)GMBで次の曲に移ったことがGPMDPにも伝わって、曲情報やジャケット画像が更新されることだ。以下にデモ動画を置くので、興味のある方はご覧頂きたい。

画面左半分はGMBの、右半分はGPMDPのウインドウである。GMBで再生中の曲が次に変わると、少ししてから(その次の曲の取得と処理の時間: これは如何ともし難い)GMBにその次の曲が追加され(画面左下、5曲目)、GPMDPの曲情報やジャケット画像(画面右中央)が更新される。

下の動画は、力技でやっているうえに、まだバグがあって、(いつ何が起こるか分からず、)ドキドキする機能なのだが、GMB(画面左下)でリスト中の前の曲をダブルクリックして移動した場合でも、GPMDP(画面右中央)も戻るようになっている(戻るのが遅いのは愛嬌w)。もちろん、取得されている範囲で、先の曲に進むこともできる。

リストの最後(7曲目)に2曲目の曲が追加されるのはバグである。難しい。。。

冷静に考えれば、再生中の曲のGPMDPへの同期なんて、音楽を聴くには不要な機能で、本当に飾りなのだが、「おもしろそうで、不可能でないならやってみたい」という、技術者の無駄なこだわりがあって実装したw

(10/1 6:38 わずかに修正)

 

PS. プレーヤーにGMBを使ったのは正解だった。最初は単純な再生だけを考えていたので、alsaplayerなどの軽いものにしようかと思っていたのだが、機能的に不十分な点があったので、最初からGMBで試した。また、GMBはコマンドラインにPerlのプログラムを指定して実行できるという、夢(麻薬)のような機能があり、それでGMBの内部データにアクセスできるので、かなり役に立っている。もう開発は停まっているようだが、セキュリティホールになるので、公開版に入れ続けるのは難しいかも知れない。

PS2. かなりハードルが高いのだが、将来的には、GPMDPじゃなくて、ブラウザのGPMのページから直接GMBと連携できないかと思っている。GPMDPが必要なのではなく、GPMのページ内の要素にアクセスするために使っているだけなので、ブラウザのアドオンか何かでできるのではないだろうか。

同時に、可能な限り機能を外部に出して、JavaScriptの部分を減らして開発効率を向上させ、GPMのページ構成になるべく依存しないようにもしたい。

とは言え、本当にやりたいのは音楽を聴くことなので、苦労してそこまでやることもないかとも思っている。

(10/1 17:44追記) と書きつつも、(だるくてドライブを止めたため、)暇だったので、ちょっとだけ試してみた。一番最初に気になった、GPMのページ中の再生ボタンを押したらGMBに曲を送れるようにする時に必要な、ボタンのイベントハンドラを変更できるかを試した。

最初は、安直に、ローカルのHTMLでiframeでGPMのトップページを読み込んで、JavaScriptで書き換えればできるだろうと思ったのだが、駄目だった。それから、いくつかのライブラリやAJAXやjQueryまで試したが、駄目だった。

どうも、セキュリティ上の制限のようで、ローカルのファイルからGPMのサイトを呼び出すのが駄目なようだ(おそらく、元がローカルファイルじゃなくても、サイトをまたがるようなことが駄目なのだろう)。それを回避したかったのだが、できなかった。この制限は「同一生成元ポリシー」というものらしく、かなり昔からあるようだ。

それで、一旦、ローカルのHTMLを使うのは諦めて、(GPMDPを改造して使う前提で、)GPMのページ中の再生ボタンのイベントハンドラを変更できるかを試した。JavaScriptには疎いので、それすらも苦労したが、できた。getElementById()で再生ボタンの要素を探して、onclickメンバにハンドラを設定すれば良い。以下のようにすると、GPMの再生ボタンを押すと関数click_func()が呼ばれる。

var elem= document.getElementById("buttonContent");
elem.onclick= click_func;

function click_func() {...}

onclick(onClick)は属性ではないとのことで、setAttribute()で設定しても呼ばれないことに気付かず、苦労した。あと、ボタンの本来のハンドラが依然として有効(どうやっているのか不明)なのがちょっと気に入らないが、まあ、細かいことだ。

(10/2 7:08追記) その後、GPMの再生につながるボタンは山ほどあるので、それらを全部書き換えるのは現実的でないことに気付いた。それらの呼び先を修正するのも困難なので、やっぱり、低レベルなところはGPMDP(実際には、その下位のライブラリ)に依存するのがよさそうだ・・・

  •   0
  •   1

GPMDPの改良。音量の正規化の改良について考えていたら、確か、以下のようなことだったと思うが、GPMDPでなく、外部プレーヤーで再生した方がいいのではないかということになった。

  • GPMDPの構造上避けられない、曲の開始と同時に一時停止しても先頭が一瞬再生されることがある問題は、外部プレーヤーを使わないと解決できない。
  • 再生ゲインの計算のために曲のファイルをキャッシュしているのだから、そのファイルをVLCやgmusicbrowser (GMB)などの外部のプレーヤーで再生することができる。
  • 再生ゲイン対応のプレーヤーなら、音量(ボリューム)の設定やファイルにを再生ゲインを乗算しなくても、再生ゲインタグに設定するだけで、プレーヤーによって反映されるのも良さそう。
  • GPMDPは使い勝手がいいとは言えないし、リモコンを2個にしたり、2つのプレーヤー間の切り替えもしたくないので、操作性を改善する点でもGMBで再生したい。

いずれにしても、昨夜までに構想が練り上がった気がしたし、基本的なところは容易にできそうだったので、今朝、GPMの曲をGPMDPでなく外部プレーヤーで再生できるようにしようとする作業を初めてしまった。そして、確かに、再生できるようにすること自体は簡単だった。14時前には、GMBで再生できるようになった。

GPMの曲をGMBで再生

図の左上はGMBのミニプレーヤーで、右はGPMDPのウインドウである。GPMDPが再生しているように見えるGPMの曲は、実際にはGMBで再生されている。その証拠に、双方で同じ曲・アルバムになっているし、僕はこのアルバムは持っていないし、GPMDPの再生時間は0だが、GPMは0ではない。

が、やっぱり難航し、この時間になっても終わっていない。残っている難しいことは、以下である。

  • 次に再生する曲を途切れないようにGMBに送り続ける(今は、最初の1曲の再生が終わったら停まってしまう)。また、ギャップレス再生のためには、再生中の曲が終わる前に送る必要がある。
  • GMBとGPMDPの連携 (例: GMBの再生が終わったことを検出して、次の曲を再生開始する)
  • GMBとGPMDPの操作の統合 (例:GPMDPで一時停止したら、GMBを一時停止させる)。GMBに統一すればいいのだが、曲の検索など、どうしてもGPMDPでしかできないことがある。まだ、ユースケースの検討が充分でないので、方針が固まっていないせいもある。

でも、今日のところは、目論見どおりGMBで再生できたので、良しとする。

(気が向いたら、詳細を追記します。)

(9/24 21:35追記) どうにかこうにか、次に再生する曲をGMBに送り続けられるようになった。GMBも自分で作ったGPMDPの追加プログラムも、想定外の動きをしたりして、なかなか大変だった(おもしろかったけどw)。

GPMの次の曲を自動でGMBに追加

図の左はGMBのウインドウで、右はGPMDPのウインドウである。GPMDPのプレイリストの、現在再生中の次の曲がGMBに自動的に追加され、連続再生できるようになった。

余談: 上のジャケットの工藤静香、なんかお化けみたいだ。。。

動き出したばかりで、まだまだ荒削りで、さまざまな不具合はあるが、とりあえずは音楽が聴ける状態になったので、一段落だ。それに、(GMBの)リモコンで一時停止などの操作ができるのは、すごく便利だ。

不具合の例:

再生していると、再生中の次の曲以降も勝手にGMBに追加される。まあ、悪いことではないが、想定外の動作なので複雑な心境だ。そして、それに伴ってGPMDPの下部のプレーヤー部分は、まだ再生していない曲になってしまう。しかも、それは上側のキューの再生中(と思っている)曲とも違うのが解せない。

  • 再生中の曲: "Here comes the Sun"
  • GPMDPが再生中(と思っている)曲: "Let it be"(上部)、「二人静」(下部)

細かいことが多いので、先は長そうだw

PS. 今日からか、URLに"?hl=en"を付けても無視するようになったようで、日本語で表示されるようになってしまった。やっぱり、ネットサービスはvolatileだなあ。 ← URLの書き方を間違えていたようだったので、撤回する。 (9/25 20:26)

(9/25 22:56 わずかに修正、余談を追加)

  •   0
  •   1

先週末に、gmusicbrowser (GMB)に、デスクトップウィジェットのアルバムアートを押すと、メインウインドウをアイコンにしたり戻したりする機能を付けた。GMBは、メインウインドウを閉じた時に、タスクトレイに最小化(アイコンにする)できるのだが、タスクトレイアイコンが小さくて押しにくいので、もっと楽に操作したかったのだ。

実装は意外に難航した。普通に最小化したのでなく、タスクトレイに最小化したのを復帰させると、その前より幅が広くなるという問題が解決できなかった。それで、普通に最小化した時にしか復帰できないようにした。

そして、今朝気付いた。実際には、GMBをタスクトレイに最小化しない設定にして(その時は間違って閉じないように注意する必要がある)、普通のアイコン(小さくない)で操作すれば充分だし、その方が操作が一貫している。あるいは、メインウインドウを閉じた時に、タスクトレイでなく普通に最小化するように変更するほうが、ずっと簡単だったような気がする。それに、今気付いたが、この機能では、アルバムアートがない場合は操作できないという欠点がある。

本当の問題は、「タスクトレイアイコンが小さくて押しにくい」というだけのことだったのだから、何か押しやすいものがあれば良かった訳で、それは(既にある)普通のアイコンそのものなので、苦労して新しい機能を作らなくても良かったのだ。

まあ、折角作ったのだから戻さないでおこう。そして、後で、幅が広くなる問題を解決したい。これは、GMBの起動時にも起こることがあるので、何かがおかしいようだ。

そして、物でもソフトでもシステムでも世の中の仕組みでも、安易にいろいろな機能や施策を追加しがちだが、その前に、本当の問題をもっと良く考えた方が、複雑にならず、コストも掛からず、新たな問題も生まれないのだろうと思う。とは言え、安易に見えるけど、実際には、多くの「頭のいい」人たちがいろいろ考えた末におかしくなってしまうことも多々あるので、なかなか難しい。

PS. 世の中の仕組みなどは、実際には、「いろいろ考える」方向が意図的に異なっていて、本当の問題は分かっているけど、根本から解決する気は毛頭なく、「頭のいい」人たちの都合のいいように「解決しようとしている振り」をするように見せて、みんなを欺いていることが多い気がする。

PS2. 本題のGMBだが、昨夜、メインウインドウの閉じるボタンを押した時に、タスクトレイでなくアイコンに最小化することができるように変更した。また、閉じた時の動作設定に、従来の動作(閉じた時にタスクトレイに最小化または終了)に加えて、アイコンに最小化する動作も追加して選択できるようにした。これで、間違って閉じるを押して終了することもないし、ウィジェットでもアイコンでも押せば復帰できるから、操作も統一できた。(1/25 4:47)

設定ウインドウの追加した部分

  •   0
  •   1

GMBでアルバムアートの検索をするプラグインPicture finderは、USのYahoo!でしか動かない。Googleなどを選択しても、結果が何も出ない。

APIが変わったのだろうと思ったが、実際に調べたら、確かにGoogleの検索結果のフォーマットは変わっていた。それで、とりあえず、Googleで検索できるようにした。

新しいフォーマット(構造化されたデータのようだ)に合わせて、fetch_cover.pmを修正した。まだまだPerlは良く分からない(し、分かりたくもない)が、既存のソースから類推してやってみたら、出来た。参考までに、主要な変更点を載せようと思ったのだが、良く考えると、日本のユーザーはとても少ないだろうし、分かる方は既にやっているだろうから、止める(もし欲しい方がいらっしゃいましたら、お知らせ下さい。無保証にて差し上げます)。

日本のYahoo!にも対応したかったが、面倒だし、中で使っているのはGoogleなので、止めた。他のサイト(例: last.fmやAmazon)にも対応したかったが、やっぱり面倒なので、とりあえず、Googleだけで満足することにする。

ただ、そのGoogleにしたって、彼らの心変わりによって、いつか変更が要るようになるのだろうな。でも、出力がHTMLである限りは大丈夫だ。でも、それもそのうち変わる気がする。。。

  •   0
  •   1

 

この週末は、デジカメからの画像取り込みプログラムの改良(同一カメラで1万枚以上への対応)や掃除や散歩やドライブなど、有意義なことをしようと思っていた。

のであるが、実際には、したかったことは何もできなった。

昨日は、疲れのせいかだるかったので、家にこもってEvernoteからDropbox Paperへの移行をした程度だ。移行は、本文はコピー・ペーストでできるのだが、埋め込んだ画像はできないので、それを手作業で復元する(元のファイルがPCに残っているのはそのまま、オリジナルがあるものはリサイズして、Paperに埋め込む。ないものは、EvernoteからダウンロードしてリサイズしてPaperに埋め込む)必要があって、結構時間が掛かった。日記1個に30分くらい掛かった。全部で7本を移行して、日記の残っていた分は終わった。が、あとドライブ関係が44本もあるので、移行プログラムを作りたくなって来た。

今朝は、「今日こそは」と思っていたのだが、思わぬ落とし穴にはまった。発端はgmusicbrowser(GMB)の、次のリストだ。

Something wrong!

何の変哲もない、普通の(と言うには重複が多いがw)ビートルズのアルバムの一覧の一部に見えるが、常々感じていた不満(何が悪いかすぐに気付いた方は、ちょっとした愛好家ですね)を思い出して、余計なことを考え付いてしまった。

同じ年に出たアルバムをちゃんと発売順にできないものだろうか?

説明すると、上の図の上半分の黄色いのは"Magical mystery tour" (1967年11月発売)、下半分のごちゃごちゃしたのは"Sgt. Pepper's lonely hearts club band" (1967年6月発売)である。それぞれ同じ年に出たのではあるが、気に入らないことに、リストには発売の逆順に出ているのだ。タイトルがアルファベットの順だとM→Sなので、上のように並んでしまっているのだ。

まあ、「そんな細かいこと、自分で分かってればいいじゃん」とは思うし、今まで我慢して来たのだが、他の例では、デビューアルバムの前にセカンドアルバムが出ることもあった覚えがある。さすがにそれはどうかと思う。要は、元になったMP3の仕様(ID3)が安直で、現実に対応できていないのだ。それを見なかったことにして使い続けるのは、技術者としてはやっぱり嫌なのだ。

技術的な問題以外にも、仮に上のリストの順で「全曲再生」したら、曲順がおかしくて、それこそ話にならない。

ソートに使われる発売日の情報は音楽ファイルに格納されているのだが、基本的には年だけしか格納できない。せめて月まで入れられればいいのだが、仕様上は無理だ。

それで、いくつかの案を考えた(それだけで数時間掛かった気がする)。

  1. 余り使っていないフィールド(例: Mood(TMOO), Grouping(TIT1), Rating, Discname(TSST)など)を流用する。
  2. GMBにカスタムフィールド(例:リリース日(例: "19670601"), 同じ年の時の順番(例: 1, 2))を追加する。
  3. GMBにAlbum sort order(TSOA)フィールドを実装する。
  4. GMBに他のフィールド(例: Original release time(TDOR))を実装する。
  5. 新しい独自フィールドを実装する(TXXXを使う)。
  6. GMBに2個の追加フィールド(1: リリース日、2: リリース日があればリリース日、なければ年)と、後者のフィールド(2番)を使うソート条件を追加する。

検討したところ、最後の6が残り(正確には、1-5の検討の結果、6のように2段階にしないとうまく行かないことが分かった)、「ちょっと試しに」実装に着手してしまったのが運の尽きである。半分は意外にすんなりできて、下のように、「リリース日または年」のフィールドが表示できたのだが、例のリストのソート順に反映することができなくて、(昼寝もしたけど)気付いたら外は暗くなっていて、とてもがっかりした。

「リリース日または年」が出るようになった (年はアルバム名の右の<<の右にも表示されている。上のエントリのアルバム名とリリース日は、テスト用の架空のもの)

随分時間を掛けてうまく行かない理由を調べたのだが、どこを直せばいいのか、まだ分からない。ソート時に、追加したフィールドをどうしても参照できない。この辺りのプログラムは、他と比べて今ひとつ直感的でなくて分かりにくく、GMBの暗部を見た気がした。まあ、何にでも触れて欲しくないことはあるだろうから、仕方ないね(僕のプログラムにだって、結構ある)。

試行錯誤の結果、何がどうなっているのは分からないが、どうにか、リリース日(なければ年)でアルバムをソートできるようになり、問題の"Magical-"が"Sgt. Pepper's-"の下に出るようになった。

リリース日でアルバムをソートできるようになった。

ところが、一難去ってまた一難。今度は、次のような、ちょっと困った状況に陥ってしまった。

"Baby it's you"はどこに置けば?

一番上の"Baby it's you"は、近年発売されたシングルなのだが、録音は1963年なので、入手した時に年に録音の年を入れた。これをどこに配置すべきなのか、結論が出ない。正しいリリース日にすると、初期の曲なのに最後の方に出るし、録音日にすればそれらしい場所に出るが、リリース日を入れるべき箇所に録音日を入れるのは掟破りな気がする。

規則に従ってリリース日を入れて、最後の方に出すのがまっとうなのだろうが、もっといい規則を決めたいところだ。「録音年」のフィールドを作ると、何かいいことがあるだろうか? (12/13 23:00)

"Baby it's you"の「リリース日」の解決策が見つかった。放送日をリリース日に入れることにした。ただ、シングルとして発売されたこの曲は、アルバム"Live at the BBC"に入っているのとはバージョンが違うので、調べても放送日が良く分からない。ただ、録音日は3日しかなく、そのうちアルバム版と同じ日に収録されたと推測できる。そして、もしかしたら放送されなかったのかも知れない。が、いくら考えても埒が明かないので、アルバム版の放送日とした。(12/15 5:09)

  •   0
  •   1

以前からやりたかったのだが、gmusicbrowser(GMB)のレイアウトと使い勝手を改良した。Perlで書かれたGMBのプログラムや、レイアウト設定ファイルを、見様見真似で試行錯誤して、なんとかした。主な変更点は以下のとおりである。

  • メインウインドウ (ベース= "Lists, Library & Context")
    • 現在の再生ゲインのモードを、"--"(off), "T"(トラック), "A"(アルバム)のように表示できるようにした。アイコンでも表示可能なのだが、適当な画像ファイルがなかったので、とりあえず文字にした。この部品は新たに作った。
    • 上記再生ゲインの表示を押すと、off → トラック→ アルバム → offのように順にモードが切り替わるようにした。
    • タイトルなどの文字やアルバムアートを大きくし、パーツの配置を改良した。
    • ボリュームを水平のスライダーにし、音量の値も表示するようにした。ボリュームは実際にはほとんど操作しないのだが、現在の音量が一目で分かるのはいい。
  • デスクトップウィジェット (ベース= "screenlet")
    • 再生位置のバーの右に、再生順序(シャフルなど)、フィルタ(自動プレイリスト)、キューの状態(次の曲の指定の有無、再生中の曲が終わったら停まるなど)、再生ゲインのモードを追加した。これは、メインウインドウに表示されているものと同じである。
    • 再生位置のバーの中に再生位置(時間)を表示するようにした。
    • タイトルなどの文字を大きくし、発表年も表示するようにした。
    • 文字領域の背景を不透明にした。

まだ収まりが悪いところや色がイマイチなところがあって、いろいろ直したいのだが、かなり僕の理想に近くなった。特に、デスクトップウィジェット(MusicBeeのコンパクト/ミニプレーヤーに相当)で再生ゲインのモードが表示・切り替えできるのは、MusicBeeではできなかった(要望しても対応してもらえなかった)ことで、長年の悲願だったから、結構嬉しい。

残念なのは、以下のことはすぐにはできないことだ。どれも、GMBの構造上、設定や小さい変更での対応は困難なようだ。

  • メインウインドウの曲一覧などのフォントが(設定では)変えられない。見難くはないから、とりあえずは問題ないのだが、中国(台湾?)系のフォントのようで、例えば、「福」の偏が「示」になったりしているのがちょっと気になる。
  • (特にデスクトップウィジェットで、)タイトルなどが長い場合に、複数行での表示ができない。

それでも、こうやってプログラムや設定を変えることでかなりのカスタマイズができるところは、完全にMusicBeeを超えている。特に、レイアウトの設定ファイルは独自の言語のようになっているのだが、もしそうでなかったら、こんなに自由なカスタマイズはできなかっただろう。その点は(最初は訳が分からなくて戸惑ったものの)感心している。それで、偶然にせよ、なかなかすごい「原石」を見つけたものだと自画自賛している。

あと、PerlでGUI(GTK)のプログラムが作れるのは、PHPにはできないことなので、すごく羨ましい。それにしても、どうしてPHPではできないのだろうか?

試行錯誤して、なんとか、デスクトップウィジェットでタイトルなどが長い場合に改行できるようにした。GMBがテキスト表示に使っている、GTKのLabelウィジェットのワードラップの機能を使うようにした。これには、設定だけでなくGMB本体の改造が必要だった。

アルバム画像下の曲情報は、以下のようにデスクトップウィジェットのレイアウトファイル(desktop.layout)に記述して表示している。

HBtrk_info= 8Text(font= 'Noto Sans CJK JP Regular 10',
color=black, opacity=1,

width-chars=32, wrap=1, wrap-mode=word,
markup="$title
<span size='xx-small'>\n\n</span>
$artist<span size='xx-small'>\n\n</span>
$album ($year)")

下線部で最大幅とワードラップを指定しているが、これをサポートする機能をGMBに追加した。GTKを良く理解せずに作っているので、最大幅はピクセル数で指定したいができておらず(そのため、文字数によって、右側に微妙に空白ができたり、ウインドウの幅が広がったりする)、文字の大きさや空行(無理に作っている)の高さなど、いろいろ改良・調整したい点はあるが、とりあえず、やりたいことができたので、うれしい。(11/9 23:53)

空行の高さは、タイトルなどの各項目を別のLabelにして、パディングを指定して縦に並べることで解決した。ただ、最後の要素(アルバム)にはパディングを指定しなくても隙間が空くのが謎だ。

また、右側の微妙な空白は、width-charsを指定しなければできないことが分かった。ただ、その場合、max-widthやmaxwidthを指定してもウインドウの幅が広がることがあるのが謎だ。(11/10 6:22)

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88_2016-11-10_06-03-57

行間を改良

HBtitle= 8Text0(font= 'Noto Sans CJK JP Regular 12', color=black, opacity=1, \
width-chars=32, wrap=1, wrap-mode=word, \
markup="$title")
:
VBmain = Cover(yalign=0, forceratio=1,hover_delay=1, \
hover_layout_pos=.5w x w,hover_layout=play_controls) \
8HBtb_ind HBtitle 4HBartist HBalbum

思わぬ欠点が見つかった。ウインドウのサイズが広がった後に、行数が少なくなると、下の方が空いて間抜けになってしまう。ちょっと調べたところでは、gtk_widget_set_redraw_on_allocate()で直りそうな感じだが、さてどうだろう? (11/10 19:46)

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88_2016-11-10_19-43-56

間抜けな状態

更に試行錯誤したのだが、なかなか広がったウインドウは小さくならない。そこで、次善の策として、アルバムアートと曲情報の部分で余白を吸収するようにしてみたら、今までよりはマシになった。また、どういう訳か、アルバムアートが段々大きくなることがあったので、サイズを厳密に指定した。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88_2016-11-10_22-02-22

余白が目立たないようにした。

HBcover= Cover(minsize=250, maxsize=250, forceratio=1, \
hover_delay=1,hover_layout_pos=.5w x w,\
hover_layout=play_controls)
:
VBmain = _HBcover 8HBtb_ind _VBtrk_info

こういう試行錯誤って、GMBやGTKやPerlをもっとちゃんと勉強すれば効率良くできるのだろうが、趣味なのでそこまでの気力は出ない(もし、PHPでGTKが使えるのなら、俄然やる気が出るのだがw)。逆に、いろいろつまずいたり、回り道・寄り道しながら自分の希望を叶えていくのがおもしろいと思う。そして、仕事じゃないから最短経路をとる必要はなく、こういう遊びがかえって仕事のヒントになることもあると思う。(11/10 22:17)

(Labelウィジェットのワードラップ機能が今ひとつのせいなのか、)改行時に文字列右側にできる無駄な空白が嫌なので、ちょっと頑張ってTextViewウィジェットを使えるようにして、解決した。

ただし、どういう訳かTextViewの背景色を設定することが難しいようなので、とりあえず全体を白にした。それでも、どういう訳か微妙に色が違っていた(TextViewがわずかに黒くなっていた)ので、それに全体を合わせた。が、それでもまだ合わないようだ。あと、上下に広がったウインドウが狭まらないのは相変わらずである。そこら辺は今後の課題としても、かなり良くなったのは確かだ。

あと、TextViewにしたことで、曲名などをマウスで選択してコピーすることができるようになった。これもMusicBeeで叶えてもらえなかった(「ホットキーでできるからいいでしょ」と言われた)ことなので、感慨深いものがある。

ただし、曲名とアーティストとアルバム名をそれぞれ別の要素にしているので、コピーも別々にしかできない。とある理由(TextViewの中では、フォントサイズを容易に変更できない)で別々にしたのだが、できれば何とかしたい。でもまあ、選択・コピーできないよりはずっといいだろう。

ちなみに、デスクトップウィジェットのレイアウトファイル(desktop.layout)でのTextViewの指定は、以下のようになる(タイトル表示の部分)。

HBtitle= 5TextView0(font= 'Noto Sans CJK JP Regular 12', \
color=black, bgcolor=lightgray, minwidth=200, maxwidth=250, \
wrap-mode=word, markup='%t')

(11/11 21:18)

ちょっと苦労したが、曲名とアーティストとアルバム名を同じTextViewに入れられた。insert_with_tags()を使い、TextViewの中でフォントサイズを指定するようにした。これをTextViewのサブクラス"SongInfoView"と名付け、以下のような指定で曲情報が出るようにした(フォント指定は未実装)。

HBsong_info2= 5SongInfoView(font= 'Noto Sans CJK JP Regular', \
color=black, bgcolor=lightgray, minwidth=200, maxwidth=250, \
wrap-mode=word)

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88_2016-11-11_23-15-12

全部の曲情報を一度で選択できるようにした。

まったく"The long and winding road"だが、いろいろアイデアが出て楽しい。(11/11 23:22)

選択はできるが、Ctrl-Cではコピーできないというオチがあった。右クリックでメニューを出して"Copy"を選択すれば可能なので、キーを登録すればいいのだろう。やっぱり長い道のりだw (11/11 23:51)

ショートカット(あるはアクセラレーション)は有効にならず、広がったウインドウは、どうしても縮まない。前者は、どうもOSレベルの設定が関係しているようだ。もちろん個人の設定ファイルもあるようだし、「デスクトップ環境」なのだから、その方が筋がとおっているのだが、アプリだけで手軽に対処するのが難しいし、ログインし直さないと試せないので面倒だ。そして、後者は深い謎だ。八方手を尽くしたが、どうにもならなかった。GTKをちゃんと勉強しないと駄目かも知れない。

そして、昨夜からの収穫は、(外見上は)本当に微妙な修正だ。タイトルなどを一度にコピーできるようにした時に、行間が数ピクセル広がってしまったのを直した。なんか、大昔、LaTeX(って知ってる方はいますか?)で資料を書いて、微妙なところを何度も直して(印刷して紙を無駄にして)、最後にできた紙(の内容でなく外見)を見て悦に入っていた頃の雰囲気を感じているのだが、なんとも複雑な気分だ。まあ、僕は賛同していないが、神は細部に宿るのかも知れないし、趣味だからいいよねw

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88_2016-11-12_17-39-53

行間を調整

そして、何度もくどいのだが、(謎はあるものの)こうやって自分でちょっとプログラムを書いて自分好みに自由に改造できるのは、ありがたいし楽しい。ただ音楽を聴けるだけじゃなくて、その道具に手が入れられるようになったのは、常に歯痒かったMusicBee/Windows時代に比べるとすごい進歩だし、結構感激している(酔ってるせいもあるが)。これは、GMBの基本思想が良く、オープンソースにしてくれて、今の実装が悪くない(Perl自体が読みにくく、コメントは少ないけど、まあ酷くはない)ことに加えて、スクリプト言語(Perl)/Linuxベースであることもある(やっぱり、腐り切った窓でC#なんて使ってられない)。そして、こういう機会を与えてくれた、gmusicbrowserの作者のQuentin Sculoには本当に感謝している。いつか、改良・変更部分を整理して提出したいと思っている。(11/12 18:28)

ここからはいつものディスになるのだが、僕がMusicBeeを止め(られ)た原因は、作者の(勝手な)方針について行けなかったということだ。作者本人が個人で作っているのだから、何をしたって自由なんだろうけど、ただ、他人の意見を余り聞かず、ソース公開せずに他人の力をほとんど借りようとせず、Windowsにべったり固執し、全く必要がなくメリットが感じられないことを「改良」して、バージョンアップしたと言って悦に入っているのは、MicrosoftやAppleのように筋が悪いし、もし彼がソフト技術者だったら、「終わっている」と思う(一言で言えば、ガキだ)。途中まではいい方向に進んでいたし、機能的には他を寄せ付けないのに、とても残念である。(11/12 18:42)

試行錯誤の結果、デスクトップウィジェットのサイズ(特に高さ)が行数に応じて縮まるようになった。ごく当たり前に、ウィジェットのresize()メソッドに小さ目のサイズを指定すれば縮んだ。以前にも試したのだが、ウィジェットのnewの中から呼んだのが失敗して、それでresizeは使えないと思い込んでいたのだ。どうも、newが終わらないとうまく動かないメソッドがあるようだ。もちろん、newの中でresizeなんてするのは良くないのだが、GTKやGMBでウィジェットのメソッドの呼び出し順序が良く分かっていないので、newの時に描画する文字列を設定することになって、結果的にresizeもしている。(11/14 22:31)

その後、ワードラップでの改行の高さが若干高く(広く)て下の要素との区切りと見分けが付きにくい場合があったので、微妙に改良した。更に、プレイリストやアルバム中の何曲目を再生しているかを、"3/10"のように表示できるようにした。(11/18 21:52)

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88_2016-11-18_21-48-21

微妙な改良

 

※まずいないとは思いますが、もし、日本語が読めてGMBを使っていて、「ここの投稿を参考に改造したいけど、詳細が書いてなくて今ひとつ分からない」という方がいらっしゃっいましたら、可能な範囲でお教えしますので、お知らせ下さい。でも、プログラミングのスキルがあることが前提です(申し訳ないですが、「コピペでなんとかしたい」という方は駄目です)。そして、そういう方は、自分でできてしまうような気がします。(11/10 19:31)

(11/11 10:14 わずかに修正, 11/12 追記)

  •   0
  •   2

先週、GMB(gmusicbrowser)の音楽ファイルの同期プログラム(sync-music)の高速化のアイデアがひらめいたものの、疲労や多忙ややる気がでなかったりで、なかなか実装できなかったのだが、昨日と今日で何とか作り込めた。途中では期待したほどの結果が出ず、がっかりしかけたのだが、その原因が分かって、最終的には期待以上の結果になった。

高速化の内容と効果

  1. 音楽ファイルのタグ情報を、GMBから同期プログラムに渡す。→ ファイルのタグ情報をsoxiやexiftoolなどの外部プログラムを使わずに取得できるので、その分高速になる。
    1. GMBでの同期開始時に、同期対象のファイルの同期に使うタグ(アーティスト、アルバム名、トラックの再生ゲイン、埋め込みアルバムアートの有無)の値をCSVに入れて、同期プログラムに渡す。
    2. 同期プログラムは(音楽ファイルを開かずに、)CSVの内容から、同期先ディレクトリ、音量調整量、アルバムアートの埋め込みの必要性を判断する。
  2. アルバムアートが埋め込まれているファイルには、アルバムアートを埋め込まない。→ アルバムアートを縮小して埋め込まなくて済むので、その分高速になる。

結果(ポップス全10677曲、非実行(エンコード・ファイルコピーを行わない)での同期= 全く更新がない場合を想定した所要時間):

  • オリジナル(V1): 93秒 (8.7ms/ファイル)
  • 高速化後(V2): 8秒 (0.75ms/ファイル)

先週の「今の数倍〜10倍高速になりそう!」の目論見を超えて、

約12倍速となった!

(ただし、非実行で速度を比較したので、上記2番の成果は反映されていない)

更新がない場合に8秒なら許せるし、MusicBeeと同じくらいの速度になったと思う。高速に動くプログレスバーは気分がいいものだ。

高速化ってのは、「血のにじむような」というと言い過ぎだが、まあ、堅く絞った雑巾から更に水滴を絞りだすようなところがある。実際、「これ以上は無理」と思えても、更に良くなることがあって、そこがおもしろいのだが、結構精魂を使い果たす傾向はあるw

V2のその他の機能の実装と動作確認と修正が終わり、さっそく車で使っているUSBメモリに同期しているのだが、そのメモリ(Lexar 128GB)が激遅で、エンコードしたファイルを書き込むのにものすごく時間が掛かって、並列処理も高速化も台無しというオチになった(爆) もしかしたら、メモリが壊れ掛けているのかも知れない。(11/5 16:24)

USBメモリへの同期は(11/6の)明け方に終わっていた。約11時間(3.8秒/ファイル)掛かった。(エンコード時に)PCのSSDに対して書き込む場合には約1秒/ファイルだったので、このメモリは約4倍遅かった。そして、実行ログを見たら思わぬ不具合が起きていた。同期したファイルの一部を削除していたのだ。バグかと思って調べても、なかなか原因が分からなかったのだが、結局はWindowsのファイルシステム(VFAT)の異様な仕様のせいであることが分かった。一つは、ファイル名の最後の"."を無視するのと、もう一つは、ファイル名の型(大文字/小文字)を無視するというものだ。以下に例を示す。

  • "The Journey Continues..."というディレクトリを作ると、実際には"The Journey Continues"ができる(最後の"..."がなくなる)。
  • "WINK MEMORIES"というディレクトリが既にある場合に"Wink Memories"というディレクトリを作ってもエラーにならないが、実際には既にある"WINK MEMORIES"に統合されてしまう。

前者は意味不明だし、後者はいまだにそんな古臭い仕様を残しているのに呆れて頭に来る(笑えるさすがなことに、高慢な意識高い林檎社のデスクトップOSも、Unixがベースなのにわざわざ型を無視していたっけ)。一般人は大文字と小文字の区別ができないとでも思っているのか? 今使っているのはLinuxだが、互換性維持のために、そういう下らない仕様も実現しているのだろう。

問題に対処して確認していたら、ドライブに出ようと思っていた時間(7:30頃)を過ぎてしまった。そして、疲れたので、今まで寝ていた。動作確認を兼ねて、午後には出掛けたいな。(11/6 11:45)

結局、GMBの改良(のための試行錯誤)をしているうちに億劫になって、ドライブには行かず仕舞いになったが、駐車場でエンジンを掛けて再生確認して、問題なかった。音もアルバムアートも出た。何となく音質が悪い気がしたが、ヘッドフォンで聴いた時には問題なかったので、疲れとか気のせいだろう。これでひとまず、音楽のWindows(MusicBee)からLinux(GMB)への移行は完了だ。あとは、おいおいGMBに細かい改良をして行こう。

でも、その前に、写真(画像)のLinuxへの移行(ACDSee → digiKam)を完了させたい。(11/6 17:33)

(11/5 18:21 加筆, 18:43 誤りを修正, 11/6 11:45 加筆, 12:58, 15:17 加筆修正, 17:33 車での確認結果他を追記)

 

PS. 途中で余り高速化できなかったのは、並列化処理の検討不足だった。並列化の時は、複数のファイルを同時にエンコードするのだが、同時に実行している数が最大値に達した場合に、更に処理を開始するには、どれかが終わるまで待つ必要がある。待つ時、一定の時間間隔でどれかが終了したかどうかを確認するのだが、その間隔が500msと長かったために、高速化が妨げられていた。

まあ、実際にはエンコード(数秒掛かる)するので、500msでも問題ないのだが、ファイル数が多くて更新がほとんどない場合にはかなり効いてくる。

PS2. こういうアイデアを入れて、最初に動かした時に結構うまく行くと、うれしくなる。「こいつ、動くぞ」と脳内に浮かぶかも知れないw

  •   0
  •   1

MusicBeeからgmusicbrowser(GMB)への移行は、かなり終わりに近く、もうMusicBeeは関係なくなって、GMBに閉じた話になっている。ただ、いつものことだが、ゴールは見えると遠ざかるもので、動作確認でいろいろな問題が出て来て、なかなか終わらない。予想外にも今日はほとんど全部使ってしまったのだが、あと少しでようやく本物のUSBメモリで試せそうな感じだ。以下に、つまづいたことを書く。

全体的な動作確認

ファイル名のクォート("や`や/などの特殊な文字を無効にする処理)がまだ不完全だった。これの対応はどうも場当たり的で良くないので、根本的に別の方法にした方がいい気がする。同期プログラムからOSのコマンドを呼ぶ(system()など)時に、ファイル名をシェルに解釈させないようにすれば、クォートしなくてもうまく行くように思うので、あとで何とかしたい。(が、そう思っていて実際にやったことは少ない・・・) → シェルに特殊文字を解釈させないようにする方法はないようなので、簡単には行かなそうだ。system()などを使わなければいいのだろうか? (23:28)

詳細な動作確認-エンコードしたファイルの確認

音量の正規化が全く駄目だった。再生ゲインはピーク値で決まっている訳ではないので、ファイルからピーク値のタグを抽出して、それで音量を調整しても駄目で、トラックの再生ゲインのタグの値で調整すべきだった。ffmpegにはタグに書かれたトラックの再生ゲインで音量を調整する機能がないので、soxiで(アーティスト名などのタグと同時に)トラックの再生ゲインのタグを抽出して、その値からffmpegに指定する音量の値を計算することにした(再生ゲインのタグがない場合は諦めるが、実際には、すべての手持ちファイルには再生ゲインのタグが入っている/入れるので、問題はない)。なお、exiftoolは処理が遅いので、基本的には使わないことにした(soxiで文字化けする場合は諦める)。

今、何となく、エンコードと音量の正規化にはffmpegでなくsoxを使った方がいい気がして来たので、あとで考えよう。soxが文字化けするのはMP3だけだろうから、その時だけ特別な処理をすれば良さそうだ。→ 残念ながら、soxはアルバムアートの埋め込みができないので、使えない。(23:25)

ポータブルHDDにポップス全曲(約1万曲)を同期して確認

処理が遅過ぎた。最初の同期では、1万曲をエンコードするのに約4時間掛かった。全部エンコードしたのだから仕方ないのだが、エンコードしない場合(更新ファイルの確認のみ)にも遅かった。1万曲で約1000秒(17分)掛かった。いろいろ調べたところ、上に書いたように、exiftoolが遅かった。それをsoxiに換えたところ、約10倍高速になった。ただし、soxiはMP3の再生ゲインタグを抽出できないので、その場合はexiftoolも使うことにした。

また、下に書いた、子プロセスの終了判定がうまく行かないために入れた処理も遅かったのだが、原因が分かったので省けた。現在は、(エンコードしない場合)1万曲で約100秒(1.7分)で済むようになった。これでもまだ遅い気がするので、あとで何とかしたい。

その他に、ファイル名のクォートの問題も再発したし、タグからアーティスト名を抽出する処理にバグがあったりもした。

それから、GUIのキャンセルの検出処理がうまく行かなかった。子プロセスの終了を判定する関数(pcntl_waitpid())が期待どおりに動かず、かなり手こずったのだが、結局は、それに渡すプロセスIDが異なっていたことが分かった。

なお、最初の同期(エンコード処理)時のシステム負荷なども調べたので、以下に書く。

  • CPU使用率: 約80% (同時処理数=5)
  • CPU温度: 約60℃
  • メモリ使用率: 約20%
  • GMBの音切れ: なし
  • 同期対象ファイル一覧のサイズ: 約1.5MB
  • 結果のログのサイズ: 3.7MB
  • ディスク使用量: 約55GB/約1万曲

使用率80%で動かし続けると、さすがにCPU温度が上がって、ファンが少しうるさくなる。でも、BIOSにファン回転数の調整機能があるようなので、安心だ。ファイル一覧のサイズは思ったより小さくて、同期プログラムなどは問題なく動作した。ただ、ログをエディタ(kate)にペーストしたらハングしてしまったのには、結構がっかりした。

その他の問題

  • キャンセル(処理の中止要求)の検出のためにzenityのプログレスの終了を待つつもりが、全部の子プロセスを待っていて、並列処理しているエンコードプロセスの終了でキャンセル処理してしまった。
  • [GMB] 再生中に再生ゲインがoffになることがあるようだ。メニューの表示と実際が合っていない。原因不明なので、追って調査する。
  • [GMB] 再生するだけでファイルが更新されて、同期対象になってしまう。プラグインalbuminfoが自動的にジャンルを更新しているので、一旦、albuminfoとartistinfoを使うのを止めた。あとで更に調査して修正したい。
  • [zenity] LANG=Cで起動して、日本語のディレクトリを選択すると、出力が"?????"になる。→ zenityは日本語(LANG=ja_JP.utf8)で起動することにした。
  • [zenity] プログレスのウインドウのサイズが大きくなる。原因不明。文字列(ファイル名)が長過ぎるからか。

今後

少し使ってみて、不要にファイルが更新されないことを確認してから、実際に車で使っているUSBメモリに全曲を同期して、カーナビで再生できることを確認したら、終了となる予定。ただ、上述のように、改良したい点もあるので、ゴールはもう少し先になりそうだ。

その後、いろいろ良さそうなアイデアが浮かんだので、これが完成する前に第2版に着手しそうだ。最もいい考えは以下だ。

この同期プログラムをGMBから呼ぶ時に使っているexportというプラグインには、曲のファイル名や情報をCSVやM3U形式で書き出す機能があるのだが、(必要ならそれを改造して)同期の時に使うタグ情報(アーティスト名、アルバム名、トラックの再生ゲイン値)を書き出せば、音楽ファイルのタグを読む必要がなくなるから、今の数倍〜10倍高速になりそう!

それから、もし上が駄目でも、次の案もいい。

今は音楽ファイルのタグは外部プログラム(exiftoolやsoxi)で抽出しているが、実はPHPのライブラリでも取得可能だ。php-getid3というライブラリはいろいろなフォーマットに対応しているから使えそうだ。これを使えば、外部プログラムを呼ばなくて済むので、数倍高速になる可能性が高い。

更に、もし外部プログラムを使わないで済めば、特殊文字のクォートが不要になるので、プログラムが「マトモ」になる。ただ、ffmpegは必ず使うので、特殊文字の展開をしないsystem()関数を作る必要はある。

そして、そろそろプログラムの改良や修正が怖くなってきた(間違ったら戻れない)ので、GitやSVNのようなバージョン管理システムを入れようかと思っている。→ ローカルだけで使うのであれば、Gitがとても楽なことが分かったので、それにした。GUIはSmartGitを試している。(10/31 22:55, 11/1 6:39)

  •   0
  •   0