используя openFrameworks + CoreAudio - PullRequest
0 голосов
/ 14 июля 2011

мои навыки C ++ довольно легки, но мне удается сделать что-то - пока я не наткнулся на стену.Текущая стена:

Я использую CoreAudio, чтобы сделать некоторые вещи с воспроизведением Midi.У меня есть много работы, но я застрял на простой вещи.(Я не знаю правильной терминологии C ++, так что терпите меня ...).

Я использую функцию обратного вызова рендеринга в CoreAudio, чтобы указать, когда событие midi note обрабатывается AU.Если я определяю ее как неклассовую функцию и вставляю ее в main.cpp (или в этом случае testApp.cpp), она работает - я получаю события.Проблема в том, что мне нужно, чтобы экземпляр testApp получал эти события.

Итак ... есть ли способ получить экземпляр testApp из main.cpp, чтобы я мог вызвать метод testApp Iнужно?

ИЛИ есть ли в 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 AudioTimeStamp *, UInt32, UInt32, AudioBufferList *)

Ответы [ 4 ]

2 голосов
/ 14 июля 2011

Вам не нужно связываться со статическими экземплярами, чтобы сделать это. Когда вы добавляете обратный вызов рендеринга, передайте ваш объект 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
}
0 голосов
/ 14 июля 2011

Вы правы, что вы не можете использовать указатель на метод экземпляра здесь (нет способа предоставить неявный указатель 'this' на функцию-член, так как обратный вызов фактически не вызывается через объект).

Для этого вы можете использовать статическую функцию-член (тогда вам понадобится какой-то способ предоставить этой функции указатель на экземпляр вашего testApp (глобальная переменная, статический экземпляр и т. Д.)).

0 голосов
/ 14 июля 2011

Если вы можете установить boost, boost :: bind может сделать это за вас.

0 голосов
/ 14 июля 2011

sbooth's answer - это ответ здесь, так как дизайнеры 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 .Хотелось бы, чтобы кто-то рекомендовал мне это, когда я начал.

...