見出し画像

MATLABでVSTプラグイン開発 [初級編]~数分?で作れるVST~LMSで無相関プラグイン


電子書籍発売しました!(2023/01/22)
動画・音声リンク付き紹介記事はこちら。

Amazon Kindle 電子書籍「MATLAB で簡単オーディオ プラグイン開発」

スクリプトはどなたでも無料でダウンロードできます。



だいぶ前に

夏休みはVST! MATLABで楽々(?)VSTプラグイン開発

という記事を書き、おかげさまでこのnote中ぶっちぎりの一番人気(あっ、いや、HRTFの記事がトップに躍り出てました!(^-^; )なのですが、色々詰め込んだため3万字超えになってしまいました。

そのため、
「やはり簡単にはできそうにないな・・」
と思われてしまった方もいるのではないかと思い、今回は
「MATLABなら本当に簡単にVSTが作れる!」
を趣旨に書いてみたいと思います。


生成できるのは、Windowsでは VST2(64/32bit)、Macでは AUv2 です。
単体起動可能なスタンドアローン版も生成できます。(R2022aで、VST3も生成可能となりました)


R2023a で、AUv3 (macOS) の生成に対応したようです。
(現在 Mac 版を使用していないため未確認)

2023/03/16



開発環境

MATLAB 本体以外に必要な Toolbox は
 DSP System Toolbox
 Signal Processing Toolbox
 Audio Toolbox

です。

最初の2つは "Audio Toolbox" の動作に必要なので、"Audio Toolbox" が動く状態ならVSTプラグインが作れます。HomeライセンスでもOKです。


それとCコンパイラが必要です。

対応コンパイラ一覧

MinGWであれば、MATLABメニューの 「環境 -> アドオン」 からもインストールできます。


VST_simple1

まずは、音量を変えるだけのプラグインを作ってみましょう。

classdef VST_simple1 < audioPlugin
   properties
       inputGain = 1;
   end
   properties (Constant)
       PluginInterface = audioPluginInterface(audioPluginParameter('inputGain'));
   end
   methods
       function out = process(plugin,in)
           out = in * plugin.inputGain;
       end
   end 
end

これだけです!

あとは、

>> generateAudioPlugin VST_simple1

で、(もちろん規模によって変わりますが)1分程度でVSTプラグインが生成されます。(私が今作ってるのは、40分以上掛かります・・)

画像3


デバッグは audioTestBench を使います。

>> audioTestBench(VST_simple1) 
画像2

ファイルから読みたい場合は "Input" を "Audio File Reader"、オーディオI/F等にしたい場合は "Audio Device Reader" にしてから、横の歯車アイコンでさらに詳細を決定します。
"Output" も同様に、ファイルに書き込みたい場合は "Audio File Writer"、スピーカーやオーディオI/F等に出力したい場合は "Audio Device Writer" を選択します。音を出しながらファイル出力したい場合は "Both" です。


単に見た目を確認するだけであれば

>> parameterTuner(VST_simple1)


でも表示されます。

画像4


VST_simple2

さすがにこれだけだと何なので、次はゲインをdBに、スライダーをロータリーノブにしてみましょう。

classdef VST_simple2 < audioPlugin
   properties
       inputGaindB = 0;
   end
   properties (Constant)
       PluginInterface = audioPluginInterface( ...
           audioPluginParameter('inputGaindB', ...
           'DisplayName','Gain', 'Label','dB','Mapping',{'pow', 1/3, -80, 6}, ...
           'Layout',[1,1], 'Style','rotary'), ...
           audioPluginGridLayout);
   end
   methods
       function out = process(plugin,in)
           gain = 10^(plugin.inputGaindB/20);
           out = in * gain;
       end
   end 
end

ロータリーノブを表示するには、audioPluginGridLayout を使用して配置する必要があります。

画像3

また、DAWに読み込んだときにロータリースライダーを表示させるには、カスタムGUI対応のDAW(Reaper等)が必要です。


VST_simple3

少し長くなりますが、ピーク&ノッチフィルターも追加してみましょう。

classdef VST_simple3 < audioPlugin
   properties
       channelMode ='LR';
       PEQ_ON = false;
       inputGaindB = 0;
       PEQ
       centerFreq = 4000;  peakGain = 0;  Q = 1.6;
   end
   properties (Constant)
       PluginInterface = audioPluginInterface( ...
           audioPluginParameter('inputGaindB', ...
           'DisplayName','Input Gain', 'Label','dB','Mapping',{'pow', 1/3, -80, 6}), ...
           audioPluginParameter('channelMode', 'DisplayName','Process Channel', 'Mapping',{'enum','LR','L','R'}), ...
           audioPluginParameter('PEQ_ON', 'Mapping',{'enum','OFF','ON'}, 'DisplayName','PEQ'), ...
           audioPluginParameter('centerFreq','Mapping', {'log',20,20000}, 'DisplayName','Frequency'), ...
           audioPluginParameter('peakGain','Mapping', {'lin',-40,40}, 'DisplayName','Peak Gain'), ...
           audioPluginParameter('Q','Mapping', {'lin',0.2,20}, 'DisplayName','Q') ...
           );
   end

   methods
       function plugin = VST_simple3  % クラス名と同じ名前を使ってコンストラクタを定義する
           plugin.PEQ = multibandParametricEQ('NumEQBands',1, ...
               'Frequencies',plugin.centerFreq, 'PeakGains',plugin.peakGain, 'QualityFactors',plugin.Q);
       end
       function set.centerFreq(plugin,val)
           plugin.centerFreq = val;
           plugin.PEQ.Frequencies = val; %#ok
       end
       function set.peakGain(plugin,val)
           plugin.peakGain = val;
           plugin.PEQ.PeakGains = val; %#ok
       end
       function set.Q(plugin,val)
           plugin.Q = val;
           plugin.PEQ.QualityFactors = val; %#ok
       end
       function visualize(plugin)  % for audioTestBench's "Visualize Plugin"
           visualize(plugin.PEQ, 2048);
       end

       function out = process(plugin,in)
           gain = 10^(plugin.inputGaindB/20);
           % FrameSize = length(in);
           % for fi=1:FrameSize
           %     Lin = in(fi,1);  Rin = in(fi,2);
           %     out(fi,1) = Lin * gain;  out(fi,2) = Rin * gain;
           % end
           
           if plugin.PEQ_ON
               out = plugin.PEQ(in * gain);
               switch plugin.channelMode
                   case 'LR'
                       % do nothing
                   case 'L'
                       out(:,2) = in(:,2) * gain;
                   case 'R'
                       out(:,1) = in(:,1) * gain;
                   otherwise
                       % do nothing
               end
           else
               out = in * gain;
           end
       end
       function reset(plugin) % I/F のサンプルレートが変わったときに呼び出される
           plugin.PEQ.SampleRate = getSampleRate(plugin);
       end
   end
end
画像5

multibandParametricEQ() を使うと、パラメータを代入するだけで特性がリアルタイムに変わります。
その定義はコンストラクタ内で行います。
GUIを操作すると function set~ が呼び出されますので、ここでGUIの値をフィルターにセットします。

”Process Channel” で、フィルターを掛ける対象を、LR/L/Rから選択することができます。
plugin.PEQ(in * gain) はL/R両方に一遍に掛かるのですが、そこでサイズが決定されて片chだけに掛けるのには使えないため、一旦両chに掛けてから戻しています。処理量は増えるので、それが気になる場合は片ch用のフィルターを別に定義して使います。

また、multibandParametricEQ() は、function visualize(plugin) にこの一行を書いておくと、audioTestBench でのデバッグ時に周波数特性を表示させることができます。

画像7
画像6


これらは全てフレーム単位の処理でしたが、サンプル単位で処理したい場合は、コメントアウトしてあるforループの中で処理を行います。


VST_LMS

最後に、LMSフィルターを使ってステレオイメージを強調するプラグインを作ってみましょう。

classdef VST_LMS < audioPlugin
   properties
       inputGaindB = 0;
       LMS_ON = false;
       lms1, lms2
   end
   properties (Constant)
       PluginInterface = audioPluginInterface( ...
           audioPluginParameter('inputGaindB', ...
           'DisplayName','Input Gain', 'Label','dB','Mapping',{'pow', 1/3, -80, 6}), ...
       audioPluginParameter('LMS_ON', 'Mapping',{'enum','OFF','ON'}, 'DisplayName','Decorrelation') ...
           );
   end
   methods
       function plugin = VST_LMS  % クラス名と同じ名前を使ってコンストラクタを定義する
           plugin.lms1 = dsp.LMSFilter('StepSize',2^-12,'WeightsOutput','None');
           plugin.lms2 = dsp.LMSFilter('StepSize',2^-12,'WeightsOutput','None');
       end
       function out = process(plugin,in)
           gain = 10^(plugin.inputGaindB/20);
           Lin = in(:,1) * gain;  Rin = in(:,2) * gain;
           if plugin.LMS_ON
               [ylms1,elms1] = plugin.lms1(Rin,Lin);
               [ylms2,elms2] = plugin.lms2(Lin,Rin);
               M_in = (ylms1 + ylms2)/2;
               out = [M_in + elms1, M_in + elms2];
           else
               out = [Lin Rin];
           end
       end
   end
end
画像8

LMSフィルターとは、二つの入力に対し誤差が最小となるようなフィルター係数を求めながらフィルタリングを行うアダプティブフィルターです。LMS(Least Mean Square)自体はシステム同定のための演算手法の一つです。

古くから知られたアルゴリズムですが、LMSフィルターによりLRの相関(誤差最小)成分と無相関(残差)成分を分離し、相関成分をM、無相関成分をL/Rそれぞれに振ることにより、LRの分離を向上させます。
効果がある場合とかえって悪さをする場合もあります。モノラルでは効果がありません。

LMSを、わざわざMATLAB関数を使ってやる必要はないかもしれませんが、デバッグが不要というのは大きなメリットです。まあ、過去にも使ったことあるんでアレですが、本当に数分でできました。(u_u)


いかがでしたでしょうか?
他の言語ではかなり手間の掛かるVSTプラグイン開発が、極めて簡単に行えることが分かっていただけたのではないかと思います。

MATLABとアイデアさえあれば、即VSTプラグインが作れます。
欲しいプラグインは自分で作ってみませんか?(-_☆)



この記事が参加している募集

つくってみた

やってみた

この記事が気に入ったらサポートをしてみませんか?