using openFrameworks + CoreAudio
my C++ skills are pretty light but I manage to get stuff done - until I run into a wall. The current wall:
I am using CoreAudio to do some stuff with Midi playback. I've got lots of it working but am stuck on a simple thing. (I don't know the right C++ terminology so bear with me...).
I'm using a render callback function in CoreAudio to indicate when a midi note event is being rendered by an AU. If I define it as a non-class function and stick it main.cpp (or testApp.cpp for that matter) it works - I get the events. The problem is I need to be able to have the instance of testApp get those events.
So.. is there a way to get at the instance of testApp from main.cpp so I can call the testApp method I need?
OR is there some C++ voodoo to have a a non-class function residing within a class call a method of an instance? For example, if the function below is in my class, how can it call a method on the instance of the class...
OSStatus renderCallback(void *inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
开发者_运维问答 AudioBufferList * ioData)
{
someClassMethod(); // doesn't work
this.someClassMethod(); // doesn't work
self.someClassMethod(); // doesn't work
}
I don't know for sure but I think the CoreAudio stuff doesn't take instance methods as callbacks - at least that's what I've gleaned from the error msg (below). I'm fine doing it anyway that works.
thanks for any tips!
error: argument of type OSStatus (testApp::)(void*, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32, UInt32, AudioBufferList*)' does not match 'OSStatus ()(void, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32, UInt32, AudioBufferList*)
You don't need to mess with static instances to do this. When you add the render callback, pass your C++ object as the refcon, and then cast the refcon to your object in the callback:
// The actual callback is defined as a static function
static OSStatus
myAURenderCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
MyClass *object = static_cast<MyClass *>(inRefCon);
return object->Render(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
}
// When adding the render callback pass this as the context
AURenderCallbackStruct cbs = { myAURenderCallback, this };
OSStatus result = AUGraphSetNodeInputCallback(graph, node, 0, &cbs);
// The callback will look like
OSStatus MyClass::Render(AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
// Do something
}
You're correct that you can't use a pointer to an instance method here (there's no way of providing the implicit 'this' pointer to the member function since the callback isn't actually getting called through an object).
You can use a static member function for this (then you'll need some way of providing that function with a pointer to an instance of your testApp (global variable, static instance, etc)).
If you can install boost, boost::bind can do this for you.
sbooth's answer is the anwser here as the api designers have provided you with a nice trick. If you were passing a callback into a less well designed c library, though, the answer below may help.
You need to get from a pointer-to-member-function to pointer-to-function.
The c++ faq lite here and here has your answer
You can either:
1. Make someMethod() static and keep a static instance of testApp (if you need to twiddle instance data) 2. Store a testApp pointer globally and use it from the global function you are already using
Here is an example of method 1, which I would recommend
class Test
{
public:
Test();
void InstanceCallback();
static void StaticCallbackMethod();
private:
static Test* instance;
};
// Normally in cpp
Test* Test::instance = 0;
Test::Test()
{
instance = this;
}
void Test::InstanceCallback()
{
// do stuff;
}
void Test::StaticCallbackMethod()
{
if (instance)
{
instance->InstanceCallback();
}
}
int main()
{
Test* t = new Test();
void (*mf)();
mf = &Test::StaticCallbackMethod;
mf();
return 0;
}
Given where you are with your c++ knowledge, I would really recommend reading all of the faq lite and then the fqa. I wish someone had recommended it to me when I started.
精彩评论