VST3ホスト開発03 – 音声処理クラスの作成と初期化

音声処理クラスの作成と初期化

前回はVST3プラグインの情報を表示する簡単なVST3ホストの作成について記載いたしました。
今回はVST3プラグインから音声処理クラスを取得するプログラムの説明を実施します。

今回作成するプラグインは下記のとおりです。

  • VST3プラグインを読み込む
  • VST3プラグインから音声処理クラスを作成する(new)

実際に音声処理を行うまではもう少し手順がありますが、まずは音声処理クラスを作成するところまで実施いたします。

このVST3プラグインのサンプルソースファイルはこちらからダウンロードできます→vst3host_20210410
ZIPファイルの中の「vst3host02_音声処理クラスの作成と初期化」フォルダが今回のサンプルソースファイルになります。

なお、Visual Studioのプロジェクトは「コンソールアプリケーション」で作成しております。
プロジェクト設定などは「Visual Studioのプロジェクト設定」もご参照ください。

今回の説明内容

本ページでは、前回説明したVST3プラグインの利用の流れ(下記)のうち、3.についての内容を説明します。
なお、前回説明した内容については、説明を省略させていただきます。

  1. VST3プラグインのファイル(.vst3ファイル)をホストアプリケーションに組み込む(読み込む)
  2. VST3プラグインのファイル内にある音声処理クラスとパラメーター操作クラスの一覧を取得
  3. 音声処理クラスとパラメーター操作クラスの一覧から必要なクラスのインスタンスを作成
  4. 作成した音声処理クラスとパラメーター操作クラスのインスタンスを初期化

VST3ホストのソースコード

まず、ソースコードは下記となります。今回説明する点については、ハイライトしております。説明は後述します。

【main.cpp】

必要なヘッダファイルと定義

今回は新たにヘッダファイル「plugprovider.h」と「hostclasses.h」を読み込んでいます。
ヘッダファイル「plugprovider.h」にはファクトリークラスから音声処理クラスなどのインスタンスを取得するためのPlugProviderクラス(後述)の定義が記載されています。
また、ヘッダファイル「hostclasses.h」はPlugProviderクラス(後述)の内部で使用される、HostApplicationクラスの定義が記述されています。

なお、「plugprovider.h」を利用するためにはVisual StudioのプロジェクトにPlugProviderクラスのソースファイル(下記)を追加する必要があります。

  • C:\VST_SDK\VST3_SDK\public.sdk\source\vst\hosting\plugprovider.cpp

次に、読み込んだVST3プラグインを使用するため、プラグイン関連のヘッダファイルを読み込みます。
それぞれのヘッダファイルは下記のようになります。

ヘッダ 用途
funknown.h VST SDKの多くのクラスの継承元となるFUnknownクラスの定義されたヘッダファイル(とりあえず読み込んでおく)
ftypes.h VST SDKで使われている基本的な型(int32やchar16など)が定義されたヘッダファイル
vsttypes.h VST SDKの音声処理クラスやパラメータ操作クラスで使われている型(Sample32やParamIDなど)が定義されたヘッダファイル
ivstaudioprocessor.h 音声処理クラスの継承元となるIComponentクラスやIAudioProcessorクラス、その他 構造体などが定義されたヘッダファイル
(IComponentクラス自体はivstcomponent.hで定義されており、ivstaudioprocessor.hで読み込まれている)
ivsteditcontroller.h パラメータ操作クラスの継承元となるIEditControllerクラスやその他 構造体などが定義されたヘッダファイル

他のヘッダファイルについては前回の内容をご確認ください

PluginContextの作成・セットアップ

最初にPlugProviderクラス(後述)の内部で使用されるHostApplicationクラスを準備・セットアップします。

HostApplicationクラスはホストアプリの名称やインターフェイス対応状況をVST3プラグインに知らせたり、VST3プラグインのallocateMessage()の際にIMessageを作成して渡したりするために必要となります。
VST3プラグイン側からは、これらの情報はPluginContextと呼ばれます。

PluginContextの作成・セットアップでは、下記の通りHostApplicationクラスを定義して、PluginContextFactory::setPluginContext()で設定しています。

【main.cpp】

HostApplicationクラスの詳細については割愛いたしますが、上記の設定だけすれば機能的な部分では問題はほとんどありません。
気になるのであればVST SDKの下記ファイルをご確認いただければと思います。

  • public.sdk/source/vst/hosting/hostclasses.cpp
  • public.sdk/source/vst/hosting/pluginterfacesupport.cpp

なお、HostApplicationクラスのgetName()関数の実装が悪く、ホストアプリの名称が「My VST3 HostApplication」とハードコーディングされています。
ホスト名を変えたければ、HostApplicationクラスをもとにして似たクラスを作成する必要があります。

音声処理クラスの取得

メイン関数では、前回と同様に、まずVST3プラグインのファイル読み込みとファクトリークラス(PluginFactoryクラス)の取得の完了を実施します。
(VST3プラグインファイルの読み込みとファクトリークラスの取得についての説明は前回の内容をご確認ください。)

その後、取得したPluginFactoryクラスでVST3プラグインファイル内にある音声処理クラス情報のみを変数audioClassInfoに取得しています。
これは「VST3プラグインファイル内に音声処理クラス(エフェクターやシンセサイザー)は複数存在してもよい」という仕様があるためで、いったん「どんな音声処理クラスがあるか」を配列等に列挙・取得しておき、後から「どの音声処理クラス(エフェクターやシンセサイザー)を読み込むか」を選ぶためです。

ちなみに、VST3プラグインファイル内に複数の音声処理クラスがあるサンプルとして、VST SDK付属のagainサンプルがあります。
againサンプルはVST3プラグインファイル内に「AGain VST3」と「AGain SideChain VST3」の2つの音声処理クラス(エフェクター)があります。

【main.cpp】

なお、VST3プラグインファイル内に音声処理クラス情報が1つも場合、音声処理できないので終了します。

【main.cpp】

プラグインプロバイダクラスの作成

音声処理クラス情報の列挙と取得が終われば、ファクトリークラスと音声処理クラスの情報(audioClassInfo[0])をもとにプラグインプロバイダクラス(PlugProviderクラス)を作成します。
PlugProviderクラスは名前の通り、音声処理クラスやパラメータ操作クラスを準備(作成と初期化)して利用できるように提供してくれるクラスです。

PlugProviderクラスを作成する際はmake_sharedを使用して作成します。コンストラクタに渡す引数などは下記になります。
PlugProviderクラスの他の主なメンバー関数については、順番に紹介・説明いたしますのでここでは省略します。

  • PlugProviderコンストラクタ
  • 概要 PlugProviderクラスのコンストラクタ。このコンストラクタ内で音声処理クラスやパラメータ操作クラスの作成や初期化が行われる。
    引数 変数名 概要
    PluginFactory& factory 音声処理クラス情報を列挙した際に使用したファクトリークラスへの参照です。
    ClassInfo info 作成・初期化する音声処理クラスの情報です。
    (この音声処理クラスに関連付けられたパラメータ操作クラスの作成や初期化も行われます。)
    bool plugIsGlobal ホストコンテキストであるgStandardPluginContext(今回説明は省略)を使用するかどうかのフラグです。
    PlugProviderクラスの実装を見る限りでは基本的にtrue以外の選択肢はありませんので、trueを指定します。
    なお、省略可能で省略するとtrueとなります。

今回のサンプルでは、とりあえず最初に見つかった音声処理クラスをもとにPlugProviderクラスを作成しています。
(先ほど音声処理クラスを列挙・取得しましたが、ここでは説明のため、あえて簡素化しています。実用的なアプリケーションにするには、利用者に「列挙した音声処理クラス(エフェクタなど)からどのクラスを読み込むか」を選択させる等の対応を行います。)

【main.cpp】

PlugProviderクラスの補足ですが、PlugProviderクラスが作成された際には下記3つが内部で実施されます。

実施概要 実施内容
音声処理クラスのインスタンス作成と初期化 音声処理クラスのcreateInstance()関数を使って音声処理クラスを作成するとともに、音声処理クラスのinitialize()関数が呼び出します。
音声処理クラスの対になるパラメータ操作クラスのインスタンス作成と初期化 音声処理クラスでgetControllerClassId()関数を呼び出し、パラメータ操作クラスのFUIDを取得します。
その後、パラメータ操作クラスのcreateInstance()関数を使ってパラメータ操作クラスを作成するとともに、パラメータ操作クラスのinitialize()関数が呼び出されます。
音声処理クラスとパラメータ操作クラスの接続 各クラスの作成・初期化後に、音声処理クラスとパラメーター操作クラスのconnect()関数が呼び出され、両クラスの接続が行われます。ここでは詳細を割愛しますが、パラメータ情報のやり取りのための接続ではなく、sendMessage()関数やnotify()関数でメッセージをやり取りするための接続となります。

音声処理クラスの取得

PlugProviderクラスを作成が終われば、いよいよ音声処理クラスを取得します。

音声処理クラスは基本的にAudioEffectクラスを継承して作られるのですが、ホストアプリケーションを作成する際は、このAudioEffectクラスを直接取得しないようにします。
(AudioEffectクラスを直接取得しないのは、VST Module Architecture(VST-MA)と呼ばれる設計思想に基づいているためです。VST-MAについては詳細を割愛します。)
代わりに、AudioEffectクラスの継承元である3つのインターフェイスクラス(下記)を使用してセットアップや音声処理を行います。

  • IComponentクラス
  • IAudioProcessorクラス
  • IConnectionPointクラス

上記の、3つのインターフェイスクラスのうち、音声処理で主に使用するのはIComponentクラス・IAudioProcessorクラスになります。
PlugProviderクラスからはgetComponent()関数でIComponentクラスを取得することができます。

  • getComponent()関数
  • 概要 PlugProviderクラスから初期化済みのIComponentクラス(音声処理クラスの継承元)を取得する関数
    戻り値 概要
    IComponent* 初期化済みのIComponentクラス(音声処理クラスの継承元)のポインタです。
    引数 変数名 概要
    引数はありません。

IAudioProcessorクラスの取得は、IComponentクラスのqueryInterface()関数を呼び出すことで取得します。
dynamic_castではなく、queryInterface()関数を使用するのもVST-MAの設計思想に基づいているためです。

  • queryInterface()関数
  • 概要 継承先のクラスが、引数1のFUIDで示されたインターフェイスクラスを継承しているか問い合わせ、継承している場合、そのインターフェイスクラスのポインタを取得します。
    例えば、IComponentクラスの継承先クラス(ここではAudioEffectクラス)がIAudioProcessorクラスを継承しているかをFUIDで問い合わせ、継承している場合、IAudioProcessorクラスのポインタを取得します。
    戻り値 概要
    tresult 問い合わせの結果、継承している場合はkResultOk(0x00000000)が、継承していない場合はkNoInterface(0x80004002)が返ります。
    (tresultはintの再定義)
    引数 変数名 概要
    const TUID _iid 該当のインターフェイスクラスを継承するか問い合わせるためのFUIDです。
    FUIDは各インターフェイスクラスクラスのヘッダファイル(ivstaudioprocessor.hやivsteditcontroller.h等)で定義された定数になります。
    「インターフェイスクラス名::iid」の形式で記載すれば使用することができます。
    void** obj 問い合わせ結果であるインターフェイスクラスのポインタを保存するための変数になります。

【main.cpp】

IComponentクラスとIAudioProcessorクラスの取得後は、両方のインターフェイスクラスを使用して、音声処理クラスのセットアップを行います。
音声処理クラスのセットアップについては、今回 説明が多くなり過ぎるため、次回 説明いたします。

終了処理

最後に終了処理を行います。終了処理では下記を実施します。

  • queryInterfaceで取得したインターフェイスクラスについてrelease()関数を呼び出す
  • plugProviderクラスでreleasePlugIn()関数を呼び出す。

今回queryInterfaceで取得したインターフェイスクラスはIAudioProcessorクラスになるので、IAudioProcessorクラスのrelease()関数を呼び出します。
deleteを実施する必要はありません。release()関数の詳細は割愛いたします。

インターフェイスクラスの解放後は、plugProviderクラスでのreleasePlugIn()関数の呼び出します。
引数はplugProviderクラスから取得した音声処理クラスの継承元クラス(IComponentクラス)とパラメーター操作クラスの継承元クラス(IEditControllerクラス)のポインタになります。
今回、パラメータ操作クラスは取得していないのでnullptrとしています。releasePlugIn()関数の詳細は割愛いたします。

【main.cpp】

最後に

実行結果のサンプルについては特に面白味もないため割愛しましたが、音声処理クラスの作成と初期化は以上となります。
この後、音声処理クラスをセットアップすれば実際に音声処理を行うことができるようになります。

次回は、作成した音声処理クラスをセットアップするところまでを説明いたします。

  次回→音声処理クラスでの音声処理準備

VST3プラグイン作りの情報はこちらにもございます → はじめてのVST3プラグイン作り

ご指摘やご質問などがございましたら、コメント欄か掲示板Twitterでご連絡いただければと思います。

掲示板
■Twitterアカウント:@vstcpp   URL:https://twitter.com/vstcpp


コメントを残す