1

Jack にコールバック関数を設定しようとしています。これは通常、関数「jack_set_process_callback」を使用して非常に簡単です (「プロセス」コールバックを設定する場合)。

API での定義は次のとおりです。

int jack_set_process_callback(jack_client_t* client, JackProcessCallback process_callback, void* arg).

サンプル コード (C コンポーネントを含む) では、以下のグローバル関数が宣言されています。

int process(jack_nframes_t nframes, void *arg){

  // do something in the callback
  return 0;
}

次に、次の行によって Jack プロセスのコールバックとして設定されます。

jack_set_process_callback(client, process, 0)

..これはコンパイルされ、完全に機能します。

私が今行っていることは、クラスベースのオーディオ プログラムを構築しようとしていることです。私はすべてのJackのものを想像上「Sound_Module」と呼ばれるクラスの中に入れています。

コールバックとして設定したい関数の定義は、このクラスのメンバー関数になりました。

int Sound_Module::process(jack_nframes_t nframes, void *arg){

  // do something in the callback
  return 0;
}

このメソッドをクラス コンストラクター内のコールバック関数として設定しようとしています。

(83) jack_set_process_callback(client, process, 0)

しかし、コンパイルすると、次のエラーが発生します。

sound_module.cpp:83: error: argument of type ‘int (Sound_Module::)(jack_nframes_t, void*)’ does not match ‘int (*)(jack_nframes_t, void*)’

このエラー メッセージから、コールバック関数を別のものにキャストする必要があるという印象を受けました。運の悪いコールバック用に設計された Jack タイプにキャストするなど、いくつかのことを試しました。以下は、「JackProcessCallback」の API から掘り出された行です。

typedef int(* JackProcessCallback)(jack_nframes_t nframes, void *arg)

このコンパイラエラーが何を示唆しているのか、または私が間違っている可能性があることについて、誰かが光を当てることができますか?

ありがとう!

4

5 に答える 5

3

メンバー関数は、関数がメンバーであるクラス型のオブジェクトでのみ呼び出すことができるため、非メンバー関数とは異なります。

メンバー関数に委任する非メンバー関数を作成する必要があります。を呼び出すときに、コールバックjack_set_process_callbackのパラメーターに何を渡すかをライブラリに指示します。これにより、メンバー関数コールバックを呼び出したいオブジェクトvoid*のアドレスを返すようにライブラリに指示できます。Sound_Module

非メンバー コールバックは非常に単純です。

int Sound_Module_Process_Callback(jack_nframes_t x, void* p)
{
    return static_cast<Sound_Module*>(p)->process(x);
}

登録者:

jack_set_process_callback(client, Sound_Module_Process_Callback, this);
于 2011-08-06T22:41:42.203 に答える
2

これは、クラスのすべてのメンバー関数に隠し引数thisがあるためです。代わりに、コールバック メソッドをstaticとして宣言します。

error: argument of type ‘int (Sound_Module::)(jack_nframes_t, void*)’  
                            // ^^^^^^^^^^^^^

エラー メッセージのこの部分は、非表示の引数thisを示唆するメンバー関数であることを示しています。

does not match ‘int (*)(jack_nframes_t, void*)’

そして、この部分は、通常の C 型のコールバック関数宣言です。

代わりにこれを試してください -

 class Sound_Module {
    public:
    static int process(jack_nframes_t nframes, void *arg) ; 
   // This is just declaration. Provide the definition in the source file.
 };
于 2011-08-06T22:38:23.343 に答える
1

非静的メンバー関数は、クラスのインスタンスのみを呼び出すことができるため、コールバックすることはできません。

私はあなたがこれをするべきだと思います:

int callback(jack_nframes_t nframes, void* arg)
{
    return static_cast<Sound_Module*>(arg)->process(nframes);
}

そして、メンバー関数process を次のように定義します

int Sound_Module::process(jack_nframes_t nframes){

  // do something in the callback
  return 0;
}

つまり、1つのパラメーターのみを取る必要があります。2番目のパラメーターは必要ありません。

また、次のように呼び出す必要がありますjack_set_process_callback

 jack_set_process_callback(client, callback, &soundModule);
                                           //^^^^^^^^^^^^

つまり、3番目の引数はのインスタンスのアドレスである必要がありますSound_Modulethis次のようなメンバー関数からこれを呼び出している場合は、ポインターになる可能性もありますSound_Module

void Sound_Module::SomeNonStaticMemberFunction()
{
     jack_set_process_callback(client, callback, this);
}
于 2011-08-06T22:44:15.337 に答える
1

そんなことはできません。

tl;dr: メンバー関数はフリー関数ではありません。コールバックは無料の関数でなければなりません。

より長い答え: set-callback 関数には、そのコールバック引数として関数ポインターが必要です。関数ポインターに変換できるのは、フリー関数のみです。非静的メンバー関数はフリー関数ではなく、関数ポインターに変換することはできません! 式&Foo::fメンバー関数へのポインター(PTFM) であり、これはまったく異なる、互換性のない、通常ははるかに大きな型です。

クライアント関数が C API によって修正された場合、2 つの解決策が考えられます。

  1. 静的メンバー関数を作成します。静的メンバー関数は本質的に単なるフリー関数であるため、関数ポインターを生成します。その場合、実際にはクラス構造を使用しておらず、ステートフルではありません (これができる理由です)。

  2. グローバル ラッパー関数を記述します。

Sound_Module g_sm1; // global!
Sound_Module g_sm2;

int process1(jack_nframes_t nframes, void *arg)
{
  return g_sm1.process_firsttype(nframes, arg);
}
int process2(jack_nframes_t nframes, void *arg)
{
  return g_sm1.process_secondtype(nframes, arg);
}
int process3(jack_nframes_t nframes, void *arg)
{
  return g_sm2.process_firsttype(nframes, arg);
}
int process4(jack_nframes_t nframes, void *arg)
{
  static Sound_Module s_sm;
  return s_sm.process_firsttype(nframes, arg);
}
于 2011-08-06T22:40:09.783 に答える
-1

より C++ 指向のアプローチであるキーは、Jack の JackProcessCallback 定義済みタイプを使用することです。

#include <jack/jack.h>

BaseSoundModule
{
    public:

    jack_client_t * client;

    //Use a constructor to assign a client to the class.
    BaseSoundModule( jack_client_t * external_client ){ client = external_client; }

    //Use Jack's JackProcessCallback predefined type.
    void setProcessCallback( JackProcessCallback, void * pointerArgument )
    {
        jack_set_process_callback( client, JackProcessCallback, pointerArgument );
    }

};

Metronome : public BaseSoundModule
{
    static int process_audio( jack_nframes_t nframes, void * arg )
    {
        //Note #1 at the end of this example
        Metronome * MetroPointer = ( Metronome * ) arg;

        //Call other functions inside your metronome class;
        Metronome->someotherfunc();
    }

    int someotherfunc(){ //return something. }
};

次に、これを次のように呼び出します。

jack_client_t * client;

int main()
{
    Metronome Metro;

    Metronome * MetroPointer = &Metro;

    BaseSoundModule * PolyMetro = &Metro;

    PolyMetro->setProcessCallback( MetroPointer->process_audio, MetroPointer );

}
  • 注 1: process_audio 内で MetroPointer も引数として渡したことに注意してください。つまり、コールバック内で子クラスの他のメソッドを使用できます。
于 2012-12-26T00:25:17.157 に答える