1

我有一个应用程序,允许用户使用音频单元记录节拍。为了实现这一点,我从 Apple 的 MixerHost 示例代码中修改了 Mixer 类。

目前我的声音文件循环,我想停止它。我希望用户能够在声音文件通过后保存混音。

循环的原因是函数for loop以下部分的最后一行inputrendercallback

for (UInt32 frameNumber = 0; frameNumber < inNumberFrames; ++frameNumber) {

        outSamplesChannelLeft[frameNumber]                 = dataInLeft[sampleNumber];
        if (isStereo) outSamplesChannelRight[frameNumber]  = dataInRight[sampleNumber];

        sampleNumber++;

        // After reaching the end of the sound stored in memory--that is, after
        //    (frameTotalForSound / inNumberFrames) invocations of this callback--loop back to the 
        //    start of the sound so playback resumes from there.
        if (sampleNumber >= frameTotalForSound) sampleNumber = 0;
    }

我意识到我需要进行更改if (sampleNumber >= frameTotalForSound) sampleNumber = 0;,以便在样本用完后告诉回调停止请求样本,但是我在目标 C 中调用方法要比操作这个 C-Struct 更舒服。

有人对如何做到这一点有任何想法吗?

谢谢。

4

3 回答 3

2

我只能想象很多人一定遇到过这个音频文件循环问题,因为 MixerHost 是 Apple 提供的为数不多的宝贵 Core Audio 示例之一。

我通过使用 NSNotificationCenter 解决了这个问题。在谴责在 C 函数中使用 Objective C 之前,请认识到我是通过在 MixerHost 示例本身中模仿 Apple 代码的其他部分来找到这个解决方案的。例如,要暂停程序并指示耳机已拔出,或者设备已从底座连接器中移除,Apple 使用了 MixerHostAudio 类中的通知中心audioRouteChangeListenerCallback

 if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) {

            NSLog (@"Audio output device was removed; stopping audio playback.");
            NSString *MixerObjectPlaybackStateDidChangeNotification = @"MixerObjectPlaybackStateDidChangeNotification";
            [[NSNotificationCenter defaultCenter] postNotificationName: MixerObjectPlaybackStateDidChangeNotification object: audioObject]; 

我决定还从inputrendercallback函数中发布通知:

for (UInt32 frameNumber = 0; frameNumber < inNumberFrames; ++frameNumber) {

        if (sampleNumber == frameTotalForSound) {

            NSString *AudioFileFinishedPlaying = @"AudioFileFinishedPlaying";
            [[NSNotificationCenter defaultCenter] postNotificationName: AudioFileFinishedPlaying object: nil];
        }

        outSamplesChannelLeft[frameNumber]                 = dataInLeft[sampleNumber];
        if (isStereo) outSamplesChannelRight[frameNumber]  = dataInRight[sampleNumber];

        sampleNumber++;

...

然后我在程序的另一部分使用该 addObserver:selector:name:object:方法来停止循环并执行与我的应用程序密切相关的其他任务。

我希望这会有所帮助。如果有人有更好的解决方案,那么我愿意接受。谢谢。

于 2012-04-21T13:28:15.480 回答
1

您不应在音频处理或缓冲区回调的内部循环中使用任何 Objective C 消息传递。无缘无故的循环开销太大。坚持在 C 结构中使用内在的 C 类型。设置标志变量是可以的。稍后在回调和内部音频样本循环之外执行任何需要的对象消息传递。

于 2012-04-21T07:05:00.033 回答
0

感谢您发布您的解决方案,它有效,并且与 Apple 声明其他通知的方式不一致。几点注意事项:

  1. 如果您正在混合多个文件,这将在最短的文件到达结尾时停止播放器。

  2. 我尝试了以下代码(假设 inputrendercallback 函数的其余部分未更改):

    if (sampleNumber >= frameTotalForSound) { NSLog(@"到达终点!"); 这.stopAUGraph; 样本数 = 0;// 万一想再玩一次 }

于 2012-11-21T05:23:19.530 回答