「VSTe 何も音響処理をしない入力をそのまま出力する処理」の版間の差分

提供:yonewiki
294行目: 294行目:
</syntaxhighlight>
</syntaxhighlight>


:オーディオクラスのコンストラクタではsetControllerClass(ControllerUID);という処理を記述します。引数にコントロールクラスのFUIDを保持している変数を指定します。これでオーディオクラスとコントロールクラスとの関係が関連づけられます。必須の命令です。
:オーディオクラスの初期化関数の中ではまず最初に
::AudioEffect::initialize(context);
:で初期化をし、初期化に成功したら、addAudioInput関数とaddAudioOutput関数を実行します。
::addAudioInput(STR16("AudioInput"), SpeakerArr::kStereo);とaddAudioOutput()は同じ意味の引数をとります。
:第一引数はu"AudioInput"としているのと同じ意味です。
:第二引数にはSpeakerArr::kStereo(ステレオ)の他、SpeakerArr::kMono(モノラル)、SpeakerArr::k51(5.1ch)があります。
:第三引数は省略可能でkMainが規定値で、kAuxとすることもできます。(サイドチェイン入力を意味します。)
:第四引数も省略可能でBusInfo::kDefaultActiveのみ指定できます。
 
 

2023年5月2日 (火) 20:26時点における版

プラグイン VSTに戻る。

概要

 まずは、基礎として何もしないエフェクト処理を作ってみたいと思います。こつこつ手作業版のプロジェクトを仕上げていくイメージですが、最初の方は自動生成したVSTプロジェクトでは既にもう準備されている部分になるので、自動生成されたプロジェクトの構造とも見比べながらやってみたいと思います。


  • 1.自動生成されたプロジェクトでも読み込まれているdllmain.cppを取り込む作業をします。


  • ソリューションエクスプローラのプロジェクト名を右クリックして表示されるメニューから[追加]-[既存の項目]を選択するか[Shift]+[Alt]+[A]キーを押します。


  • VSTのSDKの中のC:¥SDK¥VST_SDK¥vst3sdk¥public.sdk¥source¥main¥dllmain.cppファイルを選択します。
 このファイルは変更を加えませんが、エントリポイント(プログラムが起動したときに最初に呼び出される関数)となる。
BOOL WINAPI DllMain (HINSTANCE hInst, DWORD dwReason, LPVOID /*lpvReserved*/)
 という関数を含んでいます。開始関数は自分で作るのではなく、配布されているSDKセットの関数を取り込むのが普通なようです。dllmain.cppとは長い付き合いになりそうですね。


  • 2.ヘッダファイルとソースファイルの組み合わせを追加します。
  • ソリューションエクスプローラのプロジェクト名を右クリックして表示されるメニューから[追加]-[新しい項目]を選択するか[Ctrl]+[Shift]+[A]キーを押します。


表示されるダイアログで、myvst.h と myvst.cpp としましょうか?好きなファイル名でいいです。自動生成版では4つのヘッダファイルと3つのソースファイルに分割して記述されていて、
  • $(Prefix)cids.h
  • $(Prefix)controller.h
  • $(Prefix)processor.h
  • version.h
  • $(Prefix)controller.cpp
  • $(Prefix)processor.cpp
  • $(Prefix)entry.cpp

に記述されます。コツコツ版ではmyvst.hとmyvst.cppというファイル名に集約することにしたいと思います。

  • 3.myvst.h に以下のようなコードを記述します。
#pragma once

#include "pluginterfaces\base\funknown.h"
#include "public.sdk/source/vst/vstaudioeffect.h"
#include "public.sdk/source/vst/vsteditcontroller.h"
#include "public.sdk/source/main/pluginfactory.h"

namespace Steinberg {
	namespace Vst {

#define MYVST_VENDOR   "VST Company"             // VSTを提供する組織名
#define MYVST_URL      "https://wiki.yo-net.jp/" // WebサイトのURL
#define MYVST_EMAIL    "mailto:xxxx@yo-net.jp"   // メールアドレス
#define MYVST_VSTNAME  "MyVST Name"              // VSTの名前
#define MYVST_VERSION  "0"                       // VSTのバージョン
#define MYVST_SUBCATEGORIES Vst::PlugType::kFx   // VSTのサブカテゴリ

		static const FUID ProcessorUID(0xA185FDD5, 0xDA405CBE, 0xB54639A5, 0x0DD136ED);
		static const FUID ControllerUID(0x68F6FA83, 0x229451BE, 0x98647D8E, 0x25C4A242);

		class MyVSTProcessor : public AudioEffect
		{
		public:
			MyVSTProcessor();

			tresult PLUGIN_API initialize(FUnknown* context) SMTG_OVERRIDE;

			tresult PLUGIN_API process(ProcessData& data) SMTG_OVERRIDE;

			static FUnknown* createInstance(void*) { return (IAudioProcessor*)new MyVSTProcessor(); }
		};

		class MyVSTController : public EditController
		{
		public:
			tresult PLUGIN_API initialize(FUnknown* context) SMTG_OVERRIDE;

			static FUnknown* createInstance(void*) { return (IEditController*)new MyVSTController(); }
		};
	}
}
static const FUID ProcessorUID(0xA185FDD5, 0xDA405CBE, 0xB54639A5, 0x0DD136ED);
static const FUID ControllerUID(0x68F6FA83, 0x229451BE, 0x98647D8E, 0x25C4A242);
上記の部分は独自のIDを生成する必要があります。人の真似をすると、そのVSTが使えなくなるといった迷惑がかかります。
生成するには、VisualStudioのメニューの[ツール]-[GUIDの作成]で起動されるツールを使って、[コピー]ボタンを押してIDを得ることが出来ます。
{5A927A38-9B1C-46B9-8563-23473D9C8C62}のような形式ですが、8桁ずつの区切りとして{5A927A38-9B1C46B9-85632347-3D9C8C62}のようなIDを得ます。これに4つの引数となるような0xを先頭に付与した(0x5A927A38, 0x9B1C46B9, 0x85632347, 0x3D9C8C62)のように置き換える手順で得られるのがFUIDです。
二つ目のIDを続けて得るには[新規GUID]ボタンを押します。そしてまた[コピー]ボタンです。1秒間に5000万回生成しても重複することはないとされています。
#define MYVST_VENDOR   "VST Company"             // VSTを提供する組織名
#define MYVST_URL      "https://wiki.yo-net.jp/" // WebサイトのURL
#define MYVST_EMAIL    "mailto:xxxx@yo-net.jp"   // メールアドレス
#define MYVST_VSTNAME  "MyVST Name"              // VSTの名前
#define MYVST_VERSION  "0"                       // VSTのバージョン
#define MYVST_SUBCATEGORIES Vst::PlugType::kFx   // VSTのサブカテゴリ
 この部分も独自の値を設定した方がよいでしょう。嘘をつくことになります。重複しても迷惑はあまりかからないでしょう。ただし、問い合わせの連絡がよそに行ってしまうという意味では、URLとEMAILは他人の物は使わないことは重要です。これはVSTホスト側でも取得できる値ですのでDAWによっては、この情報が閲覧できることになります。


以下の4つのヘッダファイルを読み込みます。
#include "pluginterfaces\base\funknown.h"
#include "public.sdk/source/vst/vstaudioeffect.h"
#include "public.sdk/source/vst/vsteditcontroller.h"
#include "public.sdk/source/main/pluginfactory.h"
MyVSTProcessor(AudioEffectを継承)とMyVSTController(EditControllerを継承)クラスを作ります。


ともにtresult PLUGIN_API initialize(FUnknown* context) SMTG_OVERRIDEという初期化関数を持たせます。


ともにstatic FUnknown* createInstance(void*)という関数を持たせます。オーディオクラスの戻り値は{ return (IAudioProcessor*)new MyVSTProcessor(); }として、制御クラスの戻り値は { return (IEditController*)new MyVSTController(); }とします。


オーディオクラスにはコンストラクタMyVSTProcessor::MyVSTProcessor()関数と、tresult PLUGIN_API process(ProcessData& data)関数を持たせます。


  • 4.myvst.cpp に以下のようなコードを記述します。
using namespace Steinberg;
using namespace Steinberg::Vst;

//------------------------------------------------------------------------
//  VST Plug-in Entry
//------------------------------------------------------------------------
// Windows: do not forget to include a .def file in your project to export
// GetPluginFactory function!
// Windows: エクスポートするプロジェクトに .def ファイルを含めることを忘れないでください。
// GetPluginFactory 関数!
//------------------------------------------------------------------------

BEGIN_FACTORY_DEF ("VST Company", 
			       "https://wiki.yo-net.jp", 
			       "mailto:xxxx@yo-net.jp")

	//---このファクトリーに含まれる最初のプラグイン-------
	// kVstAudioEffectClass コンポーネント
	DEF_CLASS2 (INLINE_UID_FROM_FUID(ProcessorUID), //FUID
				PClassInfo::kManyInstances,	// 同時に実行できる数
				kVstAudioEffectClass,	// コンポーネントカテゴリ (変更できない)
				MYVST_VSTNAME,		// プラグイン名 (独自設定に変更すべき)
				Vst::kDistributable,	// コンポーネントとコントローラーを異なるコンピューターに配布できることを意味します。
				MyVSTVSTCategory, // このプラグインのカテゴリ (独自設定に変更すべき)
				MYVST_VERSION,		// プラグインのバージョン (独自設定に変更すべき)
				kVstVersionString,		// VST3SDKのバージョン (変更しない、この定義をいつも使う)
				MyVSTProcessor::createInstance)	// 関数ポインタは、コンポーネントが実体化されるべきとき呼ばれるもの。

	// kVstComponentControllerClass コンポーネント
	DEF_CLASS2 (INLINE_UID_FROM_FUID (ControllerUID),//FUID
				PClassInfo::kManyInstances, // 同時に実行できる数
				kVstComponentControllerClass,// コントローラのクラス (変更できない)
				MYVST_VSTNAME "Controller",	// コントローラの名前 (VSTの名前にControllerを付け足したものにするべき)
				0,						// 使わない。
				"",						// 使わない
				MYVST_VERSION,		// プラグインのバージョン (独自設定に変更すべき)
				kVstVersionString,		// VST3SDKのバージョン (変更しない、この定義をいつも使う)
				MyVSTController::createInstance)// 関数ポインタは、コンポーネントが実体化されるべきとき呼ばれるもの。

	//----このファクトリに含まれるその他のプラグインの場合、最初のプラグインの場合と同様に、DEF_CLASS2 が異なります---

END_FACTORY

MyVSTProcessor::MyVSTProcessor()
{
	setControllerClass(ControllerUID);
}

tresult PLUGIN_API MyVSTProcessor::initialize(FUnknown* context)
{
	tresult result = AudioEffect::initialize(context);
	if (result == kResultTrue)
	{
		addAudioInput(STR16("AudioInput"), SpeakerArr::kStereo);
		addAudioOutput(STR16("AudioOutput"), SpeakerArr::kStereo);
	}
	return result;
}

tresult PLUGIN_API MyVSTProcessor::process(ProcessData& data)
{
	if (data.numInputs != 1 || data.numOutputs != 1)
	{
		return kResultTrue;
	}
	
	if (data.inputs[0].numChannels != 2 || data.outputs[0].numChannels != 2)
	{
		return kResultTrue;
	}

	Sample32* inL = data.inputs[0].channelBuffers32[0];
	Sample32* inR = data.inputs[0].channelBuffers32[1];
	Sample32* outL = data.outputs[0].channelBuffers32[0];
	Sample32* outR = data.outputs[0].channelBuffers32[1];

	for (int32 i = 0; i < data.numSamples; i++)
	{
		outL[i] = inL[i];
		outR[i] = inR[i];
	}

	return kResultTrue;
}

result PLUGIN_API MyVSTController::initialize(FUnknown* context)
{
	tresult result = EditController::initialize(context);

	return result;
}
  • 5.これで、一旦ビルドできます。何もしない空気のようなVSTeです。ちな、最近のバージョンから必要になっているsdk_common.libを入力ライブラリの追加で忘れていると
LNK2001 外部シンボル "public: static class Steinberg::FUID const Steinberg::IPlugView::iid" (?iid@IPlugView@Steinberg@@2VFUID@2@B) は未解決です MyVstProject C:\任意のディレクトリ\sdk.lib(vsteditcontroller.obj) 1

 というエラーが表示されます。FUIDの関数の中身がsdk_common.libの中に定義されているからだと思われます。sdk.libからsdk_common.libに移ったという感じでしょうか。


マクロを展開すると以下のような関数になります。
BEGIN_FACTORY_DEFマクロ部分は以下のようになります。
__declspec (dllexport) IPluginFactory* __stdcall GetPluginFactory () {
  if (!gPluginFactory) { 
    static PFactoryInfo factoryInfo (第1引数(ベンダー), 第二引数(URL), 第三引数(EMAIL), Vst::kDefaultFactoryFlags);
    gPluginFactory = new CPluginFactory (factoryInfo);


DEF_CLASS2マクロ部分は以下のようになります。
{ 
      TUID lcid = {
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong1 ()) & 0x000000FF) ),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong1 ()) & 0x0000FF00) >> 8),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong1 ()) & 0x00FF0000) >> 16),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong1 ()) & 0xFF000000) >> 24),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong2 ()) & 0x00FF0000) >> 16),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong2 ()) & 0xFF000000) >> 24),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong2 ()) & 0x000000FF) ),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong2 ()) & 0x0000FF00) >> 8),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong3 ()) & 0xFF000000) >> 24),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong3 ()) & 0x00FF0000) >> 16),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong3 ()) & 0x0000FF00) >> 8),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong3 ()) & 0x000000FF) ),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong4 ()) & 0xFF000000) >> 24),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong4 ()) & 0x00FF0000) >> 16),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong4 ()) & 0x0000FF00) >> 8),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ProcessorUID.getLong4 ()) & 0x000000FF) )
      };
      static PClassInfo2 componentClass (lcid,PClassInfo::kManyInstances,"Audio Module Class", VSTプラグイン名,Vst::kDistributable, サブカテゴリ, 0, VSTプラグインのバージョン, VSTSDKのバージョン); 
      gPluginFactory->registerClass (&componentClass,Steinberg::Vst::MyVSTProcessor::createInstance);
    }

    {
      TUID lcid = {
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong1 ()) & 0x000000FF) ),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong1 ()) & 0x0000FF00) >> 8),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong1 ()) & 0x00FF0000) >> 16),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong1 ()) & 0xFF000000) >> 24),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong2 ()) & 0x00FF0000) >> 16),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong2 ()) & 0xFF000000) >> 24),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong2 ()) & 0x000000FF) ),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong2 ()) & 0x0000FF00) >> 8),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong3 ()) & 0xFF000000) >> 24),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong3 ()) & 0x00FF0000) >> 16),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong3 ()) & 0x0000FF00) >> 8),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong3 ()) & 0x000000FF) ),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong4 ()) & 0xFF000000) >> 24),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong4 ()) & 0x00FF0000) >> 16),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong4 ()) & 0x0000FF00) >> 8),
        (::Steinberg::int8)(((::Steinberg::uint32)(Steinberg::Vst::ControllerUID.getLong4 ()) & 0x000000FF) ) 
      };
      static PClassInfo2 componentClass (lcid, PClassInfo::kManyInstances, "Component Controller Class", VSTプラグイン名 " Controller", 0, "", 0, VSTプラグインのバージョン, VSTSDKのバージョン);
      gPluginFactory->registerClass (&componentClass,Steinberg::Vst::MyVSTController::createInstance);
    }


END_FACTORYマクロ部分は以下のようになります。
  }
  else{ 
    gPluginFactory->addRef ();
  }
  return gPluginFactory;
}


オーディオクラスのコンストラクタではsetControllerClass(ControllerUID);という処理を記述します。引数にコントロールクラスのFUIDを保持している変数を指定します。これでオーディオクラスとコントロールクラスとの関係が関連づけられます。必須の命令です。


オーディオクラスの初期化関数の中ではまず最初に
AudioEffect::initialize(context);
で初期化をし、初期化に成功したら、addAudioInput関数とaddAudioOutput関数を実行します。
addAudioInput(STR16("AudioInput"), SpeakerArr::kStereo);とaddAudioOutput()は同じ意味の引数をとります。
第一引数はu"AudioInput"としているのと同じ意味です。
第二引数にはSpeakerArr::kStereo(ステレオ)の他、SpeakerArr::kMono(モノラル)、SpeakerArr::k51(5.1ch)があります。
第三引数は省略可能でkMainが規定値で、kAuxとすることもできます。(サイドチェイン入力を意味します。)
第四引数も省略可能でBusInfo::kDefaultActiveのみ指定できます。