風邪ひいて調子悪いし、台風(今はまだ普通の雨)で外に出るのも億劫だしで、全くのプログラミング日和なのでw、昨日に引き続き、GPMDPの改良に余念がない。いや、余念があるから捗っているのかも知れない。僕の場合、別にプログラムをいじったりしたくはないのだが、音楽を気持よく聴きたくて、いろいろ考えるとできそうだから、仕方なくやっているのだ。

それはともかく、ついにGoogle Play Music (GPM)のプレーヤーGPMDPで音量の正規化ができた。我ながら大変強引な方法だし、いろいろ制限はあるが、とにかくできた。

方法は、基本的には昨日書いたとおりであるが、実際に作ってみると、細かいことがいろいろあったので、その辺りを書いてみる。

見つかった問題点

  1. 曲を再生中に再生ゲインを計算するために曲を取得すると、GPMは同時に1つの機器からしか再生できないので、次の曲の開始時にエラーになって、再生が停まってしまう。
  2. そのエラーダイアログの実装が汚く(まあ、元々がwebなのだから汚いというのは言い過ぎだが)、ブラウザ内のダイアログもどき(昔のワープロのようなもの)なので、xdotoolのようなツールで自動的に閉じるのが難しい。
  3. 曲の再生ゲインの計算が難しい。単純な最大値では聴感に合わない。実効値(どのくらい大きく聴こえるか ≒ 波形がどのくらい太くて黒いか)を求める必要が要る。
  4. GPMDPの音量のステップが段階的なので、細かい再生ゲインが反映されない。
  5. クラシックなどを聴く時のために、音量の正規化機能をon/offできるようにする必要がある。

実際に書き出すと少ないが、結構苦労した。

問題の解決

  1. GPMの同時再生エラーとエラーダイアログの問題
    • エラーダイアログが出たことを検出することすら難しいし、検出して自動で閉じるようにしても、音楽の再生中に勝手にマウスが動くのは鬱陶しい。
    • JavaScriptの機能で、ページ中にあるダイアログを探して、閉じようとしたのだが、なぜか、ダイアログもボタンも見つからず、どうにもならないので、一旦、後回しにした。
    • その後、手を抜きたかったので、曲の再生中でなく、曲間で一時停止して処理するようにしたので、最終的には、問題は起こらなくなった。それでも、処理はすぐに終わる(2秒未満: 下で訂正)ので、気になることは滅多にない。そもそも、正規化はラジオでしか使わないので、曲が間隔なしでつながることはないから、多少曲間が伸びても問題はない。(9/18 14:35 訂正: 実際に測定したら4秒前後だったが、ラジオのせいか、気にならないのは確かである。)
  2. 曲の再生ゲインの計算
    • 最初は最大値を使ったのだが、聴いてみると余り効果がなかった。
    • 値を調べると、多くの場合、最大値は100%近いので、ほとんどの曲で、正規化されていなかった。
    • 平均値を試したが、余りいい結果にならなかった。どういう訳か、平均値は小さいのに大きく聴こえる曲(The Cars "Heartbeat city": どういうことなのだろう??)があったからだ。
    • 処理に使っているffmpegにはloudnormという正規化する機能があるのだが、今のOSに入っている版には入っていないので諦めた。また、曲を正規化してもGPMDPでは再生できないので、余り便利でない。
    • 最終的には、ffmpegのastatsという機能で短時間の実効値(RMS)の最大値を取得することにした。理論的に正しいのか分からないが、聴いた感じでは良さそうだ。実効値を求める期間(時間)の設定が難しいのだが、昔のポップスを聴く限りでは1.75秒がいいようだ(ちなみに、この値は「異邦人」(1979)でチューニングした)。
  3. GPMDPの音量のステップが段階的
    • 今は音量を2.5%ステップにしているので、確かに細かい違いは反映されないが、聴いた感じでは分からない(細かい音量設定よりも、演奏の性質による違いが大きい)ので、今は保留している。
  4.  音量の正規化機能のon/off
    • 設定項目を追加すれば可能だが、いちいち開くのが面倒なので、再生メニュー(曲の右に出るもの)に追加することにした。
    • 追加はできたのだが、「ラベルの翻訳がない」という表示になってしまい、なかなか解決できなかった。
    • プログラム中のHTMLを良く見たら、<span>の属性(is="translation-key")で翻訳したラベルを使う指示をしているようだったので、それを止めるようにした(そんなものすごい機能があるとは、恐ろしい。脆弱性になるような気がするが、考え過ぎか)。
    • また、メニューでon/offするので、メニューのラベルが現在の状態を反映するように、設定変更時にラベルを書き換える(例: Onの場合は「無効にする」、offの場合は「有効にする」と表示する)ようにした(下図参照)。本来は、モードを示すアイコンなどを追加するといいのだが、それも面倒なので、このようにした。

再生メニューに音量正規化機能のトグルを追加

という訳で、随分苦労した気がするのだが、書いたらあっけないものだ。。。 実際には、Googleの検索と、そこから見つかった有用なページを書いてくれた方々に随分お世話になった。もし昔だったら、たった数日で、全く使ったことのない環境やプログラムをこんなにいじることはできなかっただろう。

それから、書く必要すらないことだが、もしWindowsを使っていたら、全く無理だったし、やる気も起こらなかっただろう。あれを使っていたら、どんなに普通のことでもなぜか大変になるから、ソフトウェアの正常な発展には大変な障害だとつくづく思う。

音量正規化の効果はおそらくあると思う(GPMDPの音量はちゃんと変化している: スライダーを表示させたままで見ていると、曲間でスライダーが自動的に動くのがおもしろい)のだが、気のせいかも知れない。上記のように完全ではないので、時々、小さく感じたり、大きく感じたりすることはある。ただ、以前は頻繁に音量を変えていたが、これができてからはほとんど変えていないので、やっぱり、効果はあると思う。

以下に、実装メモを書く。

  • 処理の流れ
    1. 曲が変わったイベントを待つ。 → 再生しようとしている曲情報が来る。
    2. 再生キュー(再生する曲一覧)を取得する。
    3. キューから曲のIDを取得(曲名、アーティスト名で検索)する。上記の曲情報には入っていないため。
    4. 計算済みの最大値が保存されていたら、使う。 → 9へ
    5. gmusicapiの機能を使い、IDよりstream URLを取得する。
    6. wgetにstream URLを指定して、曲を取得する。ただし、もしキャッシュにデータが残っていたら、再利用する。
    7. ffmpegのastatsフィルタでRMS(1.75s)の最大値を求める。
    8. 再利用できるように、いくつかの最大値を保存しておく。
    9. 最大値より、正規化するための音量値(%)を計算し、GPMDPに設定する。
    10. キャッシュ中の古いデータを消す。
    11. 1に戻る。
  • 制限事項
    • 再生ゲインはトラックモードのみ対応 (本質的に、アルバムモードには向かない。気長な人なら別)
    • 当初は、再生中にバックグラウンドで次の曲の処理をする予定だったのだが、暫定的に作ったものが結構うまく動いて、それ以上は面倒だったので、再生前にこれから再生する曲の処理をすることにした。
      • 上にも書いたが、処理は短時間(クラシックのような長い曲を除き、概ね24秒以内)に終わるので、曲間が長く感じることはない。
      • これならシャフルにも対応できるので、却って良かったのかも知れない。
    • 計算した再生ゲインの情報は保存しないので、過去に計算した値が再利用できない。(TODO)
    • GPM自体やwebページの仕様に大きく依存しているので、それらが変わったら、途端に動かなくなる(これはGPMDPも同様)。

 

PS. 前にも書いたが、どういう訳か、僕が聴くGPMのラジオで斉藤由貴の曲が頻繁に掛かる。今日は「悲しみよこんにちは」だ。好きな曲だが、今の彼女はそういう状況なのだろうか? というか、今でも彼女が現役でラジオ番組を持っていたことが驚きだった。

PS2. 本題とは関係ないが、GPMのおかげで分かったことを書く。

Winkの曲だとばかり思っていた「ふりむかないで」は、実はザ・ピーナッツの曲だった! そんな昔の曲にしては、全然違和感がなかったのがすごい。「ほう」と思った。(21:21)

PS3. この作業中に気付いたことがある。アプリをビルドして起動するのが意外に遅いのだ。もちろん何分も掛かる訳ではないのだが、一瞬ではないので、何度も繰り返すと結構イライラする。たかが(と言っては悪いが)JavaScriptなのに、ものすごく大量のモジュールが集まっているからなのだろう。そして、僕のPCが遅く感じたのは、これが初めての気がする。さすがに古くなったのかも知れない。(22:39)

(22:29 音量のスライダーが自動で動く動画を追加; 23:20 若干加筆・修正; 9/19 7:09: 実装メモ中の処理時間の訂正漏れ(4秒が正しい)を修正)

  •   0
  •   0

4件のコメント

  1. naoki:

    まずはお風邪をひかれたそうで,お大事にして下さい。

    そう。ジャケットが今話題の斉藤由貴じゃないですかと突っ込もうとしたら,言及されてましたね。

    あと,やはりプログラミングも含め,モノづくりはいいですね。こういうことができる,れんとさんを羨ましく思ってしまいます。(今回は特にボリュームのスライダーが自動で動くくだり)

    •   0
    •   0
  2. PiuLento:

    ●ありがとうございます。おかげさまで、風邪は、今日は不思議と良くなってます。昨日は、一時38℃になって、さすがにマズいと思ってたのですが・・・

    そう、物作りは楽しいですね。動くスライダー、ビデオに撮ったのですが、デジタルでのキャプチャでなく、デジカメで撮ったのがちょっと気に入らないので、まだ投稿してませんw

    •   0
    •   0
  3. naoki:

    すごい。本当にスライダが勝手に動いてる……。

    こういうのワクワクしますね。

    •   1
    •   0
  4. PiuLento:

    ●ありがとうございます。そう、考えた(思い付いた)仕組みとか機能を作って、本当に思った通り動くのを見る時は、すごくわくわくします。

    あの動画、もっとうまい見せ方がありそうな気がしたのですが、キャプチャと編集とフォーマット変換だけで面倒になったので、あんなそっけない感じになりましたw でも、全部Linuxでできたんです。

    •   0
    •   1

コメントを書く

名前    

メール 

URL