Linux」カテゴリーアーカイブ

utf8_collate_key

いいかげんに Y901x が落ちまくる件とソート問題を解決させねば。
なんとかさせないと追加機能もやれないよ。
落ちる件は色々試しているんだがまだ原因が解らない、困った…

ソートに関しては自力を諦め Nautilus のコードをひたすら追う。
libnautilus-private/nautilus-file.c
に compare_by_display_name というソレっぽい関数をやっと見つける。

display_name_collation_key を strcmp で比較しているだけなのか。
g_utf8_collate_key_for_filename という glib の関数で代入している。

Unicode Manipulation

あれ、もしかして数値もドットもこの関数一つで解決してまうの?

The Whole PyGTK FAQ

Python には実装されていないようで。
最近のバージョンではあるかもと dir() で探しまくるも見つからず。

とにかくこの関数でどう変換されるのか気になるので C でやってみる。
Ubuntu 10.04 デフォルトでは gcc はあるけど gtk や glib のヘッダは無い。
Glade を入れれば依存関係で Devhelp を含めまとめて入るので Glade を入れる。

/*
gcc  b.c `pkg-config --cflags --libs gtk+-2.0`
*/

#include <stdio.h>
#include <gtk/gtk.h>
#include <glib.h>

int main() {
    gchar *c;
    c = "a1.mp4";
    gchar *u;
    u = g_utf8_collate_key_for_filename (c, -1);
    printf("%s to %s\n", c, u);
    /*g_free(c); is Segmentation fault*/
    g_free(u);
    return 0;
}

久々の C なんだがこんな感じでよかったかなぁ…
strcpy で警告になったのが Visual Studio と同じだったが代替が解らない。
とにかく結果。

なんだかよく解らないのに変換されとる。
後は比較関数を作って実験して上手くいったら…
Python で使うんだが、ctypes しか手が無いかな?

Human sort 2

仕事関連でドタバタしており Blog の更新が止まりがちになっています。
今月は落ち着きそうな希望が少々持てるのでちょっぴりがんばってみる予定。
ということで

前々回(って半月前か…)

の自然順ソート仕様で我が Y901x のリストアップを色々試していた。
サボっていたのではなく地味にテストはしていた、とにかく解ったのは問題だらけ!

最大の問題は aa.mp4 aa1.mp4 等というファイルがあったとき。
Nautilus では aa.mp4 が当然のように上になる、前々回の関数では逆になってしまう。

原因が解らなくてしばらく悩んだけど解ってしまえば単純。
前々回のコードではドットは単なる文字列の一部としか認識しないからだ。
分離され整数変換された値とドットという文字列を比較ならば当然ドットのほうが大きな値と認識する。
結果 aa.mp4 のほうが aa1.mp4 より大きいと認識するファイル名になってしまう。

なんだそれ…
これじゃ拡張子が付いたファイル名では全部同じようになってしまう。
いや Linux の場合はそれだけじゃない、ドットファイルという文化があるのだから。
以下のようなファイル名を用意してテスト、nautilus は隠しファイルを表示設定に。

Python の文字列比較は先頭から一文字単位で照合しているだけ、当然の結果。
整数文字列の比較は確かに行っているけどこうなってしまう、落とし穴が深すぎだった。
Windows の Explorer 名前順ではドットファイルは先頭になるが Nautilus は日本語より下。
同じ自然順ソートでもドットをどう扱うかが違うようで。

とにかくファイル名の場合は前々回のソート関数では Nautilus とは同じにはならない。
というかドットファイルどころかバックアップファイルにも無考慮だと今頃気がつく私であった。
後日に続く(終わりカヨ!

Human sort

Python の List で sort() しても Nautilus のファイル名順にならない。
Windows XP の時のように数値優先な自然順ソートをしなければならない。

我がアプリ Y901x のリストはデフォルトのソートをしているだけ。
気にしていたけど無名なのをいいことに今まで知らん顔していた(ぉい!

Windows XP には shlwapi に StrCmpLogicalW という API 関数があったんだが…
Linux なら glib や gio に関数がありそうなんだけどな…

PyGObject Reference Manual

見つからないし。
Nautilus のソースも落としたけど何が何やらサッパリワカンネ。
自力で自然順ソート関数を作っている人のコードを参考にしてみよう。

Ned Batchelder: Human sorting

コレやったらとりあえずうまくいった。

Python sorts “u11-Phrase 1000.wav” before “u11-Phrase 101.wav”; how can I overcome this? – Stack Overflow

コッチは isdigit を使っている、その手もあるか。
というか整数の正規表現ってこのどっちでもいいんだなとか変な発見。

return [ tryint(c) for c in re.split('([0-9]+)', s) ]
or
return [ tryint(c) for c in re.split(r'(\d+)', s) ]

しかしコレで完全に Nautilus と同じになるのだろうか?
とりあえず自分でもう少し試してみる。

それと playbin2 化したらよく落ちるようになったなぁ…
切り替え事の gtk.main_iteration を消したらかなり良くなったけどこれでいいのかな…

GtkInfoBar

Part III. GTK+ Widgets and Objects

何か Linux とか GTK+ とかで新しいプログラミングのネタは無いものか…
なんて考えながら上記ををポッケーと眺めていた。

いきなり見つかったぞ、GtkInfoBar って何?

調べてみると例えば Gedit に動画ファイルをドロップしたエラーで出るあの少し大きなバー。
やれば解るので細かいことは書かないけど、ソレをわざわざ GTK+ 部品の一つにしたようだ。

GTK+ – Wikipedia, the free encyclopedia

GTK+ 2.18 で追加されたようだけど PyGtk から使えるのかな?
自前環境にて PyGtk から使えるか調べてみる。

Mandriva 2010.0 の GTK+ 2.20.0 と PyGtk 2.16 では使えない。
Ubuntu 10.04 の GTK+ 2.21.1 と PyGtk 2.17 では使える。

PyGTK 2.0 Reference Manual

こっちには今現在はマニュアルは無い、てかまだ version 2.15.2 のままのようで。
ドキュメントが遅れるのは Linux ではしかたがない、商売でやっている MSDN とは違うのだから。

しかしこの程度のインフォメーション表示バーなんて自作しても別に難しくない。
でも GTK+ 自体は GUI 部品の見た目統一を目指しているはずだし(違ったかな?
テーマ切り替え時の追従なんかも期待できる、Opera がまったく追従しないのが気になって…
とにかくせっかくベンダーが用意してくれたものだから使ってみよう。

GtkDialog の vbox アトリビュートのようなものは存在しない。
これ自体が GtkHBox サブクラスであらかじめボタン配置用スペースを予約しているみたい。
とりあえずボタンを押すと InfoBar が出てレスポンスでボタン文字を変更する例を。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import gtk

class InfoBarTest(gtk.Window):
    """
        GtkInfoBar Test
        PyGtk 2.17 or later.
    """
    def __init__(self):
        gtk.Window.__init__(self)
        vbox = gtk.VBox()
        vbox.show()
        self.button = gtk.Button("Click!")
        self.button.show()
        # GtkInfoBar
        self.infobar = gtk.InfoBar()
        self.infobar.pack_start(gtk.Label("Hi!\nButton Click"))
        self.infobar.add_button("_Cancel", gtk.RESPONSE_CANCEL)
        self.infobar.add_button(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
        # Signal
        self.infobar.connect("response", self.on_infobar_response)
        self.button.connect("button-press-event", self.on_click)
        self.connect("delete-event", gtk.main_quit)
        # append
        vbox.pack_start(self.infobar, False)
        vbox.pack_start(self.button)
        self.add(vbox)
        self.resize(300, 300)
        self.show()
        
    def on_click(self, widget, event=None):
        self.infobar.show_all()

    def on_infobar_response(self, widget, response_id):
        if response_id == gtk.RESPONSE_ACCEPT:
            self.button.set_label("OK!")
        else:
            self.button.set_label("Cancel...")
        self.infobar.hide()

if __name__ == "__main__":
    w = InfoBarTest()
    gtk.main()

バインディングは他の GTK+ 部品と同様みたい、これなら得にマニュアルは不要か。
後はチマチマ弄くってみればもっと見た目とかもよくなると思う。

うん、StatusBar や TitleBar では面積が足りない場合なんかに有効だ。
上手く使えば Debug にも利用できそう、自作すればいいとはいわない。

というか自作すればいいというのなら GtkMessageDialog なんかもいらないわけで。
「ナンデモアリ」を徹底的にやった結果として複雑怪奇になった WPF は見習ってほしいよ。

GStreamer Change Volume

GStreamer Player のボリュームを直線的に変更したい。
GtkHScale の値を直で渡すと曲線になって使いにくい、DirectShow はもっと酷かったけど。

dBデシベルの話し 音の大きさ

音量のデシベルは非常にややこしい。
GStreamer マニュアルの GstStreamVolumeFormat 以下にも 20 * log10 (val) とある。

gststreamvolume

実は私の 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 はなんとかなりそう。