2011-09-16 17 views
1

我試圖寫一個簡單的節拍器,每0.25秒播放一次系統聲音。我使用GCD在單獨的線程上播放點擊,但播放不均勻,點擊有時會以兩個快速節拍跟着慢速節拍播放。我記錄了循環中if語句執行的時間以及0.25秒時的右邊。我希望我不必使用音頻隊列服務。有什麼建議麼?簡單的節拍器

- (IBAction)start:(id)sender 
{ 
    dispatch_queue_t clickQueue; // the queue to run the metronome clicker 
    dispatch_queue_t mainQueue; // I access the main queue to demonstrate how to change UIKit items 
    //clickQueue = dispatch_queue_create("clickQueue", NULL); 
    clickQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 
    mainQueue = dispatch_get_main_queue(); 
    dispatch_async(clickQueue, ^{ 
     double timeWas = [NSDate timeIntervalSinceReferenceDate]; 
     //delay by a 1/10 of a second so the first few clicks don't bunch up. 
     double timeIs = [NSDate timeIntervalSinceReferenceDate] - 0.1; 
     // playing starts out as NO because it gets switched at the end of the loop 
     // and the PlaySystemSound block isn't off the queue yet. There is probably a 
     // better way to do this. 
     while (playing) { 
      timeIs = [NSDate timeIntervalSinceReferenceDate] ; 
      if ((timeIs - timeWas) > (60.0/240)) { 
       AudioServicesPlaySystemSound(sound); 
       timeWas = timeIs; 
       // I want to flast the 200 label between orange and black but I have to access 
       // user interface objects from the queue that they are running in, usually the 
       // main queue. 
       dispatch_async(mainQueue, ^{ 
        if (flash) 
         [bpm setTextColor:[UIColor orangeColor]]; 
        else 
         [bpm setTextColor:[UIColor blackColor]]; 
        flash = !flash; 
       }); 
      } 
     } 
    }); 
    playing = !playing; 
    if (playing) 
     [startButton setTitle:@"Stop" forState:UIControlStateNormal]; 
    else 
     [startButton setTitle:@"Start" forState:UIControlStateNormal]; 
} 

回答

3

對於時間使用NSTimer,對於聲音使用AVFoundation。

+2

即使你得到的NSTimer儘可能精確,你就需要火,AVFoundation引入的滯後將會拖延你的時間。它可能足夠接近以便在某些情況下可以接受,但對於節拍器,您將需要更精確的時間。 –

1

誰放在一起做http://www.metronomeonline.com/處理的時序問題的一個不錯的工作,但他們並沒有任何特定的硬件/操作系統開發的鄉親。我相信他們這樣做的方式是通過爲每個節拍創建預錄製的.wav/.mp3文件幾秒鐘,然後將它們循環。循環速率被計算爲節奏準確。通過使循環事件成爲唯一依賴於客戶端時序的事件,它們可以減少時序錯誤。

0

更好的方法是使用具有所需間隔的重複NSTimer。你的方法攪動了CPU。

0

我用節拍器的應用程序自己在同一條路上走了一條路。不幸的是,你永遠無法獲得像PlaySystemSound這樣的高級API所需的精度 - 它們只是不夠快速響應。

很可能,如果您希望真實的精確度與您的節奏和作爲「點擊」播放的聲音相同,您將需要使用音頻單元 - 您可能能夠脫離音頻隊列服務 - I沒有多少嘗試,意識到我需要在某個時候降低水平,並選擇全力以赴。

+0

我知道你前一段時間回答了這個問題,但只是爲了澄清,你是否使用NSTimer將音頻單元安排在單獨的線程中?你今天會對節拍器應用採取不同的方法嗎?你可能指向的任何資源? – blwinters

+0

你不會在AudioUnits中使用NSTimer。我建議閱讀如何使用AudioUnits,因爲它們可能是構建節拍器的唯一可靠解決方案。 –

+0

謝謝。我可能會從這個框架開始,以緩解學習曲線:http://theamazingaudioengine.com/ – blwinters