9
4

More than 5 years have passed since last update.

REAPERのJSFXで遊んで見る

Posted at

REAPERにはJSFXという、スクリプトを書くだけでVSTのようなオリジナルのプラグインエフェクトが作成できる機能があります。この使い方に関する情報はほとんど公式ドキュメントだけなんですけど、ちょっと調べてみました。

VSTのような、と書きましたがいきなり音声信号処理をやるよりもまず視覚的にわかりやすいところから手を付けよう、ということでまずは画面描画系の処理から。音声信号処理は今度調べます。

Hello World

まずはお約束のHello Worldです。

desc:my first effect

@init
hello = "Hello World";

@gfx
gfx_r = 0.2;
gfx_g = 0.8;
gfx_b = 0.6;

gfx_measurestr(hello, strw, strh);
gfx_x = gfx_w / 2 - strw / 2;
gfx_y = gfx_h / 2 - strh / 2;
gfx_drawstr(hello);

Hello Worldの文字がウィンドウ中央に表示されれば成功です。

説明

最初の行desc:my first effectはエフェクトの名前を指定するものです。desc:以降は何でも構いません。

@init以下のブロックは初期化処理を行う部分です。エフェクトを読み込んだ時やコードを編集して再コンパイルされた時等に呼び出されます。
このサンプルではhelloという変数に文字列を代入しています。変数は事前に宣言する必要はありません。

画面に描画する処理は@gfx以降に書きます。このコードブロックは1秒間に約30回実行され、この中でのみgfx_で始まる関数や変数を使用することができます。このブロック外でgfx_で始まる関数や変数を使用すると、正しく動作しなかったり不明な動作をすることがあるので注意してください。

gfx_r,gfx_g,gfx_bは見ての通り色のR,G,Bを表す変数です。この値は後続するgfx_の描画系関数で描画される図形の色を指定します。
それぞれの値は0.0~1.0の間で指定します。

gfx_drawstr()は文字列を描画する関数です。描画位置はgfx_x,gfx_yで事前に指定します。
画面の幅、高さはそれぞれgfx_w,gfx_hで取得できます。文字列の幅、高さはgfx_measurestr(文字列, 幅を格納する変数, 高さを格納する変数)で取得できます。
今回は画面の中央に表示したかったので、画面中央のX,Y座標を計算しました。画面の中心計算方法は(画面幅/2, 画面高さ/2)で求められますが、これだと画面の中央が文字列の左端になってしまうので、そこからさらに文字列の長さの半分だけ左に、文字列の高さの半分だけ上に移動します。

マウスの位置

マウスの位置を取得するにはmouse_x,mouse_y変数を使用します。

desc:my mouse effect

@gfx
gfx_r = gfx_g = gfx_b = 1; // white

hello = "<- This is mouse";
gfx_x = mouse_x;
gfx_y = mouse_y;
gfx_drawstr(hello);

マウスカーソルの位置に白い文字が描画されれば成功です。

mouse_x,mouse_y変数はそれぞれウィンドウ内の描画領域の左上からの相対座標を表します。X座標は右が正、Y座標は下が正です。
今回はこの値をそのままgfx_x,gfx_yに入れています。gfx_drawstr()はこの位置から描画を開始するのでした。

ランダムな値

ランダムな値を取り入れると勝手に動く面白いモノが作れそうです。

desc:random color

@gfx
gfx_r = rand(1);
gfx_g = rand(1);
gfx_b = rand(1);

hello = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
gfx_x = 10;
gfx_y = 10;
gfx_drawstr(hello);

rand()関数は0以上引数で指定した値未満のランダムな数を返します。引数を省略した場合は1を与えたのと同じことになります。(0.0~1.0の間の数。ただし1.0は含まない)

ちなみに、この例では文字列がとても長いので、ウィンドウが小さいと描画領域からはみ出てしまいます。自動で改行などはしてくれないので注意しましょう。

時間を取得

リアルタイムの信号処理において時間という値はとても大事です。

desc:show time

@gfx
gfx_r = rand();
gfx_g = rand();
gfx_b = rand();

gfx_x = 10;
gfx_y = 10;
t = time_precise();
gfx_printf("%f", t);

現在の時刻を取得する関数は2種類あります。time()time_precise()ですが、前者は1970年1月1日からの経過秒数を整数で返し、後者はシステム依存のタイムスタンプを小数で返します。
絶対的な日時や日付などが重要な場合はtime()を、ある時点からの相対的な経過時間などが必要な場合はtime_precise()を使うと良いでしょう。

ちなみにここで初登場したgfx_printf()という関数ですが、C言語のprintfのような感じで画面に文字列を描画します。gfx_drawstr()では数値の変数を描画することができません。数値を画面に表示したい場合はgfx_printf("%f", 数値変数)のように書きます。

参考: printf - Wikipedia

条件分岐

desc:condition

@gfx
gfx_r = rand();
gfx_g = rand();
gfx_b = rand();

gfx_x = 10;

gfx_y > gfx_h ? gfx_y = 0 : gfx_y += 10;

gfx_drawstr("AAAAAAAAAA");

なんと、JSFXではif文が使えません!その代わりに条件演算子を使って表します。
この例ではgfx_yが描画領域の高さよりも大きくなったらgfx_yを0に設定し、そうでなければgfx_yの値に10を加算する、という処理をしています。これがgfx_y > gfx_h ? gfx_y = 0 : gfx_y += 10;の部分で行われている処理です。

if文で書いたとすると

if (gfx_y > gfx_h) {
  gfx_y = 0;
} else {
  gfx_y += 10;
}

というような感じになります。

もし◯◯だったら、の中のコードが複数になる場合は()でくくって複数のコードを書くこともできます。

条件 ? (
  ...
  ...
) : (
  ...
  ...
);

という感じで。

繰り返し

desc:condition

@gfx
gfx_r = rand();
gfx_g = rand();
gfx_b = rand();

gfx_x = 10;
gfx_y = 10;

loop(5, gfx_drawstr("Hello"));

gfx_x = 10;
gfx_y = 30;

while(gfx_x < gfx_w) (
  gfx_drawstr("He");
);

一定回数の繰り返し処理を行うにはloop(回数, 処理)のように書きます。回数には変数を与えることも可能ですが、loopに入った時点の値でループ回数が決まり、ループ内で変数を変更しても反映されません。

他のプログラミングに慣れている人はwhile(条件) (処理)という書き方の方がしっくり来るかもしれません。上記の例ではgfx_x < gfx_wの条件を満たす間、gfx_drawstr("He")の処理を繰り返します。

上記の例でgfx_xの値をいじっている箇所はどこにもないのに、なんで無限ループにならないんだろう?と思った方もいるかもしれません。
実はgfx_drawstrは内部で描画した文字列の分だけgfx_x,gfx_yの値を増やします。なので、gfx_drawstrを繰り返し呼ぶだけで文字が横に並ぶのです。文字列に改行\nを含んでいたら、ちゃんとgfx_yの値も増えていることがわかります。

9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4