Qtopiaアプリケーションの開発 その3 メモリリーク実験


 new演算子の仕様が気になったんで、ちょっと確かめてみました。

リスト1「HelloQT」

# main.cpp

#include 
#include 

int main (int argc, char *argv[])
{
	QPEApplication hello( argc , argv );
	QLabel *label = new QLabel ("Hello World!",0);
	hello.setMainWidget(label);
	(*label).show();
	return hello.exec();
}
リスト2「HelloQT2」

# main.cpp

#include 
#include 

int main (int argc, char *argv[])
{

	int result;

	QPEApplication hello( argc , argv );
	QLabel *label = new QLabel ("Hello World!",0);
	hello.setMainWidget(label);
	(*label).show();

	result=hello.exec();
	delete label;

	return result;
}

 リスト1はこれまでと同じサンプルソース
 リスト2では、hello.exec()の戻り値を別途、変数に返すようにした上で、終了前に明示的にdeleteをかけるようにしてみました。

 検証は、ホーム画面にそれぞれのアプリケーションを登録後、一旦再起動を行い、システム起動直後の状態から、10回ずつ起動・終了を繰り返します。
 その上で、それぞれのメモリ使用状況を確認すると以下の通りとなりました。

HelloQT (delete処理なし)
 起動前:19184KB
 起動後:19196KB

HelloQT2(delete処理あり)
 起動前:19184KB
 起動後:19196KB

 システムのメモリ使用状況に関しては、キーやペンタップ等の操作自体でも変動します。そのため、起動前の空きメモリ状況は必ずしも一定にはなりません。また、どうもシステム情報自体でも、微妙にメモリリークが発生しているようなので、数値そのものはあくまでも目安に過ぎません。

 ただ、上記の結果を見る限りでは、少なくともdelete処理の有無は必ずしもメモリリークに直結するものでは無さそうですな。
 まぁ、実際、クラス内部でnew演算子使われてたりした場合、それら全てを把握することは困難な訳で、そういう意味ではあんまり神経質になっても仕方無いのかもしれませんが(苦笑)。

 ・・・しかし、起動前後で、総じて空きメモリ減ってるってことは、それ以外のトコでリークが発生してるとも言えるわけで、そっちのが問題かもしんない(^^;)。

Qtopiaアプリケーションの開発 その2 ソースの流れを追う

 さて、ようやくQtopiaアプリケーションの開発に取り掛かったのは良いんですが、そもそもC++からしてよく分かってなかったりします(爆)。無印のCは一応少しは分かるんですが(苦笑)。

 てな訳で、C++もまとめて一緒にお勉強状態です。この先、色々とQtopia以前の話も出てくると思います(^^;)。


 まずは、お勉強の第一歩として、これまでの動作テストで使ったサンプルソース(HelloQT)の流れを追ってみることにします。

# main.cpp

 1: #include 
 2: #include 
 3:
 4; int main (int argc, char *argv[])
 5: {
 6:	QPEApplication hello( argc , argv );
 7:	QLabel *label = new QLabel ("Hello World!",0);
 8:	hello.setMainWidget(label);
 9:	label->show();
10:	return hello.exec();
11: }


・1〜5行目
 このへんは、従来のCとさほど変わりはありません。

 使用する関数に応じて、ヘッダをインクルード。で、実行部はmain関数で囲います。

 注意点は、インクルードするヘッダファイルの差異についてです。

 通常、Qtアプリケーションでは、まず最初にqapplication.hをインクルードします。実際、手元のQtの参考書に載ってるソースでは大概そちらが記述されています。

 しかし、上のソースではqapplication.hの代わりにqpeapplication.hがインクルードされています。

 この違いは、そもそもZaurus上で動いてるシステムに起因します。

 ZaurusQtopia環境は、Qt/Embeddedと言うQtのサブセットで動作しています。QtとQt/Embeddedは、基本的な部分での互換性は確保されており、通常のQtアプリケーションを動作させることも可能ではあります。
 ただ、厳密にZaurus(Qtopia)用のアプリケーションを組む場合は、当然ながらQt/Embedded用のアプリケーションを作成する必要がある訳です。

 で、ぶっちゃけた話、Qt/Embedded用にアプリケーションを組むにはどうすれば良いか?と言うと、qapplication.hの代わりにqpeapplication.hをインクルードする、だけだったりします(^^;)。

 qapplication.hとqpeapplication.hでは、単純なウィンドウの見た目とかだけで無く、勿論、使える関数やライブラリにも色々と差異があります。
 ただ、ウィンドウを構成するボタンやラベル等と言った各パーツに関しては、共通のものを利用するので、続いてインクルードされてるqlabel.hqpelabel.hなんかになったりはしません。


6行目

QPEApplication hello( argc , argv );

 早速、怪しくなってきました(^^;)。

 えーと、とりあえず、これはクラスに関わる記述です。
 具体的にはQPEApplicationクラスのオブジェクト「hello」を新規に定義しています。
 クラスは、内部に値を保持する変数だけでなく、機能を持つ関数も含めることが出来るため、まとめてオブジェクトと呼称するそうです。

 ただ、逆に言えば、この記述は機能的な差異はともかくとして、ソースの本質的には

int a=0;

と大差は無いってことですか。

 変数を使用する際は型を指定し、ソース中の変数名を設定します。
 同様に、クラスを使用する場合は、使用するクラスを指定し、ソース中のクラス名を設定する、と。そう考えてくと、まぁ、分かりやすいかな?。


7行目

QLabel *label = new QLabel ("Hello World!",0);

 思いっきり分かりません(爆)。

 とは言え、前項のことも踏まえると、型(クラス)を指定して新たなポインタ(*label)を設定し、後に続く値を代入してるらしいことまでは大体分かります。

 要は、その値の指定方法の表記ですな(汗)。

 で、調べてみると、ここで使われてる「new」演算子は、動的にヒープ領域のメモリを確保するもんらしく、いわゆる無印Cでのmalloc関数と同等のものみたいです。・・・まぁ、そのヒープ領域ってのがよく分かんないんですが(^^;)。

 えーと、だからこの場合、後ろのQlabel();の定義内容をメモリ上に確保し、そのアドレスをポインタ*labelに収めてる訳ですか。
 ・・・なんか、直接文字列をポインタで渡すんでも良いよーな気もしますが、このへんはQtの仕様みたい。

 しかし、それはともかく、この「new」演算子で確保したメモリ領域は「malloc」に対する「free」と同じく、「delete」演算子で解放しないといけないとC++の教科書には書いてあります。
 でも、このソース見る限りでは、main()の最後でhello.exec()の戻り値だけ返して処理終わる格好になってますな。
 ・・・Qtって、アプリケーション終了時にちゃんとメモリ解放してくれてるんでしょーか?(^^;)。そのへんがQtアプリでやたらメモリリーク発生する原因だったりせんでしょうな(汗)。


8行目

hello.setMainWidget(label);

 6行目で定義したオブジェクト「hello」のメンバ関数setMainWidgetに*labelの中身を引き渡してます。

 Widgetウィジェットってのは、ウィンドウ&オブジェクト&ガジェット辺りの用語をひとまとめにした造語で、要はGUIにおけるウインドウや、ボタン、テキストボックスなどの各パーツの総称です。
 QtopiaアプリケーションはGUIである以上、当然、一番基本の土台となる親ウィンドウが、アプリケーションにつき必ず一つは存在します。それがメインウィジェットになる訳ですな。

 今回引き渡してるのはQlabel=ラベルな訳ですが、恐らく他のウィジェット(部品)もこんな感じで各ウィジェットを、さらにその親となるウィジェットに引き渡していき、最終的に全体のウィンドウが形成されていくんでしょう。


9行目

label->show();

 またまた、勉強が必要な表記が(苦笑)。

 「->」はアロー演算子と呼ばれるもので、クラスをポインタ表現で表す際の表記方法の一つらしいです。
 そもそも、クラスは複数の変数・関数の集合体、いわば超デッカい配列みたいなもんなんで、ポインタを使って取り扱う場面が出てくることは、まぁ分かります。

 で、その上でクラスのメンバを指定する場合、単純に

 *class.member

てな表記でいけそうな気がするんですが、これはNGになります。と、言うのもこの表記だと、ポインタ演算子「*」が「class.member」全体にかかってしまうからです。
 あくまでも、ここではポインタ「*class」で示されるクラス中のメンバ「member」を指定したい訳なんで、

(*class).member

と、明確に括弧で括ってやって、はじめて意図した結果が得られます。

 で、いちいち括弧で括るのは面倒(爆)だろうってんで、生まれたのがこのアロー演算子らしいです。上記をアロー演算子を用いて表記すると、

class->member

となります。ポインタ「class」から導かれるメンバだから、右向きの矢印ってことみたい。・・・何か、個人的には括弧で括る方が分かりやすい気が(苦笑)。

 ま、とりあえず、アロー演算子について分かったところで、改めてソースに戻り、上記に従って翻訳すると、要はここの表記は

(*label).show();

ってことになります。
 なんだ、結局*labelで示されたQlabelクラスのメンバ関数show()を実行してるだけですか(苦笑)。


10行目

return hello.exec();

 前項で書き忘れましたが「.」はクラス内のメンバ(変数・関数)を指定する際に用います。
 helloはQPEApplicationクラスのオブジェクトなんで、つまり、ここのexec()はQPEApplicationクラス内で定義されているメンバ関数です。

 で、その戻り値をそのままmain関数の戻り値として返す形で、main()が終了してます。
 ってことは、逆に言うとここまで来て、ようやくアプリケーションが動作し始めるってことですね。



 ここまでソースを追ってみた限り、基本的にQtopiaアプリケーションの流れは、

  1. 各パーツ(ウィジェット)のパラメータを設定
  2. 設定の終わった各パーツ(ウィジェット)を親(ウィンドウ)にセット
  3. 全ての設定と、パーツ配置が終わったところで、おもむろにメインウィジェットを実行

って流れになるようですね。

 このへん、前にちょっと触った qshdlgと感覚的には同じなんで、割とすっと理解することが出来ました。してみると、qshdlgは、Qtopia触るための入り口として、非常に良い教材でありますな(^^)。

Qtopiaアプリケーションの開発 その1 コンパイル手順

 と言う訳で、セルフ開発環境がようやく整ったので、改めてQtopiaアプリケーションの作成手順を学んでいきます。

 さて、ソースの解析や、ライブラリの使い方など、学ぶべきことは山程ありますが、まずは何よりも、コンパイルそのものの手順からまとめてみることにしましょう。

 開発環境構築の際、動作テストとして、既に手順そのものは記載していますので、内容的には一部、そちらと重複することになりますが、確認の意味も含めて、改めてきちんと手順を追っていきます。

コンパイル(ビルド)手順

 Qtopiaアプリケーションのビルドにあたっては、基本的に以下の手順を踏むことになります。

  1. ソースリストの作成
  2. progenでproject(.pro)ファイルの作成
  3. tmakeでMakefileを作成
  4. make

 以下、具体的な手順です。

 まずは、ソースリストを用意します。
 ソースに関しては、別にQtopiaアプリケーションに限った話ではありませんが、通常は適当なテキストエディタで記述していきます。
 私はZEditorを利用していますが、極端な話、標準のメモ帳でもソースの記述は可能です。


 今回は、先日のセルフ開発環境構築の時に使ったソースをそのまま流用します。

# main.cpp

#include 
#include 

int main (int argc, char *argv[])
{
	QPEApplication hello( argc , argv );
	QLabel *label = new QLabel ("Hello World!",0);
	hello.setMainWidget(label);
	label->show();
	return hello.exec();
}


 ソースリストが用意出来たら、2.project(.pro)ファイルを作成します。

$ progen -o ./HelloQT.pro

 progenはディレクトリ内のソースリストファイルを走査し、後のtmakeコマンドが参照するprojectファイルを作成します。
 この際、カレントディレクトリ中のソースファイルは全てが走査の対象となり、単一のprojectファイルが生成されます。
 そのため、複数のアプリケーションを開発を行っている場合は、開発アプリケーション毎に作業ディレクトリを分けて作業する必要があります。


 projectファイル(.pro)が作成されたら、続いて3.tmakeを実行し、Makefileを作成します。

$ tmake -o ./Makefile ./HelloQT.pro


 最後に、4.makeすることで、ソースリストのコンパイルが行われ、実行バイナリ(アプリケーション本体)が完成します。

$ make


 出力されるバイナリはprojectファイル、及びMakefileで出力ファイル名が定義されているため、デフォルトのa.outでは無く、きちんとしたファイル名が付けられています。


 作成されたバイナリは、コンソールから直接実行することが出来ます。

実行結果


 勿論、この実行バイナリは/opt/QtPalmtop/binに配置することで、ホーム画面−設定タブ−ホーム画面設定から、Qtopia上のアプリケーションとして登録することが出来ます。

ホーム画面設定


 基本的なQtopiaアプリケーション作成の手順は以上です。

既存のソースをビルドする

 さて、今度は配布されている既存のソースから、Qtopiaアプリケーションをビルドしてみましょう。
 今回は、毎度お世話になっているZEditorをソースからビルドしてみることにします。

 まずは、satoshiさんのページ公開されているソースアーカイブを入手します。


 ソースアーカイブは、ipkgでは無く、tarとgzipで圧縮されたファイルとなっていますので、まずはこれを適当なディレクトリに解凍します。

$ tar zxvf ./zeditor3.5.1_src.tar.gz

 解凍されたファイルを確認すると、既にprojectファイル(zeditor.pro)が用意されていることが分かります。

$ ls
FileDialog.cpp
filedialog.h
idiom.cpp
idiom.h
jump.cpp
jump.h
ls.txt
main.cpp
optdialog.cpp
optdialog.h
repdialog.cpp
repdialog.h
zeditor.control
zeditor.cpp
zeditor.desktop
zeditor.h
zeditor.png
zeditor.pro
zeditor3.5.1_src.tar.gz

 このprojectファイルを基にMakefileを作成します。

$ tmake -o Makefile ./zeditor.pro


 後はmake一発。

$ make


 以上の手順で、バイナリパッケージで配布されているのと同等のZEditorを自分の手元で生み出すことが出来ます(^^)。

 なお、今回のZEditorのビルドでは、ソースアーカイブで用意されていたprojectファイルをそのまま使いましたが、勿論自分でprojectファイルを生成することも出来ます。

$ progen -o ZEditor.pro

 なお、同名のprojectファイルが既に存在していた場合は、上書きされます。

 ソースアーカイブ中にprojectファイルが含まれていない場合は、上記の手順でprojectファイルを生成するところから始めることになるでしょう。
 逆に、既にMakefileが存在するならば、いきなりmake一発でビルドが完了する場合もあるかと思います。

 このへんは前項のコンパイル(ビルド)手順を参照しながら、現在の作業がどの段階にあるのかを確認してみて下さい。

tmakeとprogen

 Qt(Qtopia)アプリケーションに限った話では無く、一般にプログラムが複雑になってくると、ソースファイルや関連モジュールは複数のファイルに分かれて記述することが多くなります。
 ソースを複数に分けるのは、共通するルーチンを多数のプログラムで使い回したり、幾人かで共同開発を行う際、作業を円滑に進めるために行われますが、当然ながらその分コンパイルの手順や、ソースの管理は煩雑になっていきます。

 そういった複数のソースを管理し、簡便にプログラムをビルドするツールがmakeです。
 makeは単純なソースリストの管理だけでなく、異なる機種間でのコンパイル環境に対応した設定等も行うことが出来るため、CUIGUI関わらず、既存のソースをビルドする場合、大抵ソースを解凍後、make一発、と言うのが現在のスタンダードになっています。

 そういう意味では、直接ソースファイルに対して直接、cc(gcc)やc++(g++)でコンパイルを行う場面の方が今は少ないのかもしれません。

 Qt(Qtopia)の開発にあたっても、このmakeを使ってアプリケーションをビルドすることが推奨されています。

 tmakeprogenはこのmakeを実行するための補助ツールです。

 progenはディレクトリ中のソースファイルを検索し、tmakeを実行するために必要なテンプレート=projectファイル(.proファイル)を作成します。

# HelloQT.pro

TEMPLATE	= app
CONFIG		= qt warn_on release
HEADERS		= 
SOURCES		= main.cpp
INTERFACES	= 

 この様に、実際に作成されたファイルを見てみると分かりますが、ぶっちゃけprojectファイルはただのソースファイルの一覧表に過ぎません。

 tmakeはこうして出来たテンプレートファイルを基に、Makefileを作成します。

# Makefile

#############################################################################
# Makefile for building ./HelloQT
# Generated by tmake at 11:25, 2006/04/12
#     Project: ./HelloQT
#    Template: app
#############################################################################

####### Compiler, tools and options

CC	=	gcc
CXX	=	g++
CFLAGS	=	-pipe -Wall -W -O2 -DNO_DEBUG
CXXFLAGS=	-pipe -DQT_QWS_EBX -DQT_QWS_CUSTOM -DQWS -fno-exceptions -fno-rtti -fsigned-char -DQT_NO_DRAGANDDROP -DQT_NO_PROPERTIES -Wall -W -O2 -DNO_DEBUG
INCPATH	=	-I$(QTDIR)/include
LINK	=	g++
LFLAGS	=	
LIBS	=	$(SUBLIBS) -L$(QTDIR)/lib -lqte -lqpe
MOC	=	$(QTDIR)/bin/moc
UIC	=	$(QTDIR)/bin/uic

TAR	=	tar -cf
GZIP	=	gzip -9f

####### Files

HEADERS =	
SOURCES =	main.cpp
OBJECTS =	main.o
INTERFACES =	
UICDECLS =	
UICIMPLS =	
SRCMOC	=	
OBJMOC	=	
DIST	=	
TARGET	=	./HelloQT
INTERFACE_DECL_PATH = .

####### Implicit rules

.SUFFIXES: .cpp .cxx .cc .C .c

.cpp.o:
	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<

.cxx.o:
	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<

.cc.o:
	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<

.C.o:
	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<

.c.o:
	$(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<

####### Build rules


all: $(TARGET)

$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) 
	$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS)

moc: $(SRCMOC)

tmake: Makefile

Makefile: ./HelloQT.pro
	tmake ./HelloQT.pro -o Makefile

dist:
	$(TAR) ./HelloQT.tar ./HelloQT.pro $(SOURCES) $(HEADERS) $(INTERFACES) $(DIST)
	$(GZIP) ./HelloQT.tar

clean:
	-rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS) $(TARGET)
	-rm -f *~ core

####### Sub-libraries


###### Combined headers


####### Compile

main.o: main.cpp

 Makefileでは、ターゲットとなるソースファイルの他、実際にアプリケーションをビルドするのに使われるツールや、ライブラリパス等が細かく設定されています。

 Makefileも、途中で生成されたprojectファイルも、その実体はテキストで記述された設定ファイルに過ぎません。しかし、これを一から手書きで書いていくのが、大変面倒であることは言うまでも無いでしょう。

 つまるところ、tmake及び、progenは、この「Makefile」を自動的に生成するためのツールな訳です。

 なお、これらのツールで生成されたprojectファイル、及びMakefileコンパイルするにあたって、さらに手作業での修正が必要になる場合があります。
 これは主にクロスコンパイルで開発を行う場合で、Zaurusの実機とクロスコンパイル環境とで、ライブラリ等の依存ファイルのパスが異なるために修正が必要となります。
 Zaurus実機で、セルフコンパイルを行う場合は、こういった不整合が発生することはありませんので、修正の必要は無く、そのままmake(コンパイル)を実行すればOKです。

SL-C3000でセルフ開発環境を組む。


 SL-C3200の環境の方が落ち着いてきたので、SL-C3000を開発・実験機へ回すことにする。

 ってことで、一旦完全消去を行った後、開発環境を構築する。
 手順としては、これまでの環境再設定と被る部分も多いけど、そのへん開発の事を考慮して、多少変更。


 まず、ネットワーク設定については、無線LAN環境のみセットアップ。基本的に屋内での開発作業限定なんで、BT環境は設定しない。

 続いて、アプリケーションをインストール後、ホーム画面を整理。
 今回は開発機ってことで、不要なアイコン類はかなり思い切って、片っ端から削除している。


 さらに、下図の通りにハードキーを割り当てる。

 不要なキーは殺した上で、さらにこうしておくとターミナルとエディタ(ZEditor)を一発で切り替えられるので、何かと便利。


 続いて、作業用のディレクトリを作成する。
 開発作業するにあたってはFAT領域だと何かと不便・・・つか、実際問題として、色々と不都合もあるんで、ext2/3領域でまとまった作業領域が欲しい。幸い、SL-C3000は他機種と比して、非常に広大な300MB近くものext3領域が/hdd2に確保されてるんで、これを活用することにする。

$ su
# mkdir /hdd2/work
# chmod 777 /hdd2/work
# exit

 さらに、/home/zaurusからアクセス出来た方が便利なので、シンボリックリンクも作成しておく。

$ ln -s /hdd2/work /home/zaurus/hdd2

Perlの設定

 Qtopiaのアプリケーション開発で使われるtmakeコマンドは、Perlを必要とするため、まずPerlの環境をセットアップする。

 パッケージはWalrus,Visit.で公開されているものを使用。


 インストール時、必要ライブラリの警告が出るが、特に他のパッケージを追加しなくても、上記パッケージのみで動作に支障は無い。

 インストール後、ホームディレクトリの.bashrcに下記の記述を追加(.bashrcが無い場合は作成)する。

# .bashrc

PERL_BADLANG=0
export PERL_BADLANG

 以上で、Perlの設定は終了。

・動作テスト
$ perl -e 'print "Hello World!\n"'

実行結果

C 開発環境(gcc)のインストール

 続いて、全ての基本となるC開発環境をセットアップする。

 てくのうのページ(SLザウルス用ソフト&データ)から、下記のパッケージをインストール。


 インストール後、特に環境設定等を行う必要も無く、これだけでCコンパイル環境が整う。

・動作テスト

 適当なエディタで、ソースリストを作成。

# hello.c

#include 

int main(void)
{
    printf("Hello World!\n");
    return 0;
}

 ソースリストを用意したら、下記の通りのコマンドでコンパイルを行う。

$ gcc ./hello.c


 出来上がったバイナリを実行。

$ ./a.out

実行結果

C++ 開発環境(gcc c++)のインストール

 次にC++の開発環境をインストール。
 CUIコマンドライン)ベースでの開発だけであれば、別にCだけでも十分に開発は可能だが、後のGUI(Qtopia)の開発環境はC++を前提としている。そのため、後々GUI環境での開発を行うことを考慮し、C++の開発環境を整える。

 先程と同様、下記のパッケージをインストールする。

・動作テスト

 ソースファイルを用意。

# hello.cpp

#include 
using namespace std;

int main()
{
	cout << "Hello World!\n";
	return 0;
}

 コンパイル

$ g++ ./hello.cpp

 バイナリ実行。

$ ./a.out

実行結果

Qtopia開発環境のインストール

 最後にGUI(Qtopia)アプリケーションの開発環境をセットアップする。

 下記のパッケージをインストール。


 シャープライブラリは必須のものでは無いが、まぁ、念のため(^^;)。
 なお、QtopiaSDKのインストール時は、環境再設定のため、システムの再起動が行われる。

・動作テスト。

 ソースファイルを用意。

# main.cpp

#include 
#include 

int main (int argc, char *argv[])
{
	QPEApplication hello( argc , argv );
	QLabel *label = new QLabel ("Hello World!",0);
	hello.setMainWidget(label);
	label->show();
	return hello.exec();
}

 project(.pro)ファイルを作成。

$ progen -o ./HelloQT.pro

 Makefileを作成。

$ tmake -o ./Makefile ./HelloQT.pro

 make(コンパイル)。

$ make

 バイナリ実行。

$ ./HelloQT

実行結果


 以上、これで一通りのセルフ開発環境がようやく整った(^^)。

desktopファイルの解析 「Display」エントリ

 どうも、よく分からないんで軽く調べてみた。

 一応、SHARPのFAQに拠ると、アプリケーションのVGA/QVGA画面モードを規定するもんらしい。

 とりあえず、適当なアプリケーション(メモ帳)のdesktopファイルを実際に触って試してみる。

Display=
 640x480/144dpi                              : VGAモード : VGA最適化チェックボックスなし:縦横切替可能
 480x640/144dpi                              : VGAモード : VGA最適化チェックボックスなし:縦横切替可能
 640x480/144dpi,480x640/144dpi,240x320/72dpi : VGAモード : VGA最適化チェックボックスなし:縦横切替可能
 240x320/72dpi                               : VGAモード : VGA最適化チェックボックスなし:縦横切替可能

 ・・・うーむ、あんま変わった気がしない。
 どの設定でも、画面モードはVGAのままで、最適化のチェックボックスが表示されないため、QVGAモードにすることも出来ない。
 つか、640x480/144dpiとか、480x640/144dpiに関しては、横、及び縦それぞれの画面専用ってFAQでも書いてあるんだけど(^^;)。

 逆に、「Display=」の設定項目そのものを削除して、初めて「VGAへ最適化」=QVGAモードが行われるようになる(苦笑)。

 どうも、この「Display=」の設定自体では必ずしもシステムの画面モードを規定出来ないよーですな。

 結局、最終的な画面モードは、あくまでもアプリケーションで設定され、その情報が取得出来ない場合、ユーザーが手動でQVGAVGAの画面モードを指定出来るよう、プロパティに最適化のチェックボックスが表示されるってことなのかもしれない。

 と言うか、この「Display」の項目自体がアプリケーション側の意図しない画面モードで立ち上がってしまわないよう、Qtopiaのシステムに情報を通知するための項目ってことなのかな?。

 ってことで、改めてサンプルアプリケーションを変更。
 今度はVGA横画面専用のアプリケーションであることが分かっているフォトストレージで試してみることに。
 まず、/home/QtPalmtop/apps/Applications/photostrage.desktop中の「Display=」項目を削除し、さらにQVGAモードで立ち上げてみる。

 見事にレイアウトが崩れた(笑)。
 改めて、最適化のチェックを外し、VGAモードを設定した上で縦画面にしてみると、

 あ、やっぱり崩れまくり(笑)。

 ま、よーするに、こーゆー事態になってしまわないための保護設定項目ってことなワケやね。成程、理解した。

TextToSpeechの多言語化 その3

 改めて、もっぺんtexttospeechの実行バイナリを調べてみたところ、0001B36Cバイト辺りで各種設定項目らしき文字列を発見。うーむ、やっぱり、バイナリ本体でスタティックに設定されてたか(苦笑)。

 それを見る限り、設定ファイルの所在や、テンポラリファイルの名称、で、肝心の構文解析する国言語や話者データ等、全て決め打ちで設定されてるみたい。
 ってことは、そもそもこのtexttospeechの実行バイナリ自体が、American English、それもJenniferさん以外には対応出来ないってことですな。

 まぁ、ついでにライブラリファイル、librssolo.soの方を覗いてみた限りでは、ちゃんと多言語に対応してるフシが残されてるみたいだけど。

 ってことで、今度こそ完全に終了。
 個人レベルで買えそうな、Realspeak Solo 4.0の開発キットとかあったら話は別ですが(笑)。

TextToSpeechの多言語化 その2


 と言う訳で、RealSpeak Solo 4.0を搭載したソフト「Panasonic Voice Editing」を入手したので、改めて、TTSの日本語化に挑戦してみる。

 CD-ROMの中を確認してみると、RealSpeak Soloとおぼしきインストールファイル群が各言語別に用意されていた。ただ、各インストールファイルはWindowsインスーラ形式となっているため、そのままファイルを抽出することは出来ないんで、とりあえずPCにソフトをインストール。

 インストールすると、そのものずばりC:\Program Files\Panasonic\RealSpeak_Solo_for_Panasonicってフォルダが出来ていた。
 さらにその下を調べてみると、C:\Program Files\Panasonic\RealSpeak_Solo_for_Panasonic\speech\componets\data\とSL-C3200と同様のフォルダ構成で、拡張子が.datとなっている発話データと思しきファイルを発見。とりあえず、ぱっと見、ファイル名の命名規則SL-C3200で見つけたファイルと同様なんで、バージョン的には問題なさそう。

 ってことで、とりあえずこれらのファイルを抽出し、SL-C3200へ。

 ・・・なんだけど、コピーしようとしたら領域不足でコピー失敗(^^;)。
 仕方が無いので、一旦/hdd3に適当なフォルダを作成し、改めて/home/QtPalmtop/etc/speech/へシンボリックリンクを貼り直す。
 一応、先にオリジナルの発話データファイル(jenniferさん)をコピーし、この構成で発話に問題無いことを確認した後、改めてファイルをインストールする。

 で、結論から言うと・・・失敗(^^;)。

 どうも、これだけでは、まだ日本語を認識してくれないようだ。

 と、言うか実際問題として、エンジンが共通ならばなおのこと、どこかで発話データの所在(ファイルパス)や、国言語なんかの設定・登録を行うのがスジだと思うんだけど、どうにも、それらしきファイルが見つからない。

 試しに、抽出した日本語の発話データをオリジナル(US)のファイル名に変更して、丸ごと差し替える形にしてみたけど、状況変わらず。
 逆に、オリジナルの発話データのファイル名を変更してみると、やっぱり発話出来なくなった。

 ってことは、やはり発話データの有無で発話言語を自動認識する訳ではなくて、どこかで何かしらの設定・登録を行っているってことでは無いかと思われる。

 最悪、実行バイナリ内でスタティックに指定してるのかとも思ったんだけど、ざっとファイルの中覗いた限りではそれらしき文字列は見つからなかった。

 さらに、/QtPalmtop/lib/で、librssolo.soってのを発見。恐らく、libRealSpeaksSolo.soの略で、十中八九関連ファイルだとアタリをつけて調べてみたけど、こっちでもそれらしき文字列は発見出来ない。

 まぁ、汎用性のこと考えると普通、実行バイナリやライブラリでスタティックにデータファイルのパスや、登録言語を決め打ちで埋め込んだりはしないと思うんだけど。うーむ、どこで設定してるんだろう?。

 ま、やっぱりスタティックにリンクされた上で、文字列が符号化されてる可能性や、そもそも発話データファイルの形式がやっぱり抽出元と違ってるっつーことも考えられるワケだけど・・・。とりあえず、ここらで一旦手詰まりかなぁ(苦笑)。

関連ファイル群

 とりあえず、ここまでに確認出来たtexttospeechの関連ファイル群の所在をめも。

/home/QtPalmtop/bin/
 texttospeech

/home/QtPalmtop/etc/speech/components/data/
 us_jennifer_r40_83swf11_04.dat
 vf_jennifer_r40_83swf11_110_04.dat

/home/QtPalntop/lib/
 librssolo.so
 librssolo.so.1
 librssolo.so.1.0
 librssolo.so.1.0.0

/home/QtPalmtop/apps/Applications
 #texttospeech.desktop#
 texttospeech.desktop

/home/zaurus/Applications/Contents
 texttospeech.desktop

/home/zaurus/settings/
 texttospeech.conf

 なお、/home/QtPalmtop/以下のbin、etc、libの各ファイルはシンボリックリンクとなっており、実ファイルは下記の通りとなる。

/usr/QtPalmtop.rom/bin/texttospeech
/usr/QtPalmtop.rom/etc/speech/components/data/us_jennifer_r40_83swf11_04.dat
/usr/QtPalmtop.rom/etc/speech/components/data/vf_jennifer_r40_83swf11_110_04.dat
/usr/QtPalntop.rom/lib/librssolo.so.1.0.0