2012-04-20 37 views
1

我有一個應用程序,允許用戶使用音頻單元在節拍中錄製。爲了達到這個目的,我從Apple的MixerHost示例代碼修改了Mixer類。如何阻止音頻文件在Apple的MixerHost中循環播放核心音頻示例

目前我的聲音文件循環,我想停止。我希望用戶能夠在聲音文件通過時保存混音。

的原因環路處於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 >= frameTotalForSound) sampleNumber = 0;爲了告訴回調停止請求樣品一旦樣本耗盡,但我更願意調用目標C中的方法,而不是我操縱這個C-Struct。

有沒有人有關於如何做到這一點的任何想法?

謝謝。

回答

2

我只能想象許多人都必須遇到這個音頻文件循環問題,因爲MixerHost是Apple提供的少數核心音頻示例之一。

我使用NSNotificationCenter解決了這個問題。在C函數內部解密使用Objective C之前,請認識到我通過在MixerHost示例中模仿蘋果代碼的其他部分找到了此解決方案。例如,要暫停節目,並指示耳機都拔掉,或者該裝置是由一個基座連接器取出,蘋果使用在通知中心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:方法來獲取循環停止,並執行有密切關係我的應用程序的其他任務。

我希望這是有幫助的。如果有人有更好的解決方案,那麼我願意接受它。謝謝。

1

您不應該在音頻處理或緩衝區回調的內部循環中使用任何Objective C消息。無緣無故的循環開銷。堅持使用C結構中的內部C類型。設置一個標誌變量是可以的。稍後在回調之外發送任何所需的對象消息,並在內部音頻採樣循環中發送消息

+0

你能解釋一下你的意思@ hotpaw2嗎?我通過在回調中向NSNotificationCenter註冊並在程序的另一部分中使用方法停止audiograph來解決此問題,但如果您可以概述更清潔的C解決方案,那麼我將不勝感激。 – 2012-04-21 12:54:30

+0

有效的解決方案不一定看起來更清潔。設置標誌並進行輪詢是一種常見的工作解決方案,即使「醜陋」也是如此。 – hotpaw2 2012-04-21 14:18:38

+0

這不是我的意思是熱水。我在說,如果你能以比我更好或更「清潔」的解決方案來幫助我,我肯定會歡迎它。據我瞭解,我的解決方案是「髒」,但我開始認爲它可能是好的。所以,如果我錯了,請幫助我! – 2012-04-21 15:59:22

0

感謝您發佈您的解決方案,它的工作原理與Apple宣佈其他通知的方式不矛盾。一些注意事項:

  1. 如果您要混合多個文件,這將在最短的文件到達結尾時停止播放器。

  2. 我嘗試以下代碼(假設inputrendercallback函數的其餘部分是不變的):

    如果(將SampleNumber> = frameTotalForSound){ 的NSLog;(@ 「到達結束!」) 這個。stopAUGraph; sampleNumber = 0; //萬一你想再玩一次 }