Chinaunix首页 | 论坛 | 博客
  • 博客访问: 279850
  • 博文数量: 17
  • 博客积分: 2096
  • 博客等级: 大尉
  • 技术积分: 535
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-28 18:55
文章分类

全部博文(17)

文章存档

2010年(16)

2008年(5)

分类: C/C++

2010-06-12 23:17:11

emit a signal from inside a callback routine

Qt Ambassador Program
Hi to all,
I' writing an audio editor using fmod and Qt.
Hi have a fmod callback that's called by the fmod engine when a sound is stopped to play and from it I would emit a signal.
Here the callback that's part of a class:

Qt Code:
  1. class AudioDevice : public
  2. {
  3. Q_OBJECT
  4.  
  5. public:
  6. static FMOD_RESULT F_CALLBACK endCallback(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type,
  7. unsigned int commanddata1, unsigned int commanddata2)
  8. {
  9. (void)commanddata1; // Unused (to avoid warnings)
  10. (void)commanddata2; // Unused (to avoid warnings)
  11.  
  12. SoundData* currentSound;
  13.  
  14. switch(type)
  15. {
  16. case FMOD_CHANNEL_CALLBACKTYPE_END:
  17. {
  18. FMOD_RESULT result;
  19. FMOD::Channel *currentChannel = (FMOD::Channel *)channel;
  20.  
  21. void *ud = NULL;
  22. result = currentChannel->getUserData( &ud );
  23.  
  24. currentSound = (SoundData*)ud;
  25.  
  26. /* inform that sound stopped */
  27. emit( soundStopped() );// <------- THIS ONE
  28. break;
  29. }
  30. default:
  31. break;
  32. }
  33.  
  34. return FMOD_OK;
  35. }
  36. public slots:
  37. // Initialize the audio system
  38. bool init();
  39.  
  40. signals:
  41. void soundStopped();
  42. ..more code...
To copy to clipboard, switch view to plain text mode 


The compiler don't like the emit call.
It says
error C2352: 'AudioDevice::soundStopped' : illegal call of non-static member function
How can I do?

Best
Franco Amato
 

  • Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    238
    Thanks
    11
    Thanked 36 Times in 36 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: emit a signal from inside a callback routine

    Hi!

    The compiler is correct. You are calling a non static member from inside a static function. That's a no go. What would be the this object of that call?

    Your callback probably cannot be non-static, so you will have to reference your audiodevice in another way.

    Usually you would use the "user-data" of the callback for that. When you set the callback up, you can pass a pointer to your Audiodevice as commanddata1.

    Qt Code:
    1. class AudioDevice : public
    2. { Q_OBJECT
    3. friend FMOD_RESULT F_CALLBACK endCallback(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type,
    4. unsigned int commanddata1, unsigned int commanddata2);
    5. signals:
    6. void soundStopped();
    7. protected:
    8. void DoEndCallBack() {emit soundStopped();}
    9. }
    10.  
    11. ..
    12.  
    13. FMOD_RESULT F_CALLBACK endCallback(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type,
    14. unsigned int commanddata1, unsigned int commanddata2)
    15. {
    16. AudioDevice* ad = dynamic_cast*>(commanddata1);
    17. if (ad)
    18. ad->DoEndCallBack();
    19. ..
    20. }
    To copy to clipboard, switch view to plain text mode 

    Using the friends approach you can even declare the DoEndCallBack protected..

    HIH

    Johannes
    Last edited by JohannesMunk; 8th December 2009 at 02:57.
     

  • Join Date
    Nov 2007
    Location
    Italy
    Posts
    354
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: emit a signal from inside a callback routine

    Quote Originally Posted by JohannesMunk View Post
    Hi!

    The compiler is correct. You are calling a non static member from inside a static function. That's a no go. What would be the this object of that call?

    Your callback probably cannot be non-static, so you will have to reference your audiodevice in another way.

    Usually you would use the "user-data" of the callback for that. When you set the callback up, you can pass a pointer to your Audiodevice as commanddata1.

    Qt Code:
    1. class AudioDevice : public
    2. { Q_OBJECT
    3. friend FMOD_RESULT F_CALLBACK endCallback(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type,
    4. unsigned int commanddata1, unsigned int commanddata2);
    5. signals:
    6. void soundStopped();
    7. protected:
    8. void DoEndCallBack() {emit soundStopped();}
    9. }
    10.  
    11. ..
    12.  
    13. FMOD_RESULT F_CALLBACK endCallback(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type,
    14. unsigned int commanddata1, unsigned int commanddata2)
    15. {
    16. AudioDevice* ad = dynamic_cast*>(commanddata1);
    17. if (ad)
    18. ad->DoEndCallBack();
    19. ..
    20. }
    To copy to clipboard, switch view to plain text mode 

    Using the friends approach you can even declare the DoEndCallBack protected..

    HIH

    Johannes
    Hi thank you very much.
    I didn't understand. What does the DoEndCallback do?
    Sorry but in this case commanddata1 and commanddata2 are always 0.
    This is the part where I use the userdata:
    Qt Code:
    1. case FMOD_CHANNEL_CALLBACKTYPE_END:
    2. {
    3. FMOD_RESULT result;
    4. FMOD::Channel *currentChannel = (FMOD::Channel *)channel;
    5.  
    6. void *ud = NULL;
    7. result = currentChannel->getUserData( &ud ); //<---USERDATA
    8.  
    9. currentSound = (SoundData*)ud;
    10.  
    11. /* inform that sound stopped */
    12. currentSound->soundFinished(); //<-- I call a routine instead of emiting signals
    13. break;
    14. }
    To copy to clipboard, switch view to plain text mode 
    but I don't cast it to an AudioDevice type. AudioDevice is a singleton.
    I cast to a SoundData type ( in my example )..

    Is a bit difficult. May be I can not use signals in this case
    Last edited by franco.amato; 8th December 2009 at 05:19.
    Franco Amato
     

  • Join Date
    Sep 2009
    Location
    Tashkent, Uzbekistan
    Posts
    107
    Thanks
    1
    Thanked 4 Times in 4 Posts
    Qt products
    Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: emit a signal from inside a callback routine

    Hi. When I met the same problem I solved that with startTimer/killTimer and reimplementation. Then what you can do is to set any Boolean variable (or QMutex based variable if you have multiple access) to true (lock) accordingly and process that inside timerEvent.

    Typical solution might be:

    Qt Code:
    1. static const int timeScale = 50; // 50 Msec
    2.  
    3. class A: public
    4. {
    5. Q_OBJECT
    6.  
    7. public:
    8.  
    9. Q_INVOKABLE A( * parent = 0 )
    10. : (parent),
    11. m_check(false),
    12. m_timer(0)
    13. {
    14. m_timer = startTimer(timeScale);
    15. }
    16. ~A()
    17. {
    18. if (m_timer > 0)
    19. killTimer(m_timer);
    20. }
    21.  
    22. public slots:
    23.  
    24. void handler()
    25. {
    26. if (m_check)
    27. return;
    28. // do something here
    29. m_check = true;
    30. }
    31.  
    32. protected:
    33. void timerEvent ( * event)
    34. {
    35. if (m_check)
    36. {
    37. // do something
    38. emit some_signal(some_args);
    39. m_check != m_check; // Just quicker
    40. }
    41. }
    42. private:
    43.  
    44. bool m_check;
    45. int m_timer;
    46. }
    To copy to clipboard, switch view to plain text mode 

    Good luck.
    Last edited by Tanuki-no Torigava; 8th December 2009 at 05:51.
     

  • Join Date
    Nov 2007
    Location
    Italy
    Posts
    354
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: emit a signal from inside a callback routine

    Quote Originally Posted by Tanuki-no Torigava View Post
    Hi. When I met the same problem I solved that with startTimer/killTimer and reimplementation. Then what you can do is to set any Boolean variable (or QMutex based variable if you have multiple access) to true (lock) accordingly and process that inside timerEvent.

    Typical solution might be:

    Qt Code:
    1. static const int timeScale = 50; // 50 Msec
    2.  
    3. class A: public
    4. {
    5. Q_OBJECT
    6.  
    7. public:
    8.  
    9. Q_INVOKABLE A( * parent = 0 )
    10. : (parent),
    11. m_check(false),
    12. m_timer(0)
    13. {
    14. m_timer = startTimer(timeScale);
    15. }
    16. ~A()
    17. {
    18. if (m_timer > 0)
    19. killTimer(m_timer);
    20. }
    21.  
    22. public slots:
    23.  
    24. void handler()
    25. {
    26. if (m_check)
    27. return;
    28. // do something here
    29. m_check = true;
    30. }
    31.  
    32. protected:
    33. void timerEvent ( * event)
    34. {
    35. if (m_check)
    36. {
    37. // do something
    38. emit some_signal(some_args);
    39. m_check != m_check; // Just quicker
    40. }
    41. }
    42. private:
    43.  
    44. bool m_check;
    45. int m_timer;
    46. }
    To copy to clipboard, switch view to plain text mode 

    Good luck.
    I don't know how to adapt your code for my purpose, but how can be possible to connect
    a slot of an object that's created when the gui is started with a signal of an object that is created later?
    I get an error
    Franco Amato
     

  • Join Date
    Sep 2009
    Location
    Tashkent, Uzbekistan
    Posts
    107
    Thanks
    1
    Thanked 4 Times in 4 Posts
    Qt products
    Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: emit a signal from inside a callback routine

    I don't know how to adapt your code for my purpose, but how can be possible to connect
    a slot of an object that's created when the gui is started with a signal of an object that is created later?
    I get an error
    That is easy. Let's say you create object B from some method of the object A, so it will look like that:

    Qt Code:
    1. A::someMethod()
    2. {
    3. B* b = new B(this);
    4. connect(b, SIGNAL(b_signal(mask)), this, SLOT(signal_handler);
    5.  
    6. }
    To copy to clipboard, switch view to plain text mode 

    So, you get the idea.
     

  • Join Date
    Nov 2007
    Location
    Italy
    Posts
    354
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: emit a signal from inside a callback routine

    Quote Originally Posted by Tanuki-no Torigava View Post
    That is easy. Let's say you create object B from some method of the object A, so it will look like that:

    Qt Code:
    1. A::someMethod()
    2. {
    3. B* b = new B(this);
    4. connect(b, SIGNAL(b_signal(mask)), this, SLOT(signal_handler);
    5.  
    6. }
    To copy to clipboard, switch view to plain text mode 

    So, you get the idea.
    Hi yes,
    but what the key "mask" means?
    Seems that I have to connect after the new
    Franco Amato
     

  • Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    238
    Thanks
    11
    Thanked 36 Times in 36 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: emit a signal from inside a callback routine

    Hi there!

    You seem to miss the point of the commanddata.. That is data you pass along / define once when you call the callback-setup! You seem to pass 0 at the moment, that is why its zero. Just pass a pointer to your AudioDevice and it should work. That pointer-data then is passed to the callback each time it is called. At least that is, how callbacks usually work..

    You should have mentioned, that AudioDevice is a singleton.. Because than you can call the DoEndCallBack directly, even if your callback doesn't provide a user-defined-data (which I think it does => commanddata).

    protected:
    void DoEndCallBack() {emit soundStopped();}

    DoEndCallback just emits the soundStopped signal, as I defined it... But you can of course code it directly, see below:

    Let me give you a more complete Callback scenario:

    Qt Code:
    1. class TDAQCaptureThread : public
    2. {
    3. friend int32 CVICALLBACK DoneCallback(TaskHandle taskHandle, int32 status, void *callbackData);
    4. Q_OBJECT
    5. signals:
    6. void Finished();
    7. protected:
    8. void run();
    9. };
    10.  
    11. #include "DAQCaptureThread.h"
    12.  
    13. int32 CVICALLBACK DoneCallback(TaskHandle taskHandle, int32 status, void *callbackData);
    14.  
    15. void TDAQCaptureThread::run()
    16. {
    17. ...
    18.  
    19. DAQmxRegisterDoneEvent(taskHandle,1,DoneCallback,this);
    20.  
    21. ..
    22.  
    23. DAQmxStartTask(taskHandle);
    24.  
    25. exec();
    26.  
    27. ...
    28.  
    29. }
    30.  
    31. int32 CVICALLBACK DoneCallback(TaskHandle taskHandle, int32 status, void *callbackData)
    32. {
    33. ..
    34.  
    35. emit ((TDAQCaptureThread*)callbackData)->Finished();
    36.  
    37. ...
    38.  
    39. return 0;
    40. }
    To copy to clipboard, switch view to plain text mode 

    The DAQmxRegisterDoneEvent is defined int the used DAQmx library as follows:

    Qt Code:
    1. int32 __CFUNC DAQmxRegisterDoneEvent(TaskHandle task, uInt32 options, DAQmxDoneEventCallbackPtr callbackFunction, void *callbackData);
    To copy to clipboard, switch view to plain text mode 

    This callbackData is what I'm talking about.. If you decide one day to have several AudioDevices :->

    HIH

    Johannes
     

  • Join Date
    Nov 2007
    Location
    Italy
    Posts
    354
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: emit a signal from inside a callback routine

    Quote Originally Posted by JohannesMunk View Post
    Hi there!

    You seem to miss the point of the commanddata.. That is data you pass along / define once when you call the callback-setup! You seem to pass 0 at the moment, that is why its zero. Just pass a pointer to your AudioDevice and it should work. That pointer-data then is passed to the callback each time it is called. At least that is, how callbacks usually work..

    You should have mentioned, that AudioDevice is a singleton.. Because than you can call the DoEndCallBack directly, even if your callback doesn't provide a user-defined-data (which I think it does => commanddata).

    protected:
    void DoEndCallBack() {emit soundStopped();}

    DoEndCallback just emits the soundStopped signal, as I defined it... But you can of course code it directly, see below:

    Let me give you a more complete Callback scenario:

    Qt Code:
    1. class TDAQCaptureThread : public
    2. {
    3. friend int32 CVICALLBACK DoneCallback(TaskHandle taskHandle, int32 status, void *callbackData);
    4. Q_OBJECT
    5. signals:
    6. void Finished();
    7. protected:
    8. void run();
    9. };
    10.  
    11. #include "DAQCaptureThread.h"
    12.  
    13. int32 CVICALLBACK DoneCallback(TaskHandle taskHandle, int32 status, void *callbackData);
    14.  
    15. void TDAQCaptureThread::run()
    16. {
    17. ...
    18.  
    19. DAQmxRegisterDoneEvent(taskHandle,1,DoneCallback,this);
    20.  
    21. ..
    22.  
    23. DAQmxStartTask(taskHandle);
    24.  
    25. exec();
    26.  
    27. ...
    28.  
    29. }
    30.  
    31. int32 CVICALLBACK DoneCallback(TaskHandle taskHandle, int32 status, void *callbackData)
    32. {
    33. ..
    34.  
    35. emit ((TDAQCaptureThread*)callbackData)->Finished();
    36.  
    37. ...
    38.  
    39. return 0;
    40. }
    To copy to clipboard, switch view to plain text mode 

    The DAQmxRegisterDoneEvent is defined int the used DAQmx library as follows:

    Qt Code:
    1. int32 __CFUNC DAQmxRegisterDoneEvent(TaskHandle task, uInt32 options, DAQmxDoneEventCallbackPtr callbackFunction, void *callbackData);
    To copy to clipboard, switch view to plain text mode 

    This callbackData is what I'm talking about.. If you decide one day to have several AudioDevices :->

    HIH

    Johannes
    In this case commanddata1 and commanddata2 are not the user data ( fmod callbacks ). In this case they are 0. User data are sent by another routine setUserdata and I got it from inside the callback by getUserdData() .

    Thank you
    Franco Amato
  • 阅读(1204) | 评论(0) | 转发(0) |
    给主人留下些什么吧!~~