【Kontakt音源】KSPスクリプトの勉強ノート【作りたい】


はじめまして。
本noteは、Native Instruments社Kontaktのプログラミング言語KSPの勉強ノートです。
モチベに繋がればいいな(主に逃げ道を塞ぐ意味で)という思いで公開するのが目的なので内容はテキトーです。テキトーに簡潔にどんどん更新していこうと思ってます。
更新がとまったら挫折したのだと笑ってください。

それでは、一緒にKSPを学びましょう♪

24年12月5日 Mitarasi ( https://x.com/kanimo_n )

↓↓ 少し遅れて目次表示 ↓↓





1-1

まず入れる

プログラムを書くためのソフト

VS Code用のKSP拡張

ノブを作るためのツール


DAW

https://www.image-line.com/



参考サイト・動画

・KSP実践スクリプト集 ( 著: aike )

・VS Codeの使い方

・ChatGPT

・リファレンスマニュアル(以下RMと言います)

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/welcome-to-ksp

・サンプラー部分のマニュアル

・コミュニティサイト VI-CONTROL

・aike氏のチュートリアル

Yaron Eshkar 氏のチュートリアル

チュートリアルリソース一覧 ↓


・Stephen O'Connell氏のチュートリアル


・David Hilowitz氏

・七味めんつゆ氏


・水月想二氏 実践KSP

https://reverie.sakura.ne.jp/ksp/index.html


・kk_sampling_lab氏 KSP groupのvolumeをコントロールする

https://note.com/kk_sampling_lab/n/n3475603464fe


・松本一策氏 ISSAKU★DTM

https://s-violine.com/index.php?QBlog&mode=category&catname=Kontakt%20Script


【KSP以外】
・「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典
https://wa3.i-3-i.info/index.html


1-2

まずやる

・これから作る音源のファイル作成、リソースフォルダの作成、スクリプトテキストとVS Codeの紐づけをする
参考:KONTAKT Tutorial: Create your own Sampling Library


on init ~ end on

・音源を立ち上げた時のモロモロ(どんなUIにするのか?機能を追加するか?)を決める
・この間にたくさんコードを書く

make_perfview

・on init内で書いたコードを実際に反映させるために書く
・なぜこれを書かないと反映されないのか。意味不明

set_ui_height(もしくはwidth)_px

・UIのサイズを決定する

declare

・declare = 宣言
・ノブを追加したい・ボタンを追加したい・その他数あるKontaktの機能を追加したい・もしくは自分が指定した変数を定義したい(?)などと、音源に何かしらのモノを追加する時にまずdeclareする・・・ってことで宜しいです?

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/variables#---integer-variable-

・RMでdeclareと検索すると色々な機能が出てくる

message( "" )

・何のためにあるのか今は不明。無でOKらしい

set_script_title( "" )

・Kontaktはスクリプトスロットが5つあってその表示名をここで決める


1-3

参考:Kontakt Builder KSP Scripting Course Tutorials - Lesson 2 (Our instrument, UI, persistence)


declare ui_slider $name ()

・スライダーを作る
・sliderをknobにすればノブができる・buttonにすればボタンができる
・KSP拡張のおかげで、VSCode内ではsliderと入力するだけですぐに作成することができる
・カッコ内は最小値と最大値。通常は0~100万と設定する

make_persistent

・スライダーノブを動かしても何かするとリセットされてしまうらしいのでこれをする (深く理解してない所はこんな感じのノリで行きます)


1-4

参考:KSP実践スクリプト集

ノブを作る

・ノブを作る

・ちょっと詰まったのですが、ノブの全体サイズは右のズームで変更できる

・ノブの角度に追従するようにバーの色を変える設定はここ「マスク」

テキトーに弄ってたらできた、理屈は理解できてませんw


ノブができた

・ノブができた

・png画像をリソースフォルダのpicturesに保存する
・png画像を入れた場所に同名の謎のテキストファイルを作成する(KSP実践スクリプト集 参考)

・RMに「NOTE: This .txt file must have one empty line at the end, and end of line (EOL) type should be Windows (CR/LF)!」とあり最後の一行を空白にしたほうが良い説がある

1-5

参考:Kontakt Builder KSP Scripting Course Tutorials - Lesson 2 (Our instrument, UI, persistence)


set_control_par () 未解決

・par = パラメータ str = 文字列
・1-3で宣言したスライダーに新たな何かを追加する(?)
・set_control_parは数値を、set_control_par_strは文字列を参照する時に使う(?)(?)(?)

動画だけではよく分からなかったが、ここはちゃんと理解しないと先に進めない気がするので、RMをもとに一旦別のスクリプトで理解を深めようと試みる ↓↓


declare ui_label $name ()

・パフォーマンスビューにラベルを追加する
・set_text ( declareした変数名, テキストの内容 ) でテキストを決められる

declare ui_label $Osake (2, 2)
set_text( $Osake, "Yakitori" )

これでYakitoriというラベルが作られた   

set_control_par_str () でテキスト追加

・set_textの他にset_control_par_strでもテキスト内容を決められる
set_control_par_str(<ui-id>, <control-parameter>, <value>)

(これ以降、括弧内を左から①, ②, ③と言います)

①は何を参照するか(?)正確な意味は分からなかったので放置。
get_ui_id ()で変数を参照できる

②は①にどんなパラメータを追加するのか。
ここで少し理解したがset_control_parもset_control_par_strもここで選択できるコントロールパラメータを①に追加するためのもの・・・ってことで良いか?(常に自信が持てないw)

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/control-parameters

今回はテキストを変更したいので $CONTROL_PAR_TEXT を使う

③は②のパラメータの値を決める。ここが文字列になる場合はset_control_par_strを使い、文字列以外になる場合はset_control_parを使う・・・ってことで宜しいのか・・・?

・上記に従って書いてみると、

declare ui_label $Osake (2, 2)
set_control_par_str( get_ui_id( $Osake ), $CONTROL_PAR_TEXT, "KaiHimo" )

これでKaiHimoというラベルが作られた!

・set_textとset_control_par_str・・・テキストを設定する方法がどうして2つあるのか、どちらを使うべきなのか、、、分からないが一旦放置。
(追記:何日か前の私へ、早速使い分ける例が出てきて分かったぞ→1-13



set_control_par_str () でノブを参照する

・1-5の動画へ戻る(動画時間12:37~)
今やろうとしてることを整理すると、1-3で作ったスライダーのUIを1-4で作ったノブにしたい

set_control_par_str(<ui-id>, <control-parameter>, <value>)

今回はリソースコンテナ内の画像を①に設定したい。だから②では$CONTROL_PAR_PICTURE というコントロールを選択する。③には画像名(文字列)が入るのでset_control_par_strを使う

・動画に従って作成すると、、、

make_perfview
declare ui_slider $amp_env_attack( 0, 1000000 )
make_persistent( $amp_env_attack )
set_control_par_str( get_ui_id( $amp_env_attack ), $CONTROL_PAR_PICTURE, "mitaknob" )

私が作ったノブがKontakt上に表示された!!

まだ初歩の初歩の初歩だと思いますが理屈が分かると楽しいです。楽しくなってきました (^^)/



1-6 ノブの配置


move_control_px( variable, x-position, y-position )

・variableの位置を設定できる


declare ui_panel $name

・複数のウィジェットを一つにまとめる


$CONTROL_PAR_PARENT_PANEL

・ui_panelにぶち込むためのコントロール
・set_control_par( get_ui_id($①), $CONTROL_PAR_PARENT_PANEL, get_ui_id( $③ ) )
①を③のパネルにぶち込む
・↑を各ノブに行うことで4つのノブを1つのパネルにまとめることができた


パネル内の各ノブの配置を決める

・動画参照(今ここ https://youtu.be/z7T2Z9-MZD8?feature=shared&t=1394 )
・私が何も考えずに作ったノブは64x64だったのでこれを基に位置を決める

つまりこうじゃ!

move_control_px( $amp_env_attack, 0, 0 )
move_control_px( $amp_env_decay, 68, 0 )
move_control_px( $amp_env_sustain, 136, 0 )
move_control_px( $amp_env_release, 204, 0 )

おお~★★



1-7

set_ui_color()

・背景色を設定する
・よく分からんが、「16進数 色」でググって出てきた番号を0とHの間に入れれば宜しい・・・?


$CONTROL_PAR_MOUSE_BEHAVIOUR

・BEHAVIOUR = 行動
・スライダーの移動方向と感度を決める
・set_control_par( get_ui_id( ), $CONTROL_PAR_MOUSE_BEHAVIOUR, -900 )
③をマイナスにすれば垂直方向に、プラスにすれば横方向に


declare const $<name>

・constant = 定数

・単一の整数値を格納するためのユーザー定義定数を宣言します
・名前が示すように、定数変数の値は読み取りのみ可能で、変更することはできません。
・定数の名前を大文字で書くことは非常に一般的であり、推奨されています。
・整数定数に格納できる有効な数値は、-2147483648 ... 2147483647の範囲です。

RMより(Google翻訳)

・あー定数ね、定数なら今俺の横で寝ているよ

定数とは:
「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典(リンク)

declare const $MOUSE_KANDO := -900
set_control_par( get_ui_id( $amp_env_attack ), $CONTROL_PAR_MOUSE_BEHAVIOUR, $MOUSE_KANDO )
set_control_par( get_ui_id( $amp_env_decay ), $CONTROL_PAR_MOUSE_BEHAVIOUR, $MOUSE_KANDO )
set_control_par( get_ui_id( $amp_env_sustain ), $CONTROL_PAR_MOUSE_BEHAVIOUR, $MOUSE_KANDO )
set_control_par( get_ui_id( $amp_env_release ), $CONTROL_PAR_MOUSE_BEHAVIOUR, $MOUSE_KANDO )

ところでプログラムの記述でこうやってローマ字日本語を使うのは控えたほうがいいのだろうか?


$CONTROL_PAR_DEFAULT_VALUE

・CTRL+クリックのデフォルト値を設定する
・対象がknobの場合は
set_knob_defval()を使う

対象がsliderの場合は
set_control_par(①,$CONTROL_PAR_DEFAULT_VALUE,③)と設定する


1-8 ラベルの設定

動画・現在地

https://www.youtube.com/watch?v=YLr7fGt0p_M&t=793s

一通りノブを配置するところまで来て、今それに表示名をつけてるところ

VS Code 変数名を一括で変更する

・変数名を選択して右クリックからシンボルの名前変更

変数はダブルクリックで選択できる・・・すごい


declare ui_label $name () その2

・1-5参照
・動画ではui_labelを挿入する場所について言及しています
https://youtu.be/YLr7fGt0p_M?feature=shared&t=1050

プログラムは上から下に向かって順番に処理が行われる

・ラベルの背景削除は、
hide_part($ , $HIDE_PART_BG)

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/user-interface-widgets.html#ui_label-101909

・ラベルの後ろのバーの長さを変える方法が分からなかった。放置


1-9

参考:Kontakt Builder KSP Scripting Course Tutorials - Lesson 4 (Callbacks, engine pars, display values)


on ui_control ~ end on

・UIウィジェットを操作した時に何をするのかを決める

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/callbacks#on-ui_controls

・on init ~ end on 間に置かないように

・on ui_control ( $対象のウィジェット )

set_engine_par()

・Kontakt内蔵のボリュームやADSR・エフェクトなど、Kontaktエンジンのパラメータを制御する

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/engine-parameter-commands.html#set_engine_par--

set_engine_par(<parameter>, <value>, <group>, <slot>, <generic>)

①は何のエンジンを対象とするか

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/engine-parameters

↑ ここの一覧にとてつもない量のエンジンパラメータ

②はパラメータに設定される値・・・となっているけど、大抵は紐づける対象の変数を参照するだろうからui_control()と同じで。

③④⑤がマニュアル見てもよく分からないので精神と時の部屋へ ↓↓

Kontakt Group Editor

・サンプルをどのグループに属するか、そのグループごとにまとめてエフェクトやらボリュームエンベロープやらを設定することができる

・初期値ではEdit All Groupがオンになっているため注意

・Kontaktのサンプラー側の操作は日本語マニュアルでしっかり理解しよう


・前項の③はやはりこのグループの番号のことだった。一番目のグループが0になる。その次が1。グループの外?にあるエンジンは-1にする
・④はそのままエフェクトスロットの番号だろう
・⑤は複雑そうなので一旦放置。今は-1だけで良さそう

というかエンジン右クリックでちゃんと教えてくれる!


1-10

ui_controlの中にset_text

・ui_controlはコントロールを動かしたときにどんな動作をさせるのか
・だからここにテキストを入れれば、ノブを動かした時にテキストが表示されるようになる(動画時間9:32あたり)
・仮にこうすると、ノブを動かしたときにahoと表示されるようになる

on ui_control( $amp_env_attack_slider )
 set_engine_par( $ENGINE_PAR_ATTACK, $amp_env_attack_slider, 0, 0, -1 )               
 set_text( $amp_env_attack_label, "aho" )
end on

get_engine_par

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/engine-parameter-commands.html#get_engine_par--

・特定のエンジン パラメータの値を返します。(翻訳語)
・set_engine_parは双方向、get_engine_parは一方通行・・・でいい?

get_engine_par_disp()

・特定のエンジン パラメータの表示値を文字列として返します。(翻訳語)
・何してるのか整理すると、、

on ui_control( $amp_env_attack_slider )
    set_engine_par( $ENGINE_PAR_ATTACK, $amp_env_attack_slider, 0, 0, -1 )     
 set_text( $amp_env_attack_label, get_engine_par_disp( $ENGINE_PAR_ATTACK, 0, 0, -1 ) & "ms" )
end on

①$amp_env_attack_sliderの値が変化した時にこうしてください宣言
②$amp_env_attack_sliderの値と"0,0,-1"の場所にあるアタックエンジンを同期させてくださいね(?)
③$amp_env_attack_sliderの値が変化した時に$amp_env_attack_labelで表示している数値を表示してくださいね。その表示には"0,0,-1"の場所にあるアタックエンジンの表示値を参照してくださいね。あとmsとつけてください(& "ms")
④よろしくお願いします(end on)

こんな感じか・・・!?

・ついでにRMの下にあったget_engine_par_disp_ext()を覚えようとコードを書いたらエラーが出て、、Kontakt 8専用のコードだったことが原因でした。Kontakt 8買うべきなのか・・・?


wait

・コードとコードの間をしばらくの間待機する・遅延を入れられる

これで思い出したけどロジクールのマウスがすごーく便利

ロジクールOptions+ Smart Actions


VS Code 選択範囲のみ置換

・Ctrl + H
・右の横棒の「選択範囲を検索」をクリック

すごく、便利、、


1-11 ID番号


参考:Kontakt Builder KSP Scripting Course Tutorials - Lesson 5 (CB ID, slider label, pccb, automation)

前項までで、ノブを操作した時にノブの値が表示されるようにはなった。しかし値が表示されっぱなしで元のラベルに戻らないのをどうにかしようってところです。

「if」がくるのかついに・・・
一つ一つ咀嚼して学んでいきましょう

% 整数配列

・array = 配列
・declare %<variable-name>[<num-of-elements>]
特定のインデックスに複数の 32 ビット符号付き整数値を格納するためのユーザー定義配列を宣言します。

んー分からぬ
・まず特定のインデックス(specific indices)とはvariable-nameの部分を指すのだろう
・32 ビット符号付き整数値は-2147483648 ... 2147483647までの整数のこと
・「複数の」ここが$ 変数との違いで重要なところだけどイメージがつかないぬ~

・こういう時はChat GPTの出番です!


・・・・あーね、マヤ分かっちゃった
GPT先生の言う通りに、$ と %のコードをそれぞれ比べて書いてみる

declare $my_var
$my_var := 10
set_script_title( $my_var )

これはスクリプトタイトルは10になる
対して、

declare %my_array[5]
%my_array[0] := 10
%my_array[1] := 15
%my_array[2] := 20
set_script_title( %my_array[1] )

これはスクリプトタイトルが15になる

配列の指定はこう省略できる

declare %my_array[5] := ( 10, 15, 20, 21, 22 )
set_script_title( %my_array[4] )

これはスクリプトタイトルが22になる(0から数える)

つまり、10も15も20も21も22もいちいち変数宣言してらんねえ!って時にこの配列を使う・・・ってことで合ってる?^^;

GPT先生のありがたい表

       変数        配列
データ数   
単一の値      複数の値
宣言方法   declare $var      declare %array[5]
アクセス方法 $var         %array[インデックス]
サイズ変更  不要        必須(固定サイズ)
初期化   := 値 で1つの     := (値, 値, ...)で
      値を設定可能     複数設定可能
          
主な用途 状態や単純な値の管理  複数データの一括管理

改行しまくりだからスマホだと表示崩れまくりかも

・RMではさらに10*8なんてやってるけど見なかったことにする

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/variables.html#---integer-array-


if ... else ... end if

・これをした時はこうしてください(if)
   それ以外はこうしてください(else)
   話は終わりです(end if)


$NI_CALLBACK_ID 未解決

・この変数はコールバックの ID 番号を返します。すべてのコールバックには一意の ID 番号があり、ユーザー関数内では同じままです。

なるほど分からん

GPTに従い、こういうスクリプト書いた

on init
 declare ui_label $aho (4,4)
end on
on note
 set_text($aho,"Callback ID: " & $NI_CALLBACK_ID & " (on note)")
end on

この状態で鍵盤を弾くと確かに数字が表示される。これがコールバック(on note?)のID番号なのだろう。しかし数字が3ずつどんどん増えていくのはなんだ?(一旦放置)

分かったかも。 on initのID番号が2・on noteのID番号が1で、だから3ずつ増えてるのか。
つまり、$NI_CALLBACK_IDはその時点で実行したすべてのコールバック(on initやon note)を足した数値を表示してくれる・・・そういうことだな!?

ワイでもちゃんと理解できるじゃん・・・これで気持ちよく眠れるな(現在土曜日AM2:00)

→昨日のワイよ・・・残念ながら間違ってるみたいだ・・・

on init コールバックには、ID番号は割り当てられません。言い換えると、$NI_CALLBACK_ID は on init の中では使用されないか、無効な値を返します。

GPTの解説だけどちょっと怪しい(注釈1-11)↓↓↓

そもそもID番号とは何か?

・変数や定数を宣言した時点でID番号というものが割り振られるらしい

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/user-interface-commands.html#get_ui_id--

UI ID は、スクリプトで宣言された最初の変数または定数から順番に割り当てられ、32768から始まります。

・こんなコードを書いてみると、

on init
  make_perfview
  message( "" )
  set_script_title( "title" )
 
  declare $aiueo  {32768}
  declare $kakiku {32769}
  declare $sasisu {32770}
 
  declare ui_label $Banana( 4, 4 )
  set_text( $Banana, get_ui_id( $sasisu ) )
end on

32770と表示される

一番最初にdeclareした$aiueoには32768が割り振られて、そこから数値が1ずつ増えて、さらにset_text( $Banana, get_ui_id( $Banana ) )とすると上から4番目に位置するため(?)32772と表示される

つまりID番号とは、こちら側が何か指定するものではなくコード内の位置や状況によって何某かが一意に決まるもの・・・でOK?

・そして$NI_CALLBACK_IDとは、

この変数はコールバックの ID 番号を返します。すべてのコールバックには一意の ID 番号があり、ユーザー関数内では同じままです。

とある通り・・・と。今ならこの文章も理解できるな
「ID番号を返します」はID番号を持ってきますって意味か?


<注釈1-11>

・GPT先生より
「on init コールバックには、ID番号は割り当てられません。」とあるが、

on init
 message("on init ID: " & $NI_CALLBACK_ID)
end on

Creator ToolsではこれでしっかりID番号が表示されるんだけどこれは違うのかな~・・・ここは放置で


$NI_CALLBACK_ID 再び

・$NI_CALLBACK_IDは何となく理解した
・それで動画のこのスクリプトは何なのよ?

 %knob_disp[0] := $NI_CALLBACK_ID
 のあとに
 if( %knob_disp[0] = $NI_CALLBACK_ID ) 
何で$NI_CALLBACK_IDが二つあるのよ?となるのですが・・・

何時間かの格闘の末完璧に理解したのでお任せください

on ui_controlの中身は今

%knob_disp[0] := $NI_CALLBACK_ID ①
set_engine_par( $ENGINE_PAR_RELEASE, $amp_env_release_slider, 0, 0, -1 )set_text( $amp_env_release_label, get_engine_par_disp( $ENGINE_PAR_RELEASE, 0, 0, -1 ) & "ms" )
wait( $wait_ui )
if( %knob_disp[0] = $NI_CALLBACK_ID ) ②
  set_text( $amp_env_release_label, "Release" )
end if

①②で$NI_CALLBACK_IDが2度も出てくる意味が分からなかったのですが、waitの前後にラベルとメッセージを作ってあげると一目瞭然です

左2つのラベルの中身→set_text( $, $NI_CALLBACK_ID )

①の地点と②の地点で2回ID番号が発行されていて、本来であれば①も②も同じID番号になるのだけど(検証済み)、②の発行のタイミングはwaitコマンドにより遅れて吐き出される。②は%knob_disp[0] イコール $NI_CALLBACK_IDであるから、遅れた②が①と同じ値になった時にset_textが発動する、ということでした。

こういう時間差を利用したある意味力業のようなやり方は、なんだかマイクラのレッドストーン回路みたいで面白い


Creator Tools & Microsoft PowerToys

上のGifの右側にメッセージログと青枠があるじゃろ?

・Creator ToolsはNI Kontaktについてくるデバッグ用?のツール。なんだかよく分かってないがKontaktと開くだけで何かしてくれる(メッセージを表示してくれる)ので検証に便利ですね

・青枠はウインドウを「常に前面に表示」することができるMicrosoft PowerToysの機能の一つです。便利


1-12 永続変数

参考:Kontakt Builder KSP Scripting Course Tutorials - Lesson 5 (CB ID, slider label, pccb, automation)

翻訳が上手くいってなくて分からぬ

doはDAWは分かるのだが、オートメーションの話をしていて何のことやら


復習する set_control_par

・上記・動画時間の冒頭ではこんなコードを挿入している

set_control_par_str( get_ui_id( $amp_env_attack_slider ), $CONTROL_PAR_LABEL, get_engine_par_disp( $ENGINE_PAR_ATTACK, 0, 0, -1 ) & "ms" )

もう一度復習すると、set_control_parは「指定された UI ウィジェットのさまざまなパラメータを変更します。」という意味だった。
①のUIウィジェットのパラメータ②を③という値にしてください
ということ

$CONTROL_PAR_LABEL

ウィジェット ラベルを設定または返しますset_knob_label()。 に似ていますが、このコントロール パラメータはノブだけに限定されず、 、 、 にも機能ui_sliderui_switchますui_xy
これは、ホスト自動化を使用するときにホストに公開される文字列でもあります。

OO, OO, and OO構文に弱いGoogle翻訳先生

・つまり上のコードだと、
$amp_env_attack_sliderのラベル(ホストに公開される文字列)を「get_engine_par_disp( $ENGINE_PAR_ATTACK, 0, 0, -1 ) & "ms"」という値にしてくださいね。
こういう意味になるのかな?

・ホストに公開される文字列とは、例えばFLだとこの左上に表示されてる文字列

Automationタブを開き左の欄からノブにドラッグするとアサインできる

まだ$CONTROL_PAR_LABELを設定してないDecayだとこういう表示になる ↓↓

プロジェクト名(flp)は気にしないでくれ(勝手に馴れ馴れしくすまない)

KontaktのUI上のラベルだけでなくスライダー内部(?)のラベルも変更しよう、ということなのだな



make_persistent() 2回目

・次に行く前に、make_persistentが出てきたので1-3でテキトーに流したところをちゃんと理解しようと試みる
・persistence = 持続性

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/variables.html#make_persistent--

・やはりマニュアルに書いてあることの正確な意味は理解できない。
ただし、この記述のあり/なしでどう変化するかを見てみると、

①この右上のsaveから保存した変数の値

②このプリセットで保存した変数の値

①②いずれもmake_persistentを記述したノブは数値がセーブされ、make_persistentを記述しなかったノブはインストゥルメントをロードすると必ず0に戻ってしまった(プリセットが保存されなかった)。

・GPT先生の解説によると

make_persistent を使用すると、指定した変数は永続変数となり、スナップショットやインストゥルメントの状態とともに値が保存されます。

なるほど

・以下はRMの文で、これも重要な気がするので片隅に覚えておく↓↓

"変数の状態は、init コールバックの最後に読み取られます。init コールバック内で保存された値を手動で読み込むには、read_persistent_var()保存された値を使用する前に挿入します。"


read_persistent_var() 未解決

(追記)動画で登場してないのと結果未解決なので注意

・make_persistentと必ずセットで使う
・RMのコード例:

on init
declare ui_label $label (1, 1)
declare ui_button $button
set_text($button, "$a := 10000")
declare $a
make_persistent($a)
{read_persistent_var($a)}
set_text($label, $a)
end on
on ui_control ($button)
$a := 10000
set_text($label, $a)
end on

{read_persistent_var($a)}のカッコの有り無しで比べてねというプリセット↑↑

make_persistentのみだと0に、read_persistent_varをつけると10000になる。
のみの場合はon init内の数値だけを、read_persistent_varだと全体の数値を
・・・ということでもないみたい。
例えばinit内に$a := 500と定義すると次回ロードでちゃんと500になる

・GPT先生によると、
read_persistent_varは「初期化時に条件分岐を加えてデフォルト値を設定可能」とある。でも最近ちょっとGPT先生は信用ならない説が出てきたので話半分に聞いておく

・対して、VI CONTROLのRead_persistent_varのQA

read_persistent_var() は、init コールバックで永続変数に格納されている値を使用する必要がある場合にのみ使用してください。make_persistent の前または後に配置するかどうかは必須ではありませんが、通常は後に配置するのが賢明です。そうでない場合は、ICB に配置する必要はまったくありません。また、永続変数の値に関連するすべての操作をその中で実行する場合、persistence_changed を使用すると、これを使用する必要がなくなります。

EvilDragon氏より

スクリプトでまだ「read_persistent_var」を使用していますか?

いいえ。現在、ほとんどすべての関数呼び出しは persistence_changed にあります。また、通常、read_persistent_var が必要だったものは UI の変更に関連しており、これは NKS および persistence_changed の使用とうまく結びついています (これはスナップショットが変更された場合にのみ実行されるため、ICB はメイン NKI を実際にロードするときに 1 回だけ実行されます)。

https://vi-control.net/community/threads/read_persistent_var-on-the-first-initialization.65509/

persistence_changed コールバックを使用している場合、read_persistent_var() はまったく必要ありません。これは、そのコールバックが存在する前の時代の名残です。

https://vi-control.net/community/threads/custom-ui-controls-and-persistence.153108/


なるほど分からん!(優先度は高くなさそうなので一旦放置で)
とりあえず今はmake_persistentで変数が永続になる、ということだけ覚えておきましょう


ChatGPT

中々理解に結びつかないのですがその前に、色々調べてるうちにGPTにもいろいろな種類のユーザーメイドGPT(GPTs)があり、KSP専用のものをいくつか試すと良いと思いました

https://chatgpt.com/g/g-WgVWpM0oz-kontakt-developer-with-ksp-and-lua  これが強い



on persistence_changed

・本命はコレ

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/callbacks#on-persistence_changed

このコールバックは、インストルメント内の永続変数が変更されるたびに呼び出されます。つまり、on initコールバックの後、および/またはスナップショットのロード時に常に実行されます。

RMより

「永続変数が変更されるたびに呼び出される」←ここだけが重要と気付くのに一日かかったぜ・・・(^ω^;;)

このon persistence_changedというのは何かを永続する/しないを決めるものではなく、make_persitentで永続化した変数が変更されるたびに、このon persistence_changed内が呼び出されるということ

・動画内ではこんなコードになっている

make_persistent( $amp_env_attack_slider ① )

on persistence_changed

    set_control_par_str( get_ui_id( $amp_env_attack_slider ), $CONTROL_PAR_LABEL, get_engine_par_disp( $ENGINE_PAR_ATTACK, 0, 0, -1 ) & "ms" ) ②

end on

まず①を永続化してくださいね、
そして永続変数①が変更された時(ロードや保存をする時)に②という動作をしてくださいね
ということだと思う

①はアタックノブ、②はアタックノブの(DAW側に送る?)数値ラベルをKontaktのアタックエンジンのラベル+msと表示してください

・②をやらないとどうなるかも分かった

左が設定なし右があり

これはスナップショットを保存して呼び出したあとのDAW側の数値の表示。設定なしだと確かに表示がおかしい。ただこの状態でもノブを動かせばon controlが発動してちゃんとmsまで表示されるようになるので、そこまで重要なのか?というのが今の疑問。make_persistentの有無に限らず内部のエンジンのパラーメータはスナップショットに保存されるっぽいしね。まぁ分からん放置

とにかく理解できて良かった!次!


$CONTROL_PAR_AUTOMATION_ID or NAME

・オートメーションを設定する!以上


set_snapshot_type()

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/general-commands.html#set_snapshot_type--

スナップショットの変更時にinit コールバックが実行されるか否かを決める
・どのタイプでも永続変数はスナップショットに保存されるので問題なさそう。正確にどんな違いがあるのかは分からなかったが、永続変数以外の変数がどうなるのかって話・・・だと思う

新しくノブを作ってみた↓↓

ADSRは永続変数、type_kenはただ追加しただけ

この状態で各ノブをテキトーに弄ってスナップショットを保存してみる。
set_snapshot_type(0)と(2)ではスナップショットを呼び出した時、type_kenノブが0に戻った。(1)と(3)は数値がキープされた

「init コールバックが実行されるか」RM・動画でもここが強調されているのでここを覚えておこう。「initコールバックを実行しない」とすることで音源の動作の軽量化にも繋がるのでしょうかね?


1-13 ループ

参考:Kontakt Builder KSP Scripting Course Tutorials - Lesson 6 (While loops, string arrays)

配列やループ(?)を駆使してコードをもっとスッキリさせようぜ(意訳)


while ~ end while

・while = その間
・条件を満たすまでwhileの中をループしてください

・ループの変数名は慣習的に「i」と名付けるのだそうです

・これと%配列を組み合わせることですごいことが起こる ↓↓

declare %slider_ID[4] ①
  %slider_ID[0] := get_ui_id( $amp_env_attack_slider )
  %slider_ID[1] := get_ui_id( $amp_env_decay_slider )
  %slider_ID[2] := get_ui_id( $amp_env_sustain_slider )
  %slider_ID[3] := get_ui_id( $amp_env_release_slider )
declare $i
$i := 0 ②
while( $i < 4 ) ③
  set_control_par_str( %slider_ID[$i], $CONTROL_PAR_PICTURE, "2412Mita" )
  inc ($i) ④
end while

①で%slider_IDの0~3の意味を決めます
ループの変数$iの数値は②です
$iが4未満になるまでループしてください③
while内の処理の最後に($i + 1)をしてください④

こんな感じでしょうか?
これはすごい!今までADSRすべて設定していた項目が1行にまとまってしまいました!

④のincはIncrementという意味だそうです

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/arithmetic-commands---operators

定数とwhileを組み合わせることでひとつにまとめることができる

プログラミングっぽくなってきました
プログラムの世界では番号を常に変数にすることができるんですね。数字と$変数が同じ扱いといえば良いのか・・・しっかり把握していきましょう

! (文字列配列)

・整数配列の文字版 (1-11参照)

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/variables#---string-array-


$CONTROL_PAR_TEXT

・動画でこんな言及が

動画時間19分

・つまりループ内ではset_textじゃなくset_control_par_strを使うということらしい
1-5でやったところが再び出て嬉しい。伏線回収できた


1-14

参考:Kontakt Builder KSP Scripting Course Tutorials - Lesson 7 (Looping, functions, dynamic controls)


$CONTROL_PAR_POS_X or Y

・text同様move_controlのset_control用のやつ
・どうやらmove_control(<variable>)ここがvariableの者はループできないってことらしい。IDにしなければならない。variableは変数、ループ内は配列だからってことなのか(?)


function

・function = 関数

・「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典 関数

https://wa3.i-3-i.info/word1905.html

プログラミングの用語はこのサイトが一番分かりやすいです。ITパスポートでもお世話になりました

・関数は呼び出される前に宣言する必要があります
RM ↓↓

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/user-defined-functions.html


$

舞台裏で数値を持っていますが――

動画の翻訳。$文字は数字なのだ・・・

get_ui_id / set_control_par / set_engine_par


・動画ではこうするのはダメだと言及が。

set_engine_par( %engine_parameters[$touched], %slider_ID[0], 0, 0, -1 )

なぜなら、
%slider_ID[0]はget_ui_id( $amp_env_attack_slider )であり、

set_control_par(<ui-id>, <control-parameter>, <value>) に対して、
set_engine_par(<parameter>, <value>, <group>, <slot>, <generic>) なためである。

get_ui_id( $amp_env_attack_slider )ではなく$amp_env_attack_sliderとしないといけない。

分かるのだけど、じゃあui-idとvalueの違いって何なのよ?を考えてみる

・動画ではこのような説明

これはUI IDなので追跡しているスライダーの値が必要です。
これはUI IDであり、UIを取得する必要があるたびに使用します。IDなので直接的には役に立ちません。

動画時間13:58 Google翻訳より

・RMより get_ui_id()

UI ウィジェットの UI ID 番号を取得します。
UI ID は、スクリプトで宣言された最初の変数または定数から順番に割り当てられ、32768から始まります。

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/user-interface-commands.html#get_ui_id--

1-11でやったところですね
つまり、
declare ui_sliderと宣言した時には一意のIDが割り当てられていて、
[declare ui_slider ①] {$attack_slider (0, 1000000)②}

[~①]の部分のID番号を参照するのが<ui-id>、{~②}の$と括弧内の数値を参照するのが<value>と、、、そんな理解でいいですか?

set_control_par
https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/user-interface-commands.html#set_control_par--

1-12で私はこう書いた

もう一度復習すると、set_control_parは「指定された UI ウィジェットのさまざまなパラメータを変更します。」という意味だった。
①のUIウィジェットのパラメータ②を③という値にしてください
ということ

今の頭で書くとこうなるのかな ↓

①の「一意で決まるID番号」のUIウィジェットのパラメータ②を③という値にしてください 

そして一意で決まるID番号を参照できるコマンドがget_ui_id()ということか

うーむ、少しずつ理解の外堀が埋まってきて楽しい
今の私が正しいところにいるのかは分からんw

set_engine_par
https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/engine-parameter-commands.html#set_engine_par--

set_engine_par(<parameter>, <value>, <group>, <slot>, <generic>)

①のKontaktエンジンパラメータを②という値にしてください
①の場所は③④⑤ですよ

こんな感じやろ(適当)
OK次行こう!


get_control_par( ui-ID, control-parameter )

・一意で決まるID番号①のUIウィジェットのコントロールパラメータ②を取得してください

・動画ではこうではなく↓
set_engine_par( %, %slider_ID[0], 0, 0, -1 )

こうしろと。↓
set_engine_par( %, get_control_par( %slider_ID[$0], $CONTROL_PAR_VALUE ), 0, 0, -1 )


get_control_par( get_ui_id( $amp_env_attack_slider ), $CONTROL_PAR_VALUE )

get_ui_id( $amp_env_attack_slider )で参照できるID番号のUIウィジェットのコントロールパラメータを参照してください

こんな感じか?
①の$CONTROL_PAR_VALUEというのはつまるところ、
$amp_env_attack_slider ( 0, 1000000 ) ←これの値ってワケか
ふむ・・・w(若干理解がふわついてきた)


配列は定数だけ

・前項で疑問に思ったこと
なぜget_control_par( get_ui_id( $amp_env_attack_slider ), $CONTROL_PAR_VALUE )なんて長いコードを書いたのか?

例えば新たに配列を作ってこうではダメなのか?

 declare %aho[]
  %aho[0] := $amp_env_attack_slider
set_engine_par( %engine_parameters[$touched], %aho[0], 0, 0, -1 )

→すぐに解決。RMによると

要素の数は定数値で定義する必要があり、この目的で変数を使用することはできません。

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/variables

ということらしい。Kontaktについてるエンジンの変数(?)を指定することはOKだけれど、ユーザーが決めた数値が変わる変数(?)を定義することはできない・・・ということかな
get_ui_IDはID番号(定数)を参照してるから良いってことでOK?


定数(const)・配列(%)・変数($)・文字(!)・whileを駆使して短縮しまくれ!

・動画ではとにかく変換して変換して・・・とにかくすんごい(小並感)
一つ一つやっていけば私もやってることの意味は分かるけど、参照場所があっちゃこっちゃなって目がガチャる
多分VS Codeの機能をもっと活用しながらやるといいんだと思う。調べるか~あとはとにかく慣れだろうか

1-15

参考:Kontakt Builder KSP Scripting Course Tutorials - Lesson 8 (IDs in loop, generic script)


配列をwhileにぶち込む

・これを↓

declare const $num_controls := 4
declare %slider_ID[$num_controls]
  %slider_ID[0] := get_ui_id( $amp_env_attack_slider )
  %slider_ID[1] := get_ui_id( $amp_env_decay_slider )
  %slider_ID[2] := get_ui_id( $amp_env_sustain_slider )
  %slider_ID[3] := get_ui_id( $amp_env_release_slider )

↓こうした

declare const $num_controls := 4
declare %slider_ID[$num_controls]
$i := 0
while( $i < $num_controls )
  %slider_ID[$i] := get_ui_id( $amp_env_attack_slider ) + $i
  inc ($i)
end while

すごい(涙)
この、一度定義した数字を骨の髄まで活用する感じ・・・これがプログラミンなのだね。芸術的だ・・・
そして・・・やってることがちゃんと理解できる・・・!嬉しい(涙)
しかしこれを「自分で書け」と言われた時にできるのか?(絶望)

1-111-14でやった通り、get_ui_id( $amp_env_attack_slider )というのはID番号なのだよね。ID番号はdeclareした順番で上から1ずつ増えていく。だからそのID番号に $i (0, 1, 2, 3)を順々に足していけば良いのだね


参考:Kontakt Builder KSP Scripting Course Tutorials - Lesson 9 (Help tags)

https://www.youtube.com/watch?v=ytqGpsTOWNg&list=PLlcfBjDN_ijt0W5B2q7JJyX94KlO3FQoi&index=9


$CONTROL_PAR_HELP

・Kontaktのinfoタブに文章を表示することができる
set_control_par_str( UIウィジェットID, $CONTROL_PAR_HELP, "文字" )


小休憩

 ここで動画が一区切りしました。アタックディケイサステインリリースの4つのノブを作り、そこに文字・値の表示やプリセットの保存が正常に動作するようにプログラムを書きました。
 ごく当たり前の機能ですが、それぞれが行っていることをコードに書き起こすと膨大な量になることが分かりました。Kontaktに限らずプロラグムソフトの裏では膨大な量のプログラミング言語による指示があり、それをCPUが血眼になって読み込んでいるということなんですね。また一つこの世の摂理を知りました。
 これ、市販の音源クラス並みに複雑なことをしたらどれほどコードが分厚くなるのだろう。今から楽しみで仕方がありません(震え)。
 
 チュートリアルを公開してくださったすべての技術者に感謝します。 
 重ねて、Ocean Swift / Faxi NaduのYaron Eshkar氏に感謝します。
                       24年12月19日 Mitarasi  


次の動画に行きましょう~!


2-1

参考:Kontakt Builder KSP Scripting Course Tutorials - Lesson 10 (Kontakt Lua API Intro and Setup)

Kontakt Lua API 未解決

・つまりKontaktのあらゆる操作を自動化するということか!?

・Lesson10ではVS CodeとKontaktの連携方法まで教えていただきました

・Kontakt8ではLua言語が使えるようです。Lua言語ってなんだ?

・3言語学ぶ必要がある・・・?(´;ω;`)


参考:Kontakt Builder KSP Scripting Course Tutorials - Lesson 11 (Debugging in Kontakt Overview)

Creator Tools と message("")

・Creator Toolsはデバッグに便利。常に開いておくべし
・Kontaktを開いている状態でCTを開くと自動で接続される。Monitor→Engineで接続されてるか確認できる

・Kontakt側でもデバッグ情報が一文表示される(スクリプト下のステータス)。このままだとこのメッセージは消えないので、message("")とコードを書く

watch_var

・Creator Toolsに変数の値を表示する

このコマンドはコールバック内でのみ使用できますon init
このコマンドは Kontakt のステータス バーには影響しません。イベントは Creator Tools にのみ表示されます

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/variables.html#watch_var--

messageの値版かな
・配列の値を表示する時はこっち→watch_array_idx()

CPU Profilling Mode

・CPUをプロファイリングできるモード
・Monitor → EngineからCPU Profilling ModeをON

エフェクトの上にCPUの何某かが表示される

VS Codeにデバッグ情報を表示

・Lesson10でVS Codeに何某かを設定した状態で、
上のツールバーから「ターミナル→タスクの実行→Kontakt7」と選択するとスタンドアロンのKontaktが開く。その状態でKontaktを操作すると、Creator Toolsに表示される内容がVS Codeに表示されるようになる。Creator Toolsを起動しなくてもデバッグできるので便利というわけですなぁ
KontaktをスタンドアロンではなくVSTiで開いてDAWの中で作業したいんだけど、その場合はどうすればいいんだろう。分からなかったので放置。

LuaAPIがKontakt8で何某かできる・・・という話を聞いて、Kontakt8にアプデするかすごく悩んでます。KSPでも8専用のものとかあったし・・・。NIのセールって来年の6月?とかですよねー・・・


2-2 ラジオボタン

KSP リソース

・Kontakt Builder KSP Scripting Course Tutorials - Lesson 12 (Learning And Resources)ではKSPの勉強方法を紹介されています

音源制作をどこで学べばよいのかを示してくれていますね
広大な大海原ですねー・・・↓↓

コミュニティだとDiscordが一番賑わっているのかな

参考:Kontakt Builder KSP Scripting Course Tutorials - Lesson 13 (Radio Buttons Example)


declare ui_switch

・スイッチを作る
・ui_buttonとほぼ同じ
 switchはオートメーション書ける、buttonは書けない
 switchはクリックした時にスイッチする
 buttonはクリックから指を離した時にスイッチする

・スイッチを押した時(白の状態の時)の値(?)は
 
オフの時は

1-15までの知識で、KSP実践スクリプト集(著: aike)が大分読めるようになっていたのでこれも見ながら理解を深めます。

 KSPのui_buttonとui_switchはほとんど同じように使用できるUIですが、スイッチの方が オートメーションに対応しているので、ボタン的な見た目のUIには通常スイッチを使います。 スイッチの画像を設定するには、画像のような6種類のイメージを縦につなげた画像(png)ファ イルを用意します。

KSP実践スクリプト集( https://booth.pm/ja/items/902910 )より   

日本語の解説だ・・・ちゃんとした文章の日本語だ・・・(涙)
スクリプト集ではこの文章に続いてスイッチの画像を作成する方法が書かれておりました。ありがたい

select ()

このステートメントはif、任意の数のブランチがあることを除いて、 ステートメントに似ています。キーワードの後の式select が評価され、個々のcaseブランチと照合されます。一致する最初のcaseブランチが実行されます。

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/control-statements.html#select---

・ifと似てるらしいがよく分からんねぇ
・例文を見ると、おそらく条件分岐する系のやつっぽい。一旦次 ↓↓

複数のスイッチを切り替え式にする(ラジオボタン)

・実践スクリプト集にもコード例の記述がありましたが、ここではLesson 13の内容に準拠することといたします。

・① functionにselectを入れてこんな感じにする


function set_label_text
  select( $switch_flag )
    case 0
      set_text( $label_1, "hello" )
    case 1
      set_text( $label_1, "world" )
    case 2
      set_text( $label_1, "Sayonara" )
  end select
end function

この$switch_flagが0・1・2と変わることでどのcaseを参照するのかが変わるってことなんですねぇ

② スイッチの変数をずっと1にする+スイッチを押した時にほかのスイッチを0にする+ついでにselectの$switch_flagを設定する


if( $switch_1 = 1 )
 $switch_flag := 0
 $switch_2 := 0
 $switch_3 := 0
else
 $switch_1 := 1
end if

【if スイッチが1の時、以下の値を0にしてください。
   else それ以外(スイッチが0の時つまりスイッチがオフの時)はスイッ
   チを1にしてください。】
ということですね。そして①と②を組み合わせることでラジオボタンの完成です!

「スイッチをオフにしないやり方はないか?」という壁にぶち当たった時に、「スイッチが0の時に1にする」←このコードを書く発想が俺にできるのかは謎ですがねぇ!(ヤケ)

③ ui_control内でcall functionして①と②を合体させる。一旦完成!

④ このままだとon initの時にスイッチがオフの状態になるので、$switch_1 := 1とon persistence_changed内でラベルを呼び出して完成☆

num_elements(<array-variable>)

スクリプト集ではこのコードが使われていたので調べます。

・配列内の要素の数を返します。
・declare %aaa [3]で
 num_elements(%aaa)とした時、num_elementsは3という数値になるということかな

実践スクリプト集は神

(Yaron Eshkar氏の動画ももちろん神)

ラジオボタンの流れで実践スクリプト集を眺めていて思いましたが、この書籍プリセットの用例だけでなくしっかり的を得た説明をしてくれます。
read_persistent_var1-12で長時間調べて結局分からなかった項目ですが、この書籍に解説が載っていてすぐに理解できました。KSPを学ぶ日本人にとって唯一の素晴らしい書籍です。


2-3 アニメーション

参考:Kontakt Builder KSP Scripting Course Tutorials - Lesson 14 (Animations and Listener Callback)

Kontakt内にアニメーションを作成しようの回

アニメーション.pngを作成する

・ノブの時と同じように連続した画像のpngファイルを作成する

・ここ(リソーソ内pictures)にanimation.pngを置いてください。これは基本的にフレームの連続ストリップです。
・アニメーションの作成方法とpngを圧縮する方法を知っておく必要があります。
・(pngファイルの容量について)非常に意識してください。

動画時間5分まで

・うーむ、連続した画像のpngについて調べる時か・・・ ↓↓


スプライトシート

・1-4で作成したように一枚の画像の中に複数の画像を並べたモノをスプライトシートと言うらしい

スラシ(と略してみる)を作成する時のルールみたいなものはあるんだろうか?それはKontaktのGUI製作と同じだろうか?

こんなコメントがありました↓↓

グリッドを作成する場合は、すべてのフレームをグリッド内に配置します。幅と高さは同じである必要はありませんが、一貫している必要があります。

https://www.reddit.com/r/godot/comments/s0gxhr/sprite_sheet_from_affinity_designer_help/?rdt=45902

・grokより↓↓

・スプライトシート自体を自動的に生成するには、専用のソフトウェアやツール(Aseprite、Piskel、Adobe Animate等)が必要です。これらのツールはスプライトシートを作成するための機能を提供しており、そこに私のデザインやアドバイスが活用されることが考えられます。
・スプライトシート内の画像の配置間隔は、使用するツールやゲームエンジン、そして具体的なプロジェクトの要件によって異なります。
一般的には、1〜2ピクセルの間隔が推奨されますが、最適な間隔はプロジェクトの具体的なニーズや使用するツールの特性に基づいて決めるべきです。実際のプロジェクトでは、プロトタイプを作成し、テストを重ねて最適な配置間隔を見つけることが多いです。

・ChatGPTでスラシを作る試み↓↓


・参考動画のようにデザインソフトで適当な模様を作ってそれをスプライトシートにする方法が知りたかったのだけど、ちょっと調べても分からなかったので一旦放置


GUIデザイン その1

2-2のKSPリソースのGUI Design ToolsにはGUI製作に関する様々なリンクが記されています。一通り触れましたが改めてこのg200kg氏のKnobManは他に代替がないすごいツールだなという感じでした。

リンク集の中にあるKnobGalleryでは、KnobManで作成したノブの数々を有志がパブリックドメインで公開しており、今も更新されています。

今回はLeslie Sanford氏製作のこちらのVU Meterをお借りして動画を進めて参ります。↓↓

こんなカッコいいVU Meterを作れてしまうとは・・・!凄いです


pngファイルと一緒に同梱する謎のtxtデータの詳細

RMの$CONTROL_PAR_PICTUREより翻訳して引用 ↓↓

  1. Has Alpha Channel Kontakt に、画像に透明 (アルファ) レイヤーが含まれているかどうかを通知します。不明な場合は、 を使用しますyes。

  2. Number of Animations 画像に含まれるフレームの数を設定します。これにより、Kontakt はフィルムストリップアニメーション (ノブ、スライダー、ボタンなど) を適切にレンダリングできるようになります。

  3. Horizontal Animation noフィルムストリップアニメーションの方向を指定します。ノブ、水平スライダー、ボタンの場合は垂直方向 ( ) を使用し、垂直スライダーの場合は水平方向 ( )を使用することをお勧めしますyes。

  4. Vertical Resizable Kontakt が制御パラメータを使用して画像の高さを調整できるようにします$CONTROL_PAR_HEIGHT。

  5. Horizontal Resizable Kontakt が制御パラメータを使用して画像の幅を調整できるようにします$CONTROL_PAR_WIDTH。

  6. Fixed Top/Bottom/Left/Right プロパティを使用すると、画像のサイズを変更するときに、画像の端の周囲の特定の領域をそのままにすることができます。これにより、丸みを帯びた端を持つサイズ変更可能なボタン、右側のドロップダウン矢印が常に固定されたサイズ変更可能なメニューなどが可能になります。

6はほぼ使わないらしいので気にせんとこう


set_listener() / on listener

時間系の何某か。スクリプトで設定した時間(?)やDAWの再生・停止に同期できるらしい


set_listener(<signal-type>, <parameter>)
・リスナー コールバックが反応するシグナルを設定します。

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/time-related-commands.html#set_listener--


on listener
リスナー コールバックは、set_listener()コマンドで定義された時間間隔で実行されます。また、ホストのトランスポート開始および停止コマンドに反応することもできます。
https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/callbacks#on-listener


つまり、set_listenerのsignal-typeがparameterの値の時にシグナルを出してね。(シグナルを受け取った時など)一定の条件の時にon listener内の動作をしてねってことかな

・この例を読み込んでみると分かりやすい↓↓

on init
    set_listener($NI_SIGNAL_TIMER_BEAT, 1) {1}
end on

on listener
    if ($NI_SIGNAL_TYPE = $NI_SIGNAL_TIMER_BEAT) {2}
        message($ENGINE_UPTIME) {3}
    end if
end on

DAWのテンポの1拍ごとに$ENGINE_UPTIMEがメッセージで表示される。

$ENGINE_UPTIME
・この変数は、Kontakt のインスタンス化から経過した時間をミリ秒単位 (マイクロ秒ではありません!) で返します。エンジンの稼働時間はサンプル レートから計算されるため、オフライン バウンスでも同期が維持されるため、音楽のコンテキスト (アルペジエーターやシーケンサーの構築など) で使用できます。

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/built-in-variables-and-constants#callbacks-and-ui

$NI_SIGNAL_TYPE
この変数はコールバックで使用され、on listenerどのシグナル タイプがコールバックをトリガーしたかを判別できます。

つまり上のコードだと、
{1}1拍ごとにシグナルを出します
{2}もし1拍ごとに出るシグナルを受け取ったら、
{3}エンジン稼働時間をメッセージに表示してください

こんな感じやろw


$NI_SIGNAL_TIMER_MS

・動画では set_listener( $NI_SIGNAL_TIMER_MS, 40000 ) とした。
だから「40秒ごとにシグナルを出してね」ということかと思ったらどうやら違う。↓

$NI_SIGNAL_TIMER_MS: マイクロ秒単位の時間間隔(最小値は1000で、1 ミリ秒に相当します)

https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/time-related-commands.html#set_listener--

マイクロ秒ぢゃん・・・・

40000㎲ = 40ms = 0.04s
1/0.04 = 25 で1秒間に25回のシグナルを出してね(25フレーム)ってことになるのか


アニメーションさせる

ちょっと動画を進めるとすぐにアニメーションを作ることができた

もうこの時点で大分テンション上がるんですけど・・・・

・動画ではこんなコード↓

on listener
    if( $on_switch = 1 ) ①
        if( $animation_vu = get_control_par( get_ui_id( $animation_vu ), $CONTROL_PAR_MAX_VALUE ) ) ②
            $animation_vu := 0
        else
            $animation_vu := $animation_vu + 1 ③
        end if
    end if
end on

$animation_vu = uiスライダーの意

①スイッチの値が1の時、下の動作をしてください
②スライダーの値がマックスの時、スライダー := 0にしてください
③それ以外の時はスライダーの値に1を足してください

そして、このコードはon listener内のコードなわけだから、最初に設定したset_listener内のシグナルを受け取るごとに①②③をしてください(0.04sごとに$animation_vu + 1をしてください)ということになるわけね!


動画はここで終わりだけども、スライダーがマックスになった時に0まで-1するプログラムを自分で考えてみるわ!




→・・・分からなかったので答え見る(´;ω;`)



行って、戻ってくるコード

・RMのon listenerに私がやりたいコードの例があるので見てみよう
https://www.native-instruments.com/ni-tech-manuals/ksp-manual/en/callbacks#on-listener

on init
    declare ui_knob $Test (0, 99, 1)
    declare $direction
    declare $tick_counter

    set_listener($NI_SIGNAL_TIMER_MS, 10000)
end on

on listener
    if ($NI_SIGNAL_TYPE = $NI_SIGNAL_TIMER_MS)
        if ($direction = 0)             {1}
            inc($tick_counter)
        else
            dec($tick_counter)           {2}
        end if

        $Test := $tick_counter           {3}

        if ($tick_counter = 99)          {4}
            $direction := 1
        end if

        if ($tick_counter = 0)           {5}
            $direction := 0
        end if
    end if
end on

まずもって初見じゃ何のこっちゃという感じ
$tick_counterの数を色んな数字にして、{3}のタイミングでその数字を$Testに代入するというのは分かった

tick = 印(t), direction = 指示・方向(d)
一つずつ見ていくと、

{1}
dが0の時、tを+1する
{2}
dが0以外の時、tを-1する
{3}
ここでスライダーの値をtにする
{4}
tが99の時、dを1にする
{5}
tが0の時、dを0にする

つまり、
dが0の時はt+1を10000μsごとにする、
dが1の時はt-1を10000μsごとする
そのdの0と1を切り替えるタイミングはtが0or 99の時ってことね!

dが切り替えスイッチになってるんだなーなるほどー
論理パズルみたいで面白いね。まだついていけてることに安堵するわ・・w

ちなみに変数をdeclareした時の初期値は0になるようである


・自分でも書いてみた

うおー!アニメーションができたー!


2-4 サンプル録音・編集 その1

ドラム録音してきた

明けましておめでとうございます(2025年1月7日)。

Ocean Swift / Faxi Nadu氏の次の動画(Lesson 15)はラウンドロビン。
自前のサンプルを使ったスクリプトを書くことが予想されるので録ってきました。ドラムの音!

PCとオーディオIFを持っていきマイクをお借りして、見よう見まねでマイクを立てて録音しました。

家に帰ってサンプルを聴いてみるとなんと素晴らしい音か!素晴らしい★★★
使用マイクはSENNHISER MD421です。この素晴らしい音がこのマイクによるものなのか、それとも他のマイクでもこんな音が録れるのか、たくさん検証したいことができてしまったのでまた今度作戦を立ててスタジオに行きましょう。


● 今回の振り返りを箇条書き

・一時間では全く足りなかった

・あとで録音データを編集しようとすると非常に大変なので、録音する前に録音データをどうするのか・ラベル付けをどうするのかをしっかり考えて臨んだほうがよい。そのために、楽器を演奏する人と録音操作をする人で二人は欲しい(そんな友達はいない

・今回はUR12の1OUTマイク一本で、スネアにマイクを立てて叩きマイクを移動してバスドラの前に置いてバスドラを録音して、、とやった。
うん、時間足りるわけないね。せめてOHとオンマイクは同時に録りたい。マルチアウトのAIFをレンタルできるスタジオがあるみたいだからそこに行こう。

・スネアは自前で持って行った方が良さそう。これから色んなスタジオで録音を試すと思う。その時に同じ音で比べることができるように自分のスネアを持っていこう。というわけで家の奥にあったスネアを引っ張り出して年末は掃除をしてました。

ヘッドやスナッピーも張り替えて新品同然になったど!
ただ一つ気になるのは、このスネアがステンレススティールの深胴でめっちゃ重いことwアルミのスネア買うかと本気で思ったが、このスネアの状態が良かったので、こいつと歩いていくと決めた。重い分良い音(このスネアにしかない音)が鳴ってくれると良いなと思ってる。

・スタジオにはハイピッチとミドルピッチのスネアがあり、叩いている時はハイピッチのほうが良い音かなと思ったが、録音データを聴くとミドルピッチがドンピシャに良い音だった。ドラムセットの前で叩く音と俯瞰して聴く音の差をしっかり聴きながらチューニングすべきだと思った。

・オンマイクのマイクを楽器に近づけて録る理由がなんとなく分かった。
あんなにマイクを近づけて録って音割れしないのか?とずっと思っていたんだ。しかしAIFに繋げて録るマイクの音というのは、音の小さい音から大きい音までのレンジが物凄く広かった。だからどんなに大きな音を出しても(人間がデカいと思うレベルの音では)音割れしないのだね。
そこで思うのは、スネアのアタックの音はしっかり録れてるのだがサスティンがその分小さすぎること。アタックの音がデカすぎて、サスティンの音が小さすぎる。このサスティンの音を編集で大きくするべきなのか?という疑問。とりあえず放置。

・マイクも一つ自前で持っておきたい。
今回の録音、意外にも良い音が録れてしまったので自分のマイクを持って色々試したい。今回使ったSENNHISER MD421。これが欲しい。サウンドハウスで今62,143円ですって。6万かぁ。。。


参考:Introduction & Planning Your FIRST Kontakt Instrument... KONTAKT: FIRST STEPS (Ch. 1 Ep. 1)

Kontakt音源を作るにあたって最初に考えることを示した動画。
15:18~の、1サンプルあたりの長さとレイヤー数から全体の収録時間の計画を立てる方法とても参考になります。本チャンのレコーディングスタジオで音を録る時は、こういった緻密なタイムキープも必要になるでしょう。


参考:Recording Acoustic Audio Samples for Your First Instrument... KONTAKT: FIRST STEPS (Ch. 1 Ep. 2)

レコーディングのファーストステップ

・信号に近づくほどクリアになります(3:40~)

・すべてのファイルを1つの大きなモノリスファイルと呼ばれるシンプルな録音にまとめて録音することをオススメします。→ノイズ処理をまとめて行えるため

・防音された雑音が少ない環境ではより感度の高いマイクを使うことができる

・マイクからワイヤレスデバイスを遠ざけてください・スマホやタブレットやPCを遠ざけてください・計画表などは物理の紙に印刷することをおすすめします・マイクが無線ノイズを拾う可能性があります(えー!)

・サンプリング周波数を何で録るのか?CDは44.1khz、ハイレゾ96kHz
96kHzの利点はオーディオサンプルを引き延ばした時の品質が高くなること。96kHzで録ればいつでもダウンサンプリングもできる。(ここはもう少し勉強したい)(多少の音質の違いで容量がデカくなるのは避けたいと考えるのだがどうだろうか)

・屋外の録音はヘッドホンを装着し雑音のレベルなど録り音を確認すること

・ノイズリダクションツールを使う

FLの話ですがEdisonの代わりにRXを呼び出すことができ記事。
他のDAWでも同様の連携が行えるようです。

・サンプルのワンショットを作る時のヒント:
「サンプルのトランジェントの開始前に少なくとも数ミリ秒の余裕を持たせるようにしてください。」
「後でフェードを追加し始める時に便利です」

・フェードインフェードアウトの設定
DAWと編集ソフトの操作を確認しましょう

・サンプルのチューニング
メロダインなどを使う

・命名規則しっかり・耳で聴かなくてもどんなファイルなのか分かるように
KontaktはC0から数え真ん中はC3
FL StudioではC5


ノーマライズについて

推奨する人もいれば推奨しない人もいる。ライブラリによって異なる。
ノーマライズして後からKontaktのベロシティで音量を変更するor
ノーマライズせずにサンプルのダイナミクスに任せる(私(Stephen氏)はこの方法が気に入っています。パフォーマンスの側面を維持したいのですべてを正規化したくありませんが、もう少し正確に音量を設定したい・一貫性を持ちたい時・あとで簡単に形を変えたい時は正規化を選択するかもしれません)

ドラム音源はどうしているのか確認してみると、NIとGGDはノーマライズを行っていない

GetGoodDrums Benny Greb Signature Pack

ISWのTSDKは弱の奏法でもノーマライズを行ってました

Impact Soundworks Tokyo Scoring Drum Kits

Kontakt側とサンプル編集ソフトどちらで音量を設定するかでも変わってきそうです。縦の編集もそうですが、横のプリデイレイをいくつ入れるのか(すべての楽器のアタックをどう揃えるのか)といったことも気になります。編集ソフトの操作をしっかり把握したいですね。

サンプルをどこで編集するか

①DAWの編集
②iZotope RXなどの編集ソフト
③Kontaktのサンプルエディター



慣れ親しんだDAWの操作が一番なのでできればここで編集したいところです。
FL Studioを使用していますが、自動スライス・個別サンプル化やノーマライズなどの最低限の編集はEdisonで行えます。ただし細かい数値を設定するところでEdisonスクリプトに頼らなければならなく、貧弱なので・・・どうするかといったところです。

参考動画ではロジックが使われていて、個別のサンプルを作るのに適しているようにも見えますし、動画内のフェードイン/アウトの処理はFLではEdisonで一瞬でできるのでFLのほうが勝ってる部分もあるように思います。
サンプル編集でどのDAWを使うのが良いのか、悩みどころですね。

めちゃくちゃ余談ですが昔、声優の浅木式さんが音声編集でFL Studioを使っていると見てテンションがぶち上がったことを思い出しました。



iZotope RX7を所持しているので活用したいところですが、RXはノイズ処理では最強ですがサンプルの長さやタイミングを細かく編集するソフトではないのでRXだけでは完結しなさそうです。オートスライス機能もないですね。


こちらのサイトで基本操作が解説されています。
KontaktのWaveEditor、ざっと触った感じは使いづらい。特に、サンプルエディターをダブルクリックするとサンプルエディターが閉じてしまうの何とかなりませんか?なんだこれ!
でも下のバーに日本語のヒントバーが出てくるのは素晴らしいです。
自動スライスとオートマッピングは使う場面があるかもしれません。

Editing samples in FL Studio

モノリスファイルから個々にリージョン分けしてノーマライズ
この工程がEdisonだと一瞬で行える

ただ前述のように細かい数値を指定した編集ができないため、それが必要になった時は別のソフトも要検討。今回はEdisonを使用した
まず波形が弱すぎるところのゲインを上げる

スクリプトのAmpでゲインを上げる

それから自動スライス

それからユーザースクリプトのFade and normalize regions

https://forum.image-line.com/viewtopic.php?t=311134

これを用いて、リージョン間のフェードイン/アウトを行う + リージョン内のノーマライズを行う

リージョンメニューから自動リネームを行う

最後、Export regionsからコモンを選び個別のサンプルの出来上がり

2-4で大分時間かかっちゃった
KSPに戻る


2-5

参考:Kontakt Builder KSP Scripting Course Tutorials - Lesson 15 (Round Robins)


いいなと思ったら応援しよう!