【问题标题】:using openFrameworks + CoreAudio使用 openFrameworks + CoreAudio
【发布时间】:2011-07-14 02:50:16
【问题描述】:

我的 C++ 技能很轻,但我设法完成了工作 - 直到我碰壁。当前墙:

我正在使用 CoreAudio 来做一些关于 Midi 播放的事情。我有很多工作,但被困在一个简单的事情上。 (我不知道正确的 C++ 术语,所以请耐心等待......)。

我在 CoreAudio 中使用渲染回调函数来指示 AU 何时渲染 midi 音符事件。如果我将它定义为非类函数并将其粘贴到 main.cpp (或 testApp.cpp ),它就可以工作 - 我得到了事件。问题是我需要能够让 testApp 的实例获取这些事件。

那么.. 有没有办法从 main.cpp 获取 testApp 的实例,这样我就可以调用我需要的 testApp 方法了?

或者是否有一些 C++ voodoo 有一个驻留在类中的非类函数调用实例的方法?比如下面的函数在我的类中,怎么会调用类的实例上的方法……

    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, 音频缓冲区列表*)

【问题讨论】:

    标签: c++ core-audio openframeworks


    【解决方案1】:

    你不需要弄乱静态实例来做到这一点。添加渲染回调时,将 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
    }
    

    【讨论】:

    • 这是一个漂亮的 API 技巧,显然有人考虑过人们如何使用它。我假设提问者在我的回答中调用了一个常规的 c 库
    • 是的,Apple 清楚地意识到这个 API 的正常使用方式。我似乎还记得在 Pascal 工具箱编程时代的这种模式,所以我认为它已经存在了一段时间。
    • 感谢大家的回复。我能够使用上面的方法让它工作。 CoreAudio 一开始对所有的指针都感到困惑,但我已经掌握了窍门。
    【解决方案2】:

    您是正确的,您不能在此处使用指向实例方法的指针(无法提供指向成员函数的隐式“this”指针,因为回调实际上并未通过对象调用)。

    您可以为此使用静态成员函数(然后您需要某种方式为该函数提供指向您的 testApp 实例(全局变量、静态实例等)的指针)。

    【讨论】:

      【解决方案3】:

      如果你可以安装 boost,boost::bind 可以为你做这件事。

      【讨论】:

        【解决方案4】:

        sbooth 的answer 是这里的 anwser,因为 api 设计者为您提供了一个不错的技巧。但是,如果您将回调传递给设计不太完善的 c 库,那么下面的答案可能会有所帮助。

        你需要从一个指向成员函数的指针到指向函数的指针。

        c++ faq lite herehere 有你的答案

        您可以:

        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。我希望有人在我开始时向我推荐它。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-11-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多