記事一覧

My most frequent error when working with Interface Builder

Interface BuilderでUIを作って XCode でビューコントローラを書いたものの全く何も動かない・・・
というケースがよくあるんですが、僕の場合ほとんど原因は IB書類のセーブ忘れ;
何度も経験してるのだけどそのたびにあれ?あれ?とか言ってけっこう時間を食ってしまうのでアホくさいことこの上ないです。

Having built a neat UI on the Interface Builder and
a nice view controller on XCode but
nothing reacts at all....
In such situation, most of the case I forgot to save the IB document after changing.
Pretty silly, but I do this very often, and spend a certain length of time until I notice...

NSScrollView with custom ruler

スクロールビューに対数軸とか使ったりする科学系の座標目盛りを付けるには、どんな方法がベストなんでしょうね。

今のところ、メインの表示エリア用、X軸表示用、Y軸表示用の3つのNSScrollViewを作ってこれをnotification center経由で同期させたりしてますが、なんか遠回りな感じがしております。

NSRulerViewをサブクラス化してカスタマイズする方がシンプルな気がするんですが、そこまでフルカスタマイズするような場合の解説とかが見つからないんですよね。
ハテどうしたもんだか・・・。


What's the best way to make the scroll view with scientific kind of rulers like allowing users to use logarithm axis?

So far, I made it by placing three separated NSScrollView as main view, X-axis view and Y-axis view and synchronizing them through notification center. It's working actually, but I feel it's a bit too redundant.

I guess it may be much simpler if you subclass NSRulerView and customize it, but I can't find a good document about this kind of full-customizing.
Hmm..

Document-based Application

A small tips:
In Document-based Application, if you set the "Role"s of all file types to "viewer" no blank document will open when launching. How smart...!

ちょっとした発見:
ドキュメントベースアプリケーションで、すべてのファイルタイプについて「役割」を「ビューア」に設定すると、アプリ起動時に空のドキュメントを開かないようになる。なんか微妙にかしこい!

ファイルコピーが止まる

ファイルのバックアップの方法はいろいろありますが、僕は基本的に手動で、単純なファイルコピーでやっています。
RAIDとかにしようかとも思ったんですが、それだとオペレーションミスによる誤削除も即座に "バックアップ" されてしまうのがちょっと怖いんですよね。
というわけで、バックアップ時には一挙に大量のファイルコピーを行うわけですが、これがアクセス権うんぬんの理由で途中で止まるのが非常に鬱陶しい。

どうやらWinユーザーからもらったファイルがそうなりがちっぽいのですが、イマイチ原因はよくわからない。

前から気になっていたことなので少し調査したり実験したりしてみたところ、ファイルオーナーの書き込み権限が無いとそうなる、ということだけはわかった。
なんでコピー元に対して書き込み権源が必要なんだ・・・。
納得はいかないが、とりあえず
chmod u+w すれば対処可能ということのようです。
面倒なんでホームディレクトリで
sudo chmod -R u+w *
とかやろうと思ったんですが別の所で問題起こしそうだし、対象ファイル数もそれほど多くなさそうなので個別に対応しました;

後で分かったんですが、どうやらシェルから cp -R とかでコピーすると、アクセス権のないものは飛ばして続行してくれるみたいですね。
Finderのファイルコピーはなぜそうしないのか・・・

How to import ObjCOSC to project

ObjCOSC comes with .framework file but it doesn't work maybe because the version of SDK doesn't match.
But you can use ObjCOSC by manually importing the sources to your new project. Below is how to do that.

1. Make your new project as usual.

2. Add all ObjCOSC source files to your project. The files are:
* OSCInPort.h
* OSCInPort.m
* OSCPort.h
* OSCPort.m
* All files under OSC-Kit-Mac/

3. Delete or comment out
#import <Cocoa/Cocoa.h>
at line #9 of OSCInPort.h :

4. At line #492 in OSC-address-space.c insert a dummy code (like "1;") to avoid "Label at end of compound statement" error.

5. Add #import "OSCPort.h" and #import "OSCInPort.h"
to your codes where you need it.


ObjCOSCには一応 .framework ファイルが付いてくるので本来はそれをインストールすれば良いはずなんですが、おそらくSDKのバージョン違いか何かで動きません。
が、ソースをプロジェクトに入れ込んでコンパイルしてしまえば大丈夫です。以下その方法。

1. 普通のiPhoneアプリのテンプレートでプロジェクト作成

2. ObjCOSCのソースを全部プロジェクトに追加。内訳は:
*OSCInPort.h
*OSCInPort.m
*OSCPort.h
*OSCPort.m
*OSC-Kit-Mac/ 以下全部
※「デスティネーションにコピー」を忘れずに。

3. OSCInPort.h 9行目の
#import <Cocoa/Cocoa.h>を削除またはコメントアウト

4. OSC-address-space.c の 492行目に何かダミーコード("1;" とか)を入れる。これを入れないと "Label at end of compound statement" エラーになる(少なくともウチのコンパイラ設定では)

5. 必要なところに
#import "OSCPort.h"
#import "OSCInPort.h"
を入れる。

Receiving MIDI when playing qtz with QuickTime Player

QCでMIDIを受信するようなコンポジションを作りまして、実際 Quartz Composer の上ではちゃんと動いてるんですが、その qtz を QuickTime Player で開いた場合まったく MIDI を受信しない。
何か解決策はあったりするんでしょうか。それともそういう仕様だからどうしようもない?

I've made a composition receiving MIDI signal, and it works well on Quartz Composer application.
But when running its qtz file with QuickTime Player it doesn't receive MIDI at all.
Are there any ways to make it work??

ObjCOSC and Cocos2d Scene

シーン(Cocos2dのSceneですね)を切り替える場合、ObjCOSCの入力ポートの扱いはどうするのが正しいんでしょうね?
入力ポートを使うのは1つのシーンだけなので、該当シーンの init に入力ポート作成処理、dealloc に破棄処理を書いてみたのだけど、別のシーンに行って戻ってきたときにポートの再開に失敗する。
エラー的には
"Could not bind UDP socket for OSC".
というもので、これはおそらく最初に作ったポートが生きていて、もう一度作ろうとしても作れないという理由なんじゃないか・・・と思うのだけど詳しく調べる気力がないので別の方法で逃げました;
別の方法というのは、シングルトンを1コ作って、そっちに OSC受信を担当させるというもの。メッセージが来たらそれをディスパッチする。
で、実際に受信時処理が必要なシーンに入ったら、そのシーンをデリゲートとして登録してディスパッチを受ける。逆に要らないときはデリゲートを nil にする、という感じ。

What's the right way to manage ObjCOSC Input Port when changing the scene (<- I mean Cocos2d Scene)?
I need to activate OSC Input Port in only one scene, so I put the codes to make the port in the scene's init routine,and releasing codes in dealloc routine.
But it fails to restart the port when go to and back from other scenes.
The error is
"Could not bind UDP socket for OSC".
What does this mean?
My guess is, the port I first made still remains alive and cannot make new one.
If I did some tests I may be able to figure it out, but I don't have the energy to give it a go;
So I've added a singleton to my project and let it have the OSC Input Port so that the port keeps alive between scenes.
The singleton only does the dispatching OSC messages to the delegate. When entering the scene register itself as the delegate, and when leaving reset it to nil.

OSCメッセージの構造

ここ読んでやっとわかった。
http://opensoundcontrol.org/spec-1_0-examples
説明されればなんてことないけど、いきなり仕様を見ても気が滅入るんですわ・・・ということでちょっとまとめ。
ちなみに、仕様が分かると ObjCOSC に入っている main.m の PrintOSCArgs() の中身もあっという間に分かります。

--
普通にちょっとしたやりとりをするためのメッセージは、
基本的にはこんな構造のようです。

OSCアドレス(ASCII文字) + 1〜4個のヌル文字
+ 引数の個数と型を表す文字列(ASCII文字) + 1〜4個のヌル文字
+ 引数の値(バイナリ)

■ヌル文字
区切りの意味で挿入するわけだけども、データが4バイト単位にまとまるよう 1〜4個の間で数を調節します(いわゆるパディング)。

■OSCアドレス
/channel1/volume/
とかいうやつです。

■引数の個数と型を表す文字列
・1文字目はコンマ
・2文字目以降には、引数の数だけASCII文字を並べる。その文字は、float型なら 'f' , int型なら 'i' , char型なら 's' など。
例えば
,iifis
みたいな感じ。この例は引数5個で、型はそれぞれ int, int, float, int, char ですね。

■引数の値
上記で指定したデータを並べるだけです。でもバイナリなのが厄介。
iPhoneとのやりとりに使う場合はエンディアン問題が出ます。
http://akamatsu.org/aka/?lang=qtufeuecuie&paged=43
この記事のエンディアン変換のコード例、ちょっと紛らわしいところがあるので以下にウチで施した改造を改めて載せておきます。元の PrintOSCArgs() と比べてみて下さい。 floatの変換はintに比べて一手間多いですね。


void PrintOSCArgs(int arglen, const void* args)
{
const char* myArgTypes = (const char*) args;
const char* myArgs = myArgTypes + OSCPaddedStrlen(myArgTypes);

int intValue;
float floatValue;
CFSwappedFloat32 swappedFloatValue;

while (*myArgTypes != '\0') {
switch (*myArgTypes) {
case 'i':
intValue = CFSwapInt32BigToHost(*((const int*)myArgs));
NSLog(@"\t\tread int %i", intValue);
myArgs += sizeof(int);
break;
case 'f':
swappedFloatValue.v = *((const float*)myArgs);
floatValue = CFConvertFloat32SwappedToHost(swappedFloatValue);
NSLog(@"\t\tread float %f", floatValue);
myArgs += sizeof(float);
break;
case 's':
NSLog(@"\t\tread string %s", myArgs);
myArgs += OSCPaddedStrlen(myArgs);
break;
}
myArgTypes++;
}
}

Receiving by ObjCOSC

とりあえずよくわからないので、まずはココ
http://d.hatena.ne.jp/soundflower/20090425/1240618558
を参考に ObjCOSC ベースで受信プログラムを組んでみたらあっさりできました。

ただ、ちょっとハマったのが、そこに載ってるコードだけではダメで、最後に
[portIn start];
を入れないとダメなのでした;
ObjCOSC に添付の main.m を見て初めて気づきました。ていうか、上記リンクのコード自体、ほぼこの main.m を見てれば分かる話でした;

I let the problem I wrote in my last post aside and start coding receiving program based on this issue:
http://d.hatena.ne.jp/soundflower/20090425/1240618558 (in Japanese)
As result, it worked:)

There was only one thing I was stuck in:
You have to write this after the port settings to make it work
[portIn start];
which is not written in the code in the URL above.
I noticed later that all of these are written in the sample code included in the ObjCOSC package as "main.m"...

OSC - receiving

I'm testing receiving OSC message by iPhone using TouchOSC, sendOSC, dumpOSC and OSCulator, but there seems to be something strange.
When I send message from OSCulator TouchOSC does react, but from sendOSC it doesn't.
I checked the message string from OSCulator by receiving it by dumpOSC and send exactly the same from sendOSC, but TouchOSC still doesn't react.
Why????


OSC メッセージを iPhone 側で受信するテストとして、TouchOSC と sendOSC, dumpOSC, OSCulator などでメッセージの仕組みを見ているところなのだけど、どうも sendOSC からメッセージを送ると TouchOSC が反応してくれない。
OSCulator から送ると動くんだけど。
変だと思って OSCulator から送ったメッセージを dumpOSC で受信してみて、その通りに sendOSC から送ってみたんだけどやっぱり反応なし。
どういうこと???