【问题标题】:How to stop an audio file from looping in Apple's MixerHost Core Audio Example如何在 Apple 的 MixerHost 核心音频示例中阻止音频文件循环播放
【发布时间】:2012-04-20 07:32:37
【问题描述】:

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

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

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

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 &gt;= frameTotalForSound) sampleNumber = 0; 以便在样本用完后告诉回调停止请求样本,但我会更舒服地调用目标 C 中的方法而不是操纵这个 C-结构。

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

谢谢。

【问题讨论】:

    标签: iphone c core-audio


    【解决方案1】:

    我只能想象很多人一定遇到过这个音频文件循环问题,因为 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: 方法来停止循环并执行与我的应用程序密切相关的其他任务。

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 你能解释一下@hotpaw2 的意思吗?我通过在回调中注册 NSNotificationCenter 并使用程序另一部分中的方法停止音频记录解决了这个问题,但如果你能概述一个更简洁的 C 解决方案,我将不胜感激。
      • 有效的解决方案不一定看起来更干净。设置标志并轮询它是一种常见的工作解决方案,即使“丑陋”。
      • 我说的不是hotpaw。我的意思是,如果你能帮助我找到比我更好或更“干净”的解决方案,我肯定会欢迎它。据我了解,我的解决方案是“肮脏”的解决方案,但我开始认为它可能没问题。所以,如果我错了,请帮助我!
      【解决方案3】:

      感谢您发布您的解决方案,它有效,并且与 Apple 声明其他通知的方式并无矛盾。几点说明:

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

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

        if (sampleNumber >= frameTotalForSound) { NSLog(@"到达终点!"); 这.stopAUGraph; 样本数 = 0; // 如果有人想再次播放 }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-10
        • 2022-01-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多