【问题标题】:NSSound-like framework that works, but doesn't require dealing with a steep learning curve类似 NSSound 的框架,有效,但不需要处理陡峭的学习曲线
【发布时间】:2010-08-24 13:26:34
【问题描述】:

我的一个应用程序使用 NSSound 播放 10 秒 AAC 编码的预先录制的白噪声循环,我已经完成了一项白噪声功能的工作。

[sound setLoops: YES]

应该是所有需要的,对吧?

它就像一个魅力,但我注意到在声音文件完成和重新启动之间有一个可听见的停顿......一种“扑通”的声音。这在循环原始声音文件时不存在,经过一个小时左右的时间试图弄清楚这一点,我得出的结论是 NSSound 很糟糕,并且可听见的暂停是私有后台线程同步的产物播放声音。它似乎以某种方式依赖于主运行循环,这会导致声音结束和重新开始之间的声音间隙。

我对声音知之甚少,这是一个非常小的功能,所以我不想深入 CoreAudio 只是为了播放循环播放 10 秒的声音片段.. 所以我去追求一个不错的选择,但似乎没有什么合适的:

  • Core Audio:完全矫枉过正,但至少是标准框架
  • AudioQueue:复杂,有 C++ 示例代码!?
  • MusicKit/ SndKit:也有巨大的学习曲线,基于大量开源内容等。

我看到 iOS 4 上的 AVFoundation 会是播放声音的好方法,但这只计划用于 Mac OS X 10.7..

在 Mac OS X 10.5+ 上是否有任何易于使用的可靠循环声音的方法?

是否有任何用于 AudioQueue 或 Core Audio 的示例代码可以减轻在 Objective-C 应用程序中使用它们的痛苦?

任何帮助将不胜感激..

最好的问候,

弗兰克

【问题讨论】:

    标签: cocoa macos core-audio audioqueueservices nssound


    【解决方案1】:

    使用 QTKit。为声音创建一个QTMovie,将其设置为循环播放,然后继续播放。

    【讨论】:

    • 同意。使用 QTKit 播放声音最困难的部分是将其包含在您的项目中(这需要几秒钟)。
    • 让它与 QTKit 一起工作。我认为由于 QuickTime 不能在 64 位或垃圾收集模式下运行,所以也不值得尝试 QTKit。但它似乎只是工作美好的。谢谢。
    • 旧的 QuickTime 框架只有 32 位。 QTKit 是兼容 64 位的现代 Objective-C 框架,也应该对 GC 友好。
    【解决方案2】:

    只是为了存档。

    QTKit 还存在一个播放结束和下一个播放开始之间的间隙。它似乎与以某种方式重新初始化数据(也许从磁盘重新读取它?)有关。使用小得多但高度压缩的 m4a 格式比播放未压缩的 aiff 文件时明显得多,但它仍然存在。

    我找到的解决方案是使用音频队列服务:

    http://developer.apple.com/mac/library/documentation/MusicAudio/Conceptual/AudioQueueProgrammingGuide/AQPlayback/PlayingAudio.html#//apple_ref/doc/uid/TP40005343-CH3-SW1

    http://developer.apple.com/mac/library/samplecode/AudioQueueTools/Listings/aqplay_cpp.html#//apple_ref/doc/uid/DTS10004380-aqplay_cpp-DontLinkElementID_4

    音频队列调用一个回调函数来准备下一个缓冲区并将其排入队列,因此当您到达当前文件的末尾时,您需要从头开始重新开始。这提供了完全无间隙的播放。

    文档中的示例代码有两个陷阱。

    第一个是一个实际的错误(我会就此联系 DTS,以便他们进行更正)。在分配和启动音频缓冲区之前,自定义结构必须打开播放,否则音频缓冲区永远不会被启动并且什么都不会播放:

        aqData.mIsRunning = 1;
    

    第二个问题是代码不是在 Cocoa 中运行,而是作为一个独立的工具运行,因此代码将音频队列连接到一个新的运行循环,并且实际上将运行循环本身实现为程序的最后一步。

    不传递 CFRunLoopGetCurrent(),而是传递 NULL,这会导致 AudioQueue 在自己的运行循环中运行。

    result = AudioQueueNewOutput (                                // 1
                         &aqData.mDataFormat,                             // 2
                         HandleOutputBuffer,                              // 3
                         &aqData,                                         // 4
                         NULL, //CFRunLoopGetCurrent (),                          // 5
                         kCFRunLoopCommonModes,                           // 6
                         0,                                               // 7
                         &aqData.mQueue                                   // 8
                         );
    

    我希望这可以为那些试图在未来做同样事情的可怜虫节省一点时间:-)

    【讨论】:

      【解决方案3】:

      遗憾的是,在 OS X 上开发音频应用程序时有很多痛苦。学习曲线非常陡峭,因为文档很少。

      如果您不介意 Objective-C++,我已经为这种事情编写了一个框架:SFBAudioEngine。如果你想用我的代码播放声音,你可以这样做:

      DSPAudioPlayer *player = new DSPAudioPlayer();
      player->Enqueue((CFURLRef)audioURL);
      player->Play();
      

      循环也是可能的。

      【讨论】:

      • 感谢您的帮助。我将逐步测试 Mike 的 QTKit 解决方案,看看它是否真的正常工作,但除非出现意外情况,否则我可能会坚持使用它来满足我的卑微需求.. 但你永远不知道 :-)跨度>
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-24
      • 2021-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多