RubyCocoaでQuartzComposer プラグインをつくれるようになった ので、さっそくつくってみました。
みんな大好きGainer の入力を QuartzComposer からとれるようにしました。
ソースコード
github:qc_gainer に。MITライセンスです。
Funnel, osc を使っています。
短かいので、コードをはっておきます。ごさんこうに。
#
# qc_gainer.rb
#
# Created by mootoh on 6/6/08.
# Copyright (c) 2008 deadbeaf.org. All rights reserved.
#
require 'osx/cocoa'
OSX.require_framework 'QuartzComposer'
require 'funnel'
class QCGainer < OSX::QCPlugIn
def self.executionMode
2
end
def self.timeMode
1
end
def initialize
@initialized = false
@gio = Funnel::Gainer.new(Funnel::Gainer::MODE1)
@ain = [0,0,0,0]
@din = [0,0,0,0]
@aot = [0,0,0,0]
@dot = [0,0,0,0]
end
def startExecution(context)
Thread.new do
sleep 0.1
4.times { |i| addInputPortWithType_forKey_withAttributes(OSX::QCPortTypeNumber, "aot_" + i.to_s, nil) }
4.times { |i| addInputPortWithType_forKey_withAttributes(OSX::QCPortTypeNumber, "dot_" + i.to_s, nil) }
4.times { |i| addOutputPortWithType_forKey_withAttributes(OSX::QCPortTypeNumber, "ain_" + i.to_s, nil) }
4.times { |i| addOutputPortWithType_forKey_withAttributes(OSX::QCPortTypeNumber, "din_" + i.to_s, nil) }
end
true
end
def execute_atTime_withArguments(context, time, args)
unless @initialized
4.times do |i|
@gio.ain(i).on Funnel::PortEvent::CHANGE do |event|
@ain[i] = event.target.value
end
@gio.din(i).on Funnel::PortEvent::CHANGE do |event|
@din[i] = event.target.value
end
end
@initialized = false
end
4.times do |i|
setValue_forOutputKey(@ain[i], "ain_" + i.to_s)
setValue_forOutputKey(@din[i], "din_" + i.to_s)
end
true
end
def stopExecution(context)
true
end
end
使い方
- Gainer I/O をMacとつなげる
- Funnelサーバを起動
- Quartz Composerを起動
- Pluginを配置
デモ
ビデオに撮るのがめんどうなので、Ruby会議 に持っていきます。
まとめ
こんなふうに、ありものをくっつけてささっと何かをつくるというとき、glue言語としてRubyはグッドですね。
Happy Physical Hacking !
RubyCocoaで、QuartzComposerのカスタムプラグインをつくることができました on Leopard。
LeopardでのQuartzComposerカスタムプラグインづくりの続きです。あれから4ヶ月。
サンプル: qcplugin_rb
サンプルとして、2入力をとってその間に “Ruby” を挿入して後段に流すというプラグインを書きました。
githubにアップしてあります。MITライセンスです。
ソースコード: github:qcplugin_rb
スクリーンショット

ポイント
- Info.plistの書きかた
- 入出力ポートの追加方法
Info.plistの書きかた
1.まず、Info.plist の NSPrincipalClass エントリに、RubyCocoaのBundleを初期化するObjective-Cのクラスを指定します。
RubyCocoaでMacのプラグインをつくるときの共通tipsですね。
2.それと、実際のプラグインの動作を記述するクラスを QCPlugInClasses に列挙します。QCPlugInクラスを継承したやつですね。
<key>NSPrincipalClass</key>
<string>RBLoader</string> <-- 1
<key>QCPlugInClasses</key>
<array>
<string>QCRubyPlugin</string> <-- 2
</array>
入出力ポートの追加方法
LeopardのQuartzComposerから、ポートの指定は Objective-C 2.0 の property 機能を使って行うようになりました。
これをRubyCocoaからどう使うか分からなかったので、QCPlugInクラスのメソッドであるaddInputPortWithType:forKey:withAttributes: や addOutputPortWithType:forKey:withAttributes: を使ってなんとかします。
では、どこにこれらのメソッドを書くか。QuartzComposerの制約で、executeメソッド内に書いちゃダメよ、とあるので困ります。
サンプルコードを漁ってみたところ、別スレッドを立ててそこで呼び出すのはOKぽい。
そこで、RubyのThreadをつかってやってみたところ、うまくいきました。ただし、ちょっとdelayを設けてやらないとQuartzComposerが死にます。なぜだ。
もっとうまいやり方をご存知のかたがいれば、ぜひ教えてください。 m(_ _)m
ひっかかりどころ
バッドノウハウがいくつかありますね。
- s/QCPlugin/QCPlugIn/ なのです。見落しやすすぎる。
- ポート追加のdelay。
- メソッド名。execute が execute_atTime_withArguments になったりします。気づかずにいると、いつまでたってもメソッドが呼ばれずに悲しくなる。
- イチからXcodeのプロジェクトをつくるよりも、サンプルを元に書き換えていくとはまりにくい。
おまけ
こう書くとすんなり動くようになったみたいですが、現実は泥のようなデバッグでした。
RubyCocoaのフレームワークをデバッガで追ったり、QuartzComposerの謎の挙動に悩まされたり。
フレームワークをつかった開発でのデバッグについては得るところがあったので、別に書くことにします。
関連エントリ
まとめ
Happy Visual Hacking !
日本人にやさしい時間に始まった SRM 404 でした。404 TopCoder Not Found.
250 : Reading Books
Problem Statement : コード
配列をシーケンシャルに読んでいって、3種類のなにかを拾いあつめていく問題。んー、うまく言えない。
単純に要素をカウントしていくだけだとうまくテストケースをとおせないので、ちょっと考える必要がありました。ad-hocに書いてテストケースすべてがとおったところでsubmit。190pts。
500 : RevealTriangle
Problem Statement : コード
おもしろい問題。
穴ぼこだらけの三角形に、数字を入れていくという穴埋め問題ですね。
手でやると小学生でも解ける問題だけど、じっさいコードに落とすとなるとけっこう手強い。さんざん時間をかけて、テストケースをすべてとおしてsubmit。222ptsでした。コードが汚なすぎてわらえる。
TopCoderアカウントがある方は、これ を見て「これはひどい」と感じることでしょう。
結果
Challenge phaseで晩ごはんを食べているうちにSystem testを2つともパスし、Rating は 898→943 と 45点アップしました。ひさびさの緑コーダーに返り咲きです。うれしす。
コツコツつづけていくしかないですね。まずは250, 500の両方をコンスタントに解けるようにしていくことです。