見出し画像

System Object Plugin ~ Simulink にもそのまま読み込めるプラグインを作る

まえがき

前回の記事で、以下のように書きました。

最初から System object 兼用でソースコードを書く方法もありますが、少なくとも私にとってはこちらの方がやりやすいのでこの方法をとります。ただし、generateSimulinkAudioPlugin() は R2022b 以降です。それより前のバージョンをお使いの場合は、System Object Plugin として書く必要があります。

今回は試していませんが、Audio Plugins in MATLAB を参考に書き換えれば動くのではないかと思われます。確か、ほぼ function 名等を書き換える程度だったはず・・。(普通に VST も生成できます)

MATLAB でマルチチャネル対応 VST 開発


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

少なくとも上に書いた変更だけだと、パラメータの外部入力設定ができません!

したがってその場合は、パラメータをリアルタイムに変えながらのシミュレーションはできないことになります。

ラッパー経由
System Object Plugin


また、前回の記事中でも描いたように 「Simulink では boolean、リテラル文字ベクトルまたは非数値構造体の値をもつパラメーターを調整可能にすることができない」ためか Mode の選択肢が出ず、直接書く必要があります。

当然一文字でも間違えたら正常に動かないので、数値にした方がよいでしょう。

2023/1/18





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