为什么我不能在 Jack 中将非全局函数设置为回调?

发布于 2024-11-28 09:52:18 字数 1329 浏览 2 评论 0原文

我正在尝试在 Jack 中设置回调函数。这通常非常简单,使用函数“jack_set_process_callback”(在设置“process”回调的情况下)。

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)

任何人都可以阐明这个编译器错误可能暗示什么,或者我可能做错了什么?

谢谢!

I'm trying to set a callback function in Jack. This is usually quite simple, using the function "jack_set_process_callback" (in the case of setting the "process" callback).

The definition in the API is this:

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

In the example code (which has C components) the global function below is declared.

int process(jack_nframes_t nframes, void *arg){

  // do something in the callback
  return 0;
}

It is then set as the Jack process callback by the line:

jack_set_process_callback(client, process, 0)

.. and this compiles and works perfectly.

What I'm doing now is trying to build a class-based audio program. I'm putting all the Jack stuff inside a class imaginatively called "Sound_Module".

The definition of the function that I want to set as my callback is now a member function of this class:

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

  // do something in the callback
  return 0;
}

I'm trying to set this method as my callback function within the class constructor:

(83) jack_set_process_callback(client, process, 0)

but on compilation this leads to the following error:

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

I get the impression from this error message that I need to cast the callback function to something else. I've tried a few things, such as casting to the Jack type designed for callbacks with no luck - below is the line dug out of the API for "JackProcessCallback".

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

Can anyone shed any light on what this compiler error might be hinting at, or what I could be doing wrong?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

走走停停 2024-12-05 09:52:18

成员函数与非成员函数不同,因为只能在该函数所属的类类型的对象上调用它们。

您需要编写一个委托给成员函数的非成员函数。当您调用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);

Member functions are different from non-member functions because you can only call them on an object of the class type of which the function is a member.

You need to write a non-member function that delegates to the member function. When you call jack_set_process_callback, you tell the library what to pass to the void* parameter of your callback, so you can tell it to pass back the address of the Sound_Module object for which you want to call the member function callback.

The non-member callback is quite simple:

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

Registered as:

jack_set_process_callback(client, Sound_Module_Process_Callback, this);
你是我的挚爱i 2024-12-05 09:52:18

这是因为类的每个成员函数都有一个隐藏参数this。相反,将回调方法声明为静态

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.
 };

It's because every member function of class has a hidden argument this. Instead declare the call back method as static.

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

This part of the error message says it's a member function hinting the hidden argument this.

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

And this part says it is regular C-type call back function declaration.

Instead try this -

 class Sound_Module {
    public:
    static int process(jack_nframes_t nframes, void *arg) ; 
   // This is just declaration. Provide the definition in the source file.
 };
酷炫老祖宗 2024-12-05 09:52:18

你不能那样做。

tl;dr:成员函数不是自由函数。您的回调必须是免费函数。

更长的答案:set-callback 函数需要一个函数指针作为其回调参数。只有自由函数才能变成函数指针。非静态成员函数不是自由函数,它们不能变成函数指针!表达式 &Foo::f 是一个成员函数指针 (PTFM),它是一种完全不同、不兼容且通常要大得多的类型。

如果您的客户端函数由 C API 固定,那么您有两种可能的解决方案:

  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);
}

You can't do that.

tl;dr: Member functions are not free functions. Your callback has to be a free function.

Longer answer: The set-callback function requires a function pointer as its callback argument. Only free functions can be turned into a function pointer. Non-static member functions are not free functions, and they cannot be turned into function pointers! The expression &Foo::f is a pointer-to-member-function (PTFM), which is an entirely different, incompatible, usually much larger type.

If your client function is fixed by a C API, then you have two possible solutions:

  1. Make a static member function. Static member functions are essentially just free functions, so they do produce function pointers. In that case you're not really using the class structure and there's no statefulness (which is why you can do this).

  2. Write a global wrapper function.

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);
}
泪之魂 2024-12-05 09:52:18

非静态成员函数不能被回调,因为它们只能被类的实例调用。

我认为你应该这样做:

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;
}

,它应该只接受一个参数。不需要第二个参数。

另外,您应该将 jack_set_process_callback 调用为:

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

也就是说,第三个参数应该是 Sound_Module 实例的地址。如果您从 Sound_Module 的成员函数调用 this,它也可能是 this 指针:

void Sound_Module::SomeNonStaticMemberFunction()
{
     jack_set_process_callback(client, callback, this);
}

Non-static member function cannot be callback, since they can be invoked only instances of the class.

I think you should be doing this:

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

And define the member function process as

int Sound_Module::process(jack_nframes_t nframes){

  // do something in the callback
  return 0;
}

That is, it should take one parameter only. Second parameter is not needed.

Also, you should call jack_set_process_callback as:

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

That is, the third argument should be the address of an instance of Sound_Module. It could be this pointer as well, if you're calling this from a member function of Sound_Module as:

void Sound_Module::SomeNonStaticMemberFunction()
{
     jack_set_process_callback(client, callback, this);
}
早乙女 2024-12-05 09:52:18

一种更面向 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 作为参数。这意味着您可以在回调中使用子类的其他方法。

A more C++ oriented approach, the key is using Jack's JackProcessCallback predefined type:

#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. }
};

Then you would call this like so:

jack_client_t * client;

int main()
{
    Metronome Metro;

    Metronome * MetroPointer = &Metro;

    BaseSoundModule * PolyMetro = &Metro;

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

}
  • Note 1: Notice that inside process_audio you also passed MetroPointer as an argument. Which means you can use other methods of the child class inside the callback.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文