« 2014年2月 | トップページ | 2014年4月 »

2014年3月

2014年3月27日 (木)

音がでないなぁ その2

Qtでの音の出し方、間違えていました。これだから素人は…

PullだとかPushというのはサンプルソースの実装の仕方による違いでした、すみません。

要は届いたPCMデータをバッファリングしておき、サウンドデバイスに、必要なデータサイズ分のデータをバッファの空きがある限り転送する(write()する)ということのようです。

現状の実装では、届いたデータを届くたびに転送(write)しているので、データが足らず、ブツギリになっているようです。必要なデータが足りていないということのようですね。

サンプルソースではQTimerで20msec毎にイベントを発生させ、呼ばれた関数内でバッファに溜まったデータを転送します。サンプルソースではPCMデータはコンストラクタから呼ばれる関数で生成時にバッファに生成されるため、通信のオーバヘッドを考慮する必要はないので、一定量のPCMデータを用意しておいて、20msecごとに必要な分だけ転送するようになっています。

ですので、ネットワークのオーバヘッドを考慮して、サウンドデバイスへPCMデータを必要な分だけ転送してやることが必要になります。なんとなく先が見えた、ような気がします(^_^;

バッファの空きサイズはQAudioOutputのメンバ関数bytesFree()で調べられます。
デバイスが要求するデータサイズは同じくメンバ関数periodSize()で調べられます。

これを表示するようにしてログを採ってみました。

$ ./debug/qtbrynhildr.exe
Boot : QDateTime("2014-03-27 23:32:09.621 JST Qt::LocalTime")
Assertion SUCCESS : brynhildr.cpp : LINE : 213
[control] Connected for control.
[graphics] Connected for graphics.
[sound] Connected for sound.
[sound] recievedSize = 3840
[sound] recievedSize = 3840
[sound] recievedSize = 5632
[sound] sample rate -> 48000
[sound] stop : IdleState
[sound] start
[sound] bytesFree(): 38400
[sound] periodSize(): 7680
[sound] stop : ActiveState
[sound] recievedSize = 3840
[sound] stop : IdleState
[sound] recievedSize = 3840
[sound] recievedSize = 5888
[sound] sample rate -> 48000
[sound] bytesFree(): 38400
[sound] periodSize(): 7680
[sound] stop : ActiveState
[sound] recievedSize = 7680
[sound] sample rate -> 48000
[sound] bytesFree(): 30720
[sound] periodSize(): 7680
[sound] recievedSize = 1792
[sound] sample rate -> 48000
[sound] bytesFree(): 23040
[sound] periodSize(): 7680
[sound] recievedSize = 5888
[sound] sample rate -> 48000
[sound] bytesFree(): 15360
[sound] periodSize(): 7680
[sound] recievedSize = 3840
[sound] sample rate -> 48000
[sound] bytesFree(): 15360
[sound] periodSize(): 7680
[sound] recievedSize = 5632

サウンドバッファのサイズは38400バイトのようです。この値は、再生中はいろいろ変化します。必要なデータサイズは7680バイトです。これは一定ですね。必要なデータサイズ分ないとbufferunderrunというのが発生します。再生するデータが必要なのにデバイスのバッファにはデータが無いよってことです。現在はこのbufferunderrunが発生しているため、聞き苦しいノイズが発生しています。

適当なサイズ分データを受け取るまで待って、7680バイトの単位で転送すれば良さ気です。ま、これをバッファリングというのですね。リングバッファを実装しなくては…googleさんで調べると…

stackoverflowで質問している人がいますね。

http://stackoverflow.com/questions/19059336/c-threadsafe-ringbuffer-implementation

threadsafeなringbufferらしいです。C++11が実装されたコンパイラでないとだめなそうですが…MinGW-4.8.1なら"-std=c++11"オプションが使えるらしいです、O.K.ですね。しかし、インデックスの計算に割り算を使ってます。バッファサイズを2のべき乗サイズにすれば、ここはAND演算に置き換えられますのでアクセスが速くできそうです。

どうしようかな…

2014年3月26日 (水)

配布方法を考える

#まだ音も出ていないのですが、ちょっと現実逃避。

Windowsでのバイナリ配布について調べてみます。

フリーのインストーラー作成ツールは、googleさんで検索すると…

「EXEpress CX 5」フリー版

最近アップデートされているので、メンテナンスは問題なさそうです。CABからEXEファイルを作成します。

「簡単インストーラ」

このツールも年末にアップデートされてます。

これらのツールがあるので、とりあえずなんとかなりそうです。

で、次に考えなければならないのが、配布用のファイルの準備です。さすがにQt-Projectの配布しているSDKを入れてくださいというのはまずそうです。500MBをダウンロードして、インストールすることに抵抗ありますよね、普通。

ということで、一番良いのはQtの関連ファイルを全くインストールすることなく使えることでしょう。

現在MinGW+Qt5で開発しているQt Brynhildr(仮称)は、MinGWとQt5の多くのダイナミックリンクライブラリに依存しています。

lddコマンドでリリース用実行ファイルを確認すると以下の様な結果が得られます。
#"???"となっているところはよくわかりません。cygwinのlddコマンドだからかな?

$ ldd release/qtbrynhildr.exe
ntdll.dll => /c/Windows/SYSTEM32/ntdll.dll (0x7ff81ebd0000)
ntdll.dll => /c/Windows/SYSTEM32/ntdll.dll (0x77580000)
wow64.dll => /c/Windows/SYSTEM32/wow64.dll (0x77530000)
wow64win.dll => /c/Windows/system32/wow64win.dll (0x774c0000)
wow64cpu.dll => /c/Windows/system32/wow64cpu.dll (0x774b0000)
??? => ??? (0x2b0000)
KERNEL32.DLL => /c/Windows/SYSTEM32/KERNEL32.DLL (0x77370000)
??? => ??? (0x2b0000)
??? => ??? (0x5a0000)
KERNEL32.DLL => /c/Windows/SYSTEM32/KERNEL32.DLL (0x77370000)
KERNELBASE.dll => /c/Windows/SYSTEM32/KERNELBASE.dll (0x76930000)
apphelp.dll => /c/Windows/system32/apphelp.dll (0x6ef30000)
msvcrt.dll => /c/Windows/SYSTEM32/msvcrt.dll (0x76a00000)
libgcc_s_dw2-1.dll => /c/Tools/develop/Qt/Qt5.2.1/5.2.1/mingw48_32/bin/libgcc_s_dw2-1.dll (0x6e940000)
libstdc++-6.dll => /c/Tools/develop/Qt/Qt5.2.1/5.2.1/mingw48_32/bin/libstdc++-6.dll (0x6fc40000)
Qt5Core.dll => /c/Tools/develop/Qt/Qt5.2.1/5.2.1/mingw48_32/bin/Qt5Core.dll (0x68880000)
Qt5Gui.dll => /c/Tools/develop/Qt/Qt5.2.1/5.2.1/mingw48_32/bin/Qt5Gui.dll (0x61940000)
Qt5Multimedia.dll => /c/Tools/develop/Qt/Qt5.2.1/5.2.1/mingw48_32/bin/Qt5Multimedia.dll (0x6b480000)
Qt5Network.dll => /c/Tools/develop/Qt/Qt5.2.1/5.2.1/mingw48_32/bin/Qt5Network.dll (0x69700000)
Qt5Widgets.dll => /c/Tools/develop/Qt/Qt5.2.1/5.2.1/mingw48_32/bin/Qt5Widgets.dll (0x61dc0000)
libwinpthread-1.dll => /c/Tools/develop/Qt/Qt5.2.1/5.2.1/mingw48_32/bin/libwinpthread-1.dll (0x64940000)
USER32.dll => /c/Windows/SYSTEM32/USER32.dll (0x75210000)
ADVAPI32.dll => /c/Windows/SYSTEM32/ADVAPI32.dll (0x76f30000)
ole32.dll => /c/Windows/SYSTEM32/ole32.dll (0x76e20000)
WS2_32.dll => /c/Windows/SYSTEM32/WS2_32.dll (0x77190000)
icuin51.dll => /c/Tools/develop/Qt/Qt5.2.1/5.2.1/mingw48_32/bin/icuin51.dll (0x71000000)
icuuc51.dll => /c/Tools/develop/Qt/Qt5.2.1/5.2.1/mingw48_32/bin/icuuc51.dll (0x6c280000)
GDI32.dll => /c/Windows/SYSTEM32/GDI32.dll (0x766d0000)
OPENGL32.DLL => /c/Windows/SYSTEM32/OPENGL32.DLL (0x68400000)
OLEAUT32.dll => /c/Windows/SYSTEM32/OLEAUT32.dll (0x765f0000)
WINMM.DLL => /c/Windows/SYSTEM32/WINMM.DLL (0x74eb0000)
CRYPT32.dll => /c/Windows/SYSTEM32/CRYPT32.dll (0x75090000)
DNSAPI.DLL => /c/Windows/SYSTEM32/DNSAPI.DLL (0x6c560000)
SHELL32.DLL => /c/Windows/SYSTEM32/SHELL32.DLL (0x75380000)
sechost.dll => /c/Windows/SYSTEM32/sechost.dll (0x77330000)
RPCRT4.dll => /c/Windows/SYSTEM32/RPCRT4.dll (0x74fd0000)
combase.dll => /c/Windows/SYSTEM32/combase.dll (0x767e0000)
NSI.dll => /c/Windows/SYSTEM32/NSI.dll (0x77320000)
icudt51.dll => /c/Tools/develop/Qt/Qt5.2.1/5.2.1/mingw48_32/bin/icudt51.dll (0x6c9c0000)
GLU32.dll => /c/Windows/SYSTEM32/GLU32.dll (0x4ff90000)
DDRAW.dll => /c/Windows/SYSTEM32/DDRAW.dll (0x5c760000)
WINMMBASE.dll => /c/Windows/SYSTEM32/WINMMBASE.dll (0x74d80000)
MSASN1.dll => /c/Windows/SYSTEM32/MSASN1.dll (0x75360000)
SHLWAPI.dll => /c/Windows/SYSTEM32/SHLWAPI.dll (0x76590000)
SspiCli.dll => /c/Windows/SYSTEM32/SspiCli.dll (0x74fb0000)
DCIMAN32.dll => /c/Windows/SYSTEM32/DCIMAN32.dll (0x64dd0000)
cfgmgr32.dll => /c/Windows/SYSTEM32/cfgmgr32.dll (0x771e0000)
DEVOBJ.dll => /c/Windows/SYSTEM32/DEVOBJ.dll (0x74d60000)
CRYPTBASE.dll => /c/Windows/SYSTEM32/CRYPTBASE.dll (0x74fa0000)
bcryptPrimitives.dll => /c/Windows/SYSTEM32/bcryptPrimitives.dll (0x74f40000)
IMM32.DLL => /c/Windows/system32/IMM32.DLL (0x76ac0000)
MSCTF.dll => /c/Windows/SYSTEM32/MSCTF.dll (0x77220000)
qwindows.dll => /c/Tools/develop/Qt/Qt5.2.1/5.2.1/mingw48_32/plugins/platforms/qwindows.dll (0x6a880000)
kernel.appcore.dll => /c/Windows/SYSTEM32/kernel.appcore.dll (0x74cd0000)
uxtheme.dll => /c/Windows/system32/uxtheme.dll (0x72110000)
dwmapi.dll => /c/Windows/system32/dwmapi.dll (0x716e0000)
qjpeg.dll => /c/Tools/develop/Qt/Qt5.2.1/5.2.1/mingw48_32/plugins/imageformats/qjpeg.dll (0x626c0000)
CRYPTSP.dll => /c/Windows/SYSTEM32/CRYPTSP.dll (0x72240000)
rsaenh.dll => /c/Windows/system32/rsaenh.dll (0x72210000)
bcrypt.dll => /c/Windows/SYSTEM32/bcrypt.dll (0x721f0000)

Qt5.2.1に依存しているところは配布前に解決しておく必要があります。このためには必要なライブラリをスタティックリンクしてしまう方法が考えられます。

googleさんで調べると、Qt-Projectが提供しているページでstatic linkについて説明されていました。

http://qt-project.org/wiki/How-to-build-a-static-Qt-for-Windows-MinGW

なんか「windows-build-qt-static.ps1」とかいうスクリプトがあるそうですね。Power Shellで書かれているそうです。#Power Shellって見たこと無いけど(^_^;

これを使って、なんとかすれば、Qtライブラリの必要のないコマンドができそうです。詳しくはその時になった時に読み倒すことにします。まだ、本体ができていないので…
#当然ですが、スタティックリンクするとコマンドはバカでかくなりますが仕方ありません。

あと少し気になるのは、サービスへの登録とかインストール時にUACが働くのか、などあるのですが、またその時に考えます。(クライアントだけならサービスは関係ありませんが)

PCMデータを確認する

とりあえず、届いたPCMデータを実際に聴いてみます。

届いたPCMデータを追記モードでファイルにそのまま記録します。その後先日調べたsoxコマンドでwavファイルに変換してみます。サーバには24000Hzでのサンプリングを要求しますが、適切に最適化され、異なるサンプリングレートで送られてくることがあります。今回の場合は48000Hzでサンプリングされたようです。以下のコマンドで変換してみます。

sox -r 48000 -b 16 -c 2 -e unsigned-integer -t raw test.pcm test.wav

プレイヤーで出来上がったwavファイルを聴いてみます。「う、音が割れている…」音楽らしき音が聞こえますがバリバリとノイズが入ります。「もしかして…」と思い、以下のコマンドで再変換します。

sox -r 48000 -b 16 -c 2 -e signed-integer -t raw test.pcm test.wav

ビンゴでした。2チャンネル16bitで量子化されているのですが、値はsigned intだったようです。Qt5ではunsigned intもサポートしています。これで綺麗に曲が聴けました、一安心。

もしかして、PCMデータのテンポラリファイル保存・再生バージョンで音が割れていたのは、unsigned int(QAudioFormat::UnSignedInt)を指定したからかもしれません。実はそれなりの音が出ていたのかも…と思いましたがやはりそうではありませんでした、そんなに甘くはありませんね(^_^;

来週は作業が出来ないのでそれまでに綺麗に音を出せるようにしたいなぁ…と思いますがどうなることやら。

テストのため隣の部屋のノートPCでYouTube動画をヘビーローテーションさせていますが、なんとなく精神衛生上良くないです。単にPCが起動しているだけなのですが、ずーっと音楽が流れているので。

キャプチャーしてみました。

http://youtu.be/10agC-lPCA8

次にアップロードする時は同時に音が出るバージョンにします。

2014年3月25日 (火)

PCMデータはどのように届いているの

Qt5でのPCMデータの出力方法はサンプルソースをよく読んでみたので大体察しがついて来ました。

おおまかに言うと届いたPCMデータをバッファリングし、フォーマットを指定した上で、再生開始の指示を出す、という感じのようです。PullとPushの2つの方法があって、オーディオデバイスのタイミングでデータをPullしてもらう方法と、明示的にデータをオーディオデバイスに送りつける方法の2つらしいです。

どちらにしてもネットワーク経由で届いたPCMデータをどこかにバッファリングして、適切に受け渡せるようにする必要がありそうです。

でも、BrynhildrサーバさんからどのようにPCMデータが届くのでしょうか?これが分からないと適切に扱えないような気がします。

これを確認するには、やはりデバッグプリントを挿入して調べてみるくらいしか方法が浮かびません。おおよそのPCMデータの再生の処理をサンプルソースを参考に実装します。そこへデバッグプリントを実装し、届いたデータのサイズやらエラーの種類、オーディオデバイスの状態、オーディオデバイスから要求されたデータサイズなどの情報を適当なタイミングで表示するようにしました。

表示させたデバッグプリントのサンプルが以下です。制御用の通信とグラフィックデータ用の通信のデバッグ表示は今はOFFにしてサウンド関係のみ表示するようにしています。

Assertion SUCCESS : brynhildr.cpp : LINE : 199
[control] Connected for control.
[graphics] Connected for graphics.
[sound] Connected for sound.
[sound] sample rate -> 48000
[sound] SoundDevice.setData():size = 3840
[sound] start
[sound] stop : ActiveState
[sound] SoundDevice.readData():len = 38400
[sound] SoundDevice.readData():len = 0
[sound] stop : IdleState
[sound] stop : StopppedState
[sound] sample rate -> 48000
[sound] SoundDevice.setData():size = 7680
[sound] start
[sound] stop : ActiveState
[sound] SoundDevice.readData():len = 38400
[sound] SoundDevice.readData():len = 0
[sound] stop : IdleState
[sound] stop : StopppedState
[sound] sample rate -> 48000
[sound] SoundDevice.setData():size = 7680
[sound] start
[sound] stop : ActiveState
[sound] SoundDevice.readData():len = 38400
[sound] SoundDevice.readData():len = 0
[sound] stop : IdleState
[sound] stop : StopppedState
[sound] sample rate -> 48000
[sound] SoundDevice.setData():size = 7680
[sound] start
[sound] stop : ActiveState
[sound] SoundDevice.readData():len = 38400
[sound] SoundDevice.readData():len = 0
[sound] stop : IdleState
[sound] stop : StopppedState
[sound] sample rate -> 48000
[sound] SoundDevice.setData():size = 7680
[sound] start
[sound] stop : ActiveState

最初に3840バイトのPCMデータが送られてきた後は、7680バイトごとのPCMデータが送られているようです。
サウンドデバイス再生用に要求されるデータサイズは38400バイトを1つの単位としているようですね。

一応確認のため、もう一度ログを取ってみました。すると最初の数回のやりとりはデータサイズが異なっていました。安定するとおおよそ7680バイトに安定するようです。最初の数回は1792バイトだったり、5888バイトだったりしますが、そのうち7680バイトに落ち着きます。(これは今回のサンプルの場合で送られてくるデータサイズはマチマチだと思われます。

これまでのログの解析の結果考えられる方法は大雑把に言って以下の様な感じでしょうか。

1,サウンドデバイスから要求されたデータサイズ分のPCMデータが届くまで待つ。
  届いたPCMデータはバッファへ順次コピーしておく。

2,要求されたサイズ分のPCMデータが溜まったら、サウンドデバイスへ転送する。

3,バッファをクリアし、1へ戻る。

上記のバッファリングをうまく行う必要がありそうです。

2014年3月20日 (木)

すべてはイベントである…らしい

PCMのバッファリングを検討していますが、気分転換に書きます。

リモートデスクトップツールなので、遠隔操作が出来なくては意味がありません(無いことはないですが(^_^;、操作したい時はありますよね)。ですので、デバイスの入力を扱う必要があります。

Qtでは、キーボード、マウス、タッチパネルなど入力デバイスからの操作をすべてイベントとして扱います。キーを押したり、離したり、マウスを動かしたり、クリックしたり、そういった操作は全部イベントとして伝わり、このイベントと指定の関数を結びつけることで、キーを押すたびにとか離すたびに呼び出される関数が指定できます。

この仕組みはQtでのいろんな処理についても同様に扱えるようになっています。例えば、ウィンドウのCloseアイコンでウィンドウが閉じられたりした時に呼び出す関数の指定も、ネットワーク通信で接続が完了した時、データが届いた時、全部同じように結び付けられた関数が呼び出され、その中で処理を行うことになります。

キーボードの操作、マウスの操作(クリック、ホイール、その他)もイベントで伝わってくるところまでは、すでに実装していますが、Brynhildrサーバさんにどのように伝えるのかがよくわからないので、Pending中です。

書き忘れてましたが、メニューとかアイコンを選択した時の操作もイベントとして扱われます。
例えば、こんな感じ。このイベントがきたら、この関数を呼び出してねという設定です。


void Brynhildr::createActions()
{
    // exit Action
    exitAction = new QAction(tr("Exit"), this);
    exitAction->setStatusTip(tr("Exit Qt Brynhildr"));
    connect(exitAction, SIGNAL(triggered()), this, SLOT(exit()));

// about Action
aboutAction = new QAction(tr("About"), this);
aboutAction->setStatusTip(tr("Show Qt Brynhildr"));
connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));

// about Qt Action
aboutQtAction = new QAction(tr("About &Qt"), this);
aboutQtAction->setStatusTip(tr("Show Qt library's About box"));
connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}

#もちろん、QtのRADツールを使えば、このあたりはGUIで簡単に作れると思います。
#でも、手動での作り方を知っておいて損はないと思います。

ここまで書いて、アレなのですがキーボードとかマウスの操作では予め呼び出される関数が決められています。
これを自前の関数が呼び出されるように変更するためには、関数のオーバライドという仕組みを用いることになります。要は決められた名前(引数も同じでないといけません)の関数を自分のクラスでも定義すればいいんですが、このあたりはC++のクラスについて知る必要がありますね。

どんな関数を書けば(オーバライドすれば)いいかはQt Assistantで調べられます。例えば、こんな関数を定義します。
#オーバーライドするということはもともと標準の処理がすでに入っていることを意味します。ですので、標準の処置も行いたい時は、オーバライドする前のもともとの関数を呼び出してやる必要があります。

// paint event
void paintEvent(QPaintEvent *event) ウィンドウ内部の画像再描画が必要な時に呼び出されます

// resize event
void resizeEvent(QPaintEvent *event) ウィンドウの大きさを変えた時に呼び出されます

// mouse press event
void mousePressEvent(QMouseEvent *event) マウスボタンを押した時に呼び出されます

// mouse move event
void mouseMoveEvent(QMouseEvent *event) マウスを動かした時に呼び出されます

// mouse release event
void mouseReleaseEvent(QMouseEvent *event) マウスボタンを離した時に呼び出されます

// key press event
void keyPressEvent(QKeyEvent *event) キーを押した時に呼び出されます

// mouse wheel event
void wheelEvent(QWheelEvent *event) マウスホイールを回した時に呼び出されます

どんなキーを押したのかとかマウスの位置情報とかはそれぞれの引数(イベント)に情報が含まれてますので、関数の中でこれらの情報を取得して、いろんなことを調べられます。昔みたいにI/Oポートを調べて…なんてことはしなくていいのは便利ですね。今どきはそんなことをしているのは最下層のドライバーさんたちなので、Qtはその情報をさらにわかり易く加工して開発者に提供してくれています。

#私自身がC++初心者なので、うまく伝わらないかもしれませんね。
#ソースを見るのが参考になると思うのですが…

2014年3月18日 (火)

音の出し方が違う…

Qt AssistantでQAudioOutputクラスを調べようとして、同じ並びに「Audio Output Example | Qt Multimedia 5.2」という項目があることに気づきました。ここにあるサンプルソース audiooutput.cpp を見ると、メモリ上のPCMデータを使って音を出力する例が載ってます。

このサンプルソースをじっくり読んでから、さらにリングバッファの実装を検討してから、修正にとりかかります。
やっつけ仕事は後で結局面倒なことになりますのでよく検討してから実装したほうがよいというのが経験則ですね。

Qt Brynhildr(仮称)の基本機能はおよそ2,000行程度で実装可能な予感がします。ソースコード中にハードコーディングしているパラメータの設定ダイアログとかを実装するともう少し必要かもしれませんが。

これもすべてQt5さんのおかげです。

(追記) サンプルソースを読むと、Qt5プログラミングの作法みたいなものがなんとなく分かります。

効率的なバッファリングはどうすればいい?

さて、PCMデータのバッファリングが必要だろうなぁという推測はたてたのですが、解決策は考え中でした。

"アルゴリズム データ"とか"アルゴリズム データ構造"で検索すればたくさんの本が引っかかります。
古典的バイブルから最近のJava, C++, C#など具体的な本までよりどりみどりです。

いろいろ勉強したい時は一冊良書を購入して欲しいですが、今はバッファリングに限定して調べたいので…

"バッファリング 高速化 アルゴリズム"でgoogleさんにお伺いを立てます。

ちゃんとまとめている方がいらっしゃいますね、すばらしい。C#でのサンプルのようです。

http://ufcpp.net/studY/algorithm/index.html

バッファリングに関しては以下です。

http://ufcpp.net/study/algorithm/col_circular.html

某知恵袋に質問する人もいますね。サンプルソースも作ってくれる方がいるようです。#今度何かあったら質問しよう。

http://okwave.jp/qa/q5448508.html

リングバッファ(ring buffer)、循環バッファ(circular buffer)と呼ばれる手法が一般的だそうです。

自分で実装するのも手ですが、すでにあるBoostというクラスライブラリを使ったりするのも手ですね。C++にもう取り込まれているのでしょうか?最近疎いので分かりません。

boost: https://sites.google.com/site/boostjp/tips/circular_buffer

とりあえずアルゴリズムが決まれば、あとは実装するだけなのですが、今日はこのあたりでやめときます。
#今日は疲れました。

(追記:2015/11/02)

Qt Brynhildrで実装しているバッファはオーソドックスなリングバッファです。C++で書いたシンプルなもので、かもなく不可もなくという感じです。(sounbuffer.cpp)

ソースコードの構成を変更したら

(追記)
.proがMakefile*よりも新しい場合は自動的にqmakeを再実行するようになっていました…
make distcleanなどを行う必要はありません。以下の記事は修正しておりませんがご容赦ください。

-- ここから --

Qt5を使ってアプリケーションを開発する場合ソースコードを追加したりしたら、Makefile*を作り替える必要があります。Qt5をバージョンアップしたら問答無用でMakefileは作り直し(qmakeの再実行)です。

また、.proファイルの内容を変更する必要があるかもしれません。利用するQt5のモジュールに変更があった場合も同様です。

GUI、ネットワーク、マルチメディアを使う今の実装では、例えば.proファイルは以下の様な内容になります。


######################################################################
# Automatically generated by qmake (3.0) ? 2 12 23:44:23 2014
######################################################################

TEMPLATE = app
TARGET = qtbrynhildr
INCLUDEPATH += .
QT += gui
QT += network
QT += widgets
QT += multimedia
RESOURCES = brynhildr.qrc

# Input
HEADERS += brynhildr.h mainwindow.h util.h common.h protocols.h machine/protocols_x86.h machine/protocols_x64.h
SOURCES += brynhildr.cpp mainwindow.cpp main.cpp


.pro ファイル自体を作りなおす(qmake -project)こともできますが時間がかかることがあるので、最低限のソースコードを生成してから一度作った後は手動で.proを変更し、Makefile*を作り直すようにした方が良さそうです。


ソースコードはgitで管理しているので、削除、移動、追加した場合はそれぞれgit rm/mv/add を使ってます。
gitはファイル自体の削除、移動も同時に行うので、驚かないでください。

.proファイルも要変更です。

[image/image.jpを削除する]

git rm images/image.jpg

[protocols_x86.hをmachine以下に移動]

git mv protocols_x86.h machine/protocols_x86.h

[newsource.cppをカレントディレクトリに追加]

git add newsource.cpp

のような感じです。

ライセンスの確認をしてみる

以下のページでQtのライセンスの確認をしてみました。

http://www.sra.co.jp/qt/faq/licenses.html


問 : これからは Qt をどこでも無料で使えるのですか。
答 : 使えません。LGPL または GPL ライセンスで唱われる義務を守ったオープンソースソフトウェアを作成する場合のみ、Qt を無料で使用できます。
もしも、どのような理由であれ、そのようにできない/したくない場合は、商用ライセンスを購入する必要があります。


ということは、ソースコードを公開しないソフトウェアは作れないということ?ですかね。

確認すると


問: 自分のソースコードを公開したくないのです。どうすればいいですか。
答: Qt の LGPL 版または商用版ライセンスを購入しなければなりません。


と書いてあります。ま、公開するんでいいんですけどね。修正BSDは使えないということですね…

どちらにしろライセンスの問題は難しいですね、賠償問題とかなったら面倒この上ないことになりそう。

あ、今気づきましたが、SRAからLGPL版Qtが入手できますね。
最新のQtを試そうとすると結局オープンソース版Qt5のソースコードから作らないといけないのでしょうけど。一応後で確認します。開発規模を入力するところがあるのですが、さすがに一人ってアレだし、あと部署だとか会社名とか入れなければなりません…会社でないし(^_^; 大人しくソースコードから作ろうかな。

MemoryBarrierとはなんぞや

最初にQtで開発を始めた時に、ハマったので書いておこうと思ったのですが、今の環境で試すとエラーになりません。だったら、書かなくてもいいかと思ったのですが、ちょっとだけ書いておきます。

ビルド時に以下のようなエラーが出るというものです。

C:\Qt\Qt5.1.1\5.1.1\mingw48_32\include\QtGui\qopenglversionfunctions.h:785: error: expected unqualified-id before ')' token
void (QOPENGLF_APIENTRYP MemoryBarrier)(GLbitfield barriers);

「MemoryBarrier」ってなんだ?ということなんですが、いろいろgoogleさんで調べた結果以下のページが引っかかりました。(日本語のページは見つけられなかったです)

http://stackoverflow.com/questions/18739688/compile-time-error-from-a-qt-file-expected-unqualified-id-before-token

つまるところMinGWのバグってことらしいです。

http://sourceforge.net/p/mingw/bugs/2024/

以下をインクルードすることで対策できます…が。

// -*- mode: cc-mode; coding: utf-8-unix -*-
// last updated : 2014/03/18
#ifndef COMMON_H
#define COMMON_H

// for Qt 5.2.1 with MinGW 4.8.1
// http://stackoverflow.com/questions/18739688/compile-time-error-from-a-qt-file-expected-unqualified-id-before-token
// http://sourceforge.net/p/mingw/bugs/2024/
// Windows always needs this to ensure that APIENTRY gets defined
#if defined(Q_OS_WIN)
# include
# undef MemoryBarrier
#endif

#endif /* COMMON_H */

MinGWを最新にしたら、この対策は要らないということになりました…ソースファイルをアップデートしなければ…

MinGW + Qt5 + Cygwin

少しだけWindows 64bitでの開発環境について書きます。

MinGW(4.8.1) + Qt5.2.1 + Cygwin (x64) で開発しています。MinGW, Cygwinのダウンロードについては多くの情報があるのでここでは書きません。Qtもインストーラがついているのでインストール自体は問題無いと思います。

開発環境としてはCygwinの端末上で行うのですが、C++コンパイラはMinGWのg++を使います。単純に考えるとg++コマンドへのパスを設定するだけなのですが、makeコマンドとしてはCygwinのmakeコマンドにはqmakeが生成するMakefileが対応していません。このため、MinGWでインストールされるmingw32-makeを用いる必要があります。

いろいろ試行錯誤(trial and error)した結果、make.shというシェルスクリプトを書くことにしました。内容は以下の様な感じです。

#!/bin/bash
/c/MinGW/bin/mingw32-make CC="c:/MinGW/bin/gcc" CXX="c:/MinGW/bin/g++" LINKER="c:/MinGW/bin/g++" $1

使い方は、以下です。カレントディレクトリにパスは通してはいけないので…ちゃんとカレントディレクトリを指定します。引数は、通常debugです。./debugの中に自動生成のソースファイル、オブジェクトファイル、実行ファイルが生成されます。

./make.sh debug

ちなみにCygwinの最新のmakeコマンドは、バージョン4.0です。

$ make -v
GNU Make 4.0
このプログラムは x86_64-pc-cygwin 用にビルドされました
Copyright (C) 1988-2013 Free Software Foundation, Inc.
ライセンス GPLv3+: GNU GPL バージョン 3 以降
これはフリーソフトウェアです: 自由に変更および配布できます.
法律の許す限り、 無保証 です.

$ LANG=C make -v
GNU Make 4.0
Built for x86_64-pc-cygwin
Copyright (C) 1988-2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

MinGW(4.8.1)のmakeは3.82.90です。

$ LANG=C /c/MinGW/bin/mingw32-make -v
GNU Make 3.82.90
Built for i686-pc-mingw32
Copyright (C) 1988-2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

make 4.0を使うと以下のようなメッセージが表示され、makeできません。

$ make
Makefile:62: *** 複数のターゲットパターンです. 中止.

$ LANG=C make
Makefile:62: *** multiple target patterns. Stop.

と、ここまで書いて、ふと気づいたのですが…MinGWのg++コマンドへのパスが通してあったのですが、
そのように設定しておけば、普通に

/c/MinGW/bin/mingw32-make.exe debug

と実行するだけで、makeできました…ということはmake.shは要らないかも(うう…)。

ということで、make.shは削除することにしました。 (git rm make.shで削除)

.bashrcで以下のようにaliasすることにしました。

# for Qt
alias mmake='/c/MinGW/bin/mingw32-make'

source ~/.bashrc

で再読み込みさせると、

mmake debug

でmakeできました。'm'を1つ多く打つ必要はありますが、それくらいはいいでしょう。

当然ですが、Cygwinのg++より前にパスを設定する必要があります。

ちなみに私の環境変数PATHの要約は以下の通りです。

$ echo $PATH
/home/xxxxxxx/Bin /home/xxxxxx/Bin/win64 /c/Tools/develop/Qt/Qt5.2.1/5.2.1/mingw48_32/bin /c/MinGW/bin /usr/local/llvm/bin /usr/local/bin /usr/bin /c/Windows/system32 /c/Windows

重要なのはパスの順番ですね。

このパスの順番がおかしいとmakeできたコマンドを実行しようとしても、何も表示されない(No Message)で終了してしまいます。main関数に到達する前のスタートアップの時点で異常終了するためです。main関数にいくらデバッグ表示を入れても、うんともすんともいいません。

多分初心者だとコマンドがメッセージ無しで終了するので、どこが悪いのか分からずハマってしまいますね、多分。私もハマりましたが、googleさんで探しても日本語での情報が見つからず、英語のページを探しまわって、ようやくそれらしい原因が言及されているページを見つけました。「Qtをインストールしなおせ」とか「もっと基本からやり直せ」とか中々的を射た指摘を見つけるのに苦労しました。

パスはQt -> MinGW -> cygwin の順に設定しましょう。

(*) If you use both of cygwin and MinGW and Qt, check PATH environment variable.
PATH order : Qt -> MinGW -> cygwin

これらを調べるために、かなりの時間を費やしました。次に試す人の参考になればいいのですが…

あと参考ですが、ソースコードはUTF-8N, LF で記述してます。(まだ日本語入れていないのですが(^_^;)
つまり、以下の様なemacs用の設定をソースコードの先頭に入れてます。

// -*- mode: cc-mode; coding: utf-8-unix -*-

emacsを使う酔狂な方がどれくらいいるのか分かりませんが、ご参考ということで。

あ、あとソースコード公開の準備としてソースコードの整備をしていますが、一応gitで管理してます。公開する前に正式なリポジトリは作りますが、とりあえずプロトタイプの時点からソースコードを管理する癖を付けたほうがよいかと思います。バックアップがないと不安なので(^_^;

進捗記録 2014.3.18

ここまでのまとめ…音出てないけど。

最高クオリティにするとオリジナルのデスクトップとまったく遜色ないレベルの画像となりますがその分通信量が50Mbpsレベルとなります。標準レベルで25Mbpsくらいです。これらは、音声データも含みます。

http://youtu.be/cmSlMe6uyLw

VMware上のBrynhildrサーバとの通信なのでローカルホストに閉じているので問題ないですが、外から繋ぐ場合はもっと画質を落とすことになりそうでしょうかね。

技術評論社から出ている「オンラインゲームを支える技術 壮大なプレイ空間の舞台裏」を読むといろいろ大変だなと思いますね。PS4のクラウドゲーム環境(PS Now)もこういう技術を使うらしいです。あらゆる技術を総動員する必要がありそうですね。

Linux 64-bit でも画像でました

今日ビルドし直すとUbuntu 64bitでもデスクトップ転送までは正常動作しました。

違いといえばノートPC上のBrynhildrサーバからVMware上のWindows XP上のBrynhildrサーバに変更したこととサウンドのモードをCoreAudioからダイレクトサウンドに変更したことだけです…、謎です。
# カーネルを最新stableの3.13.6に作りなおしたけど、関係ないしな…

ま、エンコード計算自体はO.K.だったということで一安心。

しかし、音はまだ正常に出ないので、PCMデータのバッファリングの仕組みをきちんと入れないと…音が聞こえないのは悲しいですね。

20140318_114224

Linux 32-bitでなく、64-bitだといっても分からないですね、これでは(^_^;

キャプチャしてみました。

http://youtu.be/LALHAj464pE

2014年3月16日 (日)

Linux 64-bit 再び

Ubuntu 64-bit移植のため、プロトコル構造体を見直しました。

結局のところ、8バイトになってしまったlongを4バイトであるintに書き換えただけでO.K.でした。あと定数をL付きからLなしにすることも必要でしたが。それぞれのメンバオフセットは正確に一致しています。1つだけdoubleのメンバがありますが、問題なさそうです。

さて、64bit Ubuntu 13.10 でビルドしようとしましたが、Ubuntu 13.10でパッケージとして提供されているQt5は5.0.2と少し古いです。Windowsでは5.2.1を利用しているので、これに合わすためQt Projectから直接最新をダウンロードしてインストールしました。

qt-opensource-linux-x64-5.2.1.run

というファイルです。普通システムにインストールするので、sudoコマンドでインストールします。

#ちなみに5.0.2では「multimedia moduleはない」という旨のメッセージが表示されます。

sudo ./qt-opensource-linux-x64-5.2.1.run

インストーラウィンドウが表示され、/opt/Qt5.2.1 にインストールするよう勧められます。あまり気にしないので、そのままインストールします。Qt5.2.1/5.2.1/gcc_64/bin へのパス設定追加をお忘れなく。

5.2.1のqmakeコマンドを使えば、問題なくMakefileが生成されました。

これでO.K.かと思いきや、さらなる問題が発覚しました。認証チェック用のデータ生成処理が32bit時と異なるようです。ま、x64でウィンドウが出たので今日はよしとします。基本的には書き換えなしでO.K.です。コードの可搬性の問題ですね。移植性がないコードを書くとハマることがよくありますね。

これで普段使っているWindows8.1とUbuntu x64 での検証作業ができることになりました。ソースコードはコメント込みで1511行です。コメント(ワンラインコメント"//"でしか書いていない)が457行なので、実質1000行ちょっとですね。AndoroidとかiOS(iPhone, iPad)とかMacも検証できるといいですが、あまり手を広げすぎても進まないので、しばらくWindows8.1とUbuntu x64 で確認したいと思います。(FreeBSDも確認したいんですが…5.2.1はソースからビルドしなければならないかも)

20140316_175714

コンパイル時にQt5さんが自動生成するソースコードは6000行ちょっとです。
moc_xxxxx.cpp, qrc_xxxxx.cpp という名前のソースコードが自動生成されます。Linuxだと標準でMakefileと同じディレクトリに生成されるので、少し気持ち悪いです。qmake実行時に何か指定できるのかも、後で調べよう。

(追記) 自動生成するコードのうち5943行はjpgファイルの取り込み用のデータ定義(qrc_xxxx.c)でした。

(追記2) openGLライブラリが必要でした。

sudo apt-get install libglu1-mesa-dev

でopenGLライブラリをインストールしてください。

音がでないなぁ

Phononの代わりにQt Multimedia moduleを使うことは分かりましたが、参考書は使えませんので自力で試していくしかありません。一応googleで検索しますが、ピンポイントには難しそうです。

まずは、Qt Assistantですね、やはり。「Qt Multimedia」で検索します。

提供されているクラスライブラリを眺めます。「QAudioOutput」がそれっぽいでしょうか。リンクをクリックして「QAudioOutput」へ移動します。「お、サンプルソースが載っている」これを参考にすれば音が出るのかも。

サンプルソースを読んでみると、どうやら音声ファイルを読み込んで、再生の開始を指示して一端関数は終わって、再生が終わったら特定の関数が呼び出されて終了処理をするという手順のようです。ということは、Brynhildrサーバさんから届いたデータを届いたデータの順にどんどん再生すれば、結局一連の音声データが再生できそうな感じですね。

現在の実装では、音声データは到着順にファイルにどんどん上書きしてくことにしています。サーバさんが送ってくる音声データは今回の場合(Windows7 NotePC)サンプルレート48000Hzで10KB以下に抑えられているようです。本当はファイルに落とすことは無駄なのですが、チェックのためにそのようにしています。

ところがそのようにしたことで、今はトラブっています。お気づきだと思いますが、ファイルを指定して、音声再生を指示すると後は、バックグラウンドで音声再生が行われます。しかし、次々と音声データは送られてくるわけで、どんどん同じファイルに上書きしているのです。このため、ファイルのオープンやサウンドデバイスのオープンでタイミングが悪いと失敗します。その結果音声がブツギリで聞こえてしまい、最後にはQt5さんの内部データに不整合が起こって、ぶつっとアプリケーションが終了します(^_^;

ま、これはファイルにしたからということでもなく、メモリ上にデータ置き場を作っても同じ状況が発生します。これを避けるにはデータの上書きが起こらないように適切に調整することが必要となりそうです。
少し落ち着いて考える必要がありそうです。

今回のテストではローカルのVMware Workstationでサーバを走らせると音が出ているのか分からないので、ノートPCを利用してます。

20140316_135126

音はぶつ切れにしか出ていません(^_^; #動画はYoutubeで公開されているもので、たいした意図はありません(^_^; テストのためループ中。


おまけ

最初音声ファイルの内容を耳で確認しようとしました。
生のPCMファイルを聞くためのツールを知らなかったので、VLCというメディアプレイヤーを利用しようとしましたが無理です。生のPCMファイルなので、どんなデータか分からないのですから当然です。

どのような音声ファイルかを知らせるために、ファイルの先頭にヘッダを付ける必要があります。なんかRIFFという形式のヘッダーをつけるそうです。が、WikipediaでRIFFを調べても、いまいち分かりません…最小単位のチャンクと呼ばれるものが幾つかあるらしいのですが…

こういう時はgoogleさんで調べましょう。「raw 音声 変換 wav」で調べてみます。
下記のURLが先頭にありました。

http://www.xucker.jpn.org/pc/sox_raw.html

どうやら、オープンソースで提供されているsoxというツールで生のPCMファイルをWAVファイルに変換できるようです。幸いなことに普段使っているcygwin(x64)の中にすでにsoxは提供されているようです。

ただ、上記のページは古いsoxに関する記述のようなのでman soxとして確認しました。

例えば、サンプルレート48000Hz 16bit ステレオ 2ch の場合だと以下のようにすればwavファイルに変換できます。

sox -r 48000 -b 16 -c 2 -e unsigned-integer -t raw test.pcm test.wav

バイナリエディタでみると最初の4バイトが"RIFF"となっていて8バイト目から"WAVE"となっているので".WAV"ファイルに変換されているようです。

と、ここまでくれば音が聞こえると思ったのですが、VLCで再生しても、どう再生しても、何も聞こえず、速攻で終了します。

16bit、ステレオ2ch、サンプリング・レート 48000Hz、データサイズ 10KBの音声データがどのくらい長さなのかを考えれば、まず最初に気づくべきでした。あまりに短すぎて、人間の耳では聞き取れません…

今の状態はこんな感じです。画像自体は滑らかなんですが、音がだめだめです。

http://youtu.be/CvlJzSoaKXo

ホントはこんな画像と音声が出ます。これはBrynhildrの最新バージョンです。

http://youtu.be/TD9fuYGswl8

ローカルLANです、念のため。

2014年3月15日 (土)

いちおう画像データのことも載せておこう

Brynhildrではデスクトップの画像をjpegデータとして転送します(少なくとも公開されているサンプルソースでは…)。一般的にはデスクトップの情報は通信量を少なくするためにそれぞれのGUI部品に分解して、その描画用情報を送るというのが常套手段でした。

が、Brynhildrでは、最終的に出来上がっているデスクトップの画面そのものを一枚の画像として転送する方法を取りました。昔のようにGUI部品それぞれが単純な部品で構成される場合かなり軽いのですが、最近では殆どビットマップ情報を転送するような形になるので、普通に転送すると結局重たいままになるようです。

それだったら、最終的な画面情報だけをデータ圧縮して送ったほうが結局軽くなるんでない?というのがアイデアだと思われます。クライアントソフトは、送られてきた圧縮済み画像データを紙芝居の如く到着するたびに表示するだけに専念できるということですね。ま、音も再生しないといけませんが(^_^;

下のサンプルだとおよそ98KBです。Brynhildrサーバはこのような画像を全力で送りつけてきます(^_^;


Test

この情報は通常のJPEGファイルなので、ファイルに書きだすようにすれば、通常の画像ファイルとしてダブルクリックで閲覧することが出来ます。枚数が恐ろしく多いので、今はどんどん上書きするようにしてますが。

通常のJPEGファイルなのでヘッダーも存在します。バイナリで見ると以下の様な感じです。
実はヘッダーの詳しい内容は知りません…Qt5さんが勝手に解釈してくれるので(^_^;

20140314_233909

これが一秒間に30枚表示できれば、30 FPSになるわけですね。Qt Brynhildr (仮称)では、ネットワーク経由で
データが到着する度に、1枚分画像が送られてきたかをチェックして、1枚分受け取ったと思ったら、どりゃーと表示をQt5にお願いするということをしています。描画処理自体は、Qt5さんにおまかせです。Qt5さんはメモリ経由で渡されたJPEGヘッダを解析して勝手に描画してくれます。

画像描画、音再生などをどのタイミングで再生するかはあまり考えてなくて、到着次第すぐに再生という指示だけ行うのですが、まぁいろいろタイミングを考えるよりは楽チンでいいかなと思います、マルチスレッド面倒だし。
ま、紙芝居表示するのに実ソースコード1300行(コメント含む)というのはやはりQt5さんのお陰なのです。JPEGも詳細を知らなくても表示できてるし(^_^;
#PNGとかに変更できるとメリットあるのかな…でもサーバを実装しないといけないな…まずはクライアントを完成させなくては。

明日は早いので、もう寝ます。
#読者はおよそ一名様状態なので…ぼちぼちでいいかなぁ。
#何かありましたらご指摘ください…変なこと書いていたら(^_^;

2014年3月14日 (金)

音を出すにはどうするの?

Brynhildrサーバーさんからは、画像データと音データと入力デバイス(キーボード、マウス)のデータが送られてきます。厳密には、こちらのデバイスのデータを送ったりもします。今のところ、デスクトップは表示できていますが、音データは暫定でファイルに落としているだけです。中身はPCMデータだそうです。

具体的にはこんな感じです。生のデータだけなので、ヘッダーはありません。

20140314_215956_2

音を出すには、ってどこかに書いてあったな…と思い出して、「実践Qt4プログラミング」を探しました。
第2章「オーディオとビデオ」という章が見つかりました。「Phonon マルチメディアフレームワーク」というのがあるそうです。さっそくQt Assistantを起動し、該当するフレームワークのドキュメントを検索します…と、

「Porting Guide | QtDoc 5.2」という項目しか出てきません。「ん、悪い予感がする」と思いながらポチッとハイパーリンクをクリックしました。

The following list summarizes the changes in Qt 5:

という項目がありまして、そこの最後の項目に以下のように書いてあります。

Multimedia - In Qt 5, multimedia support is provided by the Qt Multimedia module. Phonon framework is no longer part of Qt, but it continues to be maintained by the Phonon developers and has support for Qt 5. See http://phonon.kde.org.

20140314_221359


「もうPhononはQtの一部ではなくなったよ、代わりにQt Multimedia moduleを使ってね、あ、でもPhononもメンテされてるよ、ここで(URL)」

て感じですかね。つまりPhononを使うことはできるけど、それはQtの正式サポートではないということなので、今後を考えるとQt Multimedia moduleを使ったほうが良さそうです。

しかし、参考書は参考にならない…ということになり、頼りはQt Assistantさんだけのようです。英語の文献を読むのかぁ…。まぁ、参考書自体もそんなに記述が分かりやすいわけでもないので、今後のために読んでおいても損はないかと思い直すのでした。しかし、明日にしよう。

2014年3月13日 (木)

Qt Brynhildr on Linux x86

VMware Workstationに 32bit版 Ubuntu13.10 をインストールして、Qt Brynhildrをビルドしました。

qmakeコマンドでMakefileを作りなおして、makeを実行すると全く修正なしでビルドできました。
バイナリができる場所がWindowsとは違うようですね。

Qtb_on_ubuntu

Windows8.1上で走るVMware Workstationの中で走るUbuntu13.10(32bit)の中でQt Brynhildrが走り、その中で同じくVMware Workstation上で走るWindows XP Professionalの画面が出てます。訳が分からないですね…


スクリーンキャプチャをアップロードしました。
スプラッシュウィンドウは消えるのが早すぎて分からない…


http://youtu.be/fyuf44fDwg4

2014年3月12日 (水)

試しに Linux 64-bit でつくってみる

テスト画面が出たので、試し、Ubuntu 13.10 (Linux 64bit) で作ってみることにしました。

まず、VMware上のLinux 64-bit 仮想マシンにソースコードを転送します。
Windows(Cygwin x64)で使っているホームディレクトリをアーカイブして、仮想マシンにftpします。
共有できるようにしているので、基本同期をとるだけでO.K.なんですが…

ここからLinuxでの作業になります。

Windows版のQtでは、qmakeコマンドで以下の3つのファイルができます。

Makefile
Makefile.Debug
Makefile.Release

ですが、Linuxだと Makefile の1ファイルとなります。(まだあまり試せてないのですが、デフォルトではそうです)
で、普通に make とすると、

#error "Not support 64 bit compiler!!"

と出ました。自分で、そう出るように記述していたのですが、それを忘れてました(^_^;

構造体の宣言がおもいっきり、32 bit に依存してました…

googleさんで調べると…g++コンパイラ (64bit)はlongが8バイトであることとアライン条件が異なることが分かりました。(昔sparcとかに依存していてハマることはありましたが)

brynhildrサーバーさんが送ってくるデータなので、勝手なことはできません。JPEG,PCMデータはO.K.ですが、コントロール(キー入力、マウス入力など)は残念ながら、x86(32bit)依存ですね。

昔読んだ本を引っ張り出してきます。「Write Protable Code」 2006年初版です。386BSD(PC98)やLinux(PC98)でも有名な鵜飼さん(他一名の方)が監訳されてます。BitKeeperの話は出ていますが、gitの話はまだ載ってません(^_^;

どうやら、バイトオーダー、アライン条件など吸収するライブラリを作るか、地味に調整するしかなさそうです。
サーバ側もいじれたら、Qtの機能で解決できそうですが、サーバ側はすでにあるという前提なので…

んー、iPhoneとかAndroidとかに展開する時はやはりarmとかに適合させる必要があると思うと少しガックリ(´・ω・`)

ちょっと要検討…です。先にLinux (x86)で試してみようかな…、32bitなので、すぐウィンドウは出てくれるはず。

同様に移植、コーディングの参考になる本としては、以下の2冊を見つけました。

「Code Quality」
「Code Craft」

いずれも毎日コミュニケーションズ刊です。他にもありますが、載せきれません。

2014年3月10日 (月)

進捗記録 2014.3.10

デスクトップの一部をキャプチャしてみました。
#スプラッシュウィンドウはテスト用イメージです。

軽いですね。どのくらいのFPSが出ているか気になりますが、JPEGで1転送あたり100KB程度のようです。
ローカルホスト内のVMware WorkstationなのでFPSはあまり参考にならない…かも。

http://youtu.be/3JAjx0kej0U

2014年3月 6日 (木)

進捗記録 2014.3.6

なんとなく絵はでるようになりました。まだ、入力デバイスは使えません(^_^; 音も出ません…

20140306_021040


サーバ機能も実装すれば、iPad/iPhone/Windows Phone/TizenなどをWindowsやLinuxでリモート・コントロール出来ますね、多分。そんな機能が欲しがられるのか不明ですが…
ソースコードは1468行。デバッグ表示が多いので正味は結構少ないかも…

2014年3月 2日 (日)

Qtでできること


Qtでできることの最初のイメージ→GUI関係のみ。GUIの定義はあまり分からない…Windowの描画とかキー、マウスの制御とか…。

で、さらりとQt4の入門編(入門Qt4プログラミング)を流し読みしてみると、入門編だけで結構プログラミング出来るかもしれない、という印象。

とりあえず、入門編と最新のQtのページ(http://qt-project.org/)を少し読んでみてまとめますと。

(1) サポートしている環境

Android
BlackBerry
Sailfish OS (組み込み向けLinuxの1つらしい)
QNX
VxWorks
iOS
Linux/X11
Mac OS X
Windows (x32/x64)
Windows CE

[現在進行中]
WinRT (Windows Phoneを含む)
Tizen(新しい組み込みOS:Docomoから出る予定だった…)

(2) 利用可能な開発ツール (記述言語はC++です)

Visual Studio 2010 SP1 (ExpressでもO.K.っぽい)
2012 SP2 (ExpressでもO.K.っぽい)
2008 + Windows XPも可能

MinGW-4.8.0

Clang (appleから提供されている)

GCC (appleから提供されている)

(3) 情報源

日本語、英語などのページが結構充実している。ググれば、いろいろ情報は出てきそう。パッケージに含まれるQt Assistantというアプリケーションでリファレンス文書が検索、閲覧できる、これは便利。英語だが、技術英語なので、比較的分かりやすい。あと、開発者が国内外に結構いるため、ノウハウが蓄積されているらしい。

(4) ソースコードが公開されている

最終的には自分で調べられる…が。

(5) いろいろな部品(ライブラリ)をサポートしている

 ウィンドウ部品、入力デバイス(キーボード、マウスなど)以外に以下をサポートしている。

ネットワーク通信関係
マルチスレッドサポート関係
ファイル操作関係
印刷関係
マルチ言語対応(国際化)
プラグインの仕組み

あと、うれしいツールとして、GUIのRADツール, Qt Assistant。

まとめると、フリーな開発環境を使って、たくさんのOSで動くアプリケーションが、1つのソースコードを書くことで、ほぼ移植作業を行わずに開発できて、詰まったら、豊富な情報を利用できて、ソースコードを見て確認することもできるらしい、ということになりますでしょうか…。C#のように1つのバイナリを共有するというのは理想的ではあるのですが、リコンパイルするだけで対応できるというのは動作速度を考えるとまだまだ解決策の1つではあると思います。標準C++とQt5で環境非依存なソースコードを記述できそうです。(といっても私はC++を勉強しなくてはなりませんが(^_^;)

« 2014年2月 | トップページ | 2014年4月 »