在Mac上实时处理音频的最简单方式是从音频输入中捕获原始音频。

4

如何从内置音频输入捕获音频,并能够实时读取原始采样值(例如.wav),就像从套接字中读取一样。

希望使用苹果的框架之一(Audio Queues)编写代码。文档不是很清楚,我需要的非常基础。

2个回答

7
尝试使用AudioQueue框架。您主要需要执行3个步骤:
  1. 设置音频格式,以对传入的模拟音频进行采样
  2. 使用AudioQueueNewInput()启动新的录音AudioQueue
  3. 注册回调函数以处理传入的音频数据包
在第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以及如何正确设置所有所需对象的详细信息。
您还可以更仔细地查看苹果的演示程序SpeakHere。但是,这对于初学者来说可能有点混乱。

2

这取决于你需要多实时的程度。如果需要非常精准的实时性,可以在底层使用音频单元。这意味着设置一个输入回调函数。请注意,当该回调被触发时,您需要分配自己的缓冲区,然后从麦克风请求音频。

不要被参数中存在缓冲指针所迷惑...这只是因为苹果正在使用相同的函数声明来处理输入和渲染回调函数。

以下是我其中一个项目的剪切版:

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;
}

1
在输入回调中调用malloc()可能会影响实时性能,这并不是一个好主意。最好通过inRefCon指针传递预先分配的缓冲区。 - j b

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接