SOUND FORGE Pro Script - DTMプログラミング言語探訪

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

# SOUND FORGE Pro Script

## 概要

波形編集ソフトを使う作業は定型的な操作が多いため、多くのソフトは手順を自動化するためのバッチ機能を搭載しています。また、そのうちいくつかのソフトはテキスト言語でバッチ処理を書くスクリプト機能を持っています。
SOUND FORGE Proもバッチ処理とスクリプトの両方を持っているので機能や手順を説明します。[^1]
[^1]: Windows版のSOUND FORGE Pro 12で動作確認しました。最新版の15でも大きな変更はないと思います。Mac版がどこまでスクリプトに対応しているのかは未確認です。

## 用途

- 定型的手順の自動化
- 複数ファイルの一括処理

## バッチ処理

本題ではありませんが、スクリプトを使わないバッチ処理の手順も比較のために説明しておきます。

### バッチジョブ作成

「ツール」メニュー → バッチコンバータ を選択してバッチコンバータウィンドウを表示します。
![sf1_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/b7183a58-7b4e-2ef8-587f-557bbe895ac2.png)

「プロセス」タブを選択します。
「選択」ドロップダウンで適用するエフェクトを指定して「エフェクトの追加」ボタンを押します。
エフェクトのパラメータ設定画面が出るので、パラメータを調整します。
プリセット名（ここではmy_preset）を指定してFDアイコンを押して保存、OKボタンを押して閉じます。

![sf2_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/aaa044d5-2abb-2f25-2a90-3baa241acc63.png)

同様にいくつかエフェクトを追加したらバッチコンバータウィンドウのFDアイコンからバッチジョブを保存します。

### バッチジョブ実行

バッチコンバータウィンドウのフォルダーアイコンからバッチジョブファイルを開きます。
「変換するファイル」タブから対象ファイルまたは対象フォルダを追加します。
「保存」タブから保存オプションの「ファイルの保存先」を指定します。
「ジョブの実行」ボタンで実行します。
![sf3_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/539bb865-ab86-0ab3-1e07-c3eb2325a88e.png)


## 言語仕様

- C#/JScript/VBScript
- Sound Forge API
- .NET Framework

.NET Frameworkを使用しておりC#/JScript/VBScript言語で記述することができます。サンプルスクリプトはC#で書かれているのでそれに倣うのが良いと思います。
Sound Forge APIの完全な公式リファレンスはネット上にはありません。「ヘルプ」メニューの「目次と索引」から見ることができます。

C#.NETのAPIを呼ぶことができます。そのためディレクトリやファイルの操作やSystem.Windows.FormsのMessageBox.Show()を使ったメッセージダイアログ表示も可能です。

## プログラム例

### シンプルな例

開いているファイルにノーマライズと自動トリム（前後の空白を削除）をおこなうスクリプトです。
EntryPointクラスのFromSoundForge()メソッドに処理を書きます。
IScriptableApp::DoMenuAndWait()メソッドはアプリのメニュー項目を実行します。

これだけで簡単なバッチ処理を書けますが、各処理の細かいパラメータを指定できないのが問題です。
DoMenuAndWait()の第2引数をtrueにするとデフォルト値で処理されます。デフォルト値の詳細はドキュメントを見ても不明です。第2引数がfalseの場合はパラメータを設定するためのウィンドウが都度表示されるので好きな値を設定できますが、多くのファイルを一気に処理するような用途には向きません。

```NormalizeTrim.cs
using System;
using SoundForge;

public class EntryPoint
{
    public void FromSoundForge(IScriptableApp app)
    {
        app.SetStatusText("Script Start");
        app.DoMenuAndWait("Process.Normalize", true);
        app.DoMenuAndWait("Process.AutoTrimCrop", true);
        app.SetStatusText("Script End");
    }
}
```
また、DoMenuAndWait()の第1引数に与えるメニュー名の一覧がドキュメントにないことも問題です。SOUND FORGE Proは言語設定を簡単に変更することができず、日本語版を購入した人は英語メニュー名がわかりません。
[ネット上のドキュメント](http://soundforge.helpmax.net/en/batchengine-chmbatchengine-hhc/effects/acoustic-mirror/)から英語メニュー名を確認することでなんとか対応可能です。メニュー名が間違っていると実行時エラーになるのでエラーが出なければ正しいメニュー名です。
なお、ネット上のドキュメントにはスクリプトのAPIの説明はありません。


### 実用的な例

前項のパラメータ問題を解決し、複数のファイルにノーマライズと自動トリムをかけるスクリプトです。
入力ファイルのフォルダと出力先のフォルダをスクリプトに指定しています。対象フォルダにある.wavファイルをすべて処理します。

ISfFileHost::DoEffect()を使うことで好みのパラメータが設定されたプリセットを指定しています。ここではノーマライズ処理のプリセットとしてmy_normalize_preset、トリム処理のプリセットとしてmy_trim_presetを指定しています。

```NormalizeTrimBatch.cs
using System.IO;
using SoundForge;

public class EntryPoint
{
    public void FromSoundForge(IScriptableApp app)
    {
        string inPath = @"D:\work\samples\";
        string outPath = @"D:\work\processed\";
        string targetFile = "*.wav";

        DirectoryInfo dir = new DirectoryInfo(inPath);
        FileInfo[] files = dir.GetFiles(targetFile, SearchOption.TopDirectoryOnly);
        foreach (FileInfo file in files)
        {
            app.OutputText(inPath + file.Name);
            ISfFileHost inFile = app.OpenFile(inPath + file.Name, true, true);
            if (inFile == null)
                return;
            ISfFileHost outFile = app.NewFile(inFile.DataFormat, false);
            outFile.ReplaceAudio(new SfAudioSelection(0, 0), inFile, new SfAudioSelection(inFile));

            outFile.DoEffect("Normalize", "my_normalize_preset",
                new SfAudioSelection(outFile),
                EffectOptions.EffectOnly | EffectOptions.WaitForDoneOrCancel);
            outFile.DoEffect("Auto Trim/Crop", "my_trim_preset",
                new SfAudioSelection(outFile),
                EffectOptions.EffectOnly | EffectOptions.WaitForDoneOrCancel);

            outFile.SaveAs(outPath + file.Name, inFile.SaveFormat.Guid, "Default Template", RenderOptions.RenderOnly);
            outFile.WaitForDoneOrCancel();
            inFile.Close(CloseOptions.DiscardChanges);
            outFile.Close(CloseOptions.DiscardChanges);
        }
    }
}
```

プリセットの作成は、何か波形ファイルを読み込んだ状態で、たとえば「プロセス」メニュー → ノーマライズを選択し、パラメータを調整した後に上部のテキストボックスにプリセット名を入力しFDアイコンを押して保存することでおこないます。

![sf7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/7cacc083-d5e1-4c1a-dd44-ae181fcd5cab.png)



## スクリプトの使用方法

### スクリプト作成

「表示」メニュー → スクリプトエディタ でスクリプトエディタを表示させます。
エディタでスクリプトを入力します。
![sf4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/e46fe4ad-6d16-3a4f-67c5-c74b1ca4da0e.png)

### スクリプトエディタから実行

![sf5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/57be7ddb-d7e9-47dc-cc67-8963067746ff.png)

左端のフォルダアイコンはスクリプトの読み込み。サンプルスクリプトが用意されているので参考になります。
隣のFDアイコンは保存と別名保存。
中央はスクリプトテンプレートを読み込みます。最初はこれを使うと楽かもしれません。
右端の二つは実行とコンパイル。

### メニューから実行

スクリプトは特に変えなければ(インストールフォルダ)\SOUND FORGE\Script Menu\ に保存されます。
ここに保存したスクリプトは「ツール」メニュー → スクリプトの作成 から実行できるようになります。
![sf6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22455/8a7daec3-cd0c-7ecf-19d1-5960e5ba6162.png)

### コマンドラインから実行

以下のようにしてコマンドラインから実行することもできます。バージョンによってファイル名が異なるので注意してください。コマンドラインから引数を渡す仕組みも用意されています。

```
> "C:\Program Files\SOUND FORGE\ForgeXXX.exe" -SCRIPT:"C:\Program Files\SOUND FORGE\Script Menu\my_convert.cs"
```


## 感想

昔から定番波形編集ツールとして使われてきたSOUND FORGE Proですが、スクリプト機能はあまり使われていないのか情報が整理されていないのが今回調べて少し意外に感じました。

C#言語は良い言語ですが、IDEからクラス定義などをたどれないとつらい部分もあります。内蔵のスクリプトエディタは機能が貧弱なので、スクリプトの下書きをVisual Studioで書くことでシンタックスハイライトの恩恵を受けながら入力するというような裏技もあります。このときForgeXXX.Script.dllを参照に含めることでAPI定義も参照することができて少し快適になります。

iZotope RXの人気に押されて、最近は少し古く感じることもあるSOUND FORGE Proですが今も安定して使いやすく、今回調査した波形編集ソフトのスクリプトでは（ドキュメント不足を除くと）一番こなれている印象でした。

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