このブログの内容が難しい方へ

もし、内容が難しくて理解出来ない場合には、Cプログラミング入門以前などのプログラミングを始める前に知っておくと良い事が書いてある本を読んでから、その後にやさしいC 第3版 [やさしいシリーズ]などのC言語というプログラミング言語の入門書を読むことをお勧めします。また、MIDIの知識がない人は、コンプリートMIDIブックなどがお勧めです。そこまで理解できれば、KSP特有の作法は、このブログを参考にすれば大丈夫だと思います。

2011年9月17日土曜日

set_event_par(),set_event_par_arr()

set_event_parは、イベントのパラメータを設定するだけです。第1引数にはIDを、第2引数にはパラメータの種類を、第3引数には値を指定します。


on note
	set_event_par($EVENT_ID,$EVENT_PAR_NOTE,30)
end on

何を弾いても、ノートナンバー30の音が再生されます。

set_event_par_arrは、第1引数にはIDを、第2引数は$EVENT_PAR_ALLOW_GROUPで固定、第3引数には1でグループを有効に0で無効に、第4引数にはグループインデックスを指定します。


on note
	disallow_group($ALL_GROUPS)
	set_event_par_arr($EVENT_ID,$EVENT_PAR_ALLOW_GROUP,1,find_group("Single"))
end on

この場合は、Singleというグループだけを有効にしています。

get_event_ids(),get_event_par(),get_event_par_arr()

get_event_idsは、現在、有効なイベントがあれば、そのIDを配列に入れていきます。get_event_idsは、呼び出される度に配列の内容を上書きします。


on init
	declare %Array[200]
end on

on note
	get_event_ids(%Array)
	message(%Array[0])
end on

これは、現在有効なイベントの1つ目のIDをステータスラインに表示します。

get_event_parは、第1引数にはイベントのIDを、第2引数には取り出すパラメータの種類を指定して、その値を取り出します。


on note
	message(get_event_par($EVENT_ID,$EVENT_PAR_VELOCITY))
end on

この場合は、ノートオンのベロシティがステータスラインに表示されます。

get_event_par_arrは、指定したグループが有効か無効かの状態を返します。第1引数にはイベントのIDを、第2引数は$EVENT_PAR_ALLOW_GROUPで固定、第3引数にはグループインデックスを指定します。


on init
	declare $State
end on

on note
	disallow_group($ALL_GROUPS)
	$State := get_event_par_arr($EVENT_ID,$EVENT_PAR_ALLOW_GROUP,find_group("Single"))
	message($State)
end on

この場合は、Singleというグループが無効になっているので、0がステータスラインに表示されます。

on init
	declare $State
end on

on note
	$State := get_event_par_arr($EVENT_ID,$EVENT_PAR_ALLOW_GROUP,find_group("Single"))
	message($State)
end on

このようにすると、1がステータスラインに表示されます。

2011年9月11日日曜日

ignore_event(),ignore_controller()

ignore_eventは、指定したイベントのIDのノートイベントを無視しちゃいます。


on note
	ignore_event($EVENT_ID)
end on

どの鍵盤を押しても、反応がなくなります。

ignore_controllerは、コントローラーイベントを無視しちゃいます。


on controller
	if($CC_NUM = $VCC_PITCH_BEND)
		ignore_controller
	end if
end on

ピッチベンドを無効化しています。

event_status()

event_statusはイベントIDを渡すと、そのイベントが生きているか死んでいるかを返します。生きていれば1、死んでいれば0を返します。


on init
	declare $text
	declare $id
end on

on note
	$text := event_status($id)
	message($text)
	$id := $EVENT_ID
end on

1つ前のイベントのIDを渡してみると、0が返っていることが分かります。

on init
	declare $text
	declare $id
end on

on note
	$id := $EVENT_ID
	$text := event_status($id)
	message($text)
end on

現在のイベントのIDを渡してみると、1が返っていることが分かります。

change_note(),change_pan(),change_tune(),change_velo(),change_vol()

change_noteは、指定したイベントのノートナンバーを変更します。第1引数にはイベントのIDを、第2引数にはノートナンバーを指定します。


on init
	declare ui_knob $Key(-12,12,1)
	$Key := 0
end on

on note
	change_note($EVENT_ID,$EVENT_NOTE+$Key)
end on

この場合は、ノブで指定した値だけキーを変更します。

change_panは、指定したイベントのパンを変更します。第1引数にはイベントのIDを、第2引数にはパンの値を、第3引数には第2引数の値が相対的か絶対的なのかを指定します。


on init
	declare $Pan
end on

on note
	$Pan := random(-1000,1000)
	change_pan($EVENT_ID,$Pan,0)
end on

パンをランダムな値にしています。

change_tuneは、ミリセント単位で音程を変更します。第1引数にはイベントのIDを、第2引数には変更する値を、第3引数には第2引数の値が相対的か絶対的なのかを指定します。


on init
	declare $tune
end on

on note
	$tune := random(-500000,500000)
	change_tune ($EVENT_ID,$tune,0)
end on

これを実行して鍵盤を連打すると、昔懐かしいアニメのコンピュータっぽい効果音になります(笑)

change_volもchange_veloも同じように使います。


on init
	declare $note
	declare $pan
	declare $tune
	declare $velo
end on

on note
	$note := random(-12,12)
	change_note($EVENT_ID,$EVENT_NOTE+$note)
	$pan := random(-1000,1000)
	change_pan($EVENT_ID,$pan,0)
	$velo := random(-20,20)
	change_velo($EVENT_ID,$velo)
	$tune := random(-500000,500000)
	change_tune ($EVENT_ID,$tune,0)
end on

全部ランダムにしてみると、こんな感じになります。

play_note(),note_off(),set_controller()

play_noteは、ノート・オンを生成します。第1引数にはノートナンバーを、第2引数にはベロシティを、第3引数にはオフセットを、第4引数にはデュレーションを指定します。第4引数には、-1を指定するとトリガーしたノートのノートオフと同時に音が止まります。0を指定すると、トリガーしたノートのノートオフに関係なく、サンプルの最後まで再生されます。


on note
	play_note($EVENT_NOTE + 7,$EVENT_VELOCITY,0,-1)
end on

完全5度音程で、和音を生成します。

on note
	while($NOTE_HELD = 1)
		wait($DURATION_EIGHTH)
		play_note($EVENT_NOTE + 7,$EVENT_VELOCITY,0,$DURATION_EIGHTH)
	end while
end on

鍵盤が押されている間、8分音符感覚で、完全5度音程の音が再生されます。

note_offは、ノートオフを生成します。


on init
	declare ui_button $Button
	set_text ($Button,"Stop All Notes")
end on

on ui_control($Button)
	note_off($ALL_EVENTS)
	wait(100000)
	$Button := 0
end on

発音中の全てのノートを停止させます。何かのエラーが起きた時のために、こういうボタンを用意しておくと親切かもしれません。

set_controllerは、CCやピッチベンドを生成します。第1引数にはCCナンバーか$VCC_PITCH_BENDでピッチベンドを指定します。第2引数には値を指定します。


on note
	set_controller(1,100)
end on

on release
	set_controller(1,0)
end on

ノートオンでモジュレーションが100、ノートオフでモジュレーションが0になります。

2011年9月9日金曜日

output_channel_name()

output_channel_nameは、アウトプットチャンネルの名前を返すだけです。

on init
	declare @String
	@String := output_channel_name(0)
	message(@String)
end on

output_channel_name(0)の0を1や2にしてみると動作が分かると思います。

msb(),lsb()

14ビットの値を、msbとlsbに7ビットずつの値として、変換します。この辺りはMIDIの知識がないと分からないと思うので、分からない人は分からないままで問題ないです。

on init
  declare ui_knob $Value (0,16383,1)
end on
on ui_control ($Value)
  message("MSB: " & msb($Value) & " - LSB: " & lsb($Value))
end on

ui_knobに、14ビット分の値を設定します。で、msbで上位7ビット、lsbで下位7ビットの値を取り出しているわけです。この7ビットというのは、0~127を表現できるビット数のことですよ、と言うと、割と馴染みのある数字に見えてくると思います。

reset_ksp_timer,wait(),ticks_to_ms(),ms_to_ticks,ticks_to_ms

reset_ksp_timerは、$KSP_TIMERの値をリセットするだけです。$KSP_TIMERはKontaktが起動してからの時間をマイクロ秒単位で格納してます。reset_ksp_timerは、あるスクリプトの処理にどれくらいの時間がかかっているかを調べたりするのに使えます。

on init
	message($KSP_TIMER)
end on

on note
	message($KSP_TIMER)
end on

on controller
	if($CC_NUM = 1)
		reset_ksp_timer
		message($KSP_TIMER)
	end if
end on

waitは、指定した時間だけ、マイクロ秒単位でコールバックの処理を停止させます。

on note
	wait($DURATION_EIGHTH)
	play_note($EVENT_NOTE,$EVENT_VELOCITY,0,$DURATION_EIGHTH)
end on

8分音符分の時間だけ待って、リピートしてます。$DURATION_EIGHTHっていうのは組み込み変数で、現在のテンポでの8分音符分の時間になります。ちなみに、ticks_to_msはティックからマイクロ秒へ、ms_to_ticksは、マイクロ秒からティックへ変換します。

on init
	declare $Ticks
	$Ticks := ms_to_ticks($DURATION_QUARTER)
	message($Ticks)
end on

2011年9月8日木曜日

abs(),random(),inc(),dec(),message(),exit()

今回は、簡単なコマンドをいくつかご紹介します。absは絶対値を返します。randomは指定した範囲内でのランダムな値を返します。incは値をインクリメントします。decは値をデクリメントします。messageはすでにご存知だと思いますが、ステータスラインにテキストを表示します。exitはコールバックを強制終了します。一つ一つ見ていきましょう。

on init
	declare $test
	declare $abs
	$test := -2
	$abs := abs($test)
	message($abs)
end on

ステータスラインに2が表示されてますよね?

on init
	declare $random
	$random := random(0,10)
	message($random)
end on

randomは第1引数には最小値を、第2引数には最大値を指定します。あとはその範囲内でステータスラインに値が表示されます。

on init
	declare $inc
	$inc := 3
	inc($inc)
	message($inc)
end on
ステータスラインに4が表示されてますよね。インクリメントは値を+1します。

on init
	declare $dec
	$dec := 3
	dec($dec)
	message($dec)
end on

デクリメントはその逆。

on init
	declare $test
	$test := 20
end on

on note
	if($EVENT_NOTE = 64)
		exit
	else
		inc($test)
		message($test)
	end if
end on

exitは、コールバックを強制終了します。ノートナンバー64(E)の時だけ、インクリメントされません。

listener callbackとset_listener()とchange_listener_par()

listener callbackは、一見難しいようで、実はものすごく簡単です。(listener callbackがなかった頃は、同じ事をやろうとすると結構面倒だったんですよ……。いい時代になったものです。)で、ちょっと復習になりますが、listener callbackは、ホストのスタートとストップ、もしくは一定間隔置きに実行したいプログラムを簡単に書くことが出来ます。はっきし言ってちょーおもしろカッコイイ(←ネタが古い)機能です。listener callbackを使うには、ちょっとした事前準備が必要でして、init callbackにて、どのタイミングでlistener callbackを呼び出すかを予め指定しておきます。そして、listener callbackにて、実際に実行したいプログラムを書いていくわけです。では、以下のコードを見てください。

on init
	set_listener ($NI_SIGNAL_TRANSP_START,1)
	set_listener ($NI_SIGNAL_TRANSP_STOP,1)
	set_listener ($NI_SIGNAL_TIMER_MS,1000)
	set_listener ($NI_SIGNAL_TIMER_BEAT,1)
end on

on listener
	select ($NI_SIGNAL_TYPE)
		case $NI_SIGNAL_TRANSP_STOP
			message ("Stopped")
		case $NI_SIGNAL_TRANSP_START
			message ("Started")
		case $NI_SIGNAL_TIMER_MS
		case $NI_SIGNAL_TIMER_BEAT
	end select
end on

set_listenerは、init callback内でのみ使えます。これで、どのタイミングでlistener callbackを呼び出すかを指定しておきます。第1引数にはシグナルタイプを、第2引数にはパラメータを指定します。シグナルタイプには四種類しかないので、覚えてしまいましょう。$NI_SIGNAL_TRANSP_STARTは、ホストがスタートした時で、$NI_SIGNAL_TRANSP_STOPは、ホストがストップした時にlistener callbackを呼び出すかを指定します。この場合は、第2引数のパラメータが1の時には、呼び出し、0の時には呼び出しません。注目すべきは、listener callbackで、select文で$NI_SIGNAL_TYPEによって、処理を選択出来ることです。これで、アイディア次第で色んな事ができます。$NI_SIGNAL_TIMER_MSは、第2引数に指定したマイクロ秒単位でlistener callbackを呼び出します。

on init
	declare $Count
	set_listener ($NI_SIGNAL_TRANSP_STOP,1)
	set_listener ($NI_SIGNAL_TRANSP_START,1)
	set_listener ($NI_SIGNAL_TIMER_MS,1000000)
	set_listener ($NI_SIGNAL_TIMER_BEAT,1)
end on

on listener
	select ($NI_SIGNAL_TYPE)
		case $NI_SIGNAL_TRANSP_STOP
			message ("Playback was stopped.")
		case $NI_SIGNAL_TRANSP_START
			message ("Playback was started.")
		case $NI_SIGNAL_TIMER_MS
			$Count := $Count + 1
			message($Count)
		case $NI_SIGNAL_TIMER_BEAT
	end select
end on

1秒単位でlistener callbackを呼び出して、変数Countの値をステータスラインに表示しています。

on init
	declare $Count
	set_listener ($NI_SIGNAL_TRANSP_STOP,1)
	set_listener ($NI_SIGNAL_TRANSP_START,1)
	set_listener ($NI_SIGNAL_TIMER_MS,1000000)
	set_listener ($NI_SIGNAL_TIMER_BEAT,1)
end on

on listener
	select ($NI_SIGNAL_TYPE)
		case $NI_SIGNAL_TRANSP_STOP
			message ("Playback was stopped.")
		case $NI_SIGNAL_TRANSP_START
			message ("Playback was started.")
		case $NI_SIGNAL_TIMER_MS
		case $NI_SIGNAL_TIMER_BEAT
			$Count := $Count + 1
			message($Count)
	end select
end on

$NI_SIGNAL_TIMER_BEATは、第2引数に、一拍あたりに何回呼び出すかをを指定します。

on init
	declare $Count
	set_listener ($NI_SIGNAL_TRANSP_STOP,1)
	set_listener ($NI_SIGNAL_TRANSP_START,1)
	set_listener ($NI_SIGNAL_TIMER_MS,1000000)
	set_listener ($NI_SIGNAL_TIMER_BEAT,1)
	change_listener_par($NI_SIGNAL_TIMER_BEAT,2)
end on

on listener
	select ($NI_SIGNAL_TYPE)
		case $NI_SIGNAL_TRANSP_STOP
			message ("Playback was stopped.")
		case $NI_SIGNAL_TRANSP_START
			message ("Playback was started.")
		case $NI_SIGNAL_TIMER_MS
		case $NI_SIGNAL_TIMER_BEAT
			$Count := $Count + 1
			message($Count)
	end select
end on

ちなみに、change_listener_parは、設定を変更するだけです。change_listener_parは、set_listenerと違い、どのコールバックでも使うことが出来ます。

2011年9月7日水曜日

set_control_par()とget_control_par()とget_ui_id()

set_control_parとget_control_parは、少し使いこなすのが難しいと思います。というのも、UI要素の各パラメータは、予め組み込み変数として用意されています。で、その変数にset_control_parによって値を設定したり、get_control_parによって値を取り出したりするわけです。なので、組み込み変数とセットで使い方を覚えないといけません。ですが、ここで組み込み変数の全てを一気に説明するのは大変なので、気になる人は、KSPのマニュアル(Kontakt4のです)で、114ページを見てください。

set_control_parの第1引数にはui要素のIDを、第2引数には組み込み変数を、第3引数には値を設定します。第3引数がテキストだったり配列だったりする場合には、それぞれ、set _control_par_strとset_control_par_arrに変わるところに注意が必要です。get_control_parは、第1引数にはui要素のIDを、第2引数には組み込み変数を指定します。


on init
	make_perfview
	set_ui_height(3)
	declare ui_slider $Slider(0,100)
	set_control_par_str(get_ui_id($Slider),$CONTROL_PAR_PICTURE,...
"pv_orchestral_knob")
end on

これはスライダーを宣言し、そこからスライダーの画像を変更しています。pv_orchestral_knobというのは、Kontakt4をインストールするとプリセットに組み込まれる画像データです。get_ui_idは、UI要素の名前を渡すとIDを返します。

set_skin_offset()

set_skin_offsetは、壁紙の表示位置を指定するのに使います。引数にはピクセル単位で数値を指定するだけです。壁紙はInstrument Options → Instrument → Instrument WallpaperのBrawseをクリックすると指定できます。適当にプリセットの中にあるtgaファイルを指定してみてください。

on init
  make_perfview
  set_ui_height(1)
end on

on note
        set_skin_offset($EVENT_NOTE)
end on

ノートナンバーの高低で、壁紙が動きます。

2011年9月6日火曜日

set_control_help()

set_control_helpは、Kontaktのインフォペインに、各UI要素の説明を表示することが出来ます。インフォペインは、Kontaktの上部にある「Info」を有効にすると、下部に表示されます。第1引数には変数を、第2引数にはテキストを設定します。

on init
	declare ui_knob $Knob(0,100,1)
	set_control_help($Knob,"Knob")
end on

ノブの上にマウスを持ってくると、インフォペインにKnobと表示されると思います。set_key_colorと同じように、こういうところにも配慮したいところですね:-)

set_key_color()

set_key_colorは、Kontaktのキーボードの色を変更したい時に使います。キースイッチの位置や、KSPで用意した機能を配置したキーの位置を視覚的に示すのに使えると思います。第1引数にはノートナンバーを、第2引数には色の指定をします。色の指定には、以下のものが使えます。
  • $KEY_COLOR_NONE
  • $KEY_COLOR_WHITE
  • $KEY_COLOR_YELLOW
  • $KEY_COLOR_GREEN
  • $KEY_COLOR_RED
  • $KEY_COLOR_CYAN
  • $KEY_COLOR_BLUE
  • $KEY_COLOR_BLACK
とりあえず、動作確認のためにしか使えない(笑)スクリプトをどうぞ。

on init
	declare $count
end on

on note
	set_key_color(60,$KEY_COLOR_YELLOW)
	set_key_color(62,$KEY_COLOR_GREEN)
	set_key_color(64,$KEY_COLOR_RED)
	set_key_color(65,$KEY_COLOR_CYAN)
	set_key_color(67,$KEY_COLOR_BLUE)
end on

on release
	while ($count < 128)
		set_key_color($count,$KEY_COLOR_WHITE)
		$count := $count + 1
	end while
	$count := 0
end on

set_script_title()

set_script_titleは、テキストを渡して、スクリプトのタイトルを設定するだけです。それだけです。でも、スクリプトを書く上で、必須項目だとは思います:-)

on init
	set_script_title("Junk Guitar")
end on

2011年9月5日月曜日

move_controlとmove_control_px

move_controlも特に難しくなくて、第1引数には変数、第2引数にはX(横)軸の位置(最大値は6)、第3引数にはY(縦)軸の位置(最大値は16)を指定します。で、このmove_controlはinit callback以外でも使えるので、イベントによってUI要素を動かせるわけです。

on init
	make_perfview
	set_ui_height(8)
	declare ui_knob $Knob(0,1000,1)
	move_control($Knob,1,1)
	declare $X := 1
	declare $Y := 1
end on

on note
	if($X < 6)
		$X := $X + 1
	else
		$X := 1
		if($Y < 15)
			$Y := $Y + 2
		else
			$Y := 1
	end if
	end if
	move_control($Knob,$X,$Y)
end on

このプログラムを実行すると、ノートオン毎にノブが動きます。ちなみにmove_control_pxは、ピクセル単位で動かすことが出来ます。

on init
	make_perfview
	set_ui_height(8)
	declare ui_knob $Knob(0,1000,1)
	move_control_px($Knob,66,2)
	declare $X := 66
	declare $Y := 2
end on

on note
	if($X < 500)
		$X := $X + 90
	else
		$X := 66
		if($Y < 260)
			$Y := $Y + 40
		else
			$Y := 2
	end if
	end if
	move_control_px($Knob,$X,$Y)
end on

で、これはピクセル単位で動かしただけ。

make_perfview

make_perfviewは、init callbackでしか使えません。で、何をするかというと、パフォーマンスビューにスクリプトで作り上げたUIを表示すると設定することになります。面白いのが、make_perfviewをそれぞれのスロット(スクリプトを埋め込めるスロットは5つありますよね?)で設定すると、設定した数だけ、パフォーマンスビューに表示できます。その場合は、タブで切り替えれるようになっています。

on init
	make_perfview
	declare ui_knob $Knob(0,100,1)
end on

試しに、これをどこかのスロットに。

on init
	make_perfview
	declare ui_table %table_1[10] (2,2,100)
	declare ui_table %table_2[10] (2,2,-100)
end on

これは別のスロットにコピペしてみてください。この状態で、パフォーマンスビューを確認してみると、効果が分かると思います。

set_ui_height()とset_ui_height_px()

set_ui_heightとset_ui_height_pxは、UIの高さを指定します。set_ui_heightはグリッド単位で1~8の間で指定します。set_ui_height_pxはピクセル単位で50~350の間で指定します。

on init
	make_perfview
	set_ui_height(8)
end on

こっちはグリッド単位。

on init
	make_perfview
	set_ui_height_px(350)
end on

こちらはピクセル単位。

ui_waveformとattach_zone()

ui_waveformは、波形を表示するものです。第1引数には幅、第2引数には高さを指定します。どちらも最大値は6です。それ以上の値を指定すると表示されなくなります。(ただし、set_ui_height()で高さを変更した場合は別です)

n init
  declare ui_waveform $Waveform(6,6)
end on

で、これだけだと、箱を用意しただけなので、表示する波形を指定しないといけません。attach_zoneで、第1引数にui_waveformの変数、第2引数にゾーンID、第3引数にフラグを指定します。ゾーンIDは、find_zoneにゾーンの名前を渡して、IDを返してもらいます。ちなみにfind_zoneはinit callbackでしか使えません。

on init
  declare ui_waveform $Waveform(6,6)
  attach_zone ($Waveform,find_zone(”Zone_1”),0)
end on

これで、Zone_1の波形が表示されます。ちなみにゾーン名は、「Browse」を有効にして、Monitorタブをクリック、Zonesのところに表示されてます。フラグについては、僕もはっきりと理解できていません。ご存じの方がいらっしゃいましたら、教えて頂ければ幸いです。

ui_tableとset_table_steps_shown()

ui_tableの特徴は、配列を使うっていうことです。あとは特に難しくないです。配列なので、列の数も指定します。あとは第1引数に幅、第2引数に高さ、第3引数に値域を指定します。値域は、-にすると、最小値がその値で、最大値が-を取った値になります。ちょっと文字だけだと説明しにくいので、以下のコードを実行してみてください。

on init
  declare ui_table %table_1[10] (2,2,100)
  declare ui_table %table_2[10] (2,2,-100)
end on

set_table_steps_shownは、テーブルの列の数を変更する時に使います。第1引数に配列を、第2引数に変更したい値を指定します。

on init
	declare ui_table %table_1[10] (2,2,100)
	set_table_steps_shown(%table_1,5)
end on

ここで、気を付けないといけないのが、最初に配列で指定した以上の数には変更できないことです。

on init
	declare ui_table %table_1[10] (2,2,100)
	set_table_steps_shown(%table_1,20)
end on

列数を20に指定しても、変化しません。これは、配列 table_1が10までしか宣言していないからです。

ui_menuとadd_menu_item()

ui_menuとadd_menu_itemはセットで使います。ui_menuは宣言するだけです。add_menu_itemはinit callbackでのみ使えます。ui_menuに表示されるテキストを指定するのに使います。第1引数には変数を、第2引数にはテキストを、第3引数には数値を指定します。この第3引数のことが少し分かりにくいと思うので、以下のコードを見てください。

on init
	declare ui_menu $Menu
	add_menu_item($Menu,"8th",0)
	add_menu_item($Menu,"16th",1)
	add_menu_item($Menu,"32th",2)
	$Menu := 0
end on

実際に実行してみると、第2引数のテキストまでは、意味がわかると思います。第3引数ですが、$Menu := 0のところを、1とか2にしてみると意味が分かると思います。つまり、$Menuの値とテキストを対応付けているわけです。ということは、以下のように書いても問題ないわけです。

on init
	declare ui_menu $Menu
	add_menu_item($Menu,"8th",2)
	add_menu_item($Menu,"16th",1)
	add_menu_item($Menu,"32th",0)
	$Menu := 0
end on

hide_part()

hide_partは、その名の通り、UI要素の各パーツを隠しちゃうわけです。第1引数には変数を、第2引数には何を隠すかっていうのを指定します。第2引数に指定できるのは、$HIDE_MOD_LIGHT(ui_knobにしか適用出来ない)、$HIDE_PART_TITEL(ui_knobにしか適用出来ない)、$HIDE_PART_VALUE(ui_knobにしか適用出来ない)、$HIDE_PARTGB(ui_knob、ui_label、ui_value_edit、ui_tableに適用できる)です。あと、hide_partはinit callbackでしか使えません。ちなみに、第2引数に複数指定したい場合には、それぞれを「.or.」でつないで指定します。

on init
  declare ui_knob $Knob (0,100,1)
  hide_part($Knob,$HIDE_PART_BG...
  .or. $HIDE_PART_MOD_LIGHT...
  .or. $HIDE_PART_TITLE...
  .or. $HIDE_PART_VALUE)
end on

で、こんなことが出来て何が嬉しいのかと言いますと、Kontaktでは、Instrument Optionsで、壁紙を設定出来るわけです。(フォントとかで)グラフィックデザインにこだわりたい場合には、これで各要素のパーツを隠して、壁紙の方でテキストとかを配置することも出来るわけなんですねー。(僕はグラフィックデザインは出来ないので、一人ではそこまで作り込めませんが……)

ui_value_edit

ui_value_editの動作は、ui_knobと似ているので、ミュージシャンのためのKSP入門: ui_knobを参照してください。第1引数には最小値、第2引数には最大値、第3引数にはdisplay-ratioです。一応、宣言の仕方だけ。

on init
	declare ui_value_edit $Value (0,100,1)
end on

ui_labelとset_text()とadd_text_line()

ui_labelも簡単です。第1引数には幅、第2引数には高さを指定するだけです。ui_labelは、文字列を表示するのに使います。

on init
	declare ui_label $Label_1 (1,4)
end on

とりあえず、ラベルを表示しただけです。set_textは第1引数には変数、第2引数にはテキストを指定するだけです。set_textはこんな感じになります。

on init
	declare ui_label $Label_1 (1,4)
	set_text($Label_1,"Label")

	declare ui_knob $Knob_1 (0,100,1)
	set_text($Knob_1,"Knob")

	declare ui_button $Button_1
	set_text($Button_1,"Button")

	declare ui_switch $Switch_1
	set_text($Switch_1,"Switch")

	declare ui_value_edit $Value_Edit (0,100,1)
	set_text($Value_Edit,"Value_Edit")
end on

これも特に難しくないですよね。ui_value_editは次回以降に説明しますが、実際に実行してみれば引数の動作はui_knobと一緒なのが分かると思います。add_text_lineは、テキストをどんどん追加していきますが、set_textは、既存のテキストを一度全部消去してしまいます。

on init
	declare ui_label $Label_1 (1,4)
	set_text($Label_1,"Label")
	add_text_line($Label_1,"Test")
end on

on note
	add_text_line($Label_1,$EVENT_NOTE)
end on

on controller
	if($CC_NUM = 1)
		set_text($Label_1,"Clear")
	end if
end on

ノートオンのたびに、ノートナンバーがラベルにどんどん追加されると思います。そして、モジュレーションホイールを動かすと、全てのテキストが消去され、「Clear」の文字だけになるはずです。set_textとadd_text_lineの違いはこんなところです。

2011年9月4日日曜日

ui_buttonとui_switch

ui_buttonとui_switchは、ほとんど同じです。違うのは、ui_switchは、オートメーションを設定できるのに対して、ui_buttonは設定できません。オートメーションは、Kontaktのウィンドウの上部の「Browse」をクリックして、Autoタブを選択して表示される、Host AutomationとMidi Automationです。ここから、ui_switchへドラッグするとマウスアイコンが+の表示になるので、アサイン出来るわけです。

on init
	declare ui_button $Button_1
	declare ui_switch $Switch_1
end on

とりあえず、ボタンとスイッチを表示しただけ。

on init
	declare ui_button $Button_1
	declare ui_button $Button_2
	declare ui_button $Button_3
	
	$Button_1 := 1
end on

on ui_control ($Button_1)
	if($Button_1 = 0)
		$Button_1 := 1
	else
		$Button_2 := 0
		$Button_3 := 0
	end if
end on

on ui_control ($Button_2)
	if($Button_2 = 0)
		$Button_2 := 1
	else
		$Button_1 := 0
		$Button_3 := 0
	end if
end on

on ui_control ($Button_3)
	if($Button_3 = 0)
		$Button_3 := 1
	else
		$Button_1 := 0
		$Button_2 := 0
	end if
end on

ボタンをラジオボタンみたいな挙動にしてみました。

ui_slider

ui_sliderは特に難しくないです。第1引数には最小値、第2引数には最大値を設定するだけです。

on init
	declare ui_slider $Slider (0,100) 
end on

on ui_control($Slider)
	message($Slider)
end on

set_knob_unit()

set_knob_unitは、ノブに表示される数値に単位もセットで表示したい場合に使います。第1引数には変数を、第2引数には単位をしていします。 $KNOB_UNIT_NONEは非表示、$KNOB_UNIT_DBはdB、$KNOB_UNIT_HZはHz、$KNOB_UNIT_PERCENTは%、$KNOB_UNIT_MSはms、$KNOB_UNIT_OCTはOC、$KNOB_UNIT_STはStになります。

on init
	declare ui_knob $Knob_1(0,100,1)
	set_knob_unit($Knob_1,$KNOB_UNIT_NONE)
	declare ui_knob $Knob_2(-600,600,100)
	set_knob_unit($Knob_2,$KNOB_UNIT_DB)
	declare ui_knob $Knob_3(4300,4500,10)
	set_knob_unit($Knob_3,$KNOB_UNIT_HZ)
	declare ui_knob $Knob_4(0,100,1)
	set_knob_unit($Knob_4,$KNOB_UNIT_PERCENT)
	declare ui_knob $Knob_5(0,1000,10)
	set_knob_unit($Knob_5,$KNOB_UNIT_MS)
	declare ui_knob $Knob_6(-4,4,1)
	set_knob_unit($Knob_6,$KNOB_UNIT_OCT)
	declare ui_knob $Knob_7(0,100,1)
	set_knob_unit($Knob_7,$KNOB_UNIT_ST)
end on

set_knob_label()

set_knob_labelは、ノブの値を数値じゃなくてテキストにしたいよ!っていう時に使います。第1引数にはノブの変数を、第2引数にはテキストを指定します。

on init
	declare ui_knob $Rate (0,17,1)
	set_knob_label($Rate,"Text")
end on

で、このように書いちゃうと、ノブをいくら回してもTextとしか表示されません。なので、この場合は、先に文字列配列を用意します。そして、ノブを回した時に文字列配列からテキストを読み込むようにします。

on init
	declare !rate_names[18]

	!rate_names[0] := "1/128"
	!rate_names[1] := "1/64"
	!rate_names[2] := "1/32"
	!rate_names[3] := "1/16 T"
	!rate_names[4] := "3/64"
	!rate_names[5] := "1/16"
	!rate_names[6] := "1/8 T"
	!rate_names[7] := "3/32"
	!rate_names[8] := "1/8"
	!rate_names[9] := "1/4 T"
	!rate_names[10] := "3/16"
	!rate_names[11] := "1/4"
	!rate_names[12] := "1/2 T"
	!rate_names[13] := "3/8"
	!rate_names[14] := "1/2"
	!rate_names[15] := "3/4"
	!rate_names[16] := "4/4"
	!rate_names[17] := "Bar"

	declare ui_knob $Rate (0,17,1)
	$Rate := 8
	set_knob_label($Rate,!rate_names[$Rate])
end on

on ui_control ($Rate)
	set_knob_label($Rate,!rate_names[$Rate])
end on

文字列配列rate_namesにそれぞれテキストを入れてます。その後に、ui_knobの初期値8(1/8)を指定して、ノブのラベルにテキストを設定しています。あとは、ui callbakにて、ノブの値が変更される度に、テキストも変更するようにしています。

set_knob_defval()

set_knob_defvalは、コマンドキーを押しながら(Macの場合です)、ui_knobをクリックした時に設定される値を設定します。気を付けないといけないのが、あくまでコマンドキーとセットでクリックした時に設定される値であって、スクリプトを読み込んだ時に設定される値ではないということです。

on init
	declare ui_knob $Knob(-100,100,1)
	set_knob_defval ($Knob,0)
end on

このプログラムを実行するとわかりますが、スクリプトを読み込んだ時には、Knobの値は0ではなく-100になります。スクリプトの解析が終わった段階で、Knobの値を0にしたい場合は以下のようにします。あ、その前に、一応、コマンドキーを押しながらノブをクリックして、動作を確認しておいてくださいね(笑)。

on init
	declare ui_knob $Knob(-100,100,1)
	set_knob_defval ($Knob,0)
	$Knob := 0
end on

ui_knob

ui_knobは、簡単なようで、ちょっと難しいところがあります。前回説明したとおり、UIの各要素はinit callbackで変数として宣言します。つまり、ui_knobは、変数の型ってことですね。で、引数の説明に入ります。ui_knobは引数を3つ取ります。第1引数には最小値、第2引数には最大値、第3引数にはdisplay-ratioとあります。このdisplay-ratioというのが、少し分かりにくいかもしれません。まずは、このdisplay-ratioを1にしてみましょう。

on init
      declare ui_knob $Knob_1 (0,10,1)
      declare ui_knob $Knob_2 (0,100,1)
      declare ui_knob $Knob_3 (0,1000,1)
      declare ui_knob $Knob_4 (5,10,1)
      declare ui_knob $Knob_5 (500,1000,1)
end on

さて、どれも特に理解するのに難しくない動作をすると思います。ちなみに、マウスで数値を細かく調整したい時にはshiftキーを押しながらになります。では、次のコードを見てください。

on init
      declare ui_knob $Knob_1 (0,1000,1)
      declare ui_knob $Knob_2 (0,1000,10)
      declare ui_knob $Knob_3 (0,1000,100)
      declare ui_knob $Knob_4 (0,1000,20)
      declare ui_knob $Knob_5 (0,1000,-1)
      declare ui_knob $Knob_6 (0,1000,-10)
end on

Knob_1は、特に難しくないですよね。では、Knob_2の動作です。これは結果的に、最小値が0で、最大値が100、単位が0.1ずつになると思います。Knob_1との違いは、display-ratioの値だけですので、ここが怪しいとなります。で、どういうことかというと、display-ratioを10にすると、第2引数に指定した値を10で割った値が最大値になります。この場合は、1000を10で割ると100になりますので、最大値は100になるわけです。さらに、ノブを動かした時の数値の変化の単位も1を10で割った値になります。つまり0.1ずつの変化になるわけです。同じようにKnob_3もKnob_4も計算してみてください。どうですか?ちゃんと計算したとおりの動作を確認できたでしょうか?ちなみにKnob_5とKnob_6は、マイナスを付けただけです。

on init
      declare ui_knob $Knob_1 (500,1000,10)
end on

ちなみに、第1引数に0以外の数値を指定した場合も、display-ratioで指定した値で割った値になります。この場合は、最小値が50.0で、最大値が100.0で、単位が0.1ずつの変化になります。

UI callback

次回から、UI関係の機能の説明をするので、その前段階として、UI callbackの説明をします。callbackは既に説明したとおり、あるイベントや、タイミングごとに実行されるプログラムのことです。UIとは、ユーザー・インターフェイスのことで、ボタンとかノブとかのことです。で、UI callbackは、他のコールバックと少し違うところがあります。それは、UI callbackごとに、各UI要素を指定して記述します。「on ui_control(変数)」という具合です。この場合の変数は、init callbackで、UI要素を変数として宣言するので、その変数を指定します。以下のコードを見てください。

on init
	declare ui_knob $Knob (0,100,1)
end on

on ui_control ($Knob)
	message("Knob" & "(" & $ENGINE_UPTIME & ")")
end on

ui_knobについては、次回以降に説明しますので割愛します(まぁ、プログラムを実行すれば一目瞭然ですがw)。ここで大事なのは、ui_control($Knob)の部分です。これは変数Knobに何らかの変化があると実行されるという意味です。ちなみに$ENGINE_UPTIMEとは、Kontaktが起動してからの経過時間をミリ秒単位で返します。つまり、ノブを動かすと経過時間がステータスラインに表示されるというわけです。簡単ですが、まずはここを理解しておいてください。

2011年9月3日土曜日

group_name()

group_nameはfind_groupの逆です。find_groupはグループ名からインデックスを取り出していましたが、group_nameはインデックスからグループ名を取り出します。グループ名の一覧を取り出したり、現在有効なグループ名を取り出したりするのに使うと便利です。

on init
	declare $count := 0
	declare ui_menu $groups_menu	
	while ($count < $NUM_GROUPS)
		add_menu_item ($groups_menu,group_name($count),$count)
		inc($count)
	end while
end on

$NUM_GROUPSは、グループの総数です。add_menu_itemで、メニューにグループ名を一つ一つセットしているわけです。

purge_group()とget_purge_state()

purge_groupは、メモリ上から、指定したグループのサンプルをパージしちゃいます。つまり、メモリ上から消えてしまうっていうことです。get_purge_stateは、指定したグループがパージされているのかされていないのかをチェックする時に使います。purge_groupは、第1引数にグループインデックスを、第2引数に0か1を指定します。0の場合はパージします。1の場合はリロードします。ちなみにpurge_groupはui callbackでのみ使えます。以下のコードを見てください。

on init
  declare ui_button $Purge
  set_text ($Purge,"Purge First Group")
end on

on ui_control ($Purge)
	message($Purge)
	purge_group(0 ,abs($Purge-1))
end on

ボタンをクリックすると、インデックス0のグループがパージされます。ボタンは、押した状態が1で、押されていない状態が0になるのがわかるように、message($Purge)で表示しています。つまり、押されていない状態の変数Purgeの状態が0なわけですから、-1をして、abs()で絶対値をとると1になるわけです。つまり、ボタンをクリックする度に、パージされたり、リロードされたりするわけです。ちなみに、グループ名を使いたい時には、以下のようになります。

on init
  declare ui_button $Purge
  set_text ($Purge,"Purge Single")
end on

on ui_control ($Purge)
	message($Purge)
	purge_group(finde_group("Single") ,abs($Purge-1))
end on

get_purge_stateは、第1引数にグループインデックスを渡します。パージされていれば0が、されていなければ1を返します。

on init
	declare $State
	declare ui_button $Purge
	set_text ($Purge,"Purge First Group")
end on

on ui_control ($Purge)
	purge_group(0 ,abs($Purge-1))
	$State := get_purge_state(0)
	message($State)
end on

allow_group()とdisallow_group()とfind_group()

allow_groupとdisallow_groupは、グループインデックスを引数にとって、グループを有効にしたり、無効にしたりします。find_groupはグループネームを引数にとって、グループインデックスを返します。つまり、find_groupはallow_groupやdisallow_groupと共に使うことが多いわけです。KSPプログラミングで、allow_groupとdisallow_groupは、よく使うことになると思いますので、しっかりと覚えてください。まずは、以下のコードを見てください。

on init
	declare $Flag := 0
end on

on note
	inc($Flag)
	message($Flag)
	if($Flag > 1)
		disallow_group($ALL_GROUPS)
		allow_group(find_group("Hammer"))
	else
		disallow_group($ALL_GROUPS)
		allow_group(find_group("Single"))
	end if
end on

on release
	dec($Flag)
	message($Flag)
end on

仮に、SingleとHammerという2つのグループが存在するライブラリがあったとします(この2つのグループには、特にキースイッチなどの設定はしない)。そこで、このスクリプトを適用すると、単音でレガートに弾くとHammerが発音されます。(ただし、実際にこのままスクリプトを使うと、色々とバグが発生しますので、オススメしません)。この、disallow_groupとallow_groupで気を付けないといけないのが、そのコールバックを呼んだイベントにしか適用されないということです。つまり、いわゆるキースイッチみたいな使い方は出来ないということです。例として、以下のスクリプトを見てください。

on note
	message($EVENT_NOTE)
	select($EVENT_NOTE)
		case 12
			disallow_group($ALL_GROUPS)
			allow_group(find_group("Group_1"))
		case 13
			disallow_group($ALL_GROUPS)
			allow_group(find_group("Group_2"))
		case 14
			disallow_group($ALL_GROUPS)
			allow_group(find_group("Group_3"))
		case 15
			disallow_group($ALL_GROUPS)
			allow_group(find_group("Group_4"))
	end select
end on

この場合、一見して、キースイッチのように動作するように思えます。しかし、ノートナンバー12のノート・オン・イベントが発生しても、それ自身のイベントにのみ有効であるため、ノートナンバー12のノート・オンでしか、Group_1にマッピングされたサウンドは再生されません。

save_array()とload_array()

save_array()は、配列の値を外部のファイルに保存します。load_array()は、外部のファイルに保存した配列の値を取り出します。第1引数には配列を渡し、第2引数は、0の時にはダイアログを表示し、1の時にはリソースコンテナを使います(リソースコンテナについては後日説明します)。0の時には、ui_callbackかpgs_callback内でしか使えません。1の時には、init callbackでしか使えません。では、以下のコードを見てください。

on init
	declare %Array [10] := (0,1,2,3,4,5,6,7,8,9)
	declare ui_menu $Menu
	add_menu_item($Menu,"Save",0)
	add_menu_item($Menu,"Load",1)
	declare ui_table %Table[10](3,3,10)
	declare $i
end on

on ui_control ($Menu)
	select($Menu)
		case 0
			$i := 0
			while($i < 10)
				%Array[$i] := %Table[$i]
				$i := $i + 1
			end while
			save_array(%Array,0)
		case 1
			load_array(%Array,0)
			$i := 0
			while($i < 10)
				%Table[$i] := %Array[$i]
				$i := $i + 1
			end while
	end select
end on

メニューにて、Saveを選択した時には、テーブルの値を配列Arrayにコピーした後、ファイルに保存するダイアログが表示されます。Loadを選択した時には、ダイアログが表示され、ファイルを選択し、配列Arrayeに値が読み込まれ、テーブルの値にコピーします。テーブルを適当にクリックして、値を変更したら、メニューでSaveを選んで、適当な名前を付けて、デスクトップに保存してください。そのファイルをテキストエディタで開くと、どのようなファイルになっているか分かります。

2011年9月2日金曜日

sort()

sort()は、並べ替えです。大きい順と小さい順を指定できます。第1引数には配列を、第2引数には並び順を指定できます。第2引数が0の場合には小さい順、0以外の場合には大きい順になります。以下のコードを見てください。

on init
	declare ui_table %Table[10] (3,3,100)
end on

on note
	sort(%Table,0)
end on

ui_tableについては後日説明します。とりあえず、Kontaktの画面に表示されるテーブルの値を適当に変更してみてください。その後、ノートオンで、小さい順に並べ替えされます。

search()

search()は、配列の中から、指定した値と同じ値を探し、何番目の要素なのかを返します。同じ値のものが2つ以上あった場合には、インデックスが小さい方を返します。見つからなかった場合には-1を返します。第1引数には配列を、第2引数には検索する値を指定します。以下のコードを見てください。

on init
	declare %Array_1[10] := (0,1,2,3,4,5,6,7,8,1)
	declare $Number
end on

on note
	if(search(%Array_1,1) = -1)
		message("Not Found")
	else
		$Number := search(%Array_1,1)
		message($Number)
	end if
end on

on release
	message(" ")
end on

このプログラムでは、ステータスラインに1が表示されます。Array_1[9]の1は無視されます。ついでに、以下のコードも記載しておきます。

on init
	declare %Array_1[10] := (0,1,2,3,4,5,6,7,8,1)
	declare $Number
end on

on note
	if(search(%Array_1,9) = -1)
		message("Not Found")
	else
		$Number := search(%Array_1,1)
		message($Number)
	end if
end on

on release
	message(" ")
end on

この場合は、Not Foundのテキストがステータスラインに表示されます。

num_elements()

num_elements()は、配列のサイズ(要素数)を返します。以下のコードを見てください。

on init
	declare %Array_1[10] := (0,1,2,3,4,5,6,7,8,9)
	declare %Array_2[20] := (0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19)
	declare $Number
end on

on note
	if($EVENT_NOTE > 64)
		$Number := num_elements(%Array_1)
		message($Number)
	else
		$Number := num_elements(%Array_2)
		message($Number)
	end if
end on

on release
	message(" ")
end on

ノートナンバーが64以上で配列Array_1の要素数が、ノートナンバーが63以下で配列Array_2の要素数がステータスラインに表示されます。

array_equal()

では、今回からは、KSP特有の機能(コマンドとか)を解説していきます。

array_equal()は、第1引数と第2引数に配列を渡して、2つの配列の値を比較します。全ての値が等しければtrue(真)、等しくないものがあればfalse(偽)を返します。以下のコードを見てください。

on init
	declare %Array_1[10]
	declare %Array_2[20]
	if(array_equal(%Array_1, %Array_2))
		message("Array_1 = Array_2")
	end if
end on

このプログラムはエラーが出ます。なぜなら、比較対象の配列Array_1とArray_2のサイズが違うからです。比較する場合には、同じサイズである必要があります。では、次のコードを見てください。

on init
	declare %Array_1[10] := (0,1,2,3,4,5,6,7,8,9)
	declare %Array_2[10] := (0,1,2,3,4,5,6,7,8,9)
end on

on note
	if(array_equal(%Array_1, %Array_2))
		message("Array_1 = Array_2")
	end if
end on

on release
	message(" ")
end on

このプログラムでは、ノートオンで、「Array_1 = Array_2」のテキストがステータスラインに表示されます。では、さらに次のコードを見てください。

on init
	declare %Array_1[10] := (0,1,2,3,4,5,6,7,8,9)
	declare %Array_2[10] := (0,1,2,3,4,5,6,7,8,10)
end on

on note
	if(array_equal(%Array_1, %Array_2))
		message("Array_1 = Array_2")
	else
		message("Array_1 # Array_2")
	end if
end on

on release
	message(" ")
end on


このプログラムでは、ノートオンで、「Array_1 # Array_2」のテキストがステータスラインに表示されます。つまり、1つでも配列の中の値が違えば、falseが返ってくるわけです。

ビット演算子

ビット演算子は、少し難しいです。2進数を理解していないと、ビット演算子を理解するのは難しいです。なので、2進数が苦手な人は、読まなくてもいいです(笑)。では、先にKSPに用意されているビット演算子の表を見てしまいましょう。

x .and. y ビット単位のand
x .or. y ビット単位のor
.not. x ビット単位の否定
sh_left(,) ビット単位での左シフト
sh_right(,) ビット単位での右シフト

では、一つ一つ調べていきましょう。ビット単位のandとは、xとyの値を、ビット単位で比較して、どちらも1であれば1を返し、どちらかが0、もしくはどちらも0であれば0を返します。どういうことかというと、例えば10進数で255とは、2進数にすると1111 1111になります(コンピュータ内では、もっと多くの桁を使っていて、9桁以上の桁は全て0になっています。この桁数が32桁だと32ビット、64桁だと64ビットと言うわけです)。そして、10進数で170は、2進数にすると、1010 1010になります。これをビット単位のandで演算すると、1010 1010の170になるわけです。もう1つ例を出すと、10進数で162(2進数だと1010 0010)と、10進数で10(2進数だと0000 1010)をビット単位のandで演算すると、0000 0010で2になるわけです。つまり、ビット単位の演算とは、2進数で、一桁ずつ演算するという意味です。KSPのプログラムだと以下のようになります。

on init
	declare $X := 162
	declare $Y := 10
	declare $A 
end on

on note
	$A := $X .and. $Y
	message($A)
end on

ビット単位のorとは、少なくともどちらかが1であれば1を返します。170と、85のビット単位のorとは、2進数にすると1010 1010と0101 0101のビット単位のorということなので、1111 1111の255になります。

on init
	declare $X := 170
	declare $Y := 85
	declare $A 
end on

on note
	$A := $X .or. $Y
	message($A)
end on

ビット単位のnotとは、つまり、ビット単位で反転するわけですね。170をビット単位でnot演算すると、1010 1010が0101 0101になるので、85に……なりません(笑)。まずは、以下のコードを見てください。

on init
	declare $X := 170
	declare $A 
end on

on note
	$A := .not. $X
	message($A)
end on

このプログラムを実行すると、ステータスラインには、-171と表示されます。なぜでしょうか?まず、2進数で一番左の桁というのは、1で負の値、0で正の値を意味します。つまり、170を2進数で表すと、一番左の桁は0なのです。この0は.not.で1になりますから、符号が-に変わるわけです。コンピュータ内では、正の値の最大値は一番左の桁が0で、残りの桁が全て1の数です。負の値の最小値は、一番左の桁が1で、残りの桁が全て0の数です(-1は、2進数にすると全ての桁が1になります)。そして、もう1つ、2の補数という概念を理解しないといけません。2の補数とは、ビット単位で全て反転させて、+1をした数です。この辺りの理屈を理解するには、「2の補数」でググッて調べてみてください。 では、次にいきましょう。

on init
	declare $X := 170
	declare $A 
end on

on note
	$A := sh_left($X,2)
	message($A)
end on

左シフトとは、ビット単位で、指定した単位だけ、桁を左にずらします。桁を1つずらせば、数は2倍、2つずらせば4倍、3つずらせば8倍となっていきます。このプログラムの場合は4倍になるので、680がステータスラインに表示されます。逆に右シフトの場合は、1/2、1/4、1/8となっていくわけです。今回は、2進数が理解できていないと、なかなか難しいと思いますので、興味のない方は、全く理解できなくても問題ありません。これでKSPの演算子については終わりです。

算術演算子

算術演算子とは、皆さんよくご存知の、+とか-とかのあれです。特に難しくないですよね。気を付けないといけないのが、乗算は*、除算は/で表します。というわけで、表にしましたので、今回はそれをさっと眺めていただいて終わりです。ちなみに、xとyは変数を表しています。

x + y 加算
x - y 減算
x * y 乗算
x / y 除算
x mod y xをyで割った余り
- x xの負の値

ブーリアン

ブーリアンオペレータとは、真理値を返す演算子のことです。はい。何を言っているかさっぱりわかりませんよね。真理値とは、真と偽、つまり、正しいか正しくないかってことです。演算子は普通は+とか-とかのことですね。真理値を返す演算子なので、>とか<になります。ようは、変数Xと変数Yがあった時に、この2つの変数は、同じか?とか、どっちが大きいか?とかを比較して、正しければ真、正しければ偽を返すってことです。では、KSPに用意されている以下の演算子を見ていきましょう。ちなみに、xとyとzは、変数を、aとbは、真理値を表しています。

x > y xはyより大きい
x < y xはyより小さい
x >= y xはyより大きいか等しい
x <= y xはyより小さいか等しい
x = y xとyは等しい
x # y xとyは等しくない
in_range(x,y,z) xは、yとzの間の値である
not a aが偽であった場合に真を返し、aが真であった場合に偽を返す
a and b aもbもどちらも真である
a or b aかbのどちらかが真である

これらの演算子は、以下のように、while文やif文で使います。

on init
	declare $X := 1
	declare $Y := 1
	declare $Z := 1
end on

on note
	if($X = $Y and $Y = $Z)
		message("X = Y = Z")
	end if
end on

この場合は、表の「a and b」を使っていますね。変数Xと変数Yが等しく、かつ、変数Yと変数Zも等しい場合に、ステータスラインに文字列が表示されます。

while文

では、最後のコントロールステートメント、while文の説明です。while文は、ある条件が満たされる間、ずっと指定されたプログラムを実行し続けます。実は、while文はけっこう危険です(笑)。何が危険かというと、条件が満たされる間、ずっと実行し続けるわけです。もし、プログラムのバグで、永久に条件が満たされ続けることになってしまうと……暴走します。というわけで、while文は気をつけて使ってください。while文は、以下のように記述します。
while(条件)
    {プログラム}
end while
もう、見慣れましたよね。では、早速、例を見ていきましょう。(あ、ちなみに、このプログラムを実行してはいけません。あとで説明します)

on init
	declare $Flag := 1
end on

on note
	while($Flag = 1)
		play_note($EVENT_NOTE,$EVENT_VELOCITY,0,$DURATION_QUARTER/2)
		wait($DURATION_QUARTER)
	end while
end on

play_noteというのは、()内で指定した条件を元に、ノートオンを生成します。余談ですが、この()内のそれぞれの値を引数(ひきすう)と言ったりします。play_noteを関数とか言ったりもします。まぁ、関数は、命令の事だと思ってもらっていいです。「ここで、この命令を実行してくれ」とKontaktに伝えるわけです。で、その命令に細かく指示を出すために、引数が必要になったりするわけですね。この関数と引数のセットは、予め使い方が決まっています(関数は他にもたくさんあるので、後日、少しずつ説明します)。

ちなみに、$EVENT_NOTEは、callbackを起動したイベントのノートナンバーです。$EVENT_VELOCITYは、callbackを起動したイベントのベロシティです。その次の0とは、再生するサンプルのオフセットのマイクロ秒単位の値です(オフセットを知らない人には、いつか説明しますので、理解できなくても読み飛ばしてください)。そして、$DURATION_QUARTERとは、現在のテンポの4分音符の長さです。それを2で割っているので、8分音符の長さを指定しています。

つまり、このプログラムは、ノートオンを実行すると、そのノートの再生を4分音符のタイミングで、8分音符のノートを再生し続けます。そう、永遠に……、永遠に……。あれ?そうです。おかしいですよね。while文はこういう危険性があるんです。一度ノートオンでトリガーしたら最後、このプログラムは止まりません。しかも、KSPで、こういうバグを自動的に検知することは出来ないんです。では、少しこのプログラムを修正しましょう。

on note
	while($NOTE_HELD = 1)
		play_note($EVENT_NOTE,$EVENT_VELOCITY,0,$DURATION_QUARTER/2)
		wait($DURATION_QUARTER)
	end while
end on

$NOTE_HELDというのは、要は鍵盤を押しっぱなしかどうか?という状態を保持している変数です。押しっぱなしであれば値が1で、そうでなければ0になります。これで、プログラムは暴走しなくなったわけです。

KSPでは、このwhile文と、if文、select文の3つがコントロールステートメント(俗に言う制御文というものです)として用意されています。ちょっと大変だったかもしれませんが、慣れるとすぐに体に染み込みますので、ご安心を:-)

select文

select文は、if文と似ていますが、ちょっと動作が違います。例えば、キースイッチをいくつか仕込んであるライブラリを作ったとします。そこで、それぞれのキースイッチを押された時に、何かしらの動作をさせたい、なんていう場合には、select文が便利です。select文は、以下のように記述します。
select(比較に使いたい変数)
    case (条件)
        {実行するプログラム}
    case (条件)
        {実行するプログラム}
    case (条件)
        {実行するプログラム}
end select
このように、select(変数)で、条件分岐に使いたい変数を指定します。 case (条件)で、その変数の値がいくつの時にプログラムを実行したいかを指定します。では、ノートナンバー64,65,66にそれぞれキースイッチが設定されていると仮定して、それぞれのキースイッチが押された時に、どのグループが指定されたのかを、文字列でステータスラインに表示するプログラムを書いてみましょう。ちなみにノートナンバー64とは、Eの音です。

on note
	select($EVENT_NOTE)
		case(64)
			message("Single")
		case(65)
			message("Mute")
		case(66)
			message("Picking Harmonics")
	end select
end on

実際には、キースイッチを押されたときの動作を指定したい場合に、ステータスラインに文字を表示するだけということはないと思います。(もっとカッコイイ動作を作りこみたいですよねw)でも、少しずつですが、KSPを使ったライブラリのイメージが出来そうな雰囲気になってきましたね!

if文

さてさて、今回から、次のステップですね:-) 今回はif文について学んでいきましょう。if文とは、プログラム内で「もし〜なら、このプログラムを実行してね」と、条件を指定して時と場合によって動作を指定するためのものです。
if(ここの条件を記述)
    {条件に合致した場合実行するプログラム}
end if
というように、if(条件)から始まりend ifで終わります。 では、以下のコードを見てください。

on init
	declare $Check
	$Check := 1
end on

on note
	if ($Check = 1)
		message($EVENT_NOTE)
	end if
end on

「if($Check = 1)」は、もし変数Checkの値が1なら、という意味です。init callbackで、変数Checkに値1を代入しているので、もちろん、この条件を満たしているわけです。あとはいつものようにステータスラインにノートナンバーを表示しているだけです。 では、次のコードを見てください。

on note
	if($EVENT_NOTE > 64)
		message("Note Number is " & $EVENT_NOTE)
	else
		message($EVENT_NOTE)
	end if
end on

新しく「else」というのが登場しています。elseというのは、if文の条件に合致しなかった場合に実行される動作を指定します。つまり、ノートナンバーが64より大きければ「Note Number is ノートナンバー」がステータスラインに表示され、ノートナンバーが64より大きくなかった場合には、ノートナンバーだけがステータスラインに表示されます。 他のプログラミング言語だと、もう少し複雑な制御をif文で出来るのですが、 Kontaktの場合はこれだけです。実際にKSPでプログラミングをする時には、if文はよく使いますので、がんばってしっかりと覚えてください。

文字列変数と文字列配列

文字列と聞くと、「なんじゃそりゃ?」って感じるかもしれませんが、要はテキストのことです。今まで勉強してきた人にとっては、文字列は簡単です。文字列変数を宣言する時には、「declare @String」とすればいいだけです。

on init
	declare @text
	@text := "Note Number"
end on

on note
	message(@text & $EVENT_NOTE)
end on

on release
	message(@text & $EVENT_NOTE)
end on

文字列変数textを宣言して、文字列"Note Number"を代入しています。あとは、ノート・オン時にノートナンバーをステータスラインに表示します。$EVENT_NOTEとは、組み込み変数の1つです。組み込み変数とは、予めKSPに定義された変数のことで、全て大文字になります。$EVENT_NOTEは、callbackを起動したイベントのノートナンバーが格納されます。 文字列配列は、「declare !text[2]」のように、配列のサイズを指定して宣言しなければなりません。以下のコードを見てください。

on init
	declare !text[2]
	!text[0] := "Note Number"
	!text[1] := "Release Note Number"
end on

on note
	message(!text[0] & $EVENT_NOTE)
end on

on release
	message(!text[1] & $EVENT_NOTE)
end on

前回の配列の記事を読んでいる人は、特に解説しなくても、何をやっているかわかると思います:-) これで、KSPに用意されている変数の機能(組み込み変数は除く)は、全て理解出来たことになります。お疲れ様でした!

配列

配列とは、変数をセットにして、番号をつけて並べたようなものです。例えば、変数を10個並べたint型のArrayという配列を宣言する時には、「declare %Array[10]」と記述します。これで、配列を使う事ができます。Kontaktの場合、宣言時に、配列のサイズ(この場合は10)も指定しなければなりません。そして、一度指定した配列のサイズは変更することが出来ません。 まずは、以下のコードを見てください。

on init
	declare %Array[10] := (...
		1,2,3,4,5,6,7,8,9)
end on

on note
	message(%Array[0])
end on

int型の配列%Arrayをサイズ10でして宣言し、配列の宣言と同時に、配列の値も代入しています。ノートオン時には、ステータスラインに配列の1番目の値を表示します。ここで「おや?」と思った人もいるのではないでしょうか。プログラミングでは日常的なことなのですが、配列の1番目は0から数えます。10番目の値を表示したい時には、「message(%Array[9])」となるわけです。 また、配列は以下のように、取り出して使うことも出来ます。

on init
	declare %Array[10] := (...
		0,1,2,3,4,	5,6,7,8,9)
	declare $Int
end on

on note
	$Int := %Array[9]
	message($Int)
end on

配列Arrayの10番目の値を、int型の変数Intに代入して、ステータスラインに表示します。ちなみに、2行目の「...」はプログラムを途中で改行した時に記述します。つまり、本来は「declare %Array[10] := (0,1,2,3,4, 5,6,7,8,9)」と1行で記述するところを、「...」を使って少し見やすく出来るわけです。 配列に値を代入したい時には、以下のように記述します。

on init
	declare %Array[10] := (...
		0,1,2,3,4,	5,6,7,8,9)
	declare $Int
end on

on note
	%Array[9] := 21
	message(%Array[9])
end on

「%Array[9] := 21」で、配列Arrayの10番目に21を代入して、ステータスラインに表示します。 これで、配列の基本的な使い方は理解できたと思います:-)

2011年9月1日木曜日

定数

定数とは、一度定義すると、その値を変えることは出来ない、特殊な変数です。宣言の仕方は、constを付けるだけです。例えば、Constantという定数を宣言するには「declare const $Constant」と記述すればいいわけですが、定数は宣言時に値を代入しないといけません。つまり、「declare const $Constant := 16」などのように記述しなければ使うことが出来ないわけです。ちなみに、KSPにおける定数はint型です。

例として以下のコードを見てください。


on init
	declare const $Constant
	$Constant := 16
end on


このコードは、エラーが出て解析に失敗します。何がいけないのかと言うと、定数の宣言とは別の行で、定数に値を代入しようとしているからです。定数は宣言と同時に値の代入を一行で記述する必要があります。つまり、以下のように記述しないといけません。


on init
	declare const $Constant := 16
end on


同じように、以下のコードもエラーが出ます。


on init
	declare const $Constant := 16
end on

on note
	$Constant := 32
end on


さて、では定数の存在意義とはどこにあるのでしょうか?

それは、プログラム内で、同じ意味で使われている数値の管理を容易にするためです。以下のコードを見てください。


on init
	declare polyphonic $a
end on

on note
	$a := 4
	message($a)
	wait(1000000)
	$a := $a + 4
	message($a)
	wait(1000000)
	$a := $a + 4
	message($a)
	wait(1000000)
	$a := $a + 4
	message($a)
	wait(1000000)
	$a := $a + 4
	message($a)
	wait(1000000)
	$a := $a + 4
	message($a)
	wait(1000000)
	$a := $a + 4
	message($a)
end on



このプログラムは、あまり良いプログラムではないのですが、説明のためにあえてこうしています。wait()とは、マイクロセカンド単位(1秒の100万分の1)で、プログラムの実行を一時停止します。つまり、ノートオン毎に、1秒ごとにポリフォニック変数aの値を+4して、ステータスラインに表示しているわけです。

さて、この+4の部分を+12にしたい場合は、どうしたらいいでしょうか?+4の部分を全て+12に書きなおさないといけません。このプログラムでは、書き直しによるミスは起きそうにもありませんが、複雑なプログラムになってくると、バグの温床になりそうなことは、容易に想像出来るのではないでしょうか?

では、以下のコードを見てください。


on init
	declare polyphonic $a
	declare const $Constant := 4
end on

on note
	$a := $Constant
	message($a)
	wait(1000000)
	$a := $a + $Constant
	message($a)
	wait(1000000)
	$a := $a + $Constant
	message($a)
	wait(1000000)
	$a := $a + $Constant
	message($a)
	wait(1000000)
	$a := $a + $Constant
	message($a)
	wait(1000000)
	$a := $a + $Constant
	message($a)
	wait(1000000)
	$a := $a + $Constant
	message($a)
end on


やっていることは、前のプログラムと同じですが、今回は定数を利用しています。もう、お気付きのこととは思いますが、これで、4の部分を12にしたい時に、たった1ヶ所の修正で済むことが見て取れます。定数とは、こういう具合に使うことで、便利になってくるわけです。

実は、このプログラムは、もっと効率的に書く余地が残されているのですが、それはまたの機会に説明しますので、楽しみにしていてください。

定数は、分かりやすい概念なので、簡単だったかもしれないですね:-)

2011年8月28日日曜日

ポリフォニック変数

ポリフォニック変数は、少し分かりにく変数ですが、先に仕組みを覚えてしまいましょう。早速ですが、以下のコードを見てください。


on init
	declare $Poly
	$Poly := 0
end on

on note
	$Poly := $Poly + 1
	message($Poly)
end on

on release
	$Poly := $Poly - 1
	message($Poly)
end on


init callbackで、int型の変数Polyを宣言して、0を代入しています。note callbackにて、変数Polyに+1を加算し、その値をKontaktのステータスライン(Kontaktのウィンドウの左下の部分)に表示します。release callbackでは、変数Polyから1を減算して、同じようにその値をKontaktのステータスラインに表示します。

動作としては、1つ鍵盤を押せば、ステータスラインに1が表示され、鍵盤を離すと、ステータスラインに0が表示されます。2つ同時に鍵盤を押せば2が表示され、3つ同時に鍵盤を押せば3が表示されます。つまり、変数Polyは、お互いのイベントの中で共有されて使われているわけです。

では、次に今回のテーマである、ポリフォニック変数を使ってみましょう。ポリフォニック変数は、変数の宣言時に、polyphonicと付け足すだけで使うことが出来ます。ポリフォニック変数Polyを宣言したい時には、declare polyphonic $Polyと記述します。

では、以下のコードを見てください。


on init
	declare polyphonic $Poly
	$Poly := 0
end on

on note
	$Poly := $Poly + 1
	message($Poly)
end on

on release
	$Poly := $Poly - 1
	message($Poly)
end on


先ほどのコードとほとんど同じですが、変数がポリフォニック変数になっています。この場合、鍵盤を同時に2つ押しても、ステータスラインには1が表示されます。3つ押しても4つ押しても同じです。

なぜでしょうか?

ポリフォニック変数とは、実際にはイベントごとに個別の変数が用意されるからです。

イベントごとに変数を用意したい時に、通常の変数で対処しようとすると、とても面倒なプログラムを書かないといけませんが、ポリフォニック変数を使うことで、簡単に記述することが出来ます。ただし、通常の変数と比較して、多くのメモリを使用することになるので、注意が必要とされています。

実際に、どちらのタイプの変数を使うかは、目的によって変わってきますが、「こういう変わった変数があるんだな」くらいに記憶に留めておけば、まずは大丈夫です。

では、次回も他のタイプの変数の勉強をしていきましょう:-)

2011年8月27日土曜日

変数

変数とは、既にプログラミングをやっている人には当たり前のものなのですが、未経験の人にとっては、(とても小さな)最初の難関です。

プログラムを書く際に、「ある値を一時的に保存して、別の箇所でその値を使いたい。だけど、その値は、時と場合によって変化する。」という事がとてもとてもよくあります。そこで、変数が登場します。変数とは、一時的に値を保存する箱のようなものです。変数を使う場合には、それぞれの箱を区別できるように、一意な名前を付けます。そして、どのようなタイプの値を保存するかによって、型を指定します。

Kontaktに用意されている変数の型のうち、もっとも基本になるのは、int型です。int型とは整数のことです。

また、Kontaktで変数を使用する場合には、init callbackで、変数を宣言しなければなりません。変数の宣言とは、「このプログラムでは、これらの変数を使用しますよ」と、型と名前を予め指定しておくことです。例えば、int型のInstrumentという名前の変数を宣言する場合は以下のように記述します。


on init
    declare $Instrument
end on


これで、int型のInstrumentという変数を使う準備が出来ました。

変数に値を代入するには、「$変数名 := 値」というように記述します。int型のInstrumentという変数に値1024を代入するには、「$Instrument := 1024」となるわけです。

では、以下のコートを見てください。



on init
    declare $Instrument
end on

on note
    $Instrument := 1024
    message("No." & $Instrument & "!")
end on


このプログラムでは、init callbackにて、int型のInstrumentという変数を宣言し、note callbackにて、変数Instrumentに1024を代入し、messageコマンドで、テキストと変数を表示します。

messageコマンドとは、変数やテキストをKontaktのステータスライン(Kontaktの画面の左下です)に表示します。messageコマンドは、message(ここにテキストか変数を記述する)というように使います。テキストの場合は、"Hello World!"のように、"でテキストを囲います。変数は"で囲わずにそのまま記述します。テキストと変数を組み合わせて表示したい場合には、&でテキストと変数を接続します。

ちなみにnote callbackとは、ノート・オン・メッセージを受信する度に実行されるコールバックです。つまり、このプログラムでは、接続されたMIDIキーボードなどを押すと、Kontaktのステータスラインに「No.1024!」と表示されるわけです。

ここまで理解できれば、変数の基本的な使い方は理解できたと言って良いと思います。次回は、他の変数の型についても学んでいきましょう。

2011年8月26日金曜日

コールバック

KSPでプログラムを書くときは、まずは、コールバックが基本になります。

コールバックとは、特定のタイミングで、あるイベントごとに実行されるプログラム のことです。「ノート・オン毎に実行されるプログラム」、「ノート・オフ毎に実行されるプログラム」、「CCやピッチベンドに反応して実行されるプログラム」などのように、それぞれ記述していくようになっています。

コールバックで最も基本になるのはinitコールバックです。これは、スクリプトの解析が正常に終了した時に実行されます。ライブラリの利用時には、ライブラリを読み込んだ時に、最初に実行されるプログラムの部分になります。initコールバックは、主に初期設定を行う部分になるので、最初に実行される必要があるわけです。


プログラム内では以下のように記述します。


on init
    {ここに実行させたいプログラムを記述します}
end on


on initで、ここからプログラムを記述することを明記し、end onで、プログラムが終了していることを明記しています。実際に記述するプログラムについては、次回以降説明するので、ここでは割愛します。まずは、「initコールバックは初期設定を記述する」とだけ覚えれば十分です。

他には、「ノート・オン・メッセージを受信する度に実行されるnote callback」、「ノート・オフ・メッセージを受信する度に実行されるrelease callback」、「コントロール・チェンジやピッチベンド、チャンネル・プレッシャーを受信する度に実行されるcontroller callback」、「ホストのトランスポートコマンドを受信した時や、予め設定しておいた経過時間毎に実行されるlistener callback」、「ポリフォニック・アフタータッチ・メッセージを受信した時に実行されるpolyphonic aftertouch callback」など、他にもいくつかあります。

とりあえず、「初期設定を行うinitコールバックと、イベント毎に実行されるコールバックが色々と用意されている」ことと、「イベント毎に実行させたいプログラムを、それぞれ記述していけばいい」ことを覚えれば、今回は十分だと思います。