Используя openFrameworks + CoreAudio
Мои навыки C++ довольно легки, но мне удается сделать что-то - пока я не наткнулся на стену. Текущая стена:
Я использую CoreAudio, чтобы сделать некоторые вещи с воспроизведением Midi. У меня есть много работы, но я застрял на простой вещи. (Я не знаю правильной терминологии C++, так что терпите меня...).
Я использую функцию обратного вызова рендеринга в CoreAudio, чтобы указать, когда событие midi note обрабатывается AU. Если я определяю ее как неклассовую функцию и вставляю ее в main.cpp (или в этом случае testApp.cpp), она работает - я получаю события. Проблема в том, что мне нужно, чтобы экземпляр testApp получал эти события.
Итак... есть ли способ получить экземпляр testApp из main.cpp, чтобы я мог вызвать нужный мне метод testApp?
ИЛИ есть ли в C++ вуду иметь неклассовую функцию, находящуюся внутри класса, вызывающего метод экземпляра? Например, если функция ниже находится в моем классе, как она может вызвать метод в экземпляре класса...
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
}
Я не знаю наверняка, но я думаю, что материал CoreAudio не принимает методы экземпляра в качестве обратных вызовов - по крайней мере, это то, что я почерпнул из сообщения об ошибке (ниже). Я в порядке, все равно это работает.
спасибо за любые советы!
ошибка: аргумент типа OSStatus (testApp::)(void*, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32, UInt32, AudioBufferList*)'не соответствует' OSStatus () (void, AudioUnitRenderActionFlags *, const UimeTime *), AudioBufferList *)
4 ответа
Вам не нужно связываться со статическими экземплярами, чтобы сделать это. Когда вы добавляете обратный вызов рендеринга, передайте ваш объект C++ как refcon, а затем приведите refcon к вашему объекту в обратном вызове:
// 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
}
Если вы можете установить boost, boost::bind может сделать это за вас.
Ответ sbooth - здесь ответ, так как дизайнеры API предоставили вам хороший трюк. Если вы передавали обратный вызов в менее хорошо спроектированную библиотеку c, ответ ниже может помочь.
Вам нужно перейти от указателя на функцию-член к указателю на функцию.
C++ faq lite здесь и здесь есть ваш ответ
Вы также можете:
1. Сделайте someMethod() статическим и сохраните статический экземпляр testApp (если вам нужно изменить данные экземпляра) 2. Сохраните указатель testApp глобально и используйте его из глобальной функции, которую вы уже используете
Вот пример метода 1, который я бы порекомендовал
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;
}
Учитывая, где вы находитесь со своими знаниями C++, я бы порекомендовал прочитать все faq lite, а затем fqa. Я хотел бы, чтобы кто-то рекомендовал мне это, когда я начал.
Вы правы в том, что вы не можете использовать указатель на метод экземпляра здесь (нет способа предоставить неявный указатель 'this' на функцию-член, поскольку обратный вызов фактически не вызывается через объект).
Вы можете использовать статическую функцию-член для этого (тогда вам понадобится какой-то способ предоставить этой функции указатель на экземпляр вашего testApp (глобальная переменная, статический экземпляр и т. Д.)).