NI KONTAKT CREATOR TOOLS - DTMプログラミング言語探訪

[DTMプログラミング言語探訪](https://qiita.com/aike@github/items/77b3eccc6861de09513a)

# Native Instruments KONTAKT CREATOR TOOLS

## 概要

Native Instrumentsのサンプラーソフト[KONTAKT](https://www.native-instruments.com/jp/products/komplete/samplers/kontakt-6/)にはCREATOR TOOLSという支援ツールが付属しています。CREATOR TOOLSはKONTAKTと接続してライブラリの構成やKSPの変数の値などを表示するデバッガ機能の他に、Lua言語のプログラムでKONTAKTライブラリのプロパティを参照・変更することができます。

## 用途

- KONTAKTライブラリの情報を表示
- KONTAKTライブラリの情報をテキストファイルに出力
- KONTAKTライブラリのプロパティを一括変更

CREATOR TOOLSは、他にもKONTAKTライブラリのGUIを作成することもできます。CREATOR TOOLSで作成したGUIは.nckp形式のパフォーマンスビューとしてResources/performance_viewフォルダに保存し、ライブラリのKSPからload_performance_view(ファイル名)として読み込みます。ただしWYSIWYGのGUIエディタではないので、使い勝手はさほど良くはありません。

## 言語仕様

- Lua言語
- KONTAKTライブラリAPI
- ファイルシステムAPI
- サウンド解析API

Lua言語なので現代的なプログラミング言語の機能はひととおり用意されています。
KONTAKTライブラリはinstrument構造体として表現されており mode = instrument.group.playbackMode のようライブラリのプロパティにアクセスできるようになっています。
Music Information Retrieval (MIR) というサウンド解析ライブラリが用意されています。これを利用すると大量のサンプルファイルを解析して音程の名前のファイル名にリネームするようなこともできます。

公式リファレンス　[CREATOR TOOLS MANUAL](https://www.native-instruments.com/jp/products/komplete/samplers/kontakt-6/downloads/)

## GUI仕様

GUIは作成できません。


## プログラム例

### ライブラリ中の全サンプルファイルとその割り当てを一覧表示

```lua:ShowSamples.lua
print(string.format("Instrument: \"%s\"", instrument.name))
for _, group in pairs(instrument.groups) do
  print(string.format("  Group: \"%s\"", group.name))
  for _, zone in pairs(group.zones) do
    local nopath = string.match(zone.file, "[^/\\]+$")
    print(string.format("    key=%3d -%3d  vel=%3d -%3d  %s",
      zone.keyRange.low, zone.keyRange.high,
      zone.velocityRange.low, zone.velocityRange.high,
      nopath))
  end
end
```

### ライブラリの全グループのボリュームを-3dBに変更

値を変更するには、あらかじめFile→Newからプロジェクトを作成・保存しておく必要があります。
変更される値はCREATOR TOOLS側のローカルコピーが対象なので、スクリプト実行後にCREATOR TOOLS画面の右上にある「↑」ボタンを押して接続先のKONTAKTライブラリ側にも変更を反映させる必要があります。
今回の例はKSPのchange_vol()のような演奏時にテンポラリに変更するものではなく、ボリュームノブを恒久的に変更するものです。

```lua:SetVolume.lua
local newVolume = -3

print(string.format("Instrument: \"%s\"", instrument.name))
for i, group in pairs(instrument.groups) do
    group.volume = newVolume
    print(string.format("  Set \"%s\" Group Volume to %d", group.name, newVolume))
end

print("Click up arrow button to apply new properties")
```


### ライブラリの全KSPスクリプトをファイルに出力

ファイル書き込みするには、あらかじめPreferenceからEnable Write and Execute Permissionsを有効にしておく必要があります。また構成が見られないようになっている商用ライブラリやパスワードが設定されているスクリプトの内容は参照できません。

```lua:ExportScripts.lua
local sep = package.config:sub(1, 1)
for i, script in pairs(instrument.scripts) do
    if script.sourceCode ~= "" then
        local filename = string.format("%s%s%d.nkp", scriptPath, sep, i + 1)
        local f = io.open(filename, "w+b")
        f:write(string.gsub(script.sourceCode, "\r\r", "\r"))
        f:close()
        print("wrote " .. filename)
    end
end
```

### 大量のwavファイルを音程の名前にリネーム

サウンド解析ライブラリMusic Information Retrieval (MIR)を使った例です。フォルダ内にある大量のサンプルファイルを解析して音程の名前のファイル名にリネームします。

```lua:RenameToDetectedPitch.lua
notename = {"C","C#","D","D#","E","F","F#","G","G#","A","A#","B"}

print(scriptPath)
pitchBatchData = mir.detectPitchBatch(scriptPath)
for filename, pitch in pairs(pitchBatchData) do
    notenumber = math.floor(pitch + 0.5)
    note = notename[notenumber % 12 + 1]
    octave = notenumber // 12 - 2
    ext = filesystem.extension(filename)
    nopath = filesystem.filename(filename)
    print("  " .. nopath .. " --> " .. note .. octave .. ext)
    os.rename(filename, scriptPath .. "/" .. note .. octave .. ext)
end
```

### 大量のwavファイルの音程と音量をチェック

これもMIRを使った例です。フォルダ内にある大量のサンプルファイルを解析して、音程が狂っていたり音量が他のサンプルと大きく異なるものを検出します。

```lua:sample_checker.lua
pitchThreshold    = 0.2  -- semitone
loudnessThreshold = 6.0  -- dB

print(scriptPath)
print("=== pitch check ===")
pitchBatchData = mir.detectPitchBatch(scriptPath)
for filename, pitch in pairs(pitchBatchData) do
    detune = pitch - math.floor(pitch)
    if (detune > 0.5) then
        detune = detune - 1.0
    end
    if (math.abs(detune) > pitchThreshold) then
        nopath = filesystem.filename(filename)
        print("  " .. nopath .. " " .. detune)
    end
end

print("=== loudness check ===")
loudnessBatchData = mir.detectLoudnessBatch(scriptPath)
cnt = 0
meanLoudness = 0
for filename, loudness in pairs(loudnessBatchData) do
    meanLoudness = meanLoudness + loudness
    cnt = cnt + 1
end
meanLoudness = meanLoudness / cnt
for filename, loudness in pairs(loudnessBatchData) do
    deviation = loudness - meanLoudness
    if (math.abs(deviation) > loudnessThreshold) then
        nopath = filesystem.filename(filename)
        print("  " .. nopath .. " " .. deviation)
    end
end
```


## 実行方法

あらかじめKONTAKTを起動しておく

CREATOR TOOLSを起動するとKONTAKTとは自動で接続する

NEW PROJECTボタンを押して一旦プロジェクトを保存する。
![ct1_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/ebbe1fc5-e254-7e8a-062f-e211b0bdab4b.png)

右下にあるLua Scriptタブを選択する。
![ct2_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/5294a06e-b5ee-2cda-1e73-0a9b591c6554.png)

Luaスクリプトファイルをタブの下にあるエリアにドラッグ＆ドロップする
![ct3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/bbfd691c-fa2c-162f-69be-58603cd5223b.png)

スクリプトが読み込まれるとファイル名が表示されます。
左端のボタンを押すと外部エディタを起動されてスクリプトが編集できます。
三角ボタンを押すするとスクリプトが実行されます。
![ct4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/cbb78b2f-751a-1348-a5e1-e9077e117569.png)

## 感想

サンプラーのライブラリを制作するときは、一括してパラメータを設定するような定型的な作業が多いので、そのあたりをLua言語で自動化できるのは助かります。Webなどのサーバ管理の世界ではInfrastructure as Code（IaC）のように手順をスクリプトで自動化する流れが数年前からあります。サンプリングライブラリの構築もスクリプトで自動化する時代が来たのかもしれません。

[DTMプログラミング言語探訪](https://qiita.com/aike@github/items/77b3eccc6861de09513a)