System Object Plugin ~ Simulink にもそのまま読み込めるプラグインを作る
まえがき
前回の記事で、以下のように書きました。
Audio Plugins in MATLAB を読んでもイマイチ、Basic Plugin と System Object Plugin の違いが、継承元が異なる以外分かりません。
さらに、「MATLAB環境におけるオブジェクト指向プログラミングをより高度に理解する必要があります」みたいなことが書かれています。
あまり近寄らない方が良いのかもしれませんが、Simulink に組み込めるようにするだけなら簡単なので、一応やり方を書いておきます。
Basic Plugin からの変更点
1.継承元の追加
audioPlugin → audioPlugin & matlab.System
2.function 名の変更と protected 化
process() → stepImpl()
reset() → resetImpl()
とし、methods (Access = protected) にします
3.private プロパティを分ける(オプション)
ユーザーが触る必要のないプロパティをプライベートにします
これは Basic の方でもやった方が良いので、ついでにやっておきます
これだけで、Simulink で直接読み込めるようになります。
スクリプト
classdef Ducking_sys < audioPlugin & matlab.System
% Copyright 2023
% AudiiSion Sound Lab. LLC.
% All rights reserved.
properties
inputGaindB = 0;
outputGaindB = 0;
LimitdB = -80;
kneeWidth = 5;
attackTime = 200;
releaseTime = 2000;
compRatio = 2;
Mode = 'Compressor';
end
properties (Access = private)
dRL; % limiter obj
dRC; % compressor obj
ModeC = {'Limiter','Compressor'};
ModeN = 0;
ModeN_old = 0;
end
properties (Constant)
PluginInterface = audioPluginInterface( ...
'PluginName','Ducking',...
'VendorName', 'AudiiSion Sound Lab.', ...
'VendorVersion', '0.0.1', ...
'UniqueId', 'hiro',...
audioPluginParameter('inputGaindB', ...
'DisplayName','Input Gain', 'Label','dB','Mapping',{'pow', 1/3, -80, 6}, ...
'Layout',[2,1;2,2], 'Style','rotary'), ...
audioPluginParameter('outputGaindB', ...
'DisplayName','Output Gain', 'Label','dB','Mapping',{'pow', 1/3, -80, 6}, ...
'Layout',[2,5;2,6], 'Style','rotary'), ...
audioPluginParameter('Mode','Mapping',{'enum', 'OFF','Limiter','Compressor'}, ...
'Layout',[1,4;1,6], 'DisplayNameLocation','none'), ...
audioPluginParameter('kneeWidth', ...
'DisplayName','KneeWidth', 'Label','dB', 'Mapping',{'pow', 1/3, 0, 12}, ...
'Layout',[4,3;4,4], 'Style','rotary'), ...
audioPluginParameter('LimitdB', ...
'DisplayName','Threshold', 'Label','dB','Mapping',{'pow', 1/3, -80, 6}, ...
'Layout',[4,5;4,6], 'Style','rotary'), ...
audioPluginParameter('compRatio', ...
'DisplayName','Comp Ratio', 'Mapping',{'lin', 0, 10}, ...
'Layout',[6,1;6,2], 'Style','rotary'), ...
audioPluginParameter('attackTime', ...
'DisplayName','Attack Time', 'Label','ms', 'Mapping',{'lin', 0, 1000}, ...
'Layout',[6,3;6,4], 'Style','rotary'), ...
audioPluginParameter('releaseTime', ...
'DisplayName','Release Time', 'Label','ms', 'Mapping',{'lin', 0, 5000}, ...
'Layout',[6,5;6,6], 'Style','rotary'), ...
audioPluginGridLayout('RowHeight', [40 70 15 70 15 70 15], ...
'ColumnWidth', [repmat([40 40],1,3)], 'Padding', [10 10 10 20]), ...
'InputChannels',4, 'OutputChannels',4, ...
'BackgroundColor',[1 1 1],'BackgroundImage','DLossy_bk3.jpg' ...
);
end
methods
function plugin = Ducking_sys % constructor
plugin@audioPlugin;
Fs = getSampleRate(plugin);
% limiter
plugin.dRL = limiter(plugin.LimitdB, SampleRate=Fs, EnableSidechain = true);
% compressor
plugin.dRC = compressor(plugin.LimitdB, SampleRate=Fs, EnableSidechain = true);
end
end
methods (Access = protected)
function out = stepImpl(plugin,in)
out = zeros(size(in,1),4);
inGain = 10^(plugin.inputGaindB/20);
outGain = 10^(plugin.outputGaindB/20);
% set ModeN in out of frame loop
% prevent Mode change within frame
switch plugin.Mode
case plugin.ModeC{1}
plugin.ModeN = 1;
case plugin.ModeC{2}
plugin.ModeN = 2;
otherwise % OFF
plugin.ModeN = 0;
end
input = in(:,1:2) * inGain;
plugin.dRL.KneeWidth = plugin.kneeWidth;
plugin.dRL.AttackTime = plugin.attackTime/1000;
plugin.dRL.ReleaseTime = plugin.releaseTime/1000;
plugin.dRL.Threshold = plugin.LimitdB;
plugin.dRC.KneeWidth = plugin.kneeWidth;
plugin.dRC.AttackTime = plugin.attackTime/1000;
plugin.dRC.ReleaseTime = plugin.releaseTime/1000;
plugin.dRC.Threshold = plugin.LimitdB;
plugin.dRC.Ratio = plugin.compRatio;
sideIn = in(:,3:4);
switch plugin.ModeN
case 1
outTmp = plugin.dRL(input,sideIn);
case 2
outTmp = plugin.dRC(input,sideIn);
otherwise
outTmp = in * inGain;
end
outTmp = outTmp * outGain;
out(:,3:4) = outTmp(1:size(in,1),1:2);
out(:,1:2) = outTmp(1:size(in,1),1:2);
out(:,1:2) = out(:,1:2) * outGain + sideIn;
end
function resetImpl(plugin)
plugin.dRL.SampleRate = getSampleRate(plugin);
plugin.dRC.SampleRate = getSampleRate(plugin);
reset(plugin.dRL);
reset(plugin.dRC);
end
end
end
Ducking_sys.m
こうしておけば generateSimulinkAudioPlugin() でラッパーを作らなくても Simulink の MATLAB System ブロックで直接読み込めますし、普通に VST プラグインも生成できます。
少なくとも今回のソースでは、生成されるプラグインのファイルサイズも変わらないようです。
前回のスクリプトと見比べてみてください。
あとがき
最初から全て System Object Plugin 形式で書いておけば良いのかもしれませんが、どこかに罠があるような気がして、とりあえず普段は Basic plugin 形式で書いています。(¬_¬)
Basic Plugin と System Object Plugin の違いについて、何か情報をお持ちであればぜひ教えてください。
「どこかに罠があるような気がして」
ありました。w
少なくとも上に書いた変更だけだと、パラメータの外部入力設定ができません!
したがってその場合は、パラメータをリアルタイムに変えながらのシミュレーションはできないことになります。
また、前回の記事中でも描いたように 「Simulink では boolean、リテラル文字ベクトルまたは非数値構造体の値をもつパラメーターを調整可能にすることができない」ためか Mode の選択肢が出ず、直接書く必要があります。
当然一文字でも間違えたら正常に動かないので、数値にした方がよいでしょう。
2023/1/18
この記事が気に入ったらサポートをしてみませんか?