programingの最近のブログ記事

Objective-Cという言語が面白いのは、コンパイラ言語でありながら、インタプリタ言語のような動的操作ができる点ではないかと思う。

実際にはCの上に構築されたプリプロセッサのようなイメージで、その操作はCのコードとランタイムライブラリへのアクセスへと還元することが出来る。そしてCの部分は隠蔽されることなく使用することが出来、それ故、インラインアセンブラのようにObjective-Cの操作をCで記述したコードを混在させるといったことも出来てしまう。そういった泥臭さはC言語族の特徴と言うべきなのだろうか。

ランタイムライブラリをいじらないまでも、例えば文字列で指定されたクラス名のインスタンスを作成するのはこんな感じで出来る。

Class klass = NSClassFromString(className);
id obj = [klass alloc];

この機能を使用すると、テキストファイルで指定されているクラスのインスタンスを動的に作成するというようなことが出来る。

さらに、標準のXMLパーサNSXMLParserと組み合わせると、手っ取り早く(とりあえずの)設定を読み取り、インスタンスを生成するモジュールを実装することが出来る。

Animating UIViewのエントリーではUIViewにラップされたインターフェイスからCore Animationの機能、アニメーションをさせてみた。簡単なお約束ごとでアニメーションを実行できるのだけど、Core Animationのクラス、CALayerだとどうだろうか。

いきなり結論から言ってしまうと、CALayerを使うともっと簡単にアニメーションができてしまう。実はCALayerクラスのアニメーション可能となっているプロパティに値を設定すると、それは即時実行ではなく現在値からのアニメーションとして設定される。

つまり何も考えずにプロパティ値を設定するだけでアニメーションを実行できてしまうわけだ。これをCoreAnimationではImplicit Animationと呼んでいる。

たとえば、

theLayer.alpha = 0.0f;
とするだけで、レイヤーはalpha=0へと消えていく。

今回はImplicit Animationを使ってみようと思う。

前回までにClock(TempoClock)によってトリガーを発生させ、そのタイミングでコマンドをシンセサイザノードに送信することによって演奏を行うことが可能だと言うことを見てきた。

ただ、その操作はローレベル過ぎて、確かに可能なのだけど、毎回このような基礎の部分から行わないといけないとなると面倒だ。おそらく、プログラムをかける人なら必ずなんらかの手間の簡略化(クラス化なり)を行うだろう。そしてSuperColliderにもそういった上位のラッパークラスが用意されていて、演奏をさせたいのに、それまでのことに煩わせらるといったことがないようになっている。

今回見ていくのはPatternクラスだ。Patternクラスは豊富な派生クラスが存在していて、名前が示すとおりパターンとして登録しておけばそれを演奏してくれるというものだ。必ずしも最初に決められたものだけではなく、ジェネレーティブなものもある、そしてそれらを複雑に組み合わせることも出来る。

パターンクラスを使うと、例えばこんなコードで演奏をさせることが出来る。

Pbind(\degree, Pseq(#[0,1,2],2)).play

さて、これを見ていると、ふと疑問がわいてくる。魔法というものが存在しないように、前々回見たような処理を誰かが行ってくれているわけだ。それは誰がどのようにして行っているのだろうか。どうやってコマンドは手元からシンセサイザノードに届くのだろうか。

その点に注目してPatternクラスを見ていこう。

前回は実際にサウンドの生成を行っているサーバscsynthを離れて、クライアントであるsclang側でのシンセサイザコントロールのさわりの部分を見てみた。

SuperColliderにはClockというクラスがあり、その機能はトリガーをかけて欲しい時間を登録しておき、トリガーのタイミングで行いたい処理を実行すれば良いという仕組みになっていた。トリガーは一度かかると解除されるので、繰り返し行いたい場合は処理の終了時に再度トリガーを登録しておく必要がある。

そのClockクラスの主要な派生クラスの一つがTempoClockであり、名前の通りテンポによる時間管理を行うクラスになっている。主要というのは、このクラスにはdefaultというクラス変数があり、クラスがロードされたときに暗黙にそこにインスタンスが生成される。そして、いろんな演奏に関するクラスがClockに関するパラメータのデフォルト引数(引数が明示的に指定された無かった場合も)としてTempoClock.defaultを使用しているからだ。

TempoClockにはプロパティtempoがあるのだけど、ではこのtempoのパラメータの単位はなんだろうか。メトロノームと同じくBPMでいいのか、はたまた違うのか。初期的に設定されているテンポはどれぐらいの速さなのだろうか。

今回はTempoClockに注目してみようと思う。

Animating UIViewのエントリーでUIViewにラッパーされたCoreAnimationを使ってみたのだけど、今回はもう一歩CoreAnimationの世界に踏み込んでみる。とはいっても、アニメーションさせようっていうわけでなく、CoreAnimationで用意されている機能を使ってちょっとおいしいところをつまんでみようかということなのだ。

CoreAnimationはOSXではLeopardで追加された機能の一つなのだけど、iPhoneOS(おっとiOS)では最初から使える機能だ。ただ、CocoaとCocoa touchの類似性を保つためなのか、そのViewとの関係性は同じように実装されている(何となく後付け的な感じがうかがえる)。

UIViewに対応してそのCoreAnimationレイヤーであるのがCALayerクラスだ。layerプロパティがUIViewに用意されている。ちょっとわかりにくいのが、UIViewとしてもヒエラルキーを組めるのだけど、それとは別にCALayer側でも親子構造が組めるということだ。

今回扱うのはこのCALayerクラスだ。いくつかプロパティを持っているのだけど、注目するのは形状に関するプロパティだ。

前回までのところで、シンセサイザを作り(SynthDef、Synth)、そのラッパクラス(Synth)を使いクライアント(sclang)からサーバ(scsynth)を操作できるというところまでたどり着いた。

SynthDefのコンストラクタの2つめの引数ugenGraphFuncで渡される関数オブジェクトの引数が、すなわちそのシンセサイザのコントローラとなり、Synthクラスのsetメソッドを使って値をセットすることが出来る。

とりあえず演奏すべきシンセサイザを作るところまでは来たので、次はそれを演奏させたい。手動で値をセットするのも良いのだけど、ある程度は自動演奏させたい。

SuperColliderには演奏させるための仕組みが色々と用意されている。今回ピックアップしたのはRoutineクラスだ。流れ的には、必要なコントロールパラメータを設定し、必要なだけスリープする(次のタイミングを待つ)、その繰り返しが単純明快なので、サーバ側でのUGenの時のようにクライアント側のSuperCollider探求のとっかかりとして最適なのではないかと思ったのだ。

話の舞台はサーバからクライアントに移る。

OSXのLeopardからCoreAnimationというフレームワークが追加された。それによってCoverFlowなんかを実現している。それまでは空間的な管理しか行わなかったGUIシステムにおいて、時間の管理もOSが面倒を見てくれるようになったというのが、CoreAnimationのキモなのではないかと思う。

そして、OSX系の流れをくむiPhoneOSにもCoreAnimationは含まれている。iPhoneOSはOSXの紆余曲折のまだ後の方に出たということもあり、構造的にはモバイルOSにしてはかなりモダンな、OSXの成功も失敗も踏まえた上で設計されていると感じることがある。

さて、iPhoneのCoreAnimationだけど、かなりお手軽に使う方法が用意されている。ダイアログをビヨヨンとだしたり、スライドしてカットインさせたり、はたまた二つのViewをクロスディゾルブさせたり。UIViewControllerのトランジション効果なんかにもプリセットのアニメーションパターンが用意されているのだけど、簡単なお約束でアニメーションさせることが出来るので使わない手はない。

今回デモ用にEscapeButtonというジョークソフトを軽く組んでみた(ほんとに数行しか書いてない)。名前からして出落ちな感もあるけど、実装を見つつご紹介しようと思う。

前回、前々回でUGenという出口から始まり、ようやくクライアント側からサーバ側への橋がみつかった。いままでの道のりを図示すると左図のようになるだろうか。

今回見ていくのはもう一つの橋、Synthクラスだ。

前回はUGenを中心としてSuperColliderの世界への探求を試みてみた。今回はその上位構造となるSynthDefを見ていこうと思う。

SuperColliderはクライアントサーバ型アーキテクチャであることは既出のことなのだけど、SynthDef、そしてSynthがこの二つの間にかかった橋だと言えるだろう。UGenは確実に向こう側の世界だ。

お約束だけど、まだSuperColliderへの冒険の道半ばなので、間違っていることが含まれているかもしれないということは注記しておこうと思う。

少々前よりSuperColliderをいじっている。SuperColliderというのは、あえて説明することもないぐらいの有名どころなのだけど、主に音楽・音響記述に長けたプログラミング言語環境だ。音響系といってもDSPなどのストリームプロセスを書くというよりは、むしろ、ノードの接続を記述してシンセサイザーをつくり、それをコントロールするロジックを記述して動かすというのがコアな部分のようだ(もちろんそれ以外が出来ないというわけではない)。

Maxなどともコンセプトでは似ているところもあるのだけど、決定的に違うのはそれがビジュアルプログラムではなくテキストコーディングで行うものという点ではないかと思う。

わたしがSuperColliderに興味を持ったそもそものきっかけは、SC140というTwitterに書けるだけの分量でSuperColliderで音楽を作ろうという試みがあるということを知ったときだった。そのミニマムな魅力にくらくらっときて自分でもやってみたいと思ったのだった。

SuperColliderは少々取っつきにくいところがあるのだけど、コミュニティのパワーが補って余る。わたしもとても助けられている。特に、@umbrellaprocess氏(on twitter)にはわたしの初歩の初歩な質問にもきちんとレスポンスをいただき、大変感謝している。

SuperColliderのTutorialは、公式のIntroductory Tutorialがよくまとまっていると思う。今見返してみると、よく読めばちゃんと書いてあるということも多い・・・。

わたしはSuperColliderを学ぶ上でまずターゲットに決めたのはUGenというクラスだった。その部分がSuperColliderでシンセサイザ(音響処理も含む)を扱うクラスの基底クラスだったというのがその理由だった。

今回、とりあえず今までに分かったことをまとめてみた。しかし、まだSuperColliderへの冒険の道半ばなので、間違っていることが含まれているかもしれないということは注記しておこうと思う。