Tag Archive for 'QuartzComposer'

QCGainer : Quartz Composer Gainer plugin

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

使い方

  1. Gainer I/O をMacとつなげる
  2. Funnelサーバを起動
  3. Quartz Composerを起動
  4. Pluginを配置

デモ

ビデオに撮るのがめんどうなので、Ruby会議 に持っていきます。

まとめ

こんなふうに、ありものをくっつけてささっと何かをつくるというとき、glue言語としてRubyはグッドですね。

Happy Physical Hacking !

Leopard で Quartz Composer カスタム Plugin を RubyCocoa でつくる

RubyCocoaで、QuartzComposerのカスタムプラグインをつくることができました on Leopard。 LeopardでのQuartzComposerカスタムプラグインづくりの続きです。あれから4ヶ月。

サンプル: qcplugin_rb

サンプルとして、2入力をとってその間に “Ruby” を挿入して後段に流すというプラグインを書きました。 githubにアップしてあります。MITライセンスです。

ソースコード: github:qcplugin_rb

スクリーンショット

screenshot

ポイント

  • 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 !

LeopardでのQuartzComposerカスタムプラグインづくり

Ruby会議2008CFPとして、RubyCocoaでインタラクティブにMacのプラグインをつくるよ、みたいなものを書いて出してみました。 出してから、そういえばLeopardになってからQuartzComposerで遊んでないなあと気づき、ちょっと触ってみたらえらく変わっていたので、今日調べたことをカスタムプラグインをつくるという観点でメモっときます。

カスタムプラグインがオフィシャルに

最大の変更点はこれです。 Appleの丁寧なドキュメント Introduction to Quartz Composer Custom Patch Programming Guide を読めば、たちまちつくれるようになるのではないかと。サンプルも充実してて、/Developer/Examples/Quartz\ Composer/Plugins/にごろごろ転がってます。 これまで、kineme.net:Xcode Template for Custom Quartz Composer Patches を使い、非公開のAPIでプログラミングしていたのに対して大きな進歩です。

Port指定にはpropertyをつかう

Objective-C 2.0で導入された、propertyという機能をつかって入出力Portの指定をコードでやるようになっています。 これまでは、インスタンス変数名の先頭にinput/outputがあれば、それがPortになっていました。

Portの増減が動的にできる

RubyCocoaでpropertyを使う方法を知らないのでどうしようかなあと思ってたのですが、 addinputPortWithTypeとかaddOutputPortWithTypeというメソッドを使えば動的にPortが加えられます。

注意すべきことは、これらのメソッドはプラグインのexecuteメソッドに入れてはいけないことです (例外があがってQuartzComposerが止まってしまいます)。んじゃどうするかということで、ExampleのCommandLineToolFreeFrameHostを調べてみると、どうやらQuartzComposerのインスペクタから受け取るイベントのハンドラで、これらのメソッドを呼ぶようにしています。なるほど。

インストール場所が変わっている

これまでは、/Library/Graphics/Patch にプラグインを置くのが流儀だったのですが、Leopardからは/Library/Graphics/Quartz\ Composer\ Plug-Ins/ になりました(~/Library以下でもOK)。


カスタムプラグインをつくるという点から、Leopardになって気づいたことをまとめました。次はいよいよ、RubyCocoaでカスタムプラグインづくりです。

関連エントリ

RubyCocoa で QuartzComposer CustomPatch (2)

とりあえず、できました。

スクリーンショット

QCRubyPatch QCRubyPatch-2

サンプル

input, output ともにStringのPortを1つずつもち、入力にある”Objective-C”を”Ruby”に正規表現で置換するというだけのサンプルを書きました。

RubyPatch (binary & source) rev3 (i386 Binary)

RubyCocoaをUniversal Binary でビルドしていなかったため、いまのところIntel Mac だけで動きます。

RubyCocoa の svn trunk、 MacBook Kuroで動作確認をしています。

何をしているか

  1. Patchがロードされるとき、すなわち “registerNodesWithManager” が呼ばれるときに、RBBundleInitを呼んでRubyCocoaの準備をする
  2. Patchの動作を記述するObjective-CのクラスをProxyとして、実際の動作を記述するRubyクラスのインスタンスを保持させる
  3. Rubyクラスは、Objective-CクラスからPortをもらってくる
  4. Patchを実行するイベントがきたら、Rubyクラスのインスタンスに対して処理を移譲

といったところ。

実際のコードは、RubyQC::Trac にあるのでご覧ください。

このアプローチの問題点

  • いちいち全メソッドを Objective-Cのクラス → Rubyのクラス に投げるよう書くのがめんどう
  • Portの記述がObjective-Cのクラスにしか書けない (みたい) なので、Portを加えたり減らしたりするたびにObjective-C/Rubyコードともに変更しないといけない。わすれそう。

OSX::QCPatchクラスをRubyクラスで継承できて、さらにPortの情報もRubyクラスで書けるようになれば、これらの問題は解決しそうです。

課題

QCPatch.execute は、3つの引数をとるのですが、Rubyクラスのメソッドにどうやって3引数を渡すのか分からない…

18:03 追記

MLで、LimeChatの中の人に教えてもらいました。

objc_method :execute_time_arguments, %w|char id double id|
def execute_time_arguments(fp8, fp12, fp20)
  ...
end

のようにすればいいよ、とのことで、ばっちり動きました。ありがとうございます。


とはいえ、CustomPatch がRubyで書けるようになったのは大きな進歩です。ApacheReaderPatch とかも、ずいぶんと簡単に書けそう。

RubyCocoa で QuartzComposer CustomPatch をつくりたい

先に今の状態 : できそうな糸口がつかめたところで挫折 :(

SocketReaderPatchApacheLogPatch とQuartzComposerのカスタムパッチをつくってきたのですが、ここらでRubyで書くかと思い立ちました。 バベル案内ホワイの(感動的)Rubyガイド を読んで、こんなにもRubyが世界に受け入れらているのかと感動したことと、いくつかCustomPatchをつくってみて、CustomPatchj作成の概観がつかめてきたから。

どうやるか

RubyCocoaのsvn trunkを使います。 最近のリビジョンでは、QuartzComposer.frameworkが使えるようになっているのです。

>> require 'osx/cocoa'
r=> true
>> OSX.require_framework 'QuartzComposer'
=> true
>> OSX::QCStructure
=> OSX::QCStructure
>> OSX::QCPatch
=> OSX::QCPatch

ひゃっほう。

で、いつもどおりQuartzComposer CustomPatch の Xcode template をつかって、Xcodeプロジェクトをはじめます。

RubyCocoa.frameworkをリンクしておき、RubyPatchPrincipla.m を

#import <rubyCocoa/RubyCocoa.h>
#imporut "RubyPatchPrincipal.h"
 
@implementation RubyPatchPlugin
+ (void)registerNodesWithManager:(GFNodeManager*)fp8
{
  static bool loaded = false;
  if (!loaded) {
    if (RBBundleInit("/tmp/custom_patch.rb", self, nil)) {
      NSLog(@"[RubyPatchPlugin.registerNodesWithManager] RBBundleInit failed");
    } else {
      loaded = true;
    }
  }
 
  Class helperClass = NSClassFromString(@"RubyPatch");
  [fp8 registerNodeWithClass:helperClass];
}
@end

のように書きました。 RubyCocoaのbundle生成用APIを用いています。

loadされるRubyスクリプトはこういうもの。

require 'osx/cocoa'
OSX.require_framework 'QuartzComposer'
 
class RubyPatch < OSX::QCPatch
  #attr_accessor :inputFoo, :outputBar
 
  def RubyPatch.logger=(l)
    @@logger = l
  end
 
  def RubyPatch.executionMode
    @@logger.info("executionMode")
    2
  end
 
  def RubyPatch.allowsSubpatches
    @@logger.info("allowsSubpatches")
    0 # in objc.h, NO is defined as 0
  end
 
  def RubyPatch.timeMode
    @@logger.info("timeMode")
    1
  end
 
 
  def init
    @@logger.info("init")
    @inputFoo = OSX::QCBooleanPort.alloc.init
  end
 
  def initWithIdentifier(fp8)
    @@logger.info("initWithIdentifier")
    init
    self
  end
 
  def setup(fp8)
    @@logger.info("setup %s, %s", fp8, fp8.class)
    fp8
  end
 
  def cleanup(fp8)
    @@logger.info("cleanup")
  end
 
  def enable(fp8)
    @@logger.info("enable")
  end
 
  def disable(fp8)
    @@logger.info("disable")
  end
 
  def execute(fp8, time, arg)
    @@logger.info("execute")
    true;
  end
end
 
OSX.init_for_bundle do |bundle, param, logger|
logger.info("init bundle=%s param=%s", bundle, param)
  RubyPatch.logger = logger
end

templateが生成するObjective-Cのコードを、Rubyに書き下したものですね。

実行

ビルドもすんなり通り、さっそく実行してみます。

qc-exception-rubycocoapatch.png

アウチ。 なんか例外が投げられてしまいます。 出しているログを眺めてみると…

正常なもの (Objective-Cで書いたカスタムパッチ)

2007-07-14 14:35:03.568 Quartz Composer[15580] RubyPatch.plugin (Quartz Composer): init bundle=NSBundle  (loaded) param=
2007-07-14 14:35:03.708 Quartz Composer[15580] initWithIdentifier
2007-07-14 14:35:03.708 Quartz Composer[15580] executionMode
2007-07-14 14:35:03.708 Quartz Composer[15580] timeMode
2007-07-14 14:35:03.710 Quartz Composer[15580] allowsSubpatches
2007-07-14 14:35:03.741 Quartz Composer[15580] allowsSubpatches
2007-07-14 14:35:03.741 Quartz Composer[15580] allowsSubpatches
2007-07-14 14:35:03.741 Quartz Composer[15580] allowsSubpatches
2007-07-14 14:35:03.785 Quartz Composer[15580] setup

だめなもの (RubyCocoaで書いた)

2007-07-14 14:36:11.300 Quartz Composer[15602] RubyPatch.plugin (Quartz Composer): init bundle=NSBundle  (loaded) param=
2007-07-14 14:36:11.301 Quartz Composer[15602] assert passed !
2007-07-14 14:36:11.342 Quartz Composer[15602] RubyPatch.plugin (Quartz Composer): initWithIdentifier
2007-07-14 14:36:11.342 Quartz Composer[15602] RubyPatch.plugin (Quartz Composer): init
2007-07-14 14:36:11.345 Quartz Composer[15602] RubyPatch.plugin (Quartz Composer): allowsSubpatches
2007-07-14 14:36:11.377 Quartz Composer[15602] RubyPatch.plugin (Quartz Composer): allowsSubpatches
2007-07-14 14:36:11.378 Quartz Composer[15602] RubyPatch.plugin (Quartz Composer): allowsSubpatches

よく見てみると、RubyCocoaで書いた方は、initWithIdentifier のあとに executionMode, timeMode が呼ばれることなく allowsSubpatches が呼ばれています。 executionMode, timeMode が分からないので、QuartzComposer としてはこのパッチをどの種類にして良いか分からず、レンダリングできませんよーという例外がきてるっぽい。

問題

ではなぜ executionMode, timeMode が呼ばれないか、考えてみます。

QCPatchのヘッダによると、executionMode, timeMode はそれぞれ int を返すメソッドのようです。 ところが、RubyCocoaで用意した executionMode, timeMode は返り値の型を指定していません。 ちょっと調べたところ、RubyCocoaではRubyのメソッドが整数型を返すとき、Objective-Cの世界にはNSDecimalNumberの型を返すようになっているようです。

その結果、executionMode, timeMode は別のメソッドとして認識されてしまい、QCPatchのメソッドをオーバーライドできず、呼ばれていないのではないかと推測しました。

解決案

  1. intで返すようにRubyCocoaでなんとかする
  2. QCPatchをRubyクラスで継承せずにObjective-Cのクラスで継承させ、そのメンバにRubyクラスのdelegateのオブジェクトをもたせて、実際の処理はdelegateオブジェクトに振る

2が手っ取り早そうですが、いまひとつかっこいくないなぁ。

別の問題

CustomPatchのテンプレートによると、QCPatchを継承したクラスのメンバに QCPortクラスのインスタンス (ex. inputEnable, outputString など) を書くことで、パッチのinput/outputポートを指定できるような仕組みになっています。

じゃあ、

attr_accessor :inputEnable, :outputString
...

みたいにすればいいのか、というとどうもそうでもないみたいで…

やはり解決案2を使うしかないのかもです。

ApacheLogPatchを公開してみて

被ブックマーク数が2ケタを越えて自己最高記録を樹立するなど、思ったよりも反応をいただけたApacheLogPatchですが、公開してみて感じたことをメモしておきます。

リリースたいへん

アイデアを思いついて、がりがりとつくってきたものが、できたー! という時は最高に楽しいものです。

しかし、これをいざ公開するという段になると、

  • スクリーンショットとらなきゃ
  • スクリーンキャストもとらなきゃ
  • ライセンスってどうしたらよいんだろう
  • コードの汚い部分をマシに
  • 動作検証しなきゃ
  • リリースビルドにしなきゃ
  • パッケージにしなきゃ

なんていう複雑で雑多なタスクがあり、ちょっとめげます。これは仕事でもそう。 慣れてないことをするから敷居が高いのかも。

リリース段階になると、開発のときとは違う人格になるのがよさそうです。

Mac mini (PPC) きつい

うちのサーバは Mac mini (PPC) なのですが、今回みたいなアクセス数がきただけできついことになりました。スラッシングしてしまうのです。なんて貧弱。512MBもメモリを持っているというのに。170MBもfree領域があるというのに。 スラッシングしてしまうと、コンソールから入ることもできなくなってしまって困ります。

反応うれしい

とはいえ、redditとかはてブとかで参照されてるととてもうれしくなります。反応ドリブン開発。

プログラムと絵

ハッカーと画家 でも言われていた気がしますが、プログラムをつくっていくことと絵を描いていくことの共通点は、対象に手を入れることを止めたときが完成のときだ、というところです。この前みに行ったモネの大回顧展NHKの特集でも言われていたような。

とくにQuartzComposerの作品をつくるのは楽しくて、あ、ここはちょっとJavascriptで対数を使えばきれいにフェードできるんじゃない? とか、細かいところを調整しているとキリがありません。 もうここらでいいや! という見切りをどこでつけるかというところにその人のセンスが表われそうです。

インタラクション

僕を駆りたてるのは、インタラクションなのです。 打てばすぐ響いてほしい。

なぜ最近QuartzComposerにはまっているかというと、フィードバックがものすごい迅速だからです。パラメータをちょっと変えただけで敏感に反応してくれる。 Rubyのirbもそうで、なにかちょっと実験してみるとすぐ答えが得られる。 思いつく→やってみる→確かめる のループをどれだけ速く回せるか、が生産性にかかってくると思うわけです。

それに対して、Objective-Cでカスタムパッチを書いているときの生産性はものすごい低い。 デバッガを使えないのでpritnfデバッグをするしかない。打ってもすぐに響かず、やまびこのように聞こえる。

とか言ってたら組み込みの開発なんてできないんですけどね。


などと、まとまりなくつらつらと書き連ねてみました。 次はなにつくろう。

2007.07/11 22:53 追記

Google Analyticsを眺めていたら、自己最多アクセス数 (約400セッション、ユーザ) になっていたので記念にとっておきました。 2007.06/19頃にもひと山あるのですが、これはSocketReaderPatchのとき。どちらもオレンジニュース効果です。OrangeNewsed !

20070710-ganalytics.png

ApacheLogPatch 0.1

ApacheLogPatch というものをつくりました。 Apacheのログを、Quartz Composer で派手に tail -f するというものです。 パス、リモートホストのアドレス、リファラー、検索キーワードが表示されます。

Apacheの設定ファイルを書き換えたりと動くようにするまでの敷居が妙に高いわりには、動いたときの「おー、ふーん」感がなんともいえませんが、動かしてみようという方はどうぞぜひ。

自宅サーバをMacで動かしている方という、たいへん狭いターゲットを狙いました。 スクリーンセーバーとして動かしておき、自分のサーバに人がどんな検索キーワードできているのか、なんてことを夕食どきにご飯を食べながら眺めてみるのも一興ではないでしょうか。

ビデオとスクリーンショット

ビデオは、本当はDVカメラで撮影したちゃんとしたものがあったのですが、どうもFirewireからの取り込みができず挫折して vnc2swf を使いました。ので、フレームレートが悲惨なことになっており、本当にこれ、動かして楽しいの? みたいなことになってます。楽しいんですよ。

Python版のvnc2swfで録り直しました。だいぶ見れるレベルになったのでは。

ApacheLogPatch

Apache の ログ を、リアルタイムに QuartzComposer で表示するものをつくりました。 tail -f /var/log/httpd/access.log の代わりにつかう、みたいな。

Download

httpd2qc package (Universal Binary, tested on Tiger)

Screencast

プライバシーをまもるために、リモートホストのIPアドレスは “xxx.xxx.xxx.xxx” にしています。実際にはばっちり表示されます。

Quick Start

  • ApacheLogPatch.plugin を、/Library/Graphics/Patches にコピー
  • Apacheの設定ファイル (httpd.conf とか) に、filter.rb へ カスタムログ を パイプするような設定を加える
    例:
      LogFormat "%h \"%{Referer}i\" %U" httpd2qc
      CustomLog "|/opt/local/httpd2qc/filter.rb" httpd2qc
  • ApacheLogDisplay.qtz を 開く
  • Apache を restart
  • 眺める

Detail

overview.png

  1. ApacheのカスタムログをパイプでRubyスクリプトに流しこむ
  2. Rubyスクリプト (filter.rb) は、文字列のURI デコードなどをして、QuartzComposerのカスタムパッチ用にデータをつくる (ここでもうちょっと賢いことができそう)
  3. QuartzComposerのカスタムパッチ (ApacheLogPatch) は、流れてきたデータをQCStructureのスロット (とりあえず3つ) に詰め込む

ApacheLogPatch は、QCStructureのオブジェクトを出力します。実際には、[リクエストパス、リモートホストのアドレス、リファラー、検索キーワード] の要素をもつQCStructure の配列になっています。

より詳しくはソースを。

ToDo

  • 背景に世界地図を描いておいて、ログが来たときにIPアドレスから地理情報を取得して、それらしき場所を点滅させる (IP2Location とかをつかえばよさそう)
  • もうちょっとカスタマイザブルに
  • もうちょっとかっこよく

きっかけ

Google本社では、検索キーワードがリアルタイムに画面を流れているのが見れるとか聞きました。僕が行ったときには、そんなディスプレイは見当たらなかったのだけれど。

せっかく自宅サーバをMacで動かしているのだし、なにか面白いことはできないもんかなー、と風呂でぼんやり考えていて、最近遊んでいる QuartzComposer の CustomPatch と組み合わせてみたら? と。

QuartzComposer の CustomPatch で Signal を生成する方法

QuartzComposer の Patch には、Signal という 一瞬だけ True になったあとまたすぐ False になるような Port をもつものがあります。たとえば、StopWatch とか、Counterとか。

では、どのようにして CustomPatch で Signal を生成すればよいか、いろいろ試行錯誤してみたので、メモを残しておきます。

Port

@interface SomePatch : QCPatch {
  QCBooleanPort *outputSignal;
  ....
}

のように、Boolean な Port を宣言しておきます。

Configuration

まず、CustomPatch の timeMode を 1 にして、常に Patch が実行されるようにしておきます。

+ (int)timeMode { return 1; }

としておけばよいでしょう。

ここらへんの詳細については、QCPatch Configuration に書かれてあります。

Signal を発生させる

1〜2回、execute が実行される間に outputSignal の値が True になっていれば、Signal が発生したとみなされるようです。

- (BOOL)execute:(id)fp8 time:(double)fp12 arguments:(id)fp20 {
  static int count = 0;
 
  // signal hack
  if (TRUE == [outputSignal booleanValue]) {
    if (1 == count++) {
      [outputSignal setBooleanValue:FALSE];
      count = 0;
    }
  }
 
  return YES;
}

みたいにしました。[outputSignal setBooleanValue:TRUE] にするのは、どこか別のスレッドにてやっています。

まとめ

俺Patchで Signal が送れるようになれば、データが変わったタイミングを後段のPatchに伝えることができて、なにかと使えそうです。RSS Feed Patch や、Image Downloader も、FeedやImageのダウンロードが終わったタイミングをSignalで通知しているわけで。

おまけ

QuartzComposer の CustomPatch をデバッグするには、NSLog が便利です。 というか、つくった Patch は plugin 形式なので、いつものようにデバッガを直接起動することができないので。

NSLogのログは、 /Library/Logs/Console/”自分の uid”/console.log に出力されるので、tail -f などとして眺めるとグッドです。

QuartzComposer の CustomPatch をつくるための Xcode template

の0.2が公開されてました

なにが素晴らしいかって、

  • より多くの種類の Port ( Image, Structure, …)
  • ビルドしたら、自動的に /Library/Graphics/Patch につくったPatchがインストールされる

というところ。

以前のもの よりも格段に使えるものになっているので、QuartzComposerで俺パッチをつくるぜ! という方はぜひインストールしてみればよいと思います。