GStreamer Player のボリュームを直線的に変更したい。
GtkHScale の値を直で渡すと曲線になって使いにくい、DirectShow はもっと酷かったけど。
音量のデシベルは非常にややこしい。
GStreamer マニュアルの GstStreamVolumeFormat 以下にも 20 * log10 (val) とある。
実は私の Cinema という Windows 用 DirectShow プレイヤーは手抜きをしていて…
DirectShow ボリュームは最大 0、無音 -10,000 をデシベル単位でということなのですが…
void CDirectA::SetVolume(int nVolume) { double d = pow((double)(nVolume * 2), 2.0); m_nVolume = static_cast(-d); if (pBasicAudio) pBasicAudio->put_Volume(m_nVolume); }
というベキ乗を利用してなんとなく似たようなカーブにしている。
ぶっちゃけ WMP とは全然カーブが違うんだが面倒だということで(ぉい!
GStreamer ボリュームは最大 100.0、無音 0.0 なのでコレを Y901x で真似るには
def on_volume_value_changed(self, widget, event=None): val = widget.get_value()**2 / 10000.0 self.player.set_property("volume", val)
とやってみたけど完全に違う、GStreamer では同じ手は使えないようだ。
キチンと調べないといけないみたい、Totem はどうやっているかコードを漁る。
bacon-video-widget-gst-0.10.c の bacon_video_widget_set_volume 関数で
GST_STREAM_VOLUME_FORMAT_CUBIC を指定している、この型と相互変換が必要か。
gststreamvolume を pygst から利用するには c ヘッダが gst/interfaces 以下にあるので
import gst dir(gst.interfaces)
みたいにやれば関数が一覧されるので探ってみる。
stream_volume_set_volume は流石に使えないようだけど convert はできるようだ。
CLAMP 関数も必要かな C言語でCLAMP(a,b,c) | OKWave
一行なのでラムダ式を使えと言われそうだが CLAMP という関数名も覚書に使いたい。
def set_volume(self, value): v = gst.interfaces.stream_volume_convert_volume( gst.interfaces.STREAM_VOLUME_FORMAT_CUBIC, gst.interfaces.STREAM_VOLUME_FORMAT_LINEAR, value) def clamp(a,b,c): return min(max(a,b),c) v = clamp(v, 0.0, 1.0) self.player.set_property("volume", v) def on_volume_value_changed(self, widget, event=None): self.set_volume(widget.get_value() / 100.0)
おっし、これで Totem とまったく同じ音量カーブになった。
CUBIC を LINEAR に変換すればいいのね、実はいまいちよく解っていなかったり(ぉい!
もう少し Debug して Y901x の Playbin2 化 version 0.3 はなんとかなりそう。