こんにちは、ぺろりです。
今回はExtensionからC/C++とReaScript(lua,EEL)に対してAPIを公開する方法を紹介します。
Pythonでスクリプトを書く方法は試してないので機会があれば・・・。
ここまで読み進めて来たという方であればコード見ればすぐ分かりそうですので、そこからいきましょう。
plugin_register( "API_UnkoFunc", (void*)UnkoFunc ) は、"UnkoFunc"という名前でExtensionAPIを登録しています。"API_"以下の部分が公開APIの名前となりますが、登録する関数(第2引数のやつ)の名前は合わせなくても問題ないようです(__UnkoFuncという関数を登録しても問題なかった)。
plugin_register( "APIdef_UnkoFunc", ... ) ではAPIの戻り値、Helpテキストといった情報を登録します。これも登録が必須です。文字列のフォーマットは
"戻り値\0引数の型リスト\0引数の名前リスト\0Helpテキスト"
といった感じでしょうか。複数引数があるなら、例えば "int\0int,double\0arg1,arg2\0Hoge Function" という感じです。
plugin_register( "APIvararg_UnkoFunc", ... ) はスクリプトから呼ばれる関数登録となります。スクリプトからは "API_○○" で登録した関数が直接呼ばれるわけではありません。"APIvararg_○○" で登録した関数が呼ばれることになります。
スクリプトから呼び出されると、引数(arglist)がどれだけ積まれたか(numParams)という情報がやってきますので、必要なだけ情報を引用して結果を返してやればいいようです。今回のサンプルだと UnkoFunc を呼んで結果を返してやればOK。
あとはExtension終了時に plugin_register( "-API_UnkoFunc", (void*)UnkoFunc ); などで登録したものを解除して実装完了です。(このへんはまぁ、もう分かりますよね)
実際のところ、1つのAPI登録で3つの登録用文字列が必要なことから、沢山APIを公開しようとすると結構煩雑になっていくと思います。SWSのReaScript.cppあたりを見てみると、マクロで文字列を一括定義したりといった部分などもろもろ参考になるのではないかと思います。
で
これらを実装したExtensionをREAPERにインストールしてからREAPERを起動して、reaper_plugin_functions.hを書き出す(Action"[developer] Write C++ API functions header"で[Write functions exported by 3rd party extensions]にチェックを入れる)と、自分で登録した関数(ここだとUnkoFunc)がヘッダに出力されて使えるようになります。
・・・っと書いたものの、自分の環境だとこの3rdPartyの関数も出力したreaper_plugin_functions.hを使おうとしてみたところ、他のExtensionが公開している関数で使われている構造体などの型が見つからず、コンパイルエラーになってしまいました(このへんもうちょっと頑張って取り組むのは後にしようかと思います)。
なので、自分は前述のサンプルコードにあるようにGetFunc()で関数ポインタを取得して使う方法を今のところ使っています。
ひとまずC++側では呼べるようになったので、次はluaで呼び出してみます(ActionListでReaScriptのNewボタンでluaファイルを作成してスクリプトを書きます)。
ハイ、簡単ですね。
ついでにEELでも試してみます。今度は.eelファイルを作成して書きます。
EELではExtension APIの呼び出しに extension_api() を使います。

ちなみにExtensionからの公開関数はREAPERのメニューから、[Help > ReaScript documentation]でHTML出力されるので、自分の関数がこのHTMLにも表示されるようになります。

今回はREAPERのExtension API公開方法を解説しました。
これでスクリプトからもあなたの関数を呼び出すことができて、また一段とREAPER機能実装の自由度が上がるのではないかと思います。
しかしこのDAW、ホントやりたい放題出来てオモチャとして面白すぎる・・・
ではまた次の記事でお会いしましょう。
今回はExtensionからC/C++とReaScript(lua,EEL)に対してAPIを公開する方法を紹介します。
Pythonでスクリプトを書く方法は試してないので機会があれば・・・。
ここまで読み進めて来たという方であればコード見ればすぐ分かりそうですので、そこからいきましょう。
/// REAPER経由での公開関数 /// @param[in] num 任意の数値 /// @return てきとーに計算した結果 static int UnkoFunc(int num) { return 2 * num; // てきとーに値を倍にして返すだけ } /// 単なる便利用typedef typedef int (*FUNC_UnkoFunc)(int); /// Luaから呼び出せるようにするための関数 /// - Script系の言語からはCの関数を直接ではなくて、こういった可変引数的な呼ばれ方をする模様 /// @param[in] arglist luaとかからくる引数リスト /// @param[in] numParams arglistの要素数 /// @return 結果の値(ここだとUnkoFunc()の戻り値) static void* __vararg_UnkoFunc( void** arglist, int numParams ) { // Cで公開していた関数を呼ぶ int res = UnkoFunc( (intptr_t)arglist[0] ); // 戻り値をvoid*にして返してやる return (void*)(intptr_t)(res); } REAPER_PLUGIN_DLL_EXPORT int REAPER_PLUGIN_ENTRYPOINT( REAPER_PLUGIN_HINSTANCE hInstance, reaper_plugin_info_t *rec) { // (中略) // 初期化時の処理で、以下の登録処理を行う // 公開する処理を書く関数を登録 plugin_register( "API_UnkoFunc", (void*)UnkoFunc ); // 関数の引数やHelp文字列などの情報を登録 plugin_register( "APIdef_UnkoFunc", "int\0int\0num\0[Pelori:API]Exported Unko API" ); // luaなどのスクリプト側から呼ばれる関数を登録 plugin_register( "APIvararg_UnkoFunc", __vararg_UnkoFunc ); // Cで呼び出せるかのテスト // 関数のアドレスをREAPERから取得 FUNC_UnkoFunc unkofunc_ptr = (FUNC_UnkoFunc)(rec->GetFunc("UnkoFunc")); // 呼び出してみる int unkoResult = unkofunc_ptr( 3 ); // 3*2=6が返ってくればOK
// (後略)}
plugin_register( "API_UnkoFunc", (void*)UnkoFunc ) は、"UnkoFunc"という名前でExtensionAPIを登録しています。"API_"以下の部分が公開APIの名前となりますが、登録する関数(第2引数のやつ)の名前は合わせなくても問題ないようです(__UnkoFuncという関数を登録しても問題なかった)。
plugin_register( "APIdef_UnkoFunc", ... ) ではAPIの戻り値、Helpテキストといった情報を登録します。これも登録が必須です。文字列のフォーマットは
"戻り値\0引数の型リスト\0引数の名前リスト\0Helpテキスト"
といった感じでしょうか。複数引数があるなら、例えば "int\0int,double\0arg1,arg2\0Hoge Function" という感じです。
plugin_register( "APIvararg_UnkoFunc", ... ) はスクリプトから呼ばれる関数登録となります。スクリプトからは "API_○○" で登録した関数が直接呼ばれるわけではありません。"APIvararg_○○" で登録した関数が呼ばれることになります。
スクリプトから呼び出されると、引数(arglist)がどれだけ積まれたか(numParams)という情報がやってきますので、必要なだけ情報を引用して結果を返してやればいいようです。今回のサンプルだと UnkoFunc を呼んで結果を返してやればOK。
あとはExtension終了時に plugin_register( "-API_UnkoFunc", (void*)UnkoFunc ); などで登録したものを解除して実装完了です。(このへんはまぁ、もう分かりますよね)
実際のところ、1つのAPI登録で3つの登録用文字列が必要なことから、沢山APIを公開しようとすると結構煩雑になっていくと思います。SWSのReaScript.cppあたりを見てみると、マクロで文字列を一括定義したりといった部分などもろもろ参考になるのではないかと思います。
で
これらを実装したExtensionをREAPERにインストールしてからREAPERを起動して、reaper_plugin_functions.hを書き出す(Action"[developer] Write C++ API functions header"で[Write functions exported by 3rd party extensions]にチェックを入れる)と、自分で登録した関数(ここだとUnkoFunc)がヘッダに出力されて使えるようになります。
// (↓ reaper_plugin_functions.hに書き出された部分) #if defined(REAPERAPI_WANT_UnkoFunc) || !defined(REAPERAPI_MINIMAL) REAPERAPI_DEF //============================================== // UnkoFunc // [Pelori:API]Exported Unko API int (*UnkoFunc)(int num); #endif
・・・っと書いたものの、自分の環境だとこの3rdPartyの関数も出力したreaper_plugin_functions.hを使おうとしてみたところ、他のExtensionが公開している関数で使われている構造体などの型が見つからず、コンパイルエラーになってしまいました(このへんもうちょっと頑張って取り組むのは後にしようかと思います)。
なので、自分は前述のサンプルコードにあるようにGetFunc()で関数ポインタを取得して使う方法を今のところ使っています。
ひとまずC++側では呼べるようになったので、次はluaで呼び出してみます(ActionListでReaScriptのNewボタンでluaファイルを作成してスクリプトを書きます)。
val = reaper.UnkoFunc(3) reaper.ShowConsoleMsg(val)

ハイ、簡単ですね。
ついでにEELでも試してみます。今度は.eelファイルを作成して書きます。
EELではExtension APIの呼び出しに extension_api() を使います。
num = extension_api("UnkoFunc", 3); sprintf(#str, "Result:%d", num); ShowConsoleMsg(#str);

ちなみにExtensionからの公開関数はREAPERのメニューから、[Help > ReaScript documentation]でHTML出力されるので、自分の関数がこのHTMLにも表示されるようになります。

今回はREAPERのExtension API公開方法を解説しました。
これでスクリプトからもあなたの関数を呼び出すことができて、また一段とREAPER機能実装の自由度が上がるのではないかと思います。
しかしこのDAW、ホントやりたい放題出来てオモチャとして面白すぎる・・・
ではまた次の記事でお会いしましょう。
このブログにコメントするにはログインが必要です。
さんログアウト
この記事には許可ユーザしかコメントができません。