最简单的方法是从音频输入中捕获原始音频,以便在mac上进行实时处理

时间:2011-05-18 02:37:02

标签: audio core-audio sampling

从内置音频输入中捕获音频的最简单方法是什么,并且能够在请求时实时读取原始采样值(如.wav中),例如从套接字读取。 / p>

希望代码使用Apple的一个框架(音频队列)。文档不是很清楚,我需要的是非常基础的。

2 个答案:

答案 0 :(得分:7)

为此尝试AudioQueue框架。您主要必须执行3个步骤:

  1. 设置音频格式如何对传入的模拟音频进行采样
  2. 使用AudioQueueNewInput()
  3. 开始新的录音AudioQueue
  4. 注册处理传入音频数据包的回调例程
  5. 在第3步中,您有机会使用AudioQueueGetProperty()分析传入的音频数据

    大致是这样的:

    static void HandleAudioCallback (void                               *aqData,
                                     AudioQueueRef                      inAQ,
                                     AudioQueueBufferRef                inBuffer, 
                                     const AudioTimeStamp               *inStartTime, 
                                     UInt32                             inNumPackets, 
                                     const AudioStreamPacketDescription *inPacketDesc) {
        // Here you examine your audio data
    }
    
    static void StartRecording() {
        // now let's start the recording
        AudioQueueNewInput (&aqData.mDataFormat,  // The sampling format how to record
                            HandleAudioCallback,  // Your callback routine
                            &aqData,              // e.g. AudioStreamBasicDescription
                            NULL,
                            kCFRunLoopCommonModes, 
                            0, 
                            &aqData.mQueue);      // Your fresh created AudioQueue
        AudioQueueStart(aqData.mQueue,
                        NULL);
    }
    

    我建议Apple AudioQueue Services Programming Guide了解有关如何启动和停止AudioQueue以及如何正确设置所有必需对象的详细信息。

    您可能还需要仔细研究Apple的演示程序SpeakHere。但这是恕我直言,开始时有点混乱。

答案 1 :(得分:2)

这取决于你需要它的“实时”

如果您需要它非常清脆,请在底层向下并使用音频单元。这意味着设置INPUT回调。请记住,当发生这种情况时,您需要分配自己的缓冲区,然后从麦克风请求音频。

即不要被参数中存在缓冲区指针所迷惑......它只是因为Apple正在为输入使用相同的函数声明并渲染回调。

这是我的一个项目中的粘贴:

OSStatus dataArrivedFromMic(
                    void                        * inRefCon, 
                    AudioUnitRenderActionFlags  * ioActionFlags, 
                    const AudioTimeStamp        * inTimeStamp, 
                    UInt32                      inBusNumber, 
                    UInt32                      inNumberFrames, 
                    AudioBufferList             * dummy_notused )
{    
    OSStatus status;

    RemoteIOAudioUnit* unitClass = (RemoteIOAudioUnit *)inRefCon;

    AudioComponentInstance myUnit = unitClass.myAudioUnit;

    AudioBufferList ioData;
    {
        int kNumChannels = 1; // one channel...

        enum {
            kMono = 1,
            kStereo = 2
        };

        ioData.mNumberBuffers = kNumChannels;

        for (int i = 0; i < kNumChannels; i++) 
        {
            int bytesNeeded = inNumberFrames * sizeof( Float32 );

            ioData.mBuffers[i].mNumberChannels = kMono;
            ioData.mBuffers[i].mDataByteSize = bytesNeeded;
            ioData.mBuffers[i].mData = malloc( bytesNeeded );
        }
    }

    // actually GET the data that arrived
    status = AudioUnitRender( (void *)myUnit, 
                             ioActionFlags, 
                             inTimeStamp, 
                             inBusNumber, 
                             inNumberFrames, 
                             & ioData );


    // take MONO from mic
    const int channel = 0;
    Float32 * outBuffer = (Float32 *) ioData.mBuffers[channel].mData;

    // get a handle to our game object
    static KPRing* kpRing = nil;
    if ( ! kpRing )
    {
        //AppDelegate *  appDelegate = [UIApplication sharedApplication].delegate;

        kpRing = [Game singleton].kpRing;

        assert( kpRing );
    }

    // ... and send it the data we just got from the mic
    [ kpRing floatsArrivedFromMic: outBuffer
                            count: inNumberFrames ];

    return status;
}