MATLABでVST開発 ~ Map オブジェクト(文字ベクトル Key データ構造体)を使ってVSTパラメータをセットする(R2022a対応版)
まえがき
以前の記事
externalAudioPlugin class ~ MATLABで外部VSTプラグインをホスト ~ 動的変数名を使ってVSTパラメータをセットする
で、
と書きました。その後、"Prerelease Customer Survey" にその旨報告したところ MathWorks のサポートさんから連絡があり、何回かやりとりをして解決方法を教えてもらいました!
改めて問題点をおさらいすると・・、
各パラメータが、
パラメータファイル内では「変数名」
loadAudioPlugin() では「DisplayName」
と違っていて、「並び順」でしか突き合わせる方法がない、と思っていました。
R2022a ではそれの並び順がパラメータファイルだけ変更になったので突き合わせができなくなっていたのですが、MATLAB上でその対応テーブルを簡単に作成可能とのことです。
具体的には次のようにします。
解決策
"VSTtest_EQU.m" が VSTプラグインのMATLABソースファイルとします。
% Create a map of DisplayName from ParameterName using the plugin class
pm = VSTtest_EQU; % get properties from VST class file (VSTtest_EQU.m)
params = pm.PluginInterface.Parameters; % get GUI parameters as struct
fn = fieldnames(params); % get property names
m = containers.Map('KeyType','char','ValueType','char');
for k = 1:numel(fn)
m(fn{k}) = params.(fn{k}).DisplayName; % set PropertyNames as keys and set DisplayNames as values
end
これで "m" に、その対応マップが生成されます。
以下、もう少し詳しく説明します。
クラスのプロパティ構造体を取得
まず、class になっていれば、変数に代入するだけで全プロパティを取得できるようです。(知らなかった!)
そこから VST のインターフェース定義部分である PluginInterface の さらに .Parameters でパラメータ定義の構造体を取得します。この構造体は、audioPluginParameter() で定義した全てが含まれています。
次に、fieldnames() を使って、構造体のフィールド名を cell 配列に返します。(フィールドの値を取るには、struct2cell() を使います)
Map オブジェクト生成
containers.Map は、値を一意の Key にマップする Map オブジェクトを生成します。Map オブジェクトは、数値インデックスではなく、実数または文字ベクトルを Key として使用することのできるデータ構造体です。
m = containers.Map('KeyType','char','ValueType','char');
で空の Map オブジェクトを作成し、
m(fn{k}) = params.(fn{k}).DisplayName; % set DisplayNames as index
で、Key として変数名、Value として DisplayName をセットすることにより、変数名でアクセスできる変換テーブルを作成します。
もちろん他の方法で変換テーブルを作っても良いのですが、教えていただいたこの方法がスマートかと思います。
m('変数名') で DisplayName が返ってきます。
以前の記事の
displayName = matlab.lang.makeValidName(pInf.DisplayName);
setParameter(hostedPlugin,k,tog_comboVal);
N = sprintf("%s",displayName);
hostedPlugin.(N) = parasVal(k);
部分をそれぞれ、
displayName = matlab.lang.makeValidName(m(parasName(k)));
setParameter(hostedPlugin,m(parasName(k)),tog_comboVal);
hostedPlugin.(displayName) = parasVal(k);
と書き換えれば良いことになります。
2022/06/12 修正
2022/09/18 修正
コード例
clear
% read VST parameter file
fileID = fopen('VST_R2022a.para');
paraset = fread(fileID); % read as binary
fclose(fileID);
parasetStr = char(paraset'); % convert to 1 line string
paras = split(parasetStr,["<PARAM id=","value=", "/>"]); % split at "id", "value" and "/"
paras([1 end],:) = []; % delete other than "id" and "value"
paras = paras(strlength(paras) > 0); % delete blank lines
paras = erase(paras,'"'); % delete "
paras = strtrim(paras); % delete unnecessary spaces
parasTable = cell2table(reshape(paras,2,[])); % convert to table
parasTable.Properties.VariableNames = table2cell(parasTable(1,:)); % set properties name
parasNameT = table2cell(parasTable(1,:)); % take properties
parasName = string(parasNameT); % convert to strings
parasVal = str2double(parasTable{2,:}); % take values
% Create a map of DisplayName from ParameterName using the plugin class
pm = VSTtest_EQU; % get properties
params = pm.PluginInterface.Parameters; % get GUI parameters as struct
fn = fieldnames(params); % get property names
m = containers.Map('KeyType','char','ValueType','char');
for k = 1:numel(fn)
m(fn{k}) = params.(fn{k}).DisplayName; % set PropertyNames as keys and set DisplayNames as values
end
% VST hosting
hostedPlugin = loadAudioPlugin('VSTtest_EQU.dll');
parameterTuner(hostedPlugin)
for k = 1:numel(fn)
[pvalN, pInf] = getParameter(hostedPlugin,k);
displayName = matlab.lang.makeValidName(m(parasName(k)));
tog_comboFlag = isnan(str2double(pInf.DisplayValue));
if tog_comboFlag
tog_comboVal = parasVal(k) / (str2double(pInf.Label)-1); % normarize
setParameter(hostedPlugin,m(parasName(k)),tog_comboVal);
else
hostedPlugin.(displayName) = parasVal(k);
end
end
サポートさん、数ヶ月に渡り何度もやりとりをして対応策を検討していただき、大変感謝です!
これでやっと、R2022a に完全移行できる!(-_☆)