2010-08-24 27 views
1

我已經完成了對我的應用程序之一使用NSSound播放10秒AAC編碼循環的白噪聲功能的工作預錄白噪聲。NSSound-like框架,但不需要處理陡峭的學習曲線

[sound setLoops: YES] 

應該是所有必需的,對嗎?

它的工作原理就像是一種魅力,但我注意到在聲音文件的整理和重新啓動之間有一段可以聽到的停頓......一種「plop」聲音。這在循環原始聲音文件時並不存在,並且在嘗試弄清楚這一點之後的一個小時左右,我得出的結論是NSSound很糟糕,並且可聽見的暫停是私人後臺線程同步的人爲現象播放聲音。它似乎依賴於主運行循環,這會導致聲音結束和重新開始之間的聲音間隙。

我對聲音的知識知之甚少,而且這是一個非常小的功能,所以我不想進入CoreAudio的深處只是爲了播放循環的10s聲音片段..所以我追逐了一個不錯的選擇,但似乎沒有任何頗爲契合:

  • 核心音頻:總矯枉過正,但至少一個標準框架
  • AudioQueue:複雜,C++代碼示例!?
  • MusicKit/SndKit:也是巨大的學習曲線,基於大量的開源的東西,等

我看到AVFoundation在iOS 4將播放聲音的好辦法,但這只是計劃爲Mac OS X 10.7 ..

是否有在Mac OS X 10.5+上可靠地循環播放聲音的簡單易用的方法?

是否有AudioQueue或Core Audio的任何示例代碼,不需要從Objective-C應用程序中使用它們?

任何幫助將是非常讚賞..

最好的問候,

弗蘭克

回答

2

使用QTKit。爲聲音創建一個QTMovie,將其設置爲循環,並讓其播放。

+0

Isn QTKit 32位和非垃圾收集? 我的應用程序都是64位GC編輯。 – 2010-08-24 14:48:33

+0

同意。使用QTKit播放聲音最難的部分是將其包含在您的項目中(這需要幾秒鐘)。 – 2010-08-24 14:49:45

+0

得到它與QTKit工作..我認爲QuickTime無法運行在64位或垃圾收集模式,這是不值得嘗試QTKit ..但它似乎工作得很好。 謝謝。 – 2010-08-24 15:40:11

0

可悲的是,有很多痛苦的發展在OS X上的音頻應用程序時的學習曲線很陡峭,因爲文件相當稀疏。

如果你不介意Objective-C++,我已經寫了這樣的一個框架:SFBAudioEngine。如果你想用我的代碼播放聲音,你可以這樣做:

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

循環也是可能的。

+0

感謝您的幫助了。我打算通過邁克的QTKit解決方案來確定它的工作是否正常,但除非出現意想不到的情況,否則我可能會堅持這一點以滿足我的卑微需求......但是您永遠不知道:-) – 2010-08-24 15:42:34

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; 

第二個疑難雜症的是,代碼不可可但作爲一個運行獨立的工具,所以代碼將音頻隊列連接到一個新的運行循環,並實際上將運行循環本身作爲程序的最後一步。

而不是傳遞CFRunLoopGetCurrent(),只是傳遞NULL,導致AudioQueue運行在它自己的運行循環中。

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

我希望這可以節省可憐蟲試圖做同樣的事情在未來一點時間:-)