凹みTips

C++、JavaScript、Unity、ガジェット等の Tips について雑多に書いています。

QML で使える OSC 要素を作ってみた

はじめに

先日書きました Maker Faire Tokyo 2013 でレゴへのプロジェクションマッピングネタで出展してきた - 凹みTips でも使用していた Qt から OSC を扱うカスタム QML 要素を紹介します。

OSC とは

OpenSound Control の略で、UDP の上で非常に低遅延なメッセージのやり取りをプロセス間や別 PC 間で、それぞれのメッセージにアドレスを付加しながら行うことが出来ます(一つのポートを使いまわせて便利)。数値データのような小さなものから画像の様な大きなものまで扱えます。

イメージしやすいように Node.js で書いたコードは以下の様な形になります。

サーバ側
var osc = require('node-osc');

var server = new osc.Server(3333, '127.0.0.1');
server.on('message', function (msg, rinfo) {
	console.log(msg);
});
クライアント側
var osc = require('node-osc');

var client = new osc.Client('127.0.0.1', 3333);
var cnt = 0;
setInterval(function() {
	client.send('/Hoge/cnt', ++cnt);
}, 1000/60);

これで 2 つのスクリプトを走らせると、3333 ポート下で、/Hoge/cnt というアドレスのもと、カウンタの数字のやりとりが出来る感じです。

使い方

.pro で osc.pri をインクルード
include(path_to_qml-osc/osc.pri) # <-- 追加

folder_01.source = qml/CustomElementsTest
folder_01.target = qml
DEPLOYMENTFOLDERS = folder_01
...
main.cpp でカスタム要素を登録
#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"

#include <osc_receiver.h> // <-- 追加
#include <osc_sender.h>   // <-- 追加

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

    qmlRegisterType<OSCReceiver>("OSC", 1, 0, "OSCReceiver"); // <-- 追加
    qmlRegisterType<OSCSender>("OSC", 1, 0, "OSCSender");     // <-- 追加

    QtQuick2ApplicationViewer viewer;
    viewer.setMainQmlFile(QStringLiteral("qml/CustomElementsTest/main.qml"));
    viewer.showExpanded();

    return app.exec();
}
QML で利用
import QtQuick 2.0
import OSC 1.0

Rectangle {
    width: 360
    height: 360
    Text {
        id: message
        anchors.centerIn: parent
    }
    OSCReceiver {
        port: 3333
        onMessage: {
            message.text = address + ' : ' + msg;
        }
    }
    OSCSender {
        id: osc
        ip: '127.0.0.1'
        port: 3333
    }
    Timer {
        property int cnt: 0
        interval: 1000/60
        running: true
        repeat: true
        onTriggered: {
            osc.send('/Hoge/cnt', ++cnt);
        }
    }
}

これで Node.js で書いた相当の処理が行えます。同じ QML に書いていますが別のプログラムに分けても通信できますし、どちらか一方を使って、他方は別のプログラム(先日の記事では Unity 等)にしても良いと思います。JS 間で行うのであれば、JSON.stringify して送って受け取り先で JSON.parse すると便利だと思います。

参考

以下のサイトで懇切丁寧に説明されています、すごい分かりやすいです。

Qt Quick 1 のお話ですが、Qt Quick 2 との差分は declarative が qml になったくらいです。手順としてはおおまかに 2 種類、共有ライブラリを作成するか、読み込み用のプロジェクトファイル(.pri)を作成してプロジェクトファイル(.pro)から読み込ませるかです。前者は何故かうまくいかなかったのと、どちらかというとエディタから参照可能な後者の手法の方が扱いやすそうなので後者でやりました。

おわりに

こういった形で自分なりのカスタム要素を拡充していけばプロトがしやすくなりそうです。